HCD changes
. Verbose debug output in HCD . HCD now outputs threading information in debug build. . With this patch, multiple high speed usb sticks can work with high speed usb hub. . Allow HCD to use a sequence of hubs . Make HCD ignore URBs for removed devices . HCD has list of allocated devices to determine validity of events . DDEKit debug build's error fixed . HCD handles pending URB on device detach . With this, URB scheduler is no longer locked on device detach NAK limit fixed Change-Id: I60036fa9902b98ac9090196dfe08a385155041c8
This commit is contained in:
parent
d401ea8186
commit
0d6daaaebf
|
|
@ -38,7 +38,7 @@ main(int UNUSED(argc), char * UNUSED(argv[]))
|
||||||
int ret_val;
|
int ret_val;
|
||||||
|
|
||||||
USB_MSG("Starting USBD");
|
USB_MSG("Starting USBD");
|
||||||
USB_DBG("Built: %s %s", __DATE__, __TIME__);
|
USB_MSG("Built: %s %s", __DATE__, __TIME__);
|
||||||
|
|
||||||
/* Basic SEF,DDE,... initialization */
|
/* Basic SEF,DDE,... initialization */
|
||||||
usbd_init();
|
usbd_init();
|
||||||
|
|
@ -75,7 +75,7 @@ main(int UNUSED(argc), char * UNUSED(argv[]))
|
||||||
static int
|
static int
|
||||||
usbd_sef_handler(int type, sef_init_info_t * UNUSED(info))
|
usbd_sef_handler(int type, sef_init_info_t * UNUSED(info))
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
/* No DEBUG_DUMP, threading unavailable yet */
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SEF_INIT_FRESH:
|
case SEF_INIT_FRESH:
|
||||||
|
|
@ -126,7 +126,7 @@ usbd_start(void)
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* Driver's "main loop" is within DDEKit server thread */
|
/* Driver's "main loop" is within DDEKit server thread */
|
||||||
usbd_th = ddekit_thread_create(usbd_server_thread, NULL, "usbd");
|
usbd_th = ddekit_thread_create(usbd_server_thread, NULL, "ddekit_usb");
|
||||||
|
|
||||||
/* After spawning, allow server thread to work */
|
/* After spawning, allow server thread to work */
|
||||||
if (NULL != usbd_th) {
|
if (NULL != usbd_th) {
|
||||||
|
|
@ -157,16 +157,18 @@ usbd_start(void)
|
||||||
static void
|
static void
|
||||||
usbd_init(void)
|
usbd_init(void)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
/* No DEBUG_DUMP, threading unavailable yet */
|
||||||
|
|
||||||
/* Set one handler for all messages */
|
/* Set one handler for all messages */
|
||||||
sef_setcb_init_fresh(usbd_sef_handler);
|
sef_setcb_init_fresh(usbd_sef_handler);
|
||||||
sef_setcb_init_lu(usbd_sef_handler);
|
sef_setcb_init_lu(usbd_sef_handler);
|
||||||
sef_setcb_init_restart(usbd_sef_handler);
|
sef_setcb_init_restart(usbd_sef_handler);
|
||||||
sef_setcb_signal_handler(usbd_signal_handler);
|
|
||||||
|
|
||||||
/* Initialize DDEkit (involves sef_startup()) */
|
/* Initialize DDEkit (involves sef_startup()) */
|
||||||
ddekit_init();
|
ddekit_init();
|
||||||
|
|
||||||
|
/* After threading initialization, add signal handler */
|
||||||
|
sef_setcb_signal_handler(usbd_signal_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ static hcd_device_state * hcd_get_child_for_ep(hcd_device_state *, hcd_reg1);
|
||||||
/* For HCD level, hub handling */
|
/* For HCD level, hub handling */
|
||||||
static void hcd_add_child(hcd_device_state *, hcd_reg1, hcd_speed);
|
static void hcd_add_child(hcd_device_state *, hcd_reg1, hcd_speed);
|
||||||
static void hcd_delete_child(hcd_device_state *, hcd_reg1);
|
static void hcd_delete_child(hcd_device_state *, hcd_reg1);
|
||||||
|
static void hcd_disconnect_tree(hcd_device_state *);
|
||||||
|
static void hcd_dump_tree(hcd_device_state *, hcd_reg1);
|
||||||
|
|
||||||
/* Typical USD device communication procedures */
|
/* Typical USD device communication procedures */
|
||||||
static int hcd_enumerate(hcd_device_state *);
|
static int hcd_enumerate(hcd_device_state *);
|
||||||
|
|
@ -36,6 +38,7 @@ static int hcd_set_address(hcd_device_state *);
|
||||||
static int hcd_get_descriptor_tree(hcd_device_state *);
|
static int hcd_get_descriptor_tree(hcd_device_state *);
|
||||||
static int hcd_set_configuration(hcd_device_state *, hcd_reg1);
|
static int hcd_set_configuration(hcd_device_state *, hcd_reg1);
|
||||||
static void hcd_handle_urb(hcd_device_state *);
|
static void hcd_handle_urb(hcd_device_state *);
|
||||||
|
static void hcd_complete_urb(hcd_device_state *);
|
||||||
static int hcd_control_urb(hcd_device_state *, hcd_urb *);
|
static int hcd_control_urb(hcd_device_state *, hcd_urb *);
|
||||||
static int hcd_non_control_urb(hcd_device_state *, hcd_urb *);
|
static int hcd_non_control_urb(hcd_device_state *, hcd_urb *);
|
||||||
|
|
||||||
|
|
@ -69,13 +72,30 @@ hcd_handle_event(hcd_device_state * device, hcd_event event, hcd_reg1 val)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* No device may be supplied */
|
/* Invalid device may be supplied */
|
||||||
if (NULL == device) {
|
if (EXIT_SUCCESS != hcd_check_device(device)) {
|
||||||
USB_MSG("No device available for event: 0x%02X, value: 0x%02X",
|
USB_MSG("No device available for event: 0x%02X, value: 0x%02X",
|
||||||
event, val);
|
event, val);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HCD_DUMP_DEVICE_TREE
|
||||||
|
/* This can be unlocked to dump current USB device tree on event */
|
||||||
|
{
|
||||||
|
/* Go to the base of USB device tree and
|
||||||
|
* print the current state of it */
|
||||||
|
hcd_device_state * base;
|
||||||
|
|
||||||
|
base = device;
|
||||||
|
|
||||||
|
while (NULL != base->parent)
|
||||||
|
base = base->parent;
|
||||||
|
|
||||||
|
USB_MSG("Current state of USB device tree:");
|
||||||
|
hcd_dump_tree(base, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Handle event and forward control to device thread when required */
|
/* Handle event and forward control to device thread when required */
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case HCD_EVENT_CONNECTED:
|
case HCD_EVENT_CONNECTED:
|
||||||
|
|
@ -95,13 +115,9 @@ hcd_handle_event(hcd_device_state * device, hcd_event event, hcd_reg1 val)
|
||||||
"Device is marked as 'disconnected' "
|
"Device is marked as 'disconnected' "
|
||||||
"for 'disconnection' event");
|
"for 'disconnection' event");
|
||||||
|
|
||||||
/* If connect callback was used before, call
|
/* Make this device and all attached children
|
||||||
* it's equivalent to signal disconnection */
|
* disconnect recursively */
|
||||||
if (HCD_STATE_CONNECTED == device->state)
|
hcd_disconnect_tree(device);
|
||||||
hcd_disconnect_cb(device);
|
|
||||||
|
|
||||||
/* Handle device disconnection (freeing memory etc.) */
|
|
||||||
hcd_disconnect_device(device);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -143,10 +159,11 @@ hcd_handle_event(hcd_device_state * device, hcd_event event, hcd_reg1 val)
|
||||||
"Device is marked as 'disconnected' "
|
"Device is marked as 'disconnected' "
|
||||||
"for 'hub port detach' event");
|
"for 'hub port detach' event");
|
||||||
|
|
||||||
|
hcd_delete_child(device, val);
|
||||||
|
|
||||||
USB_MSG("Device disconnected from "
|
USB_MSG("Device disconnected from "
|
||||||
"hub 0x%08X, port %u", device, val);
|
"hub 0x%08X, port %u", device, val);
|
||||||
|
|
||||||
hcd_delete_child(device, val);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCD_EVENT_ENDPOINT:
|
case HCD_EVENT_ENDPOINT:
|
||||||
|
|
@ -260,9 +277,6 @@ 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 */
|
||||||
|
|
@ -294,40 +308,48 @@ hcd_device_finish(hcd_device_state * this_device, const char * finish_msg)
|
||||||
static hcd_device_state *
|
static hcd_device_state *
|
||||||
hcd_get_child_for_ep(hcd_device_state * device, hcd_reg1 ep)
|
hcd_get_child_for_ep(hcd_device_state * device, hcd_reg1 ep)
|
||||||
{
|
{
|
||||||
hcd_device_state * d;
|
hcd_device_state * child_found;
|
||||||
hcd_device_state * found;
|
hcd_device_state * final_found;
|
||||||
int child_num;
|
hcd_device_state * child;
|
||||||
|
hcd_reg1 child_num;
|
||||||
|
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* Start with parent */
|
/* Nothing yet */
|
||||||
d = device;
|
final_found = NULL;
|
||||||
child_num = 0;
|
|
||||||
|
|
||||||
/* Nothing found yet */
|
/* Check if any children (and their children) wait for EP event */
|
||||||
found = NULL;
|
/* Every device in tree is checked every time so errors can be found */
|
||||||
|
for (child_num = 0; child_num < HCD_CHILDREN; child_num++) {
|
||||||
|
/* Device, to be checked for EP event recursively... */
|
||||||
|
child = device->child[child_num];
|
||||||
|
|
||||||
/* When device has multiple children (hub), this allows
|
/* ...but only if attached */
|
||||||
* routing interrupt login downstream */
|
if (NULL != child) {
|
||||||
do {
|
/* Look deeper first */
|
||||||
/* Must exist and match requirements */
|
child_found = hcd_get_child_for_ep(child, ep);
|
||||||
if ((NULL != d) &&
|
|
||||||
(HCD_EVENT_ENDPOINT == d->wait_event) &&
|
|
||||||
(ep == d->wait_ep)) {
|
|
||||||
|
|
||||||
/* Waiting for EP by multiple devices is mutually
|
if (NULL != child_found) {
|
||||||
* exclusive, as long as scheduler works correctly */
|
/* Only one device can wait for EP event */
|
||||||
USB_ASSERT(NULL == found, "More than one device waits "
|
USB_ASSERT((NULL == final_found),
|
||||||
"for given endpoint interrupt");
|
"More than one device waits for EP");
|
||||||
found = d;
|
/* Remember what was found */
|
||||||
|
final_found = child_found;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check next child */
|
/* Check this device last */
|
||||||
d = device->child[child_num++];
|
if ((HCD_EVENT_ENDPOINT == device->wait_event) &&
|
||||||
|
(ep == device->wait_ep)) {
|
||||||
|
/* Only one device can wait for EP event */
|
||||||
|
USB_ASSERT((NULL == final_found),
|
||||||
|
"More than one device waits for EP");
|
||||||
|
/* Remember what was found */
|
||||||
|
final_found = device;
|
||||||
|
}
|
||||||
|
|
||||||
} while(child_num <= HCD_CHILDREN);
|
return final_found;
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -365,27 +387,85 @@ hcd_add_child(hcd_device_state * parent, hcd_reg1 port, hcd_speed speed)
|
||||||
static void
|
static void
|
||||||
hcd_delete_child(hcd_device_state * parent, hcd_reg1 port)
|
hcd_delete_child(hcd_device_state * parent, hcd_reg1 port)
|
||||||
{
|
{
|
||||||
|
hcd_device_state * child;
|
||||||
|
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
USB_ASSERT(port < HCD_CHILDREN, "Port number too high");
|
USB_ASSERT(port < HCD_CHILDREN, "Port number too high");
|
||||||
USB_ASSERT(NULL != parent->child[port], "Child device does not exist");
|
|
||||||
|
|
||||||
/* If connect callback was used before, call
|
child = parent->child[port]; /* Child to be detached */
|
||||||
* it's equivalent to signal disconnection */
|
|
||||||
if (HCD_STATE_CONNECTED == parent->child[port]->state)
|
|
||||||
hcd_disconnect_cb(parent->child[port]);
|
|
||||||
|
|
||||||
/* Disconnect to release fields */
|
USB_ASSERT(NULL != child, "Child device does not exist");
|
||||||
hcd_disconnect_device(parent->child[port]);
|
|
||||||
|
/* Make this child device and all its attached children
|
||||||
|
* disconnect recursively */
|
||||||
|
hcd_disconnect_tree(child);
|
||||||
|
|
||||||
/* Delete to release device itself */
|
/* Delete to release device itself */
|
||||||
hcd_delete_device(parent->child[port]);
|
hcd_delete_device(child);
|
||||||
|
|
||||||
/* Mark as released */
|
/* Mark as released */
|
||||||
parent->child[port] = NULL;
|
parent->child[port] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_disconnect_tree *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_disconnect_tree(hcd_device_state * device)
|
||||||
|
{
|
||||||
|
hcd_reg1 child_num;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Generate disconnect event for all children */
|
||||||
|
for (child_num = 0; child_num < HCD_CHILDREN; child_num++) {
|
||||||
|
if (NULL != device->child[child_num])
|
||||||
|
hcd_handle_event(device, HCD_EVENT_PORT_DISCONNECTED,
|
||||||
|
child_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this device was detached during URB handling, some steps must be
|
||||||
|
* taken to ensure that no process/thread is waiting for completion */
|
||||||
|
if (NULL != device->urb) {
|
||||||
|
USB_MSG("Unplugged device had unhandled URB");
|
||||||
|
/* Tell device driver that device was detached */
|
||||||
|
/* TODO: ENODEV selected for that */
|
||||||
|
device->urb->inout_status = ENODEV;
|
||||||
|
hcd_complete_urb(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If connect callback was used before, call
|
||||||
|
* it's equivalent to signal disconnection */
|
||||||
|
if (HCD_STATE_CONNECTED == device->state)
|
||||||
|
hcd_disconnect_cb(device);
|
||||||
|
|
||||||
|
/* Handle device disconnection (freeing memory etc.) */
|
||||||
|
hcd_disconnect_device(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_dump_tree *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_dump_tree(hcd_device_state * device, hcd_reg1 level)
|
||||||
|
{
|
||||||
|
hcd_reg1 child_num;
|
||||||
|
|
||||||
|
/* DEBUG_DUMP; */ /* Let's keep tree output cleaner */
|
||||||
|
|
||||||
|
USB_MSG("Device on level %03u: 0x%08X", level, device);
|
||||||
|
|
||||||
|
/* Traverse device tree recursively */
|
||||||
|
for (child_num = 0; child_num < HCD_CHILDREN; child_num++) {
|
||||||
|
if (NULL != device->child[child_num])
|
||||||
|
hcd_dump_tree(device->child[child_num], level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* hcd_enumerate *
|
* hcd_enumerate *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
@ -803,10 +883,27 @@ hcd_handle_urb(hcd_device_state * this_device)
|
||||||
} else
|
} else
|
||||||
USB_MSG("Invalid URB supplied");
|
USB_MSG("Invalid URB supplied");
|
||||||
|
|
||||||
|
/* Perform completion routine */
|
||||||
|
hcd_complete_urb(this_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_complete_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_complete_urb(hcd_device_state * this_device)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* Signal scheduler that URB was handled */
|
/* Signal scheduler that URB was handled */
|
||||||
/* TODO: This works based on the fact that device thread has higher
|
this_device->urb->handled(this_device->urb);
|
||||||
* priority than scheduler and won't change context within this call */
|
|
||||||
urb->handled(urb);
|
/* Use this callback in case it is an external URB */
|
||||||
|
hcd_completion_cb(this_device->urb);
|
||||||
|
|
||||||
|
/* Make device forget about this URB */
|
||||||
|
this_device->urb = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -916,7 +1013,14 @@ hcd_non_control_urb(hcd_device_state * this_device, hcd_urb * urb)
|
||||||
request.direction = urb->direction;
|
request.direction = urb->direction;
|
||||||
request.data_left = (int)urb->in_size;
|
request.data_left = (int)urb->in_size;
|
||||||
request.data = urb->inout_data;
|
request.data = urb->inout_data;
|
||||||
|
/* TODO: This was changed to allow software scheduler to work correctly
|
||||||
|
* by switching URBs when they NAK, rather than waiting forever if URB
|
||||||
|
* which requires such waiting, was issued */
|
||||||
|
#if 0
|
||||||
request.interval = urb->interval;
|
request.interval = urb->interval;
|
||||||
|
#else
|
||||||
|
request.interval = HCD_DEFAULT_NAKLIMIT;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Assign to let know how much data can be transfered at a time */
|
/* Assign to let know how much data can be transfered at a time */
|
||||||
request.max_packet_size = UGETW(e->descriptor.wMaxPacketSize);
|
request.max_packet_size = UGETW(e->descriptor.wMaxPacketSize);
|
||||||
|
|
@ -967,7 +1071,8 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup,
|
||||||
this_device->control_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->current_address);
|
d->setup_device(d->private_data, ep, this_device->current_address,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
/* Send setup packet */
|
/* Send setup packet */
|
||||||
d->setup_stage(d->private_data, setup);
|
d->setup_stage(d->private_data, setup);
|
||||||
|
|
@ -1130,7 +1235,9 @@ hcd_data_transfer(hcd_device_state * this_device, hcd_datarequest * request)
|
||||||
|
|
||||||
/* Set parameters for further communication */
|
/* Set parameters for further communication */
|
||||||
d->setup_device(d->private_data, request->endpoint,
|
d->setup_device(d->private_data, request->endpoint,
|
||||||
this_device->current_address);
|
this_device->current_address,
|
||||||
|
&(this_device->ep_tx_tog[request->endpoint]),
|
||||||
|
&(this_device->ep_rx_tog[request->endpoint]));
|
||||||
|
|
||||||
/* Check transfer direction first */
|
/* Check transfer direction first */
|
||||||
if (HCD_DIRECTION_IN == request->direction) {
|
if (HCD_DIRECTION_IN == request->direction) {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,13 @@ static hcd_reg1 hcd_reserve_addr(hcd_driver_state *);
|
||||||
static void hcd_release_addr(hcd_driver_state *, hcd_reg1);
|
static void hcd_release_addr(hcd_driver_state *, hcd_reg1);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Local definitions *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* List of all allocated devices */
|
||||||
|
static hcd_device_state * dev_list = NULL;
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* hcd_os_interrupt_attach *
|
* hcd_os_interrupt_attach *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
@ -282,7 +289,7 @@ hcd_device_wait(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
USB_DBG("Device 0x%08X wait (0x%02X, 0x%02X)", device, event, ep);
|
USB_DBG("0x%08X wait (0x%02X, 0x%02X)", device, event, ep);
|
||||||
|
|
||||||
device->wait_event = event;
|
device->wait_event = event;
|
||||||
device->wait_ep = ep;
|
device->wait_ep = ep;
|
||||||
|
|
@ -299,7 +306,7 @@ hcd_device_continue(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
USB_DBG("Device 0x%08X continue (0x%02X, 0x%02X)", device, event, ep);
|
USB_DBG("0x%08X continue (0x%02X, 0x%02X)", device, event, ep);
|
||||||
|
|
||||||
USB_ASSERT(device->wait_event == event, "Unexpected event");
|
USB_ASSERT(device->wait_event == event, "Unexpected event");
|
||||||
USB_ASSERT(device->wait_ep == ep, "Unexpected endpoint");
|
USB_ASSERT(device->wait_ep == ep, "Unexpected endpoint");
|
||||||
|
|
@ -323,6 +330,18 @@ hcd_new_device(void)
|
||||||
|
|
||||||
USB_ASSERT(NULL != d, "Failed to allocate device");
|
USB_ASSERT(NULL != d, "Failed to allocate device");
|
||||||
|
|
||||||
|
if (NULL == dev_list) {
|
||||||
|
dev_list = d;
|
||||||
|
} else {
|
||||||
|
d->_next = dev_list;
|
||||||
|
dev_list = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HCD_DUMP_DEVICE_LIST
|
||||||
|
/* Dump updated state of device list */
|
||||||
|
hcd_dump_devices();
|
||||||
|
#endif
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,9 +352,78 @@ hcd_new_device(void)
|
||||||
void
|
void
|
||||||
hcd_delete_device(hcd_device_state * d)
|
hcd_delete_device(hcd_device_state * d)
|
||||||
{
|
{
|
||||||
|
hcd_device_state * temp;
|
||||||
|
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
if (d == dev_list) {
|
||||||
|
dev_list = dev_list->_next;
|
||||||
|
} else {
|
||||||
|
temp = dev_list;
|
||||||
|
|
||||||
|
/* Find the device and ... */
|
||||||
|
while (temp->_next != d) {
|
||||||
|
USB_ASSERT(NULL != temp->_next,
|
||||||
|
"Invalid state of device list");
|
||||||
|
temp = temp->_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ...make device list forget about it */
|
||||||
|
temp->_next = temp->_next->_next;
|
||||||
|
}
|
||||||
|
|
||||||
free(d);
|
free(d);
|
||||||
|
|
||||||
|
#ifdef HCD_DUMP_DEVICE_LIST
|
||||||
|
/* Dump updated state of device list */
|
||||||
|
hcd_dump_devices();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_dump_devices *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_dump_devices(void)
|
||||||
|
{
|
||||||
|
hcd_device_state * temp;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
temp = dev_list;
|
||||||
|
|
||||||
|
USB_MSG("Allocated devices:");
|
||||||
|
|
||||||
|
while (NULL != temp) {
|
||||||
|
USB_MSG("0x%08X", (int)temp);
|
||||||
|
temp = temp->_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_check_device *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_check_device(hcd_device_state * d)
|
||||||
|
{
|
||||||
|
hcd_device_state * temp;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
temp = dev_list;
|
||||||
|
|
||||||
|
/* Traverse the list of allocated devices
|
||||||
|
* to determine validity of this one */
|
||||||
|
while (NULL != temp) {
|
||||||
|
if (temp == d)
|
||||||
|
return EXIT_SUCCESS; /* Device found within the list */
|
||||||
|
temp = temp->_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device was not found, may have been removed earlier */
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -308,8 +308,9 @@ 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;
|
||||||
|
|
||||||
USB_ASSERT(NULL != d_urb, "Original DDEKit URB missing");
|
/* Original URB will not be NULL if URB
|
||||||
|
* was external (from device driver) */
|
||||||
|
if (NULL != d_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);
|
||||||
|
|
||||||
|
|
@ -318,6 +319,7 @@ hcd_completion_cb(hcd_urb * urb)
|
||||||
|
|
||||||
completion_cb(d_urb->priv);
|
completion_cb(d_urb->priv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,8 @@ usbd_init_scheduler(void)
|
||||||
num_stored_urbs = 0;
|
num_stored_urbs = 0;
|
||||||
memset(stored_urb, 0, sizeof(stored_urb));
|
memset(stored_urb, 0, sizeof(stored_urb));
|
||||||
|
|
||||||
urb_thread = ddekit_thread_create(hcd_urb_scheduler_task, NULL, "urb");
|
urb_thread = ddekit_thread_create(hcd_urb_scheduler_task, NULL,
|
||||||
|
"scheduler");
|
||||||
if (NULL == urb_thread)
|
if (NULL == urb_thread)
|
||||||
goto ERR1;
|
goto ERR1;
|
||||||
|
|
||||||
|
|
@ -170,6 +171,7 @@ hcd_unschedule_urb(hcd_urb * urb)
|
||||||
static void
|
static void
|
||||||
hcd_urb_scheduler_task(void * UNUSED(arg))
|
hcd_urb_scheduler_task(void * UNUSED(arg))
|
||||||
{
|
{
|
||||||
|
hcd_device_state * current_device;
|
||||||
hcd_urb * current_urb;
|
hcd_urb * current_urb;
|
||||||
|
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
@ -181,18 +183,37 @@ hcd_urb_scheduler_task(void * UNUSED(arg))
|
||||||
/* Get URB */
|
/* Get URB */
|
||||||
current_urb = hcd_get_urb();
|
current_urb = hcd_get_urb();
|
||||||
|
|
||||||
|
/* Get URB's target device */
|
||||||
|
current_device = current_urb->target_device;
|
||||||
|
|
||||||
/* Check for mismatch */
|
/* Check for mismatch */
|
||||||
USB_ASSERT(NULL != current_urb, "URB missing after URB unlock");
|
USB_ASSERT(NULL != current_urb, "URB missing after URB unlock");
|
||||||
|
|
||||||
|
/* Check if URB's device is still allocated */
|
||||||
|
if (EXIT_SUCCESS == hcd_check_device(current_device)) {
|
||||||
/* Tell device that this is its URB */
|
/* Tell device that this is its URB */
|
||||||
current_urb->target_device->urb = current_urb;
|
current_device->urb = current_urb;
|
||||||
|
|
||||||
/* Start handling URB event */
|
/* Start handling URB event */
|
||||||
hcd_handle_event(current_urb->target_device,
|
hcd_handle_event(current_device, HCD_EVENT_URB,
|
||||||
HCD_EVENT_URB, HCD_UNUSED_VAL);
|
HCD_UNUSED_VAL);
|
||||||
|
|
||||||
/* Wait for completion */
|
/* Wait for completion */
|
||||||
ddekit_sem_down(handled_lock);
|
ddekit_sem_down(handled_lock);
|
||||||
|
|
||||||
|
/* TODO: Not enough DDEKit thread priorities
|
||||||
|
* for a better solution */
|
||||||
|
/* Yield, to allow unlocking thread, to continue
|
||||||
|
* before next URB is used */
|
||||||
|
ddekit_yield();
|
||||||
|
|
||||||
|
/* Makes thread debugging easier */
|
||||||
|
USB_DBG("URB handled, scheduler unlocked");
|
||||||
|
} else {
|
||||||
|
USB_MSG("Device 0x%08X for URB 0x%08X, is unavailable",
|
||||||
|
(int)current_device,
|
||||||
|
(int)current_urb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,8 +227,6 @@ hcd_urb_handled(hcd_urb * urb)
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* This URB will be scheduled no more */
|
/* 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);
|
hcd_unschedule_urb(urb);
|
||||||
|
|
||||||
/* Handling completed */
|
/* Handling completed */
|
||||||
|
|
|
||||||
|
|
@ -345,13 +345,16 @@ musb_core_stop(void * cfg)
|
||||||
* musb_setup_device *
|
* musb_setup_device *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void
|
void
|
||||||
musb_setup_device(void * cfg, hcd_reg1 ep, hcd_reg1 addr)
|
musb_setup_device(void * cfg, hcd_reg1 ep, hcd_reg1 addr,
|
||||||
|
hcd_datatog * tx_tog, hcd_datatog * rx_tog)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* Assign */
|
/* Assign */
|
||||||
((musb_core_config *)cfg)->ep = ep;
|
((musb_core_config *)cfg)->ep = ep;
|
||||||
((musb_core_config *)cfg)->addr = addr;
|
((musb_core_config *)cfg)->addr = addr;
|
||||||
|
((musb_core_config *)cfg)->datatog_tx = tx_tog;
|
||||||
|
((musb_core_config *)cfg)->datatog_rx = rx_tog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -372,7 +375,7 @@ musb_reset_device(void * cfg, hcd_speed * speed)
|
||||||
r = core->regs;
|
r = core->regs;
|
||||||
|
|
||||||
/* Set initial parameters */
|
/* Set initial parameters */
|
||||||
musb_setup_device(core, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR);
|
musb_setup_device(core, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR, NULL, NULL);
|
||||||
|
|
||||||
/* Set EP and device address to be used in this command */
|
/* Set EP and device address to be used in this command */
|
||||||
musb_set_state(core);
|
musb_set_state(core);
|
||||||
|
|
@ -534,16 +537,16 @@ musb_rx_stage(void * cfg, hcd_datarequest * request)
|
||||||
|
|
||||||
/* Make controller reconfigure */
|
/* Make controller reconfigure */
|
||||||
host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
||||||
if (MUSB_DATATOG_UNKNOWN == core->datatog_rx[core->ep]) {
|
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOGWREN); /* Enable first */
|
||||||
/* Reset DATA toggle on first transfer */
|
|
||||||
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_CLRDATATOG);
|
|
||||||
core->datatog_rx[core->ep] = MUSB_DATATOG_INIT;
|
|
||||||
}
|
|
||||||
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO);
|
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
|
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
|
||||||
|
|
||||||
/* Request packet */
|
/* Set data toggle and start receiving */
|
||||||
host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
||||||
|
if (HCD_DATATOG_DATA0 == *(core->datatog_rx))
|
||||||
|
HCD_CLR(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOG);
|
||||||
|
else
|
||||||
|
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOG);
|
||||||
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_REQPKT);
|
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_REQPKT);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
|
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
|
||||||
}
|
}
|
||||||
|
|
@ -630,19 +633,20 @@ musb_tx_stage(void * cfg, hcd_datarequest * request)
|
||||||
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE);
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE);
|
||||||
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_ISO);
|
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_ISO);
|
||||||
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_AUTOSET);
|
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_AUTOSET);
|
||||||
if (MUSB_DATATOG_UNKNOWN == core->datatog_tx[core->ep]) {
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOGWREN); /* Enable first */
|
||||||
/* Reset DATA toggle on first transfer */
|
/* TODO: May have no effect */
|
||||||
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_CLRDATATOG);
|
|
||||||
core->datatog_tx[core->ep] = MUSB_DATATOG_INIT;
|
|
||||||
}
|
|
||||||
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
|
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
|
||||||
|
|
||||||
/* Put data in FIFO */
|
/* Put data in FIFO */
|
||||||
musb_write_fifo(cfg, request->data, request->data_left, core->ep);
|
musb_write_fifo(cfg, request->data, request->data_left, core->ep);
|
||||||
|
|
||||||
/* Request packet */
|
/* Set data toggle and start transmitting */
|
||||||
host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
||||||
|
if (HCD_DATATOG_DATA0 == *(core->datatog_tx))
|
||||||
|
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOG);
|
||||||
|
else
|
||||||
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOG);
|
||||||
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_TXPKTRDY);
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_TXPKTRDY);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
|
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
|
||||||
}
|
}
|
||||||
|
|
@ -790,6 +794,7 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
}
|
}
|
||||||
musb_error_case;
|
musb_error_case;
|
||||||
|
|
||||||
|
musb_core_config * core;
|
||||||
void * r;
|
void * r;
|
||||||
hcd_reg2 host_csr;
|
hcd_reg2 host_csr;
|
||||||
musb_error_case error_case;
|
musb_error_case error_case;
|
||||||
|
|
@ -800,7 +805,8 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
USB_ASSERT(HCD_TRANSFER_ISOCHRONOUS != xfer,
|
USB_ASSERT(HCD_TRANSFER_ISOCHRONOUS != xfer,
|
||||||
"ISO transfer not supported");
|
"ISO transfer not supported");
|
||||||
|
|
||||||
r = ((musb_core_config *)cfg)->regs;
|
core = (musb_core_config *)cfg;
|
||||||
|
r = core->regs;
|
||||||
|
|
||||||
/* Set EP and device address to be used in this command */
|
/* Set EP and device address to be used in this command */
|
||||||
musb_set_state((musb_core_config *)cfg);
|
musb_set_state((musb_core_config *)cfg);
|
||||||
|
|
@ -859,6 +865,13 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
/* Get TX status register */
|
/* Get TX status register */
|
||||||
host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
||||||
|
|
||||||
|
/* Check for completion */
|
||||||
|
if (!(host_csr & MUSB_VAL_HOST_TXCSR_TXPKTRDY)) {
|
||||||
|
/* ACK received update data toggle */
|
||||||
|
*(core->datatog_tx) ^= HCD_DATATOG_DATA1;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for common errors */
|
/* Check for common errors */
|
||||||
if (host_csr & MUSB_VAL_HOST_TXCSR_ERROR) {
|
if (host_csr & MUSB_VAL_HOST_TXCSR_ERROR) {
|
||||||
USB_MSG("HOST_TXCSR ERROR: %04X", host_csr);
|
USB_MSG("HOST_TXCSR ERROR: %04X", host_csr);
|
||||||
|
|
@ -876,18 +889,30 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
|
|
||||||
if (host_csr & MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT) {
|
if (host_csr & MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT) {
|
||||||
USB_MSG("HOST_TXCSR NAK_TIMEOUT: %04X", host_csr);
|
USB_MSG("HOST_TXCSR NAK_TIMEOUT: %04X", host_csr);
|
||||||
|
/* Flush FIFO before clearing NAKTIMEOUT
|
||||||
|
* to abort transfer */
|
||||||
|
HCD_SET(host_csr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
|
||||||
|
host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
||||||
HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT);
|
HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
|
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
USB_ASSERT(0, "Invalid state of HOST_TXCSR");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MUSB_IN_ERROR_CASE == error_case) {
|
if (MUSB_IN_ERROR_CASE == error_case) {
|
||||||
/* Get RX status register */
|
/* Get RX status register */
|
||||||
host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
||||||
|
|
||||||
|
/* Check for completion */
|
||||||
|
if (host_csr & MUSB_VAL_HOST_RXCSR_RXPKTRDY) {
|
||||||
|
/* ACK received update data toggle */
|
||||||
|
*(core->datatog_rx) ^= HCD_DATATOG_DATA1;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for common errors */
|
/* Check for common errors */
|
||||||
if (host_csr & MUSB_VAL_HOST_RXCSR_ERROR) {
|
if (host_csr & MUSB_VAL_HOST_RXCSR_ERROR) {
|
||||||
USB_MSG("HOST_RXCSR ERROR: %04X", host_csr);
|
USB_MSG("HOST_RXCSR ERROR: %04X", host_csr);
|
||||||
|
|
@ -905,12 +930,16 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
|
|
||||||
if (host_csr & MUSB_VAL_HOST_RXCSR_NAKTIMEOUT) {
|
if (host_csr & MUSB_VAL_HOST_RXCSR_NAKTIMEOUT) {
|
||||||
USB_MSG("HOST_RXCSR NAK_TIMEOUT: %04X", host_csr);
|
USB_MSG("HOST_RXCSR NAK_TIMEOUT: %04X", host_csr);
|
||||||
|
/* Clear REQPKT before NAKTIMEOUT to abort transfer */
|
||||||
|
HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_REQPKT);
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
|
||||||
|
host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
||||||
HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_NAKTIMEOUT);
|
HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_NAKTIMEOUT);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
|
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
USB_ASSERT(0, "Invalid state of HOST_RXCSR");
|
||||||
}
|
}
|
||||||
|
|
||||||
USB_MSG("Invalid USB transfer error check: 0x%X, 0x%X, 0x%X",
|
USB_MSG("Invalid USB transfer error check: 0x%X, 0x%X, 0x%X",
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,6 @@
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* Types and constants *
|
* Types and constants *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
/* Holds info on DATA toggle (DATA0/DATA1) initialization,
|
|
||||||
* required by bulk transfers */
|
|
||||||
typedef enum {
|
|
||||||
|
|
||||||
MUSB_DATATOG_UNKNOWN = 0, /* Default with memset 0 */
|
|
||||||
MUSB_DATATOG_INIT
|
|
||||||
}
|
|
||||||
musb_datatog;
|
|
||||||
|
|
||||||
/* Structure to hold Mentor USB core configuration
|
/* Structure to hold Mentor USB core configuration
|
||||||
* May be more than one on a single chip
|
* May be more than one on a single chip
|
||||||
* Should be initialized by MUSB's variant specific code (like AM335x) */
|
* Should be initialized by MUSB's variant specific code (like AM335x) */
|
||||||
|
|
@ -28,8 +19,8 @@ typedef struct {
|
||||||
void * regs; /* Points to beginning of memory mapped registers */
|
void * regs; /* Points to beginning of memory mapped registers */
|
||||||
hcd_reg1 ep; /* Currently used endpoint */
|
hcd_reg1 ep; /* Currently used endpoint */
|
||||||
hcd_reg1 addr; /* Currently used address */
|
hcd_reg1 addr; /* Currently used address */
|
||||||
musb_datatog datatog_tx[HCD_TOTAL_EP];
|
hcd_datatog * datatog_tx; /* Should point at currently used TX toggle */
|
||||||
musb_datatog datatog_rx[HCD_TOTAL_EP];
|
hcd_datatog * datatog_rx; /* Should point at currently used RX toggle */
|
||||||
}
|
}
|
||||||
musb_core_config;
|
musb_core_config;
|
||||||
|
|
||||||
|
|
@ -43,7 +34,8 @@ void musb_core_stop(void *);
|
||||||
|
|
||||||
|
|
||||||
/* For HCD interface */
|
/* For HCD interface */
|
||||||
void musb_setup_device(void *, hcd_reg1, hcd_reg1);
|
void musb_setup_device(void *, hcd_reg1, hcd_reg1,
|
||||||
|
hcd_datatog *, hcd_datatog *);
|
||||||
int musb_reset_device(void *, hcd_speed *);
|
int musb_reset_device(void *, hcd_speed *);
|
||||||
void musb_setup_stage(void *, hcd_ctrlrequest *);
|
void musb_setup_stage(void *, hcd_ctrlrequest *);
|
||||||
void musb_rx_stage(void *, hcd_datarequest *);
|
void musb_rx_stage(void *, hcd_datarequest *);
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,14 @@ typedef enum {
|
||||||
}
|
}
|
||||||
hcd_speed;
|
hcd_speed;
|
||||||
|
|
||||||
|
/* Possible data toggle values (at least for bulk transfer) */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
HCD_DATATOG_DATA0 = 0,
|
||||||
|
HCD_DATATOG_DATA1 = 1
|
||||||
|
}
|
||||||
|
hcd_datatog;
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* HCD threading/device/URB types *
|
* HCD threading/device/URB types *
|
||||||
|
|
@ -166,12 +174,15 @@ typedef struct usb_ctrlrequest hcd_ctrlrequest;
|
||||||
|
|
||||||
/* Largest value that can be transfered by this driver at a time
|
/* Largest value that can be transfered by this driver at a time
|
||||||
* see MAXPAYLOAD in TXMAXP/RXMAXP */
|
* see MAXPAYLOAD in TXMAXP/RXMAXP */
|
||||||
#define MAX_WTOTALLENGTH 1024
|
#define MAX_WTOTALLENGTH 1024u
|
||||||
|
|
||||||
/* TODO: This has corresponding redefinition in hub driver */
|
/* TODO: This has corresponding redefinition in hub driver */
|
||||||
/* Limit of child devices for each parent */
|
/* Limit of child devices for each parent */
|
||||||
#define HCD_CHILDREN 8u
|
#define HCD_CHILDREN 8u
|
||||||
|
|
||||||
|
/* Total number of endpoints available in USB 2.0 */
|
||||||
|
#define HCD_TOTAL_EP 16u
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
typedef struct hcd_datarequest hcd_datarequest;
|
typedef struct hcd_datarequest hcd_datarequest;
|
||||||
typedef struct hcd_urb hcd_urb;
|
typedef struct hcd_urb hcd_urb;
|
||||||
|
|
@ -219,6 +230,7 @@ struct hcd_device_state {
|
||||||
|
|
||||||
hcd_device_state * parent; /* In case of hub attachment */
|
hcd_device_state * parent; /* In case of hub attachment */
|
||||||
hcd_device_state * child[HCD_CHILDREN]; /* In case of being hub */
|
hcd_device_state * child[HCD_CHILDREN]; /* In case of being hub */
|
||||||
|
hcd_device_state * _next; /* To allow device lists */
|
||||||
hcd_driver_state * driver; /* Specific HCD driver object */
|
hcd_driver_state * driver; /* Specific HCD driver object */
|
||||||
hcd_thread * thread;
|
hcd_thread * thread;
|
||||||
hcd_lock * lock;
|
hcd_lock * lock;
|
||||||
|
|
@ -234,6 +246,8 @@ struct hcd_device_state {
|
||||||
hcd_state state;
|
hcd_state state;
|
||||||
hcd_reg1 reserved_address;
|
hcd_reg1 reserved_address;
|
||||||
hcd_reg1 current_address;
|
hcd_reg1 current_address;
|
||||||
|
hcd_datatog ep_tx_tog[HCD_TOTAL_EP];
|
||||||
|
hcd_datatog ep_rx_tog[HCD_TOTAL_EP];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Control transfer's local data:
|
* Control transfer's local data:
|
||||||
|
|
@ -266,8 +280,9 @@ struct hcd_device_state {
|
||||||
#define HCD_LAST_ADDR 0x7Fu
|
#define HCD_LAST_ADDR 0x7Fu
|
||||||
#define HCD_TOTAL_ADDR 0x80u
|
#define HCD_TOTAL_ADDR 0x80u
|
||||||
#define HCD_LAST_EP 0x0Fu
|
#define HCD_LAST_EP 0x0Fu
|
||||||
#define HCD_TOTAL_EP 0x10u
|
|
||||||
#define HCD_UNUSED_VAL 0xFFu /* When number not needed */
|
#define HCD_UNUSED_VAL 0xFFu /* When number not needed */
|
||||||
|
#define HCD_DEFAULT_NAKLIMIT 0x10u
|
||||||
|
|
||||||
|
|
||||||
/* Legal interval values */
|
/* Legal interval values */
|
||||||
#define HCD_LOWEST_INTERVAL 0x00u
|
#define HCD_LOWEST_INTERVAL 0x00u
|
||||||
|
|
@ -332,6 +347,8 @@ void hcd_device_continue(hcd_device_state *, hcd_event, hcd_reg1);
|
||||||
/* Allocation/deallocation of device structures */
|
/* Allocation/deallocation of device structures */
|
||||||
hcd_device_state * hcd_new_device(void);
|
hcd_device_state * hcd_new_device(void);
|
||||||
void hcd_delete_device(hcd_device_state *);
|
void hcd_delete_device(hcd_device_state *);
|
||||||
|
void hcd_dump_devices(void);
|
||||||
|
int hcd_check_device(hcd_device_state *);
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ hcd_addr_state;
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
struct hcd_driver_state {
|
struct hcd_driver_state {
|
||||||
/* Standard USB controller procedures */
|
/* Standard USB controller procedures */
|
||||||
void (*setup_device) (void *, hcd_reg1, hcd_reg1);
|
void (*setup_device) (void *, hcd_reg1, hcd_reg1,
|
||||||
|
hcd_datatog *, hcd_datatog *);
|
||||||
int (*reset_device) (void *, hcd_speed *);
|
int (*reset_device) (void *, hcd_speed *);
|
||||||
void (*setup_stage) (void *, hcd_ctrlrequest *);
|
void (*setup_stage) (void *, hcd_ctrlrequest *);
|
||||||
void (*rx_stage) (void *, hcd_datarequest *);
|
void (*rx_stage) (void *, hcd_datarequest *);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,13 @@
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This allows us to analyze thread context in
|
||||||
|
* consecutive function calls (DEBUG_DUMP) */
|
||||||
|
#include <ddekit/thread.h>
|
||||||
|
|
||||||
|
/* Represents current thread's name string */
|
||||||
|
#define HCD_THREAD_NAME ddekit_thread_get_name(ddekit_thread_myself())
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* Standard output message *
|
* Standard output message *
|
||||||
|
|
@ -34,12 +41,12 @@
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define DEBUG_DUMP \
|
#define DEBUG_DUMP \
|
||||||
do { \
|
do { \
|
||||||
printf("USBD (DEBUG %s)\n", __func__); \
|
printf("USBD: [%s -> %s]\n", HCD_THREAD_NAME, __func__);\
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define USB_DBG(fmt, ...) \
|
#define USB_DBG(fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
printf("USBD (DEBUG %s): ", __func__); \
|
printf("USBD: [%s -> %s] ", HCD_THREAD_NAME, __func__); \
|
||||||
printf(fmt, ##__VA_ARGS__); \
|
printf(fmt, ##__VA_ARGS__); \
|
||||||
printf("\n"); \
|
printf("\n"); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
@ -56,8 +63,9 @@
|
||||||
#define USB_ASSERT(cond, otherwise) \
|
#define USB_ASSERT(cond, otherwise) \
|
||||||
do { \
|
do { \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
USB_MSG("ASSERTION ERROR (%s:%d) - " \
|
USB_MSG("ASSERTION ERROR (%s -> %s:%d) - " \
|
||||||
otherwise, __func__, __LINE__); \
|
otherwise, HCD_THREAD_NAME, \
|
||||||
|
__func__, __LINE__); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
|
||||||
|
|
@ -288,13 +288,13 @@ void _ddekit_interrupt_trigger(int irq_id)
|
||||||
irq_s = find_by_irq_id(irq_id);
|
irq_s = find_by_irq_id(irq_id);
|
||||||
|
|
||||||
if (irq_s) {
|
if (irq_s) {
|
||||||
DDEBUG_MSG_VERBOSE("Triggering IRQ %d", irq);
|
DDEBUG_MSG_VERBOSE("Triggering IRQ %d", irq_s->irq);
|
||||||
ddekit_sem_up(irq_s->sem);
|
ddekit_sem_up(irq_s->sem);
|
||||||
if (0 != (err_code = sys_irqenable(&irq_s->irq_hook)))
|
if (0 != (err_code = sys_irqenable(&irq_s->irq_hook)))
|
||||||
ddekit_panic("Failed to enable interrupt "
|
ddekit_panic("Failed to enable interrupt "
|
||||||
"(ERROR %d)", err_code);
|
"(ERROR %d)", err_code);
|
||||||
} else {
|
} else {
|
||||||
DDEBUG_MSG_WARN("no handler for IRQ %d", irq);
|
DDEBUG_MSG_WARN("no handler for IRQ %d", irq_s->irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user