diff options
| -rw-r--r-- | drivers/hid/usbhid/hid-core.c | 71 |
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 | ||
| 994 | static void usbhid_restart_queues(struct usbhid_device *usbhid) | 994 | static 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 | ||
| 1001 | static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) | 1002 | static 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 |
| 1466 | static 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 | |||
| 1465 | static int hid_suspend(struct usb_interface *intf, pm_message_t message) | 1492 | static 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 | ||
| 1521 | static int hid_resume(struct usb_interface *intf) | 1554 | static 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 | } |
