Rename clean_up_hci_state and move to the core header so that we can power down the controller from within the kernel rather than just via mgmt commands. Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@xxxxxxxxxxxx> Reviewed-by: Daniel Winkler <danielwinkler@xxxxxxxxxx> Reviewed-by: Miao-chen Chou <mcchou@xxxxxxxxxxxx> --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 45 +++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 46 +------------------------------- 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9873e1c8cd163b..ff32d5a856f17f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1072,6 +1072,8 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active); void hci_le_conn_failed(struct hci_conn *conn, u8 status); +int hci_clean_up_state(struct hci_dev *hdev); + /* * hci_conn_get() and hci_conn_put() are used to control the life-time of an * "hci_conn" object. They do not guarantee that the hci_conn object is running, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 502552d6e9aff3..8e90850d6d769e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2290,6 +2290,51 @@ static void hci_power_on(struct work_struct *work) } } +static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode) +{ + BT_DBG("%s status 0x%02x", hdev->name, status); + + if (hci_conn_count(hdev) == 0) { + cancel_delayed_work(&hdev->power_off); + queue_work(hdev->req_workqueue, &hdev->power_off.work); + } +} + +/* This function requires the caller holds hdev->lock */ +int hci_clean_up_state(struct hci_dev *hdev) +{ + struct hci_request req; + struct hci_conn *conn; + bool discov_stopped; + int err; + u8 scan = 0x00; + + hci_req_init(&req, hdev); + + if (test_bit(HCI_ISCAN, &hdev->flags) || + test_bit(HCI_PSCAN, &hdev->flags)) { + hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + } + + hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false); + + if (hci_dev_test_flag(hdev, HCI_LE_ADV)) + __hci_req_disable_advertising(&req); + + discov_stopped = hci_req_stop_discovery(&req); + + list_for_each_entry(conn, &hdev->conn_hash.list, list) { + /* 0x15 == Terminated due to Power Off */ + __hci_abort_conn(&req, conn, 0x15); + } + + err = hci_req_run(&req, clean_up_hci_complete); + if (!err && discov_stopped) + hci_discovery_set_state(hdev, DISCOVERY_STOPPING); + + return err; +} + static void hci_power_off(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 12d7b368b428e8..ea136a6b730f9a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1122,16 +1122,6 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) sizeof(settings)); } -static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode) -{ - bt_dev_dbg(hdev, "status 0x%02x", status); - - if (hci_conn_count(hdev) == 0) { - cancel_delayed_work(&hdev->power_off); - queue_work(hdev->req_workqueue, &hdev->power_off.work); - } -} - void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance) { struct mgmt_ev_advertising_added ev; @@ -1159,40 +1149,6 @@ static void cancel_adv_timeout(struct hci_dev *hdev) } } -static int clean_up_hci_state(struct hci_dev *hdev) -{ - struct hci_request req; - struct hci_conn *conn; - bool discov_stopped; - int err; - - hci_req_init(&req, hdev); - - if (test_bit(HCI_ISCAN, &hdev->flags) || - test_bit(HCI_PSCAN, &hdev->flags)) { - u8 scan = 0x00; - hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); - } - - hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false); - - if (hci_dev_test_flag(hdev, HCI_LE_ADV)) - __hci_req_disable_advertising(&req); - - discov_stopped = hci_req_stop_discovery(&req); - - list_for_each_entry(conn, &hdev->conn_hash.list, list) { - /* 0x15 == Terminated due to Power Off */ - __hci_abort_conn(&req, conn, 0x15); - } - - err = hci_req_run(&req, clean_up_hci_complete); - if (!err && discov_stopped) - hci_discovery_set_state(hdev, DISCOVERY_STOPPING); - - return err; -} - static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -1230,7 +1186,7 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, err = 0; } else { /* Disconnect connections, stop scans, etc */ - err = clean_up_hci_state(hdev); + err = hci_clean_up_state(hdev); if (!err) queue_delayed_work(hdev->req_workqueue, &hdev->power_off, HCI_POWER_OFF_TIMEOUT); -- 2.29.2.299.gdc1121823c-goog