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:
parent
a1a769dfe8
commit
d401ea8186
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <string.h> /* memset */
|
||||
#include <stdint.h>
|
||||
#include <time.h> /* nanosleep */
|
||||
|
||||
#include <ddekit/thread.h>
|
||||
#include <minix/sef.h>
|
||||
|
|
@ -51,6 +52,9 @@ static void hub_task(void *);
|
|||
/* Limits number of communication retries (when needed) */
|
||||
#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 */
|
||||
#define USB_HUB_DESCRIPTOR_TYPE 0x29
|
||||
|
||||
|
|
@ -821,6 +825,7 @@ hub_handle_change(int port_num, hub_port_status * status)
|
|||
static int
|
||||
hub_handle_connection(int port_num, hub_port_status * status)
|
||||
{
|
||||
struct timespec wait_time;
|
||||
int reset_tries;
|
||||
long port_speed;
|
||||
|
||||
|
|
@ -841,6 +846,8 @@ hub_handle_connection(int port_num, hub_port_status * status)
|
|||
}
|
||||
|
||||
reset_tries = 0;
|
||||
wait_time.tv_sec = 0;
|
||||
wait_time.tv_nsec = USB_HUB_RESET_DELAY;
|
||||
|
||||
/* Wait for reset completion */
|
||||
while (!status->C_PORT_RESET) {
|
||||
|
|
@ -857,6 +864,11 @@ hub_handle_connection(int port_num, hub_port_status * status)
|
|||
}
|
||||
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <usbd/hcd_common.h>
|
||||
#include <usbd/hcd_ddekit.h>
|
||||
#include <usbd/hcd_interface.h>
|
||||
#include <usbd/hcd_schedule.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 */
|
||||
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 *);
|
||||
|
||||
/* 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 */
|
||||
#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 *
|
||||
|
|
@ -255,6 +260,9 @@ hcd_device_thread(void * thread_args)
|
|||
/* Block and wait for something like 'submit URB' */
|
||||
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
|
||||
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 */
|
||||
|
|
@ -413,12 +421,45 @@ hcd_enumerate(hcd_device_state * this_device)
|
|||
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 */
|
||||
if (EXIT_SUCCESS != hcd_set_address(this_device)) {
|
||||
USB_MSG("Failed to set device address");
|
||||
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 */
|
||||
if (EXIT_SUCCESS != hcd_get_descriptor_tree(this_device)) {
|
||||
USB_MSG("Failed to get configuration descriptor tree");
|
||||
|
|
@ -448,11 +489,11 @@ static int
|
|||
hcd_get_device_descriptor(hcd_device_state * this_device)
|
||||
{
|
||||
hcd_ctrlrequest setup;
|
||||
hcd_urb urb;
|
||||
|
||||
DEBUG_DUMP;
|
||||
|
||||
/* TODO: magic numbers, no header for these */
|
||||
|
||||
/* Format setup packet */
|
||||
setup.bRequestType = 0x80; /* IN */
|
||||
setup.bRequest = 0x06; /* Get descriptor */
|
||||
|
|
@ -460,45 +501,31 @@ hcd_get_device_descriptor(hcd_device_state * this_device)
|
|||
setup.wIndex = 0x0000;
|
||||
setup.wLength = sizeof(this_device->device_desc);
|
||||
|
||||
/* Handle formatted setup packet */
|
||||
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup,
|
||||
HCD_DEFAULT_EP)) {
|
||||
USB_MSG("Handling setup packet failed");
|
||||
/* 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 = (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;
|
||||
}
|
||||
|
||||
/* Put what was read in device descriptor */
|
||||
if (EXIT_SUCCESS != hcd_finish_setup(this_device,
|
||||
&(this_device->device_desc),
|
||||
sizeof(this_device->device_desc)))
|
||||
/* Check if expected size was received */
|
||||
if (urb.out_size != setup.wLength) {
|
||||
USB_MSG("URB submission returned invalid amount of data");
|
||||
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;
|
||||
}
|
||||
|
|
@ -511,6 +538,7 @@ static int
|
|||
hcd_set_address(hcd_device_state * this_device)
|
||||
{
|
||||
hcd_ctrlrequest setup;
|
||||
hcd_urb urb;
|
||||
|
||||
DEBUG_DUMP;
|
||||
|
||||
|
|
@ -526,18 +554,31 @@ hcd_set_address(hcd_device_state * this_device)
|
|||
setup.wIndex = 0x0000;
|
||||
setup.wLength = 0x0000;
|
||||
|
||||
/* Handle formatted setup packet */
|
||||
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup,
|
||||
HCD_DEFAULT_EP)) {
|
||||
USB_MSG("Handling setup packet failed");
|
||||
/* Prepare self-URB */
|
||||
memset(&urb, 0, sizeof(urb));
|
||||
urb.direction = HCD_DIRECTION_OUT;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* Check if expected size was received */
|
||||
if (urb.out_size != setup.wLength) {
|
||||
USB_MSG("URB submission returned invalid amount of data");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -549,19 +590,24 @@ hcd_set_address(hcd_device_state * this_device)
|
|||
static int
|
||||
hcd_get_descriptor_tree(hcd_device_state * this_device)
|
||||
{
|
||||
hcd_config_descriptor config_descriptor;
|
||||
hcd_config_descriptor temp_config_descriptor;
|
||||
hcd_ctrlrequest setup;
|
||||
hcd_reg4 total_length;
|
||||
hcd_reg4 buffer_length;
|
||||
int completed;
|
||||
hcd_urb urb;
|
||||
|
||||
/* To receive data */
|
||||
hcd_reg4 expected_length;
|
||||
hcd_reg1 * expected_buffer;
|
||||
|
||||
int retval;
|
||||
|
||||
DEBUG_DUMP;
|
||||
|
||||
/* First, ask only for configuration itself to get length info */
|
||||
buffer_length = sizeof(config_descriptor);
|
||||
completed = 0;
|
||||
/* Initially */
|
||||
retval = EXIT_FAILURE;
|
||||
expected_buffer = NULL;
|
||||
|
||||
do {
|
||||
/* First part gets only configuration to find out total length */
|
||||
{
|
||||
/* TODO: Default configuration is hard-coded
|
||||
* but others are rarely used anyway */
|
||||
/* 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.wValue = 0x0200 | HCD_DEFAULT_CONFIG;
|
||||
setup.wIndex = 0x0000;
|
||||
setup.wLength = buffer_length;
|
||||
setup.wLength = sizeof(temp_config_descriptor);
|
||||
|
||||
/* Handle formatted setup packet */
|
||||
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup,
|
||||
HCD_DEFAULT_EP)) {
|
||||
USB_MSG("Handling setup packet failed");
|
||||
return EXIT_FAILURE;
|
||||
/* 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 = (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
|
||||
* then ask again for other descriptors */
|
||||
if (sizeof(config_descriptor) == buffer_length) {
|
||||
|
||||
/* Put what was already read in configuration
|
||||
* 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;
|
||||
/* Check if expected size was received */
|
||||
if (urb.out_size != setup.wLength) {
|
||||
USB_MSG("URB submission returned "
|
||||
"invalid amount of data");
|
||||
goto FINISH;
|
||||
}
|
||||
}
|
||||
while (!completed);
|
||||
|
||||
/* Validate... */
|
||||
if (EXIT_SUCCESS != hcd_finish_setup(this_device, NULL, total_length))
|
||||
return EXIT_FAILURE;
|
||||
/* Get total expected length */
|
||||
expected_length = UGETW(temp_config_descriptor.wTotalLength);
|
||||
|
||||
/* ... and create tree based on received buffer */
|
||||
if (EXIT_SUCCESS != hcd_buffer_to_tree(this_device->control_data,
|
||||
this_device->control_len,
|
||||
/* Check for abnormal value */
|
||||
if (expected_length > HCD_SANE_DESCRIPTOR_LENGTH) {
|
||||
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 should never happen for a fine device */
|
||||
USB_MSG("Illegal descriptor values");
|
||||
return EXIT_FAILURE;
|
||||
USB_MSG("Broken descriptor data");
|
||||
goto FINISH;
|
||||
}
|
||||
|
||||
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_ctrlrequest setup;
|
||||
hcd_urb urb;
|
||||
|
||||
DEBUG_DUMP;
|
||||
|
||||
|
|
@ -645,14 +737,21 @@ hcd_set_configuration(hcd_device_state * this_device, hcd_reg1 configuration)
|
|||
setup.wIndex = 0x0000;
|
||||
setup.wLength = 0x0000;
|
||||
|
||||
/* Handle formatted setup packet */
|
||||
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup,
|
||||
HCD_DEFAULT_EP)) {
|
||||
USB_MSG("Handling setup packet failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/* Prepare self-URB */
|
||||
memset(&urb, 0, sizeof(urb));
|
||||
urb.direction = HCD_DIRECTION_OUT;
|
||||
urb.endpoint = HCD_DEFAULT_EP;
|
||||
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");
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
|
@ -747,9 +848,7 @@ hcd_control_urb(hcd_device_state * this_device, hcd_urb * urb)
|
|||
}
|
||||
|
||||
/* Put what was read back into URB */
|
||||
if (EXIT_SUCCESS != hcd_finish_setup(this_device,
|
||||
urb->inout_data,
|
||||
HCD_ANY_LENGTH))
|
||||
if (EXIT_SUCCESS != hcd_finish_setup(this_device, urb->inout_data))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* Write transfer output info to URB */
|
||||
|
|
@ -986,8 +1085,7 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup,
|
|||
* hcd_finish_setup *
|
||||
*===========================================================================*/
|
||||
static int
|
||||
hcd_finish_setup(hcd_device_state * this_device, void * output,
|
||||
hcd_reg4 expected)
|
||||
hcd_finish_setup(hcd_device_state * this_device, void * output)
|
||||
{
|
||||
DEBUG_DUMP;
|
||||
|
||||
|
|
@ -997,21 +1095,6 @@ hcd_finish_setup(hcd_device_state * this_device, void * output,
|
|||
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 */
|
||||
if (NULL == output)
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb)
|
|||
hcd_decode_urb(urb, d_urb);
|
||||
|
||||
/* 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 */
|
||||
d_urb = (struct ddekit_usb_urb *)urb->original_urb;
|
||||
|
||||
/* This URB will be scheduled no more */
|
||||
hcd_unschedule_urb(urb);
|
||||
USB_ASSERT(NULL != d_urb, "Original DDEKit URB missing");
|
||||
|
||||
/* Turn HCD URB format to one handled by DDEKit */
|
||||
hcd_encode_urb(urb, d_urb);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@ static hcd_lock * urb_lock;
|
|||
/* This allows waiting for completion */
|
||||
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 */
|
||||
static void hcd_urb_scheduler_task(void *);
|
||||
|
||||
|
|
@ -102,9 +108,33 @@ usbd_deinit_scheduler(void)
|
|||
|
||||
|
||||
/*===========================================================================*
|
||||
* hcd_schedule_urb *
|
||||
* hcd_schedule_external_urb *
|
||||
*===========================================================================*/
|
||||
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)
|
||||
{
|
||||
DEBUG_DUMP;
|
||||
|
|
@ -114,12 +144,7 @@ hcd_schedule_urb(hcd_urb * urb)
|
|||
|
||||
/* Store and check if scheduler should be unlocked */
|
||||
if (EXIT_SUCCESS == hcd_store_urb(urb)) {
|
||||
|
||||
/* This is the first stored URB (possibly in a row)
|
||||
* so unlock scheduler */
|
||||
if (1 == num_stored_urbs)
|
||||
ddekit_sem_up(urb_lock);
|
||||
|
||||
ddekit_sem_up(urb_lock);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -130,7 +155,7 @@ hcd_schedule_urb(hcd_urb * urb)
|
|||
/*===========================================================================*
|
||||
* hcd_unschedule_urb *
|
||||
*===========================================================================*/
|
||||
void
|
||||
static void
|
||||
hcd_unschedule_urb(hcd_urb * urb)
|
||||
{
|
||||
DEBUG_DUMP;
|
||||
|
|
@ -150,9 +175,8 @@ hcd_urb_scheduler_task(void * UNUSED(arg))
|
|||
DEBUG_DUMP;
|
||||
|
||||
for (;;) {
|
||||
/* Wait for scheduler to unlock on first URB submit */
|
||||
if (0 == num_stored_urbs)
|
||||
ddekit_sem_down(urb_lock);
|
||||
/* Wait for scheduler to unlock on any URB submit */
|
||||
ddekit_sem_down(urb_lock);
|
||||
|
||||
/* Get URB */
|
||||
current_urb = hcd_get_urb();
|
||||
|
|
@ -169,9 +193,6 @@ hcd_urb_scheduler_task(void * UNUSED(arg))
|
|||
|
||||
/* Wait for completion */
|
||||
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;
|
||||
|
||||
/* Call completion regardless of status */
|
||||
hcd_completion_cb(urb);
|
||||
/* This URB will be scheduled no more */
|
||||
/* TODO: It would be better if this was connected
|
||||
* to setting urb_lock down */
|
||||
hcd_unschedule_urb(urb);
|
||||
|
||||
/* Handling completed */
|
||||
ddekit_sem_up(handled_lock);
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
#include <usbd/hcd_common.h>
|
||||
|
||||
/* Makes URB schedule enabled */
|
||||
int hcd_schedule_urb(hcd_urb *);
|
||||
/* Makes external (device driver) URB schedule enabled */
|
||||
int hcd_schedule_external_urb(hcd_urb *);
|
||||
|
||||
/* Makes URB schedule disabled */
|
||||
void hcd_unschedule_urb(hcd_urb *);
|
||||
/* Makes internal (HCD) URB schedule enabled */
|
||||
int hcd_schedule_internal_urb(hcd_urb *);
|
||||
|
||||
#endif /* !_HCD_SCHEDULE_H_ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user