USB hub fixes. Mostly dealing with setting the hub function address at the right time and powering up downstream ports
This commit is contained in:
parent
d11af85ddf
commit
2586bc3fcc
@ -251,7 +251,8 @@ void usbhost_devaddr_initialize(FAR struct usbhost_roothubport_s *rhport)
|
||||
* newly connected and so is in need of a function address.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value is returned on failure.
|
||||
* On success, a new device function address in the the range 0x01 to 0x7f
|
||||
* is returned. On failure, a negated errno value is returned.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
@ -278,38 +279,34 @@ int usbhost_devaddr_create(FAR struct usbhost_hubport_s *hport)
|
||||
if (devaddr < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate a device address\n");
|
||||
return devaddr;
|
||||
}
|
||||
|
||||
/* Set the function address in the hub port structure */
|
||||
|
||||
hport->funcaddr = devaddr;
|
||||
return OK;
|
||||
return devaddr;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: usbhost_devaddr_destroy
|
||||
*
|
||||
* Description:
|
||||
* Release a device address previously assigned to a hub port by
|
||||
* usbhost_devaddr_create().
|
||||
* Release a device address previously assigned by usbhost_devaddr_create().
|
||||
*
|
||||
* Input Parameters:
|
||||
* hport - A reference to a hub port structure from which a device has been
|
||||
* disconnected and so no longer needs the function address.
|
||||
* devaddr - The address to be released.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
void usbhost_devaddr_destroy(FAR struct usbhost_hubport_s *hport)
|
||||
void usbhost_devaddr_destroy(FAR struct usbhost_hubport_s *hport, uint8_t devaddr)
|
||||
{
|
||||
FAR struct usbhost_devaddr_s *devgen;
|
||||
|
||||
/* Ignore bad device address */
|
||||
|
||||
if (hport->funcaddr > 0 && hport->funcaddr < 0x7f)
|
||||
if (devaddr > 0 && devaddr < 0x7f)
|
||||
{
|
||||
/* Get the address generation data from the root hub port */
|
||||
|
||||
@ -323,7 +320,7 @@ void usbhost_devaddr_destroy(FAR struct usbhost_hubport_s *hport)
|
||||
|
||||
/* Free the device address */
|
||||
|
||||
usbhost_devaddr_free(devgen, hport->funcaddr);
|
||||
usbhost_devaddr_free(devgen, devaddr);
|
||||
usbhost_givesem(devgen);
|
||||
}
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ static inline int usbhost_classbind(FAR struct usbhost_hubport_s *hport,
|
||||
/* Then bind the newly instantiated class instance */
|
||||
|
||||
ret = CLASS_CONNECT(devclass, configdesc, desclen);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
/* On failures, call the class disconnect method which
|
||||
* should then free the allocated devclass instance.
|
||||
@ -313,6 +313,7 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
unsigned int cfglen;
|
||||
uint8_t maxpacketsize;
|
||||
uint8_t descsize;
|
||||
uint8_t funcaddr = 0;
|
||||
FAR uint8_t *buffer = NULL;
|
||||
int ret;
|
||||
|
||||
@ -323,14 +324,14 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
*/
|
||||
|
||||
ret = DRVR_ALLOC(hport->drvr, (FAR uint8_t **)&ctrlreq, &maxlen);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("DRVR_ALLOC failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = DRVR_ALLOC(hport->drvr, &buffer, &maxlen);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("DRVR_ALLOC failed: %d\n", ret);
|
||||
goto errout;
|
||||
@ -377,7 +378,7 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
usbhost_putle16(ctrlreq->len, descsize);
|
||||
|
||||
ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to get device descriptor, length=%d: %d\n",
|
||||
descsize, ret);
|
||||
@ -393,27 +394,6 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
|
||||
DRVR_EP0CONFIGURE(hport->drvr, hport->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)hport->funcaddr << 8));
|
||||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to set address: %d\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
usleep(2*1000);
|
||||
|
||||
/* And reconfigure EP0 with the correct address */
|
||||
|
||||
DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, hport->funcaddr, maxpacketsize);
|
||||
|
||||
/* Now read the full device descriptor (if we have not already done so) */
|
||||
|
||||
if (descsize < USB_SIZEOF_DEVDESC)
|
||||
@ -425,7 +405,7 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC);
|
||||
|
||||
ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to get device descriptor, length=%d: %d\n",
|
||||
USB_SIZEOF_DEVDESC, ret);
|
||||
@ -441,10 +421,45 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
|
||||
(void)usbhost_devdesc((struct usb_devdesc_s *)buffer, &id);
|
||||
|
||||
/* Get the configuration descriptor (only), index == 0. Should not be
|
||||
* hard-coded! More logic is needed in order to handle devices with
|
||||
* multiple configurations.
|
||||
*/
|
||||
/* Assign a function address to the device connected to this port */
|
||||
|
||||
funcaddr = usbhost_devaddr_create(hport);
|
||||
if (funcaddr < 0)
|
||||
{
|
||||
udbg("ERROR: usbhost_devaddr_create failed: %d\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* 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)funcaddr);
|
||||
usbhost_putle16(ctrlreq->index, 0);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to set address: %d\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
usleep(2*1000);
|
||||
|
||||
/* Assign the function address to the port */
|
||||
|
||||
DEBUGASSERT(hport->funcaddr == 0 && funcaddr != 0);
|
||||
hport->funcaddr = funcaddr;
|
||||
|
||||
/* And reconfigure EP0 with the correct address */
|
||||
|
||||
DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, hport->funcaddr, maxpacketsize);
|
||||
|
||||
/* Get the configuration descriptor (only), index == 0. Should not be
|
||||
* hard-coded! More logic is needed in order to handle devices with
|
||||
* multiple configurations.
|
||||
*/
|
||||
|
||||
ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE;
|
||||
ctrlreq->req = USB_REQ_GETDESCRIPTOR;
|
||||
@ -453,7 +468,7 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC);
|
||||
|
||||
ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n",
|
||||
USB_SIZEOF_CFGDESC, ret);
|
||||
@ -476,7 +491,7 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
usbhost_putle16(ctrlreq->len, cfglen);
|
||||
|
||||
ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n",
|
||||
cfglen, ret);
|
||||
@ -492,7 +507,7 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to set configuration: %d\n", ret);
|
||||
goto errout;
|
||||
@ -510,9 +525,9 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
*/
|
||||
|
||||
ret = usbhost_configdesc(buffer, cfglen, &id);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to read class identification: %d\n", ret);
|
||||
udbg("ERROR: usbhost_configdesc failed: %d\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
@ -521,28 +536,28 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
|
||||
|
||||
usleep(100*1000);
|
||||
|
||||
/* Assign a function address to the device connected to this port */
|
||||
|
||||
ret = usbhost_devaddr_create(hport);
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate device address: %d\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Parse the configuration descriptor and bind to the class instance for the
|
||||
* device. This needs to be the last thing done because the class driver
|
||||
* will begin configuring the device.
|
||||
*/
|
||||
|
||||
ret = usbhost_classbind(hport, buffer, cfglen, &id, devclass);
|
||||
if (ret != OK)
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: usbhost_classbind returned %d\n", ret);
|
||||
usbhost_devaddr_destroy(hport);
|
||||
udbg("ERROR: usbhost_classbind failed %d\n", ret);
|
||||
}
|
||||
|
||||
errout:
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Release the device function address on any failure */
|
||||
|
||||
usbhost_devaddr_destroy(hport, funcaddr);
|
||||
hport->funcaddr = 0;
|
||||
}
|
||||
|
||||
/* Release temporary buffers in any event */
|
||||
|
||||
if (buffer != NULL)
|
||||
{
|
||||
DRVR_FREE(hport->drvr, buffer);
|
||||
|
@ -1991,7 +1991,8 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass)
|
||||
|
||||
/* Free the function address assigned to this device */
|
||||
|
||||
usbhost_devaddr_destroy(hport);
|
||||
usbhost_devaddr_destroy(hport, hport->funcaddr);
|
||||
hport->funcaddr = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -2070,7 +2070,8 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass)
|
||||
|
||||
/* Free the function address assigned to this device */
|
||||
|
||||
usbhost_devaddr_destroy(hport);
|
||||
usbhost_devaddr_destroy(hport, hport->funcaddr);
|
||||
hport->funcaddr = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -49,10 +49,9 @@
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/scsi.h>
|
||||
#include <nuttx/clock.h>
|
||||
|
||||
#include <nuttx/usb/usb.h>
|
||||
#include <nuttx/usb/usbhost.h>
|
||||
@ -71,6 +70,24 @@
|
||||
# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
|
||||
#endif
|
||||
|
||||
/* Perform polling actions on the low priority work queue, if configured */
|
||||
|
||||
#ifndef CONFIG_SCHED_LPWORK
|
||||
# define POLL_WORK LPWORK
|
||||
#else
|
||||
# define POLL_WORK HPWORK
|
||||
#endif
|
||||
|
||||
#define POLL_DELAY MSEC2TICK(400)
|
||||
|
||||
/* Perform event processing on the high priority work queue, if configured */
|
||||
|
||||
#ifndef CONFIG_SCHED_HPWORK
|
||||
# define EVENT_WORK HPWORK
|
||||
#else
|
||||
# define EVENT_WORK LPWORK
|
||||
#endif
|
||||
|
||||
/* Used in usbhost_cfgdesc() */
|
||||
|
||||
#define USBHOST_IFFOUND 0x01 /* Required I/F descriptor found */
|
||||
@ -98,10 +115,7 @@ struct usbhost_hubpriv_s
|
||||
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 */
|
||||
|
||||
sem_t exclsem; /* Used to maintain mutual exclusive access */
|
||||
struct work_s work; /* Used for deferred callback work */
|
||||
usbhost_ep_t intin; /* Interrupt IN endpoint */
|
||||
@ -134,8 +148,9 @@ 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);
|
||||
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_hubpriv_s *priv,
|
||||
FAR struct usbhost_hubport_s *hport,
|
||||
bool on);
|
||||
static void usbhost_hub_event(FAR void *arg);
|
||||
static void usbhost_disconnect_event(FAR void *arg);
|
||||
|
||||
@ -220,7 +235,7 @@ static void usbhost_hport_deactivate(FAR struct usbhost_hubport_s *hport)
|
||||
|
||||
/* Free the function address if one has been assigned */
|
||||
|
||||
usbhost_devaddr_destroy(hport);
|
||||
usbhost_devaddr_destroy(hport, hport->funcaddr);
|
||||
hport->funcaddr = 0;
|
||||
|
||||
DEBUGASSERT(hport->devclass == NULL);
|
||||
@ -294,7 +309,7 @@ static void usbhost_destroy(FAR void *arg)
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
hport = hubclass->hport;
|
||||
|
||||
uvdbg("crefs: %d\n", priv->crefs);
|
||||
uvdbg("Destroying hub on port %d\n", hport->port);
|
||||
|
||||
/* Destroy the interrupt IN endpoint */
|
||||
|
||||
@ -638,8 +653,9 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass)
|
||||
* executed and the PORT_POWER feature would be turned on.
|
||||
*
|
||||
* Input Parameters:
|
||||
* hubclass - The USB host class instance.
|
||||
* on - True: enable power; false: Disablel power
|
||||
* priv - The USB hub private data
|
||||
* hport - The port on the parent hub where the this hub is connected.
|
||||
* on - True: enable power; false: Disable power
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
@ -650,53 +666,45 @@ static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
|
||||
static int usbhost_hubpwr(FAR struct usbhost_hubpriv_s *priv,
|
||||
FAR struct usbhost_hubport_s *hport,
|
||||
bool on)
|
||||
{
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hubport_s *hport;
|
||||
FAR struct usb_ctrlreq_s *ctrlreq;
|
||||
uint16_t req;
|
||||
int port;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
/* Are we enabling or disabling power? */
|
||||
|
||||
DEBUGASSERT(hubclass->hport);
|
||||
hport = hubclass->hport;
|
||||
|
||||
/* Don't bother trying to control the power of a root hub port */
|
||||
|
||||
if (!ROOTHUB(hport))
|
||||
if (on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
req = USB_REQ_SETFEATURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
req = USB_REQ_CLEARFEATURE;
|
||||
}
|
||||
req = USB_REQ_SETFEATURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
req = USB_REQ_CLEARFEATURE;
|
||||
}
|
||||
|
||||
/* Enable/disable power to all downstream ports */
|
||||
/* Enable/disable power to all downstream ports */
|
||||
|
||||
ctrlreq = priv->ctrlreq;
|
||||
DEBUGASSERT(ctrlreq);
|
||||
ctrlreq = priv->ctrlreq;
|
||||
DEBUGASSERT(ctrlreq);
|
||||
|
||||
for (port = 1; port <= priv->nports; port++)
|
||||
{
|
||||
ctrlreq->type = USBHUB_REQ_TYPE_PORT;
|
||||
ctrlreq->req = req;
|
||||
usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_POWER << 8));
|
||||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
for (port = 1; port <= priv->nports; port++)
|
||||
{
|
||||
ctrlreq->type = USBHUB_REQ_TYPE_PORT;
|
||||
ctrlreq->req = req;
|
||||
usbhost_putle16(ctrlreq->value, USBHUB_PORT_FEAT_POWER);
|
||||
usbhost_putle16(ctrlreq->index, port);
|
||||
usbhost_putle16(ctrlreq->len, 0);
|
||||
|
||||
ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to power %d port %d: %d\n", on, port, ret);
|
||||
return ret;
|
||||
}
|
||||
ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to power %s port %d: %d\n",
|
||||
on ? "UP" : "DOWN", port, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1030,38 +1038,27 @@ static void usbhost_disconnect_event(FAR void *arg)
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
DEBUGASSERT(hubclass->hport);
|
||||
hport = hubclass->hport;
|
||||
|
||||
/* Set an indication to any users of the device that the device is no
|
||||
* longer available.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
flags = irqsave();
|
||||
priv->disconnected = true;
|
||||
|
||||
/* Now check the number of references on the class instance. If it is one,
|
||||
* then we can free the class instance now. Otherwise, we will have to
|
||||
* wait until the holders of the references free them by closing the
|
||||
* block driver.
|
||||
*/
|
||||
/* Free buffer for status change (INT) endpoint */
|
||||
|
||||
ullvdbg("crefs: %d\n", priv->crefs);
|
||||
if (priv->crefs == 1)
|
||||
{
|
||||
DEBUGASSERT(hubclass->hport);
|
||||
hport = hubclass->hport;
|
||||
DRVR_IOFREE(hport->drvr, priv->buffer);
|
||||
|
||||
/* Free buffer for status change (INT) endpoint */
|
||||
/* Disable power to all downstream ports */
|
||||
|
||||
DRVR_IOFREE(hport->drvr, priv->buffer);
|
||||
(void)usbhost_hubpwr(priv, hport, false);
|
||||
|
||||
/* Disable power to all downstream ports */
|
||||
|
||||
(void)usbhost_hubpwr(hubclass, false);
|
||||
|
||||
/* Destroy the class instance */
|
||||
|
||||
usbhost_destroy(hubclass);
|
||||
}
|
||||
/* Destroy the class instance */
|
||||
|
||||
usbhost_destroy(hubclass);
|
||||
irqrestore(flags);
|
||||
}
|
||||
|
||||
@ -1127,15 +1124,36 @@ static void usbhost_callback(FAR void *arg, int result)
|
||||
{
|
||||
FAR struct usbhost_class_s *hubclass;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
uint32_t delay = 0;
|
||||
int qid = EVENT_WORK;
|
||||
|
||||
DEBUGASSERT(arg != NULL);
|
||||
hubclass = (FAR struct usbhost_class_s *)arg;
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
/* Check for a failure */
|
||||
|
||||
if (result != OK)
|
||||
{
|
||||
ulldbg("ERROR: Transfer failed: %d\n", result);
|
||||
|
||||
/* Indicate there there is nothing to do. So when the work is
|
||||
* performed, nothing will happen other than we will set to receive
|
||||
* the next event.
|
||||
*/
|
||||
|
||||
priv->buffer[0] = 0;
|
||||
|
||||
/* We don't know the nature of the failure, but we need to do all that
|
||||
* we can do to avoid a CPU hog error loop.
|
||||
*
|
||||
* Use the low-priority work queue and delay polling for the next
|
||||
* event. We want to use as little CPU bandwidth as possible in this
|
||||
* case.
|
||||
*/
|
||||
|
||||
qid = POLL_WORK;
|
||||
delay = POLL_DELAY;
|
||||
}
|
||||
|
||||
/* The work structure should always be available since hub communications
|
||||
@ -1145,8 +1163,8 @@ static void usbhost_callback(FAR void *arg, int result)
|
||||
|
||||
if (work_available(&priv->work))
|
||||
{
|
||||
(void)work_queue(HPWORK, &priv->work, (worker_t)usbhost_hub_event,
|
||||
hubclass, 0);
|
||||
(void)work_queue(qid, &priv->work, (worker_t)usbhost_hub_event,
|
||||
hubclass, delay);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1227,10 +1245,6 @@ static FAR struct usbhost_class_s *
|
||||
goto errout_with_ctrlreq;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@ -1306,6 +1320,9 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
|
||||
DEBUGASSERT(hubclass->hport);
|
||||
hport = hubclass->hport;
|
||||
|
||||
DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));
|
||||
|
||||
/* Parse the configuration descriptor to get the endpoints */
|
||||
@ -1327,7 +1344,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
|
||||
|
||||
/* Enable power to all downstream ports */
|
||||
|
||||
ret = usbhost_hubpwr(hubclass, true);
|
||||
ret = usbhost_hubpwr(priv, hport, true);
|
||||
if (ret != OK)
|
||||
{
|
||||
return ret;
|
||||
@ -1335,9 +1352,6 @@ static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
|
||||
|
||||
/* Enable monitoring of port status change events */
|
||||
|
||||
DEBUGASSERT(hubclass->hport);
|
||||
hport = hubclass->hport;
|
||||
|
||||
ret = DRVR_ASYNCH(hport->drvr, priv->intin, (FAR uint8_t *)priv->ctrlreq,
|
||||
sizeof(struct usb_ctrlreq_s), usbhost_callback,
|
||||
hubclass);
|
||||
@ -1384,8 +1398,8 @@ static int usbhost_disconnected(struct usbhost_class_s *hubclass)
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
ret = work_queue(HPWORK, &priv->work, (worker_t)usbhost_disconnect_event,
|
||||
hubclass, 0);
|
||||
ret = work_queue(EVENT_WORK, &priv->work,
|
||||
(worker_t)usbhost_disconnect_event, hubclass, 0);
|
||||
irqrestore(flags);
|
||||
return ret;
|
||||
}
|
||||
|
@ -370,7 +370,8 @@ static void usbhost_destroy(FAR void *arg)
|
||||
|
||||
/* Free the function address assigned to this device */
|
||||
|
||||
usbhost_devaddr_destroy(hport);
|
||||
usbhost_devaddr_destroy(hport, hport->funcaddr);
|
||||
hport->funcaddr = 0;
|
||||
|
||||
/* Destroy the semaphores */
|
||||
|
||||
|
@ -1857,7 +1857,8 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass)
|
||||
|
||||
/* Free the function address assigned to this device */
|
||||
|
||||
usbhost_devaddr_destroy(hport);
|
||||
usbhost_devaddr_destroy(hport, hport->funcaddr);
|
||||
hport->funcaddr = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,8 @@ void usbhost_devaddr_initialize(FAR struct usbhost_roothubport_s *rhport);
|
||||
* newly connected and so is in need of a function address.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value is returned on failure.
|
||||
* On success, a new device function address in the the range 0x01 to 0x7f
|
||||
* is returned. On failure, a negated errno value is returned.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
@ -130,19 +131,20 @@ int usbhost_devaddr_create(FAR struct usbhost_hubport_s *hport);
|
||||
* Name: usbhost_devaddr_destroy
|
||||
*
|
||||
* Description:
|
||||
* Release a device address previously assigned to a hub port by
|
||||
* usbhost_devaddr_create().
|
||||
* Release a device address previously assigned by usbhost_devaddr_create().
|
||||
*
|
||||
* Input Parameters:
|
||||
* hport - A reference to a hub port structure from which a device has been
|
||||
* disconnected and so no longer needs the function address.
|
||||
* devaddr - The address to be released.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
void usbhost_devaddr_destroy(FAR struct usbhost_hubport_s *hport);
|
||||
void usbhost_devaddr_destroy(FAR struct usbhost_hubport_s *hport,
|
||||
uint8_t devaddr);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
|
Loading…
Reference in New Issue
Block a user