Port hub support to LPC31 from SAMA5; Updated Olimex-LPC-H3131 for hub support and refresh configurations

This commit is contained in:
Gregory Nutt 2015-04-26 12:18:08 -06:00
parent d88d10830e
commit eabbb6ede1
9 changed files with 455 additions and 337 deletions

View File

@ -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

View File

@ -60,6 +60,7 @@ config LPC31_SPI
config LPC31_USBOTG
bool "USB OTG"
default n
select USBHOST_HAVE_ASYNCH
config LPC31_MCI
bool "MCI"

View File

@ -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 <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -53,6 +53,7 @@
#include <nuttx/usb/usb.h>
#include <nuttx/usb/usbhost.h>
#include <nuttx/usb/ehci.h>
#include <nuttx/usb/usbhost_devaddr.h>
#include <nuttx/usb/usbhost_trace.h>
#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

View File

@ -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.
*
*******************************************************************************/

View File

@ -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):

View File

@ -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

View File

@ -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.

View File

@ -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)
{

View File

@ -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: