aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorAbhishek Pandit-Subedi <abhishekpandit@chromium.org>2022-09-27 13:17:20 -0700
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2022-09-28 12:16:12 -0700
commit8dbc3e75a0a56fb0ab70781338a2283d28a09164 (patch)
tree553276226e8261c59a3fbaa24dc70c2fc41918e6 /net/bluetooth
parentBluetooth: Prevent double register of suspend (diff)
downloadlinux-dev-8dbc3e75a0a56fb0ab70781338a2283d28a09164.tar.xz
linux-dev-8dbc3e75a0a56fb0ab70781338a2283d28a09164.zip
Bluetooth: Call shutdown for HCI_USER_CHANNEL
Some drivers depend on shutdown being called for proper operation. Unset HCI_USER_CHANNEL and call the full close routine since shutdown is complementary to setup. Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_sync.c33
1 files changed, 26 insertions, 7 deletions
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 422f7c6911d9..15c75ef4c271 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -4727,6 +4727,31 @@ static void hci_pend_le_actions_clear(struct hci_dev *hdev)
BT_DBG("All LE pending actions cleared");
}
+static int hci_dev_shutdown(struct hci_dev *hdev)
+{
+ int err = 0;
+ /* Similar to how we first do setup and then set the exclusive access
+ * bit for userspace, we must first unset userchannel and then clean up.
+ * Otherwise, the kernel can't properly use the hci channel to clean up
+ * the controller (some shutdown routines require sending additional
+ * commands to the controller for example).
+ */
+ bool was_userchannel =
+ hci_dev_test_and_clear_flag(hdev, HCI_USER_CHANNEL);
+
+ if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) &&
+ test_bit(HCI_UP, &hdev->flags)) {
+ /* Execute vendor specific shutdown routine */
+ if (hdev->shutdown)
+ err = hdev->shutdown(hdev);
+ }
+
+ if (was_userchannel)
+ hci_dev_set_flag(hdev, HCI_USER_CHANNEL);
+
+ return err;
+}
+
int hci_dev_close_sync(struct hci_dev *hdev)
{
bool auto_off;
@@ -4746,13 +4771,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
hdev->adv_instance_timeout = 0;
}
- if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) &&
- !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
- test_bit(HCI_UP, &hdev->flags)) {
- /* Execute vendor specific shutdown routine */
- if (hdev->shutdown)
- err = hdev->shutdown(hdev);
- }
+ err = hci_dev_shutdown(hdev);
if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
cancel_delayed_work_sync(&hdev->cmd_timer);