Commit 7f59d16a50ca7e6d417c9408b91ab2f97eff0a36
Committed by
Marek Vasut
1 parent
b335fe6810
Exists in
v2017.01-smarct4x
and in
34 other branches
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 |