aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-03-15 18:06:53 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2013-03-18 13:02:00 -0400
commit229ab39caf8c1321527e408725c1350f7c9aaa84 (patch)
tree2fbbef772f20272fb1fe716a9f248cd5b2def8d9 /net
parent890ea8988f7d17453515122041adb0e1acdb6025 (diff)
Bluetooth: Wait for HCI command completion with mgmt_set_powered
We should only notify user space that the adapter has been powered on after all HCI commands related to the action have completed. This patch fixes the issue by instating an async request complete callback for these HCI commands and only notifies user space in the callback. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/mgmt.c46
1 files changed, 34 insertions, 12 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4726876298f0..bf17a62a1bef 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3082,6 +3082,24 @@ static void set_bredr_scan(struct hci_request *req)
3082 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); 3082 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3083} 3083}
3084 3084
3085static void powered_complete(struct hci_dev *hdev, u8 status)
3086{
3087 struct cmd_lookup match = { NULL, hdev };
3088
3089 BT_DBG("status 0x%02x", status);
3090
3091 hci_dev_lock(hdev);
3092
3093 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3094
3095 new_settings(hdev, match.sk);
3096
3097 hci_dev_unlock(hdev);
3098
3099 if (match.sk)
3100 sock_put(match.sk);
3101}
3102
3085static int powered_update_hci(struct hci_dev *hdev) 3103static int powered_update_hci(struct hci_dev *hdev)
3086{ 3104{
3087 struct hci_request req; 3105 struct hci_request req;
@@ -3123,32 +3141,36 @@ static int powered_update_hci(struct hci_dev *hdev)
3123 update_eir(&req); 3141 update_eir(&req);
3124 } 3142 }
3125 3143
3126 return hci_req_run(&req, NULL); 3144 return hci_req_run(&req, powered_complete);
3127} 3145}
3128 3146
3129int mgmt_powered(struct hci_dev *hdev, u8 powered) 3147int mgmt_powered(struct hci_dev *hdev, u8 powered)
3130{ 3148{
3131 struct cmd_lookup match = { NULL, hdev }; 3149 struct cmd_lookup match = { NULL, hdev };
3150 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3151 u8 zero_cod[] = { 0, 0, 0 };
3132 int err; 3152 int err;
3133 3153
3134 if (!test_bit(HCI_MGMT, &hdev->dev_flags)) 3154 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3135 return 0; 3155 return 0;
3136 3156
3137 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3138
3139 if (powered) { 3157 if (powered) {
3140 powered_update_hci(hdev); 3158 if (powered_update_hci(hdev) == 0)
3141 } else { 3159 return 0;
3142 u8 status = MGMT_STATUS_NOT_POWERED;
3143 u8 zero_cod[] = { 0, 0, 0 };
3144
3145 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
3146 3160
3147 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) 3161 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3148 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, 3162 &match);
3149 zero_cod, sizeof(zero_cod), NULL); 3163 goto new_settings;
3150 } 3164 }
3151 3165
3166 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3167 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3168
3169 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3170 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3171 zero_cod, sizeof(zero_cod), NULL);
3172
3173new_settings:
3152 err = new_settings(hdev, match.sk); 3174 err = new_settings(hdev, match.sk);
3153 3175
3154 if (match.sk) 3176 if (match.sk)