USB hub: First steps to make interfaces backward compatible

This commit is contained in:
Gregory Nutt 2015-04-20 07:45:11 -06:00
parent 8c1c365ae7
commit a6d9f0622c
4 changed files with 208 additions and 325 deletions

View File

@ -40,12 +40,16 @@ ifeq ($(CONFIG_USBHOST),y)
# Include built-in USB host driver logic # Include built-in USB host driver logic
CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c
CSRCS += usbhost_enumerate.c usbhost_storage.c usbhost_devaddr.c CSRCS += usbhost_enumerate.c usbhost_devaddr.c
ifeq ($(CONFIG_USBHOST_HUB),y) ifeq ($(CONFIG_USBHOST_HUB),y)
CSRCS += usbhost_hub.c CSRCS += usbhost_hub.c
endif endif
ifeq ($(CONFIG_USBHOST_MSC),y)
CSRCS += usbhost_storage.c
endif
ifeq ($(CONFIG_USBHOST_HIDKBD),y) ifeq ($(CONFIG_USBHOST_HIDKBD),y)
CSRCS += usbhost_hidkbd.c CSRCS += usbhost_hidkbd.c
endif endif

View File

@ -67,8 +67,6 @@
static inline uint16_t usbhost_getle16(const uint8_t *val); static inline uint16_t usbhost_getle16(const uint8_t *val);
static void usbhost_putle16(uint8_t *dest, uint16_t val); static void usbhost_putle16(uint8_t *dest, uint16_t val);
static void usbhost_callback(FAR struct usbhost_transfer_s *xfer);
static inline int usbhost_devdesc(const struct usb_devdesc_s *devdesc, static inline int usbhost_devdesc(const struct usb_devdesc_s *devdesc,
FAR struct usbhost_id_s *id); FAR struct usbhost_id_s *id);
static inline int usbhost_configdesc(const uint8_t *configdesc, int desclen, static inline int usbhost_configdesc(const uint8_t *configdesc, int desclen,
@ -116,19 +114,6 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val)
dest[1] = val >> 8; dest[1] = val >> 8;
} }
/****************************************************************************
* Name: usbhost_callback
*
* Description:
*
*
*******************************************************************************/
static void usbhost_callback(FAR struct usbhost_transfer_s *xfer)
{
sem_post(&xfer->done);
}
/******************************************************************************* /*******************************************************************************
* Name: usbhost_devdesc * Name: usbhost_devdesc
* *
@ -173,8 +158,8 @@ static inline int usbhost_devdesc(FAR const struct usb_devdesc_s *devdesc,
static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen, static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen,
struct usbhost_id_s *id) struct usbhost_id_s *id)
{ {
struct usb_cfgdesc_s *cfgdesc; FAR struct usb_cfgdesc_s *cfgdesc;
struct usb_ifdesc_s *ifdesc; FAR struct usb_ifdesc_s *ifdesc;
int remaining; int remaining;
DEBUGASSERT(configdesc != NULL && cfglen >= USB_SIZEOF_CFGDESC); DEBUGASSERT(configdesc != NULL && cfglen >= USB_SIZEOF_CFGDESC);
@ -392,7 +377,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->index, 0);
usbhost_putle16(ctrlreq->len, descsize); usbhost_putle16(ctrlreq->len, descsize);
ret = usbhost_ctrlxfer(devclass, ctrlreq, buffer); ret = DRVR_CTRLIN(devclass->drvr, ctrlreq, buffer);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to get device descriptor, length=%d: %d\n", udbg("ERROR: Failed to get device descriptor, length=%d: %d\n",
@ -417,7 +402,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->index, 0);
usbhost_putle16(ctrlreq->len, 0); usbhost_putle16(ctrlreq->len, 0);
ret = usbhost_ctrlxfer(devclass, ctrlreq, NULL); ret = DRVR_CTRLOUT(devclass->drvr, ctrlreq, NULL);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to set address: %d\n"); udbg("ERROR: Failed to set address: %d\n");
@ -441,7 +426,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->index, 0);
usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC); usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC);
ret = usbhost_ctrlxfer(devclass, ctrlreq, buffer); ret = DRVR_CTRLIN(devclass->drvr, ctrlreq, buffer);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to get device descriptor, length=%d: %d\n", udbg("ERROR: Failed to get device descriptor, length=%d: %d\n",
@ -469,7 +454,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->index, 0);
usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC); usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC);
ret = usbhost_ctrlxfer(devclass, ctrlreq, buffer); ret = DRVR_CTRLIN(devclass->drvr, ctrlreq, buffer);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n", udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n",
@ -492,7 +477,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->index, 0);
usbhost_putle16(ctrlreq->len, cfglen); usbhost_putle16(ctrlreq->len, cfglen);
ret = usbhost_ctrlxfer(devclass, ctrlreq, buffer); ret = DRVR_CTRLIN(devclass->drvr, ctrlreq, buffer);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n", udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n",
@ -508,7 +493,7 @@ int usbhost_enumerate(FAR struct usbhost_class_s *devclass)
usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->index, 0);
usbhost_putle16(ctrlreq->len, 0); usbhost_putle16(ctrlreq->len, 0);
ret = usbhost_ctrlxfer(devclass, ctrlreq, NULL); ret = DRVR_CTRLOUT(devclass->drvr, ctrlreq, NULL);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to set configuration: %d\n", ret); udbg("ERROR: Failed to set configuration: %d\n", ret);
@ -562,78 +547,3 @@ errout:
return ret; return ret;
} }
/****************************************************************************
* Name: usbhost_ctrlxfer
*
* Description:
* Free transfer buffer memory.
*
* Input Parameters:
* devclass - A reference to the class instance.
* ctrlreq - Describes the control request transfer
* buffer - Data accompanying the control transfer
*
* Returned Values:
* On sucess, zero (OK) is returned. On failure, an negated errno value
* is returned to indicate the nature of the failure.
*
****************************************************************************/
int usbhost_ctrlxfer(FAR struct usbhost_class_s *devclass,
FAR struct usb_ctrlreq_s *ctrlreq,
FAR uint8_t *buffer)
{
struct usbhost_transfer_s xfer;
struct timespec timeout;
uint16_t len;
int ret;
len = usbhost_getle16(ctrlreq->len);
xfer.buffer = buffer;
xfer.buflen = len;
xfer.len = len;
xfer.status = -EIO;
xfer.devclass = devclass;
xfer.ep = devclass->ep0;
xfer.callback = usbhost_callback;
sem_init(&xfer.done, 0, 0);
#ifdef CONFIG_USBHOST_HUB
if (ROOTHUB(devclass))
{
ret = DRVR_RHCTRL(devclass->drvr, &xfer, ctrlreq);
}
else
#endif
{
if ((ctrlreq->type & USB_REQ_DIR_IN) != 0)
{
ret = DRVR_CTRLIN(devclass->drvr, &xfer, ctrlreq);
}
else
{
ret = DRVR_CTRLOUT(devclass->drvr, &xfer, ctrlreq);
}
}
if (ret != OK)
{
goto out;
}
timeout.tv_sec = 5;
timeout.tv_nsec = 1000*1000;
ret = sem_timedwait(&xfer.done, &timeout);
if (ret == OK)
{
ret = xfer.status;
}
out:
sem_destroy(&xfer.done);
return ret;
}

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2015 Gregory Nutt. All rights reserved. * Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Author: Kaushal Parikh <kaushal@dspworks.in> * Author: Kaushal Parikh <kaushal@dspworks.in>
* Gregory Nutt <gnutt@nuttx.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -92,21 +93,23 @@
struct usbhost_hub_s struct usbhost_hub_s
{ {
volatile bool disconnected; /* TRUE: Device has been disconnected */ FAR struct usb_ctrlreq_s *ctrlreq; /* Allocated control request */
FAR uint8_t *buffer; /* Allocated buffer */
uint8_t ifno; /* Interface number */ uint8_t ifno; /* Interface number */
uint8_t nports; /* Number of ports */
uint8_t lpsm; /* Logical power switching mode */
uint8_t ocmode; /* Over current protection mode */
uint8_t ctrlcurrent; /* Control current */
volatile bool disconnected; /* TRUE: Device has been disconnected */
bool compounddev; /* Hub is part of compound device */
bool indicator; /* Port indicator */
uint16_t pwrondelay; /* Power on wait time in ms */
int16_t crefs; /* Reference count on the driver instance */ int16_t crefs; /* Reference count on the driver instance */
sem_t exclsem; /* Used to maintain mutual exclusive access */ sem_t exclsem; /* Used to maintain mutual exclusive access */
uint8_t nports; /* Number of ports */
uint8_t lpsm; /* Logical power switching mode */
bool compounddev; /* Hub is part of compound device */
uint8_t ocmode; /* Over current protection mode */
bool indicator; /* Port indicator */
uint16_t pwrondelay; /* Power on wait time in ms */
uint8_t ctrlcurrent; /* Control current */
struct usb_hubtt_s tt; /* Transaction translator */ struct usb_hubtt_s tt; /* Transaction translator */
struct usbhost_transfer_s intxfer; /* Interrupt IN endpoint */ usbhost_ep_t intin; /* Interrupt IN endpoint */
struct usbhost_class_s *childclass[USBHUB_MAX_PORTS]; struct usbhost_class_s *childclass[USBHUB_MAX_PORTS];
/* Pointer to child devices */ /* Pointer to child devices */
@ -116,11 +119,6 @@ struct usbhost_hub_s
* Private Function Prototypes * Private Function Prototypes
****************************************************************************/ ****************************************************************************/
/* Semaphores */
static void usbhost_takesem(sem_t *sem);
#define usbhost_givesem(s) sem_post(s);
/* Memory allocation services */ /* Memory allocation services */
static inline uint8_t usbhost_allocaddr(void); static inline uint8_t usbhost_allocaddr(void);
@ -198,29 +196,6 @@ static uint32_t g_addrmap[4];
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* Name: usbhost_takesem
*
* Description:
* This is just a wrapper to handle the annoying behavior of semaphore
* waits that return due to the receipt of a signal.
*
****************************************************************************/
static void usbhost_takesem(sem_t *sem)
{
/* Take the semaphore (perhaps waiting) */
while (sem_wait(sem) != 0)
{
/* The only case that an error should occr here is if the wait was
* awakened by a signal.
*/
ASSERT(errno == EINTR);
}
}
/**************************************************************************** /****************************************************************************
* Name: usbhost_allocaddr * Name: usbhost_allocaddr
* *
@ -291,12 +266,12 @@ static inline FAR struct usbhost_class_s *
priv = (FAR struct usbhost_hub_s *)hubclass->priv; priv = (FAR struct usbhost_hub_s *)hubclass->priv;
/* We are not executing from an interrupt handler so we can just call /* We are not executing from an interrupt handler so we can just call
* kmalloc() to get memory for the class instance. * kmm_malloc() to get memory for the class instance.
*/ */
DEBUGASSERT(!up_interrupt_context()); DEBUGASSERT(!up_interrupt_context());
devclass = (FAR struct usbhost_class_s *) devclass = (FAR struct usbhost_class_s *)
kmalloc(sizeof(struct usbhost_class_s)); kmm_malloc(sizeof(struct usbhost_class_s));
uvdbg("Allocated: %p\n", devclass); uvdbg("Allocated: %p\n", devclass);
@ -313,20 +288,20 @@ static inline FAR struct usbhost_class_s *
devclass->priv = NULL; devclass->priv = NULL;
devclass->tt = NULL; devclass->tt = NULL;
devclass->ttport = 0; devclass->rhport = 0;
if (!ROOTHUB(devclass)) if (!ROOTHUB(devclass))
{ {
if (hubclass->tt != NULL) if (hubclass->tt != NULL)
{ {
devclass->tt = hubclass->tt; devclass->tt = hubclass->tt;
devclass->ttport = hubclass->ttport; devclass->rhport = hubclass->rhport;
} }
else if ((devclass->speed != USB_SPEED_HIGH) && else if ((devclass->speed != USB_SPEED_HIGH) &&
(hubclass->speed == USB_SPEED_HIGH)) (hubclass->speed == USB_SPEED_HIGH))
{ {
devclass->tt = &priv->tt; devclass->tt = &priv->tt;
devclass->ttport = port; devclass->rhport = port;
} }
} }
@ -380,7 +355,7 @@ static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass)
*/ */
uvdbg("Freeing: %p\n", devclass); uvdbg("Freeing: %p\n", devclass);
kfree(devclass); kmm_free(devclass);
} }
/**************************************************************************** /****************************************************************************
@ -412,9 +387,9 @@ static void usbhost_destroy(FAR void *arg)
{ {
uvdbg("crefs: %d\n", priv->crefs); uvdbg("crefs: %d\n", priv->crefs);
if (priv->intxfer.ep) if (priv->intin)
{ {
DRVR_EPFREE(hubclass->drvr, priv->intxfer.ep); DRVR_EPFREE(hubclass->drvr, priv->intin);
} }
/* Destroy the semaphores */ /* Destroy the semaphores */
@ -431,9 +406,9 @@ static void usbhost_destroy(FAR void *arg)
} }
} }
/* Clear priv class */ /* Free private class */
kfree(hubclass->priv); kmm_free(hubclass->priv);
} }
usbhost_freeclass(hubclass); usbhost_freeclass(hubclass);
@ -609,11 +584,11 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass,
/* We are good... Allocate the endpoints */ /* We are good... Allocate the endpoints */
ret = DRVR_EPALLOC(hubclass->drvr, &intindesc, &priv->intxfer.ep); ret = DRVR_EPALLOC(hubclass->drvr, &intindesc, &priv->intin);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to allocate Interrupt IN endpoint: %d\n", ret); udbg("ERROR: Failed to allocate Interrupt IN endpoint: %d\n", ret);
(void)DRVR_EPFREE(hubclass->drvr, priv->intxfer.ep); (void)DRVR_EPFREE(hubclass->drvr, priv->intin);
return ret; return ret;
} }
@ -645,6 +620,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_hubdesc(FAR struct usbhost_class_s *hubclass)
{ {
FAR struct usbhost_hub_s *priv; FAR struct usbhost_hub_s *priv;
FAR struct usb_ctrlreq_s *ctrlreq;
struct usb_hubdesc_s hubdesc; struct usb_hubdesc_s hubdesc;
uint16_t hubchar; uint16_t hubchar;
int ret; int ret;
@ -652,9 +628,18 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass)
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv; priv = (FAR struct usbhost_hub_s *)hubclass->priv;
ret = usbhost_ctrlxfer(hubclass, (USB_REQ_DIR_IN | USBHUB_REQ_TYPE_HUB), /* Get the hub descriptor */
USB_REQ_GETDESCRIPTOR, USB_DESC_TYPE_HUB,
0, USB_SIZEOF_HUBDESC, (uint8_t *)&hubdesc); ctrlreq = priv->ctrlreq;
DEBUGASSERT(ctrlreq);
ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_HUB;
ctrlreq->req = USB_REQ_GETDESCRIPTOR;
usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_HUB << 8));
usbhost_putle16(ctrlreq->index, 0);
usbhost_putle16(ctrlreq->len, USB_SIZEOF_HUBDESC);
ret = DRVR_CTRLIN(hubclass->drvr, ctrlreq, (FAR uint8_t *)&hubdesc);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to read hub descriptor: %d\n", ret); udbg("ERROR: Failed to read hub descriptor: %d\n", ret);
@ -699,6 +684,7 @@ 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 inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
{ {
FAR struct usbhost_hub_s *priv; FAR struct usbhost_hub_s *priv;
FAR struct usb_ctrlreq_s *ctrlreq;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv; priv = (FAR struct usbhost_hub_s *)hubclass->priv;
@ -717,11 +703,20 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
req = USB_REQ_CLEARFEATURE; req = USB_REQ_CLEARFEATURE;
} }
/* Set port power */
ctrlreq = priv->ctrlreq;
DEBUGASSERT(ctrlreq);
for (port = 1; port <= priv->nports; port++) for (port = 1; port <= priv->nports; port++)
{ {
ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, ctrlreq->type = USBHUB_REQ_TYPE_PORT;
req, USBHUB_PORT_FEAT_POWER, ctrlreq->req = req;
port, 0, NULL); usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_POWER << 8));
usbhost_putle16(ctrlreq->index, port);
usbhost_putle16(ctrlreq->len, 0);
ret = DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to power %d port %d: %d\n", on, port, ret); udbg("ERROR: Failed to power %d port %d: %d\n", on, port, ret);
@ -737,7 +732,7 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
* Name: usbhost_intxfer * Name: usbhost_intxfer
* *
* Description: * Description:
* Free transfer buffer memory. * Set-up to receive a callback when an interrupt packet is received.
* *
* Input Parameters: * Input Parameters:
* devclass - A reference to the class instance. * devclass - A reference to the class instance.
@ -774,10 +769,7 @@ static int usbhost_intxfer(FAR struct usbhost_class_s *devclass,
* Name: usbhost_hubevent * Name: usbhost_hubevent
* *
* Description: * Description:
* This function implements the connect() method of struct * Handle a hub event.
* usbhost_class_s. This method is a callback into the class
* implementation. It is used to provide the device's configuration
* descriptor to the class so that the class may initialize properly
* *
* Input Parameters: * Input Parameters:
* xfer - The USB host class instance. * xfer - The USB host class instance.
@ -795,6 +787,7 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
{ {
FAR struct usbhost_class_s *hubclass; FAR struct usbhost_class_s *hubclass;
FAR struct usbhost_hub_s *priv; FAR struct usbhost_hub_s *priv;
FAR struct usb_ctrlreq_s *ctrlreq;
struct usb_portstatus_s portstatus; struct usb_portstatus_s portstatus;
uint16_t status; uint16_t status;
uint16_t change; uint16_t change;
@ -810,7 +803,10 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL); DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv; priv = (FAR struct usbhost_hub_s *)hubclass->priv;
statusmap = xfer->buffer[0]; ctrlreq = priv->ctrlreq;
DEBUGASSERT(ctrlreq);
statusmap = priv->buffer[0];
for (port = 1; port <= priv->nports; port++) for (port = 1; port <= priv->nports; port++)
{ {
@ -827,10 +823,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
/* Read hub port status */ /* Read hub port status */
ret = usbhost_ctrlxfer(hubclass, ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT;
(USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), ctrlreq->req = USB_REQ_GETSTATUS;
USB_REQ_GETSTATUS, 0, port, usbhost_putle16(ctrlreq->value, 0);
USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); usbhost_putle16(ctrlreq->index, port);
usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);
ret = DRVR_CTRLIN(hubclass->drvr, ctrlreq, (FAR uint8_t *)&portstatus);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to read port %d status: %d\n", port, ret); udbg("ERROR: Failed to read port %d status: %d\n", port, ret);
@ -848,9 +847,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
{ {
if (change & mask) if (change & mask)
{ {
ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, ctrlreq->type = USBHUB_REQ_TYPE_PORT;
USB_REQ_CLEARFEATURE, feat, ctrlreq->req = USB_REQ_CLEARFEATURE;
port, 0, NULL); usbhost_putle16(ctrlreq->value, (feat << 8));
usbhost_putle16(ctrlreq->index, port);
usbhost_putle16(ctrlreq->len, 0);
ret = DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to clear port %d change mask %x: %d\n", udbg("ERROR: Failed to clear port %d change mask %x: %d\n",
@ -880,14 +883,17 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
while (debouncetime < 1500) while (debouncetime < 1500)
{ {
ret = usbhost_ctrlxfer(hubclass, ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT;
(USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), ctrlreq->req = USB_REQ_GETSTATUS;
USB_REQ_GETSTATUS, 0, port, usbhost_putle16(ctrlreq->value, 0);
USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); usbhost_putle16(ctrlreq->index, port);
if (ret != OK) usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);
{
break; ret = DRVR_CTRLIN(hubclass->drvr, ctrlreq, (FAR uint8_t *)&portstatus);
} if (ret != OK)
{
break;
}
status = usbhost_getle16(portstatus.status); status = usbhost_getle16(portstatus.status);
change = usbhost_getle16(portstatus.change); change = usbhost_getle16(portstatus.change);
@ -909,9 +915,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
if (change & USBHUB_PORT_STAT_CCONNECTION) if (change & USBHUB_PORT_STAT_CCONNECTION)
{ {
(void)usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, ctrlreq->type = USBHUB_REQ_TYPE_PORT;
USB_REQ_CLEARFEATURE, USBHUB_PORT_FEAT_CCONNECTION, ctrlreq->req = USB_REQ_CLEARFEATURE;
port, 0, NULL); usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_CCONNECTION << 8));
usbhost_putle16(ctrlreq->index, port);
usbhost_putle16(ctrlreq->len, 0);
(void)DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL);
} }
debouncetime += 25; debouncetime += 25;
@ -927,10 +937,14 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
if (status & USBHUB_PORT_STAT_CONNECTION) if (status & USBHUB_PORT_STAT_CONNECTION)
{ {
/* Connect */ /* Connect */
ret = usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, ctrlreq->type = USBHUB_REQ_TYPE_PORT;
USB_REQ_SETFEATURE, ctrlreq->req = USB_REQ_SETFEATURE;
USBHUB_PORT_FEAT_RESET, port, 0, NULL); usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_RESET << 8));
usbhost_putle16(ctrlreq->index, port);
usbhost_putle16(ctrlreq->len, 0);
ret = DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: ailed to reset port %d: %d\n", port, ret); udbg("ERROR: ailed to reset port %d: %d\n", port, ret);
@ -939,10 +953,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
up_mdelay(100); up_mdelay(100);
ret = usbhost_ctrlxfer(hubclass, ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT;
(USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT), ctrlreq->req = USB_REQ_GETSTATUS;
USB_REQ_GETSTATUS, 0, port, usbhost_putle16(ctrlreq->value, 0);
USB_SIZEOF_PORTSTS, (uint8_t *)&portstatus); usbhost_putle16(ctrlreq->index, port);
usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);
ret = DRVR_CTRLIN(hubclass->drvr, ctrlreq, (FAR uint8_t *)&portstatus);
if (ret != OK) if (ret != OK)
{ {
udbg("ERROR: Failed to reset port %d: %d\n", port, ret); udbg("ERROR: Failed to reset port %d: %d\n", port, ret);
@ -962,10 +979,13 @@ static void usbhost_hubevent(FAR struct usbhost_transfer_s *xfer)
if (change & USBHUB_PORT_STAT_CRESET) if (change & USBHUB_PORT_STAT_CRESET)
{ {
(void)usbhost_ctrlxfer(hubclass, USBHUB_REQ_TYPE_PORT, ctrlreq->type = USBHUB_REQ_TYPE_PORT;
USB_REQ_CLEARFEATURE, ctrlreq->req = USB_REQ_CLEARFEATURE;
USBHUB_PORT_FEAT_CRESET, usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_CRESET << 8));
port, 0, NULL); usbhost_putle16(ctrlreq->index, port);
usbhost_putle16(ctrlreq->len, 0);
(void)DRVR_CTRLOUT(hubclass->drvr, ctrlreq, NULL);
} }
if (status & USBHUB_PORT_STAT_HIGH_SPEED) if (status & USBHUB_PORT_STAT_HIGH_SPEED)
@ -1078,7 +1098,7 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val)
* Name: usbhost_callback * Name: usbhost_callback
* *
* Description: * Description:
* Put a (possibly unaligned) 16-bit little endian value. * Handle end of transfer callback.
* *
* Input Parameters: * Input Parameters:
* dest - A pointer to the first byte to save the little endian value. * dest - A pointer to the first byte to save the little endian value.
@ -1091,9 +1111,18 @@ 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 struct usbhost_transfer_s *xfer)
{ {
FAR struct usbhost_class_s *hubclass;
FAR struct usbhost_hub_s *priv;
DEBUGASSERT(xfer != NULL && xfer->devclass != NULL);
hubclass = (FAR struct usbhost_class_s *)xfer->devclass;
DEBUGASSERT(hubclass != NULL && hubclass->priv != NULL);
priv = (FAR struct usbhost_hub_s *)hubclass->priv;
if (xfer->status != OK) if (xfer->status != OK)
{ {
xfer->buffer[0] = 0; 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, xfer, 0);
@ -1133,52 +1162,65 @@ static void usbhost_callback(FAR struct usbhost_transfer_s *xfer)
static int usbhost_create(FAR struct usbhost_class_s *hubclass, static int usbhost_create(FAR struct usbhost_class_s *hubclass,
FAR const struct usbhost_id_s *id) FAR const struct usbhost_id_s *id)
{ {
struct usbhost_hub_s *priv; FAR struct usbhost_hub_s *priv;
size_t maxlen;
int child; int child;
int ret = -ENOMEM; int ret;
/* Allocate a USB host class instance */ /* Allocate a USB host class instance */
priv = kmalloc(sizeof(struct usbhost_hub_s)); priv = kmm_zalloc(sizeof(struct usbhost_hub_s));
if (priv == NULL)
if (priv != NULL)
{ {
/* Initialize the allocated storage class instance */ return -ENOMEM;
memset(priv, 0, sizeof(struct usbhost_hub_s));
/* 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;
/* Initialize semaphores (this works okay in the interrupt context) */
sem_init(&priv->exclsem, 0, 1);
/* Initialize interrupt end-point */
priv->intxfer.ep = NULL;
/* Initialize transaction translator */
priv->tt.class = NULL;
/* Initialize child class pointers */
for (child = 0; child < USBHUB_MAX_PORTS; child++)
{
priv->childclass[child] = NULL;
}
ret = OK;
} }
/* Allocate memory for control requests */
ret = DRVR_ALLOC(hubclass->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen);
if (ret != OK)
{
udbg("DRVR_ALLOC failed: %d\n", ret);
goto errout_with_hub;
}
/* Allocate buffer for status change (INT) endpoint */
ret = DRVR_IOALLOC(hubclass->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;
/* Initialize semaphores (this works okay in the interrupt context) */
sem_init(&priv->exclsem, 0, 1);
/* Initialize child class pointers */
for (child = 0; child < USBHUB_MAX_PORTS; child++)
{
priv->childclass[child] = NULL;
}
return OK;
errout_with_ctrlreq:
kmm_free(priv->ctrlreq);
errout_with_hub:
kmm_free(priv);
return ret; return ret;
} }
@ -1239,15 +1281,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
} }
else else
{ {
/* Allocate buffer for status change (INT) endpoint */ /* Read the hub descriptor */
ret = DRVR_IOALLOC(hubclass->drvr, &priv->intxfer.buffer, 1);
if (ret != OK)
{
return ret;
}
/* Now read hub descriptor */
ret = usbhost_hubdesc(hubclass); ret = usbhost_hubdesc(hubclass);
if (ret != OK) if (ret != OK)
@ -1265,8 +1299,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
/* INT request to periodically check port status */ /* INT request to periodically check port status */
ret = usbhost_intxfer(hubclass, &priv->intxfer, ret = usbhost_intxfer(hubclass, &priv->ctrlreq, usbhost_callback);
usbhost_callback);
} }
return ret; return ret;
@ -1320,7 +1353,7 @@ static int usbhost_disconnected(struct usbhost_class_s *hubclass)
{ {
/* Free buffer for status change (INT) endpoint */ /* Free buffer for status change (INT) endpoint */
DRVR_IOFREE(hubclass->drvr, priv->intxfer.buffer); DRVR_IOFREE(hubclass->drvr, priv->buffer);
/* Power off (for root hub only) */ /* Power off (for root hub only) */
(void)usbhost_hubpwr(hubclass, false); (void)usbhost_hubpwr(hubclass, false);

View File

@ -52,9 +52,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <semaphore.h>
#include <nuttx/wqueue.h>
/************************************************************************************ /************************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
@ -451,7 +448,7 @@
* Input Parameters: * Input Parameters:
* drvr - The USB host driver instance obtained as a parameter from the call to * drvr - The USB host driver instance obtained as a parameter from the call to
* the class create() method. * the class create() method.
* xfr - Describes the request to be sent. This request must lie in memory * req - Describes the request to be sent. This request must lie in memory
* created by DRVR_ALLOC. * created by DRVR_ALLOC.
* buffer - A buffer used for sending the request and for returning any * buffer - A buffer used for sending the request and for returning any
* responses. This buffer must be large enough to hold the length value * responses. This buffer must be large enough to hold the length value
@ -469,8 +466,8 @@
* *
************************************************************************************/ ************************************************************************************/
#define DRVR_CTRLIN(drvr,xfer,cmd) ((drvr)->ctrlin(drvr,xfer,cmd)) #define DRVR_CTRLIN(drvr,req,buffer) ((drvr)->ctrlin(drvr,req,buffer))
#define DRVR_CTRLOUT(drvr,xfer,cmd) ((drvr)->ctrlout(drvr,xfer,cmd)) #define DRVR_CTRLOUT(drvr,req,buffer) ((drvr)->ctrlout(drvr,req,buffer))
/************************************************************************************ /************************************************************************************
* Name: DRVR_TRANSFER * Name: DRVR_TRANSFER
@ -535,7 +532,7 @@
#define DRVR_DISCONNECT(drvr) ((drvr)->disconnect(drvr)) #define DRVR_DISCONNECT(drvr) ((drvr)->disconnect(drvr))
/************************************************************************************ /************************************************************************************
* Name: DRVR_RHCTRL and DRVR_RHSTATUS * Name: DRVR_RHSTATUS
* *
* Description: * Description:
* Called by hub class to control root hub. * Called by hub class to control root hub.
@ -558,7 +555,6 @@
************************************************************************************/ ************************************************************************************/
#ifdef CONFIG_USBHOST_HUB #ifdef CONFIG_USBHOST_HUB
# define DRVR_RHCTRL(drvr,xfer,cmd) ((drvr)->rhctrl(drvr,xfer,cmd))
# define DRVR_RHSTATUS(drvr,xfer) ((drvr)->rhstatus(drvr,xfer)) # define DRVR_RHSTATUS(drvr,xfer) ((drvr)->rhstatus(drvr,xfer))
#endif #endif
@ -630,34 +626,14 @@ typedef FAR void *usbhost_ep_t;
struct usbhost_class_s struct usbhost_class_s
{ {
#ifdef CONFIG_USBHOST_HUB #ifdef CONFIG_USBHOST_HUB
/* Common host driver */ FAR struct usbhost_driver_s *drvr; /* Common host driver */
FAR struct usbhost_class_s *parent; /* Parent class */
FAR struct usbhost_driver_s *drvr; usbhost_ep_t ep0; /* Control endpoint, ep0 */
FAR struct usb_hubtt_s *tt; /* Transaction translator hub */
/* Parent class */ FAR void *priv; /* Class specific private data */
uint8_t addr; /* Device function address */
FAR struct usbhost_class_s *parent; uint8_t speed; /* Device speed */
uint8_t rhport; /* Root hub port index */
/* Control endpoint, ep0 */
usbhost_ep_t ep0;
/* Transaction translator hub */
FAR struct usb_hubtt_s *tt;
/* Class specific private data */
FAR void *priv;
/* USB device address & speed */
uint8_t addr;
uint8_t speed;
/* Transaction translator port */
uint8_t ttport;
#endif #endif
/* Provides the configuration descriptor to the class. The configuration /* Provides the configuration descriptor to the class. The configuration
@ -698,34 +674,18 @@ struct usbhost_devinfo_s
{ {
uint8_t speed:2; /* Device speed: 0=low, 1=full, 2=high */ uint8_t speed:2; /* Device speed: 0=low, 1=full, 2=high */
}; };
/* Generic transfer structure */ /* Generic transfer structure */
struct usbhost_transfer_s struct usbhost_transfer_s
{ {
FAR uint8_t *buffer;
size_t buflen; size_t buflen;
size_t len; size_t len;
int status; int status;
/* Semaphore of synchronized transfers */
sem_t done;
/* Device class */ /* Device class */
FAR struct usbhost_class_s *devclass; FAR struct usbhost_class_s *devclass;
/* Opaque endpoint pointer; can be xHCI specific */
usbhost_ep_t ep;
/* Workqueue for callback */
struct work_s work;
/* Transfer complete callback */
void (*callback)(FAR struct usbhost_transfer_s *);
}; };
/* struct usbhost_connection_s provides as interface between platform-specific /* struct usbhost_connection_s provides as interface between platform-specific
@ -826,11 +786,11 @@ struct usbhost_driver_s
*/ */
int (*ctrlin)(FAR struct usbhost_driver_s *drvr, int (*ctrlin)(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_transfer_s *xfer, FAR const struct usb_ctrlreq_s *req,
FAR const struct usb_ctrlreq_s *cmd); FAR uint8_t *buffer);
int (*ctrlout)(FAR struct usbhost_driver_s *drvr, int (*ctrlout)(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_transfer_s *xfer, FAR const struct usb_ctrlreq_s *req,
FAR const struct usb_ctrlreq_s *cmd); FAR const uint8_t *buffer);
/* Process a request to handle a transfer descriptor. This method will /* Process a request to handle a transfer descriptor. This method will
* enqueue the transfer request and wait for it to complete. Only one transfer may * enqueue the transfer request and wait for it to complete. Only one transfer may
@ -855,9 +815,6 @@ struct usbhost_driver_s
#ifdef CONFIG_USBHOST_HUB #ifdef CONFIG_USBHOST_HUB
/* Called by hub class to control root hub. */ /* Called by hub class to control root hub. */
int (*rhctrl)(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_transfer_s *xfer,
FAR const struct usb_ctrlreq_s *cmd);
int (*rhstatus)(FAR struct usbhost_driver_s *drvr, int (*rhstatus)(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_transfer_s *xfer); FAR struct usbhost_transfer_s *xfer);
#endif #endif
@ -1058,27 +1015,6 @@ int usbhost_wlaninit(void);
int usbhost_enumerate(FAR struct usbhost_class_s *devclass); int usbhost_enumerate(FAR struct usbhost_class_s *devclass);
/****************************************************************************
* Name: usbhost_ctrlxfer
*
* Description:
* Free transfer buffer memory.
*
* Input Parameters:
* devclass - A reference to the class instance.
* ctrlreq - Describes the control request transfer
* buffer - Data accompanying the control transfer
*
* Returned Values:
* On success, zero (OK) is returned. On failure, an negated errno value
* is returned to indicate the nature of the failure.
*
****************************************************************************/
int usbhost_ctrlxfer(FAR struct usbhost_class_s *devclass,
FAR struct usb_ctrlreq_s *ctrlreq,
FAR uint8_t *buffer);
#ifdef CONFIG_USBHOST_HUB #ifdef CONFIG_USBHOST_HUB
/******************************************************************************* /*******************************************************************************
* Name: usbhost_rh_connect * Name: usbhost_rh_connect