EHCI HUB: Fix some issues related to speed and device addresses

This commit is contained in:
Gregory Nutt 2015-04-28 09:43:06 -06:00
parent 08b35f042b
commit 5c76c53909
3 changed files with 115 additions and 26 deletions

View File

@ -465,6 +465,7 @@ static int lpc31_qh_dump(struct lpc31_qh_s *qh, uint32_t **bp, void *arg);
# define lpc31_qh_dump(qh, bp, arg) OK
#endif
static inline uint8_t lpc31_ehci_speed(uint8_t usbspeed);
static int lpc31_ioc_setup(struct lpc31_rhport_s *rhport,
struct lpc31_epinfo_s *epinfo);
static int lpc31_ioc_wait(struct lpc31_epinfo_s *epinfo);
@ -565,6 +566,13 @@ static struct lpc31_ehci_s g_ehci;
static struct usbhost_connection_s g_ehciconn;
/* Maps USB chapter 9 speed to EHCI speed */
static const uint8_t g_ehci_speed[4] =
{
0, EHCI_LOW_SPEED, EHCI_FULL_SPEED, EHCI_HIGH_SPEED
};
/* The head of the asynchronous queue */
static struct lpc31_qh_s g_asynchead __attribute__ ((aligned(32)));
@ -1528,6 +1536,21 @@ static int lpc31_qh_dump(struct lpc31_qh_s *qh, uint32_t **bp, void *arg)
}
#endif
/*******************************************************************************
* Name: lpc31_ehci_speed
*
* Description:
* Map a speed enumeration value per Chapter 9 of the USB specification to the
* speed enumeration required in the EHCI queue head.
*
*******************************************************************************/
static inline uint8_t lpc31_ehci_speed(uint8_t usbspeed)
{
DEBUGASSERT(usbspeed >= USB_SPEED_LOW && usbspeed <= USB_SPEED_HIGH);
return g_ehci_speed[usbspeed];
}
/*******************************************************************************
* Name: lpc31_ioc_setup
*
@ -1654,6 +1677,8 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport,
struct lpc31_qh_s *qh;
uint32_t rhpndx;
uint32_t regval;
uint8_t hubaddr;
uint8_t hubport;
/* Allocate a new queue head structure */
@ -1684,7 +1709,7 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport,
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) |
((uint32_t)lpc31_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);
@ -1714,14 +1739,33 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport,
* HUBADDR Hub Address Always 0 for now
* PORT Port number RH port index + 1
* MULT High band width multiplier 1
*
* REVISIT: Future HUB support will require the HUB port number
* and HUB device address to be included here.
*/
rhpndx = RHPNDX(rhport);
regval = ((uint32_t)0 << QH_EPCAPS_HUBADDR_SHIFT) |
((uint32_t)(rhpndx + 1) << QH_EPCAPS_PORT_SHIFT) |
#ifdef CONFIG_USBHOST_HUB
/* REVISIT: Future HUB support will require the HUB port number
* and HUB device address to be included here:
*
* - The HUB device address is the USB device address of the USB 2.0 Hub
* below which a full- or low-speed device is attached.
* - The HUB port number is the port number on the above USB 2.0 Hub
*
* These fields are used in the split-transaction protocol. The kludge
* below should work for hubs connected directly to a root hub port,
* but would not work for devices connected to downstream hubs.
*/
#warning Missing logic
hubaddr = rhport->ep0.devaddr;
hubport = rhpndx + 1;
#else
hubaddr = rhport->ep0.devaddr;
hubport = rhpndx + 1;
#endif
regval = ((uint32_t)hubaddr << QH_EPCAPS_HUBADDR_SHIFT) |
((uint32_t)hubport << QH_EPCAPS_PORT_SHIFT) |
((uint32_t)1 << QH_EPCAPS_MULT_SHIFT);
#ifndef CONFIG_USBHOST_INT_DISABLE
@ -3562,7 +3606,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn,
* repeat."
*/
rhport->ep0.speed = USB_SPEED_LOW;
hport->speed = USB_SPEED_LOW;
#if 0 /* The LPC31xx does not support a companion host controller */
regval |= EHCI_PORTSC_OWNER;
@ -3578,7 +3622,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn,
{
/* Assume full-speed for now */
rhport->ep0.speed = USB_SPEED_FULL;
hport->speed = USB_SPEED_FULL;
}
/* Put the root hub port in reset.
@ -3675,7 +3719,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn,
{
/* High speed device */
rhport->ep0.speed = USB_SPEED_HIGH;
hport->speed = USB_SPEED_HIGH;
}
else if ((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_FS)
{
@ -3695,7 +3739,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn,
* repeat."
*/
DEBUGASSERT(rhport->ep0.speed == USB_SPEED_FULL);
DEBUGASSERT(hport->speed == USB_SPEED_FULL);
#if 0 /* The LPC31xx does not support a companion host controller */
regval |= EHCI_PORTSC_OWNER;
@ -3712,7 +3756,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn,
else
{
DEBUGASSERT(rhport->ep0.speed == USB_SPEED_LOW);
DEBUGASSERT(hport->speed == USB_SPEED_LOW);
DEBUGASSERT((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_LS);
}
@ -3794,6 +3838,7 @@ static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep
/* Remember the new device address and max packet size */
epinfo->devaddr = funcaddr;
epinfo->speed = speed;
epinfo->maxpacket = maxpacketsize;
lpc31_givesem(&g_ehci.exclsem);

View File

@ -345,6 +345,7 @@ static int sam_qh_dump(struct sam_qh_s *qh, uint32_t **bp, void *arg);
# define sam_qh_dump(qh, bp, arg) OK
#endif
static inline uint8_t sam_ehci_speed(uint8_t usbspeed);
static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo);
static int sam_ioc_wait(struct sam_epinfo_s *epinfo);
static void sam_qh_enqueue(struct sam_qh_s *qhead, struct sam_qh_s *qh);
@ -442,6 +443,13 @@ static struct sam_ehci_s g_ehci;
static struct usbhost_connection_s g_ehciconn;
/* Maps USB chapter 9 speed to EHCI speed */
static const uint8_t g_ehci_speed[4] =
{
0, EHCI_LOW_SPEED, EHCI_FULL_SPEED, EHCI_HIGH_SPEED
};
/* The head of the asynchronous queue */
static struct sam_qh_s g_asynchead __attribute__ ((aligned(32)));
@ -1343,6 +1351,21 @@ static int sam_qh_dump(struct sam_qh_s *qh, uint32_t **bp, void *arg)
}
#endif
/*******************************************************************************
* Name: sam_ehci_speed
*
* Description:
* Map a speed enumeration value per Chapter 9 of the USB specification to the
* speed enumeration required in the EHCI queue head.
*
*******************************************************************************/
static inline uint8_t sam_ehci_speed(uint8_t usbspeed)
{
DEBUGASSERT(usbspeed >= USB_SPEED_LOW && usbspeed <= USB_SPEED_HIGH);
return g_ehci_speed[usbspeed];
}
/*******************************************************************************
* Name: sam_ioc_setup
*
@ -1469,6 +1492,8 @@ static struct sam_qh_s *sam_qh_create(struct sam_rhport_s *rhport,
struct sam_qh_s *qh;
uint32_t rhpndx;
uint32_t regval;
uint8_t hubaddr;
uint8_t hubport;
/* Allocate a new queue head structure */
@ -1499,7 +1524,7 @@ static struct sam_qh_s *sam_qh_create(struct sam_rhport_s *rhport,
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) |
((uint32_t)sam_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);
@ -1529,14 +1554,33 @@ static struct sam_qh_s *sam_qh_create(struct sam_rhport_s *rhport,
* HUBADDR Hub Address Always 0 for now
* PORT Port number RH port index + 1
* MULT High band width multiplier 1
*
* REVISIT: Future HUB support will require the HUB port number
* and HUB device address to be included here.
*/
rhpndx = RHPNDX(rhport);
regval = ((uint32_t)0 << QH_EPCAPS_HUBADDR_SHIFT) |
((uint32_t)(rhpndx + 1) << QH_EPCAPS_PORT_SHIFT) |
#ifdef CONFIG_USBHOST_HUB
/* REVISIT: Future HUB support will require the HUB port number
* and HUB device address to be included here:
*
* - The HUB device address is the USB device address of the USB 2.0 Hub
* below which a full- or low-speed device is attached.
* - The HUB port number is the port number on the above USB 2.0 Hub
*
* These fields are used in the split-transaction protocol. The kludge
* below should work for hubs connected directly to a root hub port,
* but would not work for devices connected to downstream hubs.
*/
#warning Missing logic
hubaddr = rhport->ep0.devaddr;
hubport = rhpndx + 1;
#else
hubaddr = rhport->ep0.devaddr;
hubport = rhpndx + 1;
#endif
regval = ((uint32_t)hubaddr << QH_EPCAPS_HUBADDR_SHIFT) |
((uint32_t)hubport << QH_EPCAPS_PORT_SHIFT) |
((uint32_t)1 << QH_EPCAPS_MULT_SHIFT);
#ifndef CONFIG_USBHOST_INT_DISABLE
@ -3402,7 +3446,7 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn,
* repeat."
*/
rhport->ep0.speed = USB_SPEED_LOW;
hport->speed = USB_SPEED_LOW;
regval |= EHCI_PORTSC_OWNER;
sam_putreg(regval, &HCOR->portsc[rhpndx]);
@ -3425,7 +3469,7 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn,
{
/* Assume full-speed for now */
rhport->ep0.speed = USB_SPEED_FULL;
hport->speed = USB_SPEED_FULL;
}
/* Put the root hub port in reset.
@ -3504,7 +3548,7 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn,
{
/* High speed device */
rhport->ep0.speed = USB_SPEED_HIGH;
hport->speed = USB_SPEED_HIGH;
}
else
{
@ -3621,6 +3665,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
/* Remember the new device address and max packet size */
epinfo->devaddr = funcaddr;
epinfo->speed = speed;
epinfo->maxpacket = maxpacketsize;
sam_givesem(&g_ehci.exclsem);

View File

@ -51,13 +51,12 @@
********************************************************************************************/
/* General definitions **********************************************************************/
/* Endpoint speed values as used in endpoint characteristics field. NOTE: These values
* are assumed to equal to the SPEED definitions in usb.h (minus 1).
* are *NOT* the same as the SPEED definitions in usb.h.
*/
#define EHCI_FULL_SPEED (0) /* Full-Speed (12Mbs) */
#define EHCI_LOW_SPEED (1) /* Low-Speed (1.5Mbs) */
#define EHCI_HIGH_SPEED (2) /* High-Speed (480 Mb/s) */
#define EHCI_SPEED(s) ((s)-1)
#define EHCI_DIR_IN (1) /* Direction IN: Peripheral to host */
#define EHCI_DIR_OUT (0) /* Direction OUT: Host to peripheral */