From a6d9f0622c4409e731e685feab8907abb5d3be09 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 20 Apr 2015 07:45:11 -0600 Subject: [PATCH] USB hub: First steps to make interfaces backward compatible --- drivers/usbhost/Make.defs | 6 +- drivers/usbhost/usbhost_enumerate.c | 106 +-------- drivers/usbhost/usbhost_hub.c | 323 +++++++++++++++------------- include/nuttx/usb/usbhost.h | 98 ++------- 4 files changed, 208 insertions(+), 325 deletions(-) diff --git a/drivers/usbhost/Make.defs b/drivers/usbhost/Make.defs index ff6db3a3de..859f5ad83f 100644 --- a/drivers/usbhost/Make.defs +++ b/drivers/usbhost/Make.defs @@ -40,12 +40,16 @@ ifeq ($(CONFIG_USBHOST),y) # Include built-in USB host driver logic CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c -CSRCS += usbhost_enumerate.c usbhost_storage.c usbhost_devaddr.c +CSRCS += usbhost_enumerate.c usbhost_devaddr.c ifeq ($(CONFIG_USBHOST_HUB),y) CSRCS += usbhost_hub.c endif +ifeq ($(CONFIG_USBHOST_MSC),y) +CSRCS += usbhost_storage.c +endif + ifeq ($(CONFIG_USBHOST_HIDKBD),y) CSRCS += usbhost_hidkbd.c endif diff --git a/drivers/usbhost/usbhost_enumerate.c b/drivers/usbhost/usbhost_enumerate.c index 8f4d973c2b..0683ea13bc 100644 --- a/drivers/usbhost/usbhost_enumerate.c +++ b/drivers/usbhost/usbhost_enumerate.c @@ -67,8 +67,6 @@ static inline uint16_t usbhost_getle16(const uint8_t *val); static void usbhost_putle16(uint8_t *dest, uint16_t val); -static void usbhost_callback(FAR struct usbhost_transfer_s *xfer); - 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, @@ -116,19 +114,6 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val) dest[1] = val >> 8; } -/**************************************************************************** - * Name: usbhost_callback - * - * Description: - * - * - *******************************************************************************/ - -static void usbhost_callback(FAR struct usbhost_transfer_s *xfer) -{ - sem_post(&xfer->done); -} - /******************************************************************************* * Name: usbhost_devdesc * @@ -173,8 +158,8 @@ static inline int usbhost_devdesc(FAR const struct usb_devdesc_s *devdesc, static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen, struct usbhost_id_s *id) { - struct usb_cfgdesc_s *cfgdesc; - struct usb_ifdesc_s *ifdesc; + FAR struct usb_cfgdesc_s *cfgdesc; + FAR struct usb_ifdesc_s *ifdesc; int remaining; DEBUGASSERT(configdesc != NULL && cfglen >= USB_SIZEOF_CFGDESC); @@ -392,7 +377,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, descsize); - ret = usbhost_ctrlxfer(devclass, ctrlreq, buffer); + ret = DRVR_CTRLIN(devclass->drvr, ctrlreq, buffer); if (ret != OK) { udbg("ERROR: Failed to get device descriptor, length=%d: %d\n", @@ -417,7 +402,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, 0); - ret = usbhost_ctrlxfer(devclass, ctrlreq, NULL); + ret = DRVR_CTRLOUT(devclass->drvr, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: Failed to set address: %d\n"); @@ -441,7 +426,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC); - ret = usbhost_ctrlxfer(devclass, ctrlreq, buffer); + ret = DRVR_CTRLIN(devclass->drvr, ctrlreq, buffer); if (ret != OK) { udbg("ERROR: Failed to get device descriptor, length=%d: %d\n", @@ -469,7 +454,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC); - ret = usbhost_ctrlxfer(devclass, ctrlreq, buffer); + ret = DRVR_CTRLIN(devclass->drvr, ctrlreq, buffer); if (ret != OK) { udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n", @@ -492,7 +477,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, cfglen); - ret = usbhost_ctrlxfer(devclass, ctrlreq, buffer); + ret = DRVR_CTRLIN(devclass->drvr, ctrlreq, buffer); if (ret != OK) { udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n", @@ -508,7 +493,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass) usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, 0); - ret = usbhost_ctrlxfer(devclass, ctrlreq, NULL); + ret = DRVR_CTRLOUT(devclass->drvr, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: Failed to set configuration: %d\n", ret); @@ -562,78 +547,3 @@ errout: return ret; } - -/**************************************************************************** - * Name: usbhost_ctrlxfer - * - * Description: - * Free transfer buffer memory. - * - * Input Parameters: - * devclass - A reference to the class instance. - * ctrlreq - Describes the control request transfer - * buffer - Data accompanying the control transfer - * - * Returned Values: - * On sucess, 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, - FAR struct usb_ctrlreq_s *ctrlreq, - FAR uint8_t *buffer) -{ - struct usbhost_transfer_s xfer; - struct timespec timeout; - uint16_t len; - int ret; - - len = usbhost_getle16(ctrlreq->len); - xfer.buffer = buffer; - xfer.buflen = len; - xfer.len = len; - xfer.status = -EIO; - xfer.devclass = devclass; - xfer.ep = devclass->ep0; - xfer.callback = usbhost_callback; - - sem_init(&xfer.done, 0, 0); - -#ifdef CONFIG_USBHOST_HUB - if (ROOTHUB(devclass)) - { - ret = DRVR_RHCTRL(devclass->drvr, &xfer, ctrlreq); - } - else -#endif - { - if ((ctrlreq->type & USB_REQ_DIR_IN) != 0) - { - ret = DRVR_CTRLIN(devclass->drvr, &xfer, ctrlreq); - } - else - { - ret = DRVR_CTRLOUT(devclass->drvr, &xfer, ctrlreq); - } - } - - if (ret != OK) - { - goto out; - } - - timeout.tv_sec = 5; - timeout.tv_nsec = 1000*1000; - - ret = sem_timedwait(&xfer.done, &timeout); - if (ret == OK) - { - ret = xfer.status; - } - -out: - sem_destroy(&xfer.done); - - return ret; -} diff --git a/drivers/usbhost/usbhost_hub.c b/drivers/usbhost/usbhost_hub.c index e852654193..abccf798c2 100644 --- a/drivers/usbhost/usbhost_hub.c +++ b/drivers/usbhost/usbhost_hub.c @@ -3,6 +3,7 @@ * * Copyright (C) 2015 Gregory Nutt. All rights reserved. * Author: Kaushal Parikh + * Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -92,21 +93,23 @@ struct usbhost_hub_s { - volatile bool disconnected; /* TRUE: Device has been disconnected */ + FAR struct usb_ctrlreq_s *ctrlreq; /* Allocated control request */ + FAR uint8_t *buffer; /* Allocated buffer */ uint8_t ifno; /* Interface number */ + uint8_t nports; /* Number of ports */ + uint8_t lpsm; /* Logical power switching mode */ + uint8_t ocmode; /* Over current protection mode */ + uint8_t ctrlcurrent; /* Control current */ + volatile bool disconnected; /* TRUE: Device has been disconnected */ + bool compounddev; /* Hub is part of compound device */ + bool indicator; /* Port indicator */ + + uint16_t pwrondelay; /* Power on wait time in ms */ int16_t crefs; /* Reference count on the driver instance */ sem_t exclsem; /* Used to maintain mutual exclusive access */ - uint8_t nports; /* Number of ports */ - uint8_t lpsm; /* Logical power switching mode */ - bool compounddev; /* Hub is part of compound device */ - uint8_t ocmode; /* Over current protection mode */ - bool indicator; /* Port indicator */ - uint16_t pwrondelay; /* Power on wait time in ms */ - uint8_t ctrlcurrent; /* Control current */ - struct usb_hubtt_s tt; /* Transaction translator */ - struct usbhost_transfer_s intxfer; /* Interrupt IN endpoint */ + usbhost_ep_t intin; /* Interrupt IN endpoint */ struct usbhost_class_s *childclass[USBHUB_MAX_PORTS]; /* Pointer to child devices */ @@ -116,11 +119,6 @@ struct usbhost_hub_s * Private Function Prototypes ****************************************************************************/ -/* Semaphores */ - -static void usbhost_takesem(sem_t *sem); -#define usbhost_givesem(s) sem_post(s); - /* Memory allocation services */ static inline uint8_t usbhost_allocaddr(void); @@ -198,29 +196,6 @@ static uint32_t g_addrmap[4]; * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: usbhost_takesem - * - * Description: - * This is just a wrapper to handle the annoying behavior of semaphore - * waits that return due to the receipt of a signal. - * - ****************************************************************************/ - -static void usbhost_takesem(sem_t *sem) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(sem) != 0) - { - /* The only case that an error should occr here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - /**************************************************************************** * Name: usbhost_allocaddr * @@ -291,12 +266,12 @@ static inline FAR struct usbhost_class_s * 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. + * kmm_malloc() to get memory for the class instance. */ DEBUGASSERT(!up_interrupt_context()); devclass = (FAR struct usbhost_class_s *) - kmalloc(sizeof(struct usbhost_class_s)); + kmm_malloc(sizeof(struct usbhost_class_s)); uvdbg("Allocated: %p\n", devclass); @@ -313,20 +288,20 @@ static inline FAR struct usbhost_class_s * devclass->priv = NULL; devclass->tt = NULL; - devclass->ttport = 0; + devclass->rhport = 0; if (!ROOTHUB(devclass)) { if (hubclass->tt != NULL) { devclass->tt = hubclass->tt; - devclass->ttport = hubclass->ttport; + devclass->rhport = hubclass->rhport; } else if ((devclass->speed != USB_SPEED_HIGH) && (hubclass->speed == USB_SPEED_HIGH)) { devclass->tt = &priv->tt; - devclass->ttport = port; + devclass->rhport = port; } } @@ -380,7 +355,7 @@ static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass) */ uvdbg("Freeing: %p\n", devclass); - kfree(devclass); + kmm_free(devclass); } /**************************************************************************** @@ -412,9 +387,9 @@ static void usbhost_destroy(FAR void *arg) { uvdbg("crefs: %d\n", priv->crefs); - if (priv->intxfer.ep) + if (priv->intin) { - DRVR_EPFREE(hubclass->drvr, priv->intxfer.ep); + DRVR_EPFREE(hubclass->drvr, priv->intin); } /* Destroy the semaphores */ @@ -431,9 +406,9 @@ static void usbhost_destroy(FAR void *arg) } } - /* Clear priv class */ + /* Free private class */ - kfree(hubclass->priv); + kmm_free(hubclass->priv); } usbhost_freeclass(hubclass); @@ -609,11 +584,11 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass, /* We are good... Allocate the endpoints */ - ret = DRVR_EPALLOC(hubclass->drvr, &intindesc, &priv->intxfer.ep); + ret = DRVR_EPALLOC(hubclass->drvr, &intindesc, &priv->intin); if (ret != OK) { udbg("ERROR: Failed to allocate Interrupt IN endpoint: %d\n", ret); - (void)DRVR_EPFREE(hubclass->drvr, priv->intxfer.ep); + (void)DRVR_EPFREE(hubclass->drvr, priv->intin); return ret; } @@ -645,6 +620,7 @@ 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_hub_s *priv; + FAR struct usb_ctrlreq_s *ctrlreq; struct usb_hubdesc_s hubdesc; uint16_t hubchar; int ret; @@ -652,9 +628,18 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass) DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); priv = (FAR struct usbhost_hub_s *)hubclass->priv; - 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); + /* Get the hub descriptor */ + + ctrlreq = priv->ctrlreq; + DEBUGASSERT(ctrlreq); + + ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_HUB; + ctrlreq->req = USB_REQ_GETDESCRIPTOR; + usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_HUB << 8)); + usbhost_putle16(ctrlreq->index, 0); + usbhost_putle16(ctrlreq->len, USB_SIZEOF_HUBDESC); + + ret = DRVR_CTRLIN(hubclass->drvr, ctrlreq, (FAR uint8_t *)&hubdesc); if (ret != OK) { udbg("ERROR: Failed to read hub descriptor: %d\n", ret); @@ -699,6 +684,7 @@ 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_hub_s *priv; + FAR struct usb_ctrlreq_s *ctrlreq; DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); priv = (FAR struct usbhost_hub_s *)hubclass->priv; @@ -717,11 +703,20 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on) req = USB_REQ_CLEARFEATURE; } + /* Set port power */ + + ctrlreq = priv->ctrlreq; + DEBUGASSERT(ctrlreq); + for (port = 1; port <= priv->nports; port++) { - ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, - req, USBHUB_PORT_FEAT_POWER, - port, 0, NULL); + ctrlreq->type = USBHUB_REQ_TYPE_PORT; + ctrlreq->req = req; + usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_POWER << 8)); + usbhost_putle16(ctrlreq->index, port); + usbhost_putle16(ctrlreq->len, 0); + + ret = DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: Failed to power %d port %d: %d\n", on, port, ret); @@ -737,7 +732,7 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on) * Name: usbhost_intxfer * * Description: - * Free transfer buffer memory. + * Set-up to receive a callback when an interrupt packet is received. * * Input Parameters: * devclass - A reference to the class instance. @@ -774,10 +769,7 @@ static int usbhost_intxfer(FAR struct usbhost_class_s *devclass, * Name: usbhost_hubevent * * Description: - * This function implements the connect() method of struct - * usbhost_class_s. This method is a callback into the class - * implementation. It is used to provide the device's configuration - * descriptor to the class so that the class may initialize properly + * Handle a hub event. * * Input Parameters: * xfer - The USB host class instance. @@ -795,6 +787,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) { FAR struct usbhost_class_s *hubclass; FAR struct usbhost_hub_s *priv; + FAR struct usb_ctrlreq_s *ctrlreq; struct usb_portstatus_s portstatus; uint16_t status; uint16_t change; @@ -810,7 +803,10 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); priv = (FAR struct usbhost_hub_s *)hubclass->priv; - statusmap = xfer->buffer[0]; + ctrlreq = priv->ctrlreq; + DEBUGASSERT(ctrlreq); + + statusmap = priv->buffer[0]; for (port = 1; port <= priv->nports; port++) { @@ -827,10 +823,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) /* Read hub port status */ - ret = usbhost_ctrlxfer(hubclass, - (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), - USB_REQ_GETSTATUS, 0, port, - USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); + ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT; + ctrlreq->req = USB_REQ_GETSTATUS; + usbhost_putle16(ctrlreq->value, 0); + usbhost_putle16(ctrlreq->index, port); + usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS); + + ret = DRVR_CTRLIN(hubclass->drvr, ctrlreq, (FAR uint8_t *)&portstatus); if (ret != OK) { udbg("ERROR: Failed to read port %d status: %d\n", port, ret); @@ -848,9 +847,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) { if (change & mask) { - ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, - USB_REQ_CLEARFEATURE, feat, - port, 0, NULL); + ctrlreq->type = USBHUB_REQ_TYPE_PORT; + ctrlreq->req = USB_REQ_CLEARFEATURE; + usbhost_putle16(ctrlreq->value, (feat << 8)); + usbhost_putle16(ctrlreq->index, port); + usbhost_putle16(ctrlreq->len, 0); + + ret = DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: Failed to clear port %d change mask %x: %d\n", @@ -880,14 +883,17 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) while (debouncetime < 1500) { - ret = usbhost_ctrlxfer(hubclass, - (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), - USB_REQ_GETSTATUS, 0, port, - USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); - if (ret != OK) - { - break; - } + ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT; + ctrlreq->req = USB_REQ_GETSTATUS; + usbhost_putle16(ctrlreq->value, 0); + usbhost_putle16(ctrlreq->index, port); + usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS); + + ret = DRVR_CTRLIN(hubclass->drvr, ctrlreq, (FAR uint8_t *)&portstatus); + if (ret != OK) + { + break; + } status = usbhost_getle16(portstatus.status); change = usbhost_getle16(portstatus.change); @@ -909,9 +915,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) if (change & USBHUB_PORT_STAT_CCONNECTION) { - (void)usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, - USB_REQ_CLEARFEATURE, USBHUB_PORT_FEAT_CCONNECTION, - port, 0, NULL); + ctrlreq->type = USBHUB_REQ_TYPE_PORT; + ctrlreq->req = USB_REQ_CLEARFEATURE; + usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_CCONNECTION << 8)); + usbhost_putle16(ctrlreq->index, port); + usbhost_putle16(ctrlreq->len, 0); + + (void)DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL); } debouncetime += 25; @@ -927,10 +937,14 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) if (status & USBHUB_PORT_STAT_CONNECTION) { /* Connect */ - - ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, - USB_REQ_SETFEATURE, - USBHUB_PORT_FEAT_RESET, port, 0, NULL); + + ctrlreq->type = USBHUB_REQ_TYPE_PORT; + ctrlreq->req = USB_REQ_SETFEATURE; + usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_RESET << 8)); + usbhost_putle16(ctrlreq->index, port); + usbhost_putle16(ctrlreq->len, 0); + + ret = DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL); if (ret != OK) { udbg("ERROR: ailed to reset port %d: %d\n", port, ret); @@ -939,10 +953,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) up_mdelay(100); - ret = usbhost_ctrlxfer(hubclass, - (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), - USB_REQ_GETSTATUS, 0, port, - USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); + ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT; + ctrlreq->req = USB_REQ_GETSTATUS; + usbhost_putle16(ctrlreq->value, 0); + usbhost_putle16(ctrlreq->index, port); + usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS); + + ret = DRVR_CTRLIN(hubclass->drvr, ctrlreq, (FAR uint8_t *)&portstatus); if (ret != OK) { udbg("ERROR: Failed to reset port %d: %d\n", port, ret); @@ -962,10 +979,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer) if (change & USBHUB_PORT_STAT_CRESET) { - (void)usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, - USB_REQ_CLEARFEATURE, - USBHUB_PORT_FEAT_CRESET, - port, 0, NULL); + ctrlreq->type = USBHUB_REQ_TYPE_PORT; + ctrlreq->req = USB_REQ_CLEARFEATURE; + usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_CRESET << 8)); + usbhost_putle16(ctrlreq->index, port); + usbhost_putle16(ctrlreq->len, 0); + + (void)DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL); } if (status & USBHUB_PORT_STAT_HIGH_SPEED) @@ -1078,7 +1098,7 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val) * Name: usbhost_callback * * Description: - * Put a (possibly unaligned) 16-bit little endian value. + * Handle end of transfer callback. * * Input Parameters: * dest - A pointer to the first byte to save the little endian value. @@ -1091,9 +1111,18 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val) static void usbhost_callback(FAR struct usbhost_transfer_s *xfer) { + FAR struct usbhost_class_s *hubclass; + FAR struct usbhost_hub_s *priv; + + DEBUGASSERT(xfer != NULL && xfer->devclass != NULL); + hubclass = (FAR struct usbhost_class_s *)xfer->devclass; + + DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); + priv = (FAR struct usbhost_hub_s *)hubclass->priv; + if (xfer->status != OK) { - xfer->buffer[0] = 0; + priv->buffer[0] = 0; } (void)work_queue(HPWORK, &xfer->work, (worker_t)usbhost_hubevent, xfer, 0); @@ -1133,52 +1162,65 @@ static void usbhost_callback(FAR struct usbhost_transfer_s *xfer) static int usbhost_create(FAR struct usbhost_class_s *hubclass, FAR const struct usbhost_id_s *id) { - struct usbhost_hub_s *priv; + FAR struct usbhost_hub_s *priv; + size_t maxlen; int child; - int ret = -ENOMEM; + int ret; /* Allocate a USB host class instance */ - priv = kmalloc(sizeof(struct usbhost_hub_s)); - - if (priv != NULL) + priv = kmm_zalloc(sizeof(struct usbhost_hub_s)); + if (priv == NULL) { - /* Initialize the allocated storage class instance */ - - memset(priv, 0, sizeof(struct usbhost_hub_s)); - - /* 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; - - /* Initialize semaphores (this works okay in the interrupt context) */ - - sem_init(&priv->exclsem, 0, 1); - - /* Initialize interrupt end-point */ - - priv->intxfer.ep = NULL; - - /* Initialize transaction translator */ - - priv->tt.class = NULL; - - /* Initialize child class pointers */ - - for (child = 0; child < USBHUB_MAX_PORTS; child++) - { - priv->childclass[child] = NULL; - } - - ret = OK; + return -ENOMEM; } + /* Allocate memory for control requests */ + + ret = DRVR_ALLOC(hubclass->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen); + if (ret != OK) + { + udbg("DRVR_ALLOC failed: %d\n", ret); + goto errout_with_hub; + } + + /* Allocate buffer for status change (INT) endpoint */ + + ret = DRVR_IOALLOC(hubclass->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; + + /* Initialize semaphores (this works okay in the interrupt context) */ + + sem_init(&priv->exclsem, 0, 1); + + /* Initialize child class pointers */ + + for (child = 0; child < USBHUB_MAX_PORTS; child++) + { + priv->childclass[child] = NULL; + } + + return OK; + +errout_with_ctrlreq: + kmm_free(priv->ctrlreq); + +errout_with_hub: + kmm_free(priv); return ret; } @@ -1239,15 +1281,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass, } else { - /* Allocate buffer for status change (INT) endpoint */ - - ret = DRVR_IOALLOC(hubclass->drvr, &priv->intxfer.buffer, 1); - if (ret != OK) - { - return ret; - } - - /* Now read hub descriptor */ + /* Read the hub descriptor */ ret = usbhost_hubdesc(hubclass); if (ret != OK) @@ -1265,8 +1299,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass, /* INT request to periodically check port status */ - ret = usbhost_intxfer(hubclass, &priv->intxfer, - usbhost_callback); + ret = usbhost_intxfer(hubclass, &priv->ctrlreq, usbhost_callback); } return ret; @@ -1320,7 +1353,7 @@ static int usbhost_disconnected(struct usbhost_class_s *hubclass) { /* Free buffer for status change (INT) endpoint */ - DRVR_IOFREE(hubclass->drvr, priv->intxfer.buffer); + DRVR_IOFREE(hubclass->drvr, priv->buffer); /* Power off (for root hub only) */ (void)usbhost_hubpwr(hubclass, false); diff --git a/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h index 039da28b29..fd91792604 100644 --- a/include/nuttx/usb/usbhost.h +++ b/include/nuttx/usb/usbhost.h @@ -52,9 +52,6 @@ #include #include #include -#include - -#include /************************************************************************************ * Pre-processor Definitions @@ -451,7 +448,7 @@ * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to * the class create() method. - * xfr - Describes the request to be sent. This request must lie in memory + * req - 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 @@ -469,8 +466,8 @@ * ************************************************************************************/ -#define DRVR_CTRLIN(drvr,xfer,cmd) ((drvr)->ctrlin(drvr,xfer,cmd)) -#define DRVR_CTRLOUT(drvr,xfer,cmd) ((drvr)->ctrlout(drvr,xfer,cmd)) +#define DRVR_CTRLIN(drvr,req,buffer) ((drvr)->ctrlin(drvr,req,buffer)) +#define DRVR_CTRLOUT(drvr,req,buffer) ((drvr)->ctrlout(drvr,req,buffer)) /************************************************************************************ * Name: DRVR_TRANSFER @@ -535,7 +532,7 @@ #define DRVR_DISCONNECT(drvr) ((drvr)->disconnect(drvr)) /************************************************************************************ - * Name: DRVR_RHCTRL and DRVR_RHSTATUS + * Name: DRVR_RHSTATUS * * Description: * Called by hub class to control root hub. @@ -558,7 +555,6 @@ ************************************************************************************/ #ifdef CONFIG_USBHOST_HUB -# define DRVR_RHCTRL(drvr,xfer,cmd) ((drvr)->rhctrl(drvr,xfer,cmd)) # define DRVR_RHSTATUS(drvr,xfer) ((drvr)->rhstatus(drvr,xfer)) #endif @@ -630,34 +626,14 @@ typedef FAR void *usbhost_ep_t; struct usbhost_class_s { #ifdef CONFIG_USBHOST_HUB - /* Common host driver */ - - FAR struct usbhost_driver_s *drvr; - - /* Parent class */ - - FAR struct usbhost_class_s *parent; - - /* Control endpoint, ep0 */ - - usbhost_ep_t ep0; - - /* Transaction translator hub */ - - FAR struct usb_hubtt_s *tt; - - /* Class specific private data */ - - FAR void *priv; - - /* USB device address & speed */ - - uint8_t addr; - uint8_t speed; - - /* Transaction translator port */ - - uint8_t ttport; + 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 /* Provides the configuration descriptor to the class. The configuration @@ -698,34 +674,18 @@ struct usbhost_devinfo_s { uint8_t speed:2; /* Device speed: 0=low, 1=full, 2=high */ }; + /* 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 @@ -826,11 +786,11 @@ struct usbhost_driver_s */ int (*ctrlin)(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_transfer_s *xfer, - FAR const struct usb_ctrlreq_s *cmd); + FAR const struct usb_ctrlreq_s *req, + FAR uint8_t *buffer); int (*ctrlout)(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_transfer_s *xfer, - FAR const struct usb_ctrlreq_s *cmd); + FAR const struct usb_ctrlreq_s *req, + FAR const uint8_t *buffer); /* 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 @@ -855,9 +815,6 @@ struct usbhost_driver_s #ifdef CONFIG_USBHOST_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 @@ -1058,27 +1015,6 @@ int usbhost_wlaninit(void); int usbhost_enumerate(FAR struct usbhost_class_s *devclass); -/**************************************************************************** - * Name: usbhost_ctrlxfer - * - * Description: - * Free transfer buffer memory. - * - * Input Parameters: - * devclass - A reference to the class instance. - * ctrlreq - Describes the control request transfer - * buffer - Data accompanying the control transfer - * - * 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, - FAR struct usb_ctrlreq_s *ctrlreq, - FAR uint8_t *buffer); - #ifdef CONFIG_USBHOST_HUB /******************************************************************************* * Name: usbhost_rh_connect