summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_core.c
diff options
context:
space:
mode:
authorAbhishek Pandit-Subedi <abhishekpandit@chromium.org>2020-03-11 16:54:01 +0100
committerMarcel Holtmann <marcel@holtmann.org>2020-03-11 18:01:47 +0100
commit4f40afc6c76451daff7d0dcfc8a3d113ccf65bfc (patch)
tree707dea2a3f4ae13aefd6b7797394e2b2485ad26e /net/bluetooth/hci_core.c
parentBluetooth: Handle PM_SUSPEND_PREPARE and PM_POST_SUSPEND (diff)
downloadlinux-4f40afc6c76451daff7d0dcfc8a3d113ccf65bfc.tar.xz
linux-4f40afc6c76451daff7d0dcfc8a3d113ccf65bfc.zip
Bluetooth: Handle BR/EDR devices during suspend
To handle BR/EDR devices, we first disable page scan and disconnect all connected devices. Once that is complete, we add event filters (for devices that can wake the system) and re-enable page scan. Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r--net/bluetooth/hci_core.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 39aa21a1fe92..dbd2ad3a26ed 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3325,16 +3325,31 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action,
goto done;
if (action == PM_SUSPEND_PREPARE) {
- hdev->suspend_state_next = BT_SUSPENDED;
+ /* Suspend consists of two actions:
+ * - First, disconnect everything and make the controller not
+ * 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);
+
+ /* 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);
+ }
} 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);
}
@@ -3399,6 +3414,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->mgmt_pending);
INIT_LIST_HEAD(&hdev->blacklist);
INIT_LIST_HEAD(&hdev->whitelist);
+ INIT_LIST_HEAD(&hdev->wakeable);
INIT_LIST_HEAD(&hdev->uuids);
INIT_LIST_HEAD(&hdev->link_keys);
INIT_LIST_HEAD(&hdev->long_term_keys);