Reorganized HCD for multiple URB scheduling

. HCD URB scheduler stub
	. Added USB hub - HCD message passing
	. Fixed invalid paths related to USB drivers

Change-Id: I878f4521d5a7b25eb97fd8b377f3fdfd7ee4f28b
This commit is contained in:
Wojciech Zajac 2014-07-30 15:38:49 +02:00 committed by Ben Gras
parent 75d3188723
commit d2032a25e2
22 changed files with 593 additions and 157 deletions

View File

@ -174,6 +174,7 @@
./service/sched minix-sys ./service/sched minix-sys
./service/tty minix-sys ./service/tty minix-sys
./service/uds minix-sys ./service/uds minix-sys
./service/usb_hub minix-sys
./service/usb_storage minix-sys ./service/usb_storage minix-sys
./service/vfs minix-sys ./service/vfs minix-sys
./service/vm minix-sys ./service/vm minix-sys
@ -5169,8 +5170,8 @@
./usr/sbin/rdate minix-sys ./usr/sbin/rdate minix-sys
./usr/sbin/traceroute minix-sys ./usr/sbin/traceroute minix-sys
./usr/sbin/unlink minix-sys ./usr/sbin/unlink minix-sys
./usr/sbin/usb_hub minix-sys ./usr/sbin/usb_hub minix-sys obsolete
./usr/sbin/usb_storage minix-sys ./usr/sbin/usb_storage minix-sys obsolete
./usr/sbin/user minix-sys ./usr/sbin/user minix-sys
./usr/sbin/useradd minix-sys ./usr/sbin/useradd minix-sys
./usr/sbin/userdel minix-sys ./usr/sbin/userdel minix-sys

View File

@ -1,6 +1,6 @@
usb_driver usb_hub usb_driver usb_hub
{ {
binary = /usr/sbin/usb_hub; binary = /service/usb_hub;
id { id {
bInterfaceClass = 0x09; bInterfaceClass = 0x09;
} }

View File

@ -1,6 +1,6 @@
usb_driver usb_storage usb_driver usb_storage
{ {
binary = /usr/sbin/usb_storage; binary = /service/usb_storage;
id { id {
bInterfaceClass = 0x08; bInterfaceClass = 0x08;
} }

View File

@ -13,8 +13,4 @@ LDADD+=-lddekit_usb_client -lddekit -lusb -lsys -lminlib
#LDADD+=-Wl,-Ttext=0x800000 #LDADD+=-Wl,-Ttext=0x800000
#CPPFLAGS+=-DHUB_DEBUG #CPPFLAGS+=-DHUB_DEBUG
MAN=
BINDIR?= /usr/sbin
.include <minix.service.mk> .include <minix.service.mk>

View File

@ -479,6 +479,11 @@ hub_task(void * UNUSED(arg))
} }
/* Block this port forever */ /* Block this port forever */
s->conn[port] = HUB_PORT_ERROR; s->conn[port] = HUB_PORT_ERROR;
HUB_MSG("Port%d status ERROR", port);
HUB_MSG("Port%d will be blocked, until "
"hub is detached", port);
break; break;
case HUB_CHANGE_COM_ERR: case HUB_CHANGE_COM_ERR:
@ -827,7 +832,8 @@ hub_handle_connection(int port_num)
HUB_MSG("Device connected to port %d", port_num); HUB_MSG("Device connected to port %d", port_num);
return EXIT_SUCCESS; return ddekit_usb_info(driver_state.dev, (long)DDEKIT_HUB_PORT_CONN,
(long)port_num);
} }
@ -841,5 +847,6 @@ hub_handle_disconnection(int port_num)
HUB_MSG("Device disconnected from port %d", port_num); HUB_MSG("Device disconnected from port %d", port_num);
return EXIT_SUCCESS; return ddekit_usb_info(driver_state.dev, (long)DDEKIT_HUB_PORT_DISCONN,
(long)port_num);
} }

View File

@ -1,7 +1,7 @@
# Makefile for the EARM USBD # Makefile for the EARM USBD
PROG= usbd PROG= usbd
SRCS= usbd.c usbd_earm.c hcd.c hcd_common.c hcd_ddekit.c musb_am335x.c musb_core.c SRCS= usbd.c usbd_earm.c hcd.c hcd_common.c hcd_ddekit.c hcd_schedule.c musb_am335x.c musb_core.c
MAN= MAN=
BINDIR= /service BINDIR= /service

View File

@ -12,6 +12,7 @@
#include <usbd/usbd_common.h> #include <usbd/usbd_common.h>
#include <usbd/usbd_interface.h> #include <usbd/usbd_interface.h>
#include <usbd/usbd_schedule.h>
/*===========================================================================* /*===========================================================================*
@ -129,8 +130,17 @@ usbd_start(void)
/* After spawning, allow server thread to work */ /* After spawning, allow server thread to work */
if (NULL != usbd_th) { if (NULL != usbd_th) {
/* This will lock current thread until DDEKit exits */
ddekit_minix_wait_exit(); /* Allow URB scheduling */
if (usbd_init_scheduler()) {
USB_MSG("Failed to start URB scheduler");
} else {
/* This will lock current thread until DDEKit exits */
ddekit_minix_wait_exit();
}
/* Disallow URB scheduling */
usbd_deinit_scheduler();
/* Cleanup */ /* Cleanup */
ddekit_thread_terminate(usbd_th); ddekit_thread_terminate(usbd_th);

View File

@ -21,13 +21,16 @@ static void hcd_device_thread(void *);
/* Procedure that locks device thread forever in case of error/completion */ /* Procedure that locks device thread forever in case of error/completion */
static void hcd_device_finish(hcd_device_state *, const char *); static void hcd_device_finish(hcd_device_state *, const char *);
/* Procedure that finds device, waiting for given EP interrupt */
static hcd_device_state * hcd_get_child_for_ep(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 *);
static int hcd_get_device_descriptor(hcd_device_state *); static int hcd_get_device_descriptor(hcd_device_state *);
static int hcd_set_address(hcd_device_state *, hcd_reg1); static int hcd_set_address(hcd_device_state *, hcd_reg1);
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 int hcd_handle_urb(hcd_device_state *, hcd_urb *); static void hcd_handle_urb(hcd_device_state *, hcd_urb *);
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 *);
@ -40,11 +43,8 @@ static int hcd_data_transfer(hcd_device_state *, hcd_datarequest *);
/*===========================================================================* /*===========================================================================*
* Local definitions * * Local definitions *
*===========================================================================*/ *===========================================================================*/
/* TODO: Only one device at a time /* Array of available devices */
* If ever HUB functionality is added, one must remember that disconnecting static hcd_device_state hcd_device[HCD_NUM_MAX_DEVICES];
* HUB, means disconnecting every device attached to it, so data structure may
* have to be altered to allow that */
static hcd_device_state hcd_device[1];
/* TODO: This was added for compatibility with DDELinux drivers that /* TODO: This was added for compatibility with DDELinux drivers that
* allow receiving less data than expected in URB, without error */ * allow receiving less data than expected in URB, without error */
@ -55,69 +55,152 @@ static hcd_device_state hcd_device[1];
* hcd_handle_event * * hcd_handle_event *
*===========================================================================*/ *===========================================================================*/
void void
hcd_handle_event(hcd_driver_state * driver) hcd_handle_event(hcd_device_state * device, hcd_event event, hcd_reg1 val)
{ {
hcd_device_state * this_device;
DEBUG_DUMP; DEBUG_DUMP;
/* TODO: Finding which hcd_device is in use should be performed here */ /* No device may be supplied */
this_device = &(hcd_device[0]); if (NULL == device) {
USB_MSG("No device available for event: 0x%02X, value: 0x%02X",
/* Sometimes interrupts occur in a weird order (EP after disconnect) event, val);
* This helps finding ordering errors in DEBUG */ return;
USB_DBG("Event: 0x%02X, state: 0x%02X", }
driver->current_event, this_device->state);
/* Set what was received for device thread to use */
this_device->driver = driver;
/* Handle event and forward control to device thread when required */ /* Handle event and forward control to device thread when required */
switch (driver->current_event) { switch (event) {
case HCD_EVENT_CONNECTED: case HCD_EVENT_CONNECTED:
if (HCD_STATE_DISCONNECTED == this_device->state) { USB_ASSERT((HCD_STATE_DISCONNECTED == device->state),
if (EXIT_SUCCESS != hcd_connect_device( "Device not marked as 'disconnected' "
this_device, "for 'connection' event");
hcd_device_thread))
USB_MSG("Device creation failed"); /* Mark as 'plugged in' first */
} else device->state = HCD_STATE_CONNECTION_PENDING;
USB_MSG("Device not marked as 'disconnected' "
"for 'connection' event"); /* Try creating new thread for device */
if (hcd_connect_device(device, hcd_device_thread))
USB_MSG("Device creation failed, nothing more "
"will happen until disconnected");
break; break;
case HCD_EVENT_DISCONNECTED: case HCD_EVENT_DISCONNECTED:
if (HCD_STATE_DISCONNECTED != this_device->state) { USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
/* If connect callback was used before, call "Device is marked as 'disconnected' "
* it's equivalent to signal disconnection */ "for 'disconnection' event");
if (HCD_STATE_CONNECTED == this_device->state)
hcd_disconnect_cb(this_device);
hcd_disconnect_device(this_device);
this_device->state = HCD_STATE_DISCONNECTED;
/* Finally, zero everything to allow /* If connect callback was used before, call
* further connections with this object */ * it's equivalent to signal disconnection */
memset(this_device, 0x00, sizeof(*this_device)); if (HCD_STATE_CONNECTED == device->state)
} else hcd_disconnect_cb(device);
USB_MSG("Device is marked as 'disconnected' "
"for 'disconnection' event"); hcd_disconnect_device(device);
device->state = HCD_STATE_DISCONNECTED;
/* Finally, zero everything to allow
* further connections with this object */
memset(device, 0x00, sizeof(*device));
break; break;
case HCD_EVENT_PORT_CONNECTED:
/* TODO: Actual port handling */
USB_MSG("Device connected to hub's port");
break;
case HCD_EVENT_PORT_DISCONNECTED:
/* TODO: Actual port handling */
USB_MSG("Device disconnected from hub's port");
break;
case HCD_EVENT_ENDPOINT: case HCD_EVENT_ENDPOINT:
case HCD_EVENT_URB: USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
/* Allow device thread to continue with it's logic */ "Parent device is marked as 'disconnected' "
if (HCD_STATE_DISCONNECTED != this_device->state) "for 'endpoint' event");
hcd_device_continue(this_device);
/* Alters 'device' when endpoint is allocated to
* child rather than parent (hub), which allows
* proper thread to continue */
device = hcd_get_child_for_ep(device, val);
/* Check if anything at all, waits for such endpoint */
if (device)
/* Allow device thread, waiting for endpoint
* event, to continue with its logic */
hcd_device_continue(device, event, val);
else else
USB_MSG("Device is marked as 'disconnected' " USB_MSG("No device waits for endpoint %u", val);
"for 'EP' event");
break;
case HCD_EVENT_URB:
USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
"Device is marked as 'disconnected' "
"for 'URB' event");
/* Allow device thread to continue with it's logic */
hcd_device_continue(device, event, val);
break; break;
default: default:
USB_ASSERT(0, "Illegal HCD event"); USB_ASSERT(0, "Illegal HCD event");
}
}
/*===========================================================================*
* hcd_update_port *
*===========================================================================*/
void
hcd_update_port(hcd_driver_state * driver, hcd_event event)
{
hcd_device_state * d;
int devnum;
const int maxdevs = (sizeof(hcd_device) / sizeof(hcd_device[0]));
DEBUG_DUMP;
switch (event) {
case HCD_EVENT_CONNECTED:
/* Check if already assigned */
USB_ASSERT(NULL == driver->port_device,
"Device was already connected before "
"receiving 'connection' event");
/* For short */
d = hcd_device;
/* Find first unused device */
for (devnum = 0; devnum < maxdevs; devnum++) {
if (HCD_STATE_DISCONNECTED == d[devnum].state) {
/* Assign free device */
driver->port_device = &(d[devnum]);
/* Associate this device with driver */
driver->port_device->driver = driver;
/* Device found, exit */
return;
}
}
/* Nothing found */
USB_MSG("Device limit reached, no more "
"free device structures to use");
break; break;
case HCD_EVENT_DISCONNECTED:
/* Check if already released */
USB_ASSERT(NULL != driver->port_device,
"Device was already disconnected before "
"receiving 'disconnection' event");
/* Clear port device */
driver->port_device = NULL;
break;
default:
USB_ASSERT(0, "Illegal port update event");
} }
} }
@ -135,9 +218,6 @@ hcd_device_thread(void * thread_args)
/* Retrieve structures from generic data */ /* Retrieve structures from generic data */
this_device = (hcd_device_state *)thread_args; this_device = (hcd_device_state *)thread_args;
/* Plugged in */
this_device->state = HCD_STATE_CONNECTION_PENDING;
/* Enumeration sequence */ /* Enumeration sequence */
if (EXIT_SUCCESS != hcd_enumerate(this_device)) if (EXIT_SUCCESS != hcd_enumerate(this_device))
hcd_device_finish(this_device, "USB device enumeration failed"); hcd_device_finish(this_device, "USB device enumeration failed");
@ -153,11 +233,8 @@ hcd_device_thread(void * thread_args)
/* Start handling URB's */ /* Start handling URB's */
for(;;) { for(;;) {
/* 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_ANY_EP); hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
hcd_handle_urb(this_device, this_device->urb);
if (EXIT_SUCCESS != hcd_handle_urb(this_device,
&(this_device->urb)))
hcd_device_finish(this_device, "URB handling failed");
} }
/* Finish device handling to avoid leaving thread */ /* Finish device handling to avoid leaving thread */
@ -177,12 +254,28 @@ hcd_device_finish(hcd_device_state * this_device, const char * finish_msg)
/* Lock forever */ /* Lock forever */
for (;;) { for (;;) {
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_ANY_EP); hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
USB_MSG("Failed attempt to continue finished thread"); USB_MSG("Failed attempt to continue finished thread");
} }
} }
/*===========================================================================*
* hcd_get_child_for_ep *
*===========================================================================*/
static hcd_device_state *
hcd_get_child_for_ep(hcd_device_state * device, hcd_reg1 ep)
{
DEBUG_DUMP;
/* TODO: When device has multiple children (hub),
* this will allow routing interrupt login downstream */
((void)ep);
return device;
}
/*===========================================================================* /*===========================================================================*
* hcd_enumerate * * hcd_enumerate *
*===========================================================================*/ *===========================================================================*/
@ -462,15 +555,13 @@ hcd_set_configuration(hcd_device_state * this_device, hcd_reg1 configuration)
/*===========================================================================* /*===========================================================================*
* hcd_handle_urb * * hcd_handle_urb *
*===========================================================================*/ *===========================================================================*/
static int static void
hcd_handle_urb(hcd_device_state * this_device, hcd_urb * urb) hcd_handle_urb(hcd_device_state * this_device, hcd_urb * urb)
{ {
int transfer_status; int transfer_status;
DEBUG_DUMP; DEBUG_DUMP;
/* TODO: One device only */
USB_ASSERT(NULL != urb, "NULL URB given");
USB_ASSERT(this_device == urb->target_device, "Unknown device for URB"); USB_ASSERT(this_device == urb->target_device, "Unknown device for URB");
/* Only if URB parsing was completed... */ /* Only if URB parsing was completed... */
@ -491,13 +582,8 @@ hcd_handle_urb(hcd_device_state * this_device, hcd_urb * urb)
this_device, urb); this_device, urb);
break; break;
case HCD_TRANSFER_ISOCHRONOUS:
/* TODO: ISO transfer */
USB_MSG("ISO transfer not supported");
break;
default: default:
USB_MSG("Invalid transfer type 0x%02X", USB_MSG("Unsupported transfer type 0x%02X",
(int)urb->type); (int)urb->type);
break; break;
} }
@ -509,13 +595,8 @@ hcd_handle_urb(hcd_device_state * this_device, hcd_urb * urb)
} else } else
USB_MSG("Invalid URB supplied"); USB_MSG("Invalid URB supplied");
/* Call completion regardless of status */ /* Signal scheduler that URB was handled */
hcd_completion_cb(urb); urb->handled();
/* TODO: Only critical failures should ever yield EXIT_FAILURE, so
* return is not bound to transfer_status for now, to let device
* driver act accordingly */
return EXIT_SUCCESS;
} }

View File

@ -235,20 +235,16 @@ hcd_disconnect_device(hcd_device_state * this_device)
* hcd_device_wait * * hcd_device_wait *
*===========================================================================*/ *===========================================================================*/
void void
hcd_device_wait(hcd_device_state * this_device, hcd_event event, hcd_reg1 ep) hcd_device_wait(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
{ {
hcd_driver_state * drv;
DEBUG_DUMP; DEBUG_DUMP;
drv = (hcd_driver_state *)this_device->driver; USB_DBG("Device 0x%08X wait (0x%02X, 0x%02X)", device, event, ep);
drv->expected_event = event; device->wait_event = event;
drv->expected_endpoint = ep; device->wait_ep = ep;
USB_DBG("Waiting for: ev=0x%X, ep=0x%X", (int)event, ep); ddekit_sem_down(device->lock);
ddekit_sem_down(this_device->lock);
} }
@ -256,25 +252,16 @@ hcd_device_wait(hcd_device_state * this_device, hcd_event event, hcd_reg1 ep)
* hcd_device_continue * * hcd_device_continue *
*===========================================================================*/ *===========================================================================*/
void void
hcd_device_continue(hcd_device_state * this_device) hcd_device_continue(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
{ {
hcd_driver_state * drv;
DEBUG_DUMP; DEBUG_DUMP;
drv = (hcd_driver_state *)this_device->driver; USB_DBG("Device 0x%08X continue (0x%02X, 0x%02X)", device, event, ep);
/* We need to get what was expected... */ USB_ASSERT(device->wait_event == event, "Unexpected event");
USB_ASSERT(drv->current_event == drv->expected_event, USB_ASSERT(device->wait_ep == ep, "Unexpected endpoint");
"Unexpected event occurred");
/* ...including endpoint interrupts */ ddekit_sem_up(device->lock);
if (HCD_EVENT_ENDPOINT == drv->current_event) {
USB_ASSERT(drv->current_endpoint == drv->expected_endpoint,
"Unexpected endpoint interrupt");
}
ddekit_sem_up(this_device->lock);
} }

View File

@ -8,6 +8,7 @@
#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>
@ -16,7 +17,7 @@
*===========================================================================*/ *===========================================================================*/
/* /*
* In this file "struct ddekit_usb_dev" equals "hcd_device_state" * In this file "struct ddekit_usb_dev" equals "hcd_device_state"
* */ */
struct ddekit_usb_device_id; struct ddekit_usb_device_id;
struct ddekit_usb_urb; struct ddekit_usb_urb;
struct ddekit_usb_dev; struct ddekit_usb_dev;
@ -25,6 +26,13 @@ struct ddekit_usb_dev;
static void hcd_decode_urb(hcd_urb *, struct ddekit_usb_urb *); static void hcd_decode_urb(hcd_urb *, struct ddekit_usb_urb *);
static void hcd_encode_urb(hcd_urb *, struct ddekit_usb_urb *); static void hcd_encode_urb(hcd_urb *, struct ddekit_usb_urb *);
/* HCD's URB create/destroy */
static hcd_urb * hcd_new_urb(void);
static void hcd_free_urb(hcd_urb *);
/* Decodes event from received info */
static void hcd_decode_info(long, long, hcd_event *, hcd_reg1 *);
/*===========================================================================* /*===========================================================================*
* Global definitions * * Global definitions *
@ -177,35 +185,22 @@ int
ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb) ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb)
{ {
hcd_device_state * dev; hcd_device_state * dev;
hcd_driver_state * drv; hcd_urb * urb;
DEBUG_DUMP; DEBUG_DUMP;
/* Retrieve info on device/driver state from DDEKit's USB */ /* Retrieve info on device state from DDEKit's URB */
dev = (hcd_device_state *)(d_urb->dev); dev = (hcd_device_state *)(d_urb->dev);
drv = (hcd_driver_state *)(dev->driver);
/* Check for latest URB completion */ /* Get new URB */
if (NULL == dev->urb.original_urb) { urb = hcd_new_urb();
/* Remember original URB */ /* Turn DDEKit URB format to one that is easier to
dev->urb.original_urb = (void *)d_urb; * handle by HCD, also check if URB is valid */
hcd_decode_urb(urb, d_urb);
/* TODO: If multiple URB's have to be queued, this code /* Add URB to scheduler */
* or DDEKit's must be altered accordingly */ return hcd_schedule_urb(urb);
/* Turn DDEKit URB format to one that is easier to
* handle by HCD, also check if URB is valid */
hcd_decode_urb(&(dev->urb), d_urb);
/* Start handling URB event */
drv->current_event = HCD_EVENT_URB;
hcd_handle_event(drv);
return EXIT_SUCCESS;
}
/* Last URB must not have been completed */
return EXIT_FAILURE;
} }
@ -222,6 +217,31 @@ ddekit_usb_cancle_urb(struct ddekit_usb_urb * d_urb)
} }
/*===========================================================================*
* ddekit_usb_info *
*===========================================================================*/
long
ddekit_usb_info(struct ddekit_usb_dev * dev, long type, long value)
{
hcd_event event;
hcd_reg1 val;
DEBUG_DUMP;
/* Decode event */
hcd_decode_info(type, value, &event, &val);
if (HCD_EVENT_INVALID == event) {
USB_MSG("Invalid info message received");
return EXIT_FAILURE;
} else {
/* Let HCD handle info message */
hcd_handle_event((hcd_device_state *)dev, event, val);
return EXIT_SUCCESS;
}
}
/*===========================================================================* /*===========================================================================*
* ddekit_usb_init * * ddekit_usb_init *
*===========================================================================*/ *===========================================================================*/
@ -290,13 +310,16 @@ 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 */
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);
completion_cb(d_urb->priv); /* No need for this URB anymore */
hcd_free_urb(urb);
/* URB was handled, forget about it */ completion_cb(d_urb->priv);
urb->original_urb = NULL;
} }
@ -308,6 +331,9 @@ hcd_decode_urb(hcd_urb * urb, struct ddekit_usb_urb * dde_urb)
{ {
DEBUG_DUMP; DEBUG_DUMP;
/* Remember original */
urb->original_urb = (void *)dde_urb;
/* No UBR error initially */ /* No UBR error initially */
urb->inout_status = EXIT_SUCCESS; urb->inout_status = EXIT_SUCCESS;
@ -397,7 +423,57 @@ hcd_encode_urb(hcd_urb * urb, struct ddekit_usb_urb * dde_urb)
{ {
DEBUG_DUMP; DEBUG_DUMP;
/* Data buffers are the same, no need to copy */
/* Rewrite output for DDEKit part */ /* Rewrite output for DDEKit part */
dde_urb->actual_length = urb->out_size; dde_urb->actual_length = urb->out_size;
dde_urb->status = urb->inout_status; dde_urb->status = urb->inout_status;
} }
/*===========================================================================*
* hcd_new_urb *
*===========================================================================*/
static hcd_urb *
hcd_new_urb(void)
{
DEBUG_DUMP;
return malloc(sizeof(hcd_urb));
}
/*===========================================================================*
* hcd_free_urb *
*===========================================================================*/
static void
hcd_free_urb(hcd_urb * urb)
{
DEBUG_DUMP;
free(urb);
}
/*===========================================================================*
* hcd_decode_info *
*===========================================================================*/
static void
hcd_decode_info(long type, long invalue, hcd_event * event, hcd_reg1 * outvalue)
{
DEBUG_DUMP;
USB_ASSERT((invalue >= 0) && (invalue <= 0xFF),
"Illegal USB info value received");
switch ((ddekit_msg_type_t)type) {
case DDEKIT_HUB_PORT_CONN:
*event = HCD_EVENT_PORT_CONNECTED;
break;
case DDEKIT_HUB_PORT_DISCONN:
*event = HCD_EVENT_PORT_DISCONNECTED;
break;
default:
*event = HCD_EVENT_INVALID;
break;
}
*outvalue = (hcd_reg1)invalue;
}

View File

@ -0,0 +1,143 @@
/*
* Implementation of HCD URB scheduler
*/
#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>
#include <usbd/usbd_schedule.h>
/*===========================================================================*
* Required for scheduling *
*===========================================================================*/
/* Scheduler thread */
static hcd_thread * urb_thread;
/* TODO: This will soon become URB list */
static hcd_urb * current_urb;
/* This allows waiting for completion */
static hcd_lock * handled_lock;
/* Scheduler task */
static void hcd_urb_scheduler_task(void *);
/* Completion callback */
static void hcd_urb_handled(void);
/*===========================================================================*
* usbd_init_scheduler *
*===========================================================================*/
int
usbd_init_scheduler(void)
{
DEBUG_DUMP;
urb_thread = ddekit_thread_create(hcd_urb_scheduler_task, NULL, "URB");
if (NULL == urb_thread)
goto ERR1;
handled_lock = ddekit_sem_init(0);
if (NULL == handled_lock)
goto ERR2;
return EXIT_SUCCESS;
ERR2:
ddekit_thread_terminate(urb_thread);
ERR1:
return EXIT_FAILURE;
}
/*===========================================================================*
* usbd_deinit_scheduler *
*===========================================================================*/
void
usbd_deinit_scheduler(void)
{
DEBUG_DUMP;
ddekit_sem_deinit(handled_lock);
ddekit_thread_terminate(urb_thread);
}
/*===========================================================================*
* hcd_schedule_urb *
*===========================================================================*/
int
hcd_schedule_urb(hcd_urb * urb)
{
DEBUG_DUMP;
/* Tell URB what to call on completion */
urb->handled = hcd_urb_handled;
/* TODO: Proper list handling */
current_urb = urb;
return EXIT_SUCCESS;
}
/*===========================================================================*
* hcd_unschedule_urb *
*===========================================================================*/
void
hcd_unschedule_urb(hcd_urb * urb)
{
DEBUG_DUMP;
/* TODO: Proper list handling */
((void)urb);
current_urb = NULL;
}
/*===========================================================================*
* hcd_urb_scheduler_task *
*===========================================================================*/
static void
hcd_urb_scheduler_task(void * UNUSED(arg))
{
DEBUG_DUMP;
for (;;) {
if (NULL != current_urb) {
/* Tell device that this is it's URB */
current_urb->target_device->urb = current_urb;
/* Start handling URB event */
hcd_handle_event(current_urb->target_device,
HCD_EVENT_URB, HCD_UNUSED_VAL);
/* Wait for completion */
ddekit_sem_down(handled_lock);
/* Call completion regardless of status */
hcd_completion_cb(current_urb);
}
/* TODO: Temporary, poor scheduling with forced sleep */
ddekit_thread_msleep(50);
}
}
/*===========================================================================*
* hcd_urb_handled *
*===========================================================================*/
static void
hcd_urb_handled(void)
{
DEBUG_DUMP;
/* Handling completed */
ddekit_sem_up(handled_lock);
}

View File

@ -348,6 +348,7 @@ musb_am335x_init(void)
ctrl->driver.out_status_stage = musb_out_status_stage; ctrl->driver.out_status_stage = musb_out_status_stage;
ctrl->driver.read_data = musb_read_data; ctrl->driver.read_data = musb_read_data;
ctrl->driver.check_error = musb_check_error; ctrl->driver.check_error = musb_check_error;
ctrl->driver.port_device = NULL;
} }
#endif #endif
@ -388,6 +389,7 @@ musb_am335x_init(void)
ctrl->driver.out_status_stage = musb_out_status_stage; ctrl->driver.out_status_stage = musb_out_status_stage;
ctrl->driver.read_data = musb_read_data; ctrl->driver.read_data = musb_read_data;
ctrl->driver.check_error = musb_check_error; ctrl->driver.check_error = musb_check_error;
ctrl->driver.port_device = NULL;
} }
return musb_am335x_internal_init(); return musb_am335x_internal_init();
@ -563,25 +565,26 @@ musb_am335x_usbx_isr(void * data)
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED) { if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED) {
USB_DBG("Device connected"); USB_DBG("Device connected");
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED); CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED);
driver->current_event = HCD_EVENT_CONNECTED; hcd_update_port(driver, HCD_EVENT_CONNECTED);
hcd_handle_event(driver); hcd_handle_event(driver->port_device, HCD_EVENT_CONNECTED,
HCD_UNUSED_VAL);
return; return;
} }
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED) { if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED) {
USB_DBG("Device disconnected"); USB_DBG("Device disconnected");
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED); CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED);
driver->current_event = HCD_EVENT_DISCONNECTED; hcd_handle_event(driver->port_device, HCD_EVENT_DISCONNECTED,
hcd_handle_event(driver); HCD_UNUSED_VAL);
hcd_update_port(driver, HCD_EVENT_DISCONNECTED);
return; return;
} }
if (0 != irqstat0) { if (0 != irqstat0) {
USB_DBG("EP interrupt"); USB_DBG("EP interrupt");
CLEAR_IRQ0(irqstat0); CLEAR_IRQ0(irqstat0);
driver->current_event = HCD_EVENT_ENDPOINT; hcd_handle_event(driver->port_device, HCD_EVENT_ENDPOINT,
driver->current_endpoint = musb_am335x_irqstat0_to_ep(irqstat0); musb_am335x_irqstat0_to_ep(irqstat0));
hcd_handle_event(driver);
return; return;
} }

View File

@ -124,10 +124,13 @@ hcd_direction;
/* Possible asynchronous HCD events */ /* Possible asynchronous HCD events */
typedef enum { typedef enum {
HCD_EVENT_CONNECTED, HCD_EVENT_CONNECTED = 0,
HCD_EVENT_DISCONNECTED, HCD_EVENT_DISCONNECTED,
HCD_EVENT_PORT_CONNECTED,
HCD_EVENT_PORT_DISCONNECTED,
HCD_EVENT_ENDPOINT, HCD_EVENT_ENDPOINT,
HCD_EVENT_URB HCD_EVENT_URB,
HCD_EVENT_INVALID = 0xFF
} }
hcd_event; hcd_event;
@ -189,6 +192,7 @@ struct hcd_urb {
/* Basic */ /* Basic */
void * original_urb; void * original_urb;
hcd_device_state * target_device; hcd_device_state * target_device;
void (*handled)(void); /* URB handled callback */
/* 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;
@ -207,12 +211,15 @@ struct hcd_urb {
/* Current state of attached device */ /* Current state of attached device */
struct hcd_device_state { struct hcd_device_state {
hcd_driver_state * driver; /* Specific HCD driver object */ hcd_device_state * parent; /* In case of hub attachment */
hcd_driver_state * driver; /* Specific HCD driver object */
hcd_thread * thread; hcd_thread * thread;
hcd_lock * lock; hcd_lock * lock;
void * data; void * data;
hcd_urb urb; hcd_urb * urb; /* URB to be used by device */
hcd_event wait_event; /* Expected event */
hcd_reg1 wait_ep; /* Expected event's endpoint */
hcd_device_descriptor device_desc; hcd_device_descriptor device_desc;
hcd_configuration config_tree; hcd_configuration config_tree;
hcd_reg1 max_packet_size; hcd_reg1 max_packet_size;
@ -250,12 +257,15 @@ struct hcd_device_state {
#define HCD_LAST_ADDR 0x7Fu #define HCD_LAST_ADDR 0x7Fu
#define HCD_LAST_EP 0x0Fu #define HCD_LAST_EP 0x0Fu
#define HCD_TOTAL_EP 0x10u #define HCD_TOTAL_EP 0x10u
#define HCD_ANY_EP 0xFFu #define HCD_UNUSED_VAL 0xFFu /* When number not needed */
/* Legal interval values */ /* Legal interval values */
#define HCD_LOWEST_INTERVAL 0x00u #define HCD_LOWEST_INTERVAL 0x00u
#define HCD_HIGHEST_INTERVAL 0xFFu #define HCD_HIGHEST_INTERVAL 0xFFu
/* Max number of supported devices */
#define HCD_NUM_MAX_DEVICES 0x08u
/* TODO: One device only */ /* TODO: One device only */
#define HCD_ATTACHED_ADDR 0x01u #define HCD_ATTACHED_ADDR 0x01u
@ -313,7 +323,7 @@ void hcd_disconnect_device(hcd_device_state *);
void hcd_device_wait(hcd_device_state *, hcd_event, hcd_reg1); void hcd_device_wait(hcd_device_state *, hcd_event, hcd_reg1);
/* Unlocks device thread halted by 'hcd_device_wait' */ /* Unlocks device thread halted by 'hcd_device_wait' */
void hcd_device_continue(hcd_device_state *); void hcd_device_continue(hcd_device_state *, hcd_event, hcd_reg1);
/*===========================================================================* /*===========================================================================*

View File

@ -2,7 +2,8 @@
* Interface for HCD * Interface for HCD
* *
* This file holds prototypes that must be implemented by HCD * This file holds prototypes that must be implemented by HCD
* and event call that should be called when interrupt occurred * and call that should be used for asynchronous events
* (interrupts, UBR submits, hub events, ...)
*/ */
#ifndef _HCD_INTERFACE_H_ #ifndef _HCD_INTERFACE_H_
@ -39,20 +40,20 @@ struct hcd_driver_state {
/* Controller's private data (like mapped registers) */ /* Controller's private data (like mapped registers) */
void * private_data; void * private_data;
/* Current state to be handled by driver */ /* TODO: Only one port for each driver */
hcd_event current_event; /* Represents device attached to USB port handled by this driver */
hcd_reg1 current_endpoint; hcd_device_state * port_device;
hcd_event expected_event;
hcd_reg1 expected_endpoint;
}; };
/*===========================================================================* /*===========================================================================*
* HCD event handling routine * * HCD event handling routine *
*===========================================================================*/ *===========================================================================*/
/* Handle asynchronous event /* Handle asynchronous event */
* This must be called in case of specific HCD interrupts listed above */ void hcd_handle_event(hcd_device_state *, hcd_event, hcd_reg1);
void hcd_handle_event(hcd_driver_state *);
/* This resolves port's device structure for given driver and event */
void hcd_update_port(hcd_driver_state *, hcd_event);
#endif /* !_HCD_INTERFACE_H_ */ #endif /* !_HCD_INTERFACE_H_ */

View File

@ -0,0 +1,16 @@
/*
* HCD URB scheduler interface
*/
#ifndef _HCD_SCHEDULE_H_
#define _HCD_SCHEDULE_H_
#include <usbd/hcd_common.h>
/* Makes URB schedule enabled */
int hcd_schedule_urb(hcd_urb *);
/* Makes URB schedule disabled */
void hcd_unschedule_urb(hcd_urb *);
#endif /* !_HCD_SCHEDULE_H_ */

View File

@ -0,0 +1,12 @@
/*
* USBD URB scheduler interface
*/
#ifndef _USBD_SCHEDULE_H_
#define _USBD_SCHEDULE_H_
/* Should be used to create/destroy URB scheduler in base code */
int usbd_init_scheduler(void);
void usbd_deinit_scheduler(void);
#endif /* !_USBD_SCHEDULE_H_ */

View File

@ -78,12 +78,21 @@ struct ddekit_usb_urb {
void *ddekit_priv; void *ddekit_priv;
}; };
/* USB message types */
typedef enum {
DDEKIT_HUB_PORT_CONN,
DDEKIT_HUB_PORT_DISCONN
}
ddekit_msg_type_t;
int ddekit_usb_dev_set_data(struct ddekit_usb_dev *dev, void *data); int ddekit_usb_dev_set_data(struct ddekit_usb_dev *dev, void *data);
void *ddekit_usb_dev_get_data(struct ddekit_usb_dev *dev); void *ddekit_usb_dev_get_data(struct ddekit_usb_dev *dev);
void ddekit_usb_get_device_id(struct ddekit_usb_dev *dev, struct void ddekit_usb_get_device_id(struct ddekit_usb_dev *dev, struct
ddekit_usb_device_id *id); ddekit_usb_device_id *id);
int ddekit_usb_submit_urb(struct ddekit_usb_urb *d_urb); int ddekit_usb_submit_urb(struct ddekit_usb_urb *d_urb);
int ddekit_usb_cancle_urb(struct ddekit_usb_urb *d_urb); int ddekit_usb_cancle_urb(struct ddekit_usb_urb *d_urb);
long ddekit_usb_info(struct ddekit_usb_dev *, long, long);
/* /*
* This one is only implemented for the client side. For the server side is * This one is only implemented for the client side. For the server side is

View File

@ -775,7 +775,8 @@
#define USB_RQ_DEINIT (USB_BASE + 1) /* Quit the session */ #define USB_RQ_DEINIT (USB_BASE + 1) /* Quit the session */
#define USB_RQ_SEND_URB (USB_BASE + 2) /* Send URB */ #define USB_RQ_SEND_URB (USB_BASE + 2) /* Send URB */
#define USB_RQ_CANCEL_URB (USB_BASE + 3) /* Cancel URB */ #define USB_RQ_CANCEL_URB (USB_BASE + 3) /* Cancel URB */
#define USB_REPLY (USB_BASE + 4) #define USB_RQ_SEND_INFO (USB_BASE + 4) /* Sends various information */
#define USB_REPLY (USB_BASE + 5)
/* those are from USBD to driver */ /* those are from USBD to driver */
@ -793,6 +794,9 @@
# define USB_INTERFACES m4_l3 # define USB_INTERFACES m4_l3
# define USB_RB_INIT_NAME m3_ca1 # define USB_RB_INIT_NAME m3_ca1
# define USB_INFO_TYPE m4_l1
# define USB_INFO_VALUE m4_l2
/*===========================================================================* /*===========================================================================*
* Messages for DeviceManager (s/t like SysFS) * * Messages for DeviceManager (s/t like SysFS) *
*===========================================================================*/ *===========================================================================*/

View File

@ -152,4 +152,7 @@ int usb_init(char *name);
/** This functions handles a message from the HCD */ /** This functions handles a message from the HCD */
int usb_handle_msg(struct usb_driver *ubd, message *msg); int usb_handle_msg(struct usb_driver *ubd, message *msg);
/** Lets device driver send HCD various information */
int usb_send_info(long, long);
#endif /* _MINIX_USB_H */ #endif /* _MINIX_USB_H */

View File

@ -186,6 +186,17 @@ int ddekit_usb_cancle_urb(struct ddekit_usb_urb *d_urb)
return res; return res;
} }
/*****************************************************************************
* ddekit_usb_info *
*****************************************************************************/
long
ddekit_usb_info(struct ddekit_usb_dev * UNUSED(dev), long type, long value)
{
return usb_send_info(type, value);
}
static void _ddekit_usb_thread() static void _ddekit_usb_thread()
{ {
struct ddekit_minix_msg_q *mq = ddekit_minix_create_msg_q(USB_BASE, struct ddekit_minix_msg_q *mq = ddekit_minix_create_msg_q(USB_BASE,

View File

@ -71,6 +71,7 @@ static struct ddekit_usb_urb *ddekit_usb_urb_from_mx_urb(struct usb_urb
*mx_urb); *mx_urb);
static void submit_urb(message *msg); static void submit_urb(message *msg);
static void cancle_urb(message *msg); static void cancle_urb(message *msg);
static void get_info(message *msg);
static void completion_callback(void *priv); static void completion_callback(void *priv);
static void prepare_devman_usbdev(struct ddekit_usb_dev * dev, int static void prepare_devman_usbdev(struct ddekit_usb_dev * dev, int
@ -441,6 +442,39 @@ static void cancle_urb(message *msg)
} }
/*****************************************************************************
* get_info *
*****************************************************************************/
static void
get_info(message * msg)
{
struct minix_usb_driver * drv;
endpoint_t ep;
long info_type;
long info_value;
/* Read */
ep = msg->m_source;
info_type = msg->USB_INFO_TYPE;
info_value = msg->USB_INFO_VALUE;
/* Reuse as reply */
msg->m_type = USB_REPLY;
msg->USB_RESULT = -1;
/* Try and find driver first */
if (NULL == (drv = find_driver(ep)))
ddekit_printf("Non-registered driver tries to send info");
else
/* Route info to device */
msg->USB_RESULT = ddekit_usb_info(_devices[drv->dev].dev,
info_type, info_value);
/* Reply */
ipc_send(ep, msg);
}
/***************************************************************************** /*****************************************************************************
* completion_callback * * completion_callback *
****************************************************************************/ ****************************************************************************/
@ -713,6 +747,9 @@ static int handle_msg(message *msg)
case USB_RQ_CANCEL_URB: case USB_RQ_CANCEL_URB:
cancle_urb(msg); cancle_urb(msg);
return 1; return 1;
case USB_RQ_SEND_INFO:
get_info(msg);
return 1;
default: default:
return 0; return 0;
} }

View File

@ -223,3 +223,32 @@ int usb_handle_msg(struct usb_driver *ud, message *msg)
} }
} }
/*****************************************************************************
* usb_send_info *
*****************************************************************************/
int
usb_send_info(long info_type, long info_value)
{
int res;
message msg;
/* Prepare message */
msg.m_type = USB_RQ_SEND_INFO;
msg.USB_INFO_TYPE = info_type;
msg.USB_INFO_VALUE = info_value;
/* Send/receive message */
res = ipc_sendrec(hcd_ep, &msg);
if (res != 0)
panic("usb_send_info: could not talk to HCD: %d", res);
if (msg.m_type != USB_REPLY)
panic("usb_send_info: got illegal response from HCD: %d", msg.m_type);
if (msg.USB_RESULT != 0)
panic("usb_send_info: got illegal response from HCD: %d", msg.m_type);
return msg.USB_RESULT;
}