From fde0bf650e6313a627bf32c582de590a70f67835 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 21 Apr 2015 12:17:49 -0600 Subject: [PATCH] USB host: Integrate logic to assign device function address --- arch/arm/src/sama5/sam_ehci.c | 38 ++-- arch/arm/src/sama5/sam_ohci.c | 64 +++--- drivers/usbhost/usbhost_devaddr.c | 292 ++++++++++++++-------------- drivers/usbhost/usbhost_enumerate.c | 13 +- drivers/usbhost/usbhost_hidkbd.c | 8 +- drivers/usbhost/usbhost_hidmouse.c | 8 +- drivers/usbhost/usbhost_hub.c | 53 +---- drivers/usbhost/usbhost_skeleton.c | 12 +- drivers/usbhost/usbhost_storage.c | 9 +- include/nuttx/usb/usbhost.h | 29 ++- include/nuttx/usb/usbhost_devaddr.h | 70 +++---- 11 files changed, 312 insertions(+), 284 deletions(-) diff --git a/arch/arm/src/sama5/sam_ehci.c b/arch/arm/src/sama5/sam_ehci.c index 0db99b0fd54..b943e535a7b 100644 --- a/arch/arm/src/sama5/sam_ehci.c +++ b/arch/arm/src/sama5/sam_ehci.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include "up_arch.h" @@ -146,6 +147,11 @@ #define FRAME_LIST_SIZE 1024 +/* Port numbers */ + +#define RHPNDX(rh) ((rh)->hport.hport.port) +#define RHPORT(rh) (RHPNDX(rh)+1) + /******************************************************************************* * Private Types *******************************************************************************/ @@ -228,7 +234,7 @@ struct sam_rhport_s /* This is the hub port description understood by class drivers */ - struct usbhost_hubport_s hport; + struct usbhost_roothubport_s hport; /* The bound device class driver */ @@ -1492,7 +1498,7 @@ static struct sam_qh_s *sam_qh_create(struct sam_rhport_s *rhport, * and HUB device address to be included here. */ - rhpndx = rhport->hport.port; + rhpndx = RHPNDX(rhport); regval = ((uint32_t)0 << QH_EPCAPS_HUBADDR_SHIFT) | ((uint32_t)(rhpndx + 1) << QH_EPCAPS_PORT_SHIFT) | ((uint32_t)1 << QH_EPCAPS_MULT_SHIFT); @@ -1839,7 +1845,7 @@ static ssize_t sam_async_transfer(struct sam_rhport_s *rhport, usbhost_vtrace2(EHCI_VTRACE2_ASYNCXFR, epinfo->epno, buflen); #else uvdbg("RHport%d EP%d: buffer=%p, buflen=%d, req=%p\n", - rhport->hport.port+1, epinfo->epno, buffer, buflen, req); + RHPORT(rhport), epinfo->epno, buffer, buflen, req); #endif DEBUGASSERT(rhport && epinfo); @@ -2198,7 +2204,7 @@ static ssize_t sam_intr_transfer(struct sam_rhport_s *rhport, usbhost_vtrace2(EHCI_VTRACE2_INTRXFR, epinfo->epno, buflen); #else uvdbg("RHport%d EP%d: buffer=%p, buflen=%d\n", - rhport->hport.port+1, epinfo->epno, buffer, buflen); + RHPORT(rhport), epinfo->epno, buffer, buflen); #endif DEBUGASSERT(rhport && epinfo && buffer && buflen > 0); @@ -3192,7 +3198,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) * write a zero to the Port Enable bit." */ - regaddr = &HCOR->portsc[rhport->hport.port]; + regaddr = &HCOR->portsc[RHPNDX(rhport)]; regval = sam_getreg(regaddr); regval &= ~EHCI_PORTSC_PE; regval |= EHCI_PORTSC_RESET; @@ -3294,7 +3300,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) */ usbhost_vtrace2(EHCI_VTRACE2_CLASSENUM, rhpndx+1, rhpndx+1); - ret = usbhost_enumerate(&g_ehci.rhport[rhpndx].hport, &rhport->class); + ret = usbhost_enumerate(&g_ehci.rhport[rhpndx].hport.hport, &rhport->class); if (ret < 0) { usbhost_trace2(EHCI_TRACE2_CLASSENUM_FAILED, rhpndx+1, -ret); @@ -3670,10 +3676,10 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* Terse output only if we are tracing */ #ifdef CONFIG_USBHOST_TRACE - usbhost_vtrace2(EHCI_VTRACE2_CTRLINOUT, rhport->hport.port + 1, req->req); + usbhost_vtrace2(EHCI_VTRACE2_CTRLINOUT, RHPORT(rhport), req->req); #else uvdbg("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %04x\n", - rhport->hport.port + 1, req->type, req->req, req->value[1], req->value[0], + RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], len); #endif @@ -3959,6 +3965,7 @@ static int sam_reset(void) FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) { + FAR struct usbhost_hubport_s *hport; irqstate_t flags; uint32_t regval; #if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE) @@ -4087,13 +4094,18 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) /* Initialize the public port representation */ - rhport->hport.drvr = &rhport->drvr; + hport = &rhport->hport.hport; + hport->drvr = &rhport->drvr; #ifdef CONFIG_USBHOST_HUB - rhport->hport.parent = NULL; + hport->parent = NULL; #endif - rhport->hport.ep0 = &rhport->ep0; - rhport->hport.port = i; - rhport->hport.speed = USB_SPEED_FULL; + hport->ep0 = &rhport->ep0; + hport->port = i; + hport->speed = USB_SPEED_FULL; + + /* Initialize function address generation logic */ + + usbhost_devaddr_initialize(&rhport->hport); } #ifndef CONFIG_SAMA5_EHCI_PREALLOCATE diff --git a/arch/arm/src/sama5/sam_ohci.c b/arch/arm/src/sama5/sam_ohci.c index 0c393f27eae..be725ce6fed 100644 --- a/arch/arm/src/sama5/sam_ohci.c +++ b/arch/arm/src/sama5/sam_ohci.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -189,6 +190,11 @@ #define TD_DELAY(n) (uint32_t)((n) << GTD_STATUS_DI_SHIFT) +/* Port numbers */ + +#define RHPNDX(rh) ((rh)->hport.hport.port) +#define RHPORT(rh) (RHPNDX(rh)+1) + /******************************************************************************* * Private Types *******************************************************************************/ @@ -228,7 +234,7 @@ struct sam_rhport_s /* This is the hub port description understood by class drivers */ - struct usbhost_hubport_s hport; + struct usbhost_roothubport_s hport; /* The bound device class driver */ @@ -1643,7 +1649,7 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist, ret = sam_wdhwait(rhport, edctrl); if (ret != OK) { - usbhost_trace1(OHCI_TRACE1_DEVDISCONN, rhport->hport.port + 1); + usbhost_trace1(OHCI_TRACE1_DEVDISCONN, RHPORT(rhport)); return ret; } @@ -1707,7 +1713,7 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist, } else { - usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, rhport->hport.port + 1, + usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, RHPORT(rhport), edctrl->tdstatus); ret = -EIO; } @@ -1797,14 +1803,14 @@ static void sam_rhsc_bottomhalf(void) if ((rhportst & OHCI_RHPORTST_LSDA) != 0) { - rhport->hport.speed = USB_SPEED_LOW; + rhport->hport.hport.speed = USB_SPEED_LOW; } else { - rhport->hport.speed = USB_SPEED_FULL; + rhport->hport.hport.speed = USB_SPEED_FULL; } - usbhost_vtrace1(OHCI_VTRACE1_SPEED, rhport->hport.speed); + usbhost_vtrace1(OHCI_VTRACE1_SPEED, rhport->hport.hport.speed); } /* Check if we are now disconnected */ @@ -1817,7 +1823,7 @@ static void sam_rhsc_bottomhalf(void) rhpndx + 1, g_ohci.rhswait); rhport->connected = false; - rhport->hport.speed = USB_SPEED_FULL; + rhport->hport.hport.speed = USB_SPEED_FULL; /* Are we bound to a class instance? */ @@ -2170,7 +2176,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) { /* No, return an error */ - usbhost_vtrace1(OHCI_VTRACE1_ENUMDISCONN, rhport->hport.port + 1); + usbhost_vtrace1(OHCI_VTRACE1_ENUMDISCONN, RHPORT(rhport)); return -ENODEV; } @@ -2181,7 +2187,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) ret = sam_ep0enqueue(rhport); if (ret < 0) { - usbhost_trace2(OHCI_TRACE2_EP0ENQUEUE_FAILED, rhport->hport.port + 1, + usbhost_trace2(OHCI_TRACE2_EP0ENQUEUE_FAILED, RHPORT(rhport), -ret); return ret; } @@ -2216,7 +2222,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) */ usbhost_vtrace2(OHCI_VTRACE2_CLASSENUM, rhpndx+1, rhpndx+1); - ret = usbhost_enumerate(&g_ohci.rhport[rhpndx].hport, &rhport->class); + ret = usbhost_enumerate(&g_ohci.rhport[rhpndx].hport.hport, &rhport->class); if (ret < 0) { usbhost_trace2(OHCI_TRACE2_CLASSENUM_FAILED, rhpndx+1, -ret); @@ -2271,7 +2277,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, edctrl->hw.ctrl = (uint32_t)funcaddr << ED_CONTROL_FA_SHIFT | (uint32_t)maxpacketsize << ED_CONTROL_MPS_SHIFT; - if (rhport->hport.speed == USB_SPEED_LOW) + if (rhport->hport.hport.speed == USB_SPEED_LOW) { edctrl->hw.ctrl |= ED_CONTROL_S; } @@ -2287,7 +2293,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, sam_givesem(&g_ohci.exclsem); usbhost_vtrace2(OHCI_VTRACE2_EP0CONFIGURE, - rhport->hport.port + 1, (uint16_t)edctrl->hw.ctrl); + RHPORT(rhport), (uint16_t)edctrl->hw.ctrl); return OK; } @@ -2394,7 +2400,7 @@ static int sam_epalloc(FAR struct usbhost_driver_s *drvr, /* Check for a low-speed device */ - if (rhport->hport.speed == USB_SPEED_LOW) + if (rhport->hport.hport.speed == USB_SPEED_LOW) { ed->hw.ctrl |= ED_CONTROL_S; } @@ -2766,10 +2772,10 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, DEBUGASSERT(rhport != NULL && eplist != NULL && req != NULL); #ifdef CONFIG_USBHOST_TRACE - usbhost_vtrace2(OHCI_VTRACE2_CTRLIN, rhport->hport.port + 1, req->req); + usbhost_vtrace2(OHCI_VTRACE2_CTRLIN, RHPORT(rhport), req->req); #else uvdbg("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %02x%02x\n", - rhport->hport.port + 1, req->type, req->req, req->value[1], + RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], req->len[1], req->len[0]); #endif @@ -2815,10 +2821,10 @@ static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, DEBUGASSERT(rhport != NULL && eplist != NULL && req != NULL); #ifdef CONFIG_USBHOST_TRACE - usbhost_vtrace2(OHCI_VTRACE2_CTRLOUT, rhport->hport.port + 1, req->req); + usbhost_vtrace2(OHCI_VTRACE2_CTRLOUT, RHPORT(rhport), req->req); #else uvdbg("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %02x%02x\n", - rhport->hport.port + 1, req->type, req->req, req->value[1], + RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], req->len[1], req->len[0]); #endif @@ -2929,7 +2935,7 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, ret = sam_wdhwait(rhport, ed); if (ret != OK) { - usbhost_trace1(OHCI_TRACE1_DEVDISCONN, rhport->hport.port + 1); + usbhost_trace1(OHCI_TRACE1_DEVDISCONN, RHPORT(rhport)); goto errout; } @@ -3012,7 +3018,7 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, } else { - usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, rhport->hport.port + 1, + usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, RHPORT(rhport), ed->tdstatus); ret = ed->tdstatus == TD_CC_STALL ? -EPERM : -EIO; } @@ -3095,6 +3101,7 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr) FAR struct usbhost_connection_s *sam_ohci_initialize(int controller) { + FAR struct usbhost_hubport_s *hport; uintptr_t physaddr; uint32_t regval; uint8_t *buffer; @@ -3218,6 +3225,8 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller) { struct sam_rhport_s *rhport = &g_ohci.rhport[i]; + /* Initialize the device operations */ + rhport->drvr.ep0configure = sam_ep0configure; rhport->drvr.epalloc = sam_epalloc; rhport->drvr.epfree = sam_epfree; @@ -3230,13 +3239,20 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller) rhport->drvr.transfer = sam_transfer; rhport->drvr.disconnect = sam_disconnect; - rhport->hport.drvr = &rhport->drvr; + /* Initialize the public port representation */ + + hport = &rhport->hport.hport; + hport->drvr = &rhport->drvr; #ifdef CONFIG_USBHOST_HUB - rhport->hport.parent = NULL; + hport->parent = NULL; #endif - rhport->hport.ep0 = &rhport->ep0; - rhport->hport.port = i; - rhport->hport.speed = USB_SPEED_FULL; + hport->ep0 = &rhport->ep0; + hport->port = i; + hport->speed = USB_SPEED_FULL; + + /* Initialize function address generation logic */ + + usbhost_devaddr_initialize(&rhport->hport); } /* Wait 50MS then perform hardware reset */ diff --git a/drivers/usbhost/usbhost_devaddr.c b/drivers/usbhost/usbhost_devaddr.c index eb121c2ee94..8a3c4d8fc4b 100644 --- a/drivers/usbhost/usbhost_devaddr.c +++ b/drivers/usbhost/usbhost_devaddr.c @@ -2,7 +2,7 @@ * drivers/usbhost/usbhost_devaddr.c * Manage USB device addresses * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2013, 2015 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include #include +#include #include /******************************************************************************* @@ -64,11 +65,11 @@ * *******************************************************************************/ -static void usbhost_takesem(FAR struct usbhost_devaddr_s *hcd) +static void usbhost_takesem(FAR struct usbhost_devaddr_s *devgen) { /* Take the semaphore (perhaps waiting) */ - while (sem_wait(&hcd->exclsem) != 0) + while (sem_wait(&devgen->exclsem) != 0) { /* The only case that an error should occur here is if the wait was * awakened by a signal. @@ -78,39 +79,22 @@ static void usbhost_takesem(FAR struct usbhost_devaddr_s *hcd) } } -#define usbhost_givesem(hcd) sem_post(&hcd->exclsem) - -/******************************************************************************* - * Name: usbhost_devaddr_hash - * - * Description: - * Create a hash value from a device address. - * - *******************************************************************************/ - -static inline uint8_t usbhost_devaddr_hash(uint8_t devaddr) -{ - uint8_t ret = devaddr; - - ret ^= (devaddr >> 2); - ret ^= (devaddr >> 3); - return ret & USBHOST_DEVADDR_HASHMASK; -} +#define usbhost_givesem(devgen) sem_post(&devgen->exclsem) /******************************************************************************* * Name: usbhost_devaddr_allocate * * Description: - * Allocate a new unique device address for this HCD. + * Allocate a new unique device address. * * Assumptions: * Caller hold the exclsem * *******************************************************************************/ -static int usbhost_devaddr_allocate(FAR struct usbhost_devaddr_s *hcd) +static int usbhost_devaddr_allocate(FAR struct usbhost_devaddr_s *devgen) { - uint8_t startaddr = hcd->next; + uint8_t startaddr = devgen->next; uint8_t devaddr; int index; int bitno; @@ -121,25 +105,25 @@ static int usbhost_devaddr_allocate(FAR struct usbhost_devaddr_s *hcd) { /* Try the next device address */ - devaddr = hcd->next; - if (hcd->next >= 0x7f) + devaddr = devgen->next; + if (devgen->next >= 0x7f) { - hcd->next = 1; + devgen->next = 1; } else { - hcd->next++; + devgen->next++; } /* Is this address already allocated? */ index = devaddr >> 5; bitno = devaddr & 0x1f; - if ((hcd->alloctab[index] & (1 << bitno)) == 0) + if ((devgen->alloctab[index] & (1 << bitno)) == 0) { /* No... allocate it now */ - hcd->alloctab[index] |= (1 << bitno); + devgen->alloctab[index] |= (1 << bitno); return (int)devaddr; } @@ -156,6 +140,74 @@ static int usbhost_devaddr_allocate(FAR struct usbhost_devaddr_s *hcd) } } +/******************************************************************************* + * Name: usbhost_devaddr_free + * + * Description: + * De-allocate a device address. + * + * Assumptions: + * Caller hold the exclsem + * + *******************************************************************************/ + +static void usbhost_devaddr_free(FAR struct usbhost_devaddr_s *devgen, + uint8_t devaddr) +{ + int index; + int bitno; + + /* Free the address by clearing the associated bit in the alloctab[]; */ + + index = devaddr >> 5; + bitno = devaddr & 0x1f; + + DEBUGASSERT((devgen->alloctab[index] |= (1 << bitno)) != 0); + devgen->alloctab[index] &= ~(1 << bitno); +} + +/******************************************************************************* + * Name: usbhost_roothubport + * + * Description: + * Find and return a reference the root hub port. + * + *******************************************************************************/ + +static inline FAR struct usbhost_roothubport_s * +usbhost_roothubport(FAR struct usbhost_hubport_s *hport) +{ + while (hport->parent != NULL) + { + hport = hport->parent; + } + + return (FAR struct usbhost_roothubport_s *)hport; +} + +/******************************************************************************* + * Name: usbhost_devaddr_gen + * + * Description: + * Find root hub port and return a reference to the device function address + * data set. + * + *******************************************************************************/ + +static FAR struct usbhost_devaddr_s * +usbhost_devaddr_gen(FAR struct usbhost_hubport_s *hport) +{ + FAR struct usbhost_roothubport_s *rhport; + + rhport = usbhost_roothubport(hport); + if (rhport != NULL) + { + return &rhport->devgen; + } + + return NULL; +} + /******************************************************************************* * Public Functions *******************************************************************************/ @@ -165,169 +217,113 @@ static int usbhost_devaddr_allocate(FAR struct usbhost_devaddr_s *hcd) * * Description: * Initialize the caller provided struct usbhost_devaddr_s instance in - * preparation for the management of device addresses on behalf of an HCD. + * preparation for the management of device addresses on behalf of an root + * hub port. + * + * Input Parameters: + * rhport - A reference to a roothubport structure. + * + * Returned Value: + * None * *******************************************************************************/ -void usbhost_devaddr_initialize(FAR struct usbhost_devaddr_s *hcd) +void usbhost_devaddr_initialize(FAR struct usbhost_roothubport_s *rhport) { - DEBUGASSERT(hcd); + FAR struct usbhost_devaddr_s *devgen; - memset(hcd, 0, sizeof(struct usbhost_devaddr_s)); - sem_init(&hcd->exclsem, 0, 1); - hcd->next = 1; + DEBUGASSERT(rhport); + devgen = &rhport->devgen; + + memset(devgen, 0, sizeof(struct usbhost_devaddr_s)); + sem_init(&devgen->exclsem, 0, 1); + devgen->next = 1; } /******************************************************************************* * Name: usbhost_devaddr_create * * Description: - * Create a new unique device address for this HCD. Bind the void* arg to the - * the device address and return the newly allocated device address. + * Create a new unique device address for this hub port. + * + * Input Parameters: + * hport - A reference to a hub port structure to which a device has been + * newly connected and so is in need of a function address. + * + * Returned Value: + * Zero on success; a negated errno value is returned on failure. * *******************************************************************************/ -int usbhost_devaddr_create(FAR struct usbhost_devaddr_s *hcd, - FAR void *associate) +int usbhost_devaddr_create(FAR struct usbhost_hubport_s *hport) { - FAR struct usbhost_devhash_s *hentry; - uint8_t hvalue; + FAR struct usbhost_devaddr_s *devgen; int devaddr; - /* Allocate a hash table entry */ + /* Get the address generation data from the root hub port */ - hentry = (FAR struct usbhost_devhash_s *)kmm_malloc(sizeof(struct usbhost_devhash_s)); - if (!hentry) - { - udbg("ERROR: Failed to allocate a hash table entry\n"); - return -ENOMEM; - } + DEBUGASSERT(hport); + devgen = usbhost_devaddr_gen(hport); + DEBUGASSERT(devgen); - /* Get exclusive access to the HCD device address data */ + /* Get exclusive access to the root hub port device address data */ - usbhost_takesem(hcd); + usbhost_takesem(devgen); /* Allocate a device address */ - devaddr = usbhost_devaddr_allocate(hcd); + devaddr = usbhost_devaddr_allocate(devgen); + usbhost_givesem(devgen); + if (devaddr < 0) { udbg("ERROR: Failed to allocate a device address\n"); - free(hentry); - } - else - { - /* Initialize the hash table entry */ - - hentry->devaddr = devaddr; - hentry->payload = associate; - - /* Add the new device address to the hash table */ - - hvalue = usbhost_devaddr_hash(devaddr); - hentry->flink = hcd->hashtab[hvalue]; - hcd->hashtab[hvalue] = hentry; - - /* Try to re-use the lowest numbered device addresses */ - - if (hcd->next > devaddr) - { - hcd->next = devaddr; - } + return devaddr; } - usbhost_givesem(hcd); - return devaddr; -} + /* Set the function address in the hub port structure */ -/******************************************************************************* - * Name: usbhost_devaddr_find - * - * Description: - * Given a device address, find the void* value that was bound to the device - * address by usbhost_devaddr_create() when the device address was allocated. - * - *******************************************************************************/ - -FAR void *usbhost_devaddr_find(FAR struct usbhost_devaddr_s *hcd, - uint8_t devaddr) -{ - FAR struct usbhost_devhash_s *hentry; - uint8_t hvalue; - - /* Get exclusive access to the HCD device address data */ - - hvalue = usbhost_devaddr_hash(devaddr); - usbhost_takesem(hcd); - - /* Check each entry in the hash table */ - - for (hentry = hcd->hashtab[hvalue]; hentry; hentry = hentry->flink) - { - /* Is this the address we are looking for? */ - - if (hentry->devaddr == devaddr) - { - /* Yes.. return the payload from the hash table entry */ - - usbhost_givesem(hcd); - return hentry->payload; - } - } - - /* Didn't find the device address */ - - usbhost_givesem(hcd); - return NULL; + hport->funcaddr = devaddr; + return OK; } /******************************************************************************* * Name: usbhost_devaddr_destroy * * Description: - * Release a device address previously allocated by usbhost_devaddr_destroy() - * and destroy the association with the void* data. + * Release a device address previously assigned to a hub port by + * usbhost_devaddr_create(). + * + * Input Parameters: + * hport - A reference to a hub port structure from which a device has been + * disconnected and so no longer needs the function address. + * + * Returned Value: + * None * *******************************************************************************/ -void usbhost_devaddr_destroy(FAR struct usbhost_devaddr_s *hcd, uint8_t devaddr) +void usbhost_devaddr_destroy(FAR struct usbhost_hubport_s *hport) { - FAR struct usbhost_devhash_s *hentry; - FAR struct usbhost_devhash_s *prev; - uint8_t hvalue; + FAR struct usbhost_devaddr_s *devgen; - /* Get exclusive access to the HCD device address data */ + /* Ignore bad device address */ - hvalue = usbhost_devaddr_hash(devaddr); - usbhost_takesem(hcd); - - /* Search the hast table for the matching entry */ - - for (hentry = hcd->hashtab[hvalue], prev = NULL; - hentry; - prev = hentry, hentry = hentry->flink) + if (hport->funcaddr > 0 && hport->funcaddr < 0x7f) { - /* Is this the address we are looking for? */ + /* Get the address generation data from the root hub port */ - if (hentry->devaddr == devaddr) - { - /* Yes.. remove the entry from the hash list */ + DEBUGASSERT(hport); + devgen = usbhost_devaddr_gen(hport); + DEBUGASSERT(devgen); - if (prev) - { - prev->flink = hentry->flink; - } - else - { - hcd->hashtab[hvalue] = hentry->flink; - } + /* Get exclusive access to the root hub port device address data */ - /* And release the entry */ + usbhost_takesem(devgen); - kmm_free(hentry); - break; - } + /* Free the device address */ + + usbhost_devaddr_free(devgen, hport->funcaddr); + usbhost_givesem(devgen); } - - usbhost_givesem(hcd); } diff --git a/drivers/usbhost/usbhost_enumerate.c b/drivers/usbhost/usbhost_enumerate.c index 502a333d816..56d84f96563 100644 --- a/drivers/usbhost/usbhost_enumerate.c +++ b/drivers/usbhost/usbhost_enumerate.c @@ -51,6 +51,7 @@ #include #include #include +#include /******************************************************************************* * Pre-processor Definitions @@ -313,7 +314,7 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport, uint8_t maxpacketsize; uint8_t descsize; FAR uint8_t *buffer = NULL; - int ret; + int ret; DEBUGASSERT(hport != NULL && hport->drvr != NULL); @@ -520,6 +521,15 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport, usleep(100*1000); + /* Assign a function address to the device connected to this port */ + + ret = usbhost_devaddr_create(hport); + if (ret < 0) + { + udbg("ERROR: Failed to allocate device address: %d\n", ret); + goto errout; + } + /* Parse the configuration descriptor and bind to the class instance for the * device. This needs to be the last thing done because the class driver * will begin configuring the device. @@ -529,6 +539,7 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport, if (ret != OK) { udbg("ERROR: usbhost_classbind returned %d\n", ret); + usbhost_devaddr_destroy(hport); } errout: diff --git a/drivers/usbhost/usbhost_hidkbd.c b/drivers/usbhost/usbhost_hidkbd.c index 25f87e68440..125dea683c8 100644 --- a/drivers/usbhost/usbhost_hidkbd.c +++ b/drivers/usbhost/usbhost_hidkbd.c @@ -61,6 +61,7 @@ #include #include #include +#include #ifdef CONFIG_HIDKBD_ENCODED # include @@ -1936,8 +1937,10 @@ static int usbhost_connect(FAR struct usbhost_class_s *usbclass, static int usbhost_disconnected(struct usbhost_class_s *usbclass) { FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)usbclass; + FAR struct usbhost_hubport_s *hport; - DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL); + hport = priv->usbclass.hport; /* Set an indication to any users of the keyboard device that the device * is no longer available. @@ -1986,6 +1989,9 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass) (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0); } + /* Free the function address assigned to this device */ + + usbhost_devaddr_destroy(hport); return OK; } diff --git a/drivers/usbhost/usbhost_hidmouse.c b/drivers/usbhost/usbhost_hidmouse.c index ef81def7563..0e74b1f3696 100644 --- a/drivers/usbhost/usbhost_hidmouse.c +++ b/drivers/usbhost/usbhost_hidmouse.c @@ -58,6 +58,7 @@ #include #include #include +#include #ifdef CONFIG_HIDMOUSE_TSCIF # include @@ -2015,9 +2016,11 @@ static int usbhost_connect(FAR struct usbhost_class_s *usbclass, static int usbhost_disconnected(struct usbhost_class_s *usbclass) { FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)usbclass; + FAR struct usbhost_hubport_s *hport; int i; - DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL); + hport = priv->usbclass.hport; /* Set an indication to any users of the mouse device that the device * is no longer available. @@ -2065,6 +2068,9 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass) (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0); } + /* Free the function address assigned to this device */ + + usbhost_devaddr_destroy(hport); return OK; } diff --git a/drivers/usbhost/usbhost_hub.c b/drivers/usbhost/usbhost_hub.c index e1c3542e447..211e7833e37 100644 --- a/drivers/usbhost/usbhost_hub.c +++ b/drivers/usbhost/usbhost_hub.c @@ -57,6 +57,7 @@ #include #include #include +#include #ifdef CONFIG_USBHOST_HUB @@ -125,8 +126,6 @@ struct usbhost_hubclass_s /* Memory allocation services */ -static inline uint8_t usbhost_allocaddr(void); -static inline void usbhost_freeaddr(uint8_t addr); static inline FAR struct usbhost_hubport_s *usbhost_allochub( FAR struct usbhost_driver_s *drvr, FAR struct usbhost_class_s *hubclass, uint8_t speed, @@ -192,55 +191,10 @@ static struct usbhost_registry_s g_hub = &g_id /* id[] */ }; -/* Each bit indicates if corresponding bit number - * is allocated as usb address - */ - -static uint32_t g_addrmap[4]; - /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: usbhost_allocaddr - * - * Description: - * This is just a wrapper to handle the annoying behavior of semaphore - * waits that return due to the receipt of a signal. - * - ****************************************************************************/ - -static inline uint8_t usbhost_allocaddr(void) -{ - uint8_t addr; - - for (addr = 0; addr < 128; addr++) - { - if (!(g_addrmap[addr/32] & (0x1 << (addr % 32)))) - { - break; - } - } - - return (addr + 1); -} - -/**************************************************************************** - * Name: usbhost_freecaddr - * - * Description: - * This is just a wrapper to handle the annoying behavior of semaphore - * waits that return due to the receipt of a signal. - * - ****************************************************************************/ - -static inline void usbhost_freeaddr(uint8_t addr) -{ - addr--; - g_addrmap[addr/32] &= (~(0x1 << (addr % 32))); -} - /**************************************************************************** * Name: usbhost_allochub * @@ -288,7 +242,7 @@ static inline FAR struct usbhost_hubport_s * child->drvr = drvr; child->parent = parent; - child->funcaddr = usbhost_allocaddr(); + child->funcaddr = 0; child->speed = speed; epdesc.hport = child; @@ -334,7 +288,8 @@ static inline void usbhost_freehub(FAR struct usbhost_hubport_s *hport) hport->ep0 = NULL; } - usbhost_freeaddr(hport->funcaddr); + usbhost_devaddr_destroy(hport); + hport->funcaddr = 0; /* Free the hport instance */ diff --git a/drivers/usbhost/usbhost_skeleton.c b/drivers/usbhost/usbhost_skeleton.c index 73e41d172ba..55667e574a8 100644 --- a/drivers/usbhost/usbhost_skeleton.c +++ b/drivers/usbhost/usbhost_skeleton.c @@ -347,11 +347,15 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, static void usbhost_destroy(FAR void *arg) { FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg; - FAR struct usbhost_hport_s *hport + FAR struct usbhost_hubport_s *hport; + FAR struct usbhost_driver_s *drvr; DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL); hport = priv->usbclass.hport; + DEBUGASSERT(hport->drvr); + drvr = hport->drvr; + uvdbg("crefs: %d\n", priv->crefs); /* Unregister the driver */ @@ -364,11 +368,15 @@ static void usbhost_destroy(FAR void *arg) /* Free any transfer buffers */ + /* Free the function address assigned to this device */ + + usbhost_devaddr_destroy(hport); + /* Destroy the semaphores */ /* Disconnect the USB host device */ - DRVR_DISCONNECT(hport->drvr); + DRVR_DISCONNECT(drvr); /* And free the class instance. Hmmm.. this may execute on the worker * thread and the work structure is part of what is getting freed. That diff --git a/drivers/usbhost/usbhost_storage.c b/drivers/usbhost/usbhost_storage.c index 66a5245651f..c6b58d322c4 100644 --- a/drivers/usbhost/usbhost_storage.c +++ b/drivers/usbhost/usbhost_storage.c @@ -57,6 +57,7 @@ #include #include #include +#include /* Don't compile if prerequisites are not met */ @@ -1809,9 +1810,11 @@ static int usbhost_connect(FAR struct usbhost_class_s *usbclass, static int usbhost_disconnected(struct usbhost_class_s *usbclass) { FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)usbclass; + FAR struct usbhost_hubport_s *hport; irqstate_t flags; - DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL); + hport = priv->usbclass.hport; /* Set an indication to any users of the mass storage device that the device * is no longer available. @@ -1851,6 +1854,10 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass) } irqrestore(flags); + + /* Free the function address assigned to this device */ + + usbhost_devaddr_destroy(hport); return OK; } diff --git a/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h index c36cc347a1e..f5031c2393d 100644 --- a/include/nuttx/usb/usbhost.h +++ b/include/nuttx/usb/usbhost.h @@ -53,6 +53,8 @@ #include #include +#include + /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ @@ -606,6 +608,8 @@ typedef FAR void *usbhost_ep_t; * root hub is managed by the HCD. This structure describes that state of * that port and provides the linkage to the parent hub in that event that * the port is on an external hub. + * + * The root hub port can be distinguish because it has parent == NULL. */ struct usbhost_hubport_s @@ -620,6 +624,21 @@ struct usbhost_hubport_s uint8_t speed; /* Device speed */ }; +/* The root hub port differs in that it includes a data set that is used to + * manage the generation of unique device function addresses on all + * downstream ports. + */ + +struct usbhost_roothubport_s +{ + /* This structure must appear first so that this structure is cast- + * compatible with usbhost_hubport_s. + */ + + struct usbhost_hubport_s hport; /* Common hub port definitions */ + struct usbhost_devaddr_s devgen; /* Address generation data */ +}; + /* struct usbhost_class_s provides access from the USB host driver to the * USB host class implementation. */ @@ -695,16 +714,6 @@ typedef CODE void (*usbhost_asynch_t)(FAR void *arg, int result); struct usbhost_driver_s { -#ifdef CONFIG_USBHOST_HUB - /* Root hub */ - - FAR struct usbhost_class_s *roothub; - - /* Controller speed, i.e. High/Full/Low */ - - uint8_t speed; -#endif - /* Configure endpoint 0. This method is normally used internally by the * enumerate() method but is made available at the interface to support * an external implementation of the enumeration logic. diff --git a/include/nuttx/usb/usbhost_devaddr.h b/include/nuttx/usb/usbhost_devaddr.h index 4945f99e3e7..366d57c6a89 100644 --- a/include/nuttx/usb/usbhost_devaddr.h +++ b/include/nuttx/usb/usbhost_devaddr.h @@ -2,7 +2,7 @@ * include/nuttx/usb/usbhost_devaddr.h * Manage USB device addresses * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2013, 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * NOTE: This interface was inspired by the Linux gadget interface by @@ -49,6 +49,9 @@ #include +#include +#include + /******************************************************************************* * Pre-processor Definitions *******************************************************************************/ @@ -61,22 +64,11 @@ * Public Types *******************************************************************************/ -struct usbhost_devhash_s -{ - FAR struct usbhost_devhash_s *flink; - FAR void *payload; - uint8_t devaddr; -}; - struct usbhost_devaddr_s { uint8_t next; /* Next device address */ - sem_t exclsem; /* Enforces mutulaly exlusive access */ + sem_t exclsem; /* Enforces mutually exclusive access */ uint32_t alloctab[4]; /* Bit allocation table */ - - /* Hash table */ - - FAR struct usbhost_devhash_s *hashtab[USBHOST_DEVADDR_HASHSIZE]; }; /******************************************************************************* @@ -96,51 +88,61 @@ extern "C" * Public Functions *******************************************************************************/ +struct usbhost_hubport_s; /* Forward reference */ +struct usbhost_roothubport_s; /* Forward reference */ + /******************************************************************************* * Name: usbhost_devaddr_initialize * * Description: * Initialize the caller provided struct usbhost_devaddr_s instance in - * preparation for the management of device addresses on behalf of an HCD. + * preparation for the management of device addresses on behalf of an root + * hub port. + * + * Input Parameters: + * rhport - A reference to a roothubport structure. + * + * Returned Value: + * None * *******************************************************************************/ -void usbhost_devaddr_initialize(FAR struct usbhost_devaddr_s *hcd); +void usbhost_devaddr_initialize(FAR struct usbhost_roothubport_s *rhport); /******************************************************************************* * Name: usbhost_devaddr_create * * Description: - * Create a new unique device address for this HCD. Bind the void* arg to the - * the device address and return the newly allocated device address. + * Create a new unique device address for this hub port. + * + * Input Parameters: + * hport - A reference to a hub port structure to which a device has been + * newly connected and so is in need of a function address. + * + * Returned Value: + * Zero on success; a negated errno value is returned on failure. * *******************************************************************************/ -int usbhost_devaddr_create(FAR struct usbhost_devaddr_s *hcd, - FAR void *associate); - -/******************************************************************************* - * Name: usbhost_devaddr_find - * - * Description: - * Given a device address, find the void* value that was bound to the device - * address by usbhost_devaddr_create() when the device address was allocated. - * - *******************************************************************************/ - -FAR void *usbhost_devaddr_find(FAR struct usbhost_devaddr_s *hcd, - uint8_t devaddr); +int usbhost_devaddr_create(FAR struct usbhost_hubport_s *hport); /******************************************************************************* * Name: usbhost_devaddr_destroy * * Description: - * Release a device address previously allocated by usbhost_devaddr_destroy() - * and destroy the association with the void* data. + * Release a device address previously assigned to a hub port by + * usbhost_devaddr_create(). + * + * Input Parameters: + * hport - A reference to a hub port structure from which a device has been + * disconnected and so no longer needs the function address. + * + * Returned Value: + * None * *******************************************************************************/ -void usbhost_devaddr_destroy(FAR struct usbhost_devaddr_s *hcd, uint8_t devaddr); +void usbhost_devaddr_destroy(FAR struct usbhost_hubport_s *hport); #undef EXTERN #if defined(__cplusplus)