From bfa36c50b745c8935a25ba2922a815f8c4dc9f5c Mon Sep 17 00:00:00 2001
From: patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>
Date: Sun, 19 Dec 2010 19:18:29 +0000
Subject: [PATCH] Add class binding logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3198 42af7a65-404d-4744-a932-0658087f49c3
---
 arch/arm/src/lpc17xx/lpc17_usbhost.c | 142 ++++++++++++++++++++++++++-
 include/nuttx/usb/usbhost.h          |   2 +-
 2 files changed, 141 insertions(+), 3 deletions(-)

diff --git a/arch/arm/src/lpc17xx/lpc17_usbhost.c b/arch/arm/src/lpc17xx/lpc17_usbhost.c
index c415794b47..8fb4d1df39 100755
--- a/arch/arm/src/lpc17xx/lpc17_usbhost.c
+++ b/arch/arm/src/lpc17xx/lpc17_usbhost.c
@@ -132,7 +132,7 @@ struct lpc17_usbhost_s
    * to structlpc17_usbhost_s.
    */
 
-  struct usbhost_driver_s usbhost;
+  struct usbhost_driver_s drvr;
 
   /* The bound device class driver */
 
@@ -202,6 +202,14 @@ static void lpc17_enqueuetd(volatile struct lpc17_hced_s *ed, uint32_t dirpid,
                             uint32_t toggle, volatile uint8_t *buffer,
                             size_t buflen);
 
+/* Class helper functions ******************************************************/
+
+static int inline lpc17_configdesc(struct lpc17_usbhost_s *priv,
+                                   const uint8_t *configdesc, int desclen,
+                                   struct usbhost_id_s *id);
+static int lpc17_classbind(struct lpc17_usbhost_s *priv,
+                           const uint8_t *configdesc, int desclen);
+
 /* Interrupt handling **********************************************************/
 
 static int lpc17_usbinterrupt(int irq, FAR void *context);
@@ -236,7 +244,7 @@ static void lpc17_hccainit(volatile struct lpc17_hcca_s *hcca);
 
 static struct lpc17_usbhost_s g_usbhost =
 {
-  .usbhost        =
+  .drvr           =
     {
       .enumerate  = lpc17_enumerate,
       .alloc      = lpc17_alloc,
@@ -440,6 +448,136 @@ static void lpc17_enqueuetd(volatile struct lpc17_hced_s *ed, uint32_t dirpid,
   ed->next        = 0;
 }
 
+/****************************************************************************
+ * Name: lpc17_classbind
+ *
+ * Description:
+ *   A configuration descriptor has been obtained from the device.  Find the
+ *   ID information for the class that supports this device.
+ *
+ ****************************************************************************/
+
+static inline int
+lpc17_configdesc(struct lpc17_usbhost_s *priv, const uint8_t *configdesc,
+                 int desclen, struct usbhost_id_s *id)
+{
+  struct usb_cfgdesc_s *cfgdesc;
+  struct usb_ifdesc_s *ifdesc;
+  int remaining;
+
+  DEBUGASSERT(priv != NULL && 
+              configdesc != NULL &&
+              desclen >= sizeof(struct usb_cfgdesc_s));
+  
+  /* Verify that we were passed a configuration descriptor */
+
+  cfgdesc = (struct usb_cfgdesc_s *)configdesc;
+  if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
+    {
+      return -EINVAL;
+    }
+
+  /* Get the total length of the configuration descriptor (little endian).
+   * It might be a good check to get the number of interfaces here too.
+  */
+
+  remaining = (int)lpc17_getle16(cfgdesc->totallen);
+
+  /* Skip to the next entry descriptor */
+
+  configdesc += cfgdesc->len;
+  remaining  -= cfgdesc->len;
+
+  /* Loop where there are more dscriptors to examine */
+
+  memset(&id, 0, sizeof(FAR struct usb_desc_s));
+  while (remaining >= sizeof(struct usb_desc_s))
+    {
+      /* What is the next descriptor? Is it an interface descriptor? */
+
+      ifdesc = (struct usb_ifdesc_s *)configdesc;
+      if (ifdesc->type == USB_DESC_TYPE_INTERFACE)
+        {
+          /* Yes, extract the class information from the interface descriptor.
+           * (We are going to need to do more than this here in the future:
+           *  ID information might lie elsewhere and we will need the VID and
+           *  PID as well).
+           */
+ 
+          DEBUGASSERT(remaining >= sizeof(struct usb_ifdesc_s));
+          id->base     = ifdesc->class;
+          id->subclass = ifdesc->subclass;
+          id->proto    = ifdesc->protocol;
+          return OK;
+        }
+
+     /* Increment the address of the next descriptor */
+ 
+      configdesc += ifdesc->len;
+      remaining  -= ifdesc->len;
+    }
+
+  return -ENOENT;
+}
+
+/****************************************************************************
+ * Name: lpc17_classbind
+ *
+ * Description:
+ *   A configuration descriptor has been obtained from the device.  Try to
+ *   bind this configuration descriptor with a supported class.
+ *
+ ****************************************************************************/
+
+static int lpc17_classbind(struct lpc17_usbhost_s *priv,
+                           const uint8_t *configdesc, int desclen)
+{
+  struct usbhost_id_s id;
+  int ret;
+
+  DEBUGASSERT(priv && priv->class == NULL);
+
+  /* Get the class identification information for this device. */
+
+  ret = lpc17_configdesc(priv, configdesc, desclen, &id);
+  uvdbg("lpc17_configdesc: %d\n", ret);
+  if (ret)
+    {
+      /* So if there is a class implementation registered to support this
+       * device.
+       */
+
+      ret = -EINVAL;
+      const struct usbhost_registry_s *reg = usbhost_findclass(&id);
+      uvdbg("usbhost_findclass: %p\n", reg);
+      if (reg)
+        {
+          /* Yes.. there is a class for this device.  Get an instance of
+           * its interface.
+           */
+
+          ret = -ENOMEM;
+          priv->class = CLASS_CREATE(reg, &priv->drvr, &id);
+          uvdbg("CLASS_CREATE: %p\n", priv->class);
+          if (priv->class)
+            {
+              /* Then initialize the newly instantiated class instance */
+
+              ret = CLASS_CONFIGDESC(priv->class, configdesc, desclen);
+              if (ret != OK)
+                {
+                  udbg("CLASS_CONFIGDESC failed: %d\n", ret);
+                  CLASS_DISCONNECTED(priv->class);
+                  priv->class = NULL;
+                }
+            }
+        }
+    }
+
+  uvdbg("Returning: %d\n", ret);
+  return ret;
+}
+
 /*******************************************************************************
  * Name: lpc17_usbinterrupt
  *
diff --git a/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h
index d197b12e44..2035299c28 100644
--- a/include/nuttx/usb/usbhost.h
+++ b/include/nuttx/usb/usbhost.h
@@ -91,7 +91,7 @@
  *
  ************************************************************************************/
 
-#define CLASS_CREATE(reg, drvr, id) ((reg)->create(drvr))
+#define CLASS_CREATE(reg, drvr, id) ((reg)->create(drvr, id))
 
 /************************************************************************************
  * Name: CLASS_CONFIGDESC
-- 
GitLab