SAMA5 OHCI and EHCI: Now conform to new interfaces to support hubs

This commit is contained in:
Gregory Nutt 2015-04-21 08:59:30 -06:00
parent 47f2a0b09d
commit 5af46ed7e4
2 changed files with 160 additions and 222 deletions

View File

@ -224,10 +224,12 @@ struct sam_rhport_s
/* Root hub port status */
volatile bool connected; /* Connected to device */
volatile bool lowspeed; /* Low speed device attached */
uint8_t rhpndx; /* Root hub port index */
struct sam_epinfo_s ep0; /* EP0 endpoint info */
/* This is the hub port description understood by class drivers */
struct usbhost_hubport_s hport;
/* The bound device class driver */
struct usbhost_class_s *class;
@ -366,10 +368,8 @@ static int sam_wait(FAR struct usbhost_connection_s *conn,
FAR const bool *connected);
static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx);
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
uint16_t maxpacketsize);
static int sam_getdevinfo(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_devinfo_s *devinfo);
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
uint8_t funcaddr, uint16_t maxpacketsize);
static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep);
static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep);
@ -379,10 +379,12 @@ static int sam_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
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,
FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer);
static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
FAR const struct usb_ctrlreq_s *req, FAR const 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);
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);
static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
FAR uint8_t *buffer, size_t buflen);
static void sam_disconnect(FAR struct usbhost_driver_s *drvr);
@ -1423,6 +1425,7 @@ static struct sam_qh_s *sam_qh_create(struct sam_rhport_s *rhport,
struct sam_epinfo_s *epinfo)
{
struct sam_qh_s *qh;
uint32_t rhpndx;
uint32_t regval;
/* Allocate a new queue head structure */
@ -1452,9 +1455,9 @@ static struct sam_qh_s *sam_qh_create(struct sam_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);
@ -1465,7 +1468,7 @@ static struct sam_qh_s *sam_qh_create(struct sam_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;
@ -1489,9 +1492,10 @@ static struct sam_qh_s *sam_qh_create(struct sam_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 = rhport->hport.port;
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)
@ -1835,7 +1839,7 @@ static ssize_t sam_async_transfer(struct sam_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->hport.port+1, epinfo->epno, buffer, buflen, req);
#endif
DEBUGASSERT(rhport && epinfo);
@ -2194,7 +2198,7 @@ static ssize_t sam_intr_transfer(struct sam_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->hport.port+1, epinfo->epno, buffer, buflen);
#endif
DEBUGASSERT(rhport && epinfo && buffer && buflen > 0);
@ -2669,7 +2673,6 @@ static inline void sam_portsc_bottomhalf(void)
rhpndx+1, g_ehci.pscwait);
rhport->connected = false;
rhport->lowspeed = false;
/* Are we bound to a class instance? */
@ -3141,7 +3144,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
* repeat."
*/
rhport->ep0.speed = EHCI_LOW_SPEED;
rhport->ep0.speed = USB_SPEED_LOW;
regval |= EHCI_PORTSC_OWNER;
sam_putreg(regval, &HCOR->portsc[rhpndx]);
@ -3164,7 +3167,7 @@ static int sam_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.
@ -3189,7 +3192,7 @@ static int sam_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[rhport->hport.port];
regval = sam_getreg(regaddr);
regval &= ~EHCI_PORTSC_PE;
regval |= EHCI_PORTSC_RESET;
@ -3243,7 +3246,7 @@ static int sam_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
{
@ -3291,7 +3294,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
*/
usbhost_vtrace2(EHCI_VTRACE2_CLASSENUM, rhpndx+1, rhpndx+1);
ret = usbhost_enumerate(&g_ehci.rhport[rhpndx].drvr, rhpndx+1, &rhport->class);
ret = usbhost_enumerate(&g_ehci.rhport[rhpndx].hport, &rhport->class);
if (ret < 0)
{
usbhost_trace2(EHCI_TRACE2_CLASSENUM_FAILED, rhpndx+1, -ret);
@ -3326,17 +3329,12 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
*
************************************************************************************/
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
uint16_t maxpacketsize)
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
uint8_t funcaddr, uint16_t maxpacketsize)
{
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_epinfo_s *epinfo;
struct sam_epinfo_s *epinfo = (struct sam_epinfo_s *)ep0;
DEBUGASSERT(rhport &&
funcaddr >= 0 && funcaddr <= SAM_EHCI_NRHPORT &&
maxpacketsize < 2048);
epinfo = &rhport->ep0;
DEBUGASSERT(drvr != NULL && epinfo != NULL && maxpacketsize < 2048);
/* We must have exclusive access to the EHCI data structures. */
@ -3351,66 +3349,6 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
return OK;
}
/************************************************************************************
* Name: sam_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 sam_getdevinfo(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_devinfo_s *devinfo)
{
#if 0
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_epinfo_s *epinfo;
DEBUGASSERT(drvr && devinfo);
epinfo = &rhport->ep0;
/* As implemented now, this driver supports only HIGH speed. All
* low or full speed devices are handed off to the OHCI driver.
*/
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;
}
#else
DEBUGASSERT(drvr && devinfo);
devinfo->speed = DEVINFO_SPEED_HIGH;
#endif
return OK;
}
/************************************************************************************
* Name: sam_epalloc
*
@ -3436,14 +3374,15 @@ static int sam_getdevinfo(FAR struct usbhost_driver_s *drvr,
static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep)
{
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_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 */
@ -3472,13 +3411,13 @@ static int sam_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
@ -3683,10 +3622,11 @@ 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 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.
@ -3694,12 +3634,12 @@ static int sam_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
* in the request description. buffer must have been allocated using DRVR_ALLOC.
*
* NOTE: On an IN transaction, req and buffer may refer to the same allocated
* memory.
@ -3709,31 +3649,31 @@ static int sam_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 sam_ctrlin(FAR struct usbhost_driver_s *drvr,
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)
{
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_epinfo_s *ep0info = (struct sam_epinfo_s *)ep0;
uint16_t len;
ssize_t nbytes;
DEBUGASSERT(rhport && req);
DEBUGASSERT(rhport != NULL && epinfo != NULL && req != NULL);
len = sam_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->hport.port + 1, 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->hport.port + 1, req->type, req->req, req->value[1], req->value[0],
req->index[1], req->index[0], len);
#endif
@ -3743,12 +3683,12 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr,
/* Now perform the transfer */
nbytes = sam_async_transfer(rhport, &rhport->ep0, req, buffer, len);
nbytes = sam_async_transfer(rhport, ep0info, req, buffer, len);
sam_givesem(&g_ehci.exclsem);
return nbytes >=0 ? OK : (int)nbytes;
}
static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
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)
{
@ -3756,7 +3696,7 @@ static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
* differences in the function signatures.
*/
return sam_ctrlin(drvr, req, (uint8_t *)buffer);
return sam_ctrlin(drvr, ep0, req, (uint8_t *)buffer);
}
/*******************************************************************************
@ -4123,12 +4063,10 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller)
for (i = 0; i < SAM_EHCI_NRHPORT; i++)
{
struct sam_rhport_s *rhport = &g_ehci.rhport[i];
rhport->rhpndx = i;
/* Initialize the device operations */
rhport->drvr.ep0configure = sam_ep0configure;
rhport->drvr.getdevinfo = sam_getdevinfo;
rhport->drvr.epalloc = sam_epalloc;
rhport->drvr.epfree = sam_epfree;
rhport->drvr.alloc = sam_alloc;
@ -4143,9 +4081,19 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller)
/* 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 */
rhport->hport.drvr = &rhport->drvr;
#ifdef CONFIG_USBHOST_HUB
rhport->hport.parent = NULL;
#endif
rhport->hport.ep0 = &rhport->ep0;
rhport->hport.port = i;
rhport->hport.speed = USB_SPEED_FULL;
}
#ifndef CONFIG_SAMA5_EHCI_PREALLOCATE

View File

@ -1,7 +1,7 @@
/*******************************************************************************
* arch/arm/src/sama5/sam_ohci.c
*
* Copyright (C) 2013 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
@ -221,12 +221,15 @@ struct sam_rhport_s
/* Root hub port status */
volatile bool connected; /* Connected to device */
volatile bool lowspeed; /* Low speed device attached. */
uint8_t rhpndx; /* Root hub port index */
bool ep0init; /* True: EP0 initialized */
struct sam_eplist_s ep0; /* EP0 endpoint list */
/* This is the hub port description understood by class drivers */
struct usbhost_hubport_s hport;
/* The bound device class driver */
struct usbhost_class_s *class;
@ -361,14 +364,14 @@ static inline int sam_remisoced(struct sam_ed_s *ed);
/* Descriptor helper functions *************************************************/
static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_ed_s *ed,
uint32_t dirpid, uint32_t toggle,
volatile uint8_t *buffer, size_t buflen);
static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist,
struct sam_ed_s *ed, uint32_t dirpid, uint32_t toggle,
volatile uint8_t *buffer, size_t buflen);
static int sam_ep0enqueue(struct sam_rhport_s *rhport);
static void sam_ep0dequeue(struct sam_rhport_s *rhport);
static int sam_wdhwait(struct sam_rhport_s *rhport, struct sam_ed_s *ed);
static int sam_ctrltd(struct sam_rhport_s *rhport, uint32_t dirpid,
uint8_t *buffer, size_t buflen);
static int sam_ctrltd(struct sam_rhport_s *rhport, struct sam_eplist_s *ep0,
uint32_t dirpid, uint8_t *buffer, size_t buflen);
/* Interrupt handling **********************************************************/
@ -382,10 +385,8 @@ static int sam_wait(FAR struct usbhost_connection_s *conn,
FAR const bool *connected);
static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx);
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
uint16_t maxpacketsize);
static int sam_getdevinfo(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_devinfo_s *devinfo);
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
uint8_t funcaddr, uint16_t maxpacketsize);
static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep);
static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep);
@ -395,10 +396,10 @@ static int sam_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
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,
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);
static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
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);
static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
@ -1276,8 +1277,8 @@ static inline int sam_remisoced(struct sam_ed_s *ed)
*
*******************************************************************************/
static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_ed_s *ed,
uint32_t dirpid, uint32_t toggle,
static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist,
struct sam_ed_s *ed, uint32_t dirpid, uint32_t toggle,
volatile uint8_t *buffer, size_t buflen)
{
struct sam_gtd_s *td;
@ -1298,15 +1299,15 @@ static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_ed_s *ed,
arch_clean_dcache((uintptr_t)ed,
(uintptr_t)ed + sizeof(struct ohci_ed_s));
/* Get the tail ED for this root hub port */
/* Get the tail ED for this hub port */
tdtail = rhport->ep0.tail;
tdtail = eplist->tail;
/* Get physical addresses to support the DMA */
phytd = sam_physramaddr((uintptr_t)td);
phytail = sam_physramaddr((uintptr_t)tdtail);
phybuf = sam_physramaddr((uintptr_t)buffer);
phytd = sam_physramaddr((uintptr_t)td);
phytail = sam_physramaddr((uintptr_t)tdtail);
phybuf = sam_physramaddr((uintptr_t)buffer);
/* Initialize the allocated TD and link it before the common tail TD. */
@ -1421,7 +1422,7 @@ static int sam_ep0enqueue(struct sam_rhport_s *rhport)
*/
memset(edctrl, 0, sizeof(struct sam_ed_s));
(void)sam_ep0configure(&rhport->drvr, 0, 8);
(void)sam_ep0configure(&rhport->drvr, &rhport->ep0, 0, 8);
edctrl->hw.ctrl |= ED_CONTROL_K;
edctrl->eplist = &rhport->ep0;
@ -1626,10 +1627,9 @@ static int sam_wdhwait(struct sam_rhport_s *rhport, struct sam_ed_s *ed)
*
*******************************************************************************/
static int sam_ctrltd(struct sam_rhport_s *rhport, uint32_t dirpid,
uint8_t *buffer, size_t buflen)
static int sam_ctrltd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist,
uint32_t dirpid, uint8_t *buffer, size_t buflen)
{
struct sam_eplist_s *eplist;
struct sam_ed_s *edctrl;
uint32_t toggle;
uint32_t regval;
@ -1639,18 +1639,14 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, uint32_t dirpid,
* transfer.
*/
edctrl = rhport->ep0.ed;
edctrl = eplist->ed;
ret = sam_wdhwait(rhport, edctrl);
if (ret != OK)
{
usbhost_trace1(OHCI_TRACE1_DEVDISCONN, rhport->rhpndx + 1);
usbhost_trace1(OHCI_TRACE1_DEVDISCONN, rhport->hport.port + 1);
return ret;
}
/* Get the endpoint list structure for the ED */
eplist = &rhport->ep0;
/* Configure the toggle field in the TD */
if (dirpid == GTD_STATUS_DP_SETUP)
@ -1665,7 +1661,7 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, uint32_t dirpid,
/* Then enqueue the transfer */
edctrl->tdstatus = TD_CC_NOERROR;
ret = sam_enqueuetd(rhport, edctrl, dirpid, toggle, buffer, buflen);
ret = sam_enqueuetd(rhport, eplist, edctrl, dirpid, toggle, buffer, buflen);
if (ret == OK)
{
/* Set ControlListFilled. This bit is used to indicate whether there are
@ -1711,7 +1707,7 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, uint32_t dirpid,
}
else
{
usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, rhport->rhpndx + 1,
usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, rhport->hport.port + 1,
edctrl->tdstatus);
ret = -EIO;
}
@ -1799,8 +1795,16 @@ static void sam_rhsc_bottomhalf(void)
* when CCS == 1.
*/
rhport->lowspeed = (rhportst & OHCI_RHPORTST_LSDA) != 0;
usbhost_vtrace1(OHCI_VTRACE1_SPEED, rhport->lowspeed);
if ((rhportst & OHCI_RHPORTST_LSDA) != 0)
{
rhport->hport.speed = USB_SPEED_LOW;
}
else
{
rhport->hport.speed = USB_SPEED_FULL;
}
usbhost_vtrace1(OHCI_VTRACE1_SPEED, rhport->hport.speed);
}
/* Check if we are now disconnected */
@ -1812,8 +1816,8 @@ static void sam_rhsc_bottomhalf(void)
usbhost_vtrace2(OHCI_VTRACE2_DISCONNECTED,
rhpndx + 1, g_ohci.rhswait);
rhport->connected = false;
rhport->lowspeed = false;
rhport->connected = false;
rhport->hport.speed = USB_SPEED_FULL;
/* Are we bound to a class instance? */
@ -2166,7 +2170,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
{
/* No, return an error */
usbhost_vtrace1(OHCI_VTRACE1_ENUMDISCONN, rhport->rhpndx + 1);
usbhost_vtrace1(OHCI_VTRACE1_ENUMDISCONN, rhport->hport.port + 1);
return -ENODEV;
}
@ -2177,7 +2181,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
ret = sam_ep0enqueue(rhport);
if (ret < 0)
{
usbhost_trace2(OHCI_TRACE2_EP0ENQUEUE_FAILED, rhport->rhpndx + 1,
usbhost_trace2(OHCI_TRACE2_EP0ENQUEUE_FAILED, rhport->hport.port + 1,
-ret);
return ret;
}
@ -2212,7 +2216,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
*/
usbhost_vtrace2(OHCI_VTRACE2_CLASSENUM, rhpndx+1, rhpndx+1);
ret = usbhost_enumerate(&g_ohci.rhport[rhpndx].drvr, rhpndx+1, &rhport->class);
ret = usbhost_enumerate(&g_ohci.rhport[rhpndx].hport, &rhport->class);
if (ret < 0)
{
usbhost_trace2(OHCI_TRACE2_CLASSENUM_FAILED, rhpndx+1, -ret);
@ -2247,17 +2251,16 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
*
************************************************************************************/
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
uint16_t maxpacketsize)
static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
uint8_t funcaddr, uint16_t maxpacketsize)
{
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_eplist_s *ep0list = (struct sam_eplist_s *)ep0;
struct sam_ed_s *edctrl;
DEBUGASSERT(rhport &&
funcaddr >= 0 && funcaddr <= SAM_OHCI_NRHPORT &&
maxpacketsize < 2048);
DEBUGASSERT(rhport && maxpacketsize < 2048);
edctrl = rhport->ep0.ed;
edctrl = ep0list->ed;
/* We must have exclusive access to EP0 and the control list */
@ -2268,7 +2271,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
edctrl->hw.ctrl = (uint32_t)funcaddr << ED_CONTROL_FA_SHIFT |
(uint32_t)maxpacketsize << ED_CONTROL_MPS_SHIFT;
if (rhport->lowspeed)
if (rhport->hport.speed == USB_SPEED_LOW)
{
edctrl->hw.ctrl |= ED_CONTROL_S;
}
@ -2284,38 +2287,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
sam_givesem(&g_ohci.exclsem);
usbhost_vtrace2(OHCI_VTRACE2_EP0CONFIGURE,
rhport->rhpndx + 1, (uint16_t)edctrl->hw.ctrl);
return OK;
}
/************************************************************************************
* Name: sam_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 sam_getdevinfo(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_devinfo_s *devinfo)
{
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
DEBUGASSERT(drvr && devinfo);
devinfo->speed = rhport->lowspeed ? DEVINFO_SPEED_LOW : DEVINFO_SPEED_FULL;
rhport->hport.port + 1, (uint16_t)edctrl->hw.ctrl);
return OK;
}
@ -2346,6 +2318,7 @@ static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
{
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_eplist_s *eplist;
struct usbhost_hubport_s *hport;
struct sam_ed_s *ed;
struct sam_gtd_s *td;
uintptr_t physaddr;
@ -2355,7 +2328,10 @@ static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
* connected (because we need a valid low speed indication).
*/
DEBUGASSERT(rhport && epdesc && ep && rhport->connected);
DEBUGASSERT(rhport != NULL && epdesc != NULL && epdesc->hport != NULL);
DEBUGASSERT(ep != NULL && rhport->connected);
hport = epdesc->hport;
/* Allocate a container for the endpoint data */
@ -2400,7 +2376,8 @@ static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
/* Configure the endpoint descriptor. */
memset((void*)ed, 0, sizeof(struct sam_ed_s));
ed->hw.ctrl = (uint32_t)(epdesc->funcaddr) << ED_CONTROL_FA_SHIFT |
ed->hw.ctrl = (uint32_t)(hport->funcaddr) << ED_CONTROL_FA_SHIFT |
(uint32_t)(epdesc->addr) << ED_CONTROL_EN_SHIFT |
(uint32_t)(epdesc->mxpacketsize) << ED_CONTROL_MPS_SHIFT;
@ -2417,7 +2394,7 @@ static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
/* Check for a low-speed device */
if (rhport->lowspeed)
if (rhport->hport.speed == USB_SPEED_LOW)
{
ed->hw.ctrl |= ED_CONTROL_S;
}
@ -2745,10 +2722,11 @@ 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 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.
@ -2756,12 +2734,12 @@ static int sam_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
* in the request description. buffer must have been allocated using DRVR_ALLOC.
*
* NOTE: On an IN transaction, req and buffer may refer to the same allocated
* memory.
@ -2771,28 +2749,29 @@ static int sam_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 sam_ctrlin(FAR struct usbhost_driver_s *drvr,
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)
{
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_eplist_s *eplist = (struct sam_eplist_s *)ep0;
uint16_t len;
int ret;
DEBUGASSERT(rhport && req);
DEBUGASSERT(rhport != NULL && eplist != NULL && req != NULL);
#ifdef CONFIG_USBHOST_TRACE
usbhost_vtrace2(OHCI_VTRACE2_CTRLIN, rhport->rhpndx + 1, req->req);
usbhost_vtrace2(OHCI_VTRACE2_CTRLIN, rhport->hport.port + 1, req->req);
#else
uvdbg("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %02x%02x\n",
rhport->rhpndx + 1, req->type, req->req, req->value[1], req->value[0],
req->index[1], req->index[0], req->len[1], req->len[0]);
rhport->hport.port + 1, req->type, req->req, req->value[1],
req->value[0], req->index[1], req->index[0], req->len[1],
req->len[0]);
#endif
/* We must have exclusive access to EP0 and the control list */
@ -2800,17 +2779,18 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr,
sam_takesem(&g_ohci.exclsem);
len = sam_getle16(req->len);
ret = sam_ctrltd(rhport, GTD_STATUS_DP_SETUP, (uint8_t*)req, USB_SIZEOF_CTRLREQ);
ret = sam_ctrltd(rhport, eplist, GTD_STATUS_DP_SETUP, (uint8_t*)req,
USB_SIZEOF_CTRLREQ);
if (ret == OK)
{
if (len)
{
ret = sam_ctrltd(rhport, GTD_STATUS_DP_IN, buffer, len);
ret = sam_ctrltd(rhport, eplist, GTD_STATUS_DP_IN, buffer, len);
}
if (ret == OK)
{
ret = sam_ctrltd(rhport, GTD_STATUS_DP_OUT, NULL, 0);
ret = sam_ctrltd(rhport, eplist, GTD_STATUS_DP_OUT, NULL, 0);
}
}
@ -2823,22 +2803,24 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr,
return ret;
}
static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
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)
{
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_eplist_s *eplist = (struct sam_eplist_s *)ep0;
uint16_t len;
int ret;
DEBUGASSERT(rhport && req);
DEBUGASSERT(rhport != NULL && eplist != NULL && req != NULL);
#ifdef CONFIG_USBHOST_TRACE
usbhost_vtrace2(OHCI_VTRACE2_CTRLOUT, rhport->rhpndx + 1, req->req);
usbhost_vtrace2(OHCI_VTRACE2_CTRLOUT, rhport->hport.port + 1, req->req);
#else
uvdbg("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %02x%02x\n",
rhport->rhpndx + 1, req->type, req->req, req->value[1], req->value[0],
req->index[1], req->index[0], req->len[1], req->len[0]);
rhport->hport.port + 1, req->type, req->req, req->value[1],
req->value[0], req->index[1], req->index[0], req->len[1],
req->len[0]);
#endif
/* We must have exclusive access to EP0 and the control list */
@ -2846,17 +2828,19 @@ static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
sam_takesem(&g_ohci.exclsem);
len = sam_getle16(req->len);
ret = sam_ctrltd(rhport, GTD_STATUS_DP_SETUP, (uint8_t*)req, USB_SIZEOF_CTRLREQ);
ret = sam_ctrltd(rhport, eplist, GTD_STATUS_DP_SETUP, (uint8_t*)req,
USB_SIZEOF_CTRLREQ);
if (ret == OK)
{
if (len)
{
ret = sam_ctrltd(rhport, GTD_STATUS_DP_OUT, (uint8_t*)buffer, len);
ret = sam_ctrltd(rhport, eplist, GTD_STATUS_DP_OUT,
(uint8_t*)buffer, len);
}
if (ret == OK)
{
ret = sam_ctrltd(rhport, GTD_STATUS_DP_IN, NULL, 0);
ret = sam_ctrltd(rhport, eplist, GTD_STATUS_DP_IN, NULL, 0);
}
}
@ -2945,7 +2929,7 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
ret = sam_wdhwait(rhport, ed);
if (ret != OK)
{
usbhost_trace1(OHCI_TRACE1_DEVDISCONN, rhport->rhpndx + 1);
usbhost_trace1(OHCI_TRACE1_DEVDISCONN, rhport->hport.port + 1);
goto errout;
}
@ -2963,7 +2947,7 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
/* Then enqueue the transfer */
ed->tdstatus = TD_CC_NOERROR;
ret = sam_enqueuetd(rhport, ed, dirpid, GTD_STATUS_T_TOGGLE,
ret = sam_enqueuetd(rhport, eplist, ed, dirpid, GTD_STATUS_T_TOGGLE,
buffer, buflen);
if (ret == OK)
{
@ -3028,7 +3012,7 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
}
else
{
usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, rhport->rhpndx + 1,
usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, rhport->hport.port + 1,
ed->tdstatus);
ret = ed->tdstatus == TD_CC_STALL ? -EPERM : -EIO;
}
@ -3234,9 +3218,7 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
{
struct sam_rhport_s *rhport = &g_ohci.rhport[i];
rhport->rhpndx = i;
rhport->drvr.ep0configure = sam_ep0configure;
rhport->drvr.getdevinfo = sam_getdevinfo;
rhport->drvr.epalloc = sam_epalloc;
rhport->drvr.epfree = sam_epfree;
rhport->drvr.alloc = sam_alloc;
@ -3247,6 +3229,14 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
rhport->drvr.ctrlout = sam_ctrlout;
rhport->drvr.transfer = sam_transfer;
rhport->drvr.disconnect = sam_disconnect;
rhport->hport.drvr = &rhport->drvr;
#ifdef CONFIG_USBHOST_HUB
rhport->hport.parent = NULL;
#endif
rhport->hport.ep0 = &rhport->ep0;
rhport->hport.port = i;
rhport->hport.speed = USB_SPEED_FULL;
}
/* Wait 50MS then perform hardware reset */