diff options
| author | Pavel Rojtberg <rojtberg@gmail.com> | 2015-12-09 16:30:34 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2016-01-04 17:35:06 -0500 |
| commit | 4220f7db1e424f2a086ad41217b5770cc9f003a9 (patch) | |
| tree | 73366f1fda60c39819b5e8047ad6c51017999c47 /drivers/input/joystick | |
| parent | 2a6d7527b35cf987260800807e328d167aef22ac (diff) | |
Input: xpad - workaround dead irq_out after suspend/ resume
The irq_out urb is dead after suspend/ resume on my x360 wr pad. (also
reproduced by Zachary Lund [0]) Work around this by implementing
suspend, resume, and reset_resume callbacks and properly shutting down
URBs on suspend and restarting them on resume.
[0]: https://github.com/paroj/xpad/issues/6
Signed-off-by: Pavel Rojtberg <rojtberg@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/joystick')
| -rw-r--r-- | drivers/input/joystick/xpad.c | 175 |
1 files changed, 137 insertions, 38 deletions
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index aa6586043a6c..fa2612c9799c 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
| @@ -82,6 +82,7 @@ | |||
| 82 | #include <linux/stat.h> | 82 | #include <linux/stat.h> |
| 83 | #include <linux/module.h> | 83 | #include <linux/module.h> |
| 84 | #include <linux/usb/input.h> | 84 | #include <linux/usb/input.h> |
| 85 | #include <linux/usb/quirks.h> | ||
| 85 | 86 | ||
| 86 | #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" | 87 | #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" |
| 87 | #define DRIVER_DESC "X-Box pad driver" | 88 | #define DRIVER_DESC "X-Box pad driver" |
| @@ -346,9 +347,10 @@ struct usb_xpad { | |||
| 346 | dma_addr_t idata_dma; | 347 | dma_addr_t idata_dma; |
| 347 | 348 | ||
| 348 | struct urb *irq_out; /* urb for interrupt out report */ | 349 | struct urb *irq_out; /* urb for interrupt out report */ |
| 350 | struct usb_anchor irq_out_anchor; | ||
| 349 | bool irq_out_active; /* we must not use an active URB */ | 351 | bool irq_out_active; /* we must not use an active URB */ |
| 350 | unsigned char *odata; /* output data */ | ||
| 351 | u8 odata_serial; /* serial number for xbox one protocol */ | 352 | u8 odata_serial; /* serial number for xbox one protocol */ |
| 353 | unsigned char *odata; /* output data */ | ||
| 352 | dma_addr_t odata_dma; | 354 | dma_addr_t odata_dma; |
| 353 | spinlock_t odata_lock; | 355 | spinlock_t odata_lock; |
| 354 | 356 | ||
| @@ -764,11 +766,13 @@ static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad) | |||
| 764 | int error; | 766 | int error; |
| 765 | 767 | ||
| 766 | if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) { | 768 | if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) { |
| 769 | usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor); | ||
| 767 | error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC); | 770 | error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC); |
| 768 | if (error) { | 771 | if (error) { |
| 769 | dev_err(&xpad->intf->dev, | 772 | dev_err(&xpad->intf->dev, |
| 770 | "%s - usb_submit_urb failed with result %d\n", | 773 | "%s - usb_submit_urb failed with result %d\n", |
| 771 | __func__, error); | 774 | __func__, error); |
| 775 | usb_unanchor_urb(xpad->irq_out); | ||
| 772 | return -EIO; | 776 | return -EIO; |
| 773 | } | 777 | } |
| 774 | 778 | ||
| @@ -811,11 +815,13 @@ static void xpad_irq_out(struct urb *urb) | |||
| 811 | } | 815 | } |
| 812 | 816 | ||
| 813 | if (xpad->irq_out_active) { | 817 | if (xpad->irq_out_active) { |
| 818 | usb_anchor_urb(urb, &xpad->irq_out_anchor); | ||
| 814 | error = usb_submit_urb(urb, GFP_ATOMIC); | 819 | error = usb_submit_urb(urb, GFP_ATOMIC); |
| 815 | if (error) { | 820 | if (error) { |
| 816 | dev_err(dev, | 821 | dev_err(dev, |
| 817 | "%s - usb_submit_urb failed with result %d\n", | 822 | "%s - usb_submit_urb failed with result %d\n", |
| 818 | __func__, error); | 823 | __func__, error); |
| 824 | usb_unanchor_urb(urb); | ||
| 819 | xpad->irq_out_active = false; | 825 | xpad->irq_out_active = false; |
| 820 | } | 826 | } |
| 821 | } | 827 | } |
| @@ -832,6 +838,8 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) | |||
| 832 | if (xpad->xtype == XTYPE_UNKNOWN) | 838 | if (xpad->xtype == XTYPE_UNKNOWN) |
| 833 | return 0; | 839 | return 0; |
| 834 | 840 | ||
| 841 | init_usb_anchor(&xpad->irq_out_anchor); | ||
| 842 | |||
| 835 | xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN, | 843 | xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN, |
| 836 | GFP_KERNEL, &xpad->odata_dma); | 844 | GFP_KERNEL, &xpad->odata_dma); |
| 837 | if (!xpad->odata) { | 845 | if (!xpad->odata) { |
| @@ -866,8 +874,14 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) | |||
| 866 | 874 | ||
| 867 | static void xpad_stop_output(struct usb_xpad *xpad) | 875 | static void xpad_stop_output(struct usb_xpad *xpad) |
| 868 | { | 876 | { |
| 869 | if (xpad->xtype != XTYPE_UNKNOWN) | 877 | if (xpad->xtype != XTYPE_UNKNOWN) { |
| 870 | usb_kill_urb(xpad->irq_out); | 878 | if (!usb_wait_anchor_empty_timeout(&xpad->irq_out_anchor, |
| 879 | 5000)) { | ||
| 880 | dev_warn(&xpad->intf->dev, | ||
| 881 | "timed out waiting for output URB to complete, killing\n"); | ||
| 882 | usb_kill_anchored_urbs(&xpad->irq_out_anchor); | ||
| 883 | } | ||
| 884 | } | ||
| 871 | } | 885 | } |
| 872 | 886 | ||
| 873 | static void xpad_deinit_output(struct usb_xpad *xpad) | 887 | static void xpad_deinit_output(struct usb_xpad *xpad) |
| @@ -1196,32 +1210,73 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) { } | |||
| 1196 | static void xpad_identify_controller(struct usb_xpad *xpad) { } | 1210 | static void xpad_identify_controller(struct usb_xpad *xpad) { } |
| 1197 | #endif | 1211 | #endif |
| 1198 | 1212 | ||
| 1199 | static int xpad_open(struct input_dev *dev) | 1213 | static int xpad_start_input(struct usb_xpad *xpad) |
| 1200 | { | 1214 | { |
| 1201 | struct usb_xpad *xpad = input_get_drvdata(dev); | 1215 | int error; |
| 1202 | |||
| 1203 | /* URB was submitted in probe */ | ||
| 1204 | if (xpad->xtype == XTYPE_XBOX360W) | ||
| 1205 | return 0; | ||
| 1206 | 1216 | ||
| 1207 | xpad->irq_in->dev = xpad->udev; | ||
| 1208 | if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) | 1217 | if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) |
| 1209 | return -EIO; | 1218 | return -EIO; |
| 1210 | 1219 | ||
| 1211 | if (xpad->xtype == XTYPE_XBOXONE) | 1220 | if (xpad->xtype == XTYPE_XBOXONE) { |
| 1212 | return xpad_start_xbox_one(xpad); | 1221 | error = xpad_start_xbox_one(xpad); |
| 1222 | if (error) { | ||
| 1223 | usb_kill_urb(xpad->irq_in); | ||
| 1224 | return error; | ||
| 1225 | } | ||
| 1226 | } | ||
| 1213 | 1227 | ||
| 1214 | return 0; | 1228 | return 0; |
| 1215 | } | 1229 | } |
| 1216 | 1230 | ||
| 1217 | static void xpad_close(struct input_dev *dev) | 1231 | static void xpad_stop_input(struct usb_xpad *xpad) |
| 1218 | { | 1232 | { |
| 1219 | struct usb_xpad *xpad = input_get_drvdata(dev); | 1233 | usb_kill_urb(xpad->irq_in); |
| 1234 | } | ||
| 1235 | |||
| 1236 | static int xpad360w_start_input(struct usb_xpad *xpad) | ||
| 1237 | { | ||
| 1238 | int error; | ||
| 1239 | |||
| 1240 | error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); | ||
| 1241 | if (error) | ||
| 1242 | return -EIO; | ||
| 1220 | 1243 | ||
| 1221 | if (xpad->xtype != XTYPE_XBOX360W) | 1244 | /* |
| 1245 | * Send presence packet. | ||
| 1246 | * This will force the controller to resend connection packets. | ||
| 1247 | * This is useful in the case we activate the module after the | ||
| 1248 | * adapter has been plugged in, as it won't automatically | ||
| 1249 | * send us info about the controllers. | ||
| 1250 | */ | ||
| 1251 | error = xpad_inquiry_pad_presence(xpad); | ||
| 1252 | if (error) { | ||
| 1222 | usb_kill_urb(xpad->irq_in); | 1253 | usb_kill_urb(xpad->irq_in); |
| 1254 | return error; | ||
| 1255 | } | ||
| 1223 | 1256 | ||
| 1224 | xpad_stop_output(xpad); | 1257 | return 0; |
| 1258 | } | ||
| 1259 | |||
| 1260 | static void xpad360w_stop_input(struct usb_xpad *xpad) | ||
| 1261 | { | ||
| 1262 | usb_kill_urb(xpad->irq_in); | ||
| 1263 | |||
| 1264 | /* Make sure we are done with presence work if it was scheduled */ | ||
| 1265 | flush_work(&xpad->work); | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | static int xpad_open(struct input_dev *dev) | ||
| 1269 | { | ||
| 1270 | struct usb_xpad *xpad = input_get_drvdata(dev); | ||
| 1271 | |||
| 1272 | return xpad_start_input(xpad); | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | static void xpad_close(struct input_dev *dev) | ||
| 1276 | { | ||
| 1277 | struct usb_xpad *xpad = input_get_drvdata(dev); | ||
| 1278 | |||
| 1279 | xpad_stop_input(xpad); | ||
| 1225 | } | 1280 | } |
| 1226 | 1281 | ||
| 1227 | static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) | 1282 | static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) |
| @@ -1276,8 +1331,10 @@ static int xpad_init_input(struct usb_xpad *xpad) | |||
| 1276 | 1331 | ||
| 1277 | input_set_drvdata(input_dev, xpad); | 1332 | input_set_drvdata(input_dev, xpad); |
| 1278 | 1333 | ||
| 1279 | input_dev->open = xpad_open; | 1334 | if (xpad->xtype != XTYPE_XBOX360W) { |
| 1280 | input_dev->close = xpad_close; | 1335 | input_dev->open = xpad_open; |
| 1336 | input_dev->close = xpad_close; | ||
| 1337 | } | ||
| 1281 | 1338 | ||
| 1282 | __set_bit(EV_KEY, input_dev->evbit); | 1339 | __set_bit(EV_KEY, input_dev->evbit); |
| 1283 | 1340 | ||
| @@ -1445,21 +1502,17 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
| 1445 | * exactly the message that a controller has arrived that | 1502 | * exactly the message that a controller has arrived that |
| 1446 | * we're waiting for. | 1503 | * we're waiting for. |
| 1447 | */ | 1504 | */ |
| 1448 | xpad->irq_in->dev = xpad->udev; | 1505 | error = xpad360w_start_input(xpad); |
| 1449 | error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); | ||
| 1450 | if (error) | 1506 | if (error) |
| 1451 | goto err_deinit_output; | 1507 | goto err_deinit_output; |
| 1452 | |||
| 1453 | /* | 1508 | /* |
| 1454 | * Send presence packet. | 1509 | * Wireless controllers require RESET_RESUME to work properly |
| 1455 | * This will force the controller to resend connection packets. | 1510 | * after suspend. Ideally this quirk should be in usb core |
| 1456 | * This is useful in the case we activate the module after the | 1511 | * quirk list, but we have too many vendors producing these |
| 1457 | * adapter has been plugged in, as it won't automatically | 1512 | * controllers and we'd need to maintain 2 identical lists |
| 1458 | * send us info about the controllers. | 1513 | * here in this driver and in usb core. |
| 1459 | */ | 1514 | */ |
| 1460 | error = xpad_inquiry_pad_presence(xpad); | 1515 | udev->quirks |= USB_QUIRK_RESET_RESUME; |
| 1461 | if (error) | ||
| 1462 | goto err_kill_in_urb; | ||
| 1463 | } else { | 1516 | } else { |
| 1464 | error = xpad_init_input(xpad); | 1517 | error = xpad_init_input(xpad); |
| 1465 | if (error) | 1518 | if (error) |
| @@ -1467,8 +1520,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
| 1467 | } | 1520 | } |
| 1468 | return 0; | 1521 | return 0; |
| 1469 | 1522 | ||
| 1470 | err_kill_in_urb: | ||
| 1471 | usb_kill_urb(xpad->irq_in); | ||
| 1472 | err_deinit_output: | 1523 | err_deinit_output: |
| 1473 | xpad_deinit_output(xpad); | 1524 | xpad_deinit_output(xpad); |
| 1474 | err_free_in_urb: | 1525 | err_free_in_urb: |
| @@ -1478,35 +1529,83 @@ err_free_idata: | |||
| 1478 | err_free_mem: | 1529 | err_free_mem: |
| 1479 | kfree(xpad); | 1530 | kfree(xpad); |
| 1480 | return error; | 1531 | return error; |
| 1481 | |||
| 1482 | } | 1532 | } |
| 1483 | 1533 | ||
| 1484 | static void xpad_disconnect(struct usb_interface *intf) | 1534 | static void xpad_disconnect(struct usb_interface *intf) |
| 1485 | { | 1535 | { |
| 1486 | struct usb_xpad *xpad = usb_get_intfdata (intf); | 1536 | struct usb_xpad *xpad = usb_get_intfdata(intf); |
| 1487 | 1537 | ||
| 1488 | if (xpad->xtype == XTYPE_XBOX360W) | 1538 | if (xpad->xtype == XTYPE_XBOX360W) |
| 1489 | usb_kill_urb(xpad->irq_in); | 1539 | xpad360w_stop_input(xpad); |
| 1490 | |||
| 1491 | cancel_work_sync(&xpad->work); | ||
| 1492 | 1540 | ||
| 1493 | xpad_deinit_input(xpad); | 1541 | xpad_deinit_input(xpad); |
| 1494 | 1542 | ||
| 1543 | /* | ||
| 1544 | * Now that both input device and LED device are gone we can | ||
| 1545 | * stop output URB. | ||
| 1546 | */ | ||
| 1547 | xpad_stop_output(xpad); | ||
| 1548 | |||
| 1549 | xpad_deinit_output(xpad); | ||
| 1550 | |||
| 1495 | usb_free_urb(xpad->irq_in); | 1551 | usb_free_urb(xpad->irq_in); |
| 1496 | usb_free_coherent(xpad->udev, XPAD_PKT_LEN, | 1552 | usb_free_coherent(xpad->udev, XPAD_PKT_LEN, |
| 1497 | xpad->idata, xpad->idata_dma); | 1553 | xpad->idata, xpad->idata_dma); |
| 1498 | 1554 | ||
| 1499 | xpad_deinit_output(xpad); | ||
| 1500 | |||
| 1501 | kfree(xpad); | 1555 | kfree(xpad); |
| 1502 | 1556 | ||
| 1503 | usb_set_intfdata(intf, NULL); | 1557 | usb_set_intfdata(intf, NULL); |
| 1504 | } | 1558 | } |
| 1505 | 1559 | ||
| 1560 | static int xpad_suspend(struct usb_interface *intf, pm_message_t message) | ||
| 1561 | { | ||
| 1562 | struct usb_xpad *xpad = usb_get_intfdata(intf); | ||
| 1563 | struct input_dev *input = xpad->dev; | ||
| 1564 | |||
| 1565 | if (xpad->xtype == XTYPE_XBOX360W) { | ||
| 1566 | /* | ||
| 1567 | * Wireless controllers always listen to input so | ||
| 1568 | * they are notified when controller shows up | ||
| 1569 | * or goes away. | ||
| 1570 | */ | ||
| 1571 | xpad360w_stop_input(xpad); | ||
| 1572 | } else { | ||
| 1573 | mutex_lock(&input->mutex); | ||
| 1574 | if (input->users) | ||
| 1575 | xpad_stop_input(xpad); | ||
| 1576 | mutex_unlock(&input->mutex); | ||
| 1577 | } | ||
| 1578 | |||
| 1579 | xpad_stop_output(xpad); | ||
| 1580 | |||
| 1581 | return 0; | ||
| 1582 | } | ||
| 1583 | |||
| 1584 | static int xpad_resume(struct usb_interface *intf) | ||
| 1585 | { | ||
| 1586 | struct usb_xpad *xpad = usb_get_intfdata(intf); | ||
| 1587 | struct input_dev *input = xpad->dev; | ||
| 1588 | int retval = 0; | ||
| 1589 | |||
| 1590 | if (xpad->xtype == XTYPE_XBOX360W) { | ||
| 1591 | retval = xpad360w_start_input(xpad); | ||
| 1592 | } else { | ||
| 1593 | mutex_lock(&input->mutex); | ||
| 1594 | if (input->users) | ||
| 1595 | retval = xpad_start_input(xpad); | ||
| 1596 | mutex_unlock(&input->mutex); | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | return retval; | ||
| 1600 | } | ||
| 1601 | |||
| 1506 | static struct usb_driver xpad_driver = { | 1602 | static struct usb_driver xpad_driver = { |
| 1507 | .name = "xpad", | 1603 | .name = "xpad", |
| 1508 | .probe = xpad_probe, | 1604 | .probe = xpad_probe, |
| 1509 | .disconnect = xpad_disconnect, | 1605 | .disconnect = xpad_disconnect, |
| 1606 | .suspend = xpad_suspend, | ||
| 1607 | .resume = xpad_resume, | ||
| 1608 | .reset_resume = xpad_resume, | ||
| 1510 | .id_table = xpad_table, | 1609 | .id_table = xpad_table, |
| 1511 | }; | 1610 | }; |
| 1512 | 1611 | ||
