diff --git a/arch/arm/src/lpc17xx/lpc17_usbhost.c b/arch/arm/src/lpc17xx/lpc17_usbhost.c index 67e98d85595..ee4b14191e1 100644 --- a/arch/arm/src/lpc17xx/lpc17_usbhost.c +++ b/arch/arm/src/lpc17xx/lpc17_usbhost.c @@ -2951,7 +2951,7 @@ static void lpc17_asynch_completion(struct lpc17_usbhost_s *priv, #endif /******************************************************************************* - * Name: lcp17_asynch + * Name: lpc17_asynch * * Description: * Process a request to handle a transfer descriptor. This method will diff --git a/arch/arm/src/lpc31xx/Kconfig b/arch/arm/src/lpc31xx/Kconfig index 0e9d1d1fda0..408e947303a 100644 --- a/arch/arm/src/lpc31xx/Kconfig +++ b/arch/arm/src/lpc31xx/Kconfig @@ -60,6 +60,7 @@ config LPC31_SPI config LPC31_USBOTG bool "USB OTG" default n + select USBHOST_HAVE_ASYNCH config LPC31_MCI bool "MCI" diff --git a/arch/arm/src/lpc31xx/lpc31_ehci.c b/arch/arm/src/lpc31xx/lpc31_ehci.c index 757ce364961..2750950ff3f 100644 --- a/arch/arm/src/lpc31xx/lpc31_ehci.c +++ b/arch/arm/src/lpc31xx/lpc31_ehci.c @@ -1,7 +1,7 @@ /******************************************************************************* * arch/arm/src/lpc31xx/lpc31_ehci.c * - * Copyright (C) 2013-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2015 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -53,6 +53,7 @@ #include #include #include +#include #include #include "up_arch.h" @@ -178,6 +179,11 @@ # define TRACE2_NSTRINGS TRACE2_INDEX(__TRACE2_NSTRINGS) #endif +/* Port numbers */ + +#define RHPNDX(rh) ((rh)->hport.hport.port) +#define RHPORT(rh) (RHPNDX(rh)+1) + /******************************************************************************* * Private Types *******************************************************************************/ @@ -257,12 +263,11 @@ struct lpc31_rhport_s volatile bool connected; /* Connected to device */ volatile bool lowspeed; /* Low speed device attached */ - uint8_t rhpndx; /* Root hub port index */ - struct lpc31_epinfo_s ep0; /* EP0 endpoint info */ + struct lpc31_epinfo_s ep0; /* EP0 endpoint info */ - /* The bound device class driver */ + /* This is the hub port description understood by class drivers */ - struct usbhost_class_s *class; + struct usbhost_roothubport_s hport; }; /* This structure retains the overall state of the USB host controller */ @@ -270,6 +275,7 @@ struct lpc31_rhport_s struct lpc31_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 */ @@ -278,6 +284,12 @@ struct lpc31_ehci_s struct lpc31_list_s *qtdfree; /* List of free Queue Element Transfer Descriptor (qTD) */ 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 lpc31_rhport_s rhport[LPC31_EHCI_NRHPORT]; @@ -291,20 +303,20 @@ enum usbhost_trace1codes_e __TRACE1_BASEVALUE = 0, /* This will force the first value to be 1 */ EHCI_TRACE1_SYSTEMERROR, /* EHCI ERROR: System error */ - EHCI_TRACE1_QTDFOREACH_FAILED, /* EHCI ERROR: sam_qtd_foreach failed */ + EHCI_TRACE1_QTDFOREACH_FAILED, /* EHCI ERROR: lpc31_qtd_foreach failed */ EHCI_TRACE1_QHALLOC_FAILED, /* EHCI ERROR: Failed to allocate a QH */ EHCI_TRACE1_BUFTOOBIG, /* EHCI ERROR: Buffer too big */ EHCI_TRACE1_REQQTDALLOC_FAILED, /* EHCI ERROR: Failed to allocate request qTD */ - EHCI_TRACE1_ADDBPL_FAILED, /* EHCI ERROR: sam_qtd_addbpl failed */ + EHCI_TRACE1_ADDBPL_FAILED, /* EHCI ERROR: lpc31_qtd_addbpl failed */ EHCI_TRACE1_DATAQTDALLOC_FAILED, /* EHCI ERROR: Failed to allocate data buffer qTD */ EHCI_TRACE1_DEVDISCONNECTED, /* EHCI ERROR: Device disconnected */ - EHCI_TRACE1_QHCREATE_FAILED, /* EHCI ERROR: sam_qh_create failed */ - EHCI_TRACE1_QTDSETUP_FAILED, /* EHCI ERROR: sam_qtd_setupphase failed */ + EHCI_TRACE1_QHCREATE_FAILED, /* EHCI ERROR: lpc31_qh_create failed */ + EHCI_TRACE1_QTDSETUP_FAILED, /* EHCI ERROR: lpc31_qtd_setupphase failed */ - EHCI_TRACE1_QTDDATA_FAILED, /* EHCI ERROR: sam_qtd_dataphase failed */ - EHCI_TRACE1_QTDSTATUS_FAILED, /* EHCI ERROR: sam_qtd_statusphase failed */ + EHCI_TRACE1_QTDDATA_FAILED, /* EHCI ERROR: lpc31_qtd_dataphase failed */ + EHCI_TRACE1_QTDSTATUS_FAILED, /* EHCI ERROR: lpc31_qtd_statusphase failed */ EHCI_TRACE1_TRANSFER_FAILED, /* EHCI ERROR: Transfer failed */ - EHCI_TRACE1_QHFOREACH_FAILED, /* EHCI ERROR: sam_qh_foreach failed: */ + EHCI_TRACE1_QHFOREACH_FAILED, /* EHCI ERROR: lpc31_qh_foreach failed: */ EHCI_TRACE1_SYSERR_INTR, /* EHCI: Host System Error Interrup */ EHCI_TRACE1_USBERR_INTR, /* EHCI: USB Error Interrupt (USBERRINT) Interrupt */ EHCI_TRACE1_EPALLOC_FAILED, /* EHCI ERROR: Failed to allocate EP info structure */ @@ -314,7 +326,7 @@ enum usbhost_trace1codes_e EHCI_TRACE1_QTDPOOLALLOC_FAILED, /* EHCI ERROR: Failed to allocate the qTD pool */ EHCI_TRACE1_PERFLALLOC_FAILED, /* EHCI ERROR: Failed to allocate the periodic frame list */ - EHCI_TRACE1_RESET_FAILED, /* EHCI ERROR: sam_reset failed */ + EHCI_TRACE1_RESET_FAILED, /* EHCI ERROR: lpc31_reset failed */ EHCI_TRACE1_RUN_FAILED, /* EHCI ERROR: EHCI Failed to run */ EHCI_TRACE1_IRQATTACH_FAILED, /* EHCI ERROR: Failed to attach IRQ */ @@ -485,13 +497,14 @@ static int lpc31_ehci_interrupt(int irq, FAR void *context); /* USB Host Controller Operations **********************************************/ static int lpc31_wait(FAR struct usbhost_connection_s *conn, - FAR const bool *connected); -static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx); + FAR struct usbhost_hubport_s **hport); +static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, + FAR struct usbhost_hubport_s *hport); +static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, + FAR struct usbhost_hubport_s *hport); -static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr, - uint16_t maxpacketsize); -static int lpc31_getdevinfo(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_devinfo_s *devinfo); +static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize); static int lpc31_epalloc(FAR struct usbhost_driver_s *drvr, const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep); static int lpc31_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); @@ -501,12 +514,22 @@ static int lpc31_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); static int lpc31_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); static int lpc31_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); -static int lpc31_ctrlin(FAR struct usbhost_driver_s *drvr, +static int lpc31_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); -static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, +static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); static int lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); +#ifdef CONFIG_USBHOST_ASYNCH +static int lpc31_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); +static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); +#endif +#ifdef CONFIG_USBHOST_HUB +static int lpc31_connect(FAR struct usbhost_driver_s *drvr, + FAR struct usbhost_hubport_s *hport, bool connected); +#endif static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr); /* Initialization **************************************************************/ @@ -581,20 +604,20 @@ static struct lpc31_qtd_s *g_qtdpool; static const struct lpc31_ehci_trace_s g_trace1[TRACE1_NSTRINGS] = { TRENTRY(EHCI_TRACE1_SYSTEMERROR, TR_FMT1, "EHCI ERROR: System error: %06x\n"), - TRENTRY(EHCI_TRACE1_QTDFOREACH_FAILED, TR_FMT1, "EHCI ERROR: sam_qtd_foreach failed: %d\n"), + TRENTRY(EHCI_TRACE1_QTDFOREACH_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_foreach failed: %d\n"), TRENTRY(EHCI_TRACE1_QHALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate a QH\n"), TRENTRY(EHCI_TRACE1_BUFTOOBIG, TR_FMT1, "EHCI ERROR: Buffer too big. Remaining %d\n"), TRENTRY(EHCI_TRACE1_REQQTDALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate request qTD"), - TRENTRY(EHCI_TRACE1_ADDBPL_FAILED, TR_FMT1, "EHCI ERROR: sam_qtd_addbpl failed: %d\n"), + TRENTRY(EHCI_TRACE1_ADDBPL_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_addbpl failed: %d\n"), TRENTRY(EHCI_TRACE1_DATAQTDALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate data buffer qTD, 0"), TRENTRY(EHCI_TRACE1_DEVDISCONNECTED, TR_FMT1, "EHCI ERROR: Device disconnected %d\n"), - TRENTRY(EHCI_TRACE1_QHCREATE_FAILED, TR_FMT1, "EHCI ERROR: sam_qh_create failed\n"), - TRENTRY(EHCI_TRACE1_QTDSETUP_FAILED, TR_FMT1, "EHCI ERROR: sam_qtd_setupphase failed\n"), + TRENTRY(EHCI_TRACE1_QHCREATE_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qh_create failed\n"), + TRENTRY(EHCI_TRACE1_QTDSETUP_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_setupphase failed\n"), - TRENTRY(EHCI_TRACE1_QTDDATA_FAILED, TR_FMT1, "EHCI ERROR: sam_qtd_dataphase failed\n"), - TRENTRY(EHCI_TRACE1_QTDSTATUS_FAILED, TR_FMT1, "EHCI ERROR: sam_qtd_statusphase failed\n"), + TRENTRY(EHCI_TRACE1_QTDDATA_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_dataphase failed\n"), + TRENTRY(EHCI_TRACE1_QTDSTATUS_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_statusphase failed\n"), TRENTRY(EHCI_TRACE1_TRANSFER_FAILED, TR_FMT1, "EHCI ERROR: Transfer failed %d\n"), - TRENTRY(EHCI_TRACE1_QHFOREACH_FAILED, TR_FMT1, "EHCI ERROR: sam_qh_foreach failed: %d\n"), + TRENTRY(EHCI_TRACE1_QHFOREACH_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qh_foreach failed: %d\n"), TRENTRY(EHCI_TRACE1_SYSERR_INTR, TR_FMT1, "EHCI: Host System Error Interrupt\n"), TRENTRY(EHCI_TRACE1_USBERR_INTR, TR_FMT1, "EHCI: USB Error Interrupt (USBERRINT) Interrupt: %06x\n"), TRENTRY(EHCI_TRACE1_EPALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate EP info structure\n"), @@ -604,7 +627,7 @@ static const struct lpc31_ehci_trace_s g_trace1[TRACE1_NSTRINGS] = TRENTRY(EHCI_TRACE1_QTDPOOLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the qTD pool\n"), TRENTRY(EHCI_TRACE1_PERFLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the periodic frame list\n"), - TRENTRY(EHCI_TRACE1_RESET_FAILED, TR_FMT1, "EHCI ERROR: sam_reset failed: %d\n"), + TRENTRY(EHCI_TRACE1_RESET_FAILED, TR_FMT1, "EHCI ERROR: lpc31_reset failed: %d\n"), TRENTRY(EHCI_TRACE1_RUN_FAILED, TR_FMT1, "EHCI ERROR: EHCI Failed to run: USBSTS=%06x\n"), TRENTRY(EHCI_TRACE1_IRQATTACH_FAILED, TR_FMT1, "EHCI ERROR: Failed to attach IRQ%d\n"), @@ -1607,6 +1630,7 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport, struct lpc31_epinfo_s *epinfo) { struct lpc31_qh_s *qh; + uint32_t rhpndx; uint32_t regval; /* Allocate a new queue head structure */ @@ -1636,9 +1660,9 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport, * RL NAK count reloaded 8 */ - regval = ((uint32_t)epinfo->devaddr << QH_EPCHAR_DEVADDR_SHIFT) | - ((uint32_t)epinfo->epno << QH_EPCHAR_ENDPT_SHIFT) | - ((uint32_t)epinfo->speed << QH_EPCHAR_EPS_SHIFT) | + regval = ((uint32_t)epinfo->devaddr << QH_EPCHAR_DEVADDR_SHIFT) | + ((uint32_t)epinfo->epno << QH_EPCHAR_ENDPT_SHIFT) | + ((uint32_t)EHCI_SPEED(epinfo->speed) << QH_EPCHAR_EPS_SHIFT) | QH_EPCHAR_DTC | ((uint32_t)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) | ((uint32_t)8 << QH_EPCHAR_RL_SHIFT); @@ -1649,7 +1673,7 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport, * Otherwise it should always set this bit to a zero." */ - if (epinfo->speed != EHCI_HIGH_SPEED && + if (epinfo->speed != USB_SPEED_HIGH && epinfo->xfrtype == USB_EP_ATTR_XFER_CONTROL) { regval |= QH_EPCHAR_C; @@ -1673,9 +1697,10 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport, * and HUB device address to be included here. */ - regval = ((uint32_t)0 << QH_EPCAPS_HUBADDR_SHIFT) | - ((uint32_t)(rhport->rhpndx + 1) << QH_EPCAPS_PORT_SHIFT) | - ((uint32_t)1 << QH_EPCAPS_MULT_SHIFT); + rhpndx = RHPNDX(rhport); + regval = ((uint32_t)0 << QH_EPCAPS_HUBADDR_SHIFT) | + ((uint32_t)(rhpndx + 1) << QH_EPCAPS_PORT_SHIFT) | + ((uint32_t)1 << QH_EPCAPS_MULT_SHIFT); #ifndef CONFIG_USBHOST_INT_DISABLE if (epinfo->xfrtype == USB_EP_ATTR_XFER_INT) @@ -2015,7 +2040,7 @@ static ssize_t lpc31_async_transfer(struct lpc31_rhport_s *rhport, usbhost_vtrace2(EHCI_VTRACE2_ASYNCXFR, epinfo->epno, buflen); #else uvdbg("RHport%d EP%d: buffer=%p, buflen=%d, req=%p\n", - rhport->rhpndx+1, epinfo->epno, buffer, buflen, req); + RHPORT(rhport), epinfo->epno, buffer, buflen, req); #endif DEBUGASSERT(rhport && epinfo); @@ -2374,7 +2399,7 @@ static ssize_t lpc31_intr_transfer(struct lpc31_rhport_s *rhport, usbhost_vtrace2(EHCI_VTRACE2_INTRXFR, epinfo->epno, buflen); #else uvdbg("RHport%d EP%d: buffer=%p, buflen=%d\n", - rhport->rhpndx+1, epinfo->epno, buffer, buflen); + RHPORT(rhport), epinfo->epno, buffer, buflen); #endif DEBUGASSERT(rhport && epinfo && buffer && buflen > 0); @@ -2791,6 +2816,7 @@ static inline void lpc31_ioc_bottomhalf(void) static inline void lpc31_portsc_bottomhalf(void) { struct lpc31_rhport_s *rhport; + struct usbhost_hubport_s *hport; uint32_t portsc; int rhpndx; @@ -2853,12 +2879,13 @@ static inline void lpc31_portsc_bottomhalf(void) /* Are we bound to a class instance? */ - if (rhport->class) + hport = &rhport->hport.hport; + if (hport->devclass) { /* Yes.. Disconnect the class */ - CLASS_DISCONNECTED(rhport->class); - rhport->class = NULL; + CLASS_DISCONNECTED(hport->devclass); + hport->devclass = NULL; } /* Notify any waiters for the Root Hub Status change @@ -3126,23 +3153,20 @@ static int lpc31_ehci_interrupt(int irq, FAR void *context) * Name: lpc31_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. @@ -3151,7 +3175,7 @@ static int lpc31_ehci_interrupt(int irq, FAR void *context) *******************************************************************************/ static int lpc31_wait(FAR struct usbhost_connection_s *conn, - FAR const bool *connected) + FAR struct usbhost_hubport_s **hport) { irqstate_t flags; int rhpndx; @@ -3167,21 +3191,49 @@ static int lpc31_wait(FAR struct usbhost_connection_s *conn, for (rhpndx = 0; rhpndx < LPC31_EHCI_NRHPORT; rhpndx++) { + struct lpc31_rhport_s *rhport; + struct usbhost_hubport_s *connport; + /* Has the connection state changed on the RH port? */ - if (g_ehci.rhport[rhpndx].connected != connected[rhpndx]) + rhport = &g_ehci.rhport[rhpndx]; + connport = &rhport->hport.hport; + if (rhport->connected != connport->connected) { - /* 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 = connport; irqrestore(flags); + usbhost_vtrace2(EHCI_VTRACE2_MONWAKEUP, - rhpndx + 1, g_ehci.rhport[rhpndx].connected); - return rhpndx; + rhpndx + 1, rhport->conected); + return OK; } } +#ifdef CONFIG_USBHOST_HUB + /* Is a device connected to an external hub? */ + + if (g_ehci.hport) + { + volatile struct usbhost_hubport_s *connport; + + /* Yes.. return the external hub port */ + + connport = g_ehci.hport; + g_ehci.hport = NULL; + + *hport = (struct usbhost_hubport_s *)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 */ @@ -3200,32 +3252,35 @@ static int lpc31_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 lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) +static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, + FAR struct usbhost_hubport_s *hport) { struct lpc31_rhport_s *rhport; volatile uint32_t *regaddr; uint32_t regval; - int ret; + int rhpndx; + + DEBUGASSERT(conn != NULL && hport != NULL); + rhpndx = hport->port; DEBUGASSERT(rhpndx >= 0 && rhpndx < LPC31_EHCI_NRHPORT); rhport = &g_ehci.rhport[rhpndx]; @@ -3299,7 +3354,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) * repeat." */ - rhport->ep0.speed = EHCI_LOW_SPEED; + rhport->ep0.speed = USB_SPEED_LOW; #if 0 /* The LPC31xx does not support a companion host controller */ regval |= EHCI_PORTSC_OWNER; @@ -3315,7 +3370,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) { /* Assume full-speed for now */ - rhport->ep0.speed = EHCI_FULL_SPEED; + rhport->ep0.speed = USB_SPEED_FULL; } /* Put the root hub port in reset. @@ -3340,7 +3395,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) * write a zero to the Port Enable bit." */ - regaddr = &HCOR->portsc[rhport->rhpndx]; + regaddr = &HCOR->portsc[RHPNDX(rhport)]; regval = lpc31_getreg(regaddr); regval &= ~EHCI_PORTSC_PE; regval |= EHCI_PORTSC_RESET; @@ -3412,7 +3467,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) { /* High speed device */ - rhport->ep0.speed = EHCI_HIGH_SPEED; + rhport->ep0.speed = USB_SPEED_HIGH; } else if ((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_FS) { @@ -3453,16 +3508,35 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) DEBUGASSERT((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_LS) } - /* 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 lpc31_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].drvr, rhpndx+1, &rhport->class); + DEBUGASSERT(hport); +#ifdef CONFIG_USBHOST_HUB + if (ROOTHUB(hport)) +#endif + { + ret = lpc31_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); @@ -3485,6 +3559,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) * funcaddr - The USB address of the function containing the endpoint that EP0 * controls. A funcaddr of zero will be received if no address is yet assigned * to the device. + * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * @@ -3497,17 +3572,12 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx) * ************************************************************************************/ -static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr, - uint16_t maxpacketsize) -{ - struct lpc31_rhport_s *rhport = (struct lpc31_rhport_s *)drvr; - struct lpc31_epinfo_s *epinfo; +static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) + { + struct lpc31_epinfo_s *epinfo = (struct lpc31_epinfo_s *)ep0; - DEBUGASSERT(rhport && - funcaddr >= 0 && funcaddr <= LPC31_EHCI_NRHPORT && - maxpacketsize < 2048); - - epinfo = &rhport->ep0; + DEBUGASSERT(drvr != NULL && epinfo != NULL && maxpacketsize < 2048); /* We must have exclusive access to the EHCI data structures. */ @@ -3522,55 +3592,6 @@ static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcadd return OK; } -/************************************************************************************ - * Name: lpc31_getdevinfo - * - * Description: - * Get information about the connected device. - * - * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * devinfo - A pointer to memory provided by the caller in which to return the - * device information. - * - * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure - * - * Assumptions: - * This function will *not* be called from an interrupt handler. - * - ************************************************************************************/ - -static int lpc31_getdevinfo(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_devinfo_s *devinfo) -{ - struct lpc31_rhport_s *rhport = (struct lpc31_rhport_s *)drvr; - struct lpc31_epinfo_s *epinfo; - - DEBUGASSERT(drvr && devinfo); - epinfo = &rhport->ep0; - - switch (epinfo->speed) - { - case EHCI_LOW_SPEED: - devinfo->speed = DEVINFO_SPEED_LOW; - break; - - case EHCI_FULL_SPEED: - devinfo->speed = DEVINFO_SPEED_FULL; - break; - - default: - case EHCI_HIGH_SPEED: - devinfo->speed = DEVINFO_SPEED_HIGH; - break; - } - - return OK; -} - /************************************************************************************ * Name: lpc31_epalloc * @@ -3582,7 +3603,7 @@ static int lpc31_getdevinfo(FAR struct usbhost_driver_s *drvr, * the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the - * allocated endpoint desciptor. + * allocated endpoint descriptor. * * Returned Values: * On success, zero (OK) is returned. On a failure, a negated errno value is @@ -3596,14 +3617,15 @@ static int lpc31_getdevinfo(FAR struct usbhost_driver_s *drvr, static int lpc31_epalloc(FAR struct usbhost_driver_s *drvr, const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep) { - struct lpc31_rhport_s *rhport = (struct lpc31_rhport_s *)drvr; struct lpc31_epinfo_s *epinfo; + struct usbhost_hubport_s *hport; /* Sanity check. NOTE that this method should only be called if a device is * connected (because we need a valid low speed indication). */ - DEBUGASSERT(drvr && epdesc && ep); + DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL && ep != NULL); + hport = epdesc->hport; /* Terse output only if we are tracing */ @@ -3611,7 +3633,7 @@ static int lpc31_epalloc(FAR struct usbhost_driver_s *drvr, usbhost_vtrace2(EHCI_VTRACE2_EPALLOC, epdesc->addr, epdesc->xfrtype); #else uvdbg("EP%d DIR=%s FA=%08x TYPE=%d Interval=%d MaxPacket=%d\n", - epdesc->addr, epdesc->in ? "IN" : "OUT", epdesc->funcaddr, + epdesc->addr, epdesc->in ? "IN" : "OUT", hport->funcaddr, epdesc->xfrtype, epdesc->interval, epdesc->mxpacketsize); #endif @@ -3632,13 +3654,13 @@ static int lpc31_epalloc(FAR struct usbhost_driver_s *drvr, epinfo->epno = epdesc->addr; epinfo->dirin = epdesc->in; - epinfo->devaddr = epdesc->funcaddr; + epinfo->devaddr = hport->funcaddr; #ifndef CONFIG_USBHOST_INT_DISABLE epinfo->interval = epdesc->interval; #endif epinfo->maxpacket = epdesc->mxpacketsize; epinfo->xfrtype = epdesc->xfrtype; - epinfo->speed = rhport->ep0.speed; + epinfo->speed = hport->speed; sem_init(&epinfo->iocsem, 0, 0); /* Success.. return an opaque reference to the endpoint information structure @@ -3844,9 +3866,9 @@ static int lpc31_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may - * be queued; Neither these methods nor the transfer() method can be called - * again until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one transfer + * may be queued; Neither these methods nor the transfer() method can be + * called again until the control transfer functions returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. @@ -3854,12 +3876,13 @@ static int lpc31_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to * the class create() method. + * ep0 - The control endpoint to send/receive the control request. * req - Describes the request to be sent. This request must lie in memory * created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value * in the request description. buffer must have been allocated using - * DRVR_ALLOC + * DRVR_ALLOC. * * NOTE: On an IN transaction, req and buffer may refer to the same allocated * memory. @@ -3869,31 +3892,31 @@ static int lpc31_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * 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. * *******************************************************************************/ -static int lpc31_ctrlin(FAR struct usbhost_driver_s *drvr, - FAR const struct usb_ctrlreq_s *req, - FAR uint8_t *buffer) +static int lpc31_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + FAR const struct usb_ctrlreq_s *req, + FAR uint8_t *buffer) { struct lpc31_rhport_s *rhport = (struct lpc31_rhport_s *)drvr; + struct lpc31_epinfo_s *ep0info = (struct lpc31_epinfo_s *)ep0; uint16_t len; ssize_t nbytes; - DEBUGASSERT(rhport && req); + DEBUGASSERT(rhport != NULL && ep0info != NULL && req != NULL); len = lpc31_read16(req->len); /* Terse output only if we are tracing */ #ifdef CONFIG_USBHOST_TRACE - usbhost_vtrace2(EHCI_VTRACE2_CTRLINOUT, rhport->rhpndx + 1, req->req); + usbhost_vtrace2(EHCI_VTRACE2_CTRLINOUT, RHPORT(rhport), req->req); #else uvdbg("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %04x\n", - rhport->rhpndx + 1, req->type, req->req, req->value[1], req->value[0], + RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], len); #endif @@ -3903,20 +3926,20 @@ static int lpc31_ctrlin(FAR struct usbhost_driver_s *drvr, /* Now perform the transfer */ - nbytes = lpc31_async_transfer(rhport, &rhport->ep0, req, buffer, len); + nbytes = lpc31_async_transfer(rhport, ep0info, req, buffer, len); lpc31_givesem(&g_ehci.exclsem); return nbytes >=0 ? OK : (int)nbytes; } -static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, - FAR const struct usb_ctrlreq_s *req, - FAR const uint8_t *buffer) +static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, + FAR const struct usb_ctrlreq_s *req, + FAR const uint8_t *buffer) { /* lpc31_ctrlin can handle both directions. We just need to work around the * differences in the function signatures. */ - return lpc31_ctrlin(drvr, req, (uint8_t *)buffer); + return lpc31_ctrlin(drvr, ep0, req, (uint8_t *)buffer); } /******************************************************************************* @@ -3924,8 +3947,9 @@ static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request and return immediately. Only one transfer may be - * queued;. + * enqueue the transfer request, blocking until the transfer completes. Only + * one transfer may be queued; Neither this method nor the ctrlin or + * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. @@ -3950,7 +3974,6 @@ static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, * EPIPE - Overrun errors * * 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. * @@ -3998,6 +4021,127 @@ static int lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, return nbytes >=0 ? OK : (int)nbytes; } +/******************************************************************************* + * Name: lpc31_asynch + * + * Description: + * Process a request to handle a transfer descriptor. This method will + * enqueue the transfer request and return immediately. When the transfer + * completes, the the callback will be invoked with the provided transfer. + * This method is useful for receiving interrupt transfers which may come + * infrequently. + * + * Only one transfer may be queued; Neither this method nor the ctrlin or + * ctrlout methods can be called again until the transfer completes. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the call to + * the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which to + * perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or received + * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * buflen - The length of the data to be sent or received. + * callback - This function will be called when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback function + * when the transfer completes. + * + * Returned Values: + * On success, zero (OK) is returned. 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. + * - Never called from an interrupt handler. + * + *******************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static int lpc31_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) +{ +# error Not implemented + return -ENOSYS; +} +#endif /* CONFIG_USBHOST_ASYNCH */ + +/************************************************************************************ + * Name: lpc31_cancel + * + * Description: + * Cancel a pending asynchronous transfer on an endpoint. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the call to + * the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which an + * asynchronous transfer should be transferred. + * + * 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_ASYNCH +static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) +{ +# error Not implemented + return -ENOSYS; +} +#endif /* CONFIG_USBHOST_ASYNCH */ + +/************************************************************************************ + * Name: lpc31_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 lpc31_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; + lpc31_givesem(&g_ehci.pscsem); + } + + irqrestore(flags); + return OK; +} +#endif + /******************************************************************************* * Name: lpc31_disconnect * @@ -4029,7 +4173,7 @@ static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr) /* Unbind the class */ /* REVISIT: Is there more that needs to be done? */ - rhport->class = NULL; + rhport->hport.hport.devclass = NULL; } /******************************************************************************* @@ -4041,7 +4185,7 @@ static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr) * Description: * Set the HCRESET bit in the USBCMD register to reset the EHCI hardware. * - * Table 2-9. USBCMD – USB Command Register Bit Definitions + * Table 2-9. USBCMD - USB Command Register Bit Definitions * * "Host Controller Reset (HCRESET) ... This control bit is used by software * to reset the host controller. The effects of this on Root Hub registers @@ -4073,7 +4217,7 @@ static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr) * on failure. * * Assumptions: - * - Called during the initializaation of the EHCI. + * - Called during the initialization of the EHCI. * *******************************************************************************/ @@ -4179,6 +4323,7 @@ static int lpc31_reset(void) FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) { + FAR struct usbhost_hubport_s *hport; uint32_t regval; #if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE) uint16_t regval16; @@ -4225,12 +4370,10 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) for (i = 0; i < LPC31_EHCI_NRHPORT; i++) { struct lpc31_rhport_s *rhport = &g_ehci.rhport[i]; - rhport->rhpndx = i; /* Initialize the device operations */ rhport->drvr.ep0configure = lpc31_ep0configure; - rhport->drvr.getdevinfo = lpc31_getdevinfo; rhport->drvr.epalloc = lpc31_epalloc; rhport->drvr.epfree = lpc31_epfree; rhport->drvr.alloc = lpc31_alloc; @@ -4240,14 +4383,36 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) rhport->drvr.ctrlin = lpc31_ctrlin; rhport->drvr.ctrlout = lpc31_ctrlout; rhport->drvr.transfer = lpc31_transfer; +#ifdef CONFIG_USBHOST_ASYNCH + rhport->drvr.asynch = lpc31_asynch; + rhport->drvr.cancel = lpc31_cancel; +#endif +#ifdef CONFIG_USBHOST_HUB + rhport->drvr.connect = lpc31_connect; +#endif rhport->drvr.disconnect = lpc31_disconnect; /* Initialize EP0 */ rhport->ep0.xfrtype = USB_EP_ATTR_XFER_CONTROL; - rhport->ep0.speed = EHCI_FULL_SPEED; + rhport->ep0.speed = USB_SPEED_FULL; rhport->ep0.maxpacket = 8; sem_init(&rhport->ep0.iocsem, 0, 0); + + /* Initialize the public port representation */ + + hport = &rhport->hport.hport; + hport->drvr = &rhport->drvr; +#ifdef CONFIG_USBHOST_HUB + hport->parent = NULL; +#endif + hport->ep0 = &rhport->ep0; + hport->port = i; + hport->speed = USB_SPEED_FULL; + + /* Initialize function address generation logic */ + + usbhost_devaddr_initialize(&rhport->hport); } #ifndef CONFIG_LPC31_EHCI_PREALLOCATE @@ -4380,18 +4545,18 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) /* "In order to initialize the host controller, software should perform the * following steps: * - * • "Program the CTRLDSSEGMENT register with 4-Gigabyte segment where all + * - "Program the CTRLDSSEGMENT register with 4-Gigabyte segment where all * of the interface data structures are allocated. [64-bit mode] - * • "Write the appropriate value to the USBINTR register to enable the + * - "Write the appropriate value to the USBINTR register to enable the * appropriate interrupts. - * • "Write the base address of the Periodic Frame List to the PERIODICLIST + * - "Write the base address of the Periodic Frame List to the PERIODICLIST * BASE register. If there are no work items in the periodic schedule, * all elements of the Periodic Frame List should have their T-Bits set * to a one. - * • "Write the USBCMD register to set the desired interrupt threshold, + * - "Write the USBCMD register to set the desired interrupt threshold, * frame list size (if applicable) and turn the host controller ON via * setting the Run/Stop bit. - * • Write a 1 to CONFIGFLAG register to route all ports to the EHCI controller + * - Write a 1 to CONFIGFLAG register to route all ports to the EHCI controller * ... * * "At this point, the host controller is up and running and the port registers diff --git a/arch/arm/src/sama5/sam_ehci.c b/arch/arm/src/sama5/sam_ehci.c index d4c6e8a2f4f..11d4feb4c0c 100644 --- a/arch/arm/src/sama5/sam_ehci.c +++ b/arch/arm/src/sama5/sam_ehci.c @@ -257,7 +257,7 @@ struct sam_ehci_s volatile struct usbhost_hubport_s *hport; #endif - /* Root hub ports */ + /* Root hub ports */ struct sam_rhport_s rhport[SAM_EHCI_NRHPORT]; }; @@ -392,23 +392,20 @@ static int sam_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); static int sam_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - FAR const struct usb_ctrlreq_s *req, - FAR uint8_t *buffer); + FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - FAR const struct usb_ctrlreq_s *req, - FAR const uint8_t *buffer); + FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH 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); + FAR uint8_t *buffer, size_t buflen, usbhost_asynch_t callback, + FAR void *arg); static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); #endif #ifdef CONFIG_USBHOST_HUB static int sam_connect(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_hubport_s *hport, - bool connected); + FAR struct usbhost_hubport_s *hport, bool connected); #endif static void sam_disconnect(FAR struct usbhost_driver_s *drvr); @@ -2638,6 +2635,7 @@ static inline void sam_ioc_bottomhalf(void) static inline void sam_portsc_bottomhalf(void) { struct sam_rhport_s *rhport; + struct usbhost_hubport_s *hport; uint32_t portsc; int rhpndx; @@ -2699,12 +2697,13 @@ static inline void sam_portsc_bottomhalf(void) /* Are we bound to a class instance? */ - if (rhport->hport.devclass) + hport = &rhport->hport.hport; + if (hport->devclass) { /* Yes.. Disconnect the class */ - CLASS_DISCONNECTED(rhport->hport.devclass); - rhport->hport.devclass = NULL; + CLASS_DISCONNECTED(hport->devclass); + hport->devclass = NULL; } /* Notify any waiters for the Root Hub Status change @@ -3036,20 +3035,25 @@ static int sam_wait(FAR struct usbhost_connection_s *conn, for (rhpndx = 0; rhpndx < SAM_EHCI_NRHPORT; rhpndx++) { + struct lpc31_rhport_s *rhport; + struct usbhost_hubport_s *connport; + /* Has the connection state changed on the RH port? */ - if (g_ehci.rhport[rhpndx].hport.connected != connected[rhpndx]) + rhport = &g_ehci.rhport[rhpndx]; + connport = &rhport->hport.hport; + if (rhport->connected != connport->connected) { /* Yes.. Return the RH port to inform the caller which * port has the connection change. */ - *hport = &g_ehci.rhport[rhpndx].hport; + connport->connected = rhport->connected; + *hport = connport; irqrestore(flags); usbhost_vtrace2(EHCI_VTRACE2_MONWAKEUP, - rhpndx + 1, - g_ehci.rhport[rhpndx].hport.connected); + rhpndx + 1, rhport->conected); return OK; } } @@ -3059,14 +3063,14 @@ static int sam_wait(FAR struct usbhost_connection_s *conn, if (g_ehci.hport) { - FAR volatile struct usbhost_hubport_s *connport; + volatile struct usbhost_hubport_s *connport; /* Yes.. return the external hub port */ connport = g_ehci.hport; g_ehci.hport = NULL; - *hport = connport; + *hport = (struct usbhost_hubport_s *)connport; irqrestore(flags); usbhost_vtrace2(EHCI_VTRACE2_MONWAKEUP, @@ -3119,7 +3123,6 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn, volatile uint32_t *regaddr; uint32_t regval; int rhpndx; - int ret; DEBUGASSERT(conn != NULL && hport != NULL); rhpndx = hport->port; @@ -3690,7 +3693,6 @@ static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * Name: sam_ctrlin and sam_ctrlout * * Description: - * Description: * Process a IN or OUT request on the control endpoint. These methods * will enqueue the request and wait for it to complete. Only one transfer may be * queued; Neither these methods nor the transfer() method can be called again @@ -3847,7 +3849,7 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, } /******************************************************************************* - * Name: lcp17_asynch + * Name: lpc17_asynch * * Description: * Process a request to handle a transfer descriptor. This method will @@ -3998,7 +4000,7 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr) /* Unbind the class */ /* REVISIT: Is there more that needs to be done? */ - rhport->hport.devclass = NULL; + rhport->hport.hport.devclass = NULL; } /******************************************************************************* @@ -4010,7 +4012,7 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr) * Description: * Set the HCRESET bit in the USBCMD register to reset the EHCI hardware. * - * Table 2-9. USBCMD – USB Command Register Bit Definitions + * Table 2-9. USBCMD - USB Command Register Bit Definitions * * "Host Controller Reset (HCRESET) ... This control bit is used by software * to reset the host controller. The effects of this on Root Hub registers @@ -4042,7 +4044,7 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr) * on failure. * * Assumptions: - * - Called during the initializaation of the EHCI. + * - Called during the initialization of the EHCI. * *******************************************************************************/ diff --git a/configs/olimex-lpc-h3131/README.txt b/configs/olimex-lpc-h3131/README.txt index c952f910328..27bc61887cd 100644 --- a/configs/olimex-lpc-h3131/README.txt +++ b/configs/olimex-lpc-h3131/README.txt @@ -648,7 +648,7 @@ Configurations RAMTest: Pattern test: 30000000 33554432 33333333 cccccccc RAMTest: Address-in-address test: 30000000 33554432 - 4. This configuration has been used to test USB host functionaly. USB + 4. This configuration has been used to test USB host functionality. USB host is *not* enabled by default. If you will to enable USB host support in the NSH configuration, please modify the NuttX configuration as follows: @@ -657,7 +657,7 @@ Configurations Drivers -> USB Host Driver Support CONFIG_USBHOST=y : General USB host support - CONFIG_USBHOST_INT_DISABLE=y : Not needed (unless you use the keyboard) + CONFIG_USBHOST_INT_DISABLE=n : Interrupt EPs need with hub, HID keyboard, and HID mouse CONFIG_USBHOST_ISOC_DISABLE=y : Not needed (or supported) System Type -> Peripherals @@ -667,11 +667,24 @@ Configurations CONFIG_LPC31_EHCI_BUFSIZE=128 CONFIG_LPC31_EHCI_PREALLOCATE=y - Library Routines + RTOS Features -> Work Queue Support CONFIG_SCHED_WORKQUEUE=y : Work queue support is needed CONFIG_SCHED_HPWORKSTACKSIZE=1536 - b. USB Mass Storage Class. With this class enabled, you can support + b. Hub Support. + + Drivers -> USB Host Driver Support + CONFIG_USBHOST_INT_DISABLE=n : Interrupt endpoint support needed + CONFIG_USBHOST_HUB=y : Enable the hub class + CONFIG_USBHOST_ASYNCH=y : Asynchonous I/O supported needed for hubs + + System Type -> USB host configuration + To be provided + + Logic nesting becomes deeper with a hub and it may also be + necessary to increase some stack sizes. + + c. USB Mass Storage Class. With this class enabled, you can support connection of USB FLASH storage drives. Support for the USB mass storage class is enabled like this: @@ -718,7 +731,7 @@ Configurations nsh> umount /mnt/flash - c. HID Keyboard support. The following support will enable support + d. HID Keyboard support. The following support will enable support for certain keyboard devices (only the so-called "boot" keyboard class is supported): diff --git a/configs/olimex-lpc-h3131/nsh/defconfig b/configs/olimex-lpc-h3131/nsh/defconfig index 0fd97962134..e205166a5dc 100644 --- a/configs/olimex-lpc-h3131/nsh/defconfig +++ b/configs/olimex-lpc-h3131/nsh/defconfig @@ -46,8 +46,9 @@ CONFIG_RAW_BINARY=y # Debug Options # # CONFIG_DEBUG is not set -CONFIG_ARCH_HAVE_STACKCHECK=y # CONFIG_ARCH_HAVE_HEAPCHECK is not set +CONFIG_ARCH_HAVE_STACKCHECK=y +# CONFIG_STACK_COLORATION is not set # CONFIG_DEBUG_SYMBOLS is not set CONFIG_ARCH_HAVE_CUSTOMOPT=y # CONFIG_DEBUG_NOOPT is not set @@ -76,6 +77,7 @@ CONFIG_ARCH="arm" # CONFIG_ARCH_CHIP_C5471 is not set # CONFIG_ARCH_CHIP_CALYPSO is not set # CONFIG_ARCH_CHIP_DM320 is not set +# CONFIG_ARCH_CHIP_EFM32 is not set # CONFIG_ARCH_CHIP_IMX is not set # CONFIG_ARCH_CHIP_KINETIS is not set # CONFIG_ARCH_CHIP_KL is not set @@ -90,6 +92,7 @@ CONFIG_ARCH_CHIP_LPC31XX=y # CONFIG_ARCH_CHIP_SAMA5 is not set # CONFIG_ARCH_CHIP_SAMD is not set # CONFIG_ARCH_CHIP_SAM34 is not set +# CONFIG_ARCH_CHIP_SAMV7 is not set # CONFIG_ARCH_CHIP_STM32 is not set # CONFIG_ARCH_CHIP_STR71X is not set # CONFIG_ARCH_ARM7TDMI is not set @@ -98,11 +101,13 @@ CONFIG_ARCH_ARM926EJS=y # CONFIG_ARCH_CORTEXM0 is not set # CONFIG_ARCH_CORTEXM3 is not set # CONFIG_ARCH_CORTEXM4 is not set +# CONFIG_ARCH_CORTEXM7 is not set # CONFIG_ARCH_CORTEXA5 is not set # CONFIG_ARCH_CORTEXA8 is not set CONFIG_ARCH_FAMILY="arm" CONFIG_ARCH_CHIP="lpc31xx" # CONFIG_ARCH_HAVE_FPU is not set +# CONFIG_ARCH_HAVE_DPFPU is not set CONFIG_ARCH_HAVE_LOWVECTORS=y CONFIG_ARCH_LOWVECTORS=y CONFIG_ARCH_ROMPGTABLE=y @@ -225,6 +230,12 @@ CONFIG_NSH_MMCSDMINOR=0 # # Board-Specific Options # +CONFIG_LIB_BOARDCTL=y +# CONFIG_BOARDCTL_TSCTEST is not set +# CONFIG_BOARDCTL_ADCTEST is not set +# CONFIG_BOARDCTL_PWMTEST is not set +# CONFIG_BOARDCTL_GRAPHICS is not set +# CONFIG_BOARDCTL_IOCTL is not set # # RTOS Features @@ -254,6 +265,9 @@ CONFIG_PREALLOC_TIMERS=4 # # Tasks and Scheduling # +# CONFIG_INIT_NONE is not set +CONFIG_INIT_ENTRYPOINT=y +# CONFIG_INIT_FILEPATH is not set CONFIG_USER_ENTRYPOINT="nsh_main" CONFIG_RR_INTERVAL=200 CONFIG_TASK_NAME_SIZE=0 @@ -307,6 +321,13 @@ CONFIG_SIG_SIGCONDTIMEDOUT=16 CONFIG_PREALLOC_MQ_MSGS=4 CONFIG_MQ_MAXMSGSIZE=32 +# +# Work Queue Support +# +# CONFIG_SCHED_WORKQUEUE is not set +# CONFIG_SCHED_HPWORK is not set +# CONFIG_SCHED_LPWORK is not set + # # Stack and heap information # @@ -337,9 +358,13 @@ CONFIG_DEV_NULL=y # CONFIG_I2C is not set # CONFIG_SPI is not set # CONFIG_I2S is not set + +# +# Timer Driver Support +# +# CONFIG_TIMER is not set # CONFIG_RTC is not set # CONFIG_WATCHDOG is not set -# CONFIG_TIMER is not set # CONFIG_ANALOG is not set # CONFIG_AUDIO_DEVICES is not set # CONFIG_VIDEO_DEVICES is not set @@ -348,6 +373,7 @@ CONFIG_DEV_NULL=y # CONFIG_LCD is not set # CONFIG_MMCSD is not set # CONFIG_MTD is not set +# CONFIG_EEPROM is not set # CONFIG_PIPES is not set # CONFIG_PM is not set # CONFIG_POWER is not set @@ -377,13 +403,18 @@ CONFIG_ARCH_HAVE_UART=y # CONFIG_ARCH_HAVE_USART6 is not set # CONFIG_ARCH_HAVE_USART7 is not set # CONFIG_ARCH_HAVE_USART8 is not set +# CONFIG_ARCH_HAVE_OTHER_UART is not set # # USART Configuration # CONFIG_MCU_SERIAL=y CONFIG_STANDARD_SERIAL=y +# CONFIG_SERIAL_IFLOWCONTROL is not set +# CONFIG_SERIAL_OFLOWCONTROL is not set +# CONFIG_ARCH_HAVE_SERIAL_TERMIOS is not set CONFIG_UART_SERIAL_CONSOLE=y +# CONFIG_OTHER_SERIAL_CONSOLE is not set # CONFIG_NO_SERIAL_CONSOLE is not set # @@ -397,8 +428,6 @@ CONFIG_UART_PARITY=0 CONFIG_UART_2STOP=0 # CONFIG_UART_IFLOWCONTROL is not set # CONFIG_UART_OFLOWCONTROL is not set -# CONFIG_SERIAL_IFLOWCONTROL is not set -# CONFIG_SERIAL_OFLOWCONTROL is not set # CONFIG_USBDEV is not set # CONFIG_USBHOST is not set # CONFIG_WIRELESS is not set @@ -411,6 +440,7 @@ CONFIG_UART_2STOP=0 # System Logging # # CONFIG_RAMLOG is not set +# CONFIG_SYSLOG_CONSOLE is not set # # Networking Support @@ -436,6 +466,8 @@ CONFIG_UART_2STOP=0 # CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set CONFIG_FS_READABLE=y CONFIG_FS_WRITABLE=y +# CONFIG_FS_NAMED_SEMAPHORES is not set +CONFIG_FS_MQUEUE_MPATH="/var/mqueue" # CONFIG_FS_RAMMAP is not set CONFIG_FS_FAT=y CONFIG_FAT_LCNAMES=y @@ -451,8 +483,8 @@ CONFIG_FAT_MAXFNAME=32 # # System Logging # - # CONFIG_SYSLOG is not set +# CONFIG_SYSLOG_TIMESTAMP is not set # # Graphics Support @@ -474,7 +506,7 @@ CONFIG_MM_REGIONS=1 # CONFIG_AUDIO is not set # -# Binary Formats +# Binary Loader # # CONFIG_BINFMT_DISABLE is not set # CONFIG_BINFMT_EXEPATH is not set @@ -498,6 +530,7 @@ CONFIG_LIB_HOMEDIR="/" # CONFIG_LIBM is not set # CONFIG_NOPRINTF_FIELDWIDTH is not set # CONFIG_LIBC_FLOATINGPOINT is not set +# CONFIG_LIBC_IOCTL_VARIADIC is not set CONFIG_LIB_RAND_ORDER=1 # CONFIG_EOL_IS_CR is not set # CONFIG_EOL_IS_LF is not set @@ -508,8 +541,11 @@ CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=1024 CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=1536 # CONFIG_LIBC_STRERROR is not set # CONFIG_LIBC_PERROR_STDOUT is not set +CONFIG_LIBC_TMPDIR="/tmp" +CONFIG_LIBC_MAX_TMPFILE=32 CONFIG_ARCH_LOWPUTC=y # CONFIG_LIBC_LOCALTIME is not set +# CONFIG_TIME_EXTENDED is not set CONFIG_LIB_SENDFILE_BUFSIZE=512 # CONFIG_ARCH_ROMGETC is not set # CONFIG_ARCH_OPTIMIZED_FUNCTIONS is not set @@ -517,7 +553,6 @@ CONFIG_LIB_SENDFILE_BUFSIZE=512 # # Non-standard Library Support # -# CONFIG_SCHED_WORKQUEUE is not set # CONFIG_LIB_KBDCODEC is not set # CONFIG_LIB_SLCDCODEC is not set @@ -569,10 +604,10 @@ CONFIG_EXAMPLES_NSH=y # CONFIG_EXAMPLES_OSTEST is not set # CONFIG_EXAMPLES_PIPE is not set # CONFIG_EXAMPLES_POLL is not set +# CONFIG_EXAMPLES_PPPD is not set # CONFIG_EXAMPLES_POSIXSPAWN is not set # CONFIG_EXAMPLES_QENCODER is not set # CONFIG_EXAMPLES_RGMP is not set -# CONFIG_EXAMPLES_ROMFS is not set # CONFIG_EXAMPLES_SENDMAIL is not set # CONFIG_EXAMPLES_SERIALBLASTER is not set # CONFIG_EXAMPLES_SERIALRX is not set @@ -584,7 +619,6 @@ CONFIG_EXAMPLES_NSH=y # CONFIG_EXAMPLES_THTTPD is not set # CONFIG_EXAMPLES_TIFF is not set # CONFIG_EXAMPLES_TOUCHSCREEN is not set -# CONFIG_EXAMPLES_UDP is not set # CONFIG_EXAMPLES_WEBSERVER is not set # CONFIG_EXAMPLES_USBSERIAL is not set # CONFIG_EXAMPLES_USBTERM is not set @@ -594,12 +628,15 @@ CONFIG_EXAMPLES_NSH=y # Graphics Support # # CONFIG_TIFF is not set +# CONFIG_GRAPHICS_TRAVELER is not set # # Interpreters # +# CONFIG_INTERPRETERS_BAS is not set # CONFIG_INTERPRETERS_FICL is not set # CONFIG_INTERPRETERS_PCODE is not set +# CONFIG_INTERPRETERS_MICROPYTHON is not set # # Network Utilities @@ -609,15 +646,11 @@ CONFIG_EXAMPLES_NSH=y # Networking Utilities # # CONFIG_NETUTILS_CODECS is not set -# CONFIG_NETUTILS_DHCPD is not set # CONFIG_NETUTILS_FTPC is not set -# CONFIG_NETUTILS_FTPD is not set # CONFIG_NETUTILS_JSON is not set # CONFIG_NETUTILS_SMTP is not set -# CONFIG_NETUTILS_TFTPC is not set # CONFIG_NETUTILS_THTTPD is not set -# CONFIG_NETUTILS_NETLIB is not set -# CONFIG_NETUTILS_WEBCLIENT is not set +# CONFIG_NETUTILS_PPPD is not set # # FreeModBus @@ -650,6 +683,7 @@ CONFIG_NSH_NESTDEPTH=3 # CONFIG_NSH_DISABLE_CD is not set # CONFIG_NSH_DISABLE_CP is not set # CONFIG_NSH_DISABLE_CMP is not set +CONFIG_NSH_DISABLE_DATE=y # CONFIG_NSH_DISABLE_DD is not set # CONFIG_NSH_DISABLE_DF is not set # CONFIG_NSH_DISABLE_DELROUTE is not set @@ -671,6 +705,7 @@ CONFIG_NSH_NESTDEPTH=3 # CONFIG_NSH_DISABLE_MKRD is not set # CONFIG_NSH_DISABLE_MH is not set # CONFIG_NSH_DISABLE_MOUNT is not set +# CONFIG_NSH_DISABLE_MV is not set # CONFIG_NSH_DISABLE_MW is not set # CONFIG_NSH_DISABLE_PS is not set # CONFIG_NSH_DISABLE_PUT is not set @@ -708,7 +743,6 @@ CONFIG_NSH_FILEIOSIZE=512 CONFIG_NSH_CONSOLE=y # CONFIG_NSH_ALTCONDEV is not set CONFIG_NSH_ARCHINIT=y -CONFIG_LIB_BOARDCTL=y # # NxWidgets/NxWM @@ -722,115 +756,19 @@ CONFIG_LIB_BOARDCTL=y # # System Libraries and NSH Add-Ons # - -# -# Custom Free Memory Command -# # CONFIG_SYSTEM_FREE is not set - -# -# EMACS-like Command Line Editor -# # CONFIG_SYSTEM_CLE is not set - -# -# FLASH Program Installation -# +# CONFIG_SYSTEM_CUTERM is not set # CONFIG_SYSTEM_INSTALL is not set - -# -# FLASH Erase-all Command -# - -# -# Intel HEX to binary conversion -# # CONFIG_SYSTEM_HEX2BIN is not set - -# -# I2C tool -# - -# -# INI File Parser -# # CONFIG_SYSTEM_INIFILE is not set - -# -# NxPlayer media player library / command Line -# -# CONFIG_SYSTEM_NXPLAYER is not set - -# -# RAM test -# # CONFIG_SYSTEM_RAMTEST is not set - -# -# readline() -# CONFIG_SYSTEM_READLINE=y CONFIG_READLINE_ECHO=y - -# -# P-Code Support -# - -# -# PHY Tool -# - -# -# Power Off -# # CONFIG_SYSTEM_POWEROFF is not set - -# -# RAMTRON -# # CONFIG_SYSTEM_RAMTRON is not set - -# -# SD Card -# # CONFIG_SYSTEM_SDCARD is not set - -# -# Sudoku -# # CONFIG_SYSTEM_SUDOKU is not set - -# -# Sysinfo -# # CONFIG_SYSTEM_SYSINFO is not set - -# -# VI Work-Alike Editor -# # CONFIG_SYSTEM_VI is not set - -# -# Stack Monitor -# - -# -# USB CDC/ACM Device Commands -# - -# -# USB Composite Device Commands -# - -# -# USB Mass Storage Device Commands -# - -# -# USB Monitor -# - -# -# Zmodem Commands -# # CONFIG_SYSTEM_ZMODEM is not set diff --git a/configs/olimex-lpc-h3131/nsh/setenv.sh b/configs/olimex-lpc-h3131/nsh/setenv.sh index 7ebc4227e41..27914f77f9b 100755 --- a/configs/olimex-lpc-h3131/nsh/setenv.sh +++ b/configs/olimex-lpc-h3131/nsh/setenv.sh @@ -51,6 +51,7 @@ fi # toolchain under windows. You will also have to edit this if you install # the CodeSourcery toolchain in any other location export TOOLCHAIN_BIN="/cygdrive/c/Program Files (x86)/CodeSourcery/Sourcery G++ Lite/bin" +#export TOOLCHAIN_BIN="/cygdrive/c/Users/MyName/MentorGraphics/Sourcery_CodeBench_Lite_for_ARM_EABI/bin" # This is the Cygwin path to the location where I build the buildroot # toolchain. diff --git a/configs/olimex-lpc-h3131/src/lpc31_usbhost.c b/configs/olimex-lpc-h3131/src/lpc31_usbhost.c index 1433cce87b3..cf222b4b0df 100644 --- a/configs/olimex-lpc-h3131/src/lpc31_usbhost.c +++ b/configs/olimex-lpc-h3131/src/lpc31_usbhost.c @@ -97,35 +97,23 @@ static xcpt_t g_ochandler; static int ehci_waiter(int argc, char *argv[]) { - bool connected = false; - int rhpndx; - int ret; + FAR struct usbhost_hubport_s *hport; - uvdbg("Waiter Running\n"); + uvdbg("ehci_waiter: Running\n"); for (;;) { /* Wait for the device to change state */ - rhpndx = CONN_WAIT(g_ehciconn, &connected); - DEBUGASSERT(rhpndx >= 0 && rhpndx < 1); - - connected = !connected; - - uvdbg("RHport1 %s\n", - connected ? "connected" : "disconnected"); + DEBUGVERIFY(CONN_WAIT(g_ehciconn, &hport)); + printf("ehci_waiter: %s\n", hport->connected ? "connected" : "disconnected"); /* Did we just become connected? */ - if (connected) + if (hport->connected) { /* Yes.. enumerate the newly connected device */ - ret = CONN_ENUMERATE(g_ehciconn, rhpndx); - if (ret < 0) - { - uvdbg("RHport1 CONN_ENUMERATE failed: %d\n", ret); - connected = false; - } + (void)CONN_ENUMERATE(g_ehciconn, hport); } } @@ -183,11 +171,21 @@ int lpc31_usbhost_initialize(void) /* First, register all of the class drivers needed to support the drivers * that we care about - * - * Register theUSB host Mass Storage Class: */ +#ifdef CONFIG_USBHOST_HUB + /* Initialize USB hub support */ + + ret = usbhost_hub_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: usbhost_hub_initialize failed: %d\n", ret); + } +#endif + #ifdef CONFIG_USBHOST_MSC + /* Register theUSB host Mass Storage Class */ + ret = usbhost_storageinit(); if (ret != OK) { @@ -195,9 +193,9 @@ int lpc31_usbhost_initialize(void) } #endif +#ifdef CONFIG_USBHOST_HIDKBD /* Register the USB host HID keyboard class driver */ -#ifdef CONFIG_USBHOST_HIDKBD ret = usbhost_kbdinit(); if (ret != OK) { diff --git a/configs/olimex-lpc1766stk/README.txt b/configs/olimex-lpc1766stk/README.txt index bb329b9aa17..f5e138f8f58 100644 --- a/configs/olimex-lpc1766stk/README.txt +++ b/configs/olimex-lpc1766stk/README.txt @@ -977,7 +977,7 @@ Configuration Sub-Directories crash seems seems to be due to a corrupt addess in the callback from the new asynchronous I/O. Should not be too hard to fix. - Also, the code does not enumerat the hub if it is connected at the + Also, the code does not enumerate the hub if it is connected at the time of power up. hidmouse: