From 1e05f80f58599013b468df80dce28f01304ac81d Mon Sep 17 00:00:00 2001
From: patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>
Date: Fri, 17 Dec 2010 02:19:04 +0000
Subject: [PATCH] Add td allocation logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3190 42af7a65-404d-4744-a932-0658087f49c3
---
 drivers/usbhost/usbhost_storage.c | 168 ++++++++++++++++++++++++++++--
 include/nuttx/usb/usbhost.h       | 136 +++++++++++++++++++++++-
 2 files changed, 289 insertions(+), 15 deletions(-)

diff --git a/drivers/usbhost/usbhost_storage.c b/drivers/usbhost/usbhost_storage.c
index b824df3d8b..f62d6808c9 100644
--- a/drivers/usbhost/usbhost_storage.c
+++ b/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/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h
index d60d2b8272..e72e392ce1 100644
--- a/include/nuttx/usb/usbhost.h
+++ b/include/nuttx/usb/usbhost.h
@@ -49,6 +49,7 @@
 
 #include <nuttx/config.h>
 
+#include <sys/types.h>
 #include <stdint.h>
 #include <stdbool.h>
 
@@ -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,
+                  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 (*transfer)(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_epdesc_s *ed);
+  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 */
 
-- 
GitLab