|
@@ -1214,6 +1214,7 @@ static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe,
|
|
|
|
|
|
struct int_queue {
|
|
|
int elementsize;
|
|
|
+ unsigned long pipe;
|
|
|
struct QH *first;
|
|
|
struct QH *current;
|
|
|
struct QH *last;
|
|
@@ -1269,7 +1270,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
|
|
|
{
|
|
|
struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
|
|
|
struct int_queue *result = NULL;
|
|
|
- int i;
|
|
|
+ uint32_t i, toggle;
|
|
|
|
|
|
/*
|
|
|
* Interrupt transfers requiring several transactions are not supported
|
|
@@ -1309,6 +1310,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
|
|
|
goto fail1;
|
|
|
}
|
|
|
result->elementsize = elementsize;
|
|
|
+ result->pipe = pipe;
|
|
|
result->first = memalign(USB_DMA_MINALIGN,
|
|
|
sizeof(struct QH) * queuesize);
|
|
|
if (!result->first) {
|
|
@@ -1326,6 +1328,8 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
|
|
|
memset(result->first, 0, sizeof(struct QH) * queuesize);
|
|
|
memset(result->tds, 0, sizeof(struct qTD) * queuesize);
|
|
|
|
|
|
+ toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
|
|
|
+
|
|
|
for (i = 0; i < queuesize; i++) {
|
|
|
struct QH *qh = result->first + i;
|
|
|
struct qTD *td = result->tds + i;
|
|
@@ -1357,7 +1361,9 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
|
|
|
td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
|
|
|
debug("communication direction is '%s'\n",
|
|
|
usb_pipein(pipe) ? "in" : "out");
|
|
|
- td->qt_token = cpu_to_hc32((elementsize << 16) |
|
|
|
+ td->qt_token = cpu_to_hc32(
|
|
|
+ QT_TOKEN_DT(toggle) |
|
|
|
+ (elementsize << 16) |
|
|
|
((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */
|
|
|
0x80); /* active */
|
|
|
td->qt_buffer[0] =
|
|
@@ -1372,6 +1378,7 @@ static struct int_queue *_ehci_create_int_queue(struct usb_device *dev,
|
|
|
cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff);
|
|
|
|
|
|
*buf = buffer + i * elementsize;
|
|
|
+ toggle ^= 1;
|
|
|
}
|
|
|
|
|
|
flush_dcache_range((unsigned long)buffer,
|
|
@@ -1426,6 +1433,8 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
|
|
|
{
|
|
|
struct QH *cur = queue->current;
|
|
|
struct qTD *cur_td;
|
|
|
+ uint32_t token, toggle;
|
|
|
+ unsigned long pipe = queue->pipe;
|
|
|
|
|
|
/* depleted queue */
|
|
|
if (cur == NULL) {
|
|
@@ -1436,12 +1445,15 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
|
|
|
cur_td = &queue->tds[queue->current - queue->first];
|
|
|
invalidate_dcache_range((unsigned long)cur_td,
|
|
|
ALIGN_END_ADDR(struct qTD, cur_td, 1));
|
|
|
- if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) &
|
|
|
- QT_TOKEN_STATUS_ACTIVE) {
|
|
|
- debug("Exit poll_int_queue with no completed intr transfer. token is %x\n",
|
|
|
- hc32_to_cpu(cur_td->qt_token));
|
|
|
+ token = hc32_to_cpu(cur_td->qt_token);
|
|
|
+ if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) {
|
|
|
+ debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", token);
|
|
|
return NULL;
|
|
|
}
|
|
|
+
|
|
|
+ toggle = QT_TOKEN_GET_DT(token);
|
|
|
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle);
|
|
|
+
|
|
|
if (!(cur->qh_link & QH_LINK_TERMINATE))
|
|
|
queue->current++;
|
|
|
else
|
|
@@ -1452,7 +1464,7 @@ static void *_ehci_poll_int_queue(struct usb_device *dev,
|
|
|
queue->elementsize));
|
|
|
|
|
|
debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
|
|
|
- hc32_to_cpu(cur_td->qt_token), cur, queue->first);
|
|
|
+ token, cur, queue->first);
|
|
|
return cur->buffer;
|
|
|
}
|
|
|
|