assert ( xfer->len <= EHCI_LEN_MASK );
assert ( EHCI_FL_TOGGLE == EHCI_LEN_TOGGLE );
desc->len = cpu_to_le16 ( xfer->len | toggle );
- desc->flags = xfer->flags;
+ desc->flags = ( xfer->flags | EHCI_FL_CERR_MAX );
/* Copy data to immediate data buffer (if requested) */
data = xfer->data;
chr |= EHCI_CHR_TOGGLE;
/* Determine endpoint speed */
- switch ( usb->port->speed ) {
- case USB_SPEED_HIGH :
+ if ( usb->port->speed == USB_SPEED_HIGH ) {
chr |= EHCI_CHR_EPS_HIGH;
- break;
- case USB_SPEED_FULL :
- chr |= EHCI_CHR_EPS_FULL;
- break;
- default:
- assert ( usb->port->speed == USB_SPEED_LOW );
- chr |= EHCI_CHR_EPS_LOW;
+ } else {
+ if ( usb->port->speed == USB_SPEED_FULL ) {
+ chr |= EHCI_CHR_EPS_FULL;
+ } else {
+ chr |= EHCI_CHR_EPS_LOW;
+ }
if ( attr == USB_ENDPOINT_ATTR_CONTROL )
chr |= EHCI_CHR_CONTROL;
- break;
}
return chr;
* @ret cap Endpoint capabilities
*/
static uint32_t ehci_endpoint_capabilities ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ struct usb_port *tt = usb_transaction_translator ( usb );
unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
uint32_t cap;
unsigned int i;
}
}
+ /* Set transaction translator hub address and port, if applicable */
+ if ( tt ) {
+ assert ( tt->hub->usb );
+ cap |= ( EHCI_CAP_TT_HUB ( tt->hub->usb->address ) |
+ EHCI_CAP_TT_PORT ( tt->address ) );
+ if ( attr == USB_ENDPOINT_ATTR_INTERRUPT )
+ cap |= EHCI_CAP_SPLIT_SCHED_DEFAULT;
+ }
+
return cap;
}
/** SETUP token */
#define EHCI_FL_PID_SETUP EHCI_FL_PID ( 2 )
+/** Error counter */
+#define EHCI_FL_CERR( count ) ( (count) << 2 )
+
+/** Error counter maximum value */
+#define EHCI_FL_CERR_MAX EHCI_FL_CERR ( 3 )
+
/** Interrupt on completion */
#define EHCI_FL_IOC 0x80
/** Interrupt schedule mask */
#define EHCI_CAP_INTR_SCHED( uframe ) ( 1 << ( (uframe) + 0 ) )
+/** Split completion schedule mask */
+#define EHCI_CAP_SPLIT_SCHED( uframe ) ( 1 << ( (uframe) + 8 ) )
+
+/** Default split completion schedule mask
+ *
+ * We schedule all split starts in microframe 0, on the assumption
+ * that we will never have to deal with more than sixteen actively
+ * interrupting devices via the same transaction translator. We
+ * schedule split completions for all remaining microframes after
+ * microframe 1 (in which the low-speed or full-speed transaction is
+ * assumed to execute). This is a very crude approximation designed
+ * to avoid the need for calculating exactly when low-speed and
+ * full-speed transactions will execute. Since we only ever deal with
+ * interrupt endpoints (rather than isochronous endpoints), the volume
+ * of periodic traffic is extremely low, and this approximation should
+ * remain valid.
+ */
+#define EHCI_CAP_SPLIT_SCHED_DEFAULT \
+ ( EHCI_CAP_SPLIT_SCHED ( 2 ) | EHCI_CAP_SPLIT_SCHED ( 3 ) | \
+ EHCI_CAP_SPLIT_SCHED ( 4 ) | EHCI_CAP_SPLIT_SCHED ( 5 ) | \
+ EHCI_CAP_SPLIT_SCHED ( 6 ) | EHCI_CAP_SPLIT_SCHED ( 7 ) )
+
+/** Transaction translator hub address */
+#define EHCI_CAP_TT_HUB( address ) ( (address) << 16 )
+
+/** Transaction translator port number */
+#define EHCI_CAP_TT_PORT( port ) ( (port) << 23 )
+
/** High-bandwidth pipe multiplier */
#define EHCI_CAP_MULT( mult ) ( (mult) << 30 )