USB hub: Decouple class and hub structures
This commit is contained in:
parent
814ce6fd02
commit
f7f3a7f74d
5 changed files with 380 additions and 399 deletions
|
@ -71,9 +71,10 @@ static inline int usbhost_devdesc(const struct usb_devdesc_s *devdesc,
|
|||
FAR struct usbhost_id_s *id);
|
||||
static inline int usbhost_configdesc(const uint8_t *configdesc, int desclen,
|
||||
FAR struct usbhost_id_s *id);
|
||||
static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass,
|
||||
static inline int usbhost_classbind(FAR struct usbhost_hub_s *hub,
|
||||
const uint8_t *configdesc, int desclen,
|
||||
FAR struct usbhost_id_s *id);
|
||||
struct usbhost_id_s *id,
|
||||
FAR struct usbhost_class_s **devclass);
|
||||
|
||||
/*******************************************************************************
|
||||
* Private Data
|
||||
|
@ -221,10 +222,12 @@ static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen,
|
|||
*
|
||||
*******************************************************************************/
|
||||
|
||||
static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass,
|
||||
static inline int usbhost_classbind(FAR struct usbhost_hub_s *hub,
|
||||
const uint8_t *configdesc, int desclen,
|
||||
FAR struct usbhost_id_s *id)
|
||||
struct usbhost_id_s *id,
|
||||
FAR struct usbhost_class_s **usbclass)
|
||||
{
|
||||
FAR struct usbhost_class_s *devclass;
|
||||
FAR const struct usbhost_registry_s *reg;
|
||||
int ret = -EINVAL;
|
||||
|
||||
|
@ -232,17 +235,16 @@ static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass,
|
|||
|
||||
reg = usbhost_findclass(id);
|
||||
uvdbg("usbhost_findclass: %p\n", reg);
|
||||
|
||||
if (reg != NULL)
|
||||
{
|
||||
/* Yes.. there is a class for this device. Get an instance of
|
||||
* its interface.
|
||||
*/
|
||||
|
||||
ret = CLASS_CREATE(reg, devclass, id);
|
||||
uvdbg("CLASS_CREATE: %p\n", devclass->priv);
|
||||
|
||||
if (devclass->priv != NULL)
|
||||
ret = -ENOMEM;
|
||||
devclass = CLASS_CREATE(reg, hub, id);
|
||||
uvdbg("CLASS_CREATE: %p\n", devclass);
|
||||
if (devclass != NULL)
|
||||
{
|
||||
/* Then bind the newly instantiated class instance */
|
||||
|
||||
|
@ -256,6 +258,10 @@ static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass,
|
|||
udbg("CLASS_CONNECT failed: %d\n", ret);
|
||||
CLASS_DISCONNECTED(devclass);
|
||||
}
|
||||
else
|
||||
{
|
||||
*usbclass = devclass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,22 +287,24 @@ static inline int usbhost_classbind(FAR struct usbhost_class_s *devclass,
|
|||
* charge of the sequence of operations.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devclass - USB class information common across all classes. Whoever calls
|
||||
* enumerate should fill address, speed, driver and parent class
|
||||
* pointer. Enumeration will fill the control endpoint ep0,
|
||||
* transaction translator (if applicable) and private data
|
||||
* hub - The hub that manages the new class.
|
||||
* devclass - If the class driver for the device is successful located
|
||||
* and bound to the hub, the allocated class instance is returned into
|
||||
* this caller-provided memory location.
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Only a single class bound to a single device is supported.
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
* - Never called from an interrupt handler.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
||||
int usbhost_enumerate(FAR struct usbhost_hub_s *hub,
|
||||
FAR struct usbhost_class_s **devclass)
|
||||
{
|
||||
FAR struct usb_ctrlreq_s *ctrlreq = NULL;
|
||||
struct usbhost_devinfo_s devinfo;
|
||||
|
@ -308,20 +316,20 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
FAR uint8_t *buffer = NULL;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(devclass != NULL && devclass->drvr != NULL);
|
||||
DEBUGASSERT(hub != NULL && hub->drvr != NULL);
|
||||
|
||||
/* Allocate descriptor buffers for use in this function. We will need two:
|
||||
* One for the request and one for the data buffer.
|
||||
*/
|
||||
|
||||
ret = DRVR_ALLOC(devclass->drvr, (FAR uint8_t **)&ctrlreq, &maxlen);
|
||||
ret = DRVR_ALLOC(hub->drvr, (FAR uint8_t **)&ctrlreq, &maxlen);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("DRVR_ALLOC failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = DRVR_ALLOC(devclass->drvr, &buffer, &maxlen);
|
||||
ret = DRVR_ALLOC(hub->drvr, &buffer, &maxlen);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("DRVR_ALLOC failed: %d\n", ret);
|
||||
|
@ -330,7 +338,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
|
||||
/* Get information about the connected device */
|
||||
|
||||
ret = DRVR_GETDEVINFO(devclass->drvr, &devinfo);
|
||||
ret = DRVR_GETDEVINFO(hub->drvr, &devinfo);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("DRVR_GETDEVINFO failed: %d\n", ret);
|
||||
|
@ -367,7 +375,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
|
||||
/* Configure EP0 with the initial maximum packet size */
|
||||
|
||||
DRVR_EP0CONFIGURE(devclass->drvr, devclass->ep0, 0, maxpacketsize);
|
||||
DRVR_EP0CONFIGURE(hub->drvr, hub->ep0, 0, maxpacketsize);
|
||||
|
||||
/* Read first bytes of the device descriptor */
|
||||
|
||||
|
@ -377,7 +385,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, descsize);
|
||||
|
||||
ret = DRVR_CTRLIN(devclass->drvr, devclass->ep0, ctrlreq, buffer);
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, buffer);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to get device descriptor, length=%d: %d\n",
|
||||
|
@ -392,17 +400,17 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
|
||||
/* And reconfigure EP0 with the correct maximum packet size */
|
||||
|
||||
DRVR_EP0CONFIGURE(devclass->drvr, devclass->ep0, 0, maxpacketsize);
|
||||
DRVR_EP0CONFIGURE(hub->drvr, hub->ep0, 0, maxpacketsize);
|
||||
|
||||
/* Set the USB device address */
|
||||
|
||||
ctrlreq->type = USB_REQ_DIR_OUT | USB_REQ_RECIPIENT_DEVICE;
|
||||
ctrlreq->req = USB_REQ_SETADDRESS;
|
||||
usbhost_putle16(ctrlreq->value, ((uint16_t)devclass->addr << 8));
|
||||
usbhost_putle16(ctrlreq->value, ((uint16_t)hub->funcaddr << 8));
|
||||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(devclass->drvr, devclass->ep0, ctrlreq, NULL);
|
||||
ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to set address: %d\n");
|
||||
|
@ -413,8 +421,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
|
||||
/* And reconfigure EP0 with the correct address */
|
||||
|
||||
DRVR_EP0CONFIGURE(devclass->drvr, devclass->ep0, devclass->addr,
|
||||
maxpacketsize);
|
||||
DRVR_EP0CONFIGURE(hub->drvr, hub->ep0, hub->funcaddr, maxpacketsize);
|
||||
|
||||
/* Now read the full device descriptor (if we have not already done so) */
|
||||
|
||||
|
@ -426,7 +433,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC);
|
||||
|
||||
ret = DRVR_CTRLIN(devclass->drvr, devclass->ep0, ctrlreq, buffer);
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, buffer);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to get device descriptor, length=%d: %d\n",
|
||||
|
@ -454,7 +461,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC);
|
||||
|
||||
ret = DRVR_CTRLIN(devclass->drvr, devclass->ep0, ctrlreq, buffer);
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, buffer);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n",
|
||||
|
@ -477,7 +484,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, cfglen);
|
||||
|
||||
ret = DRVR_CTRLIN(devclass->drvr, devclass->ep0, ctrlreq, buffer);
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, buffer);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n",
|
||||
|
@ -493,7 +500,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(devclass->drvr, devclass->ep0, ctrlreq, NULL);
|
||||
ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to set configuration: %d\n", ret);
|
||||
|
@ -528,21 +535,21 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
|
|||
* will begin configuring the device.
|
||||
*/
|
||||
|
||||
ret = usbhost_classbind(devclass, buffer, cfglen, &id);
|
||||
ret = usbhost_classbind(hub, buffer, cfglen, &id, devclass);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to bind class: %d\n", ret);
|
||||
udbg("ERROR: usbhost_classbind returned %d\n", ret);
|
||||
}
|
||||
|
||||
errout:
|
||||
if (buffer != NULL)
|
||||
{
|
||||
DRVR_FREE(devclass->drvr, buffer);
|
||||
DRVR_FREE(hub->drvr, buffer);
|
||||
}
|
||||
|
||||
if (ctrlreq)
|
||||
{
|
||||
DRVR_FREE(devclass->drvr, (FAR uint8_t *)ctrlreq);
|
||||
DRVR_FREE(hub->drvr, (FAR uint8_t *)ctrlreq);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -198,7 +198,7 @@ struct usbhost_state_s
|
|||
|
||||
/* This is an instance of the USB host driver bound to this class instance */
|
||||
|
||||
struct usbhost_driver_s *drvr;
|
||||
struct usbhost_hub_s *hub; /* The hub that manages the endpoint */
|
||||
|
||||
/* The remainder of the fields are provide o the keyboard class driver */
|
||||
|
||||
|
@ -322,7 +322,7 @@ static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv);
|
|||
|
||||
/* struct usbhost_registry_s methods */
|
||||
|
||||
static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
|
||||
static struct usbhost_class_s *usbhost_create(FAR struct usbhost_hub_s *hub,
|
||||
FAR const struct usbhost_id_s *id);
|
||||
|
||||
/* struct usbhost_class_s methods */
|
||||
|
@ -759,9 +759,12 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev
|
|||
static void usbhost_destroy(FAR void *arg)
|
||||
{
|
||||
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
char devname[DEV_NAMELEN];
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
DEBUGASSERT(priv != NULL && priv->hub != NULL);
|
||||
hub = priv->hub;
|
||||
|
||||
uvdbg("crefs: %d\n", priv->crefs);
|
||||
|
||||
/* Unregister the driver */
|
||||
|
@ -778,12 +781,12 @@ static void usbhost_destroy(FAR void *arg)
|
|||
|
||||
if (priv->epin)
|
||||
{
|
||||
DRVR_EPFREE(priv->drvr, priv->epin);
|
||||
DRVR_EPFREE(hub->drvr, priv->epin);
|
||||
}
|
||||
|
||||
if (priv->epout)
|
||||
{
|
||||
DRVR_EPFREE(priv->drvr, priv->epout);
|
||||
DRVR_EPFREE(hub->drvr, priv->epout);
|
||||
}
|
||||
|
||||
/* Free any transfer buffers */
|
||||
|
@ -797,7 +800,7 @@ static void usbhost_destroy(FAR void *arg)
|
|||
|
||||
/* Disconnect the USB host device */
|
||||
|
||||
DRVR_DISCONNECT(priv->drvr);
|
||||
DRVR_DISCONNECT(hub->drvr);
|
||||
|
||||
/* And free the class instance. Hmmm.. this may execute on the worker
|
||||
* thread and the work structure is part of what is getting freed. That
|
||||
|
@ -1001,6 +1004,7 @@ static inline void usbhost_encodescancode(FAR struct usbhost_state_s *priv,
|
|||
static int usbhost_kbdpoll(int argc, char *argv[])
|
||||
{
|
||||
FAR struct usbhost_state_s *priv;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
FAR struct usb_ctrlreq_s *ctrlreq;
|
||||
#ifndef CONFIG_HIDKBD_NODEBOUNCE
|
||||
uint8_t lastkey[6] = {0, 0, 0, 0, 0, 0};
|
||||
|
@ -1025,7 +1029,8 @@ static int usbhost_kbdpoll(int argc, char *argv[])
|
|||
*/
|
||||
|
||||
priv = g_priv;
|
||||
DEBUGASSERT(priv != NULL);
|
||||
DEBUGASSERT(priv != NULL && priv->hub);
|
||||
hub = priv->hub;
|
||||
|
||||
priv->polling = true;
|
||||
priv->crefs++;
|
||||
|
@ -1065,7 +1070,7 @@ static int usbhost_kbdpoll(int argc, char *argv[])
|
|||
|
||||
/* Send HID report request */
|
||||
|
||||
ret = DRVR_CTRLIN(priv->drvr, ctrlreq, priv->tbuffer);
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, priv->tbuffer);
|
||||
usbhost_givesem(&priv->exclsem);
|
||||
|
||||
/* Check for errors -- Bail if an excessive number of errors
|
||||
|
@ -1291,6 +1296,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
|
|||
FAR const uint8_t *configdesc, int desclen,
|
||||
uint8_t funcaddr)
|
||||
{
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
FAR struct usb_cfgdesc_s *cfgdesc;
|
||||
FAR struct usb_desc_s *desc;
|
||||
FAR struct usbhost_epdesc_s epindesc;
|
||||
|
@ -1300,9 +1306,9 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
|
|||
bool done = false;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(priv != NULL &&
|
||||
configdesc != NULL &&
|
||||
DEBUGASSERT(priv != NULL && priv->hub != NULL && configdesc != NULL &&
|
||||
desclen >= sizeof(struct usb_cfgdesc_s));
|
||||
hub = priv->hub;
|
||||
|
||||
/* Keep the compiler from complaining about uninitialized variables */
|
||||
|
||||
|
@ -1489,7 +1495,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
|
|||
* IN endpoint.
|
||||
*/
|
||||
|
||||
ret = DRVR_EPALLOC(priv->drvr, &epindesc, &priv->epin);
|
||||
ret = DRVR_EPALLOC(hub->drvr, &epindesc, &priv->epin);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate interrupt IN endpoint\n");
|
||||
|
@ -1503,11 +1509,11 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
|
|||
|
||||
if ((found & USBHOST_EPOUTFOUND) != 0)
|
||||
{
|
||||
ret = DRVR_EPALLOC(priv->drvr, &epoutdesc, &priv->epout);
|
||||
ret = DRVR_EPALLOC(hub->drvr, &epoutdesc, &priv->epout);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate interrupt OUT endpoint\n");
|
||||
(void)DRVR_EPFREE(priv->drvr, priv->epin);
|
||||
(void)DRVR_EPFREE(hub->drvr, priv->epin);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -1715,8 +1721,12 @@ static void usbhost_putle32(uint8_t *dest, uint32_t val)
|
|||
|
||||
static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
|
||||
{
|
||||
DEBUGASSERT(priv && priv->tbuffer == NULL);
|
||||
return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen);
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
|
||||
DEBUGASSERT(priv != NULL && priv->hub != NULL && priv->tbuffer == NULL);
|
||||
hub = priv->hub;
|
||||
|
||||
return DRVR_ALLOC(hub->drvr, &priv->tbuffer, &priv->tbuflen);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1736,13 +1746,16 @@ static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
|
|||
|
||||
static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv)
|
||||
{
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
int result = OK;
|
||||
|
||||
DEBUGASSERT(priv);
|
||||
|
||||
if (priv->tbuffer)
|
||||
{
|
||||
DEBUGASSERT(priv->drvr);
|
||||
result = DRVR_FREE(priv->drvr, priv->tbuffer);
|
||||
DEBUGASSERT(priv->hub);
|
||||
hub = priv->hub;
|
||||
result = DRVR_FREE(hub->drvr, priv->tbuffer);
|
||||
priv->tbuffer = NULL;
|
||||
priv->tbuflen = 0;
|
||||
}
|
||||
|
@ -1766,9 +1779,7 @@ static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv)
|
|||
* USB ports and multiple USB devices simultaneously connected.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - An instance of struct usbhost_driver_s that the class
|
||||
* implementation will "bind" to its state structure and will
|
||||
* subsequently use to communicate with the USB host driver.
|
||||
* hub - The hub that manages the new class instance.
|
||||
* id - In the case where the device supports multiple base classes,
|
||||
* subclasses, or protocols, this specifies which to configure for.
|
||||
*
|
||||
|
@ -1776,13 +1787,14 @@ static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv)
|
|||
* On success, this function will return a non-NULL instance of struct
|
||||
* usbhost_class_s that can be used by the USB host driver to communicate
|
||||
* with the USB host class. NULL is returned on failure; this function
|
||||
* will fail only if the drvr input parameter is NULL or if there are
|
||||
* will fail only if the hub input parameter is NULL or if there are
|
||||
* insufficient resources to create another USB host class instance.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
|
||||
FAR const struct usbhost_id_s *id)
|
||||
static FAR struct usbhost_class_s *
|
||||
usbhost_create(FAR struct usbhost_hub_s *hub,
|
||||
FAR const struct usbhost_id_s *id)
|
||||
{
|
||||
FAR struct usbhost_state_s *priv;
|
||||
|
||||
|
@ -1801,6 +1813,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
|
|||
{
|
||||
/* Initialize class method function pointers */
|
||||
|
||||
priv->usbclass.hub = hub;
|
||||
priv->usbclass.connect = usbhost_connect;
|
||||
priv->usbclass.disconnected = usbhost_disconnected;
|
||||
|
||||
|
@ -1815,9 +1828,9 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
|
|||
sem_init(&priv->exclsem, 0, 1);
|
||||
sem_init(&priv->waitsem, 0, 0);
|
||||
|
||||
/* Bind the driver to the storage class instance */
|
||||
/* Bind the hub to the storage class instance */
|
||||
|
||||
priv->drvr = drvr;
|
||||
priv->hub = hub;
|
||||
|
||||
/* Return the instance of the USB keyboard class driver */
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
* hub class.
|
||||
*/
|
||||
|
||||
struct usbhost_hubdev_s
|
||||
struct usbhost_hubpriv_s
|
||||
{
|
||||
FAR struct usb_ctrlreq_s *ctrlreq; /* Allocated control request */
|
||||
FAR uint8_t *buffer; /* Allocated buffer */
|
||||
|
@ -109,6 +109,16 @@ struct usbhost_hubdev_s
|
|||
/* Pointer to child devices */
|
||||
};
|
||||
|
||||
/* This represents the hub class structure. It must be cast compatible
|
||||
* with struct usbhost_class_s.
|
||||
*/
|
||||
|
||||
struct usbhost_hubclass_s
|
||||
{
|
||||
struct usbhost_class_s hubclass; /* Publicly visible class data */
|
||||
struct usbhost_hubpriv_s hubpriv; /* Private class data */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
@ -117,10 +127,11 @@ struct usbhost_hubdev_s
|
|||
|
||||
static inline uint8_t usbhost_allocaddr(void);
|
||||
static inline void usbhost_freeaddr(uint8_t addr);
|
||||
static inline FAR struct usbhost_class_s *
|
||||
usbhost_allocclass(FAR struct usbhost_driver_s *drvr,
|
||||
static inline FAR struct usbhost_hub_s *usbhost_allochub(
|
||||
FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_class_s *hubclass, uint8_t speed,
|
||||
uint8_t port);
|
||||
static inline void usbhost_freehub(FAR struct usbhost_hub_s *hub);
|
||||
static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass);
|
||||
|
||||
/* Worker thread actions */
|
||||
|
@ -144,7 +155,8 @@ static void usbhost_callback(FAR void *arg, int result);
|
|||
|
||||
/* struct usbhost_registry_s methods */
|
||||
|
||||
static int usbhost_create(FAR struct usbhost_class_s *hubclass,
|
||||
static FAR struct usbhost_class_s *usbhost_create(
|
||||
FAR struct usbhost_hub_s *drvr,
|
||||
FAR const struct usbhost_id_s *id);
|
||||
|
||||
/* struct usbhost_class_s methods */
|
||||
|
@ -230,7 +242,7 @@ static inline void usbhost_freeaddr(uint8_t addr)
|
|||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_allocclass
|
||||
* Name: usbhost_allochub
|
||||
*
|
||||
* Description:
|
||||
* This is really part of the logic that implements the create() method
|
||||
|
@ -248,81 +260,115 @@ static inline void usbhost_freeaddr(uint8_t addr)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR struct usbhost_class_s *
|
||||
usbhost_allocclass(FAR struct usbhost_driver_s *drvr,
|
||||
static inline FAR struct usbhost_hub_s *
|
||||
usbhost_allochub(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_class_s *hubclass,
|
||||
uint8_t speed, uint8_t port)
|
||||
{
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_class_s *devclass;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hub_s *child;
|
||||
FAR struct usbhost_hub_s *parent;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
DEBUGASSERT(hubclass->hub);
|
||||
parent = hubclass->hub;
|
||||
|
||||
/* We are not executing from an interrupt handler so we can just call
|
||||
* kmm_malloc() to get memory for the class instance.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(!up_interrupt_context());
|
||||
devclass = (FAR struct usbhost_class_s *)
|
||||
kmm_malloc(sizeof(struct usbhost_class_s));
|
||||
child = (FAR struct usbhost_hub_s *)
|
||||
kmm_malloc(sizeof(struct usbhost_hub_s));
|
||||
|
||||
uvdbg("Allocated: %p\n", devclass);
|
||||
uvdbg("Allocated: %p\n", child);
|
||||
|
||||
if (devclass != NULL)
|
||||
if (child != NULL)
|
||||
{
|
||||
struct usbhost_epdesc_s epdesc;
|
||||
int ret;
|
||||
|
||||
devclass->addr = usbhost_allocaddr();
|
||||
devclass->speed = speed;
|
||||
devclass->drvr = drvr;
|
||||
child->drvr = drvr;
|
||||
child->parent = parent;
|
||||
child->tt = NULL;
|
||||
child->funcaddr = usbhost_allocaddr();
|
||||
child->speed = speed;
|
||||
child->rhport = 0;
|
||||
|
||||
devclass->parent = hubclass;
|
||||
devclass->priv = NULL;
|
||||
|
||||
devclass->tt = NULL;
|
||||
devclass->rhport = 0;
|
||||
|
||||
if (!ROOTHUB(devclass))
|
||||
if (!ROOTHUB(parent))
|
||||
{
|
||||
if (hubclass->tt != NULL)
|
||||
if (parent->tt != NULL)
|
||||
{
|
||||
devclass->tt = hubclass->tt;
|
||||
devclass->rhport = hubclass->rhport;
|
||||
child->tt = parent->tt;
|
||||
child->rhport = parent->rhport;
|
||||
}
|
||||
else if ((devclass->speed != USB_SPEED_HIGH) &&
|
||||
(hubclass->speed == USB_SPEED_HIGH))
|
||||
else if ((child->speed != USB_SPEED_HIGH) &&
|
||||
(parent->speed == USB_SPEED_HIGH))
|
||||
{
|
||||
devclass->tt = &priv->tt;
|
||||
devclass->rhport = port;
|
||||
child->tt = &priv->tt;
|
||||
child->rhport = port;
|
||||
}
|
||||
}
|
||||
|
||||
epdesc.devclass = devclass;
|
||||
epdesc.hub = child;
|
||||
epdesc.addr = 0;
|
||||
epdesc.in = 0;
|
||||
epdesc.xfrtype = USB_EP_ATTR_XFER_CONTROL;
|
||||
epdesc.interval = 0;
|
||||
epdesc.mxpacketsize = 8;
|
||||
|
||||
ret = DRVR_EPALLOC(devclass->drvr, &epdesc, &devclass->ep0);
|
||||
ret = DRVR_EPALLOC(drvr, &epdesc, &child->ep0);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate ep0: %d\n", ret);
|
||||
usbhost_freeclass(devclass);
|
||||
devclass = NULL;
|
||||
usbhost_freehub(child);
|
||||
child = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return devclass;
|
||||
return child;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_freehub
|
||||
*
|
||||
* Description:
|
||||
* Free a hub instance previously allocated by usbhost_allochub().
|
||||
*
|
||||
* Input Parameters:
|
||||
* hub - A reference to the hub instance to be freed.
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void usbhost_freehub(FAR struct usbhost_hub_s *hub)
|
||||
{
|
||||
if (hub && !ROOTHUB(hub))
|
||||
{
|
||||
if (hub->ep0 != NULL)
|
||||
{
|
||||
DRVR_EPFREE(hub->drvr, hub->ep0);
|
||||
hub->ep0 = NULL;
|
||||
}
|
||||
|
||||
usbhost_freeaddr(hub->funcaddr);
|
||||
|
||||
/* Free the hub instance */
|
||||
|
||||
uvdbg("Freeing: %p\n", hub);
|
||||
kmm_free(hub);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_freeclass
|
||||
*
|
||||
* Description:
|
||||
* Free a class instance previously allocated by usbhost_allocclass().
|
||||
* Free a class instance previously allocated by usbhost_create().
|
||||
*
|
||||
* Input Parameters:
|
||||
* devclass - A reference to the class instance to be freed.
|
||||
|
@ -336,17 +382,11 @@ static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass)
|
|||
{
|
||||
DEBUGASSERT(devclass != NULL);
|
||||
|
||||
if (devclass->ep0 != NULL)
|
||||
{
|
||||
DRVR_EPFREE(devclass->drvr, devclass->ep0);
|
||||
devclass->ep0 = NULL;
|
||||
}
|
||||
/* Free the bound hub */
|
||||
|
||||
usbhost_freeaddr(devclass->addr);
|
||||
usbhost_freehub(devclass->hub);
|
||||
|
||||
/* Free the class instance (calling sched_free() in case we are executing
|
||||
* from an interrupt handler.
|
||||
*/
|
||||
/* Free the class instance */
|
||||
|
||||
uvdbg("Freeing: %p\n", devclass);
|
||||
kmm_free(devclass);
|
||||
|
@ -371,40 +411,38 @@ static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass)
|
|||
static void usbhost_destroy(FAR void *arg)
|
||||
{
|
||||
FAR struct usbhost_class_s *hubclass = (FAR struct usbhost_class_s *)arg;
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
if (priv != NULL)
|
||||
uvdbg("crefs: %d\n", priv->crefs);
|
||||
|
||||
if (priv->intin)
|
||||
{
|
||||
uvdbg("crefs: %d\n", priv->crefs);
|
||||
|
||||
if (priv->intin)
|
||||
{
|
||||
DRVR_EPFREE(hubclass->drvr, priv->intin);
|
||||
}
|
||||
|
||||
/* Destroy the semaphores */
|
||||
|
||||
sem_destroy(&priv->exclsem);
|
||||
|
||||
/* Destroy allocated child classes */
|
||||
|
||||
for (i = 0; i < USBHUB_MAX_PORTS; i++)
|
||||
{
|
||||
if (priv->childclass[i] != NULL)
|
||||
{
|
||||
CLASS_DISCONNECTED(priv->childclass[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free private class */
|
||||
|
||||
kmm_free(hubclass->priv);
|
||||
DEBUGASSERT(hubclass->hub);
|
||||
hub = hubclass->hub;
|
||||
DRVR_EPFREE(hub->drvr, priv->intin);
|
||||
}
|
||||
|
||||
/* Destroy the semaphores */
|
||||
|
||||
sem_destroy(&priv->exclsem);
|
||||
|
||||
/* Destroy allocated child classes */
|
||||
|
||||
for (i = 0; i < USBHUB_MAX_PORTS; i++)
|
||||
{
|
||||
if (priv->childclass[i] != NULL)
|
||||
{
|
||||
CLASS_DISCONNECTED(priv->childclass[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the allocated class structure */
|
||||
|
||||
usbhost_freeclass(hubclass);
|
||||
}
|
||||
|
||||
|
@ -435,7 +473,8 @@ static void usbhost_destroy(FAR void *arg)
|
|||
static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass,
|
||||
FAR const uint8_t *configdesc, int desclen)
|
||||
{
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
FAR struct usb_cfgdesc_s *cfgdesc;
|
||||
FAR struct usb_desc_s *desc;
|
||||
FAR struct usbhost_epdesc_s intindesc;
|
||||
|
@ -443,17 +482,19 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass,
|
|||
uint8_t found = 0;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
DEBUGASSERT(configdesc != NULL &&
|
||||
desclen >= sizeof(struct usb_cfgdesc_s));
|
||||
DEBUGASSERT(hubclass->hub);
|
||||
hub = hubclass->hub;
|
||||
|
||||
DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));
|
||||
|
||||
/* Initialize the interrupt IN endpoint information (only to prevent
|
||||
* compiler complaints)
|
||||
*/
|
||||
|
||||
intindesc.devclass = hubclass;
|
||||
intindesc.hub = hub;
|
||||
intindesc.addr = 0;
|
||||
intindesc.in = true;
|
||||
intindesc.xfrtype = USB_EP_ATTR_XFER_INT;
|
||||
|
@ -586,11 +627,11 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass,
|
|||
|
||||
/* We are good... Allocate the interrupt IN endpoint */
|
||||
|
||||
ret = DRVR_EPALLOC(hubclass->drvr, &intindesc, &priv->intin);
|
||||
ret = DRVR_EPALLOC(hub->drvr, &intindesc, &priv->intin);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate Interrupt IN endpoint: %d\n", ret);
|
||||
(void)DRVR_EPFREE(hubclass->drvr, priv->intin);
|
||||
(void)DRVR_EPFREE(hub->drvr, priv->intin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -621,14 +662,18 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass,
|
|||
|
||||
static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass)
|
||||
{
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
FAR struct usb_ctrlreq_s *ctrlreq;
|
||||
struct usb_hubdesc_s hubdesc;
|
||||
uint16_t hubchar;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
DEBUGASSERT(hubclass->hub);
|
||||
hub = hubclass->hub;
|
||||
|
||||
/* Get the hub descriptor */
|
||||
|
||||
|
@ -641,8 +686,7 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass)
|
|||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, USB_SIZEOF_HUBDESC);
|
||||
|
||||
ret = DRVR_CTRLIN(hubclass->drvr, hubclass->ep0, ctrlreq,
|
||||
(FAR uint8_t *)&hubdesc);
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq, (FAR uint8_t *)&hubdesc);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to read hub descriptor: %d\n", ret);
|
||||
|
@ -686,13 +730,17 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass)
|
|||
|
||||
static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
|
||||
{
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
FAR struct usb_ctrlreq_s *ctrlreq;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
if (on || ROOTHUB(hubclass))
|
||||
DEBUGASSERT(hubclass->hub);
|
||||
hub = hubclass->hub;
|
||||
|
||||
if (on || ROOTHUB(hub))
|
||||
{
|
||||
uint16_t req;
|
||||
int port, ret;
|
||||
|
@ -719,7 +767,7 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
|
|||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL);
|
||||
ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to power %d port %d: %d\n", on, port, ret);
|
||||
|
@ -752,7 +800,9 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
|
|||
static void usbhost_hubevent(FAR void *arg)
|
||||
{
|
||||
FAR struct usbhost_class_s *hubclass;
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hub_s *newhub;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usb_ctrlreq_s *ctrlreq;
|
||||
struct usb_portstatus_s portstatus;
|
||||
uint16_t status;
|
||||
|
@ -765,12 +815,13 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
|
||||
DEBUGASSERT(arg != NULL);
|
||||
hubclass = (FAR struct usbhost_class_s *)arg;
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
|
||||
DEBUGASSERT(priv->ctrlreq);
|
||||
ctrlreq = priv->ctrlreq;
|
||||
DEBUGASSERT(ctrlreq);
|
||||
|
||||
DEBUGASSERT(hubclass->hub);
|
||||
hub = hubclass->hub;
|
||||
|
||||
statusmap = priv->buffer[0];
|
||||
|
||||
|
@ -795,7 +846,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);
|
||||
|
||||
ret = DRVR_CTRLIN(hubclass->drvr, hubclass->ep0, ctrlreq,
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq,
|
||||
(FAR uint8_t *)&portstatus);
|
||||
if (ret != OK)
|
||||
{
|
||||
|
@ -820,7 +871,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL);
|
||||
ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to clear port %d change mask %x: %d\n",
|
||||
|
@ -856,7 +907,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);
|
||||
|
||||
ret = DRVR_CTRLIN(hubclass->drvr, hubclass->ep0, ctrlreq,
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq,
|
||||
(FAR uint8_t *)&portstatus);
|
||||
if (ret != OK)
|
||||
{
|
||||
|
@ -889,7 +940,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
(void)DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL);
|
||||
(void)DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL);
|
||||
}
|
||||
|
||||
debouncetime += 25;
|
||||
|
@ -912,7 +963,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL);
|
||||
ret = DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: ailed to reset port %d: %d\n", port, ret);
|
||||
|
@ -927,7 +978,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);
|
||||
|
||||
ret = DRVR_CTRLIN(hubclass->drvr, hubclass->ep0, ctrlreq,
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, ctrlreq,
|
||||
(FAR uint8_t *)&portstatus);
|
||||
if (ret != OK)
|
||||
{
|
||||
|
@ -954,7 +1005,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
(void)DRVR_CTRLOUT(hubclass->drvr, hubclass->ep0, ctrlreq, NULL);
|
||||
(void)DRVR_CTRLOUT(hub->drvr, hub->ep0, ctrlreq, NULL);
|
||||
}
|
||||
|
||||
if (status & USBHUB_PORT_STAT_HIGH_SPEED)
|
||||
|
@ -970,25 +1021,22 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
speed = USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
/* Allocate new class and enumerate */
|
||||
/* Allocate new hub class and enumerate */
|
||||
|
||||
priv->childclass[port] =
|
||||
usbhost_allocclass(hubclass->drvr, hubclass, speed, port);
|
||||
|
||||
if (priv->childclass[port] != NULL)
|
||||
newhub = usbhost_allochub(hub->drvr, hubclass, speed, port);
|
||||
if (newhub)
|
||||
{
|
||||
udbg("ERROR: Failed to allocated class\n");
|
||||
uvdbg("enumerate port %d speed %d\n", port, speed);
|
||||
|
||||
#if 0
|
||||
ret = usbhost_enumerate(priv->childclass[port]);
|
||||
ret = usbhost_enumerate(newhub, &priv->childclass[port]);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to enumerate port %d: %d\n",
|
||||
port, ret);
|
||||
usbhost_freehub(hub);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1016,8 +1064,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
|
||||
/* Get the number hub event */
|
||||
|
||||
ret = DRVR_ASYNCH(hubclass->drvr, priv->intin,
|
||||
(FAR uint8_t *)priv->ctrlreq,
|
||||
ret = DRVR_ASYNCH(hub->drvr, priv->intin, (FAR uint8_t *)priv->ctrlreq,
|
||||
sizeof(struct usb_ctrlreq_s), usbhost_callback,
|
||||
hubclass);
|
||||
if (ret != OK)
|
||||
|
@ -1084,13 +1131,11 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val)
|
|||
static void usbhost_callback(FAR void *arg, int result)
|
||||
{
|
||||
FAR struct usbhost_class_s *hubclass;
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
|
||||
DEBUGASSERT(arg != NULL);
|
||||
hubclass = (FAR struct usbhost_class_s *)arg;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
if (result != OK)
|
||||
{
|
||||
|
@ -1117,9 +1162,7 @@ static void usbhost_callback(FAR void *arg, int result)
|
|||
* USB ports and multiple USB devices simultaneously connected.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - An instance of struct usbhost_driver_s that the class
|
||||
* implementation will "bind" to its state structure and will
|
||||
* subsequently use to communicate with the USB host driver.
|
||||
* hub - The hub that manages the new class instance.
|
||||
* id - In the case where the device supports multiple base classes,
|
||||
* subclasses, or protocols, this specifies which to configure for.
|
||||
*
|
||||
|
@ -1127,30 +1170,44 @@ static void usbhost_callback(FAR void *arg, int result)
|
|||
* On success, this function will return a non-NULL instance of struct
|
||||
* usbhost_class_s that can be used by the USB host driver to communicate
|
||||
* with the USB host class. NULL is returned on failure; this function
|
||||
* will fail only if the drvr input parameter is NULL or if there are
|
||||
* will fail only if the hub input parameter is NULL or if there are
|
||||
* insufficient resources to create another USB host class instance.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int usbhost_create(FAR struct usbhost_class_s *hubclass,
|
||||
FAR const struct usbhost_id_s *id)
|
||||
static FAR struct usbhost_class_s *
|
||||
usbhost_create(FAR struct usbhost_hub_s *hub,
|
||||
FAR const struct usbhost_id_s *id)
|
||||
{
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hubclass_s *alloc;
|
||||
FAR struct usbhost_class_s *hubclass;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
size_t maxlen;
|
||||
int child;
|
||||
int ret;
|
||||
|
||||
/* Allocate a USB host class instance */
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct usbhost_hubdev_s));
|
||||
if (priv == NULL)
|
||||
alloc = kmm_zalloc(sizeof(struct usbhost_hubclass_s));
|
||||
if (alloc == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize the public class structure */
|
||||
|
||||
hubclass = &alloc->hubclass;
|
||||
hubclass->hub = hub;
|
||||
hubclass->connect = usbhost_connect;
|
||||
hubclass->disconnected = usbhost_disconnected;
|
||||
|
||||
/* Initialize the private class structure */
|
||||
|
||||
priv = &alloc->hubpriv;
|
||||
|
||||
/* Allocate memory for control requests */
|
||||
|
||||
ret = DRVR_ALLOC(hubclass->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen);
|
||||
ret = DRVR_ALLOC(hub->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("DRVR_ALLOC failed: %d\n", ret);
|
||||
|
@ -1159,19 +1216,13 @@ static int usbhost_create(FAR struct usbhost_class_s *hubclass,
|
|||
|
||||
/* Allocate buffer for status change (INT) endpoint */
|
||||
|
||||
ret = DRVR_IOALLOC(hubclass->drvr, &priv->buffer, 1);
|
||||
ret = DRVR_IOALLOC(hub->drvr, &priv->buffer, 1);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("DRVR_ALLOC failed: %d\n", ret);
|
||||
goto errout_with_ctrlreq;
|
||||
}
|
||||
|
||||
/* Initialize class method function pointers */
|
||||
|
||||
hubclass->connect = usbhost_connect;
|
||||
hubclass->disconnected = usbhost_disconnected;
|
||||
hubclass->priv = priv;
|
||||
|
||||
/* The initial reference count is 1... One reference is held by the driver */
|
||||
|
||||
priv->crefs = 1;
|
||||
|
@ -1187,14 +1238,14 @@ static int usbhost_create(FAR struct usbhost_class_s *hubclass,
|
|||
priv->childclass[child] = NULL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
return hubclass;
|
||||
|
||||
errout_with_ctrlreq:
|
||||
kmm_free(priv->ctrlreq);
|
||||
|
||||
errout_with_hub:
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1236,14 +1287,14 @@ errout_with_hub:
|
|||
static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
|
||||
FAR const uint8_t *configdesc, int desclen)
|
||||
{
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
DEBUGASSERT(configdesc != NULL &&
|
||||
desclen >= sizeof(struct usb_cfgdesc_s));
|
||||
DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));
|
||||
|
||||
/* Parse the configuration descriptor to get the endpoints */
|
||||
|
||||
|
@ -1272,8 +1323,10 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
|
|||
|
||||
/* INT request to periodically check port status */
|
||||
|
||||
ret = DRVR_ASYNCH(hubclass->drvr, priv->intin,
|
||||
(FAR uint8_t *)&priv->ctrlreq,
|
||||
DEBUGASSERT(hubclass->hub);
|
||||
hub = hubclass->hub;
|
||||
|
||||
ret = DRVR_ASYNCH(hub->drvr, priv->intin, (FAR uint8_t *)&priv->ctrlreq,
|
||||
sizeof(struct usb_ctrlreq_s), usbhost_callback,
|
||||
hubclass);
|
||||
}
|
||||
|
@ -1305,11 +1358,12 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
|
|||
|
||||
static int usbhost_disconnected(struct usbhost_class_s *hubclass)
|
||||
{
|
||||
FAR struct usbhost_hubdev_s *priv;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
irqstate_t flags;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
|
||||
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
/* Set an indication to any users of the device that the device is no
|
||||
* longer available.
|
||||
|
@ -1327,9 +1381,12 @@ static int usbhost_disconnected(struct usbhost_class_s *hubclass)
|
|||
ullvdbg("crefs: %d\n", priv->crefs);
|
||||
if (priv->crefs == 1)
|
||||
{
|
||||
DEBUGASSERT(hubclass->hub);
|
||||
hub = hubclass->hub;
|
||||
|
||||
/* Free buffer for status change (INT) endpoint */
|
||||
|
||||
DRVR_IOFREE(hubclass->drvr, priv->buffer);
|
||||
DRVR_IOFREE(hub->drvr, priv->buffer);
|
||||
|
||||
/* Power off (for root hub only) */
|
||||
(void)usbhost_hubpwr(hubclass, false);
|
||||
|
@ -1371,76 +1428,4 @@ int usbhost_hubinit(void)
|
|||
return usbhost_registerclass(&g_hub);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: usbhost_rh_connect
|
||||
*
|
||||
* Description:
|
||||
* Connects USB host root hub
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call
|
||||
* to the class create() method.
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
int usbhost_rh_connect(FAR struct usbhost_driver_s *drvr)
|
||||
{
|
||||
struct usbhost_class_s *hubclass = NULL;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
memset(g_addrmap, 0, 4*4);
|
||||
|
||||
hubclass = usbhost_allocclass(drvr, NULL, drvr->speed, 1);
|
||||
if (hubclass != NULL)
|
||||
{
|
||||
ret = usbhost_enumerate(hubclass);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: failed to enumerate root hub: %d\n", ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
drvr->roothub = hubclass;
|
||||
uvdbg("Total class memory %d+%d\n",
|
||||
sizeof(struct usbhost_class_s), sizeof(struct usbhost_hubdev_s));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: usbhost_rh_disconnect
|
||||
*
|
||||
* Description:
|
||||
* Disconnects USB host root hub
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call
|
||||
* to the class create() method.
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
int usbhost_rh_disconnect(FAR struct usbhost_driver_s *drvr)
|
||||
{
|
||||
FAR struct usbhost_class_s *hubclass = drvr->roothub;
|
||||
|
||||
if (hubclass != NULL)
|
||||
{
|
||||
CLASS_DISCONNECTED(hubclass);
|
||||
|
||||
drvr->roothub = NULL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USBHOST_HUB */
|
||||
|
|
|
@ -120,9 +120,9 @@ struct usbhost_state_s
|
|||
|
||||
struct usbhost_class_s usbclass;
|
||||
|
||||
/* This is an instance of the USB host driver bound to this class instance */
|
||||
/* This is an instance of the USB hub bound to this class instance */
|
||||
|
||||
struct usbhost_driver_s *drvr;
|
||||
struct usbhost_hub_s *hub;
|
||||
|
||||
/* The remainder of the fields are provide to the mass storage class */
|
||||
|
||||
|
@ -228,7 +228,7 @@ static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *pri
|
|||
|
||||
/* struct usbhost_registry_s methods */
|
||||
|
||||
static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
|
||||
static struct usbhost_class_s *usbhost_create(FAR struct usbhost_hub_s *hub,
|
||||
FAR const struct usbhost_id_s *id);
|
||||
|
||||
/* struct usbhost_class_s methods */
|
||||
|
@ -679,6 +679,7 @@ usbhost_writecbw(size_t startsector, uint16_t blocksize,
|
|||
static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv)
|
||||
{
|
||||
FAR struct usb_ctrlreq_s *req = (FAR struct usb_ctrlreq_s *)priv->tbuffer;
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
DEBUGASSERT(priv && priv->tbuffer);
|
||||
int ret;
|
||||
|
||||
|
@ -688,12 +689,16 @@ static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv)
|
|||
*/
|
||||
|
||||
uvdbg("Request maximum logical unit number\n");
|
||||
|
||||
memset(req, 0, sizeof(struct usb_ctrlreq_s));
|
||||
req->type = USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE;
|
||||
req->req = USBMSC_REQ_GETMAXLUN;
|
||||
usbhost_putle16(req->len, 1);
|
||||
|
||||
ret = DRVR_CTRLIN(priv->drvr, req, priv->tbuffer);
|
||||
DEBUGASSERT(priv->hub);
|
||||
hub = priv->hub;
|
||||
|
||||
ret = DRVR_CTRLIN(hub->drvr, hub->ep0, req, priv->tbuffer);
|
||||
if (ret != OK)
|
||||
{
|
||||
/* Devices that do not support multiple LUNs may stall this command.
|
||||
|
@ -723,13 +728,13 @@ static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv)
|
|||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_testunitreadycbw(cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout,
|
||||
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, USBMSC_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
|
@ -757,19 +762,19 @@ static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv)
|
|||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_requestsensecbw(cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout,
|
||||
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Receive the sense data response */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, USBMSC_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
|
@ -799,13 +804,13 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
|
|||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_readcapacitycbw(cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout,
|
||||
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Receive the read capacity CBW IN response */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, SCSIRESP_READCAPACITY10_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
|
@ -817,7 +822,7 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
|
|||
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, USBMSC_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
|
@ -846,13 +851,13 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
|
|||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_inquirycbw(cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout,
|
||||
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Receive the CBW IN response */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, SCSIRESP_INQUIRY_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
|
@ -865,7 +870,7 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
|
|||
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, USBMSC_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
|
@ -914,12 +919,12 @@ static void usbhost_destroy(FAR void *arg)
|
|||
|
||||
if (priv->bulkout)
|
||||
{
|
||||
DRVR_EPFREE(priv->drvr, priv->bulkout);
|
||||
DRVR_EPFREE(priv->hub->drvr, priv->bulkout);
|
||||
}
|
||||
|
||||
if (priv->bulkin)
|
||||
{
|
||||
DRVR_EPFREE(priv->drvr, priv->bulkin);
|
||||
DRVR_EPFREE(priv->hub->drvr, priv->bulkin);
|
||||
}
|
||||
|
||||
/* Free any transfer buffers */
|
||||
|
@ -932,7 +937,7 @@ static void usbhost_destroy(FAR void *arg)
|
|||
|
||||
/* Disconnect the USB host device */
|
||||
|
||||
DRVR_DISCONNECT(priv->drvr);
|
||||
DRVR_DISCONNECT(priv->hub->drvr);
|
||||
|
||||
/* And free the class instance. Hmmm.. this may execute on the worker
|
||||
* thread and the work structure is part of what is getting freed. That
|
||||
|
@ -1149,18 +1154,18 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
|
|||
|
||||
/* We are good... Allocate the endpoints */
|
||||
|
||||
ret = DRVR_EPALLOC(priv->drvr, &boutdesc, &priv->bulkout);
|
||||
ret = DRVR_EPALLOC(priv->hub->drvr, &boutdesc, &priv->bulkout);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate Bulk OUT endpoint\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = DRVR_EPALLOC(priv->drvr, &bindesc, &priv->bulkin);
|
||||
ret = DRVR_EPALLOC(priv->hub->drvr, &bindesc, &priv->bulkin);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate Bulk IN endpoint\n");
|
||||
(void)DRVR_EPFREE(priv->drvr, priv->bulkout);
|
||||
(void)DRVR_EPFREE(priv->hub->drvr, priv->bulkout);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1552,7 +1557,7 @@ static void usbhost_putbe32(uint8_t *dest, uint32_t val)
|
|||
static inline int usbhost_talloc(FAR struct usbhost_state_s *priv)
|
||||
{
|
||||
DEBUGASSERT(priv && priv->tbuffer == NULL);
|
||||
return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen);
|
||||
return DRVR_ALLOC(priv->hub->drvr, &priv->tbuffer, &priv->tbuflen);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1577,8 +1582,8 @@ static inline int usbhost_tfree(FAR struct usbhost_state_s *priv)
|
|||
|
||||
if (priv->tbuffer)
|
||||
{
|
||||
DEBUGASSERT(priv->drvr);
|
||||
result = DRVR_FREE(priv->drvr, priv->tbuffer);
|
||||
DEBUGASSERT(priv->hub->drvr);
|
||||
result = DRVR_FREE(priv->hub->drvr, priv->tbuffer);
|
||||
priv->tbuffer = NULL;
|
||||
priv->tbuflen = 0;
|
||||
}
|
||||
|
@ -1631,9 +1636,7 @@ static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *pri
|
|||
* USB ports and multiple USB devices simultaneously connected.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - An instance of struct usbhost_driver_s that the class
|
||||
* implementation will "bind" to its state structure and will
|
||||
* subsequently use to communicate with the USB host driver.
|
||||
* hub - The hub that manages the new class instance.
|
||||
* id - In the case where the device supports multiple base classes,
|
||||
* subclasses, or protocols, this specifies which to configure for.
|
||||
*
|
||||
|
@ -1641,13 +1644,13 @@ static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *pri
|
|||
* On success, this function will return a non-NULL instance of struct
|
||||
* usbhost_class_s that can be used by the USB host driver to communicate
|
||||
* with the USB host class. NULL is returned on failure; this function
|
||||
* will fail only if the drvr input parameter is NULL or if there are
|
||||
* will fail only if the hub input parameter is NULL or if there are
|
||||
* insufficient resources to create another USB host class instance.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct usbhost_class_s *
|
||||
usbhost_create(FAR struct usbhost_driver_s *drvr,
|
||||
usbhost_create(FAR struct usbhost_hub_s *hub,
|
||||
FAR const struct usbhost_id_s *id)
|
||||
{
|
||||
FAR struct usbhost_state_s *priv;
|
||||
|
@ -1667,6 +1670,7 @@ usbhost_create(FAR struct usbhost_driver_s *drvr,
|
|||
{
|
||||
/* Initialize class method function pointers */
|
||||
|
||||
priv->usbclass.hub = hub;
|
||||
priv->usbclass.connect = usbhost_connect;
|
||||
priv->usbclass.disconnected = usbhost_disconnected;
|
||||
|
||||
|
@ -1678,10 +1682,6 @@ usbhost_create(FAR struct usbhost_driver_s *drvr,
|
|||
|
||||
sem_init(&priv->exclsem, 0, 1);
|
||||
|
||||
/* Bind the driver to the storage class instance */
|
||||
|
||||
priv->drvr = drvr;
|
||||
|
||||
/* NOTE: We do not yet know the geometry of the USB mass storage device */
|
||||
|
||||
/* Return the instance of the USB mass storage class */
|
||||
|
@ -2003,19 +2003,19 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
|
|||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout,
|
||||
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Receive the user data */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
buffer, priv->blocksize * nsectors);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, USBMSC_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
|
@ -2096,19 +2096,19 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe
|
|||
/* Construct and send the CBW */
|
||||
|
||||
usbhost_writecbw(startsector, priv->blocksize, nsectors, cbw);
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout,
|
||||
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Send the user data */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkout,
|
||||
(uint8_t*)buffer, priv->blocksize * nsectors);
|
||||
if (result == OK)
|
||||
{
|
||||
/* Receive the CSW */
|
||||
|
||||
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
|
||||
result = DRVR_TRANSFER(priv->hub->drvr, priv->bulkin,
|
||||
priv->tbuffer, USBMSC_CSW_SIZEOF);
|
||||
if (result == OK)
|
||||
{
|
||||
|
|
|
@ -61,29 +61,27 @@
|
|||
* Name: ROOTHUB
|
||||
*
|
||||
* Description:
|
||||
* Check for root hub
|
||||
* Check if a hub instance is the root hub.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#define ROOTHUB(devclass) ((devclass)->parent == NULL)
|
||||
#define ROOTHUB(hub) ((hub)->parent == NULL)
|
||||
|
||||
/************************************************************************************
|
||||
* Name: CLASS_CREATE
|
||||
*
|
||||
* Description:
|
||||
* This macro will call the create() method of struct usbhost_registry_s. The
|
||||
* create() method is a callback into the class implementation. It is used to
|
||||
* (1) create a new instance of the USB host class state and to (2) bind a USB
|
||||
* host driver "session" to the class instance. Use of this create() method
|
||||
* will support environments where there may be multiple USB ports and multiple
|
||||
* USB devices simultaneously connected.
|
||||
* This macro will call the create() method of struct usbhost_registry_s. The create()
|
||||
* method is a callback into the class implementation. It is used to (1) create
|
||||
* a new instance of the USB host class state and to (2) bind a USB host driver
|
||||
* "session" to the class instance. Use of this create() method will support
|
||||
* environments where there may be multiple USB ports and multiple USB devices
|
||||
* simultaneously connected.
|
||||
*
|
||||
* Input Parameters:
|
||||
* reg - The USB host class registry entry previously obtained from a call to
|
||||
* usbhost_findclass().
|
||||
* devclass - An instance of struct usbhost_driver_s that the class
|
||||
* implementation will "bind" to its state structure and will subsequently
|
||||
* use to communicate with the USB host driver.
|
||||
* hub - The hub that manages the new class instance.
|
||||
* id - In the case where the device supports multiple base classes, subclasses, or
|
||||
* protocols, this specifies which to configure for.
|
||||
*
|
||||
|
@ -91,7 +89,7 @@
|
|||
* On success, this function will return a non-NULL instance of struct
|
||||
* usbhost_class_s that can be used by the USB host driver to communicate with the
|
||||
* USB host class. NULL is returned on failure; this function will fail only if
|
||||
* the devclass input parameter is NULL or if there are insufficient resources to
|
||||
* the drvr input parameter is NULL or if there are insufficient resources to
|
||||
* create another USB host class instance.
|
||||
*
|
||||
* Assumptions:
|
||||
|
@ -101,7 +99,7 @@
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
#define CLASS_CREATE(reg, devclass, id) ((reg)->create(devclass, id))
|
||||
#define CLASS_CREATE(reg,hub,id) ((reg)->create(hub,id))
|
||||
|
||||
/************************************************************************************
|
||||
* Name: CLASS_CONNECT
|
||||
|
@ -567,7 +565,7 @@ struct usbhost_id_s
|
|||
* connected to the USB port.
|
||||
*/
|
||||
|
||||
struct usbhost_driver_s; /* Forward reference to the driver state structure */
|
||||
struct usbhost_hub_s; /* Forward reference to the hub state structure */
|
||||
struct usbhost_class_s; /* Forward reference to the class state structure */
|
||||
struct usbhost_registry_s
|
||||
{
|
||||
|
@ -576,7 +574,7 @@ struct usbhost_registry_s
|
|||
* provide those instances in write-able memory (RAM).
|
||||
*/
|
||||
|
||||
struct usbhost_registry_s *flink;
|
||||
struct usbhost_registry_s *flink;
|
||||
|
||||
/* This is a callback into the class implementation. It is used to (1) create
|
||||
* a new instance of the USB host class state and to (2) bind a USB host driver
|
||||
|
@ -585,14 +583,14 @@ struct usbhost_registry_s
|
|||
* simultaneously connected (see the CLASS_CREATE() macro above).
|
||||
*/
|
||||
|
||||
int (*create)(FAR struct usbhost_class_s *devclass,
|
||||
FAR const struct usbhost_id_s *id);
|
||||
FAR struct usbhost_class_s *(*create)(FAR struct usbhost_hub_s *hub,
|
||||
FAR const struct usbhost_id_s *id);
|
||||
|
||||
/* This information uniquely identifies the USB host class implementation that
|
||||
* goes with a specific USB device.
|
||||
*/
|
||||
|
||||
uint8_t nids; /* Number of IDs in the id[] array */
|
||||
uint8_t nids; /* Number of IDs in the id[] array */
|
||||
FAR const struct usbhost_id_s *id; /* An array of ID info. Actual dimension is nids */
|
||||
};
|
||||
|
||||
|
@ -605,22 +603,34 @@ struct usbhost_registry_s
|
|||
|
||||
typedef FAR void *usbhost_ep_t;
|
||||
|
||||
/* Every class connects to the host controller driver (HCD) via a hub. That
|
||||
* may be an external hub or the internal, root hub. The root hub is managed
|
||||
* by the HCD. This structure provides for the linkages in that event that
|
||||
* an external hub.
|
||||
*/
|
||||
|
||||
struct usbhost_hub_s
|
||||
{
|
||||
FAR struct usbhost_driver_s *drvr; /* Common host driver */
|
||||
usbhost_ep_t ep0; /* Control endpoint, ep0 */
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
FAR struct usbhost_hub_s *parent; /* Parent hub */
|
||||
FAR struct usb_hubtt_s *tt; /* Transaction translator hub */
|
||||
#endif
|
||||
uint8_t funcaddr; /* Device function address */
|
||||
uint8_t speed; /* Device speed */
|
||||
uint8_t rhport; /* Root hub port index */
|
||||
};
|
||||
|
||||
/* struct usbhost_class_s provides access from the USB host driver to the USB host
|
||||
* class implementation.
|
||||
*/
|
||||
|
||||
struct usbhost_class_s
|
||||
{
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
FAR struct usbhost_driver_s *drvr; /* Common host driver */
|
||||
FAR struct usbhost_class_s *parent; /* Parent class */
|
||||
usbhost_ep_t ep0; /* Control endpoint, ep0 */
|
||||
FAR struct usb_hubtt_s *tt; /* Transaction translator hub */
|
||||
FAR void *priv; /* Class specific private data */
|
||||
uint8_t addr; /* Device function address */
|
||||
uint8_t speed; /* Device speed */
|
||||
uint8_t rhport; /* Root hub port index */
|
||||
#endif
|
||||
/* The hub used by this class instance */
|
||||
|
||||
FAR struct usbhost_hub_s *hub;
|
||||
|
||||
/* Provides the configuration descriptor to the class. The configuration
|
||||
* descriptor contains critical information needed by the class in order to
|
||||
|
@ -644,14 +654,14 @@ struct usbhost_class_s
|
|||
struct usbhost_epdesc_s
|
||||
{
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
FAR struct usbhost_class_s *devclass; /* Class */
|
||||
FAR struct usbhost_hub_s *hub; /* Hub that manages the endpoint */
|
||||
#endif
|
||||
uint8_t addr; /* Endpoint address */
|
||||
bool in; /* Direction: true->IN */
|
||||
uint8_t funcaddr; /* USB address of function containing endpoint */
|
||||
uint8_t xfrtype; /* Transfer type. See USB_EP_ATTR_XFER_* in usb.h */
|
||||
uint8_t interval; /* Polling interval */
|
||||
uint16_t mxpacketsize; /* Max packetsize */
|
||||
uint8_t addr; /* Endpoint address */
|
||||
bool in; /* Direction: true->IN */
|
||||
uint8_t funcaddr; /* USB address of function containing endpoint */
|
||||
uint8_t xfrtype; /* Transfer type. See USB_EP_ATTR_XFER_* in usb.h */
|
||||
uint8_t interval; /* Polling interval */
|
||||
uint16_t mxpacketsize; /* Max packetsize */
|
||||
};
|
||||
|
||||
/* This structure provides information about the connected device */
|
||||
|
@ -967,6 +977,10 @@ int usbhost_wlaninit(void);
|
|||
* Name: usbhost_enumerate
|
||||
*
|
||||
* Description:
|
||||
* This is a share-able implementation of most of the logic required by the
|
||||
* driver enumerate() method. This logic within this method should be common
|
||||
* to all USB host drivers.
|
||||
*
|
||||
* Enumerate the connected device. 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
|
||||
|
@ -977,62 +991,24 @@ int usbhost_wlaninit(void);
|
|||
* charge of the sequence of operations.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devclass - USB class information common across all classes. Whoever calls
|
||||
* enumerate should fill address, speed, driver and parent class
|
||||
* pointer. Enumeration will fill the control endpoint ep0,
|
||||
* transaction translator (if applicable) and private data
|
||||
* hub - The hub that manages the new class.
|
||||
* devclass - If the class driver for the device is successful located
|
||||
* and bound to the hub, the allocated class instance is returned into
|
||||
* this caller-provided memory location.
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Only a single class bound to a single device is supported.
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
* - Never called from an interrupt handler.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
int usbhost_enumerate(FAR struct usbhost_class_s *devclass);
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
/*******************************************************************************
|
||||
* Name: usbhost_rh_connect
|
||||
*
|
||||
* Description:
|
||||
* Registers USB host root hub
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
int usbhost_rh_connect(FAR struct usbhost_driver_s *drvr);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: usbhost_rh_disconnect
|
||||
*
|
||||
* Description:
|
||||
* Disconnects USB host root hub
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call
|
||||
* to the class create() method.
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
int usbhost_rh_disconnect(FAR struct usbhost_driver_s *drvr);
|
||||
#endif
|
||||
int usbhost_enumerate(FAR struct usbhost_hub_s *hub,
|
||||
FAR struct usbhost_class_s **devclass);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
|
|
Loading…
Reference in a new issue