From: Kees Jongenburger Date: Mon, 26 May 2014 14:47:56 +0000 (+0200) Subject: usb:Adding usb enumeration. X-Git-Tag: v3.3.0~263 X-Git-Url: http://zhaoyanbai.com/repos/man.arpaname.html?a=commitdiff_plain;h=880ae44a72233be4a98ca1d674781321d991994d;p=minix.git usb:Adding usb enumeration. usbd update from JPEmbedded Change-Id: I4098b29a3188abe7110d59f0746ea40ac5818bbf http://gerrit.minix3.org/#/c/2698/ --- diff --git a/drivers/usbd/base/usbd.c b/drivers/usbd/base/usbd.c index 7a78293d1..288f7f942 100755 --- a/drivers/usbd/base/usbd.c +++ b/drivers/usbd/base/usbd.c @@ -5,6 +5,8 @@ #include /* ddekit_init */ #include /* DDEKit threading */ +#include /* DDEKit USB server */ + #include /* Initializing 'devman' */ #include /* SEF handling */ @@ -22,7 +24,6 @@ static void usbd_server_thread(void *); /* TODO: No headers for these... */ extern void ddekit_minix_wait_exit(void); /* dde.c */ -extern void ddekit_usb_server_init(void); /* usb_server.c */ /*===========================================================================* @@ -34,6 +35,7 @@ main(int UNUSED(argc), char * UNUSED(argv[])) int ret_val; USB_MSG("Starting USBD"); + USB_DBG("Built: %s %s", __DATE__, __TIME__); /* Basic SEF,DDE,... initialization */ usbd_init(); diff --git a/drivers/usbd/hcd/hcd.c b/drivers/usbd/hcd/hcd.c index e2ba40989..bbb39dec9 100755 --- a/drivers/usbd/hcd/hcd.c +++ b/drivers/usbd/hcd/hcd.c @@ -2,9 +2,11 @@ * Implementation of generic HCD */ -#include /* nanosleep */ #include /* memcpy */ +#include /* errno with sign */ +#include /* USB_TRANSFER_CTL... */ + #include #include #include @@ -27,15 +29,21 @@ static int hcd_set_address(hcd_device_state *, int); static int hcd_get_descriptor_tree(hcd_device_state *); static int hcd_set_configuration(hcd_device_state *, int); static int hcd_handle_urb(hcd_device_state *); +static int hcd_control_urb(hcd_device_state *); +static int hcd_bulk_urb(hcd_device_state *); /* For internal use by more general methods */ static int hcd_setup_packet(hcd_device_state *, hcd_ctrlrequest *); +static int hcd_bulk_transfer(hcd_device_state *, hcd_bulkrequest *, int); /*===========================================================================* * Local definitions * *===========================================================================*/ -/* TODO: Only one device at a time */ +/* 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]; @@ -55,13 +63,13 @@ hcd_handle_event(hcd_driver_state * driver) /* 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->event, this_device->state); + 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 */ - switch (driver->event) { + switch (driver->current_event) { case HCD_EVENT_CONNECTED: if (HCD_STATE_DISCONNECTED == this_device->state) { if (EXIT_SUCCESS != hcd_connect_device( @@ -89,6 +97,7 @@ hcd_handle_event(hcd_driver_state * driver) 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); @@ -133,13 +142,13 @@ hcd_device_thread(void * thread_args) USB_DBG("Waiting for URBs"); - /* No URB's yet */ - this_device->urb = NULL; - /* Start handling URB's */ for(;;) { + /* No URB's yet */ + this_device->urb = NULL; + /* Block and wait for something like 'submit URB' */ - hcd_device_wait(this_device); + hcd_device_wait(this_device, HCD_EVENT_URB, HCD_NO_ENDPOINT); if (EXIT_SUCCESS != hcd_handle_urb(this_device)) hcd_device_finish(this_device, "URB handling failed"); @@ -162,7 +171,7 @@ hcd_device_finish(hcd_device_state * this_device, const char * finish_msg) /* Lock forever */ for (;;) { - hcd_device_wait(this_device); + hcd_device_wait(this_device, HCD_EVENT_URB, HCD_NO_ENDPOINT); USB_MSG("Failed attempt to continue finished thread"); } } @@ -181,10 +190,11 @@ hcd_enumerate(hcd_device_state * this_device) d = this_device->driver; /* First let driver reset device */ - d->reset_device(d->private_data); - - /* Set parameters for further communication */ - d->setup_device(d->private_data, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR); + if (EXIT_SUCCESS != d->reset_device(d->private_data, + &(this_device->speed))) { + USB_MSG("Failed to reset device"); + return EXIT_FAILURE; + } /* Get device descriptor */ if (EXIT_SUCCESS != hcd_get_device_descriptor(this_device)) { @@ -201,7 +211,7 @@ hcd_enumerate(hcd_device_state * this_device) } /* Set parameters for further communication */ - d->setup_device(d->private_data, HCD_DEFAULT_EP, HCD_ATTACHED_ADDR); + d->setup_device(d->private_data, HCD_DEFAULT_EP, this_device->address); /* Get other descriptors */ if (EXIT_SUCCESS != hcd_get_descriptor_tree(this_device)) { @@ -254,11 +264,29 @@ hcd_get_device_descriptor(hcd_device_state * this_device) /* Remember max packet size from device descriptor */ this_device->max_packet_size = this_device->device_desc.bMaxPacketSize; - /* Output VID/PID when debugging */ - USB_DBG("idVendor: %02X%02X", this_device->device_desc.idVendor[1], - this_device->device_desc.idVendor[0]); - USB_DBG("idProduct: %02X%02X", this_device->device_desc.idProduct[1], - this_device->device_desc.idProduct[0]); + /* Dump device descriptor in debug mode */ +#ifdef DEBUG + { + hcd_device_descriptor * d; + d = &(this_device->device_desc); + + USB_DBG("<>"); + USB_DBG("bLength %02X", d->bLength); + USB_DBG("bDescriptorType %02X", d->bDescriptorType); + USB_DBG("bcdUSB %04X", UGETW(d->bcdUSB)); + USB_DBG("bDeviceClass %02X", d->bDeviceClass); + USB_DBG("bDeviceSubClass %02X", d->bDeviceSubClass); + USB_DBG("bDeviceProtocol %02X", d->bDeviceProtocol); + USB_DBG("bMaxPacketSize %02X", d->bMaxPacketSize); + USB_DBG("idVendor %04X", UGETW(d->idVendor)); + USB_DBG("idProduct %04X", UGETW(d->idProduct)); + USB_DBG("bcdDevice %04X", UGETW(d->bcdDevice)); + USB_DBG("iManufacturer %02X", d->iManufacturer); + USB_DBG("iProduct %02X", d->iProduct); + USB_DBG("iSerialNumber %02X", d->iSerialNumber); + USB_DBG("bNumConfigurations %02X", d->bNumConfigurations); + } +#endif return EXIT_SUCCESS; } @@ -289,11 +317,11 @@ hcd_set_address(hcd_device_state * this_device, int address) return EXIT_FAILURE; } - { - /* Sleep 5ms for proper addressing */ - struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(5)}; - nanosleep(&nanotm, NULL); - } + /* Sleep 5msec to allow addressing */ + hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(5)); + + /* Remember what was assigned in hardware */ + this_device->address = address; return EXIT_SUCCESS; } @@ -412,15 +440,180 @@ hcd_set_configuration(hcd_device_state * this_device, int configuration) static int hcd_handle_urb(hcd_device_state * this_device) { + hcd_urb * urb; + int transfer_status; + + DEBUG_DUMP; + + transfer_status = EXIT_FAILURE; + urb = this_device->urb; + + USB_ASSERT(NULL != urb, "NULL URB given"); + /* TODO: One device only */ + USB_ASSERT((void *)this_device != (void *)urb->dev, + "Unknown device for URB"); + + switch (urb->type) { + + case USB_TRANSFER_CTL: + transfer_status = hcd_control_urb(this_device); + break; + + case USB_TRANSFER_BLK: + transfer_status = hcd_bulk_urb(this_device); + break; + + case USB_TRANSFER_INT: + /* TODO: transfer */ + USB_MSG("Interrupt transfer not supported"); + break; + + case USB_TRANSFER_ISO: + /* TODO: transfer */ + USB_MSG("ISO transfer not supported"); + break; + + default: + USB_MSG("Invalid transfer type 0x%X", urb->type); + break; + } + +#ifndef URB_TEST + /* Call completion */ + hcd_completion_cb(urb->priv); +#endif + + /* Only critical failures should ever yield EXIT_FAILURE */ + return EXIT_SUCCESS; +} + + +/*===========================================================================* + * hcd_control_urb * + *===========================================================================*/ +static int +hcd_control_urb(hcd_device_state * this_device) +{ + hcd_urb * urb; + hcd_ctrlrequest setup; + DEBUG_DUMP; - USB_ASSERT(NULL != this_device->urb, "NULL URB received"); + urb = this_device->urb; - /* TODO: URB handling will be here */ + /* Assume bad values unless something different occurs later */ + urb->status = EINVAL; - /* TODO: call completion */ - /* hcd_completion_cb */ + /* Must have setup packet */ + if (NULL == urb->setup_packet) { + USB_MSG("No setup packet in URB, for control transfer"); + return EXIT_FAILURE; + } + + /* TODO: Only EP0 can have control transfer */ + if (0 != urb->endpoint) { + USB_MSG("Control transfer for non zero EP"); + return EXIT_FAILURE; + } + + /* Hold setup packet and analyze it */ + memcpy(&setup, urb->setup_packet, sizeof(setup)); + + /* TODO: broken constants for urb->direction (USB_OUT...) */ + if (((setup.bRequestType >> 7) & 0x01) != urb->direction) { + USB_MSG("URB Direction mismatch"); + return EXIT_FAILURE; + } + /* Send setup packet */ + if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup)) { + USB_MSG("Sending URB setup packet, failed"); + urb->status = EPIPE; + return EXIT_FAILURE; + } + + urb->status = EXIT_SUCCESS; + return EXIT_SUCCESS; +} + + +/*===========================================================================* + * hcd_bulk_urb * + *===========================================================================*/ +static int +hcd_bulk_urb(hcd_device_state * this_device) +{ + hcd_endpoint * e; + hcd_bulkrequest request; + hcd_urb * urb; + + DEBUG_DUMP; + + urb = this_device->urb; + + /* Assume bad values unless something different occurs later */ + urb->status = EINVAL; + + if (NULL == urb->data) { + USB_MSG("No data packet in URB, for bulk transfer"); + return EXIT_FAILURE; + } + + if ((UE_GET_ADDR(urb->endpoint) >= 16) || + (UE_GET_ADDR(urb->endpoint) <= 0)) { + USB_MSG("Illegal EP number"); + return EXIT_FAILURE; + } + + /* TODO: broken USB_IN... constants */ + if ((1 != urb->direction) && (0 != urb->direction)) { + USB_MSG("Illegal EP direction"); + return EXIT_FAILURE; + } + + /* TODO: Any additional checks? (sane size?) */ + + /* Assign to bulk request structure */ + request.endpoint = urb->endpoint; + request.size = (int)urb->size; + request.data = urb->data; + + /* Check if EP number is valid */ + e = hcd_tree_find_ep(&(this_device->config_tree), request.endpoint); + + if (NULL == e) { + USB_MSG("Invalid EP value"); + return EXIT_FAILURE; + } + + /* TODO: broken constants for urb->direction (USB_OUT...) */ + /* Check if remembered direction matches */ + if (((e->descriptor.bEndpointAddress >> 7) & 0x01) != urb->direction) { + USB_MSG("EP direction mismatch"); + return EXIT_FAILURE; + } + + /* Check if remembered type matches */ + if (e->descriptor.bmAttributes != UE_BULK) { + USB_MSG("EP type mismatch"); + return EXIT_FAILURE; + } + + /* Assign to let know how much data can be transfered at a time */ + request.max_packet_size = UGETW(e->descriptor.wMaxPacketSize); + + /* Let know how to configure EP for speed */ + request.speed = this_device->speed; + + /* Send bulk data */ + if (EXIT_SUCCESS != hcd_bulk_transfer(this_device, &request, + urb->direction)) { + USB_MSG("URB bulk transfer, failed"); + urb->status = EPIPE; + return EXIT_FAILURE; + } + + urb->status = EXIT_SUCCESS; return EXIT_SUCCESS; } @@ -447,10 +640,12 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup) d->setup_stage(d->private_data, setup); /* Wait for response */ - hcd_device_wait(this_device); + hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, HCD_ENDPOINT_0); /* Check response */ - if (EXIT_SUCCESS != d->check_error(d->private_data)) + if (EXIT_SUCCESS != d->check_error(d->private_data, + HCD_TRANSFER_CONTROL, + HCD_DIRECTION_UNUSED)) return EXIT_FAILURE; /* For data packets... */ @@ -468,11 +663,15 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup) d->in_data_stage(d->private_data); /* Wait for response */ - hcd_device_wait(this_device); + hcd_device_wait(this_device, + HCD_EVENT_ENDPOINT, + HCD_ENDPOINT_0); /* Check response */ if (EXIT_SUCCESS != d->check_error( - d->private_data)) + d->private_data, + HCD_TRANSFER_CONTROL, + HCD_DIRECTION_UNUSED)) return EXIT_FAILURE; /* Read data received as response */ @@ -510,10 +709,13 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup) d->out_status_stage(d->private_data); /* Wait for response */ - hcd_device_wait(this_device); + hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, + HCD_ENDPOINT_0); /* Check response */ - if (EXIT_SUCCESS != d->check_error(d->private_data)) + if (EXIT_SUCCESS != d->check_error(d->private_data, + HCD_TRANSFER_CONTROL, + HCD_DIRECTION_UNUSED)) return EXIT_FAILURE; } else { @@ -522,10 +724,13 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup) d->in_status_stage(d->private_data); /* Wait for response */ - hcd_device_wait(this_device); + hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, + HCD_ENDPOINT_0); /* Check response */ - if (EXIT_SUCCESS != d->check_error(d->private_data)) + if (EXIT_SUCCESS != d->check_error(d->private_data, + HCD_TRANSFER_CONTROL, + HCD_DIRECTION_UNUSED)) return EXIT_FAILURE; /* Read zero data from response to clear registers */ @@ -535,3 +740,103 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup) return EXIT_SUCCESS; } + + +/*===========================================================================* + * hcd_bulk_transfer * + *===========================================================================*/ +static int +hcd_bulk_transfer(hcd_device_state * this_device, hcd_bulkrequest * request, + int direction) +{ + hcd_driver_state * d; + hcd_bulkrequest temp_req; + int transfer_len; + + DEBUG_DUMP; + + /* Initially... */ + d = this_device->driver; + + /* Set parameters for further communication */ + d->setup_device(d->private_data, + request->endpoint, + this_device->address); + + /* TODO: broken USB_IN... constants */ + if (1 == direction) { + + do { + /* Start actual bulk transfer */ + d->bulk_in_stage(d->private_data, request); + + /* Wait for response */ + hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, + request->endpoint); + + /* Check response */ + if (EXIT_SUCCESS != d->check_error(d->private_data, + HCD_TRANSFER_BULK, + HCD_DIRECTION_IN)) + return EXIT_FAILURE; + + /* Read data received as response */ + transfer_len = d->read_data(d->private_data, + (hcd_reg1 *)request->data, + request->endpoint); + + request->size -= transfer_len; + request->data += transfer_len; + + /* Total length shall not become negative */ + USB_ASSERT(request->size >= 0, + "Invalid amount of data received"); + + /* TODO: REMOVEME (dumping of bulk transfer) */ + { + int i; + USB_MSG("RECEIVED: %d", transfer_len); + for (i = 0; i < transfer_len; i++) + USB_MSG("%c", + (request->data-transfer_len)[i]); + } + + } while (0 != request->size); + + } else if (0 == direction) { + + do { + temp_req = *request; + + /* Decide transfer size */ + if (temp_req.size > (int)temp_req.max_packet_size) { + temp_req.size = temp_req.max_packet_size; + } + + request->data += temp_req.size; + request->size -= temp_req.size; + + /* Total length shall not become negative */ + USB_ASSERT(request->size >= 0, + "Invalid amount of data received"); + + /* Start actual bulk transfer */ + d->bulk_out_stage(d->private_data, &temp_req); + + /* Wait for response */ + hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, + request->endpoint); + + /* Check response */ + if (EXIT_SUCCESS != d->check_error(d->private_data, + HCD_TRANSFER_BULK, + HCD_DIRECTION_OUT)) + return EXIT_FAILURE; + + } while (0 != request->size); + + } else + USB_ASSERT(0, "Invalid transfer direction"); + + return EXIT_SUCCESS; +} diff --git a/drivers/usbd/hcd/hcd_common.c b/drivers/usbd/hcd/hcd_common.c index d93088d64..23f981f17 100755 --- a/drivers/usbd/hcd/hcd_common.c +++ b/drivers/usbd/hcd/hcd_common.c @@ -4,6 +4,7 @@ */ #include /* memset... */ +#include /* nanosleep */ #include /* Physical to virtual memory mapping */ @@ -13,6 +14,7 @@ #include /* sys_privctl */ #include +#include #include @@ -159,6 +161,31 @@ hcd_os_clkconf_release(void) } +/*===========================================================================* + * hcd_os_nanosleep * + *===========================================================================*/ +void +hcd_os_nanosleep(int nanosec) +{ + struct timespec nanotm; + + DEBUG_DUMP; + + if (nanosec >= HCD_NANO) { + nanotm.tv_sec = nanosec / HCD_NANO; + nanotm.tv_nsec = nanosec % HCD_NANO; + } else { + nanotm.tv_sec = 0; + nanotm.tv_nsec = nanosec; + } + + /* TODO: since it is not likely to be ever interrupted, we do not try + * to sleep for a remaining time in case of signal handling */ + USB_ASSERT(EXIT_SUCCESS == nanosleep(&nanotm, NULL), + "Calling nanosleep() failed"); +} + + /*===========================================================================* * hcd_init_device * *===========================================================================*/ @@ -211,10 +238,19 @@ hcd_disconnect_device(hcd_device_state * this_device) * hcd_device_wait * *===========================================================================*/ void -hcd_device_wait(hcd_device_state * this_device) +hcd_device_wait(hcd_device_state * this_device, hcd_event event, int ep) { + hcd_driver_state * drv; + DEBUG_DUMP; + drv = (hcd_driver_state *)this_device->driver; + + drv->expected_event = event; + drv->expected_endpoint = ep; + + USB_DBG("Waiting for: ev=0x%X, ep=0x%X", (int)event, ep); + ddekit_sem_down(this_device->lock); } @@ -225,8 +261,22 @@ hcd_device_wait(hcd_device_state * this_device) void hcd_device_continue(hcd_device_state * this_device) { + hcd_driver_state * drv; + DEBUG_DUMP; + drv = (hcd_driver_state *)this_device->driver; + + /* We need to get what was expected... */ + USB_ASSERT(drv->current_event == drv->expected_event, + "Unexpected event occurred"); + + /* ...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); } @@ -260,6 +310,11 @@ hcd_buffer_to_tree(hcd_reg1 * buf, int len, hcd_configuration * c) /* Check descriptor type */ desc = (hcd_descriptor *)buf; + if (0 == desc->bLength) { + USB_MSG("Zero length descriptor"); + goto PARSE_ERROR; + } + if (UDESC_CONFIG == desc->bDescriptorType) { if (EXIT_SUCCESS != hcd_fill_configuration(buf, len, c, cfg_num++)) @@ -341,6 +396,36 @@ hcd_tree_cleanup(hcd_configuration * c) } +/*===========================================================================* + * hcd_tree_find_ep * + *===========================================================================*/ +hcd_endpoint * +hcd_tree_find_ep(hcd_configuration * c, int ep) +{ + hcd_interface * i; + hcd_endpoint * e; + int if_idx; + int ep_idx; + + DEBUG_DUMP; + + /* Free if anything was allocated */ + USB_ASSERT(NULL != c->interface, "No interfaces available"); + USB_ASSERT(c->num_interfaces > 0, "Interface number error"); + + for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) { + i = &(c->interface[if_idx]); + for (ep_idx = 0; ep_idx < i->num_endpoints; ep_idx++) { + e = &(i->endpoint[ep_idx]); + if (UE_GET_ADDR(e->descriptor.bEndpointAddress) == ep) + return e; + } + } + + return NULL; +} + + /*===========================================================================* * hcd_fill_configuration * *===========================================================================*/ @@ -385,8 +470,7 @@ hcd_fill_configuration(hcd_reg1 * buf, int len, hcd_configuration * c, int num) USB_DBG("<>"); USB_DBG("bLength %02X", desc->bLength); USB_DBG("bDescriptorType %02X", desc->bDescriptorType); - USB_DBG("wTotalLength %02X%02X", desc->wTotalLength[1], - desc->wTotalLength[0]); + USB_DBG("wTotalLength %04X", UGETW(desc->wTotalLength)); USB_DBG("bNumInterface %02X", desc->bNumInterface); USB_DBG("bConfigurationValue %02X", desc->bConfigurationValue); USB_DBG("iConfiguration %02X", desc->iConfiguration); @@ -482,8 +566,7 @@ hcd_fill_endpoint(hcd_reg1 * buf, int len, hcd_endpoint * e, int num) USB_DBG("bDescriptorType %02X", desc->bDescriptorType); USB_DBG("bEndpointAddress %02X", desc->bEndpointAddress); USB_DBG("bmAttributes %02X", desc->bmAttributes); - USB_DBG("wMaxPacketSize %02X%02X", desc->wMaxPacketSize[1], - desc->wMaxPacketSize[0]); + USB_DBG("wMaxPacketSize %04X", UGETW(desc->wMaxPacketSize)); USB_DBG("bInterval %02X", desc->bInterval); return EXIT_SUCCESS; diff --git a/drivers/usbd/hcd/hcd_ddekit.c b/drivers/usbd/hcd/hcd_ddekit.c index 950865526..5f650d06f 100755 --- a/drivers/usbd/hcd/hcd_ddekit.c +++ b/drivers/usbd/hcd/hcd_ddekit.c @@ -7,6 +7,7 @@ #include #include +#include #include @@ -40,7 +41,7 @@ _ddekit_usb_get_manufacturer(struct ddekit_usb_dev * ddev) { static const char mfg[] = "UNKNOWN"; DEBUG_DUMP; - /* TODO: UNUSED won't work */ + /* TODO: UNUSED for argument won't work */ ((void)ddev); return (char *)mfg; } @@ -54,7 +55,7 @@ _ddekit_usb_get_product(struct ddekit_usb_dev * ddev) { static const char prod[] = "UNKNOWN"; DEBUG_DUMP; - /* TODO: UNUSED won't work */ + /* TODO: UNUSED for argument won't work */ ((void)ddev); return (char *)prod; } @@ -68,7 +69,7 @@ _ddekit_usb_get_serial(struct ddekit_usb_dev * ddev) { static const char serial[] = "UNKNOWN"; DEBUG_DUMP; - /* TODO: UNUSED won't work */ + /* TODO: UNUSED for argument won't work */ ((void)ddev); return (char *)serial; } @@ -156,7 +157,7 @@ ddekit_usb_get_device_id(struct ddekit_usb_dev * dev, struct ddekit_usb_device_id * id) { DEBUG_DUMP; - /* TODO: UNUSED won't work */ + /* TODO: UNUSED for argument won't work */ ((void)dev); ((void)id); return; @@ -172,17 +173,19 @@ ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb) { hcd_urb * urb; hcd_device_state * dev; + hcd_driver_state * drv; DEBUG_DUMP; urb = (hcd_urb *)d_urb; dev = (hcd_device_state *)(urb->dev); + drv = (hcd_driver_state *)(dev->driver); - /* TODO: queue URB's */ - /* Reassign and go to thread */ dev->urb = urb; - hcd_device_continue(dev); - dev->urb = NULL; + drv->current_event = HCD_EVENT_URB; + + /* TODO: URB's must be queued somewhere */ + hcd_handle_event(drv); return EXIT_SUCCESS; } @@ -195,7 +198,7 @@ int ddekit_usb_cancle_urb(struct ddekit_usb_urb * d_urb) { DEBUG_DUMP; - /* TODO: UNUSED won't work */ + /* TODO: UNUSED for argument won't work */ ((void)d_urb); return EXIT_SUCCESS; } diff --git a/drivers/usbd/hcd/musb/musb_am335x.c b/drivers/usbd/hcd/musb/musb_am335x.c index 7ea016d6d..f818e5f25 100755 --- a/drivers/usbd/hcd/musb/musb_am335x.c +++ b/drivers/usbd/hcd/musb/musb_am335x.c @@ -3,7 +3,6 @@ */ #include /* memset */ -#include /* nanosleep */ #include #include @@ -19,17 +18,19 @@ /*===========================================================================* * AM335x base register defines * *===========================================================================*/ -/* Where MUSB core space starts */ -#define AM335X_MUSB_CORE0_BASE_ADDR 0x47401400u -#define AM335X_MUSB_CORE1_BASE_ADDR 0x47401C00u -#define AM335X_MUSB_CORE_BASE_LEN 0x400u +/* Memory placement defines */ +#define AM335X_USBSS_BASE_ADDR 0x47400000u +#define AM335X_USB0_BASE_OFFSET 0x1000u +#define AM335X_MUSB_CORE0_BASE_OFFSET 0x1400u +#define AM335X_USB1_BASE_OFFSET 0x1800u +#define AM335X_MUSB_CORE1_BASE_OFFSET 0x1C00u +#define AM335X_USBSS_TOTAL_REG_LEN 0x5000u /*===========================================================================* * AM335x USB specific register defines * *===========================================================================*/ /* SS registers base address */ -#define AM335X_USBSS_BASE_ADDR 0x47400000u #define AM335X_REG_REVREG 0x000u #define AM335X_REG_SYSCONFIG 0x010u @@ -74,13 +75,6 @@ #define AM335X_REG_IRQFRAMEENABLE0 0x240u #define AM335X_REG_IRQFRAMEENABLE1 0x244u -/* Length in bytes of SS registers */ -#define AM335X_USBSS_BASE_LEN AM335X_REG_IRQFRAMEENABLE1 + 4u - -/* USBx registers base addresses */ -#define AM335X_USB0_BASE_ADDR 0x47401000u -#define AM335X_USB1_BASE_ADDR 0x47401800u - #define AM335X_REG_USBXREV 0x00u #define AM335X_REG_USBXCTRL 0x14u #define AM335X_REG_USBXSTAT 0x18u @@ -167,6 +161,22 @@ #define AM335X_VAL_USBXIRQENABLEXXX1_DRVVBUS HCD_BIT(8) #define AM335X_VAL_USBXIRQENABLEXXX1_GENERIC HCD_BIT(9) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_1 HCD_BIT(17) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_2 HCD_BIT(18) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_3 HCD_BIT(19) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_4 HCD_BIT(20) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_5 HCD_BIT(21) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_6 HCD_BIT(22) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_7 HCD_BIT(23) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_8 HCD_BIT(24) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_9 HCD_BIT(25) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_10 HCD_BIT(26) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_11 HCD_BIT(27) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_12 HCD_BIT(28) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_13 HCD_BIT(29) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_14 HCD_BIT(30) +#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_15 HCD_BIT(31) + #define AM335X_VAL_USBXIRQSTAT1_SUSPEND HCD_BIT(0) #define AM335X_VAL_USBXIRQSTAT1_RESUME HCD_BIT(1) #define AM335X_VAL_USBXIRQSTAT1_RESET_BABBLE HCD_BIT(2) @@ -178,9 +188,6 @@ #define AM335X_VAL_USBXIRQSTAT1_DRVVBUS HCD_BIT(8) #define AM335X_VAL_USBXIRQSTAT1_GENERIC HCD_BIT(9) -/* Length in bytes of USBx registers */ -#define AM335X_USBX_BASE_LEN AM335X_REG_USBXMODE + 4u - /* Helpers for interrupt clearing */ #define CLEAR_IRQ0(irq0_bit) HCD_WR4(r, AM335X_REG_USBXIRQSTAT0, (irq0_bit)) #define CLEAR_IRQ1(irq1_bit) HCD_WR4(r, AM335X_REG_USBXIRQSTAT1, (irq1_bit)) @@ -263,6 +270,7 @@ static void musb_am335x_internal_deinit(void); static void musb_am335x_irq_init(void *); /* TODO: required by DDEKit */ static void musb_am335x_usbss_isr(void *); static void musb_am335x_usbx_isr(void *); +static int musb_am335x_irqstat0_to_ep(int); /* Configuration helpers */ static void musb_am335x_usb_reset(int); @@ -289,7 +297,7 @@ musb_am335x_init(void) /* Map memory for USBSS */ am335x.ss.regs = hcd_os_regs_init(AM335X_USBSS_BASE_ADDR, - AM335X_USBSS_BASE_LEN); + AM335X_USBSS_TOTAL_REG_LEN); if (NULL == am335x.ss.regs) return EXIT_FAILURE; @@ -312,18 +320,12 @@ musb_am335x_init(void) ctrl->priv.usb_num = AM335X_USB0; /* MUSB core addresses for later registering */ - ctrl->core.regs = hcd_os_regs_init(AM335X_MUSB_CORE0_BASE_ADDR, - AM335X_MUSB_CORE_BASE_LEN); - - if (NULL == ctrl->core.regs) - return EXIT_FAILURE; + ctrl->core.regs = (void*)((hcd_addr)am335x.ss.regs + + AM335X_MUSB_CORE0_BASE_OFFSET); /* Map AM335X USB0 specific addresses */ - ctrl->usb.regs = hcd_os_regs_init(AM335X_USB0_BASE_ADDR, - AM335X_USBX_BASE_LEN); - - if (NULL == ctrl->usb.regs) - return EXIT_FAILURE; + ctrl->usb.regs = (void*)((hcd_addr)am335x.ss.regs + + AM335X_USB0_BASE_OFFSET); /* Attach IRQ to number */ if (EXIT_SUCCESS != hcd_os_interrupt_attach(AM335X_USB0_IRQ, @@ -337,6 +339,8 @@ musb_am335x_init(void) ctrl->driver.setup_device = musb_setup_device; ctrl->driver.reset_device = musb_reset_device; ctrl->driver.setup_stage = musb_setup_stage; + ctrl->driver.bulk_in_stage = musb_bulk_in_stage; + ctrl->driver.bulk_out_stage = musb_bulk_out_stage; ctrl->driver.in_data_stage = musb_in_data_stage; ctrl->driver.out_data_stage = musb_out_data_stage; ctrl->driver.in_status_stage = musb_in_status_stage; @@ -356,18 +360,12 @@ musb_am335x_init(void) ctrl->priv.usb_num = AM335X_USB1; /* MUSB core addresses for later registering */ - ctrl->core.regs = hcd_os_regs_init(AM335X_MUSB_CORE1_BASE_ADDR, - AM335X_MUSB_CORE_BASE_LEN); + ctrl->core.regs = (void*)((hcd_addr)am335x.ss.regs + + AM335X_MUSB_CORE1_BASE_OFFSET); - if (NULL == ctrl->core.regs) - return EXIT_FAILURE; - - /* Map AM335X USB1 specific addresses */ - ctrl->usb.regs = hcd_os_regs_init(AM335X_USB1_BASE_ADDR, - AM335X_USBX_BASE_LEN); - - if (NULL == ctrl->usb.regs) - return EXIT_FAILURE; + /* Map AM335X USB0 specific addresses */ + ctrl->usb.regs = (void*)((hcd_addr)am335x.ss.regs + + AM335X_USB1_BASE_OFFSET); /* Attach IRQ to number */ if (EXIT_SUCCESS != hcd_os_interrupt_attach(AM335X_USB1_IRQ, @@ -381,6 +379,8 @@ musb_am335x_init(void) ctrl->driver.setup_device = musb_setup_device; ctrl->driver.reset_device = musb_reset_device; ctrl->driver.setup_stage = musb_setup_stage; + ctrl->driver.bulk_in_stage = musb_bulk_in_stage; + ctrl->driver.bulk_out_stage = musb_bulk_out_stage; ctrl->driver.in_data_stage = musb_in_data_stage; ctrl->driver.out_data_stage = musb_out_data_stage; ctrl->driver.in_status_stage = musb_in_status_stage; @@ -404,32 +404,9 @@ musb_am335x_deinit(void) musb_am335x_internal_deinit(); /* Release maps if anything was assigned */ -#ifdef AM335X_USE_USB0 - if (NULL != am335x.ctrl[AM335X_USB0].usb.regs) - if (EXIT_SUCCESS != hcd_os_regs_deinit(AM335X_USB0_BASE_ADDR, - AM335X_USBX_BASE_LEN)) - USB_MSG("Failed to release USB0 OTG mapping"); - - if (NULL != am335x.ctrl[AM335X_USB0].core.regs) - if (EXIT_SUCCESS != hcd_os_regs_deinit( - AM335X_MUSB_CORE0_BASE_ADDR, - AM335X_MUSB_CORE_BASE_LEN)) - USB_MSG("Failed to release USB0 core mapping"); -#endif - if (NULL != am335x.ctrl[AM335X_USB1].usb.regs) - if (EXIT_SUCCESS != hcd_os_regs_deinit(AM335X_USB1_BASE_ADDR, - AM335X_USBX_BASE_LEN)) - USB_MSG("Failed to release USB1 OTG mapping"); - - if (NULL != am335x.ctrl[AM335X_USB1].core.regs) - if (EXIT_SUCCESS != hcd_os_regs_deinit( - AM335X_MUSB_CORE1_BASE_ADDR, - AM335X_MUSB_CORE_BASE_LEN)) - USB_MSG("Failed to release USB1 core mapping"); - if (NULL != am335x.ss.regs) if (EXIT_SUCCESS != hcd_os_regs_deinit(AM335X_USBSS_BASE_ADDR, - AM335X_USBSS_BASE_LEN)) + AM335X_USBSS_TOTAL_REG_LEN)) USB_MSG("Failed to release USBSS mapping"); } @@ -449,14 +426,11 @@ musb_am335x_internal_init(void) return EXIT_FAILURE; /* TODO: time to stabilize? */ - { - /* Sleep 25ms */ - struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(25)}; - nanosleep(&nanotm, NULL); - } + /* Sleep 25msec */ + hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(25)); /* Read and dump revision register */ - USB_MSG("Revision (REVREG): %08X", + USB_MSG("MUSB revision (REVREG): %08X", (unsigned int)HCD_RD4(am335x.ss.regs, AM335X_REG_REVREG)); /* Allow OS to handle previously configured USBSS interrupts */ @@ -469,8 +443,6 @@ musb_am335x_internal_init(void) hcd_os_interrupt_enable(AM335X_USB0_IRQ); /* Enable whatever necessary for OTG part of controller */ musb_am335x_otg_enable(AM335X_USB0); - /* Configure control endpoint EP0 */ - musb_ep0_config(&(am335x.ctrl[AM335X_USB0].core)); /* Start actual MUSB core */ musb_core_start(&(am335x.ctrl[AM335X_USB0].core)); #endif @@ -481,8 +453,6 @@ musb_am335x_internal_init(void) hcd_os_interrupt_enable(AM335X_USB1_IRQ); /* Enable whatever necessary for OTG part of controller */ musb_am335x_otg_enable(AM335X_USB1); - /* Configure control endpoint EP0 */ - musb_ep0_config(&(am335x.ctrl[AM335X_USB1].core)); /* Start actual MUSB core */ musb_core_start(&(am335x.ctrl[AM335X_USB1].core)); @@ -581,8 +551,7 @@ musb_am335x_usbx_isr(void * data) if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED) { USB_DBG("Device connected"); CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED); - driver->event = HCD_EVENT_CONNECTED; - driver->subevent = HCD_SUBEVENT_NONE; + driver->current_event = HCD_EVENT_CONNECTED; hcd_handle_event(driver); return; } @@ -590,17 +559,16 @@ musb_am335x_usbx_isr(void * data) if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED) { USB_DBG("Device disconnected"); CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED); - driver->event = HCD_EVENT_DISCONNECTED; - driver->subevent = HCD_SUBEVENT_NONE; + driver->current_event = HCD_EVENT_DISCONNECTED; hcd_handle_event(driver); return; } - if (irqstat0 & 0x01) { - USB_DBG("EP0 interrupt"); - CLEAR_IRQ0(0x01); - driver->event = HCD_EVENT_ENDPOINT; - driver->subevent = HCD_SUBEVENT_EP0; + 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); return; } @@ -654,6 +622,34 @@ musb_am335x_usbx_isr(void * data) } +/*===========================================================================* + * musb_am335x_irqstat0_to_ep * + *===========================================================================*/ +static int +musb_am335x_irqstat0_to_ep(int irqstat0) +{ + int ep; + + DEBUG_DUMP; + + ep = 0; + + while (0 == (irqstat0 & 0x01)) { + irqstat0 >>= 1; + ep++; + USB_ASSERT(ep < 32, "Invalid IRQSTAT0 supplied (1)"); + } + + /* Convert RX interrupt to EP number */ + if (ep >= 16) { + ep -= 16; + USB_ASSERT(ep != 0, "Invalid IRQSTAT0 supplied (2)"); + } + + return ep; +} + + /*===========================================================================* * musb_am335x_usb_reset * *===========================================================================*/ @@ -711,8 +707,47 @@ musb_am335x_otg_enable(int usb_num) HCD_WR4(r, AM335X_REG_USBXIRQENABLESET1, intreg); - /* Set endpoint 0 interrupt to be enabled */ + /* Some MUSB implementations may not need this */ +#if 0 + /* Set EP0 interrupt to be enabled */ intreg = HCD_RD4(r, AM335X_REG_USBXIRQENABLESET0); HCD_SET(intreg, AM335X_VAL_USBXIRQENABLEXXX0_EP0); HCD_WR4(r, AM335X_REG_USBXIRQENABLESET0, intreg); +#else + + /* Set all EP interrupts as enabled */ + intreg = AM335X_VAL_USBXIRQENABLEXXX0_EP0 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP1 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP2 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP3 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP4 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP5 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP6 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP7 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP8 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP9 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP10 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP11 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP12 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP13 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP14 | + AM335X_VAL_USBXIRQENABLEXXX0_TX_EP15 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP1 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP2 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP3 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP4 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP5 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP6 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP7 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP8 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP9 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP10 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP11 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP12 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP13 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP14 | + AM335X_VAL_USBXIRQENABLEXXX0_RX_EP15 ; + + HCD_WR4(r, AM335X_REG_USBXIRQENABLESET0, intreg); +#endif } diff --git a/drivers/usbd/hcd/musb/musb_core.c b/drivers/usbd/hcd/musb/musb_core.c index cf2435ad9..f17a0972e 100755 --- a/drivers/usbd/hcd/musb/musb_core.c +++ b/drivers/usbd/hcd/musb/musb_core.c @@ -3,7 +3,6 @@ */ #include /* memcpy */ -#include /* nanosleep */ #include #include @@ -13,23 +12,17 @@ #include "musb_regs.h" -/*===========================================================================* - * Local defines * - *===========================================================================*/ -#define HCD_COPYBUF_BYTES 64 /* Stack allocated, must be multiple of 4 */ -#define HCD_COPYBUF_WORDS (HCD_COPYBUF_BYTES/4) - - /*===========================================================================* * Local prototypes * *===========================================================================*/ static void musb_set_state(musb_core_config *); -static int musb_check_rxpktrdy(void *); -static void musb_in_stage_cleanup(void *); -static void musb_clear_rxpktrdy(void *); +static int musb_check_rxpktrdy(void *, int); +static void musb_in_stage_cleanup(void *, int); +static void musb_clear_rxpktrdy(void *, int); static void musb_clear_statuspkt(void *); static int musb_get_count(void *); -static void musb_read_fifo(void *, hcd_reg1 *, int, int); +static void musb_read_fifo(void *, void *, int, int); +static void musb_write_fifo(void *, void *, int, int); /*===========================================================================* @@ -45,23 +38,23 @@ static void musb_set_state(musb_core_config * cfg) { void * r; - hcd_reg1 idx; DEBUG_DUMP; r = cfg->regs; + USB_ASSERT(cfg->ep <= 15, "Invalid EP supplied"); + USB_ASSERT(cfg->addr <= 127, "Invalid device address supplied"); + /* Set EP and address to be used in next MUSB command */ /* Set EP by selecting INDEX */ - idx = HCD_RD1(r, MUSB_REG_INDEX); - HCD_CLR(idx, 0x0F); - HCD_SET(idx, cfg->ep & 0x0F); - HCD_WR1(r, MUSB_REG_INDEX, idx); + HCD_WR1(r, MUSB_REG_INDEX, cfg->ep); /* Use device with address 'cfg->addr' */ - HCD_WR2(r, MUSB_REG_RXFUNCADDR, cfg->addr); - HCD_WR2(r, MUSB_REG_TXFUNCADDR, cfg->addr); + HCD_WR1(r, MUSB_REG_FADDR, cfg->addr); + HCD_WR2(r, MUSB_REG_CONFIG(cfg->ep, MUSB_REG_RXFUNCADDR), cfg->addr); + HCD_WR2(r, MUSB_REG_CONFIG(cfg->ep, MUSB_REG_TXFUNCADDR), cfg->addr); } @@ -69,10 +62,9 @@ musb_set_state(musb_core_config * cfg) * musb_check_rxpktrdy * *===========================================================================*/ static int -musb_check_rxpktrdy(void * cfg) +musb_check_rxpktrdy(void * cfg, int ep_num) { void * r; - hcd_reg2 host_csr0; DEBUG_DUMP; @@ -81,12 +73,18 @@ musb_check_rxpktrdy(void * cfg) /* Set EP and device address to be used in this command */ musb_set_state((musb_core_config *)cfg); - /* Get control status register for EP 0 */ - host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0); - /* Check for RXPKTRDY */ - if (host_csr0 & MUSB_VAL_HOST_CSR0_RXPKTRDY) - return EXIT_SUCCESS; + if (0 == ep_num) { + /* Get control status register for EP 0 */ + if (HCD_RD2(r, MUSB_REG_HOST_CSR0) & + MUSB_VAL_HOST_CSR0_RXPKTRDY) + return EXIT_SUCCESS; + } else { + /* Get RX status register for any other EP */ + if (HCD_RD2(r, MUSB_REG_HOST_RXCSR) & + MUSB_VAL_HOST_RXCSR_RXPKTRDY) + return EXIT_SUCCESS; + } return EXIT_FAILURE; } @@ -96,12 +94,15 @@ musb_check_rxpktrdy(void * cfg) * musb_in_stage_cleanup * *===========================================================================*/ static void -musb_in_stage_cleanup(void * cfg) +musb_in_stage_cleanup(void * cfg, int ep_num) { DEBUG_DUMP; - musb_clear_rxpktrdy(cfg); - musb_clear_statuspkt(cfg); + musb_clear_rxpktrdy(cfg, ep_num); + + /* For control EP 0 also clear STATUSPKT */ + if (0 == ep_num) + musb_clear_statuspkt(cfg); } @@ -109,10 +110,10 @@ musb_in_stage_cleanup(void * cfg) * musb_clear_rxpktrdy * *===========================================================================*/ static void -musb_clear_rxpktrdy(void * cfg) +musb_clear_rxpktrdy(void * cfg, int ep_num) { void * r; - hcd_reg2 host_csr0; + hcd_reg2 host_csr; DEBUG_DUMP; @@ -121,12 +122,22 @@ musb_clear_rxpktrdy(void * cfg) /* Set EP and device address to be used in this command */ musb_set_state((musb_core_config *)cfg); - /* Get control status register for EP 0 */ - host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0); - - /* Clear RXPKTRDY to signal receive completion */ - HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_RXPKTRDY); - HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0); + /* Check for RXPKTRDY */ + if (0 == ep_num) { + /* Get control status register for EP 0 */ + host_csr = HCD_RD2(r, MUSB_REG_HOST_CSR0); + + /* Clear RXPKTRDY to signal receive completion */ + HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_RXPKTRDY); + HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr); + } else { + /* Get RX status register for any other EP */ + host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR); + + /* Clear RXPKTRDY to signal receive completion */ + HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_RXPKTRDY); + HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr); + } } @@ -180,41 +191,92 @@ musb_get_count(void * cfg) * musb_read_fifo * *===========================================================================*/ static void -musb_read_fifo(void * cfg, hcd_reg1 * output, int size, int fifo_num) +musb_read_fifo(void * cfg, void * output, int size, int fifo_num) { void * r; - hcd_reg4 * word; - hcd_reg4 copy_buf[HCD_COPYBUF_WORDS]; + + hcd_reg1 * output_b; + hcd_reg4 * output_w; + hcd_addr fifo_addr; - int limit; - int idx; DEBUG_DUMP; - USB_ASSERT((fifo_num >= 0) && (fifo_num <= 4), "Wrong FIFO number"); + USB_ASSERT((fifo_num >= 0) && (fifo_num <= 15), "Wrong FIFO number"); r = ((musb_core_config *)cfg)->regs; fifo_addr = MUSB_REG_FIFO0 + (fifo_num * MUSB_REG_FIFO_LEN); - /* Set EP and device address to be used in this command */ - musb_set_state((musb_core_config *)cfg); + /* TODO: Apparently, FIFO can only be read by: + * 1. initially using words + * 2. using bytes for whatever remains + * Reading bytes first to achieve alignment of remaining data + * will for some reason disable further word based reading + * Such reading method, may not be optimal for unaligned data */ + output_w = (hcd_reg4 *)output; + + /* Try and copy aligned words */ + if (0 == ((hcd_addr)output_w % 4)) { + + while (size > (int)(sizeof(*output_w) - 1)) { + *output_w++ = HCD_RD4(r, fifo_addr); + size -= sizeof(*output_w); + } + } - /* Read full words from MUSB FIFO */ + output_b = (hcd_reg1 *)output_w; + + /* Then, go with remaining bytes */ while (size > 0) { - /* Largest amount of bytes that can be copied at a time */ - limit = (size < HCD_COPYBUF_BYTES) ? size : HCD_COPYBUF_BYTES; + *output_b++ = HCD_RD1(r, fifo_addr); + size--; + } +} + - /* Start copying into that */ - word = copy_buf; +/*===========================================================================* + * musb_write_fifo * + *===========================================================================*/ +static void +musb_write_fifo(void * cfg, void * input, int size, int fifo_num) +{ + void * r; - /* Read words from FIFO into copy_buf */ - for (idx = 0; idx < limit; idx += sizeof(*word)) - *word++ = HCD_RD4(r, fifo_addr); + hcd_reg1 * input_b; + hcd_reg4 * input_w; - /* Copy and shift */ - memcpy(output, copy_buf, limit); - output += limit; - size -= limit; + hcd_addr fifo_addr; + + DEBUG_DUMP; + + USB_ASSERT((fifo_num >= 0) && (fifo_num <= 15), "Wrong FIFO number"); + + r = ((musb_core_config *)cfg)->regs; + fifo_addr = MUSB_REG_FIFO0 + (fifo_num * MUSB_REG_FIFO_LEN); + + /* TODO: Apparently, FIFO can only be written by: + * 1. initially using words + * 2. using bytes for whatever remains + * Writing bytes first to achieve alignment of remaining data + * will for some reason disable further word based writing + * Such writing method, may not be optimal for unaligned data */ + input_w = (hcd_reg4 *)input; + + /* Try and copy aligned words */ + if (0 == ((hcd_addr)input_w % 4)) { + + while (size > (int)(sizeof(*input_w) - 1)) { + HCD_WR4(r, fifo_addr, *input_w++); + size -= sizeof(*input_w); + } + } + + input_b = (hcd_reg1 *)input_w; + + /* Then, go with remaining bytes */ + while (size > 0) { + HCD_WR1(r, fifo_addr, *input_b++); + size--; } } @@ -272,41 +334,6 @@ musb_core_stop(void * cfg) } -/*===========================================================================* - * musb_ep0_config * - *===========================================================================*/ -void -musb_ep0_config(void * cfg) -{ - void * r; - hcd_reg1 host_type0; - hcd_reg2 intrtxe; - - DEBUG_DUMP; - - r = ((musb_core_config *)cfg)->regs; - - /* Set parameters temporarily */ - musb_setup_device((musb_core_config *)cfg, - HCD_DEFAULT_EP, - HCD_DEFAULT_ADDR); - - /* Set EP and device address to be used in this command */ - musb_set_state((musb_core_config *)cfg); - - /* Set high speed for EP0 */ - host_type0 = HCD_RD1(r, MUSB_REG_HOST_TYPE0); - HCD_CLR(host_type0, MUSB_VAL_HOST_TYPE0_MASK); - HCD_SET(host_type0, MUSB_VAL_HOST_TYPE0_HIGH_SPEED); - HCD_WR1(r, MUSB_REG_HOST_TYPE0, host_type0); - - /* Enable EP interrupt */ - intrtxe = HCD_RD2(r, MUSB_REG_INTRTXE); - HCD_SET(intrtxe, MUSB_VAL_INTRTXE_EP0); - HCD_WR2(r, MUSB_REG_INTRTXE, intrtxe); -} - - /*===========================================================================* * * * HCD interface implementation * @@ -330,15 +357,24 @@ musb_setup_device(void * cfg, hcd_reg1 ep, hcd_reg1 addr) /*===========================================================================* * musb_reset_device * *===========================================================================*/ -void -musb_reset_device(void * cfg) +int +musb_reset_device(void * cfg, hcd_speed * speed) { void * r; + musb_core_config * core; hcd_reg1 power; + hcd_reg1 host_type0; DEBUG_DUMP; - r = ((musb_core_config *)cfg)->regs; + core = (musb_core_config *)cfg; + r = core->regs; + + /* Set initial parameters */ + musb_setup_device(core, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR); + + /* Set EP and device address to be used in this command */ + musb_set_state(core); /* Write reset bit and high speed negotiation wait for at least * 20ms for reset, clear reset bit and wait for device */ @@ -346,21 +382,37 @@ musb_reset_device(void * cfg) HCD_SET(power, MUSB_VAL_POWER_RESET | MUSB_VAL_POWER_HSEN); HCD_WR1(r, MUSB_REG_POWER, power); - { - /* Sleep 25ms */ - struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(25)}; - nanosleep(&nanotm, NULL); - } + /* Sleep 25msec */ + hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(25)); power = HCD_RD1(r, MUSB_REG_POWER); HCD_CLR(power, MUSB_VAL_POWER_RESET); HCD_WR1(r, MUSB_REG_POWER, power); - { - /* Sleep 25ms */ - struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(25)}; - nanosleep(&nanotm, NULL); + /* Sleep 25msec */ + hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(25)); + + /* High speed check */ + power = HCD_RD1(r, MUSB_REG_POWER); + + if (power & MUSB_VAL_POWER_HSMODE) { + /* Set high-speed for EP0 */ + host_type0 = HCD_RD1(r, MUSB_REG_HOST_TYPE0); + HCD_CLR(host_type0, MUSB_VAL_HOST_TYPE0_MASK); + HCD_SET(host_type0, MUSB_VAL_HOST_TYPE0_HIGH_SPEED); + HCD_WR1(r, MUSB_REG_HOST_TYPE0, host_type0); + + *speed = HCD_SPEED_HIGH; + + USB_DBG("High speed USB enabled"); + } else { + /* Only full-speed supported */ + USB_DBG("High speed USB disabled"); + + *speed = HCD_SPEED_FULL; } + + return EXIT_SUCCESS; } @@ -372,19 +424,21 @@ musb_setup_stage(void * cfg, hcd_ctrlrequest * setup) { void * r; char * setup_byte; + musb_core_config * core; hcd_reg2 host_csr0; DEBUG_DUMP; - r = ((musb_core_config *)cfg)->regs; + core = (musb_core_config *)cfg; + r = core->regs; setup_byte = (char*)setup; - /* Set EP and device address to be used in this command */ - musb_set_state((musb_core_config *)cfg); + USB_ASSERT(0 == core->ep, "Only EP 0 can handle control transfers"); - /* TODO: check for ongoing transmission */ + /* Set EP and device address to be used in this command */ + musb_set_state(core); - /* Put USB setup data into corresponding FIFO */ + /* Put USB setup data into EP0 FIFO */ HCD_WR4(r, MUSB_REG_FIFO0, HCD_8TO32(&setup_byte[0])); HCD_WR4(r, MUSB_REG_FIFO0, HCD_8TO32(&setup_byte[sizeof(hcd_reg4)])); @@ -399,6 +453,180 @@ musb_setup_stage(void * cfg, hcd_ctrlrequest * setup) } +/*===========================================================================* + * musb_bulk_in_stage * + *===========================================================================*/ +void +musb_bulk_in_stage(void * cfg, hcd_bulkrequest * request) +{ + musb_core_config * core; +#if 0 + hcd_reg2 intrrxe; +#endif + hcd_reg2 host_rxcsr; + hcd_reg1 host_rxtype; + void * r; + + DEBUG_DUMP; + + core = (musb_core_config *)cfg; + r = core->regs; + + USB_ASSERT(request->max_packet_size <= 1024, "Invalid wMaxPacketSize"); + USB_ASSERT((core->ep <= 15) && (core->ep > 0), + "Invalid bulk EP supplied"); + + /* Set EP and device address to be used in this command */ + musb_set_state(core); + + /* Evaluate RXTYPE */ + host_rxtype = MUSB_VAL_HOST_XXTYPE_BULK | core->ep; + + if (HCD_SPEED_HIGH == request->speed) + host_rxtype |= MUSB_VAL_HOST_XXTYPE_HIGH_SPEED; + else + host_rxtype |= MUSB_VAL_HOST_XXTYPE_FULL_SPEED; + + /* Rewrite HOST_RXTYPE */ + HCD_WR1(r, MUSB_REG_HOST_RXTYPE, host_rxtype); + + /* Rewrite RXMAXP */ + HCD_WR2(r, MUSB_REG_RXMAXP, request->max_packet_size); + + /* Rewrite HOST_RXINTERVAL */ + HCD_WR1(r, MUSB_REG_HOST_RXINTERVAL, MUSB_VAL_HOST_XXINTERVAL_DEFAULT); + + /* Not required in some MUSB implementations */ +#if 0 + /* Enable this interrupt */ + intrrxe = HCD_RD2(r, MUSB_REG_INTRRXE); + HCD_SET(intrrxe, HCD_BIT(core->ep)); + HCD_WR2(r, MUSB_REG_INTRRXE, intrrxe); +#endif + + /* TODO: One reusable FIFO, no double buffering */ + /* TODO: With this, only one device can work at a time but it + * may be impossible to have MUSB work reasonably with multiple + * EP interrupts anyway */ + /* Assign FIFO */ + HCD_WR2(r, MUSB_REG_RXFIFOADDR, MUSB_VAL_XXFIFOADDR_EP0_END); + HCD_WR1(r, MUSB_REG_RXFIFOSZ, MUSB_VAL_XXFIFOSZ_4096); + + /* TODO: decide which is better (or working at all when we use more + * than one transfer for bulk data in single device) */ +#if 0 + /* Make controller reconfigure */ + host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR); + HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_CLRDATATOG); + HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO); + HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr); +#else + /* Reset and flush */ + host_rxcsr = 0; + HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_CLRDATATOG); + HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO); + HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr); +#endif + + /* Request packet */ + host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR); + HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_REQPKT); + HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr); +} + + +/*===========================================================================* + * musb_bulk_out_stage * + *===========================================================================*/ +void +musb_bulk_out_stage(void * cfg, hcd_bulkrequest * request) +{ + musb_core_config * core; +#if 0 + hcd_reg2 intrtxe; +#endif + hcd_reg2 host_txcsr; + hcd_reg1 host_txtype; + void * r; + + DEBUG_DUMP; + + core = (musb_core_config *)cfg; + r = core->regs; + + USB_ASSERT(request->max_packet_size <= 1024, "Invalid wMaxPacketSize"); + USB_ASSERT((core->ep <= 15) && (core->ep > 0), + "Invalid bulk EP supplied"); + + /* Set EP and device address to be used in this command */ + musb_set_state(core); + + /* Evaluate TXTYPE */ + host_txtype = MUSB_VAL_HOST_XXTYPE_BULK | core->ep; + + if (HCD_SPEED_HIGH == request->speed) + host_txtype |= MUSB_VAL_HOST_XXTYPE_HIGH_SPEED; + else + host_txtype |= MUSB_VAL_HOST_XXTYPE_FULL_SPEED; + + /* Rewrite HOST_TXTYPE */ + HCD_WR1(r, MUSB_REG_HOST_TXTYPE, host_txtype); + + /* Rewrite TXMAXP */ + HCD_WR2(r, MUSB_REG_TXMAXP, request->max_packet_size); + + /* Rewrite HOST_TXINTERVAL */ + HCD_WR1(r, MUSB_REG_HOST_TXINTERVAL, MUSB_VAL_HOST_XXINTERVAL_DEFAULT); + + /* Not required in some MUSB implementations */ +#if 0 + /* Enable this interrupt */ + intrtxe = HCD_RD2(r, MUSB_REG_INTRTXE); + HCD_SET(intrtxe, HCD_BIT(core->ep)); + HCD_WR2(r, MUSB_REG_INTRTXE, intrtxe); +#endif + + /* TODO: One reusable FIFO, no double buffering */ + /* TODO: With this, only one device can work at a time but it + * may be impossible to have MUSB work reasonably with multiple + * EP interrupts anyway */ + /* Assign FIFO */ + HCD_WR2(r, MUSB_REG_TXFIFOADDR, MUSB_VAL_XXFIFOADDR_EP0_END); + HCD_WR1(r, MUSB_REG_TXFIFOSZ, MUSB_VAL_XXFIFOSZ_4096); + + /* TODO: decide which is better (or working at all when we use more + * than one transfer for bulk data in single device) */ +#if 0 + /* Make controller reconfigure */ + host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR); + HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DMAMODE); + HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_FRCDATATOG); + HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DMAEN); + HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE); + HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_ISO); + HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_AUTOSET); + HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_CLRDATATOG); + HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO); + HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr); +#else + /* Reset and flush */ + host_txcsr = 0; + HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE); + HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_CLRDATATOG); + HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO); + HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr); +#endif + + /* Put data in FIFO */ + musb_write_fifo(cfg, request->data, request->size, core->ep); + + /* Request packet */ + host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR); + HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_TXPKTRDY); + HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr); +} + + /*===========================================================================* * musb_in_data_stage * *===========================================================================*/ @@ -435,9 +663,8 @@ musb_out_data_stage(void * cfg) /* Set EP and device address to be used in this command */ musb_set_state((musb_core_config *)cfg); - /* TODO: not needed for enumeration but will be needed later */ - ((void)cfg); - USB_MSG("NOT IMPLEMENTED"); + /* TODO: not needed for enumeration but may be needed later */ + USB_MSG("Setup packet's 'DATA OUT' stage not implemented"); } @@ -499,29 +726,29 @@ musb_out_status_stage(void * cfg) * musb_read_data * *===========================================================================*/ int -musb_read_data(void * cfg, hcd_reg1 * buffer, int buffer_num) +musb_read_data(void * cfg, hcd_reg1 * buffer, int ep_num) { - int count0; + int count; DEBUG_DUMP; /* Check if anything received at all */ - if (EXIT_SUCCESS != musb_check_rxpktrdy(cfg)) { + if (EXIT_SUCCESS != musb_check_rxpktrdy(cfg, ep_num)) { USB_MSG("RXPKTRDY not set when receiving"); return HCD_READ_ERR; } - /* Number of bytes received at EP0 */ - count0 = musb_get_count(cfg); + /* Number of bytes received at any EP */ + count = musb_get_count(cfg); /* Read from given FIFO */ - if ((NULL != buffer) && (count0 > 0)) - musb_read_fifo(cfg, buffer, count0, buffer_num); + if ((NULL != buffer) && (count > 0)) + musb_read_fifo(cfg, buffer, count, ep_num); /* Cleanup after reading */ - musb_in_stage_cleanup(cfg); + musb_in_stage_cleanup(cfg, ep_num); - return count0; + return count; } @@ -529,10 +756,10 @@ musb_read_data(void * cfg, hcd_reg1 * buffer, int buffer_num) * musb_check_error * *===========================================================================*/ int -musb_check_error(void * cfg) +musb_check_error(void * cfg, hcd_transfer transfer, hcd_direction dir) { void * r; - hcd_reg2 host_csr0; + hcd_reg2 host_csr; DEBUG_DUMP; @@ -541,30 +768,95 @@ musb_check_error(void * cfg) /* Set EP and device address to be used in this command */ musb_set_state((musb_core_config *)cfg); - /* Get control status register for EP 0 */ - host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0); + /* TODO: In MUSB only EP0 is allowed to handle control transfers + * so there is no EP checking in this function */ + if (HCD_TRANSFER_CONTROL == transfer) { + /* Get control status register */ + host_csr = HCD_RD2(r, MUSB_REG_HOST_CSR0); + + /* Check for common errors */ + if (host_csr & MUSB_VAL_HOST_CSR0_ERROR) { + USB_MSG("HOST_CSR0 ERROR: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_ERROR); + HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr); + return EXIT_FAILURE; + } + + if (host_csr & MUSB_VAL_HOST_CSR0_RXSTALL) { + USB_MSG("HOST_CSR0 STALL: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_RXSTALL); + HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr); + return EXIT_FAILURE; + } + + if (host_csr & MUSB_VAL_HOST_CSR0_NAK_TIMEOUT) { + USB_MSG("HOST_CSR0 NAK_TIMEOUT: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_NAK_TIMEOUT); + HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr); + return EXIT_FAILURE; + } - /* Check for common errors */ - if (host_csr0 & MUSB_VAL_HOST_CSR0_ERROR) { - USB_MSG("HOST_CSR0 ERROR: %04X", host_csr0); - HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_ERROR); - HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0); - return EXIT_FAILURE; + return EXIT_SUCCESS; } - if (host_csr0 & MUSB_VAL_HOST_CSR0_RXSTALL) { - USB_MSG("HOST_CSR0 STALL: %04X", host_csr0); - HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_RXSTALL); - HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0); - return EXIT_FAILURE; + if ((HCD_TRANSFER_BULK == transfer) && (HCD_DIRECTION_OUT == dir)) { + /* Get RX status register */ + host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR); + + /* Check for common errors */ + if (host_csr & MUSB_VAL_HOST_TXCSR_ERROR) { + USB_MSG("HOST_TXCSR ERROR: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_ERROR); + HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr); + return EXIT_FAILURE; + } + + if (host_csr & MUSB_VAL_HOST_TXCSR_RXSTALL) { + USB_MSG("HOST_TXCSR STALL: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_RXSTALL); + HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr); + return EXIT_FAILURE; + } + + if (host_csr & MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT) { + USB_MSG("HOST_TXCSR NAK_TIMEOUT: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT); + HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; } - if (host_csr0 & MUSB_VAL_HOST_CSR0_NAK_TIMEOUT) { - USB_MSG("HOST_CSR0 NAK_TIMEOUT: %04X", host_csr0); - HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_NAK_TIMEOUT); - HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0); - return EXIT_FAILURE; + if ((HCD_TRANSFER_BULK == transfer) && (HCD_DIRECTION_IN == dir)) { + /* Get RX status register */ + host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR); + + /* Check for common errors */ + if (host_csr & MUSB_VAL_HOST_RXCSR_ERROR) { + USB_MSG("HOST_RXCSR ERROR: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_ERROR); + HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr); + return EXIT_FAILURE; + } + + if (host_csr & MUSB_VAL_HOST_RXCSR_RXSTALL) { + USB_MSG("HOST_RXCSR STALL: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_RXSTALL); + HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr); + return EXIT_FAILURE; + } + + if (host_csr & MUSB_VAL_HOST_RXCSR_NAKTIMEOUT) { + USB_MSG("HOST_RXCSR NAK_TIMEOUT: %04X", host_csr); + HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_NAKTIMEOUT); + HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; } - return EXIT_SUCCESS; + USB_MSG("Invalid USB transfer 0x%X:0x%X", (int)transfer, (int)dir); + return EXIT_FAILURE; } diff --git a/drivers/usbd/hcd/musb/musb_core.h b/drivers/usbd/hcd/musb/musb_core.h index c85aa1848..e51f15988 100755 --- a/drivers/usbd/hcd/musb/musb_core.h +++ b/drivers/usbd/hcd/musb/musb_core.h @@ -29,19 +29,20 @@ musb_core_config; /* Only to be used outside generic HCD code */ void musb_core_start(void *); void musb_core_stop(void *); -void musb_ep0_config(void *); /* For HCD interface */ void musb_setup_device(void *, hcd_reg1, hcd_reg1); -void musb_reset_device(void *); +int musb_reset_device(void *, hcd_speed *); void musb_setup_stage(void *, hcd_ctrlrequest *); +void musb_bulk_in_stage(void *, hcd_bulkrequest *); +void musb_bulk_out_stage(void *, hcd_bulkrequest *); void musb_in_data_stage(void *); void musb_out_data_stage(void *); void musb_in_status_stage(void *); void musb_out_status_stage(void *); int musb_read_data(void *, hcd_reg1 *, int); -int musb_check_error(void *); +int musb_check_error(void *, hcd_transfer, hcd_direction); #endif /* !_MUSB_CORE_H_ */ diff --git a/drivers/usbd/hcd/musb/musb_regs.h b/drivers/usbd/hcd/musb/musb_regs.h index 15fd554d9..ad56cfce9 100755 --- a/drivers/usbd/hcd/musb/musb_regs.h +++ b/drivers/usbd/hcd/musb/musb_regs.h @@ -33,16 +33,15 @@ #define MUSB_REG_HOST_TXCSR MUSB_REG_PERI_CSR0 #define MUSB_REG_RXMAXP 0x14u #define MUSB_REG_PERI_RXCSR 0x16u -#define MUSB_REG_HOST_RXCSR MUSB_PERI_RXCSR +#define MUSB_REG_HOST_RXCSR MUSB_REG_PERI_RXCSR #define MUSB_REG_COUNT0 0x18u -#define MUSB_REG_RXCOUNT MUSB_COUNT0 +#define MUSB_REG_RXCOUNT MUSB_REG_COUNT0 #define MUSB_REG_HOST_TYPE0 0x1Au -#define MUSB_REG_HOST_TXTYPE MUSB_HOST_TYPE0 +#define MUSB_REG_HOST_TXTYPE MUSB_REG_HOST_TYPE0 #define MUSB_REG_HOST_NAKLIMIT0 0x1Bu -#define MUSB_REG_HOST_TXINTERVAL MUSB_HOST_NAKLIMIT0 +#define MUSB_REG_HOST_TXINTERVAL MUSB_REG_HOST_NAKLIMIT0 #define MUSB_REG_HOST_RXTYPE 0x1Cu #define MUSB_REG_HOST_RXINTERVAL 0x1Du -#define MUSB_REG_CONFIGDATA 0x1Fu #define MUSB_REG_FIFO0 0x20u #define MUSB_REG_FIFO1 0x24u @@ -57,12 +56,16 @@ #define MUSB_REG_TXFIFOADDR 0x64u #define MUSB_REG_RXFIFOADDR 0x66u -#define MUSB_REG_TXFUNCADDR 0x80u -#define MUSB_REG_TXHUBADDR 0x82u -#define MUSB_REG_TXHUBPORT 0x83u -#define MUSB_REG_RXFUNCADDR 0x84u -#define MUSB_REG_RXHUBADDR 0x86u -#define MUSB_REG_RXHUBPORT 0x87u +#define MUSB_REG_EP_CONFIG_BASE 0x80u +#define MUSB_REG_TXFUNCADDR 0x00u +#define MUSB_REG_TXHUBADDR 0x02u +#define MUSB_REG_TXHUBPORT 0x03u +#define MUSB_REG_RXFUNCADDR 0x04u +#define MUSB_REG_RXHUBADDR 0x06u +#define MUSB_REG_RXHUBPORT 0x07u +#define MUSB_REG_EP_CONFIG_LEN 0x08u +#define MUSB_REG_CONFIG(ep,reg) \ + (MUSB_REG_EP_CONFIG_BASE + (MUSB_REG_EP_CONFIG_LEN * (ep)) + (reg)) /*===========================================================================* @@ -123,4 +126,68 @@ #define MUSB_VAL_HOST_CSR0_NAK_TIMEOUT HCD_BIT(7) #define MUSB_VAL_HOST_CSR0_FLUSHFIFO HCD_BIT(8) +/* HOST_RXTYPE/HOST_TXTYPE */ +#define MUSB_VAL_HOST_XXTYPE_SPEED_MASK (HCD_BIT(6) | HCD_BIT(7)) +#define MUSB_VAL_HOST_XXTYPE_HIGH_SPEED HCD_BIT(6) +#define MUSB_VAL_HOST_XXTYPE_FULL_SPEED HCD_BIT(7) +#define MUSB_VAL_HOST_XXTYPE_LOW_SPEED (HCD_BIT(6) | HCD_BIT(7)) +#define MUSB_VAL_HOST_XXTYPE_PROT_MASK (HCD_BIT(4) | HCD_BIT(5)) +#define MUSB_VAL_HOST_XXTYPE_ISOCHRONOUS HCD_BIT(4) +#define MUSB_VAL_HOST_XXTYPE_BULK HCD_BIT(5) +#define MUSB_VAL_HOST_XXTYPE_INTERRUPT (HCD_BIT(4) | HCD_BIT(5)) +#define MUSB_VAL_HOST_XXTYPE_RENDPN_MASK (HCD_BIT(0) | \ + HCD_BIT(1) | \ + HCD_BIT(2) | \ + HCD_BIT(3)) + +/* HOST_RXINTERVAL/HOST_TXINTERVAL */ +/* TODO: Default NAK limit */ +#define MUSB_VAL_HOST_XXINTERVAL_DEFAULT 0x10u + +/* HOST_RXCSR */ +#define MUSB_VAL_HOST_RXCSR_RXPKTRDY HCD_BIT(0) +#define MUSB_VAL_HOST_RXCSR_FIFOFULL HCD_BIT(1) +#define MUSB_VAL_HOST_RXCSR_ERROR HCD_BIT(2) +#define MUSB_VAL_HOST_RXCSR_NAKTIMEOUT HCD_BIT(3) +#define MUSB_VAL_HOST_RXCSR_FLUSHFIFO HCD_BIT(4) +#define MUSB_VAL_HOST_RXCSR_REQPKT HCD_BIT(5) +#define MUSB_VAL_HOST_RXCSR_RXSTALL HCD_BIT(6) +#define MUSB_VAL_HOST_RXCSR_CLRDATATOG HCD_BIT(7) +#define MUSB_VAL_HOST_RXCSR_DATATOG HCD_BIT(9) +#define MUSB_VAL_HOST_RXCSR_DATATOGWREN HCD_BIT(10) +#define MUSB_VAL_HOST_RXCSR_DISNYET HCD_BIT(12) +#define MUSB_VAL_HOST_RXCSR_DMAEN HCD_BIT(13) + +/* HOST_TXCSR */ +#define MUSB_VAL_HOST_TXCSR_TXPKTRDY HCD_BIT(0) +#define MUSB_VAL_HOST_TXCSR_FIFONOTEMPTY HCD_BIT(1) +#define MUSB_VAL_HOST_TXCSR_ERROR HCD_BIT(2) +#define MUSB_VAL_HOST_TXCSR_FLUSHFIFO HCD_BIT(3) +#define MUSB_VAL_HOST_TXCSR_SETUPPKT HCD_BIT(4) +#define MUSB_VAL_HOST_TXCSR_RXSTALL HCD_BIT(5) +#define MUSB_VAL_HOST_TXCSR_CLRDATATOG HCD_BIT(6) +#define MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT HCD_BIT(7) +#define MUSB_VAL_HOST_TXCSR_DATATOG HCD_BIT(8) +#define MUSB_VAL_HOST_TXCSR_DATATOGWREN HCD_BIT(9) +#define MUSB_VAL_HOST_TXCSR_DMAMODE HCD_BIT(10) +#define MUSB_VAL_HOST_TXCSR_FRCDATATOG HCD_BIT(11) +#define MUSB_VAL_HOST_TXCSR_DMAEN HCD_BIT(12) +#define MUSB_VAL_HOST_TXCSR_MODE HCD_BIT(13) +#define MUSB_VAL_HOST_TXCSR_ISO HCD_BIT(14) +#define MUSB_VAL_HOST_TXCSR_AUTOSET HCD_BIT(15) + +/* RXFIFOADDR/TXFIFOADDR */ +#define MUSB_VAL_XXFIFOADDR_EP0_END 0x08u + +/* RXFIFOSZ/TXFIFOSZ */ +#define MUSB_VAL_XXFIFOSZ_16 0x01u +#define MUSB_VAL_XXFIFOSZ_32 0x02u +#define MUSB_VAL_XXFIFOSZ_64 0x03u +#define MUSB_VAL_XXFIFOSZ_128 0x04u +#define MUSB_VAL_XXFIFOSZ_256 0x05u +#define MUSB_VAL_XXFIFOSZ_512 0x06u +#define MUSB_VAL_XXFIFOSZ_1024 0x07u +#define MUSB_VAL_XXFIFOSZ_2048 0x08u +#define MUSB_VAL_XXFIFOSZ_4096 0x09u + #endif /* !_MUSB_REGS_H_ */ diff --git a/drivers/usbd/include/usb/hcd_common.h b/drivers/usbd/include/usb/hcd_common.h index 0bb029970..44336fc00 100755 --- a/drivers/usbd/include/usb/hcd_common.h +++ b/drivers/usbd/include/usb/hcd_common.h @@ -62,7 +62,6 @@ typedef unsigned char hcd_reg1; /*===========================================================================* * USB descriptor types * *===========================================================================*/ -typedef struct usb_ctrlrequest hcd_ctrlrequest; typedef usb_descriptor_t hcd_descriptor; typedef usb_device_descriptor_t hcd_device_descriptor; typedef usb_config_descriptor_t hcd_config_descriptor; @@ -114,13 +113,21 @@ typedef enum { } hcd_state; +typedef enum { + + HCD_SPEED_LOW, + HCD_SPEED_FULL, + HCD_SPEED_HIGH, +} +hcd_speed; + /* Largest value that can be transfered by this driver at a time * see MAXPAYLOAD in TXMAXP/RXMAXP */ #define MAX_WTOTALLENGTH 1024 typedef struct hcd_device_state { - hcd_driver_state * driver; + hcd_driver_state * driver; /* Specific HCD driver object */ hcd_thread * thread; hcd_lock * lock; hcd_urb * urb; @@ -129,11 +136,13 @@ typedef struct hcd_device_state { hcd_device_descriptor device_desc; hcd_configuration config_tree; hcd_reg1 max_packet_size; - + hcd_speed speed; hcd_state state; + int address; /* Number of bytes received/transmitted in last transfer */ int data_len; + /* TODO: forcefully align buffer to make things clear? */ /* Buffer for each device to hold transfered data */ hcd_reg1 buffer[MAX_WTOTALLENGTH]; @@ -141,12 +150,68 @@ typedef struct hcd_device_state { hcd_device_state; +/*===========================================================================* + * HCD transfer requests * + *===========================================================================*/ +struct hcd_bulkrequest { + + char * data; + int size; + int endpoint; + unsigned int max_packet_size; + hcd_speed speed; +}; + +typedef struct usb_ctrlrequest hcd_ctrlrequest; +typedef struct hcd_bulkrequest hcd_bulkrequest; + + +/*===========================================================================* + * HCD event handling * + *===========================================================================*/ +/* Possible USB transfer types */ +typedef enum { + + HCD_TRANSFER_CONTROL = UE_CONTROL, + HCD_TRANSFER_ISOCHRONOUS = UE_ISOCHRONOUS, + HCD_TRANSFER_BULK = UE_BULK, + HCD_TRANSFER_INTERRUPT = UE_INTERRUPT +} +hcd_transfer; + +/* Possible USB transfer directions */ +typedef enum { + + HCD_DIRECTION_OUT = 0, + HCD_DIRECTION_IN = 1, + HCD_DIRECTION_UNUSED = 0xFF +} +hcd_direction; + +/* Possible asynchronous HCD events */ +typedef enum { + + HCD_EVENT_CONNECTED, + HCD_EVENT_DISCONNECTED, + HCD_EVENT_ENDPOINT, + HCD_EVENT_URB +} +hcd_event; + +/* EP event constants */ +#define HCD_NO_ENDPOINT -1 +#define HCD_ENDPOINT_0 0 + + /*===========================================================================* * Other definitions * *===========================================================================*/ -#define HCD_NANOSLEEP_SEC(sec) ((sec) * 1000000000) -#define HCD_NANOSLEEP_MSEC(msec) ((msec) * 1000000) -#define HCD_NANOSLEEP_USEC(usec) ((usec) * 1000) +#define HCD_MILI 1000 +#define HCD_MICRO 1000000 +#define HCD_NANO 1000000000 +#define HCD_NANOSLEEP_SEC(sec) ((sec) * HCD_NANO) +#define HCD_NANOSLEEP_MSEC(msec) ((msec) * HCD_MICRO) +#define HCD_NANOSLEEP_USEC(usec) ((usec) * HCD_MILI) /* Default USB communication parameters */ #define HCD_DEFAULT_EP 0x00 @@ -184,6 +249,9 @@ int hcd_os_clkconf(unsigned long, unsigned long, unsigned long); /* Release clocking */ int hcd_os_clkconf_release(void); +/* OS's sleep wrapper */ +void hcd_os_nanosleep(int); + /*===========================================================================* * Device handling calls * @@ -195,7 +263,7 @@ int hcd_connect_device(hcd_device_state *, hcd_thread_function); void hcd_disconnect_device(hcd_device_state *); /* Locks device thread until 'hcd_device_continue' */ -void hcd_device_wait(hcd_device_state *); +void hcd_device_wait(hcd_device_state *, hcd_event, int); /* Unlocks device thread halted by 'hcd_device_wait' */ void hcd_device_continue(hcd_device_state *); @@ -210,5 +278,8 @@ int hcd_buffer_to_tree(hcd_reg1 *, int, hcd_configuration *); /* Frees descriptor tree */ void hcd_tree_cleanup(hcd_configuration *); +/* Find EP in a tree */ +hcd_endpoint * hcd_tree_find_ep(hcd_configuration *, int); + #endif /* !_HCD_COMMON_H_ */ diff --git a/drivers/usbd/include/usb/hcd_interface.h b/drivers/usbd/include/usb/hcd_interface.h index 20ee3babe..c59d6e62f 100755 --- a/drivers/usbd/include/usb/hcd_interface.h +++ b/drivers/usbd/include/usb/hcd_interface.h @@ -11,30 +11,10 @@ #include -/*===========================================================================* - * HCD event handling types * - *===========================================================================*/ -/* Possible HCD events */ -typedef enum { - - HCD_EVENT_CONNECTED, - HCD_EVENT_DISCONNECTED, - HCD_EVENT_ENDPOINT -} -hcd_event; - -/* Possible HCD sub-events */ -typedef enum { - - HCD_SUBEVENT_NONE, - HCD_SUBEVENT_EP0, -} -hcd_subevent; - - /*===========================================================================* * HCD additional defines * *===========================================================================*/ +/* Can be returned by 'read_data' to indicate error */ #define HCD_READ_ERR -1 @@ -43,22 +23,26 @@ hcd_subevent; *===========================================================================*/ struct hcd_driver_state { /* Standard USB controller procedures */ - void (*setup_device) (void *, hcd_reg1, hcd_reg1); - void (*reset_device) (void *); - void (*setup_stage) (void *, hcd_ctrlrequest *); - void (*in_data_stage) (void *); - void (*out_data_stage) (void *); - void (*in_status_stage) (void *); - void (*out_status_stage) (void *); - int (*read_data) (void *, hcd_reg1 *, int); - int (*check_error) (void *); + void (*setup_device) (void *, hcd_reg1, hcd_reg1); + int (*reset_device) (void *, hcd_speed *); + void (*setup_stage) (void *, hcd_ctrlrequest *); + void (*bulk_in_stage) (void *, hcd_bulkrequest *); + void (*bulk_out_stage) (void *, hcd_bulkrequest *); + void (*in_data_stage) (void *); + void (*out_data_stage) (void *); + void (*in_status_stage) (void *); + void (*out_status_stage) (void *); + int (*read_data) (void *, hcd_reg1 *, int); + int (*check_error) (void *, hcd_transfer, hcd_direction); /* Controller's private data (like mapped registers) */ void * private_data; /* Current state to be handled by driver */ - hcd_event event; - hcd_subevent subevent; + hcd_event current_event; + int current_endpoint; + hcd_event expected_event; + int expected_endpoint; };