Upgraded HCD transfers

Types for data request are fixed and commented.

Control transfer has additional call for proper completion validation.
This commit is contained in:
Wojciech Zajac 2014-06-13 15:23:42 +02:00 committed by Lionel Sambuc
parent 1858789bf6
commit 789aa37866
4 changed files with 114 additions and 45 deletions

View file

@ -33,6 +33,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_data_transfer(hcd_device_state *, hcd_datarequest *); static int hcd_data_transfer(hcd_device_state *, hcd_datarequest *);
@ -45,6 +46,10 @@ static int hcd_data_transfer(hcd_device_state *, hcd_datarequest *);
* have to be altered to allow that */ * have to be altered to allow that */
static hcd_device_state hcd_device[1]; static hcd_device_state hcd_device[1];
/* TODO: This was added for compatibility with DDELinux drivers that
* allow receiving less data than expected in URB, without error */
#define HCD_ANY_LENGTH 0xFFFFFFFFu
/*===========================================================================* /*===========================================================================*
* hcd_handle_event * * hcd_handle_event *
@ -267,8 +272,10 @@ hcd_get_device_descriptor(hcd_device_state * this_device)
} }
/* Put what was read in device descriptor */ /* Put what was read in device descriptor */
memcpy(&(this_device->device_desc), this_device->buffer, if (EXIT_SUCCESS != hcd_finish_setup(this_device,
sizeof(this_device->device_desc)); &(this_device->device_desc),
sizeof(this_device->device_desc)))
return EXIT_FAILURE;
/* Remember max packet size from device descriptor */ /* Remember max packet size from device descriptor */
this_device->max_packet_size = this_device->device_desc.bMaxPacketSize; this_device->max_packet_size = this_device->device_desc.bMaxPacketSize;
@ -378,9 +385,12 @@ hcd_get_descriptor_tree(hcd_device_state * this_device)
* then ask again for other descriptors */ * then ask again for other descriptors */
if (sizeof(config_descriptor) == buffer_length) { if (sizeof(config_descriptor) == buffer_length) {
/* Put what was read in configuration descriptor */ /* Put what was already read in configuration
memcpy(&config_descriptor, this_device->buffer, * descriptor for analysis */
sizeof(config_descriptor)); if (EXIT_SUCCESS != hcd_finish_setup(this_device,
&config_descriptor,
buffer_length))
return EXIT_FAILURE;
/* Continue only if there is more data */ /* Continue only if there is more data */
total_length = UGETW(config_descriptor.wTotalLength); total_length = UGETW(config_descriptor.wTotalLength);
@ -404,9 +414,13 @@ hcd_get_descriptor_tree(hcd_device_state * this_device)
} }
while (!completed); while (!completed);
/* Create tree based on received buffer */ /* Validate... */
if (EXIT_SUCCESS != hcd_buffer_to_tree(this_device->buffer, if (EXIT_SUCCESS != hcd_finish_setup(this_device, NULL, total_length))
this_device->data_len, return EXIT_FAILURE;
/* ... and create tree based on received buffer */
if (EXIT_SUCCESS != hcd_buffer_to_tree(this_device->control_data,
this_device->control_len,
&(this_device->config_tree))) { &(this_device->config_tree))) {
/* This should never happen for a fine device */ /* This should never happen for a fine device */
USB_MSG("Illegal descriptor values"); USB_MSG("Illegal descriptor values");
@ -532,10 +546,14 @@ hcd_control_urb(hcd_device_state * this_device, hcd_urb * urb)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* TODO: Calling memcpy may be removed when writing directly to URB */
/* Put what was read back into URB */ /* Put what was read back into URB */
memcpy(urb->inout_data, this_device->buffer, this_device->data_len); if (EXIT_SUCCESS != hcd_finish_setup(this_device,
urb->out_size = this_device->data_len; urb->inout_data,
HCD_ANY_LENGTH))
return EXIT_FAILURE;
/* Write transfer output info to URB */
urb->out_size = (hcd_reg4)this_device->control_len;
urb->inout_status = EXIT_SUCCESS; urb->inout_status = EXIT_SUCCESS;
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -591,7 +609,7 @@ hcd_non_control_urb(hcd_device_state * this_device, hcd_urb * urb)
request.type = urb->type; request.type = urb->type;
request.endpoint = urb->endpoint; request.endpoint = urb->endpoint;
request.direction = urb->direction; request.direction = urb->direction;
request.data_left = urb->in_size; request.data_left = (int)urb->in_size;
request.data = urb->inout_data; request.data = urb->inout_data;
request.interval = urb->interval; request.interval = urb->interval;
@ -608,8 +626,10 @@ hcd_non_control_urb(hcd_device_state * this_device, hcd_urb * urb)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* Transfer successfully completed */ /* Transfer successfully completed update URB */
urb->out_size = urb->in_size - request.data_left; USB_ASSERT(request.data_left >= 0,
"Negative amount of transfer data remains");
urb->out_size = urb->in_size - (hcd_reg4)request.data_left;
urb->inout_status = EXIT_SUCCESS; urb->inout_status = EXIT_SUCCESS;
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -638,8 +658,8 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup,
/* Initially... */ /* Initially... */
d = this_device->driver; d = this_device->driver;
current_byte = this_device->buffer; /* Start reading into this */ current_byte = this_device->control_data;/* Start reading into this */
this_device->data_len = 0; /* Nothing read yet */ this_device->control_len = 0; /* Nothing read yet */
/* Set parameters for further communication */ /* Set parameters for further communication */
d->setup_device(d->private_data, ep, this_device->address); d->setup_device(d->private_data, ep, this_device->address);
@ -685,7 +705,7 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup,
/* Increment */ /* Increment */
current_byte += rx_len; current_byte += rx_len;
this_device->data_len += rx_len; this_device->control_len += rx_len;
/* If full max sized packet was read... */ /* If full max sized packet was read... */
if (rx_len == (int)this_device->max_packet_size) if (rx_len == (int)this_device->max_packet_size)
@ -752,6 +772,45 @@ 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)
{
DEBUG_DUMP;
/* Validate setup transfer output length */
if (this_device->control_len < 0) {
USB_MSG("Negative control transfer output length");
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");
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;
/* Finally, copy when needed */
memcpy(output, this_device->control_data, this_device->control_len);
return EXIT_SUCCESS;
}
/*===========================================================================* /*===========================================================================*
* hcd_data_transfer * * hcd_data_transfer *
*===========================================================================*/ *===========================================================================*/
@ -764,21 +823,22 @@ hcd_data_transfer(hcd_device_state * this_device, hcd_datarequest * request)
DEBUG_DUMP; DEBUG_DUMP;
USB_ASSERT((hcd_reg1)(UE_GET_ADDR(request->endpoint)) <= HCD_LAST_EP, USB_ASSERT((request->endpoint <= HCD_LAST_EP) &&
(request->endpoint > HCD_DEFAULT_EP),
"Invalid EP number"); "Invalid EP number");
USB_ASSERT(this_device->address <= HCD_LAST_ADDR, USB_ASSERT((this_device->address <= HCD_LAST_ADDR) &&
(this_device->address > HCD_DEFAULT_ADDR),
"Invalid device address"); "Invalid device address");
/* Initially... */ /* Initially... */
d = this_device->driver; d = this_device->driver;
/* Set parameters for further communication */ /* Set parameters for further communication */
d->setup_device(d->private_data, d->setup_device(d->private_data, request->endpoint,
(hcd_reg1)request->endpoint,
this_device->address); this_device->address);
/* TODO: broken USB_IN... constants */ /* Check transfer direction first */
if (1 == request->direction) { if (HCD_DIRECTION_IN == request->direction) {
do { do {
/* Start actual data transfer */ /* Start actual data transfer */
@ -786,7 +846,7 @@ hcd_data_transfer(hcd_device_state * this_device, hcd_datarequest * request)
/* Wait for response */ /* Wait for response */
hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, hcd_device_wait(this_device, HCD_EVENT_ENDPOINT,
(hcd_reg1)request->endpoint); request->endpoint);
/* Check response */ /* Check response */
if (EXIT_SUCCESS != d->check_error(d->private_data, if (EXIT_SUCCESS != d->check_error(d->private_data,
@ -796,8 +856,8 @@ hcd_data_transfer(hcd_device_state * this_device, hcd_datarequest * request)
/* Read data received as response */ /* Read data received as response */
transfer_len = d->read_data(d->private_data, transfer_len = d->read_data(d->private_data,
(hcd_reg1 *)request->data, request->data,
(hcd_reg1)request->endpoint); request->endpoint);
request->data_left -= transfer_len; request->data_left -= transfer_len;
request->data += transfer_len; request->data += transfer_len;
@ -810,14 +870,15 @@ hcd_data_transfer(hcd_device_state * this_device, hcd_datarequest * request)
} while (0 != request->data_left); } while (0 != request->data_left);
} else if (0 == request->direction) { } else if (HCD_DIRECTION_OUT == request->direction) {
do { do {
temp_req = *request; temp_req = *request;
/* Decide temporary transfer size */ /* Decide temporary transfer size */
if (temp_req.data_left > (int)temp_req.max_packet_size) if (temp_req.data_left > (int)temp_req.max_packet_size)
temp_req.data_left = temp_req.max_packet_size; temp_req.data_left =
(int)temp_req.max_packet_size;
/* Alter actual transfer size */ /* Alter actual transfer size */
request->data += temp_req.data_left; request->data += temp_req.data_left;
@ -832,7 +893,7 @@ hcd_data_transfer(hcd_device_state * this_device, hcd_datarequest * request)
/* Wait for response */ /* Wait for response */
hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, hcd_device_wait(this_device, HCD_EVENT_ENDPOINT,
(hcd_reg1)request->endpoint); request->endpoint);
/* Check response */ /* Check response */
if (EXIT_SUCCESS != d->check_error(d->private_data, if (EXIT_SUCCESS != d->check_error(d->private_data,

View file

@ -352,7 +352,7 @@ hcd_decode_urb(hcd_urb * urb, struct ddekit_usb_urb * dde_urb)
/* TODO: Alignment of setup packet. Can DDE client guarantee that? */ /* TODO: Alignment of setup packet. Can DDE client guarantee that? */
/* Transfer data assignment */ /* Transfer data assignment */
urb->inout_data = (void *)dde_urb->data; urb->inout_data = (hcd_reg1 *)dde_urb->data;
urb->in_setup = (hcd_ctrlrequest *)dde_urb->setup_packet; urb->in_setup = (hcd_ctrlrequest *)dde_urb->setup_packet;
/* TODO: Sane size check? */ /* TODO: Sane size check? */

View file

@ -470,7 +470,7 @@ musb_rx_stage(void * cfg, hcd_datarequest * request)
core = (musb_core_config *)cfg; core = (musb_core_config *)cfg;
r = core->regs; r = core->regs;
USB_ASSERT(request->max_packet_size <= 1024, USB_ASSERT(request->max_packet_size <= HCD_MAX_MAXPACKETSIZE,
"Invalid wMaxPacketSize"); "Invalid wMaxPacketSize");
USB_ASSERT((core->ep <= HCD_LAST_EP) && (core->ep > HCD_DEFAULT_EP), USB_ASSERT((core->ep <= HCD_LAST_EP) && (core->ep > HCD_DEFAULT_EP),
"Invalid bulk EP supplied"); "Invalid bulk EP supplied");
@ -564,7 +564,7 @@ musb_tx_stage(void * cfg, hcd_datarequest * request)
core = (musb_core_config *)cfg; core = (musb_core_config *)cfg;
r = core->regs; r = core->regs;
USB_ASSERT(request->max_packet_size <= 1024, USB_ASSERT(request->max_packet_size <= HCD_MAX_MAXPACKETSIZE,
"Invalid wMaxPacketSize"); "Invalid wMaxPacketSize");
USB_ASSERT((core->ep <= HCD_LAST_EP) && (core->ep > HCD_DEFAULT_EP), USB_ASSERT((core->ep <= HCD_LAST_EP) && (core->ep > HCD_DEFAULT_EP),
"Invalid bulk EP supplied"); "Invalid bulk EP supplied");

View file

@ -171,14 +171,16 @@ typedef struct hcd_device_state hcd_device_state;
/* Non-control transfer request structure */ /* Non-control transfer request structure */
struct hcd_datarequest { struct hcd_datarequest {
char * data; hcd_reg1 * data; /* RX/TX buffer */
int data_left; int data_left; /* Amount of data to transfer (may
int endpoint; * become negative in case of error
int direction; * thus 'int') */
unsigned int max_packet_size; hcd_reg2 max_packet_size; /* Read from EP descriptor */
unsigned int interval; hcd_reg1 endpoint; /* EP number */
hcd_speed speed; hcd_reg1 interval; /* Should match one in EP descriptor */
hcd_transfer type; hcd_direction direction; /* Should match one in EP descriptor */
hcd_speed speed; /* Decided during device reset */
hcd_transfer type; /* Should match one in EP descriptor */
}; };
/* HCD's URB structure */ /* HCD's URB structure */
@ -190,9 +192,9 @@ struct hcd_urb {
/* Transfer (in/out signifies what may be overwritten by HCD) */ /* Transfer (in/out signifies what may be overwritten by HCD) */
hcd_ctrlrequest * in_setup; hcd_ctrlrequest * in_setup;
void * inout_data; hcd_reg1 * inout_data;
hcd_reg4 in_size; hcd_reg4 in_size;
int out_size; hcd_reg4 out_size;
int inout_status; /* URB submission/validity status */ int inout_status; /* URB submission/validity status */
/* Transfer control */ /* Transfer control */
@ -218,11 +220,16 @@ struct hcd_device_state {
hcd_state state; hcd_state state;
hcd_reg1 address; hcd_reg1 address;
/* Number of bytes received/transmitted in last transfer */ /*
int data_len; * Control transfer's local data:
*/
/* Number of bytes received/transmitted in last control transfer (may
* become negative in case of error thus 'int') */
int control_len;
/* Word aligned buffer for each device to hold transfered data */ /* Word aligned buffer for each device to hold transfered data */
hcd_reg1 buffer[MAX_WTOTALLENGTH] __aligned(sizeof(hcd_reg4)); hcd_reg1 control_data[MAX_WTOTALLENGTH] __aligned(sizeof(hcd_reg4));
}; };
@ -258,6 +265,7 @@ struct hcd_device_state {
/* Default MaxPacketSize for control transfer */ /* Default MaxPacketSize for control transfer */
#define HCD_LS_MAXPACKETSIZE 8u #define HCD_LS_MAXPACKETSIZE 8u
#define HCD_HS_MAXPACKETSIZE 64u #define HCD_HS_MAXPACKETSIZE 64u
#define HCD_MAX_MAXPACKETSIZE 1024u
/*===========================================================================* /*===========================================================================*