Commit 7f59d16a50ca7e6d417c9408b91ab2f97eff0a36

Authored by Hans de Goede
Committed by Marek Vasut
1 parent b335fe6810

usb: ehci: Properly deal with data toggle for interrupt endpoints

Without this we loose every other interrupt packet. We never noticed this
because with keyboards the packets which we were loosing would normally
be key release packets.

But now that we do keyrepeat in software instead of relying on the hid
idle functionality, missing a release will result in key repeat triggering.

This commit fixes this.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Showing 1 changed file with 19 additions and 7 deletions Side-by-side Diff

drivers/usb/host/ehci-hcd.c
... ... @@ -1214,6 +1214,7 @@
1214 1214  
1215 1215 struct int_queue {
1216 1216 int elementsize;
  1217 + unsigned long pipe;
1217 1218 struct QH *first;
1218 1219 struct QH *current;
1219 1220 struct QH *last;
... ... @@ -1269,7 +1270,7 @@
1269 1270 {
1270 1271 struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
1271 1272 struct int_queue *result = NULL;
1272   - int i;
  1273 + uint32_t i, toggle;
1273 1274  
1274 1275 /*
1275 1276 * Interrupt transfers requiring several transactions are not supported
... ... @@ -1309,6 +1310,7 @@
1309 1310 goto fail1;
1310 1311 }
1311 1312 result->elementsize = elementsize;
  1313 + result->pipe = pipe;
1312 1314 result->first = memalign(USB_DMA_MINALIGN,
1313 1315 sizeof(struct QH) * queuesize);
1314 1316 if (!result->first) {
... ... @@ -1326,6 +1328,8 @@
1326 1328 memset(result->first, 0, sizeof(struct QH) * queuesize);
1327 1329 memset(result->tds, 0, sizeof(struct qTD) * queuesize);
1328 1330  
  1331 + toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
  1332 +
1329 1333 for (i = 0; i < queuesize; i++) {
1330 1334 struct QH *qh = result->first + i;
1331 1335 struct qTD *td = result->tds + i;
... ... @@ -1357,7 +1361,9 @@
1357 1361 td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
1358 1362 debug("communication direction is '%s'\n",
1359 1363 usb_pipein(pipe) ? "in" : "out");
1360   - td->qt_token = cpu_to_hc32((elementsize << 16) |
  1364 + td->qt_token = cpu_to_hc32(
  1365 + QT_TOKEN_DT(toggle) |
  1366 + (elementsize << 16) |
1361 1367 ((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */
1362 1368 0x80); /* active */
1363 1369 td->qt_buffer[0] =
... ... @@ -1372,6 +1378,7 @@
1372 1378 cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff);
1373 1379  
1374 1380 *buf = buffer + i * elementsize;
  1381 + toggle ^= 1;
1375 1382 }
1376 1383  
1377 1384 flush_dcache_range((unsigned long)buffer,
... ... @@ -1426,6 +1433,8 @@
1426 1433 {
1427 1434 struct QH *cur = queue->current;
1428 1435 struct qTD *cur_td;
  1436 + uint32_t token, toggle;
  1437 + unsigned long pipe = queue->pipe;
1429 1438  
1430 1439 /* depleted queue */
1431 1440 if (cur == NULL) {
1432 1441  
... ... @@ -1436,12 +1445,15 @@
1436 1445 cur_td = &queue->tds[queue->current - queue->first];
1437 1446 invalidate_dcache_range((unsigned long)cur_td,
1438 1447 ALIGN_END_ADDR(struct qTD, cur_td, 1));
1439   - if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) &
1440   - QT_TOKEN_STATUS_ACTIVE) {
1441   - debug("Exit poll_int_queue with no completed intr transfer. token is %x\n",
1442   - hc32_to_cpu(cur_td->qt_token));
  1448 + token = hc32_to_cpu(cur_td->qt_token);
  1449 + if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) {
  1450 + debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", token);
1443 1451 return NULL;
1444 1452 }
  1453 +
  1454 + toggle = QT_TOKEN_GET_DT(token);
  1455 + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle);
  1456 +
1445 1457 if (!(cur->qh_link & QH_LINK_TERMINATE))
1446 1458 queue->current++;
1447 1459 else
... ... @@ -1452,7 +1464,7 @@
1452 1464 queue->elementsize));
1453 1465  
1454 1466 debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n",
1455   - hc32_to_cpu(cur_td->qt_token), cur, queue->first);
  1467 + token, cur, queue->first);
1456 1468 return cur->buffer;
1457 1469 }
1458 1470