USB hub: Decouple class and hub structures

This commit is contained in:
Gregory Nutt
2015-04-20 12:06:47 -06:00
parent 814ce6fd02
commit f7f3a7f74d
5 changed files with 380 additions and 399 deletions
+40 -33
View File
@@ -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;
+38 -25
View File
@@ -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 */
File diff suppressed because it is too large Load Diff
+39 -39
View File
@@ -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)
{
+56 -80
View File
@@ -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)