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/tty minix-sys
./service/uds minix-sys
./service/usb_hub minix-sys
./service/usb_storage minix-sys
./service/vfs minix-sys
./service/vm minix-sys
@ -5169,8 +5170,8 @@
./usr/sbin/rdate minix-sys
./usr/sbin/traceroute minix-sys
./usr/sbin/unlink minix-sys
./usr/sbin/usb_hub minix-sys
./usr/sbin/usb_storage minix-sys
./usr/sbin/usb_hub minix-sys obsolete
./usr/sbin/usb_storage minix-sys obsolete
./usr/sbin/user minix-sys
./usr/sbin/useradd minix-sys
./usr/sbin/userdel minix-sys

View File

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

View File

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

View File

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

View File

@ -479,6 +479,11 @@ hub_task(void * UNUSED(arg))
}
/* Block this port forever */
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;
case HUB_CHANGE_COM_ERR:
@ -827,7 +832,8 @@ hub_handle_connection(int 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);
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
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=
BINDIR= /service

View File

@ -12,6 +12,7 @@
#include <usbd/usbd_common.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 */
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 */
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 */
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 */
static int hcd_enumerate(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_get_descriptor_tree(hcd_device_state *);
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_non_control_urb(hcd_device_state *, hcd_urb *);
@ -40,11 +43,8 @@ static int hcd_data_transfer(hcd_device_state *, hcd_datarequest *);
/*===========================================================================*
* Local definitions *
*===========================================================================*/
/* TODO: Only one device at a time
* If ever HUB functionality is added, one must remember that disconnecting
* 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];
/* Array of available devices */
static hcd_device_state hcd_device[HCD_NUM_MAX_DEVICES];
/* TODO: This was added for compatibility with DDELinux drivers that
* allow receiving less data than expected in URB, without error */
@ -55,69 +55,152 @@ static hcd_device_state hcd_device[1];
* hcd_handle_event *
*===========================================================================*/
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;
/* TODO: Finding which hcd_device is in use should be performed here */
this_device = &(hcd_device[0]);
/* Sometimes interrupts occur in a weird order (EP after disconnect)
* This helps finding ordering errors in DEBUG */
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;
/* No device may be supplied */
if (NULL == device) {
USB_MSG("No device available for event: 0x%02X, value: 0x%02X",
event, val);
return;
}
/* Handle event and forward control to device thread when required */
switch (driver->current_event) {
switch (event) {
case HCD_EVENT_CONNECTED:
if (HCD_STATE_DISCONNECTED == this_device->state) {
if (EXIT_SUCCESS != hcd_connect_device(
this_device,
hcd_device_thread))
USB_MSG("Device creation failed");
} else
USB_MSG("Device not marked as 'disconnected' "
"for 'connection' event");
USB_ASSERT((HCD_STATE_DISCONNECTED == device->state),
"Device not marked as 'disconnected' "
"for 'connection' event");
/* Mark as 'plugged in' first */
device->state = HCD_STATE_CONNECTION_PENDING;
/* 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;
case HCD_EVENT_DISCONNECTED:
if (HCD_STATE_DISCONNECTED != this_device->state) {
/* If connect callback was used before, call
* it's equivalent to signal disconnection */
if (HCD_STATE_CONNECTED == this_device->state)
hcd_disconnect_cb(this_device);
hcd_disconnect_device(this_device);
this_device->state = HCD_STATE_DISCONNECTED;
USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
"Device is marked as 'disconnected' "
"for 'disconnection' event");
/* Finally, zero everything to allow
* further connections with this object */
memset(this_device, 0x00, sizeof(*this_device));
} else
USB_MSG("Device is marked as 'disconnected' "
"for 'disconnection' event");
/* If connect callback was used before, call
* it's equivalent to signal disconnection */
if (HCD_STATE_CONNECTED == device->state)
hcd_disconnect_cb(device);
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;
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_URB:
/* Allow device thread to continue with it's logic */
if (HCD_STATE_DISCONNECTED != this_device->state)
hcd_device_continue(this_device);
USB_ASSERT((HCD_STATE_DISCONNECTED != device->state),
"Parent device is marked as 'disconnected' "
"for 'endpoint' event");
/* 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
USB_MSG("Device is marked as 'disconnected' "
"for 'EP' event");
USB_MSG("No device waits for endpoint %u", val);
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;
default:
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;
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 */
this_device = (hcd_device_state *)thread_args;
/* Plugged in */
this_device->state = HCD_STATE_CONNECTION_PENDING;
/* Enumeration sequence */
if (EXIT_SUCCESS != hcd_enumerate(this_device))
hcd_device_finish(this_device, "USB device enumeration failed");
@ -153,11 +233,8 @@ hcd_device_thread(void * thread_args)
/* Start handling URB's */
for(;;) {
/* Block and wait for something like 'submit URB' */
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_ANY_EP);
if (EXIT_SUCCESS != hcd_handle_urb(this_device,
&(this_device->urb)))
hcd_device_finish(this_device, "URB handling failed");
hcd_device_wait(this_device, HCD_EVENT_URB, HCD_UNUSED_VAL);
hcd_handle_urb(this_device, this_device->urb);
}
/* 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 */
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");
}
}
/*===========================================================================*
* 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 *
*===========================================================================*/
@ -462,15 +555,13 @@ hcd_set_configuration(hcd_device_state * this_device, hcd_reg1 configuration)
/*===========================================================================*
* hcd_handle_urb *
*===========================================================================*/
static int
static void
hcd_handle_urb(hcd_device_state * this_device, hcd_urb * urb)
{
int transfer_status;
DEBUG_DUMP;
/* TODO: One device only */
USB_ASSERT(NULL != urb, "NULL URB given");
USB_ASSERT(this_device == urb->target_device, "Unknown device for URB");
/* Only if URB parsing was completed... */
@ -491,13 +582,8 @@ hcd_handle_urb(hcd_device_state * this_device, hcd_urb * urb)
this_device, urb);
break;
case HCD_TRANSFER_ISOCHRONOUS:
/* TODO: ISO transfer */
USB_MSG("ISO transfer not supported");
break;
default:
USB_MSG("Invalid transfer type 0x%02X",
USB_MSG("Unsupported transfer type 0x%02X",
(int)urb->type);
break;
}
@ -509,13 +595,8 @@ hcd_handle_urb(hcd_device_state * this_device, hcd_urb * urb)
} else
USB_MSG("Invalid URB supplied");
/* Call completion regardless of status */
hcd_completion_cb(urb);
/* 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;
/* Signal scheduler that URB was handled */
urb->handled();
}

View File

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

View File

@ -8,6 +8,7 @@
#include <usbd/hcd_ddekit.h>
#include <usbd/hcd_interface.h>
#include <usbd/hcd_schedule.h>
#include <usbd/usbd_common.h>
@ -16,7 +17,7 @@
*===========================================================================*/
/*
* In this file "struct ddekit_usb_dev" equals "hcd_device_state"
* */
*/
struct ddekit_usb_device_id;
struct ddekit_usb_urb;
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_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 *
@ -177,35 +185,22 @@ int
ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb)
{
hcd_device_state * dev;
hcd_driver_state * drv;
hcd_urb * urb;
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);
drv = (hcd_driver_state *)(dev->driver);
/* Check for latest URB completion */
if (NULL == dev->urb.original_urb) {
/* Get new URB */
urb = hcd_new_urb();
/* Remember original URB */
dev->urb.original_urb = (void *)d_urb;
/* Turn DDEKit URB format to one that is easier to
* 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
* or DDEKit's must be altered accordingly */
/* 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;
/* Add URB to scheduler */
return hcd_schedule_urb(urb);
}
@ -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 *
*===========================================================================*/
@ -290,13 +310,16 @@ hcd_completion_cb(hcd_urb * urb)
/* Recollect original URB */
d_urb = (struct ddekit_usb_urb *)urb->original_urb;
/* This URB will be scheduled no more */
hcd_unschedule_urb(urb);
/* Turn HCD URB format to one handled by DDEKit */
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 */
urb->original_urb = NULL;
completion_cb(d_urb->priv);
}
@ -308,6 +331,9 @@ hcd_decode_urb(hcd_urb * urb, struct ddekit_usb_urb * dde_urb)
{
DEBUG_DUMP;
/* Remember original */
urb->original_urb = (void *)dde_urb;
/* No UBR error initially */
urb->inout_status = EXIT_SUCCESS;
@ -397,7 +423,57 @@ hcd_encode_urb(hcd_urb * urb, struct ddekit_usb_urb * dde_urb)
{
DEBUG_DUMP;
/* Data buffers are the same, no need to copy */
/* Rewrite output for DDEKit part */
dde_urb->actual_length = urb->out_size;
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.read_data = musb_read_data;
ctrl->driver.check_error = musb_check_error;
ctrl->driver.port_device = NULL;
}
#endif
@ -388,6 +389,7 @@ musb_am335x_init(void)
ctrl->driver.out_status_stage = musb_out_status_stage;
ctrl->driver.read_data = musb_read_data;
ctrl->driver.check_error = musb_check_error;
ctrl->driver.port_device = NULL;
}
return musb_am335x_internal_init();
@ -563,25 +565,26 @@ musb_am335x_usbx_isr(void * data)
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED) {
USB_DBG("Device connected");
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED);
driver->current_event = HCD_EVENT_CONNECTED;
hcd_handle_event(driver);
hcd_update_port(driver, HCD_EVENT_CONNECTED);
hcd_handle_event(driver->port_device, HCD_EVENT_CONNECTED,
HCD_UNUSED_VAL);
return;
}
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED) {
USB_DBG("Device disconnected");
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED);
driver->current_event = HCD_EVENT_DISCONNECTED;
hcd_handle_event(driver);
hcd_handle_event(driver->port_device, HCD_EVENT_DISCONNECTED,
HCD_UNUSED_VAL);
hcd_update_port(driver, HCD_EVENT_DISCONNECTED);
return;
}
if (0 != irqstat0) {
USB_DBG("EP interrupt");
CLEAR_IRQ0(irqstat0);
driver->current_event = HCD_EVENT_ENDPOINT;
driver->current_endpoint = musb_am335x_irqstat0_to_ep(irqstat0);
hcd_handle_event(driver);
hcd_handle_event(driver->port_device, HCD_EVENT_ENDPOINT,
musb_am335x_irqstat0_to_ep(irqstat0));
return;
}

View File

@ -124,10 +124,13 @@ hcd_direction;
/* Possible asynchronous HCD events */
typedef enum {
HCD_EVENT_CONNECTED,
HCD_EVENT_CONNECTED = 0,
HCD_EVENT_DISCONNECTED,
HCD_EVENT_PORT_CONNECTED,
HCD_EVENT_PORT_DISCONNECTED,
HCD_EVENT_ENDPOINT,
HCD_EVENT_URB
HCD_EVENT_URB,
HCD_EVENT_INVALID = 0xFF
}
hcd_event;
@ -189,6 +192,7 @@ struct hcd_urb {
/* Basic */
void * original_urb;
hcd_device_state * target_device;
void (*handled)(void); /* URB handled callback */
/* Transfer (in/out signifies what may be overwritten by HCD) */
hcd_ctrlrequest * in_setup;
@ -207,12 +211,15 @@ struct hcd_urb {
/* Current state of attached device */
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_lock * lock;
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_configuration config_tree;
hcd_reg1 max_packet_size;
@ -250,12 +257,15 @@ struct hcd_device_state {
#define HCD_LAST_ADDR 0x7Fu
#define HCD_LAST_EP 0x0Fu
#define HCD_TOTAL_EP 0x10u
#define HCD_ANY_EP 0xFFu
#define HCD_UNUSED_VAL 0xFFu /* When number not needed */
/* Legal interval values */
#define HCD_LOWEST_INTERVAL 0x00u
#define HCD_HIGHEST_INTERVAL 0xFFu
/* Max number of supported devices */
#define HCD_NUM_MAX_DEVICES 0x08u
/* TODO: One device only */
#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);
/* 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
*
* 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_
@ -39,20 +40,20 @@ struct hcd_driver_state {
/* Controller's private data (like mapped registers) */
void * private_data;
/* Current state to be handled by driver */
hcd_event current_event;
hcd_reg1 current_endpoint;
hcd_event expected_event;
hcd_reg1 expected_endpoint;
/* TODO: Only one port for each driver */
/* Represents device attached to USB port handled by this driver */
hcd_device_state * port_device;
};
/*===========================================================================*
* HCD event handling routine *
*===========================================================================*/
/* Handle asynchronous event
* This must be called in case of specific HCD interrupts listed above */
void hcd_handle_event(hcd_driver_state *);
/* Handle asynchronous event */
void hcd_handle_event(hcd_device_state *, hcd_event, hcd_reg1);
/* This resolves port's device structure for given driver and event */
void hcd_update_port(hcd_driver_state *, hcd_event);
#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;
};
/* 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);
void *ddekit_usb_dev_get_data(struct ddekit_usb_dev *dev);
void ddekit_usb_get_device_id(struct ddekit_usb_dev *dev, struct
ddekit_usb_device_id *id);
int ddekit_usb_submit_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

View File

@ -775,7 +775,8 @@
#define USB_RQ_DEINIT (USB_BASE + 1) /* Quit the session */
#define USB_RQ_SEND_URB (USB_BASE + 2) /* Send 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 */
@ -793,6 +794,9 @@
# define USB_INTERFACES m4_l3
# 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) *
*===========================================================================*/

View File

@ -152,4 +152,7 @@ int usb_init(char *name);
/** This functions handles a message from the HCD */
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 */

View File

@ -186,6 +186,17 @@ int ddekit_usb_cancle_urb(struct ddekit_usb_urb *d_urb)
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()
{
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);
static void submit_urb(message *msg);
static void cancle_urb(message *msg);
static void get_info(message *msg);
static void completion_callback(void *priv);
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 *
****************************************************************************/
@ -713,6 +747,9 @@ static int handle_msg(message *msg)
case USB_RQ_CANCEL_URB:
cancle_urb(msg);
return 1;
case USB_RQ_SEND_INFO:
get_info(msg);
return 1;
default:
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;
}