PERFORCE change 118671 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Mon Apr 23 18:24:13 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=118671
Change 118671 by hselasky at hselasky_mini_itx on 2007/04/23 18:23:20
Fix a data-toggle bug in the EHCI driver.
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/ehci.c#27 edit
.. //depot/projects/usb/src/sys/dev/usb/ehci.h#11 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/ehci.c#27 (text+ko) ====
@@ -1047,6 +1047,8 @@
u_int32_t status = 0;
u_int32_t actlen = 0;
u_int16_t len = 0;
+ u_int16_t last_len = 0;
+ u_int8_t last_toggle = 0;
ehci_qtd_t *td = xfer->td_transfer_first;
DPRINTFN(12, ("xfer=%p pipe=%p transfer done\n",
@@ -1069,12 +1071,6 @@
usbd_page_dma_enter(td->page);
if (temp & EHCI_QTD_ACTIVE) {
-
- /* if there are left over TDs
- * the toggle needs to be updated
- */
- xfer->pipe->toggle_next =
- (temp & EHCI_QTD_SET_TOGGLE(1)) ? 1 : 0;
break;
}
@@ -1082,10 +1078,24 @@
len = EHCI_QTD_GET_BYTES(status);
+ /* The status length should always be
+ * less than or equal to the setup
+ * length!
+ */
if (len <= td->len) {
- actlen += td->len - len;
+ last_len = td->len - len;
+ actlen += last_len;
+ } else {
+ /* should not happen */
+ DPRINTFN(0, ("Invalid status length, "
+ "0x%04x/0x%04x bytes\n", len, td->len));
+ last_len = 0;
}
+ /* Make a copy of the data toggle */
+ last_toggle = td->toggle_curr;
+
+ /* Check if this is the last transfer */
if (((void *)td) == xfer->td_transfer_last) {
if (len == 0) {
/* halt is ok if descriptor is last,
@@ -1098,13 +1108,16 @@
}
}
- if (len) {
- /* update toggle in case of
- * a short transfer
- */
- xfer->pipe->toggle_next ^= (len / xfer->max_packet_size) & 1;
+ /* update data toggle */
+
+ if ((last_len == 0) ||
+ (((last_len + xfer->max_packet_size - 1) /
+ xfer->max_packet_size) & 1)) {
+ last_toggle = !last_toggle;
}
+ xfer->pipe->toggle_next = last_toggle;
+
DPRINTFN(10, ("actlen=%d\n", actlen));
xfer->actlen = actlen;
@@ -1570,6 +1583,7 @@
td->qtd_buffer[1] =
htole32(buf_res.physaddr & (~0xFFF));
td->qtd_buffer_hi[1] = 0;
+ td->toggle_curr = 0;
td->len = sizeof(usb_device_request_t);
len -= sizeof(usb_device_request_t);
@@ -1664,14 +1678,15 @@
htole32(buf_res.physaddr & (~0xFFF));
td->qtd_buffer_hi[1] = 0;
+ td->toggle_curr = xfer->pipe->toggle_next;
td->len = average;
/* adjust the toggle based on the
* number of packets in this qtd
*/
- if((((average + xfer->max_packet_size - 1) /
- xfer->max_packet_size) & 1) ||
- (!average))
+ if ((average == 0) ||
+ (((average + xfer->max_packet_size - 1) /
+ xfer->max_packet_size) & 1))
{
xfer->pipe->toggle_next =
xfer->pipe->toggle_next ? 0 : 1;
==== //depot/projects/usb/src/sys/dev/usb/ehci.h#11 (text+ko) ====
@@ -319,6 +319,8 @@
struct usbd_page *page;
uint32_t qtd_self;
uint16_t len;
+ uint8_t toggle_curr;
+ uint8_t unused;
} __aligned(EHCI_QTD_ALIGN) ehci_qtd_t;
/* Queue Head */
More information about the p4-projects
mailing list