diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c index b824df3d8..f62d6808c 100644 --- a/nuttx/drivers/usbhost/usbhost_storage.c +++ b/nuttx/drivers/usbhost/usbhost_storage.c @@ -139,6 +139,8 @@ struct usbhost_state_s sem_t exclsem; /* Used to maintain mutual exclusive access */ sem_t waitsem; /* Used to wait for transfer completion events */ struct work_s work; /* For interacting with the worker thread */ + FAR uint8_t *tdbuffer; /* The allocated transfer descriptor buffer */ + size_t tdbuflen; /* Size of the allocated transfer buffer */ struct usbhost_epdesc_s bulkin; /* Bulk IN endpoint */ struct usbhost_epdesc_s bulkout; /* Bulk OUT endpoint */ }; @@ -168,9 +170,17 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev static void usbhost_destroy(FAR void *arg); static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker); -/* Data helpers */ +/* (Little Endian) Data helpers */ -static inline uint16_t usbhost_getint16(const uint8_t *val); +static inline uint16_t usbhost_getle16(const uint8_t *val); +static inline void usbhost_putle16(uint8_t *dest, uint16_t val); +static void usbhost_putle32(uint8_t *dest, uint32_t val); + +/* Transfer descriptor memory management */ + +static int usbhost_tdalloc(FAR struct usbhost_state_s *priv); +static int usbhost_tdfree(FAR struct usbhost_state_s *priv); +static FAR struct usbstrg_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *priv); /* struct usbhost_registry_s methods */ @@ -439,7 +449,7 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev * host class instance. * * Input Parameters: - * arg - A reference to the class instance to be freed. + * arg - A reference to the class instance to be destroyed. * * Returned Values: * None @@ -483,7 +493,7 @@ static void usbhost_destroy(FAR void *arg) * longer be executed. * * Input Parameters: - * arg - A reference to the class instance to be freed. + * arg - A reference to the class instance. * * Returned Values: * None @@ -587,7 +597,7 @@ static void usbhost_statemachine(FAR void *arg) * just execute the work now. * * Input Parameters: - * priv - A reference to the class instance to be freed. + * priv - A reference to the class instance. * worker - A reference to the worker function to be executed * * Returned Values: @@ -616,7 +626,7 @@ static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker) } /**************************************************************************** - * Name: usbhost_getint16 + * Name: usbhost_getle16 * * Description: * Get a (possibly unaligned) 16-bit little endian value. @@ -629,11 +639,147 @@ static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker) * ****************************************************************************/ -static inline uint16_t usbhost_getint16(const uint8_t *val) +static inline uint16_t usbhost_getle16(const uint8_t *val) { return (uint16_t)val[1] << 8 | (uint16_t)val[0]; } +/**************************************************************************** + * Name: usbhost_putle16 + * + * Description: + * Put a (possibly unaligned) 16-bit little endian value. + * + * Input Parameters: + * dest - A pointer to the first byte to save the little endian value. + * val - The 16-bit value to be saved. + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void usbhost_putle16(uint8_t *dest, uint16_t val) +{ + dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */ + dest[1] = val >> 8; +} + +/**************************************************************************** + * Name: usbhost_putle32 + * + * Description: + * Put a (possibly unaligned) 32-bit little endian value. + * + * Input Parameters: + * dest - A pointer to the first byte to save the little endian value. + * val - The 32-bit value to be saved. + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void usbhost_putle32(uint8_t *dest, uint32_t val) +{ + /* Little endian means LS halfwrd first in byte stream */ + + usbhost_putle16(dest, (uint16_t)(val & 0xffff)); + usbhost_putle16(dest+2, (uint16_t)(val >> 16)); +} + +/**************************************************************************** + * Name: usbhost_tdalloc + * + * Description: + * Allocate transfer descriptor memory. + * + * Input Parameters: + * priv - A reference to the class instance. + * + * Returned Values: + * On sucess, zero (OK) is returned. On failure, an negated errno value + * is returned to indicate the nature of the failure. + * + ****************************************************************************/ + +static int usbhost_tdalloc(FAR struct usbhost_state_s *priv) +{ + int result = OK; + + /* Is a descriptor already allocated? */ + + if (!priv->tdbuffer) + { + result = DRVR_ALLOC(priv->drvr, &priv->tdbuffer, &priv->tdbuflen); + } + return result; +} + +/**************************************************************************** + * Name: usbhost_tdfree + * + * Description: + * Free transfer descriptor memory. + * + * Input Parameters: + * priv - A reference to the class instance. + * + * Returned Values: + * On sucess, zero (OK) is returned. On failure, an negated errno value + * is returned to indicate the nature of the failure. + * + ****************************************************************************/ + +static int usbhost_tdfree(FAR struct usbhost_state_s *priv) +{ + int result = OK; + + /* Is a descriptor already allocated? */ + + if (!priv->tdbuffer) + { + result = DRVR_FREE(priv->drvr, priv->tdbuffer); + priv->tdbuffer = NULL; + priv->tdbuflen = 0; + } + return result; +} + +/**************************************************************************** + * Name: usbhost_cbwalloc + * + * Description: + * Allocate and initialize a CBW. Upon successful return, the CBW is cleared + * and has the CBW signature in place. + * + * Input Parameters: + * priv - A reference to the class instance. + * + * Returned Values: + * None + * + ****************************************************************************/ + +static FAR struct usbstrg_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *priv) +{ + FAR struct usbstrg_cbw_s *cbw = NULL; + int result; + + /* Allocate any special memory that the the driver may have for us */ + + result = usbhost_tdalloc(priv); + if (result == OK && priv->tdbuflen >= sizeof(struct usbstrg_cbw_s)) + { + /* Intialize the CBW sructure */ + + cbw = (FAR struct usbstrg_cbw_s *)priv->tdbuffer; + memset(cbw, 0, sizeof(struct usbstrg_cbw_s)); + usbhost_putle32(cbw->signature, USBSTRG_CBW_SIGNATURE); + } + return cbw; +} + /**************************************************************************** * struct usbhost_registry_s methods ****************************************************************************/ @@ -768,7 +914,7 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class, * It might be a good check to get the number of interfaces here too. */ - remaining = (int)usbhost_getint16(cfgdesc->totallen); + remaining = (int)usbhost_getle16(cfgdesc->totallen); /* Skip to the next entry descriptor */ @@ -831,7 +977,7 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class, priv->bulkout.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; priv->bulkout.in = false; - priv->bulkout.mxpacketsize = usbhost_getint16(epdesc->mxpacketsize); + priv->bulkout.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize); } else { @@ -849,7 +995,7 @@ static int usbhost_configdesc(FAR struct usbhost_class_s *class, priv->bulkin.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK; priv->bulkin.in = true; - priv->bulkin.mxpacketsize = usbhost_getint16(epdesc->mxpacketsize); + priv->bulkin.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize); } } } @@ -1192,6 +1338,7 @@ static int usbhost_geometry(FAR struct inode *inode, struct geometry *geometry) /* Check if the mass storage device is still connected */ + priv = (FAR struct usbhost_state_s *)inode->i_private; if (!priv->drvr) { /* No... the block driver is no longer bound to the class. That means that @@ -1205,7 +1352,6 @@ static int usbhost_geometry(FAR struct inode *inode, struct geometry *geometry) { /* Return the geometry of the USB mass storage device */ - priv = (FAR struct usbhost_state_s *)inode->i_private; usbhost_takesem(&priv->exclsem); DEBUGASSERT(priv->state == USBSTRG_STATE_READY); diff --git a/nuttx/include/nuttx/usb/usbhost.h b/nuttx/include/nuttx/usb/usbhost.h index d60d2b827..e72e392ce 100644 --- a/nuttx/include/nuttx/usb/usbhost.h +++ b/nuttx/include/nuttx/usb/usbhost.h @@ -49,6 +49,7 @@ #include +#include #include #include @@ -166,6 +167,119 @@ #define CLASS_DISCONNECTED(class) ((class)->disconnected(class)) +/************************************************************************************ + * Name: DRVR_ENUMERATE + * + * Description: + * Enumerate the connected device. This function will enqueue the + * enumeration process. 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 usbhost_findclass() + * to find the class that supports this device, (4) call the create() + * method on the struct usbhost_registry_s interface to get a class + * instance, and finally (5) call the configdesc() method of the struct + * usbhost_class_s interface. After that, the class is in 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. + * + * Returned Values: + * On success, zero (OK) is returned. On a failure, a negated errno value is + * returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ************************************************************************************/ + +#define DRVR_ENUMERATE(drvr) ((drvr)->enumerate(drvr)) + +/************************************************************************************ + * Name: DRVR_TRANSFER + * + * Description: + * Enqueue a request to handle a transfer descriptor. This method will + * enqueue the transfer request and return immediately. The transfer will + * be performed asynchronously. When the transfer completes, the USB host + * driver will call he complete() method of the struct usbhost_class_s + * interface. Only one transfer may be queued; this function cannot be + * again until the class complete() method has been called. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the call to + * the class create() method. + * ed - The IN or OUT endpoint descriptor for the device endpoint on which to + * perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or received + * (IN endpoint). + * buflen - The length of the data to be sent or received. + * + * Returned Values: + * On success, zero (OK) is returned. On a failure, a negated errno value is + * returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ************************************************************************************/ + +#define DRVR_TRANSFER(drvr,ed,buffer,buflen) ((drvr)->transfer(drvr,ed,buffer,buflen)) + +/************************************************************************************ + * Name: DRVR_ALLOC + * + * Description: + * Some hardware supports special memory in which transfer descriptors can + * be accessed more efficiently. This method provides a mechanism to allocate + * the transfer descriptor memory. If the underlying hardware does not support + * such "special" memory, this functions may simply map to malloc. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the call to + * the class create() method. + * buffer - The address of a memory location provided by the caller in which to + * return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in which to + * return the maximum size of the allocated buffer memory. + * + * Returned Values: + * On success, zero (OK) is returned. On a failure, a negated errno value is + * returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ************************************************************************************/ + +#define DRVR_ALLOC(drvr,buffer,maxlen) ((drvr)->alloc(drvr,buffer,maxlen)) + +/************************************************************************************ + * Name: DRVR_FREE + * + * Description: + * Some hardware supports special memory in which transfer descriptors can + * be accessed more efficiently. This method provides a mechanism to free that + * transfer descriptor memory. If the underlying hardware does not support + * such "special" memory, this functions may simply map to free(). + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the call to + * the class create() method. + * buffer - The address of the allocated buffer memory to be freed. + * + * Returned Values: + * On success, zero (OK) is returned. On a failure, a negated errno value is + * returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ************************************************************************************/ + +#define DRVR_FREE(drvr,buffer) ((drvr)->free(drvr,buffer)) + /************************************************************************************ * Public Types ************************************************************************************/ @@ -260,16 +374,30 @@ struct usbhost_driver_s * sequence of operations. */ - int (*enumerate)(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_epdesc_s *ed); + int (*enumerate)(FAR struct usbhost_driver_s *drvr); - /* Enqueue a request to process a transfer descriptor. This method will + /* Enqueue a request to handle a transfer descriptor. This method will * enqueue the transfer request and return immediately. The transfer will * be performed asynchronously. When the transfer completes, the USB host * driver will call he complete() method of the struct usbhost_class_s - * interface. + * interface. Only one transfer may be queued; this function cannot be + * again until the class complete() method has been called. */ - int (*transfer)(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_epdesc_s *ed); + int (*transfer)(FAR struct usbhost_driver_s *drvr, + FAR struct usbhost_epdesc_s *ed, + FAR uint8_t *buffer, size_t buflen); + + /* Some hardware supports special memory in which transfer descriptors can + * be accessed more efficiently. The following methods provide a mechanism + * to allocate and free the transfer descriptor memory. If the underlying + * hardware does not support such "special" memory, these functions may + * simply map to malloc and free. + */ + + int (*alloc)(FAR struct usbhost_driver_s *drvr, + FAR uint8_t **buffer, FAR size_t *maxlen); + int (*free)(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); /* Receive control information */