Unified HCD driver/controller transfer

With this patch, every MUSB host controller transaction is part of some
URB submission (may be external from device driver or internal from
HCD itself).

This way, enumeration/URB conflicts are avoided, as all transactions
are handled by URB scheduler.

Better USB hub port reset

Change-Id: I51d2b282d6e6e2c371249f77f09ddf8512044fc4
This commit is contained in:
Wojciech Zajac 2014-08-07 15:13:01 +02:00 committed by Ben Gras
parent a1a769dfe8
commit d401ea8186
5 changed files with 266 additions and 149 deletions

View File

@ -4,6 +4,7 @@
#include <string.h> /* memset */ #include <string.h> /* memset */
#include <stdint.h> #include <stdint.h>
#include <time.h> /* nanosleep */
#include <ddekit/thread.h> #include <ddekit/thread.h>
#include <minix/sef.h> #include <minix/sef.h>
@ -51,6 +52,9 @@ static void hub_task(void *);
/* Limits number of communication retries (when needed) */ /* Limits number of communication retries (when needed) */
#define USB_HUB_MAX_TRIES 3 #define USB_HUB_MAX_TRIES 3
/* How long to wait between retries, in case of reset error (in nanoseconds) */
#define USB_HUB_RESET_DELAY 200000000 /* 200ms */
/* Hub descriptor type */ /* Hub descriptor type */
#define USB_HUB_DESCRIPTOR_TYPE 0x29 #define USB_HUB_DESCRIPTOR_TYPE 0x29
@ -821,6 +825,7 @@ hub_handle_change(int port_num, hub_port_status * status)
static int static int
hub_handle_connection(int port_num, hub_port_status * status) hub_handle_connection(int port_num, hub_port_status * status)
{ {
struct timespec wait_time;
int reset_tries; int reset_tries;
long port_speed; long port_speed;
@ -841,6 +846,8 @@ hub_handle_connection(int port_num, hub_port_status * status)
} }
reset_tries = 0; reset_tries = 0;
wait_time.tv_sec = 0;
wait_time.tv_nsec = USB_HUB_RESET_DELAY;
/* Wait for reset completion */ /* Wait for reset completion */
while (!status->C_PORT_RESET) { while (!status->C_PORT_RESET) {
@ -857,6 +864,11 @@ hub_handle_connection(int port_num, hub_port_status * status)
} }
reset_tries++; reset_tries++;
/* Ignore potential signal interruption (no return value check),
* since it causes driver termination anyway */
if (nanosleep(&wait_time, NULL))
HUB_MSG("Calling nanosleep() failed");
} }
/* Reset completed */ /* Reset completed */

View File

@ -9,6 +9,7 @@
#include <usbd/hcd_common.h> #include <usbd/hcd_common.h>
#include <usbd/hcd_ddekit.h> #include <usbd/hcd_ddekit.h>
#include <usbd/hcd_interface.h> #include <usbd/hcd_interface.h>
#include <usbd/hcd_schedule.h>
#include <usbd/usbd_common.h> #include <usbd/usbd_common.h>
@ -40,7 +41,7 @@ static int hcd_non_control_urb(hcd_device_state *, hcd_urb *);
/* For internal use by more general methods */ /* For internal use by more general methods */
static int hcd_setup_packet(hcd_device_state *, hcd_ctrlrequest *, hcd_reg1); static int hcd_setup_packet(hcd_device_state *, hcd_ctrlrequest *, hcd_reg1);
static int hcd_finish_setup(hcd_device_state *, void *, hcd_reg4); static int hcd_finish_setup(hcd_device_state *, void *);
static int hcd_data_transfer(hcd_device_state *, hcd_datarequest *); static int hcd_data_transfer(hcd_device_state *, hcd_datarequest *);
/* TODO: This is not meant to be explicitly visible outside DDEKit library /* TODO: This is not meant to be explicitly visible outside DDEKit library
@ -55,6 +56,10 @@ extern void _ddekit_thread_set_myprio(int);
* allow receiving less data than expected in URB, without error */ * allow receiving less data than expected in URB, without error */
#define HCD_ANY_LENGTH 0xFFFFFFFFu #define HCD_ANY_LENGTH 0xFFFFFFFFu
/* This doesn't seem to be specified in standard but abnormal values
* are unlikely so check for this was added below */
#define HCD_SANE_DESCRIPTOR_LENGTH 2048
/*===========================================================================* /*===========================================================================*
* hcd_handle_event * * hcd_handle_event *
@ -255,6 +260,9 @@ hcd_device_thread(void * thread_args)
/* Block and wait for something like 'submit URB' */ /* Block and wait for something like 'submit URB' */
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL); hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
hcd_handle_urb(this_device); hcd_handle_urb(this_device);
/* Only external URBs should be submitted here */
hcd_completion_cb(this_device->urb);
} }
/* Finish device handling to avoid leaving thread */ /* Finish device handling to avoid leaving thread */
@ -413,12 +421,45 @@ hcd_enumerate(hcd_device_state * this_device)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* Remember max packet size from device descriptor */
this_device->max_packet_size = this_device->device_desc.bMaxPacketSize;
/* Dump device descriptor in debug mode */
#ifdef DEBUG
{
hcd_device_descriptor * d;
d = &(this_device->device_desc);
USB_DBG("<<DEVICE>>");
USB_DBG("bLength %02X", d->bLength);
USB_DBG("bDescriptorType %02X", d->bDescriptorType);
USB_DBG("bcdUSB %04X", UGETW(d->bcdUSB));
USB_DBG("bDeviceClass %02X", d->bDeviceClass);
USB_DBG("bDeviceSubClass %02X", d->bDeviceSubClass);
USB_DBG("bDeviceProtocol %02X", d->bDeviceProtocol);
USB_DBG("bMaxPacketSize %02X", d->bMaxPacketSize);
USB_DBG("idVendor %04X", UGETW(d->idVendor));
USB_DBG("idProduct %04X", UGETW(d->idProduct));
USB_DBG("bcdDevice %04X", UGETW(d->bcdDevice));
USB_DBG("iManufacturer %02X", d->iManufacturer);
USB_DBG("iProduct %02X", d->iProduct);
USB_DBG("iSerialNumber %02X", d->iSerialNumber);
USB_DBG("bNumConfigurations %02X", d->bNumConfigurations);
}
#endif
/* Set reserved address */ /* Set reserved address */
if (EXIT_SUCCESS != hcd_set_address(this_device)) { if (EXIT_SUCCESS != hcd_set_address(this_device)) {
USB_MSG("Failed to set device address"); USB_MSG("Failed to set device address");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* Sleep 5msec to allow addressing */
hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(5));
/* Remember what was assigned in hardware */
this_device->current_address = this_device->reserved_address;
/* Get other descriptors */ /* Get other descriptors */
if (EXIT_SUCCESS != hcd_get_descriptor_tree(this_device)) { if (EXIT_SUCCESS != hcd_get_descriptor_tree(this_device)) {
USB_MSG("Failed to get configuration descriptor tree"); USB_MSG("Failed to get configuration descriptor tree");
@ -448,11 +489,11 @@ static int
hcd_get_device_descriptor(hcd_device_state * this_device) hcd_get_device_descriptor(hcd_device_state * this_device)
{ {
hcd_ctrlrequest setup; hcd_ctrlrequest setup;
hcd_urb urb;
DEBUG_DUMP; DEBUG_DUMP;
/* TODO: magic numbers, no header for these */ /* TODO: magic numbers, no header for these */
/* Format setup packet */ /* Format setup packet */
setup.bRequestType = 0x80; /* IN */ setup.bRequestType = 0x80; /* IN */
setup.bRequest = 0x06; /* Get descriptor */ setup.bRequest = 0x06; /* Get descriptor */
@ -460,45 +501,31 @@ hcd_get_device_descriptor(hcd_device_state * this_device)
setup.wIndex = 0x0000; setup.wIndex = 0x0000;
setup.wLength = sizeof(this_device->device_desc); setup.wLength = sizeof(this_device->device_desc);
/* Handle formatted setup packet */ /* Prepare self-URB */
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup, memset(&urb, 0, sizeof(urb));
HCD_DEFAULT_EP)) { urb.direction = HCD_DIRECTION_IN;
USB_MSG("Handling setup packet failed"); urb.endpoint = HCD_DEFAULT_EP;
urb.in_setup = &setup;
urb.inout_data = (hcd_reg1 *)(&(this_device->device_desc));
urb.target_device = this_device;
urb.type = HCD_TRANSFER_CONTROL;
/* Put it to be scheduled and wait for control to get back */
hcd_schedule_internal_urb(&urb);
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
hcd_handle_urb(this_device);
/* Check if URB submission completed successfully */
if (urb.inout_status) {
USB_MSG("URB submission failed");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* Put what was read in device descriptor */ /* Check if expected size was received */
if (EXIT_SUCCESS != hcd_finish_setup(this_device, if (urb.out_size != setup.wLength) {
&(this_device->device_desc), USB_MSG("URB submission returned invalid amount of data");
sizeof(this_device->device_desc)))
return EXIT_FAILURE; return EXIT_FAILURE;
/* Remember max packet size from device descriptor */
this_device->max_packet_size = this_device->device_desc.bMaxPacketSize;
/* Dump device descriptor in debug mode */
#ifdef DEBUG
{
hcd_device_descriptor * d;
d = &(this_device->device_desc);
USB_DBG("<<DEVICE>>");
USB_DBG("bLength %02X", d->bLength);
USB_DBG("bDescriptorType %02X", d->bDescriptorType);
USB_DBG("bcdUSB %04X", UGETW(d->bcdUSB));
USB_DBG("bDeviceClass %02X", d->bDeviceClass);
USB_DBG("bDeviceSubClass %02X", d->bDeviceSubClass);
USB_DBG("bDeviceProtocol %02X", d->bDeviceProtocol);
USB_DBG("bMaxPacketSize %02X", d->bMaxPacketSize);
USB_DBG("idVendor %04X", UGETW(d->idVendor));
USB_DBG("idProduct %04X", UGETW(d->idProduct));
USB_DBG("bcdDevice %04X", UGETW(d->bcdDevice));
USB_DBG("iManufacturer %02X", d->iManufacturer);
USB_DBG("iProduct %02X", d->iProduct);
USB_DBG("iSerialNumber %02X", d->iSerialNumber);
USB_DBG("bNumConfigurations %02X", d->bNumConfigurations);
} }
#endif
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -511,6 +538,7 @@ static int
hcd_set_address(hcd_device_state * this_device) hcd_set_address(hcd_device_state * this_device)
{ {
hcd_ctrlrequest setup; hcd_ctrlrequest setup;
hcd_urb urb;
DEBUG_DUMP; DEBUG_DUMP;
@ -526,18 +554,31 @@ hcd_set_address(hcd_device_state * this_device)
setup.wIndex = 0x0000; setup.wIndex = 0x0000;
setup.wLength = 0x0000; setup.wLength = 0x0000;
/* Handle formatted setup packet */ /* Prepare self-URB */
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup, memset(&urb, 0, sizeof(urb));
HCD_DEFAULT_EP)) { urb.direction = HCD_DIRECTION_OUT;
USB_MSG("Handling setup packet failed"); urb.endpoint = HCD_DEFAULT_EP;
urb.in_setup = &setup;
urb.inout_data = NULL;
urb.target_device = this_device;
urb.type = HCD_TRANSFER_CONTROL;
/* Put it to be scheduled and wait for control to get back */
hcd_schedule_internal_urb(&urb);
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
hcd_handle_urb(this_device);
/* Check if URB submission completed successfully */
if (urb.inout_status) {
USB_MSG("URB submission failed");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* Sleep 5msec to allow addressing */ /* Check if expected size was received */
hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(5)); if (urb.out_size != setup.wLength) {
USB_MSG("URB submission returned invalid amount of data");
/* Remember what was assigned in hardware */ return EXIT_FAILURE;
this_device->current_address = this_device->reserved_address; }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -549,19 +590,24 @@ hcd_set_address(hcd_device_state * this_device)
static int static int
hcd_get_descriptor_tree(hcd_device_state * this_device) hcd_get_descriptor_tree(hcd_device_state * this_device)
{ {
hcd_config_descriptor config_descriptor; hcd_config_descriptor temp_config_descriptor;
hcd_ctrlrequest setup; hcd_ctrlrequest setup;
hcd_reg4 total_length; hcd_urb urb;
hcd_reg4 buffer_length;
int completed; /* To receive data */
hcd_reg4 expected_length;
hcd_reg1 * expected_buffer;
int retval;
DEBUG_DUMP; DEBUG_DUMP;
/* First, ask only for configuration itself to get length info */ /* Initially */
buffer_length = sizeof(config_descriptor); retval = EXIT_FAILURE;
completed = 0; expected_buffer = NULL;
do { /* First part gets only configuration to find out total length */
{
/* TODO: Default configuration is hard-coded /* TODO: Default configuration is hard-coded
* but others are rarely used anyway */ * but others are rarely used anyway */
/* TODO: magic numbers, no header for these */ /* TODO: magic numbers, no header for these */
@ -569,62 +615,107 @@ hcd_get_descriptor_tree(hcd_device_state * this_device)
setup.bRequest = 0x06; /* Get descriptor */ setup.bRequest = 0x06; /* Get descriptor */
setup.wValue = 0x0200 | HCD_DEFAULT_CONFIG; setup.wValue = 0x0200 | HCD_DEFAULT_CONFIG;
setup.wIndex = 0x0000; setup.wIndex = 0x0000;
setup.wLength = buffer_length; setup.wLength = sizeof(temp_config_descriptor);
/* Handle formatted setup packet */ /* Prepare self-URB */
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup, memset(&urb, 0, sizeof(urb));
HCD_DEFAULT_EP)) { urb.direction = HCD_DIRECTION_IN;
USB_MSG("Handling setup packet failed"); urb.endpoint = HCD_DEFAULT_EP;
return EXIT_FAILURE; urb.in_setup = &setup;
urb.inout_data = (hcd_reg1 *)(&temp_config_descriptor);
urb.target_device = this_device;
urb.type = HCD_TRANSFER_CONTROL;
/* Put it to be scheduled and wait for control to get back */
hcd_schedule_internal_urb(&urb);
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
hcd_handle_urb(this_device);
/* Check if URB submission completed successfully */
if (urb.inout_status) {
USB_MSG("URB submission failed");
goto FINISH;
} }
/* If we only asked for configuration itself /* Check if expected size was received */
* then ask again for other descriptors */ if (urb.out_size != setup.wLength) {
if (sizeof(config_descriptor) == buffer_length) { USB_MSG("URB submission returned "
"invalid amount of data");
/* Put what was already read in configuration goto FINISH;
* descriptor for analysis */
if (EXIT_SUCCESS != hcd_finish_setup(this_device,
&config_descriptor,
buffer_length))
return EXIT_FAILURE;
/* Continue only if there is more data */
total_length = UGETW(config_descriptor.wTotalLength);
if (total_length < sizeof(config_descriptor)) {
/* This should never happen for a fine device */
USB_MSG("Illegal wTotalLength value");
return EXIT_FAILURE;
} else if (sizeof(config_descriptor) == total_length) {
/* Nothing more was in descriptor anyway */
completed = 1;
} else {
/* Read whatever is needed */
buffer_length = total_length;
}
} else {
/* All data for given configuration was read */
completed = 1;
} }
} }
while (!completed);
/* Validate... */ /* Get total expected length */
if (EXIT_SUCCESS != hcd_finish_setup(this_device, NULL, total_length)) expected_length = UGETW(temp_config_descriptor.wTotalLength);
return EXIT_FAILURE;
/* ... and create tree based on received buffer */ /* Check for abnormal value */
if (EXIT_SUCCESS != hcd_buffer_to_tree(this_device->control_data, if (expected_length > HCD_SANE_DESCRIPTOR_LENGTH) {
this_device->control_len, USB_MSG("Total descriptor length declared is too high");
goto FINISH;
}
/* Get descriptor buffer to hold everything expected */
if (NULL == (expected_buffer = malloc(expected_length))) {
USB_MSG("Descriptor allocation failed");
goto FINISH;
}
/* Second part gets all available descriptors */
{
/* TODO: Default configuration is hard-coded
* but others are rarely used anyway */
/* TODO: magic numbers, no header for these */
setup.bRequestType = 0x80; /* IN */
setup.bRequest = 0x06; /* Get descriptor */
setup.wValue = 0x0200 | HCD_DEFAULT_CONFIG;
setup.wIndex = 0x0000;
setup.wLength = expected_length;
/* Prepare self-URB */
memset(&urb, 0, sizeof(urb));
urb.direction = HCD_DIRECTION_IN;
urb.endpoint = HCD_DEFAULT_EP;
urb.in_setup = &setup;
urb.inout_data = expected_buffer;
urb.target_device = this_device;
urb.type = HCD_TRANSFER_CONTROL;
/* Put it to be scheduled and wait for control to get back */
hcd_schedule_internal_urb(&urb);
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
hcd_handle_urb(this_device);
/* Check if URB submission completed successfully */
if (urb.inout_status) {
USB_MSG("URB submission failed");
goto FINISH;
}
/* Check if expected size was received */
if (urb.out_size != setup.wLength) {
USB_MSG("URB submission returned "
"invalid amount of data");
goto FINISH;
}
}
if (EXIT_SUCCESS != hcd_buffer_to_tree(expected_buffer,
(int)expected_length,
&(this_device->config_tree))) { &(this_device->config_tree))) {
/* This should never happen for a fine device */ USB_MSG("Broken descriptor data");
USB_MSG("Illegal descriptor values"); goto FINISH;
return EXIT_FAILURE;
} }
return EXIT_SUCCESS; /* No errors occurred */
retval = EXIT_SUCCESS;
FINISH:
/* Release allocated buffer */
if (expected_buffer)
free(expected_buffer);
return retval;
} }
@ -635,6 +726,7 @@ static int
hcd_set_configuration(hcd_device_state * this_device, hcd_reg1 configuration) hcd_set_configuration(hcd_device_state * this_device, hcd_reg1 configuration)
{ {
hcd_ctrlrequest setup; hcd_ctrlrequest setup;
hcd_urb urb;
DEBUG_DUMP; DEBUG_DUMP;
@ -645,14 +737,21 @@ hcd_set_configuration(hcd_device_state * this_device, hcd_reg1 configuration)
setup.wIndex = 0x0000; setup.wIndex = 0x0000;
setup.wLength = 0x0000; setup.wLength = 0x0000;
/* Handle formatted setup packet */ /* Prepare self-URB */
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup, memset(&urb, 0, sizeof(urb));
HCD_DEFAULT_EP)) { urb.direction = HCD_DIRECTION_OUT;
USB_MSG("Handling setup packet failed"); urb.endpoint = HCD_DEFAULT_EP;
return EXIT_FAILURE; urb.in_setup = &setup;
} urb.inout_data = NULL;
urb.target_device = this_device;
urb.type = HCD_TRANSFER_CONTROL;
return EXIT_SUCCESS; /* Put it to be scheduled and wait for control to get back */
hcd_schedule_internal_urb(&urb);
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
hcd_handle_urb(this_device);
return urb.inout_status;
} }
@ -705,6 +804,8 @@ hcd_handle_urb(hcd_device_state * this_device)
USB_MSG("Invalid URB supplied"); USB_MSG("Invalid URB supplied");
/* Signal scheduler that URB was handled */ /* Signal scheduler that URB was handled */
/* TODO: This works based on the fact that device thread has higher
* priority than scheduler and won't change context within this call */
urb->handled(urb); urb->handled(urb);
} }
@ -747,9 +848,7 @@ hcd_control_urb(hcd_device_state * this_device, hcd_urb * urb)
} }
/* Put what was read back into URB */ /* Put what was read back into URB */
if (EXIT_SUCCESS != hcd_finish_setup(this_device, if (EXIT_SUCCESS != hcd_finish_setup(this_device, urb->inout_data))
urb->inout_data,
HCD_ANY_LENGTH))
return EXIT_FAILURE; return EXIT_FAILURE;
/* Write transfer output info to URB */ /* Write transfer output info to URB */
@ -986,8 +1085,7 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup,
* hcd_finish_setup * * hcd_finish_setup *
*===========================================================================*/ *===========================================================================*/
static int static int
hcd_finish_setup(hcd_device_state * this_device, void * output, hcd_finish_setup(hcd_device_state * this_device, void * output)
hcd_reg4 expected)
{ {
DEBUG_DUMP; DEBUG_DUMP;
@ -997,21 +1095,6 @@ hcd_finish_setup(hcd_device_state * this_device, void * output,
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* In case it is required... */
if (HCD_ANY_LENGTH != expected) {
/* ...check for expected length */
if ((hcd_reg4)this_device->control_len != expected) {
USB_MSG("Control transfer output length mismatch:"
"len %d, expected %u", this_device->control_len,
expected);
return EXIT_FAILURE;
}
/* Valid but there is no need to copy anything */
if (0u == expected)
return EXIT_SUCCESS;
}
/* Length is valid but output not supplied */ /* Length is valid but output not supplied */
if (NULL == output) if (NULL == output)
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -196,7 +196,7 @@ ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb)
hcd_decode_urb(urb, d_urb); hcd_decode_urb(urb, d_urb);
/* Add URB to scheduler */ /* Add URB to scheduler */
return hcd_schedule_urb(urb); return hcd_schedule_external_urb(urb);
} }
@ -308,8 +308,7 @@ hcd_completion_cb(hcd_urb * urb)
/* Recollect original URB */ /* Recollect original URB */
d_urb = (struct ddekit_usb_urb *)urb->original_urb; d_urb = (struct ddekit_usb_urb *)urb->original_urb;
/* This URB will be scheduled no more */ USB_ASSERT(NULL != d_urb, "Original DDEKit URB missing");
hcd_unschedule_urb(urb);
/* Turn HCD URB format to one handled by DDEKit */ /* Turn HCD URB format to one handled by DDEKit */
hcd_encode_urb(urb, d_urb); hcd_encode_urb(urb, d_urb);

View File

@ -34,6 +34,12 @@ static hcd_lock * urb_lock;
/* This allows waiting for completion */ /* This allows waiting for completion */
static hcd_lock * handled_lock; static hcd_lock * handled_lock;
/* Makes URB schedule enabled */
static int hcd_schedule_urb(hcd_urb *);
/* Makes URB schedule disabled */
static void hcd_unschedule_urb(hcd_urb *);
/* Scheduler task */ /* Scheduler task */
static void hcd_urb_scheduler_task(void *); static void hcd_urb_scheduler_task(void *);
@ -102,9 +108,33 @@ usbd_deinit_scheduler(void)
/*===========================================================================* /*===========================================================================*
* hcd_schedule_urb * * hcd_schedule_external_urb *
*===========================================================================*/ *===========================================================================*/
int int
hcd_schedule_external_urb(hcd_urb * urb)
{
DEBUG_DUMP;
return hcd_schedule_urb(urb);
}
/*===========================================================================*
* hcd_schedule_internal_urb *
*===========================================================================*/
int
hcd_schedule_internal_urb(hcd_urb * urb)
{
DEBUG_DUMP;
return hcd_schedule_urb(urb);
}
/*===========================================================================*
* hcd_schedule_urb *
*===========================================================================*/
static int
hcd_schedule_urb(hcd_urb * urb) hcd_schedule_urb(hcd_urb * urb)
{ {
DEBUG_DUMP; DEBUG_DUMP;
@ -114,12 +144,7 @@ hcd_schedule_urb(hcd_urb * urb)
/* Store and check if scheduler should be unlocked */ /* Store and check if scheduler should be unlocked */
if (EXIT_SUCCESS == hcd_store_urb(urb)) { if (EXIT_SUCCESS == hcd_store_urb(urb)) {
ddekit_sem_up(urb_lock);
/* This is the first stored URB (possibly in a row)
* so unlock scheduler */
if (1 == num_stored_urbs)
ddekit_sem_up(urb_lock);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -130,7 +155,7 @@ hcd_schedule_urb(hcd_urb * urb)
/*===========================================================================* /*===========================================================================*
* hcd_unschedule_urb * * hcd_unschedule_urb *
*===========================================================================*/ *===========================================================================*/
void static void
hcd_unschedule_urb(hcd_urb * urb) hcd_unschedule_urb(hcd_urb * urb)
{ {
DEBUG_DUMP; DEBUG_DUMP;
@ -150,9 +175,8 @@ hcd_urb_scheduler_task(void * UNUSED(arg))
DEBUG_DUMP; DEBUG_DUMP;
for (;;) { for (;;) {
/* Wait for scheduler to unlock on first URB submit */ /* Wait for scheduler to unlock on any URB submit */
if (0 == num_stored_urbs) ddekit_sem_down(urb_lock);
ddekit_sem_down(urb_lock);
/* Get URB */ /* Get URB */
current_urb = hcd_get_urb(); current_urb = hcd_get_urb();
@ -169,9 +193,6 @@ hcd_urb_scheduler_task(void * UNUSED(arg))
/* Wait for completion */ /* Wait for completion */
ddekit_sem_down(handled_lock); ddekit_sem_down(handled_lock);
/* Handled, forget about it */
current_urb->target_device->urb = NULL;
} }
} }
@ -184,8 +205,10 @@ hcd_urb_handled(hcd_urb * urb)
{ {
DEBUG_DUMP; DEBUG_DUMP;
/* Call completion regardless of status */ /* This URB will be scheduled no more */
hcd_completion_cb(urb); /* TODO: It would be better if this was connected
* to setting urb_lock down */
hcd_unschedule_urb(urb);
/* Handling completed */ /* Handling completed */
ddekit_sem_up(handled_lock); ddekit_sem_up(handled_lock);

View File

@ -7,10 +7,10 @@
#include <usbd/hcd_common.h> #include <usbd/hcd_common.h>
/* Makes URB schedule enabled */ /* Makes external (device driver) URB schedule enabled */
int hcd_schedule_urb(hcd_urb *); int hcd_schedule_external_urb(hcd_urb *);
/* Makes URB schedule disabled */ /* Makes internal (HCD) URB schedule enabled */
void hcd_unschedule_urb(hcd_urb *); int hcd_schedule_internal_urb(hcd_urb *);
#endif /* !_HCD_SCHEDULE_H_ */ #endif /* !_HCD_SCHEDULE_H_ */