diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2010-12-21 16:01:27 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2010-12-22 19:58:07 -0500 |
commit | 23bb57633df97ede067ea26f3cdc8a7ba2cd8109 (patch) | |
tree | 3aa9a25b17da84975691af7159b030f810560e38 /net/bluetooth/hci_core.c | |
parent | c71e97bfaadfa727669fcfcf12301744fd169091 (diff) |
Bluetooth: Fix __hci_request synchronization for hci_open_dev
The initialization function used by hci_open_dev (hci_init_req) sends
many different HCI commands. The __hci_request function should only
return when all of these commands have completed (or a timeout occurs).
Several of these commands cause hci_req_complete to be called which
causes __hci_request to return prematurely.
This patch fixes the issue by adding a new hdev->req_last_cmd variable
which is set during the initialization procedure. The hci_req_complete
function will no longer mark the request as complete until the command
matching hdev->req_last_cmd completes.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r-- | net/bluetooth/hci_core.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1a4ec97d5ac4..8b602d881fd7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -91,9 +91,16 @@ static void hci_notify(struct hci_dev *hdev, int event) | |||
91 | 91 | ||
92 | /* ---- HCI requests ---- */ | 92 | /* ---- HCI requests ---- */ |
93 | 93 | ||
94 | void hci_req_complete(struct hci_dev *hdev, int result) | 94 | void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) |
95 | { | 95 | { |
96 | BT_DBG("%s result 0x%2.2x", hdev->name, result); | 96 | BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result); |
97 | |||
98 | /* If the request has set req_last_cmd (typical for multi-HCI | ||
99 | * command requests) check if the completed command matches | ||
100 | * this, and if not just return. Single HCI command requests | ||
101 | * typically leave req_last_cmd as 0 */ | ||
102 | if (hdev->req_last_cmd && cmd != hdev->req_last_cmd) | ||
103 | return; | ||
97 | 104 | ||
98 | if (hdev->req_status == HCI_REQ_PEND) { | 105 | if (hdev->req_status == HCI_REQ_PEND) { |
99 | hdev->req_result = result; | 106 | hdev->req_result = result; |
@@ -149,7 +156,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, | |||
149 | break; | 156 | break; |
150 | } | 157 | } |
151 | 158 | ||
152 | hdev->req_status = hdev->req_result = 0; | 159 | hdev->req_last_cmd = hdev->req_status = hdev->req_result = 0; |
153 | 160 | ||
154 | BT_DBG("%s end: err %d", hdev->name, err); | 161 | BT_DBG("%s end: err %d", hdev->name, err); |
155 | 162 | ||
@@ -252,6 +259,8 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) | |||
252 | /* Connection accept timeout ~20 secs */ | 259 | /* Connection accept timeout ~20 secs */ |
253 | param = cpu_to_le16(0x7d00); | 260 | param = cpu_to_le16(0x7d00); |
254 | hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); | 261 | hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); |
262 | |||
263 | hdev->req_last_cmd = HCI_OP_WRITE_CA_TIMEOUT; | ||
255 | } | 264 | } |
256 | 265 | ||
257 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) | 266 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) |