From d2032a25e236607fdc19b7e3607285836479f205 Mon Sep 17 00:00:00 2001 From: Wojciech Zajac Date: Wed, 30 Jul 2014 15:38:49 +0200 Subject: [PATCH] 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 --- distrib/sets/lists/minix/mi | 5 +- etc/devmand/usb_hub.cfg | 2 +- etc/devmand/usb_storage.cfg | 2 +- minix/drivers/usb/usb_hub/Makefile | 4 - minix/drivers/usb/usb_hub/usb_hub.c | 11 +- minix/drivers/usb/usbd/base/earm/Makefile | 2 +- minix/drivers/usb/usbd/base/usbd.c | 14 +- minix/drivers/usb/usbd/hcd/hcd.c | 225 ++++++++++++------ minix/drivers/usb/usbd/hcd/hcd_common.c | 33 +-- minix/drivers/usb/usbd/hcd/hcd_ddekit.c | 128 ++++++++-- minix/drivers/usb/usbd/hcd/hcd_schedule.c | 143 +++++++++++ minix/drivers/usb/usbd/hcd/musb/musb_am335x.c | 17 +- .../usb/usbd/include/usbd/hcd_common.h | 22 +- .../usb/usbd/include/usbd/hcd_interface.h | 19 +- .../usb/usbd/include/usbd/hcd_schedule.h | 16 ++ .../usb/usbd/include/usbd/usbd_schedule.h | 12 + minix/include/ddekit/usb.h | 9 + minix/include/minix/com.h | 6 +- minix/include/minix/usb.h | 3 + minix/lib/libddekit/src/usb_client.c | 11 + minix/lib/libddekit/src/usb_server.c | 37 +++ minix/lib/libusb/usb.c | 29 +++ 22 files changed, 593 insertions(+), 157 deletions(-) create mode 100644 minix/drivers/usb/usbd/hcd/hcd_schedule.c create mode 100644 minix/drivers/usb/usbd/include/usbd/hcd_schedule.h create mode 100644 minix/drivers/usb/usbd/include/usbd/usbd_schedule.h diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 2076aa230..26b64cb42 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -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 diff --git a/etc/devmand/usb_hub.cfg b/etc/devmand/usb_hub.cfg index 5018f6875..71b534aee 100644 --- a/etc/devmand/usb_hub.cfg +++ b/etc/devmand/usb_hub.cfg @@ -1,6 +1,6 @@ usb_driver usb_hub { - binary = /usr/sbin/usb_hub; + binary = /service/usb_hub; id { bInterfaceClass = 0x09; } diff --git a/etc/devmand/usb_storage.cfg b/etc/devmand/usb_storage.cfg index 7839f9b13..03c85955c 100644 --- a/etc/devmand/usb_storage.cfg +++ b/etc/devmand/usb_storage.cfg @@ -1,6 +1,6 @@ usb_driver usb_storage { - binary = /usr/sbin/usb_storage; + binary = /service/usb_storage; id { bInterfaceClass = 0x08; } diff --git a/minix/drivers/usb/usb_hub/Makefile b/minix/drivers/usb/usb_hub/Makefile index cc18fe3a0..9e5273c97 100644 --- a/minix/drivers/usb/usb_hub/Makefile +++ b/minix/drivers/usb/usb_hub/Makefile @@ -13,8 +13,4 @@ LDADD+=-lddekit_usb_client -lddekit -lusb -lsys -lminlib #LDADD+=-Wl,-Ttext=0x800000 #CPPFLAGS+=-DHUB_DEBUG -MAN= - -BINDIR?= /usr/sbin - .include diff --git a/minix/drivers/usb/usb_hub/usb_hub.c b/minix/drivers/usb/usb_hub/usb_hub.c index 1dbcd40b8..519935a6f 100644 --- a/minix/drivers/usb/usb_hub/usb_hub.c +++ b/minix/drivers/usb/usb_hub/usb_hub.c @@ -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); } diff --git a/minix/drivers/usb/usbd/base/earm/Makefile b/minix/drivers/usb/usbd/base/earm/Makefile index 59425a2c5..318f64c73 100644 --- a/minix/drivers/usb/usbd/base/earm/Makefile +++ b/minix/drivers/usb/usbd/base/earm/Makefile @@ -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 diff --git a/minix/drivers/usb/usbd/base/usbd.c b/minix/drivers/usb/usbd/base/usbd.c index 6104b1800..2d90b972d 100644 --- a/minix/drivers/usb/usbd/base/usbd.c +++ b/minix/drivers/usb/usbd/base/usbd.c @@ -12,6 +12,7 @@ #include #include +#include /*===========================================================================* @@ -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); diff --git a/minix/drivers/usb/usbd/hcd/hcd.c b/minix/drivers/usb/usbd/hcd/hcd.c index b0ed8edb4..002c7e1d2 100644 --- a/minix/drivers/usb/usbd/hcd/hcd.c +++ b/minix/drivers/usb/usbd/hcd/hcd.c @@ -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(); } diff --git a/minix/drivers/usb/usbd/hcd/hcd_common.c b/minix/drivers/usb/usbd/hcd/hcd_common.c index 6c3b73bf5..23f3f660d 100644 --- a/minix/drivers/usb/usbd/hcd/hcd_common.c +++ b/minix/drivers/usb/usbd/hcd/hcd_common.c @@ -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); } diff --git a/minix/drivers/usb/usbd/hcd/hcd_ddekit.c b/minix/drivers/usb/usbd/hcd/hcd_ddekit.c index 75b39e608..b982ff1dd 100644 --- a/minix/drivers/usb/usbd/hcd/hcd_ddekit.c +++ b/minix/drivers/usb/usbd/hcd/hcd_ddekit.c @@ -8,6 +8,7 @@ #include #include +#include #include @@ -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; +} diff --git a/minix/drivers/usb/usbd/hcd/hcd_schedule.c b/minix/drivers/usb/usbd/hcd/hcd_schedule.c new file mode 100644 index 000000000..50a9ff32f --- /dev/null +++ b/minix/drivers/usb/usbd/hcd/hcd_schedule.c @@ -0,0 +1,143 @@ +/* + * Implementation of HCD URB scheduler + */ + +#include +#include +#include +#include +#include +#include + + +/*===========================================================================* + * 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); +} diff --git a/minix/drivers/usb/usbd/hcd/musb/musb_am335x.c b/minix/drivers/usb/usbd/hcd/musb/musb_am335x.c index 824abe69f..b8d25313a 100644 --- a/minix/drivers/usb/usbd/hcd/musb/musb_am335x.c +++ b/minix/drivers/usb/usbd/hcd/musb/musb_am335x.c @@ -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; } diff --git a/minix/drivers/usb/usbd/include/usbd/hcd_common.h b/minix/drivers/usb/usbd/include/usbd/hcd_common.h index 09c155684..133003492 100644 --- a/minix/drivers/usb/usbd/include/usbd/hcd_common.h +++ b/minix/drivers/usb/usbd/include/usbd/hcd_common.h @@ -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); /*===========================================================================* diff --git a/minix/drivers/usb/usbd/include/usbd/hcd_interface.h b/minix/drivers/usb/usbd/include/usbd/hcd_interface.h index b3c887d3d..8ab31f486 100644 --- a/minix/drivers/usb/usbd/include/usbd/hcd_interface.h +++ b/minix/drivers/usb/usbd/include/usbd/hcd_interface.h @@ -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_ */ diff --git a/minix/drivers/usb/usbd/include/usbd/hcd_schedule.h b/minix/drivers/usb/usbd/include/usbd/hcd_schedule.h new file mode 100644 index 000000000..72fd560ac --- /dev/null +++ b/minix/drivers/usb/usbd/include/usbd/hcd_schedule.h @@ -0,0 +1,16 @@ +/* + * HCD URB scheduler interface + */ + +#ifndef _HCD_SCHEDULE_H_ +#define _HCD_SCHEDULE_H_ + +#include + +/* Makes URB schedule enabled */ +int hcd_schedule_urb(hcd_urb *); + +/* Makes URB schedule disabled */ +void hcd_unschedule_urb(hcd_urb *); + +#endif /* !_HCD_SCHEDULE_H_ */ diff --git a/minix/drivers/usb/usbd/include/usbd/usbd_schedule.h b/minix/drivers/usb/usbd/include/usbd/usbd_schedule.h new file mode 100644 index 000000000..2ee55e78c --- /dev/null +++ b/minix/drivers/usb/usbd/include/usbd/usbd_schedule.h @@ -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_ */ diff --git a/minix/include/ddekit/usb.h b/minix/include/ddekit/usb.h index c3b514e5a..1d3fc7438 100644 --- a/minix/include/ddekit/usb.h +++ b/minix/include/ddekit/usb.h @@ -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 diff --git a/minix/include/minix/com.h b/minix/include/minix/com.h index 9b5d22b24..637f77c0b 100644 --- a/minix/include/minix/com.h +++ b/minix/include/minix/com.h @@ -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) * *===========================================================================*/ diff --git a/minix/include/minix/usb.h b/minix/include/minix/usb.h index 07845527d..1e52d68c4 100644 --- a/minix/include/minix/usb.h +++ b/minix/include/minix/usb.h @@ -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 */ diff --git a/minix/lib/libddekit/src/usb_client.c b/minix/lib/libddekit/src/usb_client.c index c232e953e..5e56aeca3 100644 --- a/minix/lib/libddekit/src/usb_client.c +++ b/minix/lib/libddekit/src/usb_client.c @@ -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, diff --git a/minix/lib/libddekit/src/usb_server.c b/minix/lib/libddekit/src/usb_server.c index a45b65bd4..df200435c 100644 --- a/minix/lib/libddekit/src/usb_server.c +++ b/minix/lib/libddekit/src/usb_server.c @@ -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; } diff --git a/minix/lib/libusb/usb.c b/minix/lib/libusb/usb.c index a6c8f6f6e..772c58702 100644 --- a/minix/lib/libusb/usb.c +++ b/minix/lib/libusb/usb.c @@ -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; +}