aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/usbhid
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-19 16:09:01 -0400
committerJiri Kosina <jkosina@suse.cz>2012-07-20 05:24:25 -0400
commiteb055fd0560b9835e9e1a956aa6a83c51a735801 (patch)
tree172b9b1d4b88354d0349d12f0ef8c89628901c57 /drivers/hid/usbhid
parentd4150c8f3d80b4a9387083478a86da8b3390dd83 (diff)
HID: usbhid: fix error paths in suspend
This patch (as1597) fixes some of the error paths in usbhid's suspend routine. The driver was not careful to restart everything that might have been stopped, in cases where a suspend failed. For example, once the HID_SUSPENDED flag is set, an output report submission would not restart the corresponding URB queue. If a suspend fails, it's therefore necessary to check whether the queues need to be restarted. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: Oliver Neukum <oliver@neukum.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r--drivers/hid/usbhid/hid-core.c71
1 files changed, 44 insertions, 27 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 4309c03038f6..dedd8e4e5c6d 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -993,9 +993,10 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
993 993
994static void usbhid_restart_queues(struct usbhid_device *usbhid) 994static void usbhid_restart_queues(struct usbhid_device *usbhid)
995{ 995{
996 if (usbhid->urbout) 996 if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
997 usbhid_restart_out_queue(usbhid); 997 usbhid_restart_out_queue(usbhid);
998 usbhid_restart_ctrl_queue(usbhid); 998 if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
999 usbhid_restart_ctrl_queue(usbhid);
999} 1000}
1000 1001
1001static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) 1002static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
@@ -1462,11 +1463,38 @@ void usbhid_put_power(struct hid_device *hid)
1462 1463
1463 1464
1464#ifdef CONFIG_PM 1465#ifdef CONFIG_PM
1466static int hid_resume_common(struct hid_device *hid, bool driver_suspended)
1467{
1468 struct usbhid_device *usbhid = hid->driver_data;
1469 int status;
1470
1471 spin_lock_irq(&usbhid->lock);
1472 clear_bit(HID_SUSPENDED, &usbhid->iofl);
1473 usbhid_mark_busy(usbhid);
1474
1475 if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) ||
1476 test_bit(HID_RESET_PENDING, &usbhid->iofl))
1477 schedule_work(&usbhid->reset_work);
1478 usbhid->retry_delay = 0;
1479
1480 usbhid_restart_queues(usbhid);
1481 spin_unlock_irq(&usbhid->lock);
1482
1483 status = hid_start_in(hid);
1484 if (status < 0)
1485 hid_io_error(hid);
1486
1487 if (driver_suspended && hid->driver && hid->driver->resume)
1488 status = hid->driver->resume(hid);
1489 return status;
1490}
1491
1465static int hid_suspend(struct usb_interface *intf, pm_message_t message) 1492static int hid_suspend(struct usb_interface *intf, pm_message_t message)
1466{ 1493{
1467 struct hid_device *hid = usb_get_intfdata(intf); 1494 struct hid_device *hid = usb_get_intfdata(intf);
1468 struct usbhid_device *usbhid = hid->driver_data; 1495 struct usbhid_device *usbhid = hid->driver_data;
1469 int status; 1496 int status;
1497 bool driver_suspended = false;
1470 1498
1471 if (PMSG_IS_AUTO(message)) { 1499 if (PMSG_IS_AUTO(message)) {
1472 spin_lock_irq(&usbhid->lock); /* Sync with error handler */ 1500 spin_lock_irq(&usbhid->lock); /* Sync with error handler */
@@ -1482,8 +1510,9 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
1482 if (hid->driver && hid->driver->suspend) { 1510 if (hid->driver && hid->driver->suspend) {
1483 status = hid->driver->suspend(hid, message); 1511 status = hid->driver->suspend(hid, message);
1484 if (status < 0) 1512 if (status < 0)
1485 return status; 1513 goto failed;
1486 } 1514 }
1515 driver_suspended = true;
1487 } else { 1516 } else {
1488 usbhid_mark_busy(usbhid); 1517 usbhid_mark_busy(usbhid);
1489 spin_unlock_irq(&usbhid->lock); 1518 spin_unlock_irq(&usbhid->lock);
@@ -1496,11 +1525,14 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
1496 if (status < 0) 1525 if (status < 0)
1497 return status; 1526 return status;
1498 } 1527 }
1528 driver_suspended = true;
1499 spin_lock_irq(&usbhid->lock); 1529 spin_lock_irq(&usbhid->lock);
1500 set_bit(HID_SUSPENDED, &usbhid->iofl); 1530 set_bit(HID_SUSPENDED, &usbhid->iofl);
1501 spin_unlock_irq(&usbhid->lock); 1531 spin_unlock_irq(&usbhid->lock);
1502 if (usbhid_wait_io(hid) < 0) 1532 if (usbhid_wait_io(hid) < 0) {
1503 return -EIO; 1533 status = -EIO;
1534 goto failed;
1535 }
1504 } 1536 }
1505 1537
1506 hid_cancel_delayed_stuff(usbhid); 1538 hid_cancel_delayed_stuff(usbhid);
@@ -1508,14 +1540,15 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
1508 1540
1509 if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) { 1541 if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
1510 /* lost race against keypresses */ 1542 /* lost race against keypresses */
1511 status = hid_start_in(hid); 1543 status = -EBUSY;
1512 if (status < 0) 1544 goto failed;
1513 hid_io_error(hid);
1514 usbhid_mark_busy(usbhid);
1515 return -EBUSY;
1516 } 1545 }
1517 dev_dbg(&intf->dev, "suspend\n"); 1546 dev_dbg(&intf->dev, "suspend\n");
1518 return 0; 1547 return 0;
1548
1549 failed:
1550 hid_resume_common(hid, driver_suspended);
1551 return status;
1519} 1552}
1520 1553
1521static int hid_resume(struct usb_interface *intf) 1554static int hid_resume(struct usb_interface *intf)
@@ -1527,23 +1560,7 @@ static int hid_resume(struct usb_interface *intf)
1527 if (!test_bit(HID_STARTED, &usbhid->iofl)) 1560 if (!test_bit(HID_STARTED, &usbhid->iofl))
1528 return 0; 1561 return 0;
1529 1562
1530 clear_bit(HID_SUSPENDED, &usbhid->iofl); 1563 status = hid_resume_common(hid, true);
1531 usbhid_mark_busy(usbhid);
1532
1533 if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) ||
1534 test_bit(HID_RESET_PENDING, &usbhid->iofl))
1535 schedule_work(&usbhid->reset_work);
1536 usbhid->retry_delay = 0;
1537 status = hid_start_in(hid);
1538 if (status < 0)
1539 hid_io_error(hid);
1540 usbhid_restart_queues(usbhid);
1541
1542 if (status >= 0 && hid->driver && hid->driver->resume) {
1543 int ret = hid->driver->resume(hid);
1544 if (ret < 0)
1545 status = ret;
1546 }
1547 dev_dbg(&intf->dev, "resume status %d\n", status); 1564 dev_dbg(&intf->dev, "resume status %d\n", status);
1548 return 0; 1565 return 0;
1549} 1566}