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
+56 -11
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 # define lpc31_qh_dump(qh, bp, arg) OK
#endif #endif
static inline uint8_t lpc31_ehci_speed(uint8_t usbspeed);
static int lpc31_ioc_setup(struct lpc31_rhport_s *rhport, static int lpc31_ioc_setup(struct lpc31_rhport_s *rhport,
struct lpc31_epinfo_s *epinfo); struct lpc31_epinfo_s *epinfo);
static int lpc31_ioc_wait(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; 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 */ /* The head of the asynchronous queue */
static struct lpc31_qh_s g_asynchead __attribute__ ((aligned(32))); 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 #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 * 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; struct lpc31_qh_s *qh;
uint32_t rhpndx; uint32_t rhpndx;
uint32_t regval; uint32_t regval;
uint8_t hubaddr;
uint8_t hubport;
/* Allocate a new queue head structure */ /* 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) | regval = ((uint32_t)epinfo->devaddr << QH_EPCHAR_DEVADDR_SHIFT) |
((uint32_t)epinfo->epno << QH_EPCHAR_ENDPT_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 | QH_EPCHAR_DTC |
((uint32_t)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) | ((uint32_t)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) |
((uint32_t)8 << QH_EPCHAR_RL_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 * HUBADDR Hub Address Always 0 for now
* PORT Port number RH port index + 1 * PORT Port number RH port index + 1
* MULT High band width multiplier 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); 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); ((uint32_t)1 << QH_EPCAPS_MULT_SHIFT);
#ifndef CONFIG_USBHOST_INT_DISABLE #ifndef CONFIG_USBHOST_INT_DISABLE
@@ -3562,7 +3606,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn,
* repeat." * repeat."
*/ */
rhport->ep0.speed = USB_SPEED_LOW; hport->speed = USB_SPEED_LOW;
#if 0 /* The LPC31xx does not support a companion host controller */ #if 0 /* The LPC31xx does not support a companion host controller */
regval |= EHCI_PORTSC_OWNER; regval |= EHCI_PORTSC_OWNER;
@@ -3578,7 +3622,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn,
{ {
/* Assume full-speed for now */ /* Assume full-speed for now */
rhport->ep0.speed = USB_SPEED_FULL; hport->speed = USB_SPEED_FULL;
} }
/* Put the root hub port in reset. /* 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 */ /* 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) 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." * 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 */ #if 0 /* The LPC31xx does not support a companion host controller */
regval |= EHCI_PORTSC_OWNER; regval |= EHCI_PORTSC_OWNER;
@@ -3712,7 +3756,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn,
else else
{ {
DEBUGASSERT(rhport->ep0.speed == USB_SPEED_LOW); DEBUGASSERT(hport->speed == USB_SPEED_LOW);
DEBUGASSERT((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_LS); 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 */ /* Remember the new device address and max packet size */
epinfo->devaddr = funcaddr; epinfo->devaddr = funcaddr;
epinfo->speed = speed;
epinfo->maxpacket = maxpacketsize; epinfo->maxpacket = maxpacketsize;
lpc31_givesem(&g_ehci.exclsem); lpc31_givesem(&g_ehci.exclsem);
+54 -9
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 # define sam_qh_dump(qh, bp, arg) OK
#endif #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_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo);
static int sam_ioc_wait(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); 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; 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 */ /* The head of the asynchronous queue */
static struct sam_qh_s g_asynchead __attribute__ ((aligned(32))); 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 #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 * 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; struct sam_qh_s *qh;
uint32_t rhpndx; uint32_t rhpndx;
uint32_t regval; uint32_t regval;
uint8_t hubaddr;
uint8_t hubport;
/* Allocate a new queue head structure */ /* 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) | regval = ((uint32_t)epinfo->devaddr << QH_EPCHAR_DEVADDR_SHIFT) |
((uint32_t)epinfo->epno << QH_EPCHAR_ENDPT_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 | QH_EPCHAR_DTC |
((uint32_t)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) | ((uint32_t)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) |
((uint32_t)8 << QH_EPCHAR_RL_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 * HUBADDR Hub Address Always 0 for now
* PORT Port number RH port index + 1 * PORT Port number RH port index + 1
* MULT High band width multiplier 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); 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); ((uint32_t)1 << QH_EPCAPS_MULT_SHIFT);
#ifndef CONFIG_USBHOST_INT_DISABLE #ifndef CONFIG_USBHOST_INT_DISABLE
@@ -3402,7 +3446,7 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn,
* repeat." * repeat."
*/ */
rhport->ep0.speed = USB_SPEED_LOW; hport->speed = USB_SPEED_LOW;
regval |= EHCI_PORTSC_OWNER; regval |= EHCI_PORTSC_OWNER;
sam_putreg(regval, &HCOR->portsc[rhpndx]); 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 */ /* Assume full-speed for now */
rhport->ep0.speed = USB_SPEED_FULL; hport->speed = USB_SPEED_FULL;
} }
/* Put the root hub port in reset. /* 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 */ /* High speed device */
rhport->ep0.speed = USB_SPEED_HIGH; hport->speed = USB_SPEED_HIGH;
} }
else 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 */ /* Remember the new device address and max packet size */
epinfo->devaddr = funcaddr; epinfo->devaddr = funcaddr;
epinfo->speed = speed;
epinfo->maxpacket = maxpacketsize; epinfo->maxpacket = maxpacketsize;
sam_givesem(&g_ehci.exclsem); sam_givesem(&g_ehci.exclsem);
+1 -2
View File
@@ -51,13 +51,12 @@
********************************************************************************************/ ********************************************************************************************/
/* General definitions **********************************************************************/ /* General definitions **********************************************************************/
/* Endpoint speed values as used in endpoint characteristics field. NOTE: These values /* 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_FULL_SPEED (0) /* Full-Speed (12Mbs) */
#define EHCI_LOW_SPEED (1) /* Low-Speed (1.5Mbs) */ #define EHCI_LOW_SPEED (1) /* Low-Speed (1.5Mbs) */
#define EHCI_HIGH_SPEED (2) /* High-Speed (480 Mb/s) */ #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_IN (1) /* Direction IN: Peripheral to host */
#define EHCI_DIR_OUT (0) /* Direction OUT: Host to peripheral */ #define EHCI_DIR_OUT (0) /* Direction OUT: Host to peripheral */