From 7fcfca40b530338f99f835c64dee563845b372c8 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 19 Apr 2015 08:55:48 -0600 Subject: [PATCH] Bring in more logic from https://github.com/kaushalparikh/nuttx --- ChangeLog | 3 + drivers/usbhost/usbhost_hub.c | 244 +++++++++++++------------- include/nuttx/usb/usbhost.h | 317 +++++++++++++++++++++++++++------- 3 files changed, 382 insertions(+), 182 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8b5612d5a9..8c36342ec2 100755 --- a/ChangeLog +++ b/ChangeLog @@ -10253,3 +10253,6 @@ Parikh. This initial commit is incomplete. This is quite a bit more hub logic that needs to come in before the port is complete (2015-04-18). + * include/nuttx/usb/usbhost.h: Bring in more logic from + https://github.com/kaushalparikh/nuttx (2015-04-19). + diff --git a/drivers/usbhost/usbhost_hub.c b/drivers/usbhost/usbhost_hub.c index cf28d35d05..90e15ff75c 100644 --- a/drivers/usbhost/usbhost_hub.c +++ b/drivers/usbhost/usbhost_hub.c @@ -127,7 +127,7 @@ static inline uint8_t usbhost_allocaddr(void); static inline void usbhost_freeaddr(uint8_t addr); static inline FAR struct usbhost_class_s * usbhost_allocclass(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_class_s *hclass, uint8_t speed, + FAR struct usbhost_class_s *hubclass, uint8_t speed, uint8_t port); static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass); @@ -137,10 +137,10 @@ static void usbhost_destroy(FAR void *arg); /* Helpers for usbhost_connect() */ -static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hclass, +static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass, FAR const uint8_t *configdesc, int desclen); -static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hclass); -static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hclass, +static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass); +static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on); static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer); @@ -152,14 +152,14 @@ static void usbhost_callback(FAR struct usbhost_transfer_s *xfer); /* struct usbhost_registry_s methods */ -static int usbhost_create(FAR struct usbhost_class_s *hclass, +static int usbhost_create(FAR struct usbhost_class_s *hubclass, FAR const struct usbhost_id_s *id); /* struct usbhost_class_s methods */ -static int usbhost_connect(FAR struct usbhost_class_s *hclass, +static int usbhost_connect(FAR struct usbhost_class_s *hubclass, FAR const uint8_t *configdesc, int desclen); -static int usbhost_disconnected(FAR struct usbhost_class_s *hclass); +static int usbhost_disconnected(FAR struct usbhost_class_s *hubclass); /**************************************************************************** * Private Data @@ -281,14 +281,14 @@ static inline void usbhost_freeaddr(uint8_t addr) static inline FAR struct usbhost_class_s * usbhost_allocclass(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_class_s *hclass, + FAR struct usbhost_class_s *hubclass, uint8_t speed, uint8_t port) { - FAR struct usbhost_hub_s *hpriv; + FAR struct usbhost_hub_s *priv; FAR struct usbhost_class_s *devclass; - DEBUGASSERT(hclass != NULL && hclass->priv != NULL); - hpriv = (FAR struct usbhost_hub_s *)hclass->priv; + DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); + priv = (FAR struct usbhost_hub_s *)hubclass->priv; /* We are not executing from an interrupt handler so we can just call * kmalloc() to get memory for the class instance. @@ -309,7 +309,7 @@ static inline FAR struct usbhost_class_s * devclass->speed = speed; devclass->drvr = drvr; - devclass->parent = hclass; + devclass->parent = hubclass; devclass->priv = NULL; devclass->tt = NULL; @@ -317,15 +317,15 @@ static inline FAR struct usbhost_class_s * if (!ROOTHUB(devclass)) { - if (hclass->tt != NULL) + if (hubclass->tt != NULL) { - devclass->tt = hclass->tt; - devclass->ttport = hclass->ttport; + devclass->tt = hubclass->tt; + devclass->ttport = hubclass->ttport; } else if ((devclass->speed != USB_SPEED_HIGH) && - (hclass->speed == USB_SPEED_HIGH)) + (hubclass->speed == USB_SPEED_HIGH)) { - devclass->tt = &hpriv->tt; + devclass->tt = &priv->tt; devclass->ttport = port; } } @@ -401,42 +401,42 @@ static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass) static void usbhost_destroy(FAR void *arg) { - FAR struct usbhost_class_s *hclass = (FAR struct usbhost_class_s *)arg; - FAR struct usbhost_hub_s *hpriv; + FAR struct usbhost_class_s *hubclass = (FAR struct usbhost_class_s *)arg; + FAR struct usbhost_hub_s *priv; int i; - DEBUGASSERT(hclass != NULL); + DEBUGASSERT(hubclass != NULL); - hpriv = (FAR struct usbhost_hub_s *)hclass->priv; - if (hpriv != NULL) + priv = (FAR struct usbhost_hub_s *)hubclass->priv; + if (priv != NULL) { - uvdbg("crefs: %d\n", hpriv->crefs); + uvdbg("crefs: %d\n", priv->crefs); - if (hpriv->intxfer.ep) + if (priv->intxfer.ep) { - DRVR_EPFREE(hclass->drvr, hpriv->intxfer.ep); + DRVR_EPFREE(hubclass->drvr, priv->intxfer.ep); } /* Destroy the semaphores */ - sem_destroy(&hpriv->exclsem); + sem_destroy(&priv->exclsem); /* Destroy allocated child classes */ for (i = 0; i < USBHUB_MAX_PORTS; i++) { - if (hpriv->childclass[i] != NULL) + if (priv->childclass[i] != NULL) { - CLASS_DISCONNECTED(hpriv->childclass[i]); + CLASS_DISCONNECTED(priv->childclass[i]); } } /* Clear priv class */ - kfree(hclass->priv); + kfree(hubclass->priv); } - usbhost_freeclass(hclass); + usbhost_freeclass(hubclass); } /**************************************************************************** @@ -449,7 +449,7 @@ static void usbhost_destroy(FAR void *arg) * descriptor to the class so that the class may initialize properly * * Input Parameters: - * priv - The USB host class instance. + * hubclass - The USB host class instance. * configdesc - A pointer to a uint8_t buffer container the configuration * descriptor. * desclen - The length in bytes of the configuration descriptor. @@ -463,10 +463,10 @@ static void usbhost_destroy(FAR void *arg) * ****************************************************************************/ -static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hclass, +static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass, FAR const uint8_t *configdesc, int desclen) { - FAR struct usbhost_hub_s *hpriv; + FAR struct usbhost_hub_s *priv; FAR struct usb_cfgdesc_s *cfgdesc; FAR struct usb_desc_s *desc; FAR struct usbhost_epdesc_s intindesc; @@ -474,8 +474,8 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hclass, uint8_t found = 0; int ret; - DEBUGASSERT(hclass != NULL && hclass->priv != NULL); - hpriv = (FAR struct usbhost_hub_s *)hclass->priv; + DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); + priv = (FAR struct usbhost_hub_s *)hubclass->priv; DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s)); @@ -522,8 +522,8 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hclass, /* Save the interface number and mark ONLY the interface found */ - hpriv->ifno = ifdesc->ifno; - found = USBHOST_IFFOUND; + priv->ifno = ifdesc->ifno; + found = USBHOST_IFFOUND; } break; @@ -562,7 +562,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hclass, /* Save the bulk IN endpoint information */ - intindesc.devclass = hclass; + intindesc.devclass = hubclass; intindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; intindesc.in = 1; intindesc.xfrtype = USB_EP_ATTR_XFER_BULK; @@ -609,11 +609,11 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hclass, /* We are good... Allocate the endpoints */ - ret = DRVR_EPALLOC(hclass->drvr, &intindesc, &hpriv->intxfer.ep); + ret = DRVR_EPALLOC(hubclass->drvr, &intindesc, &priv->intxfer.ep); if (ret != OK) { udbg("ERROR: Failed to allocate Interrupt IN endpoint\n"); - (void)DRVR_EPFREE(hclass->drvr, hpriv->intxfer.ep); + (void)DRVR_EPFREE(hubclass->drvr, priv->intxfer.ep); return ret; } @@ -631,7 +631,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hclass, * descriptor to the class so that the class may initialize properly * * Input Parameters: - * hclass - The USB host class instance. + * hubclass - The USB host class instance. * * Returned Values: * On success, zero (OK) is returned. On a failure, a negated errno value @@ -642,17 +642,17 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hclass, * ****************************************************************************/ -static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hclass) +static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass) { - FAR struct usbhost_hub_s *hpriv; + FAR struct usbhost_hub_s *priv; struct usb_hubdesc_s hubdesc; uint16_t hubchar; int ret; - DEBUGASSERT(hclass != NULL && hclass->priv != NULL); - hpriv = (FAR struct usbhost_hub_s *)hclass->priv; + DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); + priv = (FAR struct usbhost_hub_s *)hubclass->priv; - ret = usbhost_ctrlxfer(hclass, (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_HUB), + ret = usbhost_ctrlxfer(hubclass, (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_HUB), USB_REQ_GETDESCRIPTOR, USB_DESC_TYPE_HUB, 0, USB_SIZEOF_HUBDESC, (uint8_t *)&hubdesc); if (ret != OK) @@ -661,18 +661,16 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hclass) return ret; } - hpriv->nports = hubdesc.nports; + priv->nports = hubdesc.nports; - hubchar = usbhost_getle16(hubdesc.characteristics); - hpriv->lpsm = (hubchar & USBHUB_CHAR_LPSM_MASK) >> USBHUB_CHAR_LPSM_SHIFT; - hpriv->compounddev = (hubchar & USBHUB_CHAR_COMPOUND) ? true : false; - hpriv->ocmode = (hubchar & USBHUB_CHAR_OCPM_MASK) >> USBHUB_CHAR_OCPM_SHIFT; - /* priv->ttthinktime = (((hubchar & USBHUB_CHAR_TTTT_MASK) >> USBHUB_CHAR_TTTT_SHIFT) + 1) * 666; */ - /* 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ - hpriv->indicator = (hubchar & USBHUB_CHAR_PORTIND) ? true : false; + hubchar = usbhost_getle16(hubdesc.characteristics); + priv->lpsm = (hubchar & USBHUB_CHAR_LPSM_MASK) >> USBHUB_CHAR_LPSM_SHIFT; + priv->compounddev = (hubchar & USBHUB_CHAR_COMPOUND) ? true : false; + priv->ocmode = (hubchar & USBHUB_CHAR_OCPM_MASK) >> USBHUB_CHAR_OCPM_SHIFT; + priv->indicator = (hubchar & USBHUB_CHAR_PORTIND) ? true : false; - hpriv->pwrondelay = (2 * hubdesc.pwrondelay); - hpriv->ctrlcurrent = hubdesc.ctrlcurrent; + priv->pwrondelay = (2 * hubdesc.pwrondelay); + priv->ctrlcurrent = hubdesc.ctrlcurrent; return OK; } @@ -687,7 +685,7 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hclass) * descriptor to the class so that the class may initialize properly * * Input Parameters: - * hclass - The USB host class instance. + * hubclass - The USB host class instance. * * Returned Values: * On success, zero (OK) is returned. On a failure, a negated errno value is @@ -698,14 +696,14 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hclass) * ****************************************************************************/ -static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hclass, bool on) +static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on) { - FAR struct usbhost_hub_s *hpriv; + FAR struct usbhost_hub_s *priv; - DEBUGASSERT(hclass != NULL && hclass->priv != NULL); - hpriv = (FAR struct usbhost_hub_s *)hclass->priv; + DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); + priv = (FAR struct usbhost_hub_s *)hubclass->priv; - if (on || ROOTHUB(hclass)) + if (on || ROOTHUB(hubclass)) { uint16_t req; int port, ret; @@ -719,9 +717,9 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hclass, bool on) req = USB_REQ_CLEARFEATURE; } - for (port = 1; port <= hpriv->nports; port++) + for (port = 1; port <= priv->nports; port++) { - ret = usbhost_ctrlxfer(hclass, USBHUB_REQ_TYPE_PORT, + ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, req, USBHUB_PORT_FEAT_POWER, port, 0, NULL); if (ret != OK) @@ -758,8 +756,8 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hclass, bool on) static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) { - FAR struct usbhost_class_s *hclass; - FAR struct usbhost_hub_s *hpriv; + FAR struct usbhost_class_s *hubclass; + FAR struct usbhost_hub_s *priv; struct usb_portstatus_s portstatus; uint16_t status; uint16_t change; @@ -770,14 +768,14 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) int ret; DEBUGASSERT(xfer != NULL && xfer->devclass != NULL); - hclass = (FAR struct usbhost_class_s *)xfer->devclass; + hubclass = (FAR struct usbhost_class_s *)xfer->devclass; - DEBUGASSERT(hclass != NULL && hclass->priv != NULL); - hpriv = (FAR struct usbhost_hub_s *)hclass->priv; + DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); + priv = (FAR struct usbhost_hub_s *)hubclass->priv; statusmap = xfer->buffer[0]; - for (port = 1; port <= hpriv->nports; port++) + for (port = 1; port <= priv->nports; port++) { /* Check if port status has changed */ @@ -792,7 +790,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) /* Read hub port status */ - ret = usbhost_ctrlxfer(hclass, + ret = usbhost_ctrlxfer(hubclass, (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), USB_REQ_GETSTATUS, 0, port, USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); @@ -813,7 +811,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) { if (change & mask) { - ret = usbhost_ctrlxfer(hclass, USBHUB_REQ_TYPE_PORT, + ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, USB_REQ_CLEARFEATURE, feat, port, 0, NULL); if (ret != OK) @@ -844,7 +842,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) while (debouncetime < 1500) { - ret = usbhost_ctrlxfer(hclass, + ret = usbhost_ctrlxfer(hubclass, (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), USB_REQ_GETSTATUS, 0, port, USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); @@ -873,7 +871,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) if (change & USBHUB_PORT_STAT_CCONNECTION) { - (void)usbhost_ctrlxfer(hclass, USBHUB_REQ_TYPE_PORT, + (void)usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, USB_REQ_CLEARFEATURE, USBHUB_PORT_FEAT_CCONNECTION, port, 0, NULL); } @@ -892,7 +890,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) { /* Connect */ - ret = usbhost_ctrlxfer(hclass, USBHUB_REQ_TYPE_PORT, + ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, USB_REQ_SETFEATURE, USBHUB_PORT_FEAT_RESET, port, 0, NULL); if (ret != OK) @@ -903,7 +901,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) up_mdelay(100); - ret = usbhost_ctrlxfer(hclass, + ret = usbhost_ctrlxfer(hubclass, (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), USB_REQ_GETSTATUS, 0, port, USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); @@ -926,7 +924,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) if (change & USBHUB_PORT_STAT_CRESET) { - (void)usbhost_ctrlxfer(hclass, USBHUB_REQ_TYPE_PORT, + (void)usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, USB_REQ_CLEARFEATURE, USBHUB_PORT_FEAT_CRESET, port, 0, NULL); @@ -947,15 +945,15 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) /* Allocate new class and enumerate */ - hpriv->childclass[port] = - usbhost_allocclass(hclass->drvr, hclass, speed, port); + priv->childclass[port] = + usbhost_allocclass(hubclass->drvr, hubclass, speed, port); - if (hpriv->childclass[port] != NULL) + if (priv->childclass[port] != NULL) { udbg("enumerate port %d speed %d\n", port, speed); #if 0 - ret = usbhost_enumerate(hpriv->childclass[port]); + ret = usbhost_enumerate(priv->childclass[port]); if (ret != OK) { udbg("failed to enumerate port %d\n", port); @@ -990,7 +988,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) xfer->status = -EIO; - ret = usbhost_intxfer(hclass, xfer, usbhost_callback); + ret = usbhost_intxfer(hubclass, xfer, usbhost_callback); if (ret != OK) { udbg("failed to queue interrupt endpoint\n"); @@ -1093,50 +1091,50 @@ static void usbhost_callback(FAR struct usbhost_transfer_s *xfer) * ****************************************************************************/ -static int usbhost_create(FAR struct usbhost_class_s *hclass, +static int usbhost_create(FAR struct usbhost_class_s *hubclass, FAR const struct usbhost_id_s *id) { - struct usbhost_hub_s *hpriv; + struct usbhost_hub_s *priv; int child; int ret = -ENOMEM; /* Allocate a USB host class instance */ - hpriv = kmalloc(sizeof(struct usbhost_hub_s)); + priv = kmalloc(sizeof(struct usbhost_hub_s)); - if (hpriv != NULL) + if (priv != NULL) { /* Initialize the allocated storage class instance */ - memset(hpriv, 0, sizeof(struct usbhost_hub_s)); + memset(priv, 0, sizeof(struct usbhost_hub_s)); /* Initialize class method function pointers */ - hclass->connect = usbhost_connect; - hclass->disconnected = usbhost_disconnected; - hclass->priv = hpriv; + hubclass->connect = usbhost_connect; + hubclass->disconnected = usbhost_disconnected; + hubclass->priv = priv; /* The initial reference count is 1... One reference is held by the driver */ - hpriv->crefs = 1; + priv->crefs = 1; /* Initialize semaphores (this works okay in the interrupt context) */ - sem_init(&hpriv->exclsem, 0, 1); + sem_init(&priv->exclsem, 0, 1); /* Initialize interrupt end-point */ - hpriv->intxfer.ep = NULL; + priv->intxfer.ep = NULL; /* Initialize transaction translator */ - hpriv->tt.class = NULL; + priv->tt.class = NULL; /* Initialize child class pointers */ for (child = 0; child < USBHUB_MAX_PORTS; child++) { - hpriv->childclass[child] = NULL; + priv->childclass[child] = NULL; } ret = OK; @@ -1181,21 +1179,21 @@ static int usbhost_create(FAR struct usbhost_class_s *hclass, * ****************************************************************************/ -static int usbhost_connect(FAR struct usbhost_class_s *hclass, +static int usbhost_connect(FAR struct usbhost_class_s *hubclass, FAR const uint8_t *configdesc, int desclen) { - FAR struct usbhost_hub_s *hpriv; + FAR struct usbhost_hub_s *priv; int ret; - DEBUGASSERT(hclass != NULL && hclass->priv != NULL); - hpriv = (FAR struct usbhost_hub_s *)hclass->priv; + DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); + priv = (FAR struct usbhost_hub_s *)hubclass->priv; DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s)); /* Parse the configuration descriptor to get the endpoints */ - ret = usbhost_cfgdesc(hclass, configdesc, desclen); + ret = usbhost_cfgdesc(hubclass, configdesc, desclen); if (ret != OK) { udbg("failed to parse config descriptor\n"); @@ -1204,7 +1202,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hclass, { /* Allocate buffer for status change (INT) endpoint */ - ret = DRVR_IOALLOC(hclass->drvr, &hpriv->intxfer.buffer, 1); + ret = DRVR_IOALLOC(hubclass->drvr, &priv->intxfer.buffer, 1); if (ret != OK) { return ret; @@ -1212,7 +1210,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hclass, /* Now read hub descriptor */ - ret = usbhost_hubdesc(hclass); + ret = usbhost_hubdesc(hubclass); if (ret != OK) { return ret; @@ -1220,7 +1218,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hclass, /* Power on hub (i.e. power on all hub ports) */ - ret = usbhost_hubpwr(hclass, true); + ret = usbhost_hubpwr(hubclass, true); if (ret != OK) { return ret; @@ -1228,7 +1226,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hclass, /* INT request to periodically check port status */ - ret = usbhost_intxfer(hclass, &hpriv->intxfer, + ret = usbhost_intxfer(hubclass, &priv->intxfer, usbhost_callback); } @@ -1257,20 +1255,20 @@ static int usbhost_connect(FAR struct usbhost_class_s *hclass, * ****************************************************************************/ -static int usbhost_disconnected(struct usbhost_class_s *hclass) +static int usbhost_disconnected(struct usbhost_class_s *hubclass) { - FAR struct usbhost_hub_s *hpriv; + FAR struct usbhost_hub_s *priv; irqstate_t flags; - DEBUGASSERT(hclass != NULL && hclass->priv != NULL); - hpriv = (FAR struct usbhost_hub_s *)hclass->priv; + DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); + priv = (FAR struct usbhost_hub_s *)hubclass->priv; /* Set an indication to any users of the device that the device is no * longer available. */ - flags = irqsave(); - hpriv->disconnected = true; + flags = irqsave(); + priv->disconnected = true; /* Now check the number of references on the class instance. If it is one, * then we can free the class instance now. Otherwise, we will have to @@ -1278,19 +1276,19 @@ static int usbhost_disconnected(struct usbhost_class_s *hclass) * block driver. */ - ullvdbg("crefs: %d\n", hpriv->crefs); - if (hpriv->crefs == 1) + ullvdbg("crefs: %d\n", priv->crefs); + if (priv->crefs == 1) { /* Free buffer for status change (INT) endpoint */ - DRVR_IOFREE(hclass->drvr, hpriv->intxfer.buffer); + DRVR_IOFREE(hubclass->drvr, priv->intxfer.buffer); /* Power off (for root hub only) */ - (void)usbhost_hubpwr(hclass, false); + (void)usbhost_hubpwr(hubclass, false); /* Destroy the class instance */ - usbhost_destroy(hclass); + usbhost_destroy(hubclass); } irqrestore(flags); @@ -1343,22 +1341,22 @@ int usbhost_hubinit(void) int usbhost_rh_connect(FAR struct usbhost_driver_s *drvr) { - struct usbhost_class_s *hclass = NULL; + struct usbhost_class_s *hubclass = NULL; int ret = -ENOMEM; memset(g_addrmap, 0, 4*4); - hclass = usbhost_allocclass(drvr, NULL, drvr->speed, 1); - if (hclass != NULL) + hubclass = usbhost_allocclass(drvr, NULL, drvr->speed, 1); + if (hubclass != NULL) { - ret = usbhost_enumerate(hclass); + ret = usbhost_enumerate(hubclass); if (ret != OK) { udbg("failed to enumerate root hub\n"); } else { - drvr->roothub = hclass; + drvr->roothub = hubclass; udbg("Total class memory %d+%d\n", sizeof(struct usbhost_class_s), sizeof(struct usbhost_hub_s)); } @@ -1385,11 +1383,11 @@ int usbhost_rh_connect(FAR struct usbhost_driver_s *drvr) int usbhost_rh_disconnect(FAR struct usbhost_driver_s *drvr) { - FAR struct usbhost_class_s *hclass = drvr->roothub; + FAR struct usbhost_class_s *hubclass = drvr->roothub; - if (hclass != NULL) + if (hubclass != NULL) { - CLASS_DISCONNECTED(hclass); + CLASS_DISCONNECTED(hubclass); drvr->roothub = NULL; } diff --git a/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h index 642cdf3764..65691c2c84 100644 --- a/include/nuttx/usb/usbhost.h +++ b/include/nuttx/usb/usbhost.h @@ -1,7 +1,7 @@ /************************************************************************************ * include/nuttx/usb/usbhost.h * - * Copyright (C) 2010-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2010-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: @@ -52,11 +52,24 @@ #include #include #include +#include + +#include /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ +/************************************************************************************ + * Name: ROOTHUB + * + * Description: + * Check for root hub + * + ************************************************************************************/ + +#define ROOTHUB(devclass) ((devclass)->parent == NULL) + /************************************************************************************ * Name: CLASS_CREATE * @@ -71,9 +84,9 @@ * Input Parameters: * reg - The USB host class registry entry previously obtained from a call to * usbhost_findclass(). - * drvr - An instance of struct usbhost_driver_s that the class implementation will - * "bind" to its state structure and will subsequently use to communicate with - * the USB host driver. + * devclass - An instance of struct usbhost_driver_s that the class + * implementation will "bind" to its state structure and will subsequently + * use to communicate with the USB host driver. * id - In the case where the device supports multiple base classes, subclasses, or * protocols, this specifies which to configure for. * @@ -81,7 +94,7 @@ * On success, this function will return a non-NULL instance of struct * usbhost_class_s that can be used by the USB host driver to communicate with the * USB host class. NULL is returned on failure; this function will fail only if - * the drvr input parameter is NULL or if there are insufficient resources to + * the devclass input parameter is NULL or if there are insufficient resources to * create another USB host class instance. * * Assumptions: @@ -91,23 +104,21 @@ * ************************************************************************************/ -#define CLASS_CREATE(reg, drvr, id) ((reg)->create(drvr, id)) +#define CLASS_CREATE(reg, devclass, id) ((reg)->create(devclass, id)) /************************************************************************************ * Name: CLASS_CONNECT * * Description: * This macro will call the connect() method of struct usbhost_class_s. This - * method is a callback into the usbclass implementation. It is used to provide the - * device's configuration descriptor to the usbclass so that the usbclass may initialize + * method is a callback into the devclass implementation. It is used to provide the + * device's configuration descriptor to the devclass so that the devclass may initialize * properly * * Input Parameters: - * usbclass - The USB host class entry previously obtained from a call to create(). + * devclass - The USB host class entry previously obtained from a call to create(). * configdesc - A pointer to a uint8_t buffer container the configuration descripor. * desclen - The length in bytes of the configuration descriptor. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls * * Returned Values: * On success, zero (OK) is returned. On a failure, a negated errno value is @@ -126,8 +137,8 @@ * ************************************************************************************/ -#define CLASS_CONNECT(usbclass,configdesc,desclen,funcaddr) \ - ((usbclass)->connect(usbclass,configdesc,desclen, funcaddr)) +#define CLASS_CONNECT(devclass,configdesc,desclen) \ + ((devclass)->connect(devclass,configdesc,desclen)) /************************************************************************************ * Name: CLASS_DISCONNECTED @@ -138,7 +149,7 @@ * class that the USB device has been disconnected. * * Input Parameters: - * usbclass - The USB host class entry previously obtained from a call to create(). + * devclass - The USB host class entry previously obtained from a call to create(). * * Returned Values: * On success, zero (OK) is returned. On a failure, a negated errno value is @@ -149,7 +160,7 @@ * ************************************************************************************/ -#define CLASS_DISCONNECTED(usbclass) ((usbclass)->disconnected(usbclass)) +#define CLASS_DISCONNECTED(devclass) ((devclass)->disconnected(devclass)) /******************************************************************************* * Name: CONN_WAIT @@ -220,6 +231,7 @@ * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to * the class create() method. + * ep0 - The (opaque) EP0 endpoint instance * funcaddr - The USB address of the function containing the endpoint that EP0 * controls * mps (maxpacketsize) - The maximum number of bytes that can be sent to or @@ -234,7 +246,8 @@ * ************************************************************************************/ -#define DRVR_EP0CONFIGURE(drvr,funcaddr,mps) ((drvr)->ep0configure(drvr,funcaddr,mps)) +#define DRVR_EP0CONFIGURE(drvr,ep0,funcaddr,mps) \ + ((drvr)->ep0configure(drvr,ep0,funcaddr,mps)) /************************************************************************************ * Name: DRVR_GETDEVINFO @@ -438,7 +451,7 @@ * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to * the class create() method. - * req - Describes the request to be sent. This request must lie in memory + * xfr - Describes the request to be sent. This request must lie in memory * created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value @@ -456,8 +469,8 @@ * ************************************************************************************/ -#define DRVR_CTRLIN(drvr,req,buffer) ((drvr)->ctrlin(drvr,req,buffer)) -#define DRVR_CTRLOUT(drvr,req,buffer) ((drvr)->ctrlout(drvr,req,buffer)) +#define DRVR_CTRLIN(drvr,xfer,cmd) ((drvr)->ctrlin(drvr,xfer,cmd)) +#define DRVR_CTRLOUT(drvr,xfer,cmd) ((drvr)->ctrlout(drvr,xfer,cmd)) /************************************************************************************ * Name: DRVR_TRANSFER @@ -495,7 +508,7 @@ * ************************************************************************************/ -#define DRVR_TRANSFER(drvr,ed,buffer,buflen) ((drvr)->transfer(drvr,ed,buffer,buflen)) +#define DRVR_TRANSFER(drvr,xfer) ((drvr)->transfer(drvr,xfer)) /************************************************************************************ * Name: DRVR_DISCONNECT @@ -521,6 +534,34 @@ #define DRVR_DISCONNECT(drvr) ((drvr)->disconnect(drvr)) +/************************************************************************************ + * Name: DRVR_RHCTRL and DRVR_RHSTATUS + * + * Description: + * Called by hub class to control root hub. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the call to + * the class create() method. + * xfer - Describes the request to be sent. This request must lie in memory + * created by DRVR_ALLOC. + * cmd - A buffer used for sending the request and for returning any + * responses. This buffer must be large enough to hold the length value + * in the request description. buffer must have been allocated using DRVR_ALLOC. + * + * Returned Values: + * On success, zero (OK) is returned. On a failure, a negated errno value is + * returned indicating the nature of the failure + * + * Assumptions: + * + ************************************************************************************/ + +#ifdef CONFIG_UBHOST_HUB +# define DRVR_RHCTRL(drvr,xfer,cmd) ((drvr)->rhctrl(drvr,xfer,cmd)) +# define DRVR_RHSTATUS(drvr,xfer) ((drvr)->rhstatus(drvr,xfer)) +#endif + /************************************************************************************ * Public Types ************************************************************************************/ @@ -553,7 +594,7 @@ struct usbhost_registry_s * provide those instances in write-able memory (RAM). */ - struct usbhost_registry_s *flink; + struct usbhost_registry_s *flink; /* This is a callback into the class implementation. It is used to (1) create * a new instance of the USB host class state and to (2) bind a USB host driver @@ -562,14 +603,14 @@ struct usbhost_registry_s * simultaneously connected (see the CLASS_CREATE() macro above). */ - FAR struct usbhost_class_s *(*create)(FAR struct usbhost_driver_s *drvr, - FAR const struct usbhost_id_s *id); + int (*create)(FAR struct usbhost_class_s *devclass, + FAR const struct usbhost_id_s *id); /* This information uniquely identifies the USB host class implementation that * goes with a specific USB device. */ - uint8_t nids; /* Number of IDs in the id[] array */ + uint8_t nids; /* Number of IDs in the id[] array */ FAR const struct usbhost_id_s *id; /* An array of ID info. Actual dimension is nids */ }; @@ -579,18 +620,49 @@ struct usbhost_registry_s struct usbhost_class_s { +#ifdef CONFIG_UBHOST_HUB + /* Host driver */ + + struct usbhost_driver_s *drvr; + + /* USB device address & speed */ + + uint8_t addr; + uint8_t speed; + + /* Parent class */ + + struct usbhost_class_s *parent; + + /* Control endpoint, ep0 */ + + usbhost_ep_t ep0; + + /* Transaction translator hub */ + + FAR struct usb_hubtt_s *tt; + + /* Transaction translator port */ + + uint8_t ttport; + + /* Class specific private data */ + + FAR void *priv; +#endif + /* Provides the configuration descriptor to the class. The configuration * descriptor contains critical information needed by the class in order to * initialize properly (such as endpoint selections). */ - int (*connect)(FAR struct usbhost_class_s *usbclass, + int (*connect)(FAR struct usbhost_class_s *devclass, FAR const uint8_t *configdesc, - int desclen, uint8_t funcaddr); + int desclen); /* This method informs the class that the USB device has been disconnected. */ - int (*disconnected)(FAR struct usbhost_class_s *usbclass); + int (*disconnected)(FAR struct usbhost_class_s *devclass); }; /* This structure describes one endpoint. It is used as an input to the @@ -600,12 +672,15 @@ struct usbhost_class_s struct usbhost_epdesc_s { - uint8_t addr; /* Endpoint address */ - bool in; /* Direction: true->IN */ - uint8_t funcaddr; /* USB address of function containing endpoint */ - uint8_t xfrtype; /* Transfer type. See USB_EP_ATTR_XFER_* in usb.h */ - uint8_t interval; /* Polling interval */ - uint16_t mxpacketsize; /* Max packetsize */ +#ifdef CONFIG_UBHOST_HUB + FAR struct usbhost_class_s *devclass; /* Class */ +#endif + uint8_t addr; /* Endpoint address */ + bool in; /* Direction: true->IN */ + uint8_t funcaddr; /* USB address of function containing endpoint */ + uint8_t xfrtype; /* Transfer type. See USB_EP_ATTR_XFER_* in usb.h */ + uint8_t interval; /* Polling interval */ + uint16_t mxpacketsize; /* Max packetsize */ }; /* This structure provides information about the connected device */ @@ -616,15 +691,45 @@ struct usbhost_devinfo_s }; /* This type represents one endpoint configured by the epalloc() method. - * The actual form is know only internally to the USB host controller + * The actual form is known only internally to the USB host controller * (for example, for an OHCI driver, this would probably be a pointer * to an endpoint descriptor). */ typedef FAR void *usbhost_ep_t; +/* Generic transfer structure */ + +struct usbhost_transfer_s +{ + FAR uint8_t *buffer; + size_t buflen; + size_t len; + int status; + + /* Semaphore of synchronized transfers */ + + sem_t done; + + /* Device class */ + + FAR struct usbhost_class_s *devclass; + + /* Opaque endpoint pointer; can be xHCI specific */ + + usbhost_ep_t ep; + + /* Workqueue for callback */ + + struct work_s work; + + /* Transfer complete callback */ + + void (*callback)(FAR struct usbhost_transfer_s *); +}; + /* struct usbhost_connection_s provides as interface between platform-specific - * connection monitoring and the USB host driver connectin and enumeration + * connection monitoring and the USB host driver connection and enumeration * logic. */ @@ -653,13 +758,23 @@ struct usbhost_connection_s struct usbhost_driver_s { +#ifdef CONFIG_UBHOST_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. */ - int (*ep0configure)(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr, - uint16_t maxpacketsize); + int (*ep0configure)(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + uint8_t funcaddr, uint16_t maxpacketsize); /* Get information about the connected device */ @@ -711,11 +826,11 @@ struct usbhost_driver_s */ int (*ctrlin)(FAR struct usbhost_driver_s *drvr, - FAR const struct usb_ctrlreq_s *req, - FAR uint8_t *buffer); + FAR struct usbhost_transfer_s *xfer, + FAR const struct usb_ctrlreq_s *cmd); int (*ctrlout)(FAR struct usbhost_driver_s *drvr, - FAR const struct usb_ctrlreq_s *req, - FAR const uint8_t *buffer); + FAR struct usbhost_transfer_s *xfer, + FAR const struct usb_ctrlreq_s *cmd); /* Process a request to handle a transfer descriptor. This method will * enqueue the transfer request and wait for it to complete. Only one transfer may @@ -726,8 +841,8 @@ struct usbhost_driver_s * transfer has completed. */ - int (*transfer)(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); + int (*transfer)(FAR struct usbhost_driver_s *drvr, + FAR struct usbhost_transfer_s *xfer); /* Called by the class when an error occurs and driver has been disconnected. * The USB host driver should discard the handle to the class instance (it is @@ -736,6 +851,16 @@ struct usbhost_driver_s */ void (*disconnect)(FAR struct usbhost_driver_s *drvr); + +#ifdef CONFIG_UBHOST_HUB + /* Called by hub class to control root hub. */ + + int (*rhctrl)(FAR struct usbhost_driver_s *drvr, + FAR struct usbhost_transfer_s *xfer, + FAR const struct usb_ctrlreq_s *cmd); + int (*rhstatus)(FAR struct usbhost_driver_s *drvr, + FAR struct usbhost_transfer_s *xfer); +#endif }; /************************************************************************************ @@ -766,7 +891,7 @@ extern "C" * the device. * * Input Parameters: - * usbclass - An write-able instance of struct usbhost_registry_s that will be + * devclass - An write-able instance of struct usbhost_registry_s that will be * maintained in a registry. * * Returned Values: @@ -775,7 +900,7 @@ extern "C" * ************************************************************************************/ -int usbhost_registerclass(struct usbhost_registry_s *usbclass); +int usbhost_registerclass(struct usbhost_registry_s *devclass); /************************************************************************************ * Name: usbhost_findclass @@ -799,6 +924,27 @@ int usbhost_registerclass(struct usbhost_registry_s *usbclass); const struct usbhost_registry_s *usbhost_findclass(const struct usbhost_id_s *id); +#ifdef CONFIG_USBHOST_HUB +/**************************************************************************** + * Name: usbhost_hubinit + * + * Description: + * Initialize the USB hub class. This function should be called + * be platform-specific code in order to initialize and register support + * for the USB host storage class. + * + * Input Parameters: + * None + * + * Returned Values: + * On success this function will return zero (OK); A negated errno value + * will be returned on failure. + * + ****************************************************************************/ + +int usbhost_hubinit(void); +#endif + #ifdef CONFIG_USBHOST_MSC /**************************************************************************** * Name: usbhost_storageinit @@ -881,14 +1027,52 @@ int usbhost_mouse_init(void); int usbhost_wlaninit(void); +#ifdef CONFIG_USBHOST_HUB +/**************************************************************************** + * Name: usbhost_ctrlxfer + * + * Description: + * Free transfer buffer memory. + * + * Input Parameters: + * priv - A reference to the class instance. + * + * Returned Values: + * On success, zero (OK) is returned. On failure, an negated errno value + * is returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int usbhost_ctrlxfer(FAR struct usbhost_class_s *devclass, uint8_t type, + uint8_t req, uint16_t value, uint16_t index, + uint16_t len, FAR uint8_t *buffer); +#endif + +#ifdef CONFIG_USBHOST_HUB +/**************************************************************************** + * Name: usbhost_intxfer + * + * Description: + * Free transfer buffer memory. + * + * Input Parameters: + * priv - A reference to the class instance. + * + * Returned Values: + * On success, zero (OK) is returned. On failure, an negated errno value + * is returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int usbhost_intxfer(FAR struct usbhost_class_s *devclass, + FAR struct usbhost_transfer_s *xfer, + void (*callback)(FAR struct usbhost_transfer_s *)); +#endif + /******************************************************************************* * Name: usbhost_enumerate * * Description: - * This is a share-able implementation of most of the logic required by the - * driver enumerate() method. This logic within this method should be common - * to all USB host drivers. - * * Enumerate the connected device. As part of this enumeration process, * the driver will (1) get the device's configuration descriptor, (2) * extract the class ID info from the configuration descriptor, (3) call @@ -899,27 +1083,42 @@ int usbhost_wlaninit(void); * charge of the sequence of operations. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls - * usbclass - If the class driver for the device is successful located - * and bound to the driver, the allocated class instance is returned into - * this caller-provided memory location. + * devclass - USB class information common across all classes. Whoever calls + * enumerate should fill address, speed, driver and parent class + * pointer. Enumeration will fill the control endpoint ep0, + * transaction translator (if applicable) and private data * * Returned Values: * On success, zero (OK) is returned. On a failure, a negated errno value is * returned indicating the nature of the failure * * Assumptions: - * - Only a single class bound to a single device is supported. * - Called from a single thread so no mutual exclusion is required. * - Never called from an interrupt handler. * *******************************************************************************/ -int usbhost_enumerate(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr, - FAR struct usbhost_class_s **usbclass); +int usbhost_enumerate(FAR struct usbhost_class_s *devclass); + +#ifdef CONFIG_USBHOST_HUB +/******************************************************************************* + * Name: usbhost_rh_connect + * + * Description: + * Registers USB host root hub + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the call to + * the class create() method. + * + * Returned Value: + * + * Assumptions: + * + *******************************************************************************/ + +int usbhost_rh_connect(FAR struct usbhost_driver_s *drvr); +#endif #undef EXTERN #if defined(__cplusplus)