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:
parent
b82df87c67
commit
4b7b96c759
@ -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
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user