USB hub: Add asych HCD interface

This commit is contained in:
Gregory Nutt 2015-04-20 08:41:33 -06:00
commit 8e23ad72b5
2 changed files with 70 additions and 133 deletions

View File

@ -34,13 +34,6 @@
*
****************************************************************************/
/* TODO:
* - For EHCI controller, enable use of companion controllers
* or transaction translator with root hub. Current assumption
* is that device connected on EHCI root hub is a high-speed
* device.
*/
/****************************************************************************
* Included Files
****************************************************************************/
@ -91,7 +84,7 @@
* hub class.
*/
struct usbhost_hub_s
struct usbhost_hubdev_s
{
FAR struct usb_ctrlreq_s *ctrlreq; /* Allocated control request */
FAR uint8_t *buffer; /* Allocated buffer */
@ -140,7 +133,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass,
static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass);
static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass,
bool on);
static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer);
static void usbhost_hubevent(FAR void *arg);
/* (Little Endian) Data helpers */
@ -259,11 +252,11 @@ static inline FAR struct usbhost_class_s *
FAR struct usbhost_class_s *hubclass,
uint8_t speed, uint8_t port)
{
FAR struct usbhost_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
FAR struct usbhost_class_s *devclass;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
/* We are not executing from an interrupt handler so we can just call
* kmm_malloc() to get memory for the class instance.
@ -377,12 +370,12 @@ 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_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
int i;
DEBUGASSERT(hubclass != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
if (priv != NULL)
{
uvdbg("crefs: %d\n", priv->crefs);
@ -441,7 +434,7 @@ 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_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
FAR struct usb_cfgdesc_s *cfgdesc;
FAR struct usb_desc_s *desc;
FAR struct usbhost_epdesc_s intindesc;
@ -450,7 +443,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass,
int ret;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
DEBUGASSERT(configdesc != NULL &&
desclen >= sizeof(struct usb_cfgdesc_s));
@ -619,14 +612,14 @@ 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_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
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_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
/* Get the hub descriptor */
@ -683,11 +676,11 @@ 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_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
FAR struct usb_ctrlreq_s *ctrlreq;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
if (on || ROOTHUB(hubclass))
{
@ -728,43 +721,6 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
return OK;
}
/****************************************************************************
* Name: usbhost_intxfer
*
* Description:
* Set-up to receive a callback when an interrupt packet is received.
*
* Input Parameters:
* devclass - A reference to the class instance.
* xfer - Describes the transfer to be performed
* callback - The transfer complete callback
*
* Returned Values:
* On sucess, zero (OK) is returned. On failure, an negated errno value
* is returned to indicate the nature of the failure.
*
****************************************************************************/
static int usbhost_intxfer(FAR struct usbhost_class_s *devclass,
FAR struct usbhost_transfer_s *xfer,
void (*callback)(FAR struct usbhost_transfer_s *))
{
int ret;
xfer->callback = callback;
if (ROOTHUB(devclass))
{
ret = DRVR_RHSTATUS(devclass->drvr, xfer);
}
else
{
ret = DRVR_TRANSFER(devclass->drvr, xfer);
}
return ret;
}
/****************************************************************************
* Name: usbhost_hubevent
*
@ -783,10 +739,10 @@ static int usbhost_intxfer(FAR struct usbhost_class_s *devclass,
*
****************************************************************************/
static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
static void usbhost_hubevent(FAR void *arg)
{
FAR struct usbhost_class_s *hubclass;
FAR struct usbhost_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
FAR struct usb_ctrlreq_s *ctrlreq;
struct usb_portstatus_s portstatus;
uint16_t status;
@ -797,11 +753,11 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
int port;
int ret;
DEBUGASSERT(xfer != NULL && xfer->devclass != NULL);
hubclass = (FAR struct usbhost_class_s *)xfer->devclass;
DEBUGASSERT(arg != NULL);
hubclass = (FAR struct usbhost_class_s *)arg;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
ctrlreq = priv->ctrlreq;
DEBUGASSERT(ctrlreq);
@ -1047,7 +1003,8 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
xfer->status = -EIO;
ret = usbhost_intxfer(hubclass, xfer, usbhost_callback);
ret = DRVR_ASYNCH(hubclass->drvr, &priv->ctrlreq, sizeof(struct usb_ctrlreq_s)
usbhost_callback, hubclass);
if (ret != OK)
{
udbg("ERROR: Failed to queue interrupt endpoint: %d\n", ret);
@ -1109,23 +1066,23 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val)
*
****************************************************************************/
static void usbhost_callback(FAR struct usbhost_transfer_s *xfer)
static void usbhost_callback(FAR void *arg)
{
FAR struct usbhost_class_s *hubclass;
FAR struct usbhost_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
DEBUGASSERT(xfer != NULL && xfer->devclass != NULL);
hubclass = (FAR struct usbhost_class_s *)xfer->devclass;
DEBUGASSERT(arg != NULL);
hubclass = (FAR struct usbhost_class_s *)arg;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
if (xfer->status != OK)
{
priv->buffer[0] = 0;
}
(void)work_queue(HPWORK, &xfer->work, (worker_t)usbhost_hubevent, xfer, 0);
(void)work_queue(HPWORK, &xfer->work, (worker_t)usbhost_hubevent, hubclass, 0);
}
/****************************************************************************
@ -1162,14 +1119,14 @@ static void usbhost_callback(FAR struct usbhost_transfer_s *xfer)
static int usbhost_create(FAR struct usbhost_class_s *hubclass,
FAR const struct usbhost_id_s *id)
{
FAR struct usbhost_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
size_t maxlen;
int child;
int ret;
/* Allocate a USB host class instance */
priv = kmm_zalloc(sizeof(struct usbhost_hub_s));
priv = kmm_zalloc(sizeof(struct usbhost_hubdev_s));
if (priv == NULL)
{
return -ENOMEM;
@ -1263,11 +1220,11 @@ errout_with_hub:
static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
FAR const uint8_t *configdesc, int desclen)
{
FAR struct usbhost_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
int ret;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
DEBUGASSERT(configdesc != NULL &&
desclen >= sizeof(struct usb_cfgdesc_s));
@ -1299,7 +1256,9 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
/* INT request to periodically check port status */
ret = usbhost_intxfer(hubclass, &priv->ctrlreq, usbhost_callback);
ret = DRVR_ASYNCH(hubclass->drvr, &priv->ctrlreq,
sizeof(struct usb_ctrlreq_s), usbhost_callback,
hubclass);
}
return ret;
@ -1329,11 +1288,11 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
static int usbhost_disconnected(struct usbhost_class_s *hubclass)
{
FAR struct usbhost_hub_s *priv;
FAR struct usbhost_hubdev_s *priv;
irqstate_t flags;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
priv = (FAR struct usbhost_hubdev_s *)hubclass->priv;
/* Set an indication to any users of the device that the device is no
* longer available.
@ -1430,7 +1389,7 @@ int usbhost_rh_connect(FAR struct usbhost_driver_s *drvr)
{
drvr->roothub = hubclass;
uvdbg("Total class memory %d+%d\n",
sizeof(struct usbhost_class_s), sizeof(struct usbhost_hub_s));
sizeof(struct usbhost_class_s), sizeof(struct usbhost_hubdev_s));
}
}

View File

@ -470,7 +470,7 @@
#define DRVR_CTRLOUT(drvr,req,buffer) ((drvr)->ctrlout(drvr,req,buffer))
/************************************************************************************
* Name: DRVR_TRANSFER
* Name: DRVR_TRANSFER and DRVR_ASYNCH
*
* Description:
* Process a request to handle a transfer descriptor. This method will
@ -478,17 +478,23 @@
* be queued; Neither this method nor the ctrlin or ctrlout methods can be called
* again until this function returns.
*
* This is a blocking method; this functions will not return until the
* - 'transfer' is a blocking method; this method will not return until the
* transfer has completed.
* - 'asynch' will return immediately. When the transfer completes, the
* semaphore will be posted.
*
* Input Parameters:
* drvr - The USB host driver instance obtained as a parameter from the call to
* the class create() method.
* ed - The IN or OUT endpoint descriptor for the device endpoint on which to
* ep - The IN or OUT endpoint descriptor for the device endpoint on which to
* perform the transfer.
* buffer - A buffer containing the data to be sent (OUT endpoint) or received
* (IN endpoint). buffer must have been allocated using DRVR_ALLOC
* buflen - The length of the data to be sent or received.
* callback - This function will be called when the transfer completes ('asynch'
* only).
* arg - The arbitrary parameter that will be passed to the callback function
* when the transfer completes ('asynch' only).
*
* Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is
@ -505,7 +511,13 @@
*
************************************************************************************/
#define DRVR_TRANSFER(drvr,xfer) ((drvr)->transfer(drvr,xfer))
#define DRVR_TRANSFER(drvr,ep,buffer,buflen) \
((drvr)->transfer(drvr,ep,buffer,buflen))
#ifdef CONFIG_USBHOST_ASYNCH
#define DRVR_ASYNCH(drvr,ep,buffer,buflen,callback,arg) \
((drvr)->asynch(drvr,ep,buffer,buflen,callback,arg))
#endif
/************************************************************************************
* Name: DRVR_DISCONNECT
@ -531,33 +543,6 @@
#define DRVR_DISCONNECT(drvr) ((drvr)->disconnect(drvr))
/************************************************************************************
* Name: DRVR_RHSTATUS
*
* Description:
* Called by hub class to control root hub.
*
* Input Parameters:
* drvr - The USB host driver instance obtained as a parameter from the call to
* the class create() method.
* xfer - Describes the request to be sent. This request must lie in memory
* created by DRVR_ALLOC.
* cmd - A buffer used for sending the request and for returning any
* responses. This buffer must be large enough to hold the length value
* in the request description. buffer must have been allocated using DRVR_ALLOC.
*
* Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is
* returned indicating the nature of the failure
*
* Assumptions:
*
************************************************************************************/
#ifdef CONFIG_USBHOST_HUB
# define DRVR_RHSTATUS(drvr,xfer) ((drvr)->rhstatus(drvr,xfer))
#endif
/************************************************************************************
* Public Types
************************************************************************************/
@ -675,19 +660,6 @@ struct usbhost_devinfo_s
uint8_t speed:2; /* Device speed: 0=low, 1=full, 2=high */
};
/* Generic transfer structure */
struct usbhost_transfer_s
{
size_t buflen;
size_t len;
int status;
/* Device class */
FAR struct usbhost_class_s *devclass;
};
/* struct usbhost_connection_s provides as interface between platform-specific
* connection monitoring and the USB host driver connection and enumeration
* logic.
@ -712,6 +684,10 @@ struct usbhost_connection_s
int (*enumerate)(FAR struct usbhost_connection_s *conn, int rhpndx);
};
/* Callback type used with asynchronous transfers */
typedef void (*usbhost_asynch_t)(FAR void *arg);
/* struct usbhost_driver_s provides access to the USB host driver from the
* USB host class implementation.
*/
@ -779,9 +755,9 @@ struct usbhost_driver_s
/* Process a IN or OUT request on the control endpoint. These methods
* will enqueue the request and wait for it to complete. Only one transfer may
* be queued; Neither these methods nor the transfer() method can be called again
* until the control transfer functions returns.
* until the control transfer methods returns.
*
* These are blocking methods; these functions will not return until the
* These are blocking methods; these methods will not return until the
* control transfer has completed.
*/
@ -797,12 +773,21 @@ struct usbhost_driver_s
* be queued; Neither this method nor the ctrlin or ctrlout methods can be called
* again until this function returns.
*
* This is a blocking method; this functions will not return until the
* transfer has completed.
* - 'transfer' is a blocking method; this method will not return until the
* transfer has completed.
* - 'asynch' will return immediately. When the transfer completes, the
* the callback will be invoked with the provided transfer. This method
* is useful for receiving interrupt transfers which may come
* infrequently.
*/
int (*transfer)(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_transfer_s *xfer);
int (*transfer)(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
FAR uint8_t *buffer, size_t buflen);
#ifdef CONFIG_USBHOST_ASYNCH
int (*asynch)(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
FAR uint8_t *buffer, size_t buflen,
usbhost_asynch_t callback, FAR void *arg);
#endif
/* Called by the class when an error occurs and driver has been disconnected.
* The USB host driver should discard the handle to the class instance (it is
@ -811,13 +796,6 @@ struct usbhost_driver_s
*/
void (*disconnect)(FAR struct usbhost_driver_s *drvr);
#ifdef CONFIG_USBHOST_HUB
/* Called by hub class to control root hub. */
int (*rhstatus)(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_transfer_s *xfer);
#endif
};
/************************************************************************************