mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 13:18:50 +08:00
USB hub: Change to connection interface so that applications can deal with external hubs
This commit is contained in:
parent
8e9fd9b838
commit
f7ec9b0831
7 changed files with 698 additions and 308 deletions
|
@ -156,24 +156,29 @@ struct lpc17_usbhost_s
|
|||
|
||||
/* This is the hub port description understood by class drivers */
|
||||
|
||||
struct usbhost_roothubport_s hport;
|
||||
|
||||
/* The bound device class driver */
|
||||
|
||||
struct usbhost_class_s *class;
|
||||
struct usbhost_roothubport_s rhport;
|
||||
|
||||
/* Driver status */
|
||||
|
||||
volatile bool change; /* Connection change */
|
||||
volatile bool connected; /* Connected to device */
|
||||
volatile bool lowspeed; /* Low speed device attached. */
|
||||
volatile bool rhswait; /* TRUE: Thread is waiting for Root Hub Status change */
|
||||
volatile bool pscwait; /* TRUE: Thread is waiting for a port status change */
|
||||
|
||||
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||
uint8_t ininterval; /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */
|
||||
uint8_t outinterval; /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */
|
||||
#endif
|
||||
|
||||
sem_t exclsem; /* Support mutually exclusive access */
|
||||
sem_t rhssem; /* Semaphore to wait Writeback Done Head event */
|
||||
};
|
||||
sem_t pscsem; /* Semaphore to wait Writeback Done Head event */
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
/* Used to pass external hub port events */
|
||||
|
||||
volatile struct usbhost_hubport_s *hport;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* The OCHI expects the size of an endpoint descriptor to be 16 bytes.
|
||||
* However, the size allocated for an endpoint descriptor is 32 bytes in
|
||||
|
@ -303,8 +308,11 @@ static int lpc17_usbinterrupt(int irq, void *context);
|
|||
/* USB host controller operations **********************************************/
|
||||
|
||||
static int lpc17_wait(struct usbhost_connection_s *conn,
|
||||
const bool *connected);
|
||||
static int lpc17_enumerate(struct usbhost_connection_s *conn, int rhpndx);
|
||||
struct usbhost_hubport_s **hport);
|
||||
static int lpc17_rh_enumerate(struct usbhost_connection_s *conn,
|
||||
struct usbhost_hubport_s *hport);
|
||||
static int lpc17_enumerate(struct usbhost_connection_s *conn,
|
||||
struct usbhost_hubport_s *hport);
|
||||
|
||||
static int lpc17_ep0configure(struct usbhost_driver_s *drvr,
|
||||
usbhost_ep_t ep0, uint8_t funcaddr,
|
||||
|
@ -331,7 +339,11 @@ static int lpc17_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
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
static int lpc17_connect(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_hubport_s *hport,
|
||||
bool connected);
|
||||
#endif
|
||||
static void lpc17_disconnect(struct usbhost_driver_s *drvr);
|
||||
|
||||
/* Initialization **************************************************************/
|
||||
|
@ -902,7 +914,7 @@ static inline int lpc17_addinted(struct lpc17_usbhost_s *priv,
|
|||
regval &= ~OHCI_CTRL_PLE;
|
||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||
|
||||
/* Get the quanitized interval value associated with this ED and save it
|
||||
/* Get the quantized interval value associated with this ED and save it
|
||||
* in the ED.
|
||||
*/
|
||||
|
||||
|
@ -1366,13 +1378,14 @@ static int lpc17_usbinterrupt(int irq, void *context)
|
|||
|
||||
ullvdbg("Connected\n");
|
||||
priv->connected = true;
|
||||
priv->change = true;
|
||||
|
||||
/* Notify any waiters */
|
||||
|
||||
if (priv->rhswait)
|
||||
if (priv->pscwait)
|
||||
{
|
||||
lpc17_givesem(&priv->rhssem);
|
||||
priv->rhswait = false;
|
||||
lpc17_givesem(&priv->pscsem);
|
||||
priv->pscwait = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1396,24 +1409,25 @@ static int lpc17_usbinterrupt(int irq, void *context)
|
|||
|
||||
ullvdbg("Disconnected\n");
|
||||
priv->connected = false;
|
||||
priv->change = true;
|
||||
priv->lowspeed = false;
|
||||
|
||||
/* Are we bound to a class instance? */
|
||||
|
||||
if (priv->class)
|
||||
if (priv->rhport.hport.devclass)
|
||||
{
|
||||
/* Yes.. Disconnect the class */
|
||||
|
||||
CLASS_DISCONNECTED(priv->class);
|
||||
priv->class = NULL;
|
||||
CLASS_DISCONNECTED(priv->rhport.hport.devclass);
|
||||
priv->rhport.hport.devclass = NULL;
|
||||
}
|
||||
|
||||
/* Notify any waiters for the Root Hub Status change event */
|
||||
|
||||
if (priv->rhswait)
|
||||
if (priv->pscwait)
|
||||
{
|
||||
lpc17_givesem(&priv->rhssem);
|
||||
priv->rhswait = false;
|
||||
lpc17_givesem(&priv->pscsem);
|
||||
priv->pscwait = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1521,19 +1535,20 @@ static int lpc17_usbinterrupt(int irq, void *context)
|
|||
* Name: lpc17_wait
|
||||
*
|
||||
* Description:
|
||||
* Wait for a device to be connected or disconneced.
|
||||
* Wait for a device to be connected or disconnected to/from a hub port.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The USB host connection instance obtained as a parameter from the call to
|
||||
* the USB driver initialization logic.
|
||||
* connected - A pointer to a boolean value: TRUE: Wait for device to be
|
||||
* connected; FALSE: wait for device to be disconnected
|
||||
* hport - The location to return the hub port descriptor that detected the
|
||||
* connection related event.
|
||||
*
|
||||
* Returned Values:
|
||||
* Zero (OK) is returned when a device in connected. This function will not
|
||||
* return until either (1) a device is connected or (2) some failure occurs.
|
||||
* On a failure, a negated errno value is returned indicating the nature of
|
||||
* the failure
|
||||
* Zero (OK) is returned on success when a device in connected or
|
||||
* disconnected. This function will not return until either (1) a device is
|
||||
* connected or disconnect to/from any hub port or until (2) some failure
|
||||
* occurs. On a failure, a negated errno value is returned indicating the
|
||||
* nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
|
@ -1542,26 +1557,60 @@ static int lpc17_usbinterrupt(int irq, void *context)
|
|||
*******************************************************************************/
|
||||
|
||||
static int lpc17_wait(struct usbhost_connection_s *conn,
|
||||
const bool *connected)
|
||||
struct usbhost_hubport_s **hport)
|
||||
{
|
||||
struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)&g_usbhost;
|
||||
struct usbhost_hubport_s *connport;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Are we already connected? */
|
||||
|
||||
flags = irqsave();
|
||||
while (priv->connected == *connected)
|
||||
for (;;)
|
||||
{
|
||||
/* No... wait for the connection/disconnection */
|
||||
/* Is there a change in the connection state of the single root hub
|
||||
* port?
|
||||
*/
|
||||
|
||||
priv->rhswait = true;
|
||||
lpc17_takesem(&priv->rhssem);
|
||||
if (priv->change)
|
||||
{
|
||||
connport = &priv->rhport.hport;
|
||||
|
||||
/* Yes. Remember the new state */
|
||||
|
||||
connport->connected = priv->connected;
|
||||
priv->change = false;
|
||||
|
||||
/* And return the root hub port */
|
||||
|
||||
*hport = connport;
|
||||
irqrestore(flags);
|
||||
|
||||
udbg("RHport Connected: %s\n", connport->connected ? "YES" : "NO");
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
/* Is a device connected to an external hub? */
|
||||
|
||||
if (priv->hport)
|
||||
{
|
||||
/* Yes.. return the external hub port */
|
||||
|
||||
connport = (struct usbhost_hubport_s *)priv->hport;
|
||||
priv->hport = NULL;
|
||||
|
||||
*hport = connport;
|
||||
irqrestore(flags);
|
||||
|
||||
udbg("Hub port Connected: %s\n", connport->connected ? "YES" : "NO");
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wait for the next connection event */
|
||||
|
||||
priv->pscwait = true;
|
||||
lpc17_takesem(&priv->pscsem);
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
|
||||
udbg("Connected:%s\n", priv->connected ? "YES" : "NO");
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -1573,30 +1622,30 @@ static int lpc17_wait(struct usbhost_connection_s *conn,
|
|||
* extract the class ID info from the configuration descriptor, (3) call
|
||||
* usbhost_findclass() to find the class that supports this device, (4)
|
||||
* call the create() method on the struct usbhost_registry_s interface
|
||||
* to get a class instance, and finally (5) call the configdesc() method
|
||||
* to get a class instance, and finally (5) call the connect() method
|
||||
* of the struct usbhost_class_s interface. After that, the class is in
|
||||
* charge of the sequence of operations.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The USB host connection instance obtained as a parameter from the call to
|
||||
* the USB driver initialization logic.
|
||||
* rphndx - Root hub port index. 0-(n-1) corresponds to root hub port 1-n.
|
||||
* conn - The USB host connection instance obtained as a parameter from
|
||||
* the call to the USB driver initialization logic.
|
||||
* hport - The descriptor of the hub port that has the newly connected
|
||||
* device.
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Only a single class bound to a single device is supported.
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
* - Never called from an interrupt handler.
|
||||
* This function will *not* be called from an interrupt handler.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
static int lpc17_enumerate(struct usbhost_connection_s *conn, int rphndx)
|
||||
static int lpc17_rh_enumerate(struct usbhost_connection_s *conn,
|
||||
struct usbhost_hubport_s *hport)
|
||||
{
|
||||
struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)&g_usbhost;
|
||||
DEBUGASSERT(priv && rphndx == 0);
|
||||
DEBUGASSERT(conn != NULL && hport != NULL &&& hport->port == 0);
|
||||
|
||||
/* Are we connected to a device? The caller should have called the wait()
|
||||
* method first to be assured that a device is connected.
|
||||
|
@ -1626,13 +1675,42 @@ static int lpc17_enumerate(struct usbhost_connection_s *conn, int rphndx)
|
|||
|
||||
lpc17_putreg(OHCI_RHPORTST_PRSC, LPC17_USBHOST_RHPORTST1);
|
||||
(void)usleep(200*1000);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Let the common usbhost_enumerate do all of the real work. Note that the
|
||||
* FunctionAddress (USB address) is hardcoded to one.
|
||||
static int lpc17_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(hport);
|
||||
|
||||
/* If this is a connection on the root hub, then we need to go to
|
||||
* little more effort to get the device speed. If it is a connection
|
||||
* on an external hub, then we already have that information.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
if (ROOTHUB(hport))
|
||||
#endif
|
||||
{
|
||||
ret = lpc17_rh_enumerate(conn, hport);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then let the common usbhost_enumerate do the real enumeration. */
|
||||
|
||||
uvdbg("Enumerate the device\n");
|
||||
return usbhost_enumerate(&g_usbhost.hport.hport, &priv->class);
|
||||
ret = usbhost_enumerate(hport, &hport->devclass);
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Enumeration failed: %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
|
@ -2407,6 +2485,56 @@ static int lpc17_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Name: lpc17_connect
|
||||
*
|
||||
* Description:
|
||||
* New connections may be detected by an attached hub. This method is the
|
||||
* mechanism that is used by the hub class to introduce a new connection
|
||||
* and port description to the system.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
* hport - The descriptor of the hub port that detected the connection
|
||||
* related event
|
||||
* connected - True: device connected; false: device disconnected
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
static int lpc17_connect(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_hubport_s *hport,
|
||||
bool connected)
|
||||
{
|
||||
struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr;
|
||||
DEBUGASSERT(priv != NULL && hport != NULL);
|
||||
irqstate_t flags;
|
||||
|
||||
/* Set the connected/disconnected flag */
|
||||
|
||||
hport->connected = connected;
|
||||
ullvdbg("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO");
|
||||
|
||||
/* Report the connection event */
|
||||
|
||||
flags = irqsave();
|
||||
priv->hport = hport;
|
||||
if (priv->pscwait)
|
||||
{
|
||||
priv->pscwait = false;
|
||||
lpc17_givesem(&priv->pscsem);
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: lpc17_disconnect
|
||||
*
|
||||
|
@ -2435,7 +2563,7 @@ static void lpc17_disconnect(struct usbhost_driver_s *drvr)
|
|||
struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr;
|
||||
DEBUGASSERT(priv);
|
||||
|
||||
priv->class = NULL;
|
||||
priv->rhport.hport.devclass = NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -2555,12 +2683,15 @@ struct usbhost_connection_s *lpc17_usbhost_initialize(int controller)
|
|||
drvr->transfer = lpc17_transfer;
|
||||
#ifdef CONFIG_USBHOST_ASYNCH
|
||||
drvr->asynch = lpc17_asynch;
|
||||
#endif
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
drvr->connect = lpc17_connect;
|
||||
#endif
|
||||
drvr->disconnect = lpc17_disconnect;
|
||||
|
||||
/* Initialize the public port representation */
|
||||
|
||||
hport = &priv->hport.hport;
|
||||
hport = &priv->rhport.hport;
|
||||
hport->drvr = drvr;
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
hport->parent = NULL;
|
||||
|
@ -2570,11 +2701,11 @@ struct usbhost_connection_s *lpc17_usbhost_initialize(int controller)
|
|||
|
||||
/* Initialize function address generation logic */
|
||||
|
||||
usbhost_devaddr_initialize(&priv->hport);
|
||||
usbhost_devaddr_initialize(&priv->rhport);
|
||||
|
||||
/* Initialize semaphores */
|
||||
|
||||
sem_init(&priv->rhssem, 0, 0);
|
||||
sem_init(&priv->pscsem, 0, 0);
|
||||
sem_init(&priv->exclsem, 0, 1);
|
||||
|
||||
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||
|
|
|
@ -235,10 +235,6 @@ struct sam_rhport_s
|
|||
/* This is the hub port description understood by class drivers */
|
||||
|
||||
struct usbhost_roothubport_s hport;
|
||||
|
||||
/* The bound device class driver */
|
||||
|
||||
struct usbhost_class_s *class;
|
||||
};
|
||||
|
||||
/* This structure retains the overall state of the USB host controller */
|
||||
|
@ -246,6 +242,7 @@ struct sam_rhport_s
|
|||
struct sam_ehci_s
|
||||
{
|
||||
volatile bool pscwait; /* TRUE: Thread is waiting for port status change event */
|
||||
|
||||
sem_t exclsem; /* Support mutually exclusive access */
|
||||
sem_t pscsem; /* Semaphore to wait for port status change events */
|
||||
|
||||
|
@ -254,7 +251,13 @@ struct sam_ehci_s
|
|||
struct sam_list_s *qtdfree; /* List of free Queue Element Transfer Descriptor (qTD) */
|
||||
struct work_s work; /* Supports interrupt bottom half */
|
||||
|
||||
/* Root hub ports */
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
/* Used to pass external hub port events */
|
||||
|
||||
volatile struct usbhost_hubport_s *hport;
|
||||
#endif
|
||||
|
||||
/* Root hub ports */
|
||||
|
||||
struct sam_rhport_s rhport[SAM_EHCI_NRHPORT];
|
||||
};
|
||||
|
@ -371,8 +374,11 @@ static int sam_ehci_tophalf(int irq, FAR void *context);
|
|||
/* USB Host Controller Operations **********************************************/
|
||||
|
||||
static int sam_wait(FAR struct usbhost_connection_s *conn,
|
||||
FAR const bool *connected);
|
||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx);
|
||||
FAR struct usbhost_hubport_s **hport);
|
||||
static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport);
|
||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport);
|
||||
|
||||
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
||||
uint8_t funcaddr, uint16_t maxpacketsize);
|
||||
|
@ -398,6 +404,11 @@ static int sam_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
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
static int sam_connect(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_hubport_s *hport,
|
||||
bool connected);
|
||||
#endif
|
||||
static void sam_disconnect(FAR struct usbhost_driver_s *drvr);
|
||||
|
||||
/* Initialization **************************************************************/
|
||||
|
@ -2687,12 +2698,12 @@ static inline void sam_portsc_bottomhalf(void)
|
|||
|
||||
/* Are we bound to a class instance? */
|
||||
|
||||
if (rhport->class)
|
||||
if (rhport->hport.devclass)
|
||||
{
|
||||
/* Yes.. Disconnect the class */
|
||||
|
||||
CLASS_DISCONNECTED(rhport->class);
|
||||
rhport->class = NULL;
|
||||
CLASS_DISCONNECTED(rhport->hport.devclass);
|
||||
rhport->hport.devclass = NULL;
|
||||
}
|
||||
|
||||
/* Notify any waiters for the Root Hub Status change
|
||||
|
@ -2986,23 +2997,20 @@ static int sam_uhphs_interrupt(int irq, FAR void *context)
|
|||
* Name: sam_wait
|
||||
*
|
||||
* Description:
|
||||
* Wait for a device to be connected or disconnected to/from a root hub port.
|
||||
* Wait for a device to be connected or disconnected to/from a hub port.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The USB host connection instance obtained as a parameter from the call to
|
||||
* the USB driver initialization logic.
|
||||
* connected - A pointer to an array of 3 boolean values corresponding to
|
||||
* root hubs 1, 2, and 3. For each boolean value: TRUE: Wait for a device
|
||||
* to be connected on the root hub; FALSE: wait for device to be
|
||||
* disconnected from the root hub.
|
||||
* hport - The location to return the hub port descriptor that detected the
|
||||
* connection related event.
|
||||
*
|
||||
* Returned Values:
|
||||
* And index [0, 1, or 2} corresponding to the root hub port number {1, 2,
|
||||
* or 3} is returned when a device is connected or disconnected. This
|
||||
* function will not return until either (1) a device is connected or
|
||||
* disconnected to/from any root hub port or until (2) some failure occurs.
|
||||
* On a failure, a negated errno value is returned indicating the nature of
|
||||
* the failure
|
||||
* Zero (OK) is returned on success when a device in connected or
|
||||
* disconnected. This function will not return until either (1) a device is
|
||||
* connected or disconnect to/from any hub port or until (2) some failure
|
||||
* occurs. On a failure, a negated errno value is returned indicating the
|
||||
* nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
|
@ -3011,7 +3019,7 @@ static int sam_uhphs_interrupt(int irq, FAR void *context)
|
|||
*******************************************************************************/
|
||||
|
||||
static int sam_wait(FAR struct usbhost_connection_s *conn,
|
||||
FAR const bool *connected)
|
||||
FAR struct usbhost_hubport_s **hport)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int rhpndx;
|
||||
|
@ -3029,19 +3037,43 @@ static int sam_wait(FAR struct usbhost_connection_s *conn,
|
|||
{
|
||||
/* Has the connection state changed on the RH port? */
|
||||
|
||||
if (g_ehci.rhport[rhpndx].connected != connected[rhpndx])
|
||||
if (g_ehci.rhport[rhpndx].hport.connected != connected[rhpndx])
|
||||
{
|
||||
/* Yes.. Return the RH port number to inform the caller which
|
||||
/* Yes.. Return the RH port to inform the caller which
|
||||
* port has the connection change.
|
||||
*/
|
||||
|
||||
*hport = &g_ehci.rhport[rhpndx].hport;
|
||||
irqrestore(flags);
|
||||
|
||||
usbhost_vtrace2(EHCI_VTRACE2_MONWAKEUP,
|
||||
rhpndx + 1, g_ehci.rhport[rhpndx].connected);
|
||||
return rhpndx;
|
||||
rhpndx + 1,
|
||||
g_ehci.rhport[rhpndx].hport.connected);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
/* Is a device connected to an external hub? */
|
||||
|
||||
if (g_ehci.hport)
|
||||
{
|
||||
FAR volatile struct usbhost_hubport_s *connport;
|
||||
|
||||
/* Yes.. return the external hub port */
|
||||
|
||||
connport = g_ehci.hport;
|
||||
g_ehci.hport = NULL;
|
||||
|
||||
*hport = connport;
|
||||
irqrestore(flags);
|
||||
|
||||
usbhost_vtrace2(EHCI_VTRACE2_MONWAKEUP,
|
||||
connport->port + 1, connport->connected);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No changes on any port. Wait for a connection/disconnection event
|
||||
* and check again
|
||||
*/
|
||||
|
@ -3060,33 +3092,37 @@ static int sam_wait(FAR struct usbhost_connection_s *conn,
|
|||
* extract the class ID info from the configuration descriptor, (3) call
|
||||
* usbhost_findclass() to find the class that supports this device, (4)
|
||||
* call the create() method on the struct usbhost_registry_s interface
|
||||
* to get a class instance, and finally (5) call the configdesc() method
|
||||
* to get a class instance, and finally (5) call the connect() method
|
||||
* of the struct usbhost_class_s interface. After that, the class is in
|
||||
* charge of the sequence of operations.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The USB host connection instance obtained as a parameter from the call to
|
||||
* the USB driver initialization logic.
|
||||
* rphndx - Root hub port index. 0-(n-1) corresponds to root hub port 1-n.
|
||||
* conn - The USB host connection instance obtained as a parameter from
|
||||
* the call to the USB driver initialization logic.
|
||||
* hport - The descriptor of the hub port that has the newly connected
|
||||
* device.
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Only a single class bound to a single device is supported.
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
* - Never called from an interrupt handler.
|
||||
* This function will *not* be called from an interrupt handler.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
|
||||
static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport)
|
||||
{
|
||||
struct sam_rhport_s *rhport;
|
||||
volatile uint32_t *regaddr;
|
||||
uint32_t regval;
|
||||
int rhpndx;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(conn != NULL && hport != NULL);
|
||||
rhpndx = hport->port;
|
||||
|
||||
DEBUGASSERT(rhpndx >= 0 && rhpndx < SAM_EHCI_NRHPORT);
|
||||
rhport = &g_ehci.rhport[rhpndx];
|
||||
|
||||
|
@ -3296,16 +3332,35 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Let the common usbhost_enumerate do all of the real work. Note that the
|
||||
* FunctionAddress (USB address) is set to the root hub port number + 1
|
||||
* for now.
|
||||
*
|
||||
* REVISIT: Hub support will require better device address assignment.
|
||||
* See include/nuttx/usb/usbhost_devaddr.h.
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* If this is a connection on the root hub, then we need to go to
|
||||
* little more effort to get the device speed. If it is a connection
|
||||
* on an external hub, then we already have that information.
|
||||
*/
|
||||
|
||||
usbhost_vtrace2(EHCI_VTRACE2_CLASSENUM, rhpndx+1, rhpndx+1);
|
||||
ret = usbhost_enumerate(&g_ehci.rhport[rhpndx].hport.hport, &rhport->class);
|
||||
DEBUGASSERT(hport);
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
if (ROOTHUB(hport))
|
||||
#endif
|
||||
{
|
||||
ret = sam_rh_enumerate(conn, hport);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then let the common usbhost_enumerate do the real enumeration. */
|
||||
|
||||
usbhost_vtrace1(EHCI_VTRACE2_CLASSENUM, hport->port);
|
||||
ret = usbhost_enumerate(hport, &hport->devclass);
|
||||
if (ret < 0)
|
||||
{
|
||||
usbhost_trace2(EHCI_TRACE2_CLASSENUM_FAILED, rhpndx+1, -ret);
|
||||
|
@ -3810,6 +3865,56 @@ static int sam_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Name: sam_connect
|
||||
*
|
||||
* Description:
|
||||
* New connections may be detected by an attached hub. This method is the
|
||||
* mechanism that is used by the hub class to introduce a new connection
|
||||
* and port description to the system.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
* hport - The descriptor of the hub port that detected the connection
|
||||
* related event
|
||||
* connected - True: device connected; false: device disconnected
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
static int sam_connect(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_hubport_s *hport,
|
||||
bool connected)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
/* Set the connected/disconnected flag */
|
||||
|
||||
hport->connected = connected;
|
||||
ullvdbg("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO");
|
||||
|
||||
/* Report the connection event */
|
||||
|
||||
flags = irqsave();
|
||||
DEBUGASSERT(g_ehci.hport == NULL); /* REVISIT */
|
||||
|
||||
g_ehci.hport = hport;
|
||||
if (g_ehci.pscwait)
|
||||
{
|
||||
g_ehci.pscwait = false;
|
||||
sam_givesem(&g_ehci.pscsem);
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: sam_disconnect
|
||||
*
|
||||
|
@ -3841,7 +3946,7 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr)
|
|||
/* Unbind the class */
|
||||
/* REVISIT: Is there more that needs to be done? */
|
||||
|
||||
rhport->class = NULL;
|
||||
rhport->hport.devclass = NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -4111,6 +4216,9 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller)
|
|||
rhport->drvr.transfer = sam_transfer;
|
||||
#ifdef CONFIG_USBHOST_ASYNCH
|
||||
rhport->drvr.asynch = sam_asynch;
|
||||
#endif
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
rhport->drvr.connect = sam_connect;
|
||||
#endif
|
||||
rhport->drvr.disconnect = sam_disconnect;
|
||||
|
||||
|
|
|
@ -235,26 +235,29 @@ struct sam_rhport_s
|
|||
/* This is the hub port description understood by class drivers */
|
||||
|
||||
struct usbhost_roothubport_s hport;
|
||||
|
||||
/* The bound device class driver */
|
||||
|
||||
struct usbhost_class_s *class;
|
||||
};
|
||||
|
||||
/* This structure retains the overall state of the USB host controller */
|
||||
|
||||
struct sam_ohci_s
|
||||
{
|
||||
volatile bool rhswait; /* TRUE: Thread is waiting for Root Hub Status change */
|
||||
volatile bool pscwait; /* TRUE: Thread is waiting for Root Hub Status change */
|
||||
|
||||
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||
uint8_t ininterval; /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */
|
||||
uint8_t outinterval; /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */
|
||||
#endif
|
||||
|
||||
sem_t exclsem; /* Support mutually exclusive access */
|
||||
sem_t rhssem; /* Semaphore to wait Writeback Done Head event */
|
||||
sem_t pscsem; /* Semaphore to wait Writeback Done Head event */
|
||||
struct work_s work; /* Supports interrupt bottom half */
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
/* Used to pass external hub port events */
|
||||
|
||||
volatile struct usbhost_hubport_s *hport;
|
||||
#endif
|
||||
|
||||
/* Root hub ports */
|
||||
|
||||
struct sam_rhport_s rhport[SAM_OHCI_NRHPORT];
|
||||
|
@ -388,8 +391,11 @@ static void sam_ohci_bottomhalf(void *arg);
|
|||
/* USB host controller operations **********************************************/
|
||||
|
||||
static int sam_wait(FAR struct usbhost_connection_s *conn,
|
||||
FAR const bool *connected);
|
||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx);
|
||||
FAR struct usbhost_hubport_s **hport);
|
||||
static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport);
|
||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport);
|
||||
|
||||
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
||||
uint8_t funcaddr, uint16_t maxpacketsize);
|
||||
|
@ -415,6 +421,11 @@ static int sam_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
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
static int sam_connect(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhsot_hubport_s *hport,
|
||||
bool connected);
|
||||
#endif
|
||||
static void sam_disconnect(FAR struct usbhost_driver_s *drvr);
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -1787,14 +1798,14 @@ static void sam_rhsc_bottomhalf(void)
|
|||
rhport->connected = true;
|
||||
|
||||
usbhost_vtrace2(OHCI_VTRACE2_CONNECTED,
|
||||
rhpndx + 1, g_ohci.rhswait);
|
||||
rhpndx + 1, g_ohci.pscwait);
|
||||
|
||||
/* Notify any waiters */
|
||||
|
||||
if (g_ohci.rhswait)
|
||||
if (g_ohci.pscwait)
|
||||
{
|
||||
sam_givesem(&g_ohci.rhssem);
|
||||
g_ohci.rhswait = false;
|
||||
sam_givesem(&g_ohci.pscsem);
|
||||
g_ohci.pscwait = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1825,29 +1836,29 @@ static void sam_rhsc_bottomhalf(void)
|
|||
/* Yes.. disconnect the device */
|
||||
|
||||
usbhost_vtrace2(OHCI_VTRACE2_DISCONNECTED,
|
||||
rhpndx + 1, g_ohci.rhswait);
|
||||
rhpndx + 1, g_ohci.pscwait);
|
||||
|
||||
rhport->connected = false;
|
||||
rhport->hport.hport.speed = USB_SPEED_FULL;
|
||||
|
||||
/* Are we bound to a class instance? */
|
||||
|
||||
if (rhport->class)
|
||||
if (rhport->hport.devclass)
|
||||
{
|
||||
/* Yes.. Disconnect the class */
|
||||
|
||||
CLASS_DISCONNECTED(rhport->class);
|
||||
rhport->class = NULL;
|
||||
CLASS_DISCONNECTED(rhport->hport.devclass);
|
||||
rhport->hport.devclass = NULL;
|
||||
}
|
||||
|
||||
/* Notify any waiters for the Root Hub Status change
|
||||
* event.
|
||||
*/
|
||||
|
||||
if (g_ohci.rhswait)
|
||||
if (g_ohci.pscwait)
|
||||
{
|
||||
sam_givesem(&g_ohci.rhssem);
|
||||
g_ohci.rhswait = false;
|
||||
sam_givesem(&g_ohci.pscsem);
|
||||
g_ohci.pscwait = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2056,23 +2067,20 @@ static void sam_ohci_bottomhalf(void *arg)
|
|||
* Name: sam_wait
|
||||
*
|
||||
* Description:
|
||||
* Wait for a device to be connected or disconnected to/from a root hub port.
|
||||
* Wait for a device to be connected or disconnected to/from a hub port.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The USB host connection instance obtained as a parameter from the call to
|
||||
* the USB driver initialization logic.
|
||||
* connected - A pointer to an array of 3 boolean values corresponding to
|
||||
* root hubs 1, 2, and 3. For each boolean value: TRUE: Wait for a device
|
||||
* to be connected on the root hub; FALSE: wait for device to be
|
||||
* disconnected from the root hub.
|
||||
* hport - The location to return the hub port descriptor that detected the
|
||||
* connection related event.
|
||||
*
|
||||
* Returned Values:
|
||||
* And index [0, 1, or 2} corresponding to the root hub port number {1, 2,
|
||||
* or 3} is returned when a device is connected or disconnected. This
|
||||
* function will not return until either (1) a device is connected or
|
||||
* disconnected to/from any root hub port or until (2) some failure occurs.
|
||||
* On a failure, a negated errno value is returned indicating the nature of
|
||||
* the failure
|
||||
* Zero (OK) is returned on success when a device in connected or
|
||||
* disconnected. This function will not return until either (1) a device is
|
||||
* connected or disconnect to/from any hub port or until (2) some failure
|
||||
* occurs. On a failure, a negated errno value is returned indicating the
|
||||
* nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
|
@ -2081,7 +2089,7 @@ static void sam_ohci_bottomhalf(void *arg)
|
|||
*******************************************************************************/
|
||||
|
||||
static int sam_wait(FAR struct usbhost_connection_s *conn,
|
||||
FAR const bool *connected)
|
||||
FAR struct usbhost_hubport_s **hport)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int rhpndx;
|
||||
|
@ -2122,16 +2130,42 @@ static int sam_wait(FAR struct usbhost_connection_s *conn,
|
|||
irqrestore(flags);
|
||||
usbhost_vtrace2(OHCI_VTRACE2_WAKEUP,
|
||||
rhpndx + 1, g_ohci.rhport[rhpndx].connected);
|
||||
return rhpndx;
|
||||
|
||||
*hport = &g_ohci.rphort[rhpndx].hport;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
/* Is a device connected to an external hub? */
|
||||
|
||||
if (g_ohci.hport)
|
||||
{
|
||||
FAR struct usbhost_hubport_s *connport;
|
||||
|
||||
/* Yes.. return the external hub port */
|
||||
|
||||
connport = (FAR struct usbhost_hubport_s *)g_ohci.hport;
|
||||
g_ohci.hport = NULL;
|
||||
|
||||
*hport = connport;
|
||||
irqrestore(flags);
|
||||
|
||||
usbhost_vtrace2(EHCI_VTRACE2_MONWAKEUP,
|
||||
connport->port + 1, connport->connected);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No changes on any port. Wait for a connection/disconnection event
|
||||
* and check again
|
||||
*/
|
||||
/* No changes on any port. Wait for a connection/disconnection event
|
||||
* and check again
|
||||
*/
|
||||
|
||||
g_ohci.rhswait = true;
|
||||
sam_takesem(&g_ohci.rhssem);
|
||||
g_ohci.pscwait = true;
|
||||
sam_takesem(&g_ohci.pscsem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2144,32 +2178,36 @@ static int sam_wait(FAR struct usbhost_connection_s *conn,
|
|||
* extract the class ID info from the configuration descriptor, (3) call
|
||||
* usbhost_findclass() to find the class that supports this device, (4)
|
||||
* call the create() method on the struct usbhost_registry_s interface
|
||||
* to get a class instance, and finally (5) call the configdesc() method
|
||||
* to get a class instance, and finally (5) call the connect() method
|
||||
* of the struct usbhost_class_s interface. After that, the class is in
|
||||
* charge of the sequence of operations.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The USB host connection instance obtained as a parameter from the call to
|
||||
* the USB driver initialization logic.
|
||||
* rphndx - Root hub port index. 0-(n-1) corresponds to root hub port 1-n.
|
||||
* conn - The USB host connection instance obtained as a parameter from
|
||||
* the call to the USB driver initialization logic.
|
||||
* hport - The descriptor of the hub port that has the newly connected
|
||||
* device.
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Only a single class bound to a single device is supported.
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
* - Never called from an interrupt handler.
|
||||
* This function will *not* be called from an interrupt handler.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
|
||||
static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport)
|
||||
{
|
||||
struct sam_rhport_s *rhport;
|
||||
uint32_t regaddr;
|
||||
int rhpndx;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(conn != NULL && hport != NULL);
|
||||
rhpndx = hport->port;
|
||||
|
||||
DEBUGASSERT(rhpndx >= 0 && rhpndx < SAM_OHCI_NRHPORT);
|
||||
rhport = &g_ohci.rhport[rhpndx];
|
||||
|
||||
|
@ -2221,13 +2259,36 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
|
|||
|
||||
sam_putreg(OHCI_RHPORTST_PRSC, regaddr);
|
||||
up_mdelay(200);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Let the common usbhost_enumerate do all of the real work. Note that the
|
||||
* FunctionAddress (USB address) is set to the root hub port number for now.
|
||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(hport);
|
||||
|
||||
/* If this is a connection on the root hub, then we need to go to
|
||||
* little more effort to get the device speed. If it is a connection
|
||||
* on an external hub, then we already have that information.
|
||||
*/
|
||||
|
||||
usbhost_vtrace2(OHCI_VTRACE2_CLASSENUM, rhpndx+1, rhpndx+1);
|
||||
ret = usbhost_enumerate(&g_ohci.rhport[rhpndx].hport.hport, &rhport->class);
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
if (ROOTHUB(hport))
|
||||
#endif
|
||||
{
|
||||
ret = sam_rh_enumerate(conn, hport);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then let the common usbhost_enumerate do the real enumeration. */
|
||||
|
||||
usbhost_vtrace1(OHCI_VTRACE1_CLASSENUM, hport->port);
|
||||
ret = usbhost_enumerate(hport, &hport->devclass);
|
||||
if (ret < 0)
|
||||
{
|
||||
usbhost_trace2(OHCI_TRACE2_CLASSENUM_FAILED, rhpndx+1, -ret);
|
||||
|
@ -3047,6 +3108,56 @@ static int sam_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Name: sam_connect
|
||||
*
|
||||
* Description:
|
||||
* New connections may be detected by an attached hub. This method is the
|
||||
* mechanism that is used by the hub class to introduce a new connection
|
||||
* and port description to the system.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
* hport - The descriptor of the hub port that detected the connection
|
||||
* related event
|
||||
* connected - True: device connected; false: device disconnected
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
static int sam_connect(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhsot_hubport_s *hport,
|
||||
bool connected)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
/* Set the connected/disconnected flag */
|
||||
|
||||
hport->connected = connected;
|
||||
ullvdbg("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO");
|
||||
|
||||
/* Report the connection event */
|
||||
|
||||
flags = irqsave();
|
||||
DEBUGASSERT(g_ohci.hport == NULL); /* REVISIT */
|
||||
|
||||
g_ohci.hport = hport;
|
||||
if (g_ohci.pscwait)
|
||||
{
|
||||
g_ohci.pscwait = false;
|
||||
sam_givesem(&g_ohci.pscsem);
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: sam_disconnect
|
||||
*
|
||||
|
@ -3082,7 +3193,7 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr)
|
|||
|
||||
/* Unbind the class */
|
||||
|
||||
rhport->class = NULL;
|
||||
rhport->hport.devclass = NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -3131,7 +3242,7 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
|
|||
|
||||
/* Initialize the state data structure */
|
||||
|
||||
sem_init(&g_ohci.rhssem, 0, 0);
|
||||
sem_init(&g_ohci.pscsem, 0, 0);
|
||||
sem_init(&g_ohci.exclsem, 0, 1);
|
||||
|
||||
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||
|
@ -3254,6 +3365,9 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
|
|||
rhport->drvr.transfer = sam_transfer;
|
||||
#ifdef CONFIG_USBHOST_ASYNCH
|
||||
rhport->drvr.asynch = sam_asynch;
|
||||
#endif
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
rhport->drvr.connect = sam_connect;
|
||||
#endif
|
||||
rhport->drvr.disconnect = sam_disconnect;
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ static const struct sam_usbhost_trace_s g_trace1[TRACE1_NSTRINGS] =
|
|||
TRENTRY(OHCI_VTRACE1_ALREADYDISCONN, TR_OHCI, TR_FMT1, "OHCI Already disconnected, RHPORTST: %06x\n"),
|
||||
TRENTRY(OHCI_VTRACE1_RHSC, TR_OHCI, TR_FMT1, "OHCI Root Hub Status Change. Pending: %06x\n"),
|
||||
TRENTRY(OHCI_VTRACE1_WDHINTR, TR_OHCI, TR_FMT1, "OHCI Writeback Done Head interrupt. Pending: %06x\n"),
|
||||
TRENTRY(OHCI_VTRACE1_CLASSENUM, TR_OHCI, TR_FMT1, "OHCI Hub port%d: Enumerate device\n"),
|
||||
TRENTRY(OHCI_VTRACE1_ENUMDISCONN, TR_OHCI, TR_FMT1, "OHCI RHport%dNot connected\n"),
|
||||
TRENTRY(OHCI_VTRACE1_INITIALIZING, TR_OHCI, TR_FMT1, "OHCI Initializing Stack\n"),
|
||||
TRENTRY(OHCI_VTRACE1_INITIALIZED, TR_OHCI, TR_FMT1, "OHCI Initialized\n"),
|
||||
|
@ -145,6 +146,7 @@ static const struct sam_usbhost_trace_s g_trace1[TRACE1_NSTRINGS] =
|
|||
TRENTRY(EHCI_VTRACE1_TOPHALF, TR_EHCI, TR_FMT1, "EHCI Interrupt: %06x\n"),
|
||||
TRENTRY(EHCI_VTRACE1_AAINTR, TR_EHCI, TR_FMT1, "EHCI Async Advance Interrupt\n"),
|
||||
TRENTRY(EHCI_VTRACE1_USBINTR, TR_EHCI, TR_FMT1, "EHCI USB Interrupt (USBINT) Interrupt: %06x\n"),
|
||||
TRENTRY(EHCI_VTRACE1_CLASSENUM, TR_EHCI, TR_FMT1, "EHCI Hub port%d: Enumerate device\n"),
|
||||
TRENTRY(EHCI_VTRACE1_ENUM_DISCONN, TR_EHCI, TR_FMT1, "EHCI Enumeration not connected\n"),
|
||||
TRENTRY(EHCI_VTRACE1_INITIALIZING, TR_EHCI, TR_FMT1, "EHCI Initializing EHCI Stack\n"),
|
||||
TRENTRY(EHCI_VTRACE1_HCCPARAMS, TR_EHCI, TR_FMT1, "EHCI HCCPARAMS=%06x\n"),
|
||||
|
@ -160,7 +162,7 @@ static const struct sam_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] =
|
|||
TRENTRY(OHCI_TRACE2_WHDTDSTATUS, TR_OHCI, TR_FMT2, "OHCI ERROR: WHD Bad TD completion status: %d xfrtype: %d\n"),
|
||||
TRENTRY(OHCI_TRACE2_EP0ENQUEUE_FAILED, TR_OHCI, TR_FMT2, "OHCI ERROR: RHport%d Failed to enqueue EP0: %d\n"),
|
||||
TRENTRY(OHCI_TRACE2_EDENQUEUE_FAILED, TR_OHCI, TR_FMT2, "OHCI ERROR: Failed to queue ED for transfer type %d: %d\n"),
|
||||
TRENTRY(OHCI_TRACE2_CLASSENUM_FAILED, TR_OHCI, TR_FMT2, "OHCI RHport%d usbhost_enumerate() failed: %d\n"),
|
||||
TRENTRY(OHCI_TRACE2_CLASSENUM_FAILED, TR_OHCI, TR_FMT2, "OHCI Hub port%d usbhost_enumerate() failed: %d\n"),
|
||||
|
||||
#ifdef HAVE_USBHOST_TRACE_VERBOSE
|
||||
TRENTRY(OHCI_VTRACE2_INTERVAL, TR_OHCI, TR_FMT2, "OHCI interval: %d->%d\n"),
|
||||
|
@ -169,7 +171,6 @@ static const struct sam_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] =
|
|||
TRENTRY(OHCI_VTRACE2_CONNECTED, TR_OHCI, TR_FMT2, "OHCI RHPort%d connected, rhswait: %d\n"),
|
||||
TRENTRY(OHCI_VTRACE2_DISCONNECTED, TR_OHCI, TR_FMT2, "OHCI RHPort%d disconnected, rhswait: %d\n"),
|
||||
TRENTRY(OHCI_VTRACE2_WAKEUP, TR_OHCI, TR_FMT2, "OHCI RHPort%d connected: %d\n"),
|
||||
TRENTRY(OHCI_VTRACE2_CLASSENUM, TR_OHCI, TR_FMT2, "OHCI RHPort%d: Enumerate the device, devaddr=%02x\n"),
|
||||
TRENTRY(OHCI_VTRACE2_EP0CONFIGURE, TR_OHCI, TR_FMT2, "OHCI RHPort%d EP0 CTRL: %04x\n"),
|
||||
TRENTRY(OHCI_VTRACE2_EPALLOC, TR_OHCI, TR_FMT2, "OHCI EP%d CTRL: %04x\n"),
|
||||
TRENTRY(OHCI_VTRACE2_CTRLIN, TR_OHCI, TR_FMT2, "OHCI CTRLIN RHPort%d req: %02x\n"),
|
||||
|
@ -182,7 +183,7 @@ static const struct sam_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] =
|
|||
#ifdef CONFIG_SAMA5_EHCI
|
||||
TRENTRY(EHCI_TRACE2_EPSTALLED, TR_EHCI, TR_FMT2, "EHCI EP%d Stalled: TOKEN=%04x\n"),
|
||||
TRENTRY(EHCI_TRACE2_EPIOERROR, TR_EHCI, TR_FMT2, "EHCI ERROR: EP%d TOKEN=%04x\n"),
|
||||
TRENTRY(EHCI_TRACE2_CLASSENUM_FAILED, TR_EHCI, TR_FMT2, "EHCI RHport%d usbhost_enumerate() failed: %d\n"),
|
||||
TRENTRY(EHCI_TRACE2_CLASSENUM_FAILED, TR_EHCI, TR_FMT2, "EHCI Hub port%d usbhost_enumerate() failed: %d\n"),
|
||||
|
||||
#ifdef HAVE_USBHOST_TRACE_VERBOSE
|
||||
TRENTRY(EHCI_VTRACE2_ASYNCXFR, TR_EHCI, TR_FMT2, "EHCI Async transfer EP%d buflen=%d\n"),
|
||||
|
@ -191,8 +192,7 @@ static const struct sam_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] =
|
|||
TRENTRY(EHCI_VTRACE2_PORTSC, TR_EHCI, TR_FMT2, "EHCI PORTSC%d: %04x\n"),
|
||||
TRENTRY(EHCI_VTRACE2_PORTSC_CONNECTED, TR_EHCI, TR_FMT2, "EHCI RHPort%d connected, pscwait: %d\n"),
|
||||
TRENTRY(EHCI_VTRACE2_PORTSC_DISCONND, TR_EHCI, TR_FMT2, "EHCI RHport%d disconnected, pscwait: %d\n"),
|
||||
TRENTRY(EHCI_VTRACE2_MONWAKEUP, TR_EHCI, TR_FMT2, "EHCI RHPort%d connected: %d\n"),
|
||||
TRENTRY(EHCI_VTRACE2_CLASSENUM, TR_EHCI, TR_FMT2, "EHCI RHPort%d: Enumerate the device, devaddr=%02x\n"),
|
||||
TRENTRY(EHCI_VTRACE2_MONWAKEUP, TR_EHCI, TR_FMT2, "EHCI Hub port%d connected: %d\n"),
|
||||
TRENTRY(EHCI_VTRACE2_EPALLOC, TR_EHCI, TR_FMT2, "EHCI EPALLOC: EP%d TYPE=%d\n"),
|
||||
TRENTRY(EHCI_VTRACE2_CTRLINOUT, TR_EHCI, TR_FMT2, "EHCI CTRLIN/OUT: RHPort%d req: %02x\n"),
|
||||
TRENTRY(EHCI_VTRACE2_HCIVERSION, TR_EHCI, TR_FMT2, "EHCI HCIVERSION %x.%02x\n"),
|
||||
|
|
|
@ -141,25 +141,23 @@ static struct usbhost_connection_s *g_usbconn;
|
|||
#ifdef NSH_HAVEUSBHOST
|
||||
static int nsh_waiter(int argc, char *argv[])
|
||||
{
|
||||
bool connected = false;
|
||||
struct usbhost_hubport_s *hport;
|
||||
|
||||
syslog(LOG_INFO, "nsh_waiter: Running\n");
|
||||
for (;;)
|
||||
{
|
||||
/* Wait for the device to change state */
|
||||
|
||||
DEBUGVERIFY(CONN_WAIT(g_usbconn, &connected));
|
||||
|
||||
connected = !connected;
|
||||
syslog(LOG_INFO, "%s\n", connected ? "connected" : "disconnected");
|
||||
DEBUGVERIFY(CONN_WAIT(g_usbconn, &hport));
|
||||
syslog(LOG_INFO, "%s\n", hport->connected ? "connected" : "disconnected");
|
||||
|
||||
/* Did we just become connected? */
|
||||
|
||||
if (connected)
|
||||
if (hport->connected)
|
||||
{
|
||||
/* Yes.. enumerate the newly connected device */
|
||||
|
||||
(void)CONN_ENUMERATE(g_usbconn, 0);
|
||||
(void)CONN_ENUMERATE(g_usbconn, hport);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,8 +106,9 @@ struct usbhost_hubpriv_s
|
|||
struct work_s work; /* Used for deferred callback work */
|
||||
usbhost_ep_t intin; /* Interrupt IN endpoint */
|
||||
|
||||
struct usbhost_class_s *childclass[USBHUB_MAX_PORTS];
|
||||
/* Pointer to child devices */
|
||||
/* Hub port descriptors */
|
||||
|
||||
struct usbhost_hubport_s hport[USBHUB_MAX_PORTS];
|
||||
};
|
||||
|
||||
/* This represents the hub class structure. It must be cast compatible
|
||||
|
@ -126,12 +127,7 @@ struct usbhost_hubclass_s
|
|||
|
||||
/* Memory allocation services */
|
||||
|
||||
static inline FAR struct usbhost_hubport_s *usbhost_allochub(
|
||||
FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_class_s *hubclass, uint8_t speed,
|
||||
uint8_t port);
|
||||
static inline void usbhost_freehub(FAR struct usbhost_hubport_s *hport);
|
||||
static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass);
|
||||
static inline void usbhost_class_free(FAR struct usbhost_class_s *devclass);
|
||||
|
||||
/* Worker thread actions */
|
||||
|
||||
|
@ -196,9 +192,44 @@ static struct usbhost_registry_s g_hub =
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_allochub
|
||||
* Name: usbhost_hport_free
|
||||
*
|
||||
* Description:
|
||||
* Free a hub resource previously allocated by usbhost_hport_initialize().
|
||||
*
|
||||
* Input Parameters:
|
||||
* hport - A reference to the hub port instance to be freed.
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void usbhost_hport_free(FAR struct usbhost_hubport_s *hport)
|
||||
{
|
||||
uvdbg("Freeing: %p\n", hport);
|
||||
|
||||
/* Free endpoints */
|
||||
|
||||
if (hport->ep0 != NULL)
|
||||
{
|
||||
DRVR_EPFREE(hport->drvr, hport->ep0);
|
||||
hport->ep0 = NULL;
|
||||
}
|
||||
|
||||
/* Free the function address */
|
||||
|
||||
usbhost_devaddr_destroy(hport);
|
||||
hport->funcaddr = 0;
|
||||
|
||||
DEBUGASSERT(hport->devclass == NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_hport_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize and configure an
|
||||
* This is really part of the logic that implements the create() method
|
||||
* of struct usbhost_registry_s. This function allocates memory for one
|
||||
* new class instance.
|
||||
|
@ -214,92 +245,39 @@ static struct usbhost_registry_s g_hub =
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline FAR struct usbhost_hubport_s *
|
||||
usbhost_allochub(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_class_s *hubclass,
|
||||
uint8_t speed, uint8_t port)
|
||||
static int usbhost_hport_initialize(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_class_s *hubclass,
|
||||
uint8_t port,
|
||||
FAR struct usbhost_hubport_s *child)
|
||||
{
|
||||
FAR struct usbhost_hubport_s *child;
|
||||
FAR struct usbhost_hubport_s *parent;
|
||||
FAR struct usbhost_hubport_s *parent = hubclass->hport;
|
||||
struct usbhost_epdesc_s epdesc;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->hport != NULL);
|
||||
parent = hubclass->hport;
|
||||
child->drvr = drvr;
|
||||
child->parent = parent;
|
||||
child->funcaddr = 0;
|
||||
child->speed = USB_SPEED_FULL;
|
||||
|
||||
/* We are not executing from an interrupt handler so we can just call
|
||||
* kmm_malloc() to get memory for the class instance.
|
||||
*/
|
||||
epdesc.hport = child;
|
||||
epdesc.addr = 0;
|
||||
epdesc.in = 0;
|
||||
epdesc.xfrtype = USB_EP_ATTR_XFER_CONTROL;
|
||||
epdesc.interval = 0;
|
||||
epdesc.mxpacketsize = 8;
|
||||
|
||||
DEBUGASSERT(!up_interrupt_context());
|
||||
child = (FAR struct usbhost_hubport_s *)
|
||||
kmm_malloc(sizeof(struct usbhost_hubport_s));
|
||||
|
||||
uvdbg("Allocated: %p\n", child);
|
||||
|
||||
if (child != NULL)
|
||||
ret = DRVR_EPALLOC(drvr, &epdesc, &child->ep0);
|
||||
if (ret != OK)
|
||||
{
|
||||
struct usbhost_epdesc_s epdesc;
|
||||
int ret;
|
||||
|
||||
child->drvr = drvr;
|
||||
child->parent = parent;
|
||||
child->funcaddr = 0;
|
||||
child->speed = speed;
|
||||
|
||||
epdesc.hport = child;
|
||||
epdesc.addr = 0;
|
||||
epdesc.in = 0;
|
||||
epdesc.xfrtype = USB_EP_ATTR_XFER_CONTROL;
|
||||
epdesc.interval = 0;
|
||||
epdesc.mxpacketsize = 8;
|
||||
|
||||
ret = DRVR_EPALLOC(drvr, &epdesc, &child->ep0);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to allocate ep0: %d\n", ret);
|
||||
usbhost_freehub(child);
|
||||
child = NULL;
|
||||
}
|
||||
udbg("ERROR: Failed to allocate ep0: %d\n", ret);
|
||||
usbhost_hport_free(child);
|
||||
}
|
||||
|
||||
return child;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_freehub
|
||||
*
|
||||
* Description:
|
||||
* Free a hub instance previously allocated by usbhost_allochub().
|
||||
*
|
||||
* Input Parameters:
|
||||
* hport - A reference to the hub port instance to be freed.
|
||||
*
|
||||
* Returned Values:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void usbhost_freehub(FAR struct usbhost_hubport_s *hport)
|
||||
{
|
||||
if (hport && !ROOTHUB(hport))
|
||||
{
|
||||
if (hport->ep0 != NULL)
|
||||
{
|
||||
DRVR_EPFREE(hport->drvr, hport->ep0);
|
||||
hport->ep0 = NULL;
|
||||
}
|
||||
|
||||
usbhost_devaddr_destroy(hport);
|
||||
hport->funcaddr = 0;
|
||||
|
||||
/* Free the hport instance */
|
||||
|
||||
uvdbg("Freeing: %p\n", hport);
|
||||
kmm_free(hport);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: usbhost_freeclass
|
||||
* Name: usbhost_class_free
|
||||
*
|
||||
* Description:
|
||||
* Free a class instance previously allocated by usbhost_create().
|
||||
|
@ -312,18 +290,25 @@ static inline void usbhost_freehub(FAR struct usbhost_hubport_s *hport)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void usbhost_freeclass(FAR struct usbhost_class_s *devclass)
|
||||
static inline void usbhost_class_free(FAR struct usbhost_class_s *devclass)
|
||||
{
|
||||
FAR struct usbhost_hubport_s *hport;
|
||||
DEBUGASSERT(devclass != NULL);
|
||||
|
||||
/* Free the bound hub */
|
||||
uvdbg("Freeing: %p\n", devclass);
|
||||
DEBUGASSERT(devclass != NULL && devclass->hport != NULL);
|
||||
hport = devclass->hport;
|
||||
|
||||
usbhost_freehub(devclass->hport);
|
||||
/* Detach the class from the hub port */
|
||||
|
||||
usbhost_devaddr_destroy(hport);
|
||||
hport->funcaddr = 0;
|
||||
|
||||
/* Free the class instance */
|
||||
|
||||
uvdbg("Freeing: %p\n", devclass);
|
||||
DEBUGASSERT(hport->devclass == devclass);
|
||||
kmm_free(devclass);
|
||||
hport->devclass = NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -347,37 +332,46 @@ static void usbhost_destroy(FAR void *arg)
|
|||
FAR struct usbhost_class_s *hubclass = (FAR struct usbhost_class_s *)arg;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usbhost_hubport_s *hport;
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(hubclass != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
int port;
|
||||
|
||||
uvdbg("crefs: %d\n", priv->crefs);
|
||||
|
||||
DEBUGASSERT(hubclass != NULL && hubclass->hport != NULL);
|
||||
priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;
|
||||
hport = hubclass->hport;
|
||||
|
||||
/* Destroy the interrupt IN endpoint */
|
||||
|
||||
if (priv->intin)
|
||||
{
|
||||
DEBUGASSERT(hubclass->hport);
|
||||
hport = hubclass->hport;
|
||||
DRVR_EPFREE(hport->drvr, priv->intin);
|
||||
priv->intin = NULL;
|
||||
}
|
||||
|
||||
/* Release per-per resource */
|
||||
|
||||
for (port = 0; port < USBHUB_MAX_PORTS; port++)
|
||||
{
|
||||
/* Free any devices classes connect on this hub port */
|
||||
|
||||
hport = &priv->hport[port];
|
||||
if (hport->devclass != NULL)
|
||||
{
|
||||
CLASS_DISCONNECTED(hport->devclass);
|
||||
}
|
||||
|
||||
/* Free any resource use by the hub port */
|
||||
|
||||
usbhost_hport_free(hport);
|
||||
}
|
||||
|
||||
/* Destroy the semaphores */
|
||||
|
||||
sem_destroy(&priv->exclsem);
|
||||
|
||||
/* Destroy allocated child classes */
|
||||
/* Free the hub class structure */
|
||||
|
||||
for (i = 0; i < USBHUB_MAX_PORTS; i++)
|
||||
{
|
||||
if (priv->childclass[i] != NULL)
|
||||
{
|
||||
CLASS_DISCONNECTED(priv->childclass[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the allocated class structure */
|
||||
|
||||
usbhost_freeclass(hubclass);
|
||||
usbhost_class_free(hubclass);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -735,7 +729,6 @@ static inline int usbhost_hubpwr(FAR struct usbhost_class_s *hubclass, bool on)
|
|||
static void usbhost_hubevent(FAR void *arg)
|
||||
{
|
||||
FAR struct usbhost_class_s *hubclass;
|
||||
FAR struct usbhost_hubport_s *newhub;
|
||||
FAR struct usbhost_hubport_s *hport;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
FAR struct usb_ctrlreq_s *ctrlreq;
|
||||
|
@ -930,7 +923,7 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
if (!(status & USBHUB_PORT_STAT_RESET) &&
|
||||
(status & USBHUB_PORT_STAT_ENABLE))
|
||||
{
|
||||
uint8_t speed;
|
||||
FAR struct usbhost_hubport_s *connport;
|
||||
|
||||
if (change & USBHUB_PORT_STAT_CRESET)
|
||||
{
|
||||
|
@ -943,34 +936,26 @@ static void usbhost_hubevent(FAR void *arg)
|
|||
(void)DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
|
||||
}
|
||||
|
||||
connport = &hubclass->hport[port];
|
||||
if (status & USBHUB_PORT_STAT_HIGH_SPEED)
|
||||
{
|
||||
speed = USB_SPEED_HIGH;
|
||||
connport->speed = USB_SPEED_HIGH;
|
||||
}
|
||||
else if (status & USBHUB_PORT_STAT_LOW_SPEED)
|
||||
{
|
||||
speed = USB_SPEED_LOW;
|
||||
connport->speed = USB_SPEED_LOW;
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = USB_SPEED_FULL;
|
||||
connport->speed = USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
/* Allocate new hub class and enumerate */
|
||||
/* Inform waiters that a new device has been connected */
|
||||
|
||||
newhub = usbhost_allochub(hport->drvr, hubclass, speed, port);
|
||||
if (newhub)
|
||||
ret = DRVR_CONNECT(connport->drvr, connport, true);
|
||||
if (ret < 0)
|
||||
{
|
||||
udbg("ERROR: Failed to allocated class\n");
|
||||
uvdbg("enumerate port %d speed %d\n", port, speed);
|
||||
|
||||
ret = usbhost_enumerate(newhub, &priv->childclass[port]);
|
||||
if (ret != OK)
|
||||
{
|
||||
udbg("ERROR: Failed to enumerate port %d: %d\n",
|
||||
port, ret);
|
||||
usbhost_freehub(hport);
|
||||
}
|
||||
udbg("ERROR: DRVR_CONNECT failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1118,7 +1103,7 @@ static FAR struct usbhost_class_s *
|
|||
FAR struct usbhost_class_s *hubclass;
|
||||
FAR struct usbhost_hubpriv_s *priv;
|
||||
size_t maxlen;
|
||||
int child;
|
||||
int port;
|
||||
int ret;
|
||||
|
||||
/* Allocate a USB host class instance */
|
||||
|
@ -1166,15 +1151,30 @@ static FAR struct usbhost_class_s *
|
|||
|
||||
sem_init(&priv->exclsem, 0, 1);
|
||||
|
||||
/* Initialize child class pointers */
|
||||
/* Initialize per-port data */
|
||||
|
||||
for (child = 0; child < USBHUB_MAX_PORTS; child++)
|
||||
for (port = 0; port < USBHUB_MAX_PORTS; port++)
|
||||
{
|
||||
priv->childclass[child] = NULL;
|
||||
/* Initialize the hub port descriptor */
|
||||
|
||||
ret = usbhost_hport_initialize(hport->drvr, hubclass, port,
|
||||
&hubclass->hport[port]);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_hports;
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
kmm_free(priv->ctrlreq);
|
||||
|
||||
|
|
|
@ -163,22 +163,20 @@
|
|||
* Name: CONN_WAIT
|
||||
*
|
||||
* Description:
|
||||
* Wait for a device to be connected or disconnected to/from a root hub port.
|
||||
* Wait for a device to be connected or disconnected to/from a hub port.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The USB host connection instance obtained as a parameter from the call to
|
||||
* the USB driver initialization logic.
|
||||
* connected - A pointer to an array of n boolean values corresponding to
|
||||
* root hubs 1 through n. For each boolean value: TRUE: Wait for a device
|
||||
* to be connected on the root hub; FALSE: wait for device to be
|
||||
* disconnected from the root hub.
|
||||
* hport - The location to return the hub port descriptor that detected the
|
||||
* connection related event.
|
||||
*
|
||||
* Returned Values:
|
||||
* And index [0..(n-1)} corresponding to the root hub port number {1..n} is
|
||||
* returned when a device in connected or disconnected. This function will not
|
||||
* return until either (1) a device is connected or disconnect to/from any
|
||||
* root hub port or until (2) some failure occurs. On a failure, a negated
|
||||
* errno value is returned indicating the nature of the failure
|
||||
* Zero (OK) is returned on success when a device in connected or
|
||||
* disconnected. This function will not return until either (1) a device is
|
||||
* connected or disconnect to/from any hub port or until (2) some failure
|
||||
* occurs. On a failure, a negated errno value is returned indicating the
|
||||
* nature of the failure
|
||||
*
|
||||
* Assumptions:
|
||||
* - Called from a single thread so no mutual exclusion is required.
|
||||
|
@ -186,7 +184,7 @@
|
|||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#define CONN_WAIT(conn, connected) ((conn)->wait(conn,connected))
|
||||
#define CONN_WAIT(conn,hport) ((conn)->wait(conn,hport))
|
||||
|
||||
/************************************************************************************
|
||||
* Name: CONN_ENUMERATE
|
||||
|
@ -202,9 +200,10 @@
|
|||
* charge of the sequence of operations.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The USB host connection instance obtained as a parameter from the call to
|
||||
* the USB driver initialization logic.
|
||||
* rphndx - Root hub port index. 0-(n-1) corresponds to root hub port 1-n.
|
||||
* conn - The USB host connection instance obtained as a parameter from
|
||||
* the call to the USB driver initialization logic.
|
||||
* hport - The descriptor of the hub port that has the newly connected
|
||||
* device.
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
|
@ -510,8 +509,34 @@
|
|||
((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))
|
||||
# define DRVR_ASYNCH(drvr,ep,buffer,buflen,callback,arg) \
|
||||
((drvr)->asynch(drvr,ep,buffer,buflen,callback,arg))
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Name: DRVR_CONNECT
|
||||
*
|
||||
* Description:
|
||||
* New connections may be detected by an attached hub. This method is the
|
||||
* mechanism that is used by the hub class to introduce a new connection
|
||||
* and port description to the system.
|
||||
*
|
||||
* Input Parameters:
|
||||
* drvr - The USB host driver instance obtained as a parameter from the call to
|
||||
* the class create() method.
|
||||
* hport - The descriptor of the hub port that detected the connection
|
||||
* related event
|
||||
* connected - True: device connected; false: device disconnected
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||
* returned indicating the nature of the failure.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
# define DRVR_CONNECT(drvr,hport,connected) \
|
||||
((drvr)->connect(drvr,hport,connected))
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
|
@ -618,7 +643,9 @@ struct usbhost_hubport_s
|
|||
#ifdef CONFIG_USBHOST_HUB
|
||||
FAR struct usbhost_hubport_s *parent; /* Parent hub (NULL=root hub) */
|
||||
#endif
|
||||
FAR struct usbhost_class_s *devclass; /* The bound device class driver */
|
||||
usbhost_ep_t ep0; /* Control endpoint, ep0 */
|
||||
bool connected; /* True: device connected; false: disconnected */
|
||||
uint8_t port; /* Hub port index */
|
||||
uint8_t funcaddr; /* Device function address */
|
||||
uint8_t speed; /* Device speed */
|
||||
|
@ -689,9 +716,10 @@ struct usbhost_connection_s
|
|||
{
|
||||
/* Wait for a device to connect or disconnect. */
|
||||
|
||||
int (*wait)(FAR struct usbhost_connection_s *conn, FAR const bool *connected);
|
||||
int (*wait)(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s **hport);
|
||||
|
||||
/* Enumerate the device connected on a root hub port. As part of this
|
||||
/* Enumerate the device connected on a hub port. As part of this
|
||||
* enumeration process, the driver will (1) get the device's configuration
|
||||
* descriptor, (2) extract the class ID info from the configuration
|
||||
* descriptor, (3) call usbhost_findclass() to find the class that supports
|
||||
|
@ -701,7 +729,8 @@ struct usbhost_connection_s
|
|||
* in charge of the sequence of operations.
|
||||
*/
|
||||
|
||||
int (*enumerate)(FAR struct usbhost_connection_s *conn, int rhpndx);
|
||||
int (*enumerate)(FAR struct usbhost_connection_s *conn,
|
||||
FAR struct usbhost_hubport_s *hport);
|
||||
};
|
||||
|
||||
/* Callback type used with asynchronous transfers */
|
||||
|
@ -794,6 +823,17 @@ struct usbhost_driver_s
|
|||
usbhost_asynch_t callback, FAR void *arg);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBHOST_HUB
|
||||
/* New connections may be detected by an attached hub. This method is the
|
||||
* mechanism that is used by the hub class to introduce a new connection
|
||||
* and port description to the system.
|
||||
*/
|
||||
|
||||
int (*connect)(FAR struct usbhost_driver_s *drvr,
|
||||
FAR struct usbhost_hubport_s *hport,
|
||||
bool connected);
|
||||
#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
|
||||
* stale) and not attempt any further interaction with the class driver instance
|
||||
|
@ -1010,4 +1050,3 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hub,
|
|||
#endif
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_USB_USBHOST_H */
|
||||
|
||||
|
|
Loading…
Reference in a new issue