diff --git a/drivers/usbhost/usbhost_enumerate.c b/drivers/usbhost/usbhost_enumerate.c index 659a94f0619..899afd5274f 100644 --- a/drivers/usbhost/usbhost_enumerate.c +++ b/drivers/usbhost/usbhost_enumerate.c @@ -71,9 +71,10 @@ static inline int usbhost_devdesc(const struct usb_devdesc_s *devdesc, FAR struct usbhost_id_s *id); static inline int usbhost_configdesc(const uint8_t *configdesc, int desclen, FAR struct usbhost_id_s *id); -static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass, +static inline int usbhost_classbind(FAR struct usbhost_hub_s *hub, const uint8_t *configdesc, int desclen, - FAR struct usbhost_id_s *id); + struct usbhost_id_s *id, + FAR struct usbhost_class_s **devclass); /******************************************************************************* * Private Data @@ -221,10 +222,12 @@ static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen, * *******************************************************************************/ -static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass, +static inline int usbhost_classbind(FAR struct usbhost_hub_s *hub, const uint8_t *configdesc, int desclen, - FAR struct usbhost_id_s *id) + struct usbhost_id_s *id, + FAR struct usbhost_class_s **usbclass) { + FAR struct usbhost_class_s *devclass; FAR const struct usbhost_registry_s *reg; int ret = -EINVAL; @@ -232,17 +235,16 @@ static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass, reg = usbhost_findclass(id); uvdbg("usbhost_findclass: %p\n", reg); - if (reg != NULL) { /* Yes.. there is a class for this device. Get an instance of * its interface. */ - ret = CLASS_CREATE(reg, devclass, id); - uvdbg("CLASS_CREATE: %p\n", devclass->priv); - - if (devclass->priv != NULL) + ret = -ENOMEM; + devclass = CLASS_CREATE(reg, hub, id); + uvdbg("CLASS_CREATE: %p\n", devclass); + if (devclass != NULL) { /* Then bind the newly instantiated class instance */ @@ -256,6 +258,10 @@ static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass, udbg("CLASS_CONNECT failed: %d\n", ret); CLASS_DISCONNECTED(devclass); } + else + { + *usbclass = devclass; + } } } @@ -281,22 +287,24 @@ static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass, * charge of the sequence of operations. * * Input Parameters: - * 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 + * hub - The hub that manages the new class. + * devclass - If the class driver for the device is successful located + * and bound to the hub, the allocated class instance is returned into + * this caller-provided memory location. * * 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_class_s *devclass) +int usbhost_enumerate(FAR struct usbhost_hub_s *hub, + FAR struct usbhost_class_s **devclass) { FAR struct usb_ctrlreq_s *ctrlreq = NULL; struct usbhost_devinfo_s devinfo; @@ -308,20 +316,20 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) FAR uint8_t *buffer = NULL; int ret; - DEBUGASSERT(devclass != NULL && devclass->drvr != NULL); + DEBUGASSERT(hub != NULL && hub->drvr != NULL); /* Allocate descriptor buffers for use in this function. We will need two: * One for the request and one for the data buffer. */ - ret = DRVR_ALLOC(devclass->drvr, (FAR uint8_t **)&ctrlreq, &maxlen); + ret = DRVR_ALLOC(hub->drvr, (FAR uint8_t **)&ctrlreq, &maxlen); if (ret != OK) { udbg("DRVR_ALLOC failed: %d\n", ret); return ret; } - ret = DRVR_ALLOC(devclass->drvr, &buffer, &maxlen); + ret = DRVR_ALLOC(hub->drvr, &buffer, &maxlen); if (ret != OK) { udbg("DRVR_ALLOC failed: %d\n", ret); @@ -330,7 +338,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) /* Get information about the connected device */ - ret = DRVR_GETDEVINFO(devclass->drvr, &devinfo); + ret = DRVR_GETDEVINFO(hub->drvr, &devinfo); if (ret != OK) { udbg("DRVR_GETDEVINFO failed: %d\n", ret); @@ -367,7 +375,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) /* Configure EP0 with the initial maximum packet size */ - DRVR_EP0CONFIGURE(devclass->drvr, devclass->ep0, 0, maxpacketsize); + DRVR_EP0CONFIGURE(hub->drvr, hub->ep0, 0, maxpacketsize); /* Read first bytes of the device descriptor */ @@ -377,7 +385,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, descsize); - ret = DRVR_CTRLIN(devclass->drvr, devclass->ep0, ctrlreq, buffer); + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, buffer); if (ret != OK) { udbg("ERROR: Failed to get device descriptor, length=%d: %d\n", @@ -392,17 +400,17 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) /* And reconfigure EP0 with the correct maximum packet size */ - DRVR_EP0CONFIGURE(devclass->drvr, devclass->ep0, 0, maxpacketsize); + DRVR_EP0CONFIGURE(hub->drvr, hub->ep0, 0, maxpacketsize); /* Set the USB device address */ ctrlreq->type = USB_REQ_DIR_OUT | USB_REQ_RECIPIENT_DEVICE; ctrlreq->req = USB_REQ_SETADDRESS; - usbhost_putle16(ctrlreq->value, ((uint16_t)devclass->addr << 8)); + usbhost_putle16(ctrlreq->value, ((uint16_t)hub->funcaddr << 8)); usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, 0); - ret = DRVR_CTRLOUT(devclass->drvr, devclass->ep0, ctrlreq, NULL); + ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: Failed to set address: %d\n"); @@ -413,8 +421,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) /* And reconfigure EP0 with the correct address */ - DRVR_EP0CONFIGURE(devclass->drvr, devclass->ep0, devclass->addr, - maxpacketsize); + DRVR_EP0CONFIGURE(hub->drvr, hub->ep0, hub->funcaddr, maxpacketsize); /* Now read the full device descriptor (if we have not already done so) */ @@ -426,7 +433,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC); - ret = DRVR_CTRLIN(devclass->drvr, devclass->ep0, ctrlreq, buffer); + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, buffer); if (ret != OK) { udbg("ERROR: Failed to get device descriptor, length=%d: %d\n", @@ -454,7 +461,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC); - ret = DRVR_CTRLIN(devclass->drvr, devclass->ep0, ctrlreq, buffer); + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, buffer); if (ret != OK) { udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n", @@ -477,7 +484,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, cfglen); - ret = DRVR_CTRLIN(devclass->drvr, devclass->ep0, ctrlreq, buffer); + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, buffer); if (ret != OK) { udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n", @@ -493,7 +500,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, 0); - ret = DRVR_CTRLOUT(devclass->drvr, devclass->ep0, ctrlreq, NULL); + ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: Failed to set configuration: %d\n", ret); @@ -528,21 +535,21 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) * will begin configuring the device. */ - ret = usbhost_classbind(devclass, buffer, cfglen, &id); + ret = usbhost_classbind(hub, buffer, cfglen, &id, devclass); if (ret != OK) { - udbg("ERROR: Failed to bind class: %d\n", ret); + udbg("ERROR: usbhost_classbind returned %d\n", ret); } errout: if (buffer != NULL) { - DRVR_FREE(devclass->drvr, buffer); + DRVR_FREE(hub->drvr, buffer); } if (ctrlreq) { - DRVR_FREE(devclass->drvr, (FAR uint8_t *)ctrlreq); + DRVR_FREE(hub->drvr, (FAR uint8_t *)ctrlreq); } return ret; diff --git a/drivers/usbhost/usbhost_hidkbd.c b/drivers/usbhost/usbhost_hidkbd.c index 9b07ad3e6ee..41697d97ee5 100644 --- a/drivers/usbhost/usbhost_hidkbd.c +++ b/drivers/usbhost/usbhost_hidkbd.c @@ -198,7 +198,7 @@ struct usbhost_state_s /* This is an instance of the USB host driver bound to this class instance */ - struct usbhost_driver_s *drvr; + struct usbhost_hub_s *hub; /* The hub that manages the endpoint */ /* The remainder of the fields are provide o the keyboard class driver */ @@ -322,7 +322,7 @@ static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv); /* struct usbhost_registry_s methods */ -static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, +static struct usbhost_class_s *usbhost_create(FAR struct usbhost_hub_s *hub, FAR const struct usbhost_id_s *id); /* struct usbhost_class_s methods */ @@ -759,9 +759,12 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev static void usbhost_destroy(FAR void *arg) { FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg; + FAR struct usbhost_hub_s *hub; char devname[DEV_NAMELEN]; - DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv != NULL && priv->hub != NULL); + hub = priv->hub; + uvdbg("crefs: %d\n", priv->crefs); /* Unregister the driver */ @@ -778,12 +781,12 @@ static void usbhost_destroy(FAR void *arg) if (priv->epin) { - DRVR_EPFREE(priv->drvr, priv->epin); + DRVR_EPFREE(hub->drvr, priv->epin); } if (priv->epout) { - DRVR_EPFREE(priv->drvr, priv->epout); + DRVR_EPFREE(hub->drvr, priv->epout); } /* Free any transfer buffers */ @@ -797,7 +800,7 @@ static void usbhost_destroy(FAR void *arg) /* Disconnect the USB host device */ - DRVR_DISCONNECT(priv->drvr); + DRVR_DISCONNECT(hub->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 @@ -1001,6 +1004,7 @@ static inline void usbhost_encodescancode(FAR struct usbhost_state_s *priv, static int usbhost_kbdpoll(int argc, char *argv[]) { FAR struct usbhost_state_s *priv; + FAR struct usbhost_hub_s *hub; FAR struct usb_ctrlreq_s *ctrlreq; #ifndef CONFIG_HIDKBD_NODEBOUNCE uint8_t lastkey[6] = {0, 0, 0, 0, 0, 0}; @@ -1025,7 +1029,8 @@ static int usbhost_kbdpoll(int argc, char *argv[]) */ priv = g_priv; - DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv != NULL && priv->hub); + hub = priv->hub; priv->polling = true; priv->crefs++; @@ -1065,7 +1070,7 @@ static int usbhost_kbdpoll(int argc, char *argv[]) /* Send HID report request */ - ret = DRVR_CTRLIN(priv->drvr, ctrlreq, priv->tbuffer); + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, priv->tbuffer); usbhost_givesem(&priv->exclsem); /* Check for errors -- Bail if an excessive number of errors @@ -1291,6 +1296,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, FAR const uint8_t *configdesc, int desclen, uint8_t funcaddr) { + FAR struct usbhost_hub_s *hub; FAR struct usb_cfgdesc_s *cfgdesc; FAR struct usb_desc_s *desc; FAR struct usbhost_epdesc_s epindesc; @@ -1300,9 +1306,9 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, bool done = false; int ret; - DEBUGASSERT(priv != NULL && - configdesc != NULL && + DEBUGASSERT(priv != NULL && priv->hub != NULL && configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s)); + hub = priv->hub; /* Keep the compiler from complaining about uninitialized variables */ @@ -1489,7 +1495,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, * IN endpoint. */ - ret = DRVR_EPALLOC(priv->drvr, &epindesc, &priv->epin); + ret = DRVR_EPALLOC(hub->drvr, &epindesc, &priv->epin); if (ret != OK) { udbg("ERROR: Failed to allocate interrupt IN endpoint\n"); @@ -1503,11 +1509,11 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, if ((found & USBHOST_EPOUTFOUND) != 0) { - ret = DRVR_EPALLOC(priv->drvr, &epoutdesc, &priv->epout); + ret = DRVR_EPALLOC(hub->drvr, &epoutdesc, &priv->epout); if (ret != OK) { udbg("ERROR: Failed to allocate interrupt OUT endpoint\n"); - (void)DRVR_EPFREE(priv->drvr, priv->epin); + (void)DRVR_EPFREE(hub->drvr, priv->epin); return ret; } } @@ -1715,8 +1721,12 @@ static void usbhost_putle32(uint8_t *dest, uint32_t val) static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv) { - DEBUGASSERT(priv && priv->tbuffer == NULL); - return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen); + FAR struct usbhost_hub_s *hub; + + DEBUGASSERT(priv != NULL && priv->hub != NULL && priv->tbuffer == NULL); + hub = priv->hub; + + return DRVR_ALLOC(hub->drvr, &priv->tbuffer, &priv->tbuflen); } /**************************************************************************** @@ -1736,13 +1746,16 @@ static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv) static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv) { + FAR struct usbhost_hub_s *hub; int result = OK; + DEBUGASSERT(priv); if (priv->tbuffer) { - DEBUGASSERT(priv->drvr); - result = DRVR_FREE(priv->drvr, priv->tbuffer); + DEBUGASSERT(priv->hub); + hub = priv->hub; + result = DRVR_FREE(hub->drvr, priv->tbuffer); priv->tbuffer = NULL; priv->tbuflen = 0; } @@ -1766,9 +1779,7 @@ static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv) * USB ports and multiple USB devices simultaneously connected. * * Input Parameters: - * 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. + * hub - The hub that manages the new class instance. * id - In the case where the device supports multiple base classes, * subclasses, or protocols, this specifies which to configure for. * @@ -1776,13 +1787,14 @@ static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv) * 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 + * will fail only if the hub input parameter is NULL or if there are * insufficient resources to create another USB host class instance. * ****************************************************************************/ -static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, - FAR const struct usbhost_id_s *id) +static FAR struct usbhost_class_s * + usbhost_create(FAR struct usbhost_hub_s *hub, + FAR const struct usbhost_id_s *id) { FAR struct usbhost_state_s *priv; @@ -1801,6 +1813,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d { /* Initialize class method function pointers */ + priv->usbclass.hub = hub; priv->usbclass.connect = usbhost_connect; priv->usbclass.disconnected = usbhost_disconnected; @@ -1815,9 +1828,9 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d sem_init(&priv->exclsem, 0, 1); sem_init(&priv->waitsem, 0, 0); - /* Bind the driver to the storage class instance */ + /* Bind the hub to the storage class instance */ - priv->drvr = drvr; + priv->hub = hub; /* Return the instance of the USB keyboard class driver */ diff --git a/drivers/usbhost/usbhost_hub.c b/drivers/usbhost/usbhost_hub.c index 97f3bbc9b94..e8caa678063 100644 --- a/drivers/usbhost/usbhost_hub.c +++ b/drivers/usbhost/usbhost_hub.c @@ -84,7 +84,7 @@ * hub class. */ -struct usbhost_hubdev_s +struct usbhost_hubpriv_s { FAR struct usb_ctrlreq_s *ctrlreq; /* Allocated control request */ FAR uint8_t *buffer; /* Allocated buffer */ @@ -109,6 +109,16 @@ struct usbhost_hubdev_s /* Pointer to child devices */ }; +/* This represents the hub class structure. It must be cast compatible + * with struct usbhost_class_s. + */ + +struct usbhost_hubclass_s +{ + struct usbhost_class_s hubclass; /* Publicly visible class data */ + struct usbhost_hubpriv_s hubpriv; /* Private class data */ +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -117,10 +127,11 @@ struct usbhost_hubdev_s 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, +static inline FAR struct usbhost_hub_s *usbhost_allochub( + FAR struct usbhost_driver_s *drvr, FAR struct usbhost_class_s *hubclass, uint8_t speed, uint8_t port); +static inline void usbhost_freehub(FAR struct usbhost_hub_s *hub); static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass); /* Worker thread actions */ @@ -144,7 +155,8 @@ static void usbhost_callback(FAR void *arg, int result); /* struct usbhost_registry_s methods */ -static int usbhost_create(FAR struct usbhost_class_s *hubclass, +static FAR struct usbhost_class_s *usbhost_create( + FAR struct usbhost_hub_s *drvr, FAR const struct usbhost_id_s *id); /* struct usbhost_class_s methods */ @@ -230,7 +242,7 @@ static inline void usbhost_freeaddr(uint8_t addr) } /**************************************************************************** - * Name: usbhost_allocclass + * Name: usbhost_allochub * * Description: * This is really part of the logic that implements the create() method @@ -248,81 +260,115 @@ static inline void usbhost_freeaddr(uint8_t addr) * ****************************************************************************/ -static inline FAR struct usbhost_class_s * - usbhost_allocclass(FAR struct usbhost_driver_s *drvr, +static inline FAR struct usbhost_hub_s * + usbhost_allochub(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_class_s *hubclass, uint8_t speed, uint8_t port) { - FAR struct usbhost_hubdev_s *priv; - FAR struct usbhost_class_s *devclass; + FAR struct usbhost_hubpriv_s *priv; + FAR struct usbhost_hub_s *child; + FAR struct usbhost_hub_s *parent; - DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; + DEBUGASSERT(hubclass != NULL); + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; + + DEBUGASSERT(hubclass->hub); + parent = hubclass->hub; /* We are not executing from an interrupt handler so we can just call * kmm_malloc() to get memory for the class instance. */ DEBUGASSERT(!up_interrupt_context()); - devclass = (FAR struct usbhost_class_s *) - kmm_malloc(sizeof(struct usbhost_class_s)); + child = (FAR struct usbhost_hub_s *) + kmm_malloc(sizeof(struct usbhost_hub_s)); - uvdbg("Allocated: %p\n", devclass); + uvdbg("Allocated: %p\n", child); - if (devclass != NULL) + if (child != NULL) { struct usbhost_epdesc_s epdesc; int ret; - devclass->addr = usbhost_allocaddr(); - devclass->speed = speed; - devclass->drvr = drvr; + child->drvr = drvr; + child->parent = parent; + child->tt = NULL; + child->funcaddr = usbhost_allocaddr(); + child->speed = speed; + child->rhport = 0; - devclass->parent = hubclass; - devclass->priv = NULL; - - devclass->tt = NULL; - devclass->rhport = 0; - - if (!ROOTHUB(devclass)) + if (!ROOTHUB(parent)) { - if (hubclass->tt != NULL) + if (parent->tt != NULL) { - devclass->tt = hubclass->tt; - devclass->rhport = hubclass->rhport; + child->tt = parent->tt; + child->rhport = parent->rhport; } - else if ((devclass->speed != USB_SPEED_HIGH) && - (hubclass->speed == USB_SPEED_HIGH)) + else if ((child->speed != USB_SPEED_HIGH) && + (parent->speed == USB_SPEED_HIGH)) { - devclass->tt = &priv->tt; - devclass->rhport = port; + child->tt = &priv->tt; + child->rhport = port; } } - epdesc.devclass = devclass; + epdesc.hub = child; epdesc.addr = 0; epdesc.in = 0; epdesc.xfrtype = USB_EP_ATTR_XFER_CONTROL; epdesc.interval = 0; epdesc.mxpacketsize = 8; - ret = DRVR_EPALLOC(devclass->drvr, &epdesc, &devclass->ep0); + ret = DRVR_EPALLOC(drvr, &epdesc, &child->ep0); if (ret != OK) { udbg("ERROR: Failed to allocate ep0: %d\n", ret); - usbhost_freeclass(devclass); - devclass = NULL; + usbhost_freehub(child); + child = NULL; } } - return devclass; + return child; +} + +/**************************************************************************** + * Name: usbhost_freehub + * + * Description: + * Free a hub instance previously allocated by usbhost_allochub(). + * + * Input Parameters: + * hub - A reference to the hub instance to be freed. + * + * Returned Values: + * None + * + ****************************************************************************/ + +static inline void usbhost_freehub(FAR struct usbhost_hub_s *hub) +{ + if (hub && !ROOTHUB(hub)) + { + if (hub->ep0 != NULL) + { + DRVR_EPFREE(hub->drvr, hub->ep0); + hub->ep0 = NULL; + } + + usbhost_freeaddr(hub->funcaddr); + + /* Free the hub instance */ + + uvdbg("Freeing: %p\n", hub); + kmm_free(hub); + } } /**************************************************************************** * Name: usbhost_freeclass * * Description: - * Free a class instance previously allocated by usbhost_allocclass(). + * Free a class instance previously allocated by usbhost_create(). * * Input Parameters: * devclass - A reference to the class instance to be freed. @@ -336,17 +382,11 @@ static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass) { DEBUGASSERT(devclass != NULL); - if (devclass->ep0 != NULL) - { - DRVR_EPFREE(devclass->drvr, devclass->ep0); - devclass->ep0 = NULL; - } + /* Free the bound hub */ - usbhost_freeaddr(devclass->addr); + usbhost_freehub(devclass->hub); - /* Free the class instance (calling sched_free() in case we are executing - * from an interrupt handler. - */ + /* Free the class instance */ uvdbg("Freeing: %p\n", devclass); kmm_free(devclass); @@ -371,40 +411,38 @@ static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass) static void usbhost_destroy(FAR void *arg) { FAR struct usbhost_class_s *hubclass = (FAR struct usbhost_class_s *)arg; - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hubpriv_s *priv; + FAR struct usbhost_hub_s *hub; int i; DEBUGASSERT(hubclass != NULL); + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; - if (priv != NULL) + uvdbg("crefs: %d\n", priv->crefs); + + if (priv->intin) { - uvdbg("crefs: %d\n", priv->crefs); - - if (priv->intin) - { - DRVR_EPFREE(hubclass->drvr, priv->intin); - } - - /* Destroy the semaphores */ - - sem_destroy(&priv->exclsem); - - /* Destroy allocated child classes */ - - for (i = 0; i < USBHUB_MAX_PORTS; i++) - { - if (priv->childclass[i] != NULL) - { - CLASS_DISCONNECTED(priv->childclass[i]); - } - } - - /* Free private class */ - - kmm_free(hubclass->priv); + DEBUGASSERT(hubclass->hub); + hub = hubclass->hub; + DRVR_EPFREE(hub->drvr, priv->intin); } + /* Destroy the semaphores */ + + sem_destroy(&priv->exclsem); + + /* Destroy allocated child classes */ + + for (i = 0; i < USBHUB_MAX_PORTS; i++) + { + if (priv->childclass[i] != NULL) + { + CLASS_DISCONNECTED(priv->childclass[i]); + } + } + + /* Free the allocated class structure */ + usbhost_freeclass(hubclass); } @@ -435,7 +473,8 @@ static void usbhost_destroy(FAR void *arg) static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass, FAR const uint8_t *configdesc, int desclen) { - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hubpriv_s *priv; + FAR struct usbhost_hub_s *hub; FAR struct usb_cfgdesc_s *cfgdesc; FAR struct usb_desc_s *desc; FAR struct usbhost_epdesc_s intindesc; @@ -443,17 +482,19 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass, uint8_t found = 0; int ret; - DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; + DEBUGASSERT(hubclass != NULL); + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; - DEBUGASSERT(configdesc != NULL && - desclen >= sizeof(struct usb_cfgdesc_s)); + DEBUGASSERT(hubclass->hub); + hub = hubclass->hub; + + DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s)); /* Initialize the interrupt IN endpoint information (only to prevent * compiler complaints) */ - intindesc.devclass = hubclass; + intindesc.hub = hub; intindesc.addr = 0; intindesc.in = true; intindesc.xfrtype = USB_EP_ATTR_XFER_INT; @@ -586,11 +627,11 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass, /* We are good... Allocate the interrupt IN endpoint */ - ret = DRVR_EPALLOC(hubclass->drvr, &intindesc, &priv->intin); + ret = DRVR_EPALLOC(hub->drvr, &intindesc, &priv->intin); if (ret != OK) { udbg("ERROR: Failed to allocate Interrupt IN endpoint: %d\n", ret); - (void)DRVR_EPFREE(hubclass->drvr, priv->intin); + (void)DRVR_EPFREE(hub->drvr, priv->intin); return ret; } @@ -621,14 +662,18 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass, static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass) { - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hubpriv_s *priv; + FAR struct usbhost_hub_s *hub; FAR struct usb_ctrlreq_s *ctrlreq; struct usb_hubdesc_s hubdesc; uint16_t hubchar; int ret; - DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; + DEBUGASSERT(hubclass != NULL); + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; + + DEBUGASSERT(hubclass->hub); + hub = hubclass->hub; /* Get the hub descriptor */ @@ -641,8 +686,7 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, USB_SIZEOF_HUBDESC); - ret = DRVR_CTRLIN(hubclass->drvr, hubclass->ep0, ctrlreq, - (FAR uint8_t *)&hubdesc); + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, (FAR uint8_t *)&hubdesc); if (ret != OK) { udbg("ERROR: Failed to read hub descriptor: %d\n", ret); @@ -686,13 +730,17 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass) static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on) { - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hubpriv_s *priv; + FAR struct usbhost_hub_s *hub; FAR struct usb_ctrlreq_s *ctrlreq; - DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; + DEBUGASSERT(hubclass != NULL); + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; - if (on || ROOTHUB(hubclass)) + DEBUGASSERT(hubclass->hub); + hub = hubclass->hub; + + if (on || ROOTHUB(hub)) { uint16_t req; int port, ret; @@ -719,7 +767,7 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on) usbhost_putle16(ctrlreq->index, port); usbhost_putle16(ctrlreq->len, 0); - ret = DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL); + ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: Failed to power %d port %d: %d\n", on, port, ret); @@ -752,7 +800,9 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on) static void usbhost_hubevent(FAR void *arg) { FAR struct usbhost_class_s *hubclass; - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hub_s *newhub; + FAR struct usbhost_hub_s *hub; + FAR struct usbhost_hubpriv_s *priv; FAR struct usb_ctrlreq_s *ctrlreq; struct usb_portstatus_s portstatus; uint16_t status; @@ -765,12 +815,13 @@ static void usbhost_hubevent(FAR void *arg) DEBUGASSERT(arg != NULL); hubclass = (FAR struct usbhost_class_s *)arg; + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; - DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; - + DEBUGASSERT(priv->ctrlreq); ctrlreq = priv->ctrlreq; - DEBUGASSERT(ctrlreq); + + DEBUGASSERT(hubclass->hub); + hub = hubclass->hub; statusmap = priv->buffer[0]; @@ -795,7 +846,7 @@ static void usbhost_hubevent(FAR void *arg) usbhost_putle16(ctrlreq->index, port); usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS); - ret = DRVR_CTRLIN(hubclass->drvr, hubclass->ep0, ctrlreq, + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, (FAR uint8_t *)&portstatus); if (ret != OK) { @@ -820,7 +871,7 @@ static void usbhost_hubevent(FAR void *arg) usbhost_putle16(ctrlreq->index, port); usbhost_putle16(ctrlreq->len, 0); - ret = DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL); + ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: Failed to clear port %d change mask %x: %d\n", @@ -856,7 +907,7 @@ static void usbhost_hubevent(FAR void *arg) usbhost_putle16(ctrlreq->index, port); usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS); - ret = DRVR_CTRLIN(hubclass->drvr, hubclass->ep0, ctrlreq, + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, (FAR uint8_t *)&portstatus); if (ret != OK) { @@ -889,7 +940,7 @@ static void usbhost_hubevent(FAR void *arg) usbhost_putle16(ctrlreq->index, port); usbhost_putle16(ctrlreq->len, 0); - (void)DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL); + (void)DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL); } debouncetime += 25; @@ -912,7 +963,7 @@ static void usbhost_hubevent(FAR void *arg) usbhost_putle16(ctrlreq->index, port); usbhost_putle16(ctrlreq->len, 0); - ret = DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL); + ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: ailed to reset port %d: %d\n", port, ret); @@ -927,7 +978,7 @@ static void usbhost_hubevent(FAR void *arg) usbhost_putle16(ctrlreq->index, port); usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS); - ret = DRVR_CTRLIN(hubclass->drvr, hubclass->ep0, ctrlreq, + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, (FAR uint8_t *)&portstatus); if (ret != OK) { @@ -954,7 +1005,7 @@ static void usbhost_hubevent(FAR void *arg) usbhost_putle16(ctrlreq->index, port); usbhost_putle16(ctrlreq->len, 0); - (void)DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL); + (void)DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL); } if (status & USBHUB_PORT_STAT_HIGH_SPEED) @@ -970,25 +1021,22 @@ static void usbhost_hubevent(FAR void *arg) speed = USB_SPEED_FULL; } - /* Allocate new class and enumerate */ + /* Allocate new hub class and enumerate */ - priv->childclass[port] = - usbhost_allocclass(hubclass->drvr, hubclass, speed, port); - - if (priv->childclass[port] != NULL) + newhub = usbhost_allochub(hub->drvr, hubclass, speed, port); + if (newhub) { + udbg("ERROR: Failed to allocated class\n"); uvdbg("enumerate port %d speed %d\n", port, speed); -#if 0 - ret = usbhost_enumerate(priv->childclass[port]); + ret = usbhost_enumerate(newhub, &priv->childclass[port]); if (ret != OK) { udbg("ERROR: Failed to enumerate port %d: %d\n", port, ret); + usbhost_freehub(hub); } -#endif } - } else { @@ -1016,8 +1064,7 @@ static void usbhost_hubevent(FAR void *arg) /* Get the number hub event */ - ret = DRVR_ASYNCH(hubclass->drvr, priv->intin, - (FAR uint8_t *)priv->ctrlreq, + ret = DRVR_ASYNCH(hub->drvr, priv->intin, (FAR uint8_t *)priv->ctrlreq, sizeof(struct usb_ctrlreq_s), usbhost_callback, hubclass); if (ret != OK) @@ -1084,13 +1131,11 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val) static void usbhost_callback(FAR void *arg, int result) { FAR struct usbhost_class_s *hubclass; - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hubpriv_s *priv; DEBUGASSERT(arg != NULL); hubclass = (FAR struct usbhost_class_s *)arg; - - DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; if (result != OK) { @@ -1117,9 +1162,7 @@ static void usbhost_callback(FAR void *arg, int result) * USB ports and multiple USB devices simultaneously connected. * * Input Parameters: - * 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. + * hub - The hub that manages the new class instance. * id - In the case where the device supports multiple base classes, * subclasses, or protocols, this specifies which to configure for. * @@ -1127,30 +1170,44 @@ static void usbhost_callback(FAR void *arg, int result) * 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 + * will fail only if the hub input parameter is NULL or if there are * insufficient resources to create another USB host class instance. * ****************************************************************************/ -static int usbhost_create(FAR struct usbhost_class_s *hubclass, - FAR const struct usbhost_id_s *id) +static FAR struct usbhost_class_s * + usbhost_create(FAR struct usbhost_hub_s *hub, + FAR const struct usbhost_id_s *id) { - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hubclass_s *alloc; + FAR struct usbhost_class_s *hubclass; + FAR struct usbhost_hubpriv_s *priv; size_t maxlen; int child; int ret; /* Allocate a USB host class instance */ - priv = kmm_zalloc(sizeof(struct usbhost_hubdev_s)); - if (priv == NULL) + alloc = kmm_zalloc(sizeof(struct usbhost_hubclass_s)); + if (alloc == NULL) { - return -ENOMEM; + return NULL; } + /* Initialize the public class structure */ + + hubclass = &alloc->hubclass; + hubclass->hub = hub; + hubclass->connect = usbhost_connect; + hubclass->disconnected = usbhost_disconnected; + + /* Initialize the private class structure */ + + priv = &alloc->hubpriv; + /* Allocate memory for control requests */ - ret = DRVR_ALLOC(hubclass->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen); + ret = DRVR_ALLOC(hub->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen); if (ret != OK) { udbg("DRVR_ALLOC failed: %d\n", ret); @@ -1159,19 +1216,13 @@ static int usbhost_create(FAR struct usbhost_class_s *hubclass, /* Allocate buffer for status change (INT) endpoint */ - ret = DRVR_IOALLOC(hubclass->drvr, &priv->buffer, 1); + ret = DRVR_IOALLOC(hub->drvr, &priv->buffer, 1); if (ret != OK) { udbg("DRVR_ALLOC failed: %d\n", ret); goto errout_with_ctrlreq; } - /* Initialize class method function pointers */ - - hubclass->connect = usbhost_connect; - hubclass->disconnected = usbhost_disconnected; - hubclass->priv = priv; - /* The initial reference count is 1... One reference is held by the driver */ priv->crefs = 1; @@ -1187,14 +1238,14 @@ static int usbhost_create(FAR struct usbhost_class_s *hubclass, priv->childclass[child] = NULL; } - return OK; + return hubclass; errout_with_ctrlreq: kmm_free(priv->ctrlreq); errout_with_hub: kmm_free(priv); - return ret; + return NULL; } /**************************************************************************** @@ -1236,14 +1287,14 @@ errout_with_hub: static int usbhost_connect(FAR struct usbhost_class_s *hubclass, FAR const uint8_t *configdesc, int desclen) { - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hubpriv_s *priv; + FAR struct usbhost_hub_s *hub; int ret; - DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; + DEBUGASSERT(hubclass != NULL); + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; - DEBUGASSERT(configdesc != NULL && - desclen >= sizeof(struct usb_cfgdesc_s)); + DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s)); /* Parse the configuration descriptor to get the endpoints */ @@ -1272,8 +1323,10 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass, /* INT request to periodically check port status */ - ret = DRVR_ASYNCH(hubclass->drvr, priv->intin, - (FAR uint8_t *)&priv->ctrlreq, + DEBUGASSERT(hubclass->hub); + hub = hubclass->hub; + + ret = DRVR_ASYNCH(hub->drvr, priv->intin, (FAR uint8_t *)&priv->ctrlreq, sizeof(struct usb_ctrlreq_s), usbhost_callback, hubclass); } @@ -1305,11 +1358,12 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass, static int usbhost_disconnected(struct usbhost_class_s *hubclass) { - FAR struct usbhost_hubdev_s *priv; + FAR struct usbhost_hubpriv_s *priv; + FAR struct usbhost_hub_s *hub; irqstate_t flags; - DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); - priv = (FAR struct usbhost_hubdev_s *)hubclass->priv; + DEBUGASSERT(hubclass != NULL); + priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; /* Set an indication to any users of the device that the device is no * longer available. @@ -1327,9 +1381,12 @@ static int usbhost_disconnected(struct usbhost_class_s *hubclass) ullvdbg("crefs: %d\n", priv->crefs); if (priv->crefs == 1) { + DEBUGASSERT(hubclass->hub); + hub = hubclass->hub; + /* Free buffer for status change (INT) endpoint */ - DRVR_IOFREE(hubclass->drvr, priv->buffer); + DRVR_IOFREE(hub->drvr, priv->buffer); /* Power off (for root hub only) */ (void)usbhost_hubpwr(hubclass, false); @@ -1371,76 +1428,4 @@ int usbhost_hubinit(void) return usbhost_registerclass(&g_hub); } -/******************************************************************************* - * Name: usbhost_rh_connect - * - * Description: - * Connects 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) -{ - struct usbhost_class_s *hubclass = NULL; - int ret = -ENOMEM; - - memset(g_addrmap, 0, 4*4); - - hubclass = usbhost_allocclass(drvr, NULL, drvr->speed, 1); - if (hubclass != NULL) - { - ret = usbhost_enumerate(hubclass); - if (ret != OK) - { - udbg("ERROR: failed to enumerate root hub: %d\n", ret); - } - else - { - drvr->roothub = hubclass; - uvdbg("Total class memory %d+%d\n", - sizeof(struct usbhost_class_s), sizeof(struct usbhost_hubdev_s)); - } - } - - return ret; -} - -/******************************************************************************* - * Name: usbhost_rh_disconnect - * - * Description: - * Disconnects 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_disconnect(FAR struct usbhost_driver_s *drvr) -{ - FAR struct usbhost_class_s *hubclass = drvr->roothub; - - if (hubclass != NULL) - { - CLASS_DISCONNECTED(hubclass); - - drvr->roothub = NULL; - } - - return OK; -} - #endif /* CONFIG_USBHOST_HUB */ diff --git a/drivers/usbhost/usbhost_storage.c b/drivers/usbhost/usbhost_storage.c index 04ee1baafe5..3666c995fe5 100644 --- a/drivers/usbhost/usbhost_storage.c +++ b/drivers/usbhost/usbhost_storage.c @@ -120,9 +120,9 @@ struct usbhost_state_s struct usbhost_class_s usbclass; - /* This is an instance of the USB host driver bound to this class instance */ + /* This is an instance of the USB hub bound to this class instance */ - struct usbhost_driver_s *drvr; + struct usbhost_hub_s *hub; /* The remainder of the fields are provide to the mass storage class */ @@ -228,7 +228,7 @@ static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *pri /* struct usbhost_registry_s methods */ -static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr, +static struct usbhost_class_s *usbhost_create(FAR struct usbhost_hub_s *hub, FAR const struct usbhost_id_s *id); /* struct usbhost_class_s methods */ @@ -679,6 +679,7 @@ usbhost_writecbw(size_t startsector, uint16_t blocksize, static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv) { FAR struct usb_ctrlreq_s *req = (FAR struct usb_ctrlreq_s *)priv->tbuffer; + FAR struct usbhost_hub_s *hub; DEBUGASSERT(priv && priv->tbuffer); int ret; @@ -688,12 +689,16 @@ static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv) */ uvdbg("Request maximum logical unit number\n"); + memset(req, 0, sizeof(struct usb_ctrlreq_s)); req->type = USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE; req->req = USBMSC_REQ_GETMAXLUN; usbhost_putle16(req->len, 1); - ret = DRVR_CTRLIN(priv->drvr, req, priv->tbuffer); + DEBUGASSERT(priv->hub); + hub = priv->hub; + + ret = DRVR_CTRLIN(hub->drvr, hub->ep0, req, priv->tbuffer); if (ret != OK) { /* Devices that do not support multiple LUNs may stall this command. @@ -723,13 +728,13 @@ static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv) /* Construct and send the CBW */ usbhost_testunitreadycbw(cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); if (result == OK) { /* Receive the CSW */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); if (result == OK) { @@ -757,19 +762,19 @@ static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv) /* Construct and send the CBW */ usbhost_requestsensecbw(cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); if (result == OK) { /* Receive the sense data response */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF); if (result == OK) { /* Receive the CSW */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); if (result == OK) { @@ -799,13 +804,13 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv) /* Construct and send the CBW */ usbhost_readcapacitycbw(cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); if (result == OK) { /* Receive the read capacity CBW IN response */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, SCSIRESP_READCAPACITY10_SIZEOF); if (result == OK) { @@ -817,7 +822,7 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv) /* Receive the CSW */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); if (result == OK) { @@ -846,13 +851,13 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv) /* Construct and send the CBW */ usbhost_inquirycbw(cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); if (result == OK) { /* Receive the CBW IN response */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, SCSIRESP_INQUIRY_SIZEOF); if (result == OK) { @@ -865,7 +870,7 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv) /* Receive the CSW */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); if (result == OK) { @@ -914,12 +919,12 @@ static void usbhost_destroy(FAR void *arg) if (priv->bulkout) { - DRVR_EPFREE(priv->drvr, priv->bulkout); + DRVR_EPFREE(priv->hub->drvr, priv->bulkout); } if (priv->bulkin) { - DRVR_EPFREE(priv->drvr, priv->bulkin); + DRVR_EPFREE(priv->hub->drvr, priv->bulkin); } /* Free any transfer buffers */ @@ -932,7 +937,7 @@ static void usbhost_destroy(FAR void *arg) /* Disconnect the USB host device */ - DRVR_DISCONNECT(priv->drvr); + DRVR_DISCONNECT(priv->hub->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 @@ -1149,18 +1154,18 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv, /* We are good... Allocate the endpoints */ - ret = DRVR_EPALLOC(priv->drvr, &boutdesc, &priv->bulkout); + ret = DRVR_EPALLOC(priv->hub->drvr, &boutdesc, &priv->bulkout); if (ret != OK) { udbg("ERROR: Failed to allocate Bulk OUT endpoint\n"); return ret; } - ret = DRVR_EPALLOC(priv->drvr, &bindesc, &priv->bulkin); + ret = DRVR_EPALLOC(priv->hub->drvr, &bindesc, &priv->bulkin); if (ret != OK) { udbg("ERROR: Failed to allocate Bulk IN endpoint\n"); - (void)DRVR_EPFREE(priv->drvr, priv->bulkout); + (void)DRVR_EPFREE(priv->hub->drvr, priv->bulkout); return ret; } @@ -1552,7 +1557,7 @@ static void usbhost_putbe32(uint8_t *dest, uint32_t val) static inline int usbhost_talloc(FAR struct usbhost_state_s *priv) { DEBUGASSERT(priv && priv->tbuffer == NULL); - return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen); + return DRVR_ALLOC(priv->hub->drvr, &priv->tbuffer, &priv->tbuflen); } /**************************************************************************** @@ -1577,8 +1582,8 @@ static inline int usbhost_tfree(FAR struct usbhost_state_s *priv) if (priv->tbuffer) { - DEBUGASSERT(priv->drvr); - result = DRVR_FREE(priv->drvr, priv->tbuffer); + DEBUGASSERT(priv->hub->drvr); + result = DRVR_FREE(priv->hub->drvr, priv->tbuffer); priv->tbuffer = NULL; priv->tbuflen = 0; } @@ -1631,9 +1636,7 @@ static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *pri * USB ports and multiple USB devices simultaneously connected. * * Input Parameters: - * 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. + * hub - The hub that manages the new class instance. * id - In the case where the device supports multiple base classes, * subclasses, or protocols, this specifies which to configure for. * @@ -1641,13 +1644,13 @@ static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *pri * 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 + * will fail only if the hub input parameter is NULL or if there are * insufficient resources to create another USB host class instance. * ****************************************************************************/ static FAR struct usbhost_class_s * -usbhost_create(FAR struct usbhost_driver_s *drvr, +usbhost_create(FAR struct usbhost_hub_s *hub, FAR const struct usbhost_id_s *id) { FAR struct usbhost_state_s *priv; @@ -1667,6 +1670,7 @@ usbhost_create(FAR struct usbhost_driver_s *drvr, { /* Initialize class method function pointers */ + priv->usbclass.hub = hub; priv->usbclass.connect = usbhost_connect; priv->usbclass.disconnected = usbhost_disconnected; @@ -1678,10 +1682,6 @@ usbhost_create(FAR struct usbhost_driver_s *drvr, sem_init(&priv->exclsem, 0, 1); - /* Bind the driver to the storage class instance */ - - priv->drvr = drvr; - /* NOTE: We do not yet know the geometry of the USB mass storage device */ /* Return the instance of the USB mass storage class */ @@ -2003,19 +2003,19 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, /* Construct and send the CBW */ usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); if (result == OK) { /* Receive the user data */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, buffer, priv->blocksize * nsectors); if (result == OK) { /* Receive the CSW */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); if (result == OK) { @@ -2096,19 +2096,19 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe /* Construct and send the CBW */ usbhost_writecbw(startsector, priv->blocksize, nsectors, cbw); - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); if (result == OK) { /* Send the user data */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkout, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout, (uint8_t*)buffer, priv->blocksize * nsectors); if (result == OK) { /* Receive the CSW */ - result = DRVR_TRANSFER(priv->drvr, priv->bulkin, + result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); if (result == OK) { diff --git a/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h index 15b97c41e6c..c6963f6bed3 100644 --- a/include/nuttx/usb/usbhost.h +++ b/include/nuttx/usb/usbhost.h @@ -61,29 +61,27 @@ * Name: ROOTHUB * * Description: - * Check for root hub + * Check if a hub instance is the root hub. * ************************************************************************************/ -#define ROOTHUB(devclass) ((devclass)->parent == NULL) +#define ROOTHUB(hub) ((hub)->parent == NULL) /************************************************************************************ * Name: CLASS_CREATE * * Description: - * This macro will call the create() method of struct usbhost_registry_s. The - * create() method 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 "session" to the class instance. Use of this create() method - * will support environments where there may be multiple USB ports and multiple - * USB devices simultaneously connected. + * This macro will call the create() method of struct usbhost_registry_s. The create() + * method 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 + * "session" to the class instance. Use of this create() method will support + * environments where there may be multiple USB ports and multiple USB devices + * simultaneously connected. * * Input Parameters: * reg - The USB host class registry entry previously obtained from a call to * usbhost_findclass(). - * 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. + * hub - The hub that manages the new class instance. * id - In the case where the device supports multiple base classes, subclasses, or * protocols, this specifies which to configure for. * @@ -91,7 +89,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 devclass input parameter is NULL or if there are insufficient resources to + * the drvr input parameter is NULL or if there are insufficient resources to * create another USB host class instance. * * Assumptions: @@ -101,7 +99,7 @@ * ************************************************************************************/ -#define CLASS_CREATE(reg, devclass, id) ((reg)->create(devclass, id)) +#define CLASS_CREATE(reg,hub,id) ((reg)->create(hub,id)) /************************************************************************************ * Name: CLASS_CONNECT @@ -567,7 +565,7 @@ struct usbhost_id_s * connected to the USB port. */ -struct usbhost_driver_s; /* Forward reference to the driver state structure */ +struct usbhost_hub_s; /* Forward reference to the hub state structure */ struct usbhost_class_s; /* Forward reference to the class state structure */ struct usbhost_registry_s { @@ -576,7 +574,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 @@ -585,14 +583,14 @@ struct usbhost_registry_s * simultaneously connected (see the CLASS_CREATE() macro above). */ - int (*create)(FAR struct usbhost_class_s *devclass, - FAR const struct usbhost_id_s *id); + FAR struct usbhost_class_s *(*create)(FAR struct usbhost_hub_s *hub, + 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 */ }; @@ -605,22 +603,34 @@ struct usbhost_registry_s typedef FAR void *usbhost_ep_t; +/* Every class connects to the host controller driver (HCD) via a hub. That + * may be an external hub or the internal, root hub. The root hub is managed + * by the HCD. This structure provides for the linkages in that event that + * an external hub. + */ + +struct usbhost_hub_s +{ + FAR struct usbhost_driver_s *drvr; /* Common host driver */ + usbhost_ep_t ep0; /* Control endpoint, ep0 */ +#ifdef CONFIG_USBHOST_HUB + FAR struct usbhost_hub_s *parent; /* Parent hub */ + FAR struct usb_hubtt_s *tt; /* Transaction translator hub */ +#endif + uint8_t funcaddr; /* Device function address */ + uint8_t speed; /* Device speed */ + uint8_t rhport; /* Root hub port index */ +}; + /* struct usbhost_class_s provides access from the USB host driver to the USB host * class implementation. */ struct usbhost_class_s { -#ifdef CONFIG_USBHOST_HUB - FAR struct usbhost_driver_s *drvr; /* Common host driver */ - FAR struct usbhost_class_s *parent; /* Parent class */ - usbhost_ep_t ep0; /* Control endpoint, ep0 */ - FAR struct usb_hubtt_s *tt; /* Transaction translator hub */ - FAR void *priv; /* Class specific private data */ - uint8_t addr; /* Device function address */ - uint8_t speed; /* Device speed */ - uint8_t rhport; /* Root hub port index */ -#endif + /* The hub used by this class instance */ + + FAR struct usbhost_hub_s *hub; /* Provides the configuration descriptor to the class. The configuration * descriptor contains critical information needed by the class in order to @@ -644,14 +654,14 @@ struct usbhost_class_s struct usbhost_epdesc_s { #ifdef CONFIG_USBHOST_HUB - FAR struct usbhost_class_s *devclass; /* Class */ + FAR struct usbhost_hub_s *hub; /* Hub that manages the endpoint */ #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 */ + 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 */ @@ -967,6 +977,10 @@ int usbhost_wlaninit(void); * 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 @@ -977,62 +991,24 @@ int usbhost_wlaninit(void); * charge of the sequence of operations. * * Input Parameters: - * 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 + * hub - The hub that manages the new class. + * devclass - If the class driver for the device is successful located + * and bound to the hub, the allocated class instance is returned into + * this caller-provided memory location. * * 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_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 - -/******************************************************************************* - * Name: usbhost_rh_disconnect - * - * Description: - * Disconnects 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: - * - *******************************************************************************/ - -#ifdef CONFIG_USBHOST_HUB -int usbhost_rh_disconnect(FAR struct usbhost_driver_s *drvr); -#endif +int usbhost_enumerate(FAR struct usbhost_hub_s *hub, + FAR struct usbhost_class_s **devclass); #undef EXTERN #if defined(__cplusplus)