Fix USB hub bugs: Don't allocate port EP0 until needed, otherwise run out of endpoints; using wrong pointer to access child endpoint array in a few places

This commit is contained in:
Gregory Nutt 2015-04-23 09:42:58 -06:00
parent 167f406050
commit ab17603ceb
2 changed files with 65 additions and 68 deletions

View File

@ -3154,13 +3154,13 @@ struct usbhost_connection_s *lpc17_usbhost_initialize(int controller)
/* Initialize the public port representation */ /* Initialize the public port representation */
hport = &priv->rhport.hport; hport = &priv->rhport.hport;
hport->drvr = drvr; hport->drvr = drvr;
#ifdef CONFIG_USBHOST_HUB #ifdef CONFIG_USBHOST_HUB
hport->parent = NULL; hport->parent = NULL;
#endif #endif
hport->ep0 = EDCTRL; hport->ep0 = EDCTRL;
hport->speed = USB_SPEED_FULL; hport->speed = USB_SPEED_FULL;
/* Initialize function address generation logic */ /* Initialize function address generation logic */

View File

@ -192,10 +192,10 @@ static struct usbhost_registry_s g_hub =
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: usbhost_hport_free * Name: usbhost_hport_deactivate
* *
* Description: * Description:
* Free a hub resource previously allocated by usbhost_hport_initialize(). * Free a hub resource previously allocated by usbhost_hport_activate().
* *
* Input Parameters: * Input Parameters:
* hport - A reference to the hub port instance to be freed. * hport - A reference to the hub port instance to be freed.
@ -205,72 +205,65 @@ static struct usbhost_registry_s g_hub =
* *
****************************************************************************/ ****************************************************************************/
static inline void usbhost_hport_free(FAR struct usbhost_hubport_s *hport) static inline void usbhost_hport_deactivate(FAR struct usbhost_hubport_s *hport)
{ {
uvdbg("Freeing: %p\n", hport); uvdbg("Deactivating: %d\n", hport->port);
/* Free endpoints */ /* Don't deactivate root hub ports! */
if (hport->ep0 != NULL) if (!ROOTHUB(hport))
{ {
DRVR_EPFREE(hport->drvr, hport->ep0); /* Free the control endpoint */
hport->ep0 = NULL;
if (hport->ep0 != NULL)
{
DRVR_EPFREE(hport->drvr, hport->ep0);
hport->ep0 = NULL;
}
/* Free the function address if one has been assigned */
usbhost_devaddr_destroy(hport);
hport->funcaddr = 0;
DEBUGASSERT(hport->devclass == NULL);
} }
/* Free the function address */
usbhost_devaddr_destroy(hport);
hport->funcaddr = 0;
DEBUGASSERT(hport->devclass == NULL);
} }
/**************************************************************************** /****************************************************************************
* Name: usbhost_hport_initialize * Name: usbhost_hport_activate
* *
* Description: * Description:
* Initialize and configure an * Activate a hub port by assigning it a control endpoint. This actions
* This is really part of the logic that implements the create() method * only occur when a device is connected to the hub endpoint.
* of struct usbhost_registry_s. This function allocates memory for one
* new class instance.
* *
* Input Parameters: * Input Parameters:
* None * hport - The hub port to be activated.
* *
* Returned Values: * Returned Values:
* On success, this function will return a non-NULL instance of struct * Zero (OK) is returned on success; a negated errno value is returned
* usbhost_class_s. NULL is returned on failure; this function will * on any failure.
* will fail only if there are insufficient resources to create another
* USB host class instance.
* *
****************************************************************************/ ****************************************************************************/
static int usbhost_hport_initialize(FAR struct usbhost_driver_s *drvr, static int usbhost_hport_activate(FAR struct usbhost_hubport_s *hport)
FAR struct usbhost_class_s *hubclass,
uint8_t port,
FAR struct usbhost_hubport_s *child)
{ {
FAR struct usbhost_hubport_s *parent = hubclass->hport;
struct usbhost_epdesc_s epdesc; struct usbhost_epdesc_s epdesc;
int ret; int ret;
child->drvr = drvr; uvdbg("Activating port %d\n", hport->port);
child->parent = parent;
child->funcaddr = 0;
child->speed = USB_SPEED_FULL;
epdesc.hport = child; epdesc.hport = hport;
epdesc.addr = 0; epdesc.addr = 0;
epdesc.in = 0; epdesc.in = false;
epdesc.xfrtype = USB_EP_ATTR_XFER_CONTROL; epdesc.xfrtype = USB_EP_ATTR_XFER_CONTROL;
epdesc.interval = 0; epdesc.interval = 0;
epdesc.mxpacketsize = 8; epdesc.mxpacketsize = (hport->speed == USB_SPEED_HIGH) ? 64 : 8;
ret = DRVR_EPALLOC(drvr, &epdesc, &child->ep0); ret = DRVR_EPALLOC(hport->drvr, &epdesc, &hport->ep0);
if (ret != OK) if (ret < 0)
{ {
udbg("ERROR: Failed to allocate ep0: %d\n", ret); udbg("ERROR: Failed to allocate ep0: %d\n", ret);
usbhost_hport_free(child);
} }
return ret; return ret;
@ -334,12 +327,12 @@ static void usbhost_destroy(FAR void *arg)
FAR struct usbhost_hubport_s *hport; FAR struct usbhost_hubport_s *hport;
int port; int port;
uvdbg("crefs: %d\n", priv->crefs);
DEBUGASSERT(hubclass != NULL && hubclass->hport != NULL); DEBUGASSERT(hubclass != NULL && hubclass->hport != NULL);
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv; priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
hport = hubclass->hport; hport = hubclass->hport;
uvdbg("crefs: %d\n", priv->crefs);
/* Destroy the interrupt IN endpoint */ /* Destroy the interrupt IN endpoint */
if (priv->intin) if (priv->intin)
@ -362,7 +355,7 @@ static void usbhost_destroy(FAR void *arg)
/* Free any resource use by the hub port */ /* Free any resource use by the hub port */
usbhost_hport_free(hport); usbhost_hport_deactivate(hport);
} }
/* Destroy the semaphores */ /* Destroy the semaphores */
@ -936,7 +929,7 @@ static void usbhost_hubevent(FAR void *arg)
(void)DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL); (void)DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
} }
connport = &hubclass->hport[port]; connport = &priv->hport[port];
if (status & USBHUB_PORT_STAT_HIGH_SPEED) if (status & USBHUB_PORT_STAT_HIGH_SPEED)
{ {
connport->speed = USB_SPEED_HIGH; connport->speed = USB_SPEED_HIGH;
@ -950,12 +943,23 @@ static void usbhost_hubevent(FAR void *arg)
connport->speed = USB_SPEED_FULL; connport->speed = USB_SPEED_FULL;
} }
/* Inform waiters that a new device has been connected */ /* Activate the hub port by assigning it a control endpoint. */
ret = DRVR_CONNECT(connport->drvr, connport, true); ret = usbhost_hport_activate(connport);
if (ret < 0) if (ret < 0)
{ {
udbg("ERROR: DRVR_CONNECT failed: %d\n", ret); udbg("ERROR: usbhost_hport_activate failed: %d\n", ret);
}
else
{
/* Inform waiters that a new device has been connected */
ret = DRVR_CONNECT(connport->drvr, connport, true);
if (ret < 0)
{
udbg("ERROR: DRVR_CONNECT failed: %d\n", ret);
usbhost_hport_deactivate(connport);
}
} }
} }
else else
@ -1155,26 +1159,21 @@ static FAR struct usbhost_class_s *
for (port = 0; port < USBHUB_MAX_PORTS; port++) for (port = 0; port < USBHUB_MAX_PORTS; port++)
{ {
FAR struct usbhost_hubport_s *child;
/* Initialize the hub port descriptor */ /* Initialize the hub port descriptor */
ret = usbhost_hport_initialize(hport->drvr, hubclass, port, child = &priv->hport[port];
&hubclass->hport[port]); memset(child, 0, sizeof(struct usbhost_hubport_s));
if (ret < 0)
{ child->drvr = hport->drvr;
goto errout_with_hports; child->parent = hport;
} child->port = port;
child->speed = USB_SPEED_FULL;
} }
return hubclass; return hubclass;
errout_with_hports:
for (port = 0; port < USBHUB_MAX_PORTS; port++)
{
/* Free resource used by hub port descriptor */
usbhost_hport_free(hport);
}
errout_with_ctrlreq: errout_with_ctrlreq:
kmm_free(priv->ctrlreq); kmm_free(priv->ctrlreq);
@ -1201,8 +1200,6 @@ errout_with_hub:
* configdesc - A pointer to a uint8_t buffer container the configuration * configdesc - A pointer to a uint8_t buffer container the configuration
* descriptor. * descriptor.
* desclen - The length in bytes of the configuration descriptor. * desclen - The length in bytes of the configuration descriptor.
* funcaddr - The USB address of the function containing the endpoint that
* EP0 controls
* *
* Returned Values: * Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is * On success, zero (OK) is returned. On a failure, a negated errno value is