Add class binding logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3198 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2010-12-19 19:18:29 +00:00
parent b82df87c67
commit 4b7b96c759

View File

@ -132,7 +132,7 @@ struct lpc17_usbhost_s
* to structlpc17_usbhost_s. * to structlpc17_usbhost_s.
*/ */
struct usbhost_driver_s usbhost; struct usbhost_driver_s drvr;
/* The bound device class driver */ /* 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, uint32_t toggle, volatile uint8_t *buffer,
size_t buflen); 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 **********************************************************/ /* Interrupt handling **********************************************************/
static int lpc17_usbinterrupt(int irq, FAR void *context); 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 = static struct lpc17_usbhost_s g_usbhost =
{ {
.usbhost = .drvr =
{ {
.enumerate = lpc17_enumerate, .enumerate = lpc17_enumerate,
.alloc = lpc17_alloc, .alloc = lpc17_alloc,
@ -440,6 +448,136 @@ static void lpc17_enqueuetd(volatile struct lpc17_hced_s *ed, uint32_t dirpid,
ed->next = 0; 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 * Name: lpc17_usbinterrupt
* *