mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 05:04:09 +08:00
Bluetooth: Restore running state if suspend fails
If Bluetooth fails to enter the suspended state correctly, restore the state to running (re-enabling scans). PM_POST_SUSPEND is only sent to notifiers that successfully return from PM_PREPARE_SUSPEND notification so we should recover gracefully if it fails. Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
0d7043f355
commit
8731840a34
@ -3305,6 +3305,15 @@ static void hci_prepare_suspend(struct work_struct *work)
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int hci_change_suspend_state(struct hci_dev *hdev,
|
||||
enum suspended_state next)
|
||||
{
|
||||
hdev->suspend_state_next = next;
|
||||
set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
|
||||
queue_work(hdev->req_workqueue, &hdev->suspend_prepare);
|
||||
return hci_suspend_wait_event(hdev);
|
||||
}
|
||||
|
||||
static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
@ -3330,32 +3339,24 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action,
|
||||
* connectable (disabling scanning)
|
||||
* - Second, program event filter/whitelist and enable scan
|
||||
*/
|
||||
hdev->suspend_state_next = BT_SUSPEND_DISCONNECT;
|
||||
set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
|
||||
queue_work(hdev->req_workqueue, &hdev->suspend_prepare);
|
||||
ret = hci_suspend_wait_event(hdev);
|
||||
ret = hci_change_suspend_state(hdev, BT_SUSPEND_DISCONNECT);
|
||||
|
||||
/* If the disconnect portion failed, don't attempt to complete
|
||||
* by configuring the whitelist. The suspend notifier will
|
||||
* follow a cancelled suspend with a PM_POST_SUSPEND
|
||||
* notification.
|
||||
*/
|
||||
if (!ret) {
|
||||
hdev->suspend_state_next = BT_SUSPEND_COMPLETE;
|
||||
set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
|
||||
queue_work(hdev->req_workqueue, &hdev->suspend_prepare);
|
||||
ret = hci_suspend_wait_event(hdev);
|
||||
}
|
||||
/* Only configure whitelist if disconnect succeeded */
|
||||
if (!ret)
|
||||
ret = hci_change_suspend_state(hdev,
|
||||
BT_SUSPEND_COMPLETE);
|
||||
} else if (action == PM_POST_SUSPEND) {
|
||||
hdev->suspend_state_next = BT_RUNNING;
|
||||
set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
|
||||
queue_work(hdev->req_workqueue, &hdev->suspend_prepare);
|
||||
ret = hci_suspend_wait_event(hdev);
|
||||
ret = hci_change_suspend_state(hdev, BT_RUNNING);
|
||||
}
|
||||
|
||||
/* If suspend failed, restore it to running */
|
||||
if (ret && action == PM_SUSPEND_PREPARE)
|
||||
hci_change_suspend_state(hdev, BT_RUNNING);
|
||||
|
||||
done:
|
||||
return ret ? notifier_from_errno(-EBUSY) : NOTIFY_STOP;
|
||||
}
|
||||
|
||||
/* Alloc HCI device */
|
||||
struct hci_dev *hci_alloc_dev(void)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user