USB hub: Add asych HCD interface
This commit is contained in:
commit
8e23ad72b5
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
/************************************************************************************
|
||||
|
Loading…
Reference in New Issue
Block a user