aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/bluetooth/hci_core.h3
-rw-r--r--net/bluetooth/hci_core.c102
2 files changed, 105 insertions, 0 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 89eda2ef2380..755743d508aa 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1057,6 +1057,9 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
1057void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param); 1057void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param);
1058void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); 1058void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
1059 1059
1060struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
1061 void *param, u32 timeout);
1062
1060int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); 1063int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
1061void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); 1064void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
1062void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); 1065void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7c323bd112ff..8b2d543fb143 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -79,6 +79,108 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
79 } 79 }
80} 80}
81 81
82struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode)
83{
84 struct hci_ev_cmd_complete *ev;
85 struct hci_event_hdr *hdr;
86 struct sk_buff *skb;
87
88 hci_dev_lock(hdev);
89
90 skb = hdev->recv_evt;
91 hdev->recv_evt = NULL;
92
93 hci_dev_unlock(hdev);
94
95 if (!skb)
96 return ERR_PTR(-ENODATA);
97
98 if (skb->len < sizeof(*hdr)) {
99 BT_ERR("Too short HCI event");
100 goto failed;
101 }
102
103 hdr = (void *) skb->data;
104 skb_pull(skb, HCI_EVENT_HDR_SIZE);
105
106 if (hdr->evt != HCI_EV_CMD_COMPLETE) {
107 BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt);
108 goto failed;
109 }
110
111 if (skb->len < sizeof(*ev)) {
112 BT_ERR("Too short cmd_complete event");
113 goto failed;
114 }
115
116 ev = (void *) skb->data;
117 skb_pull(skb, sizeof(*ev));
118
119 if (opcode == __le16_to_cpu(ev->opcode))
120 return skb;
121
122 BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode,
123 __le16_to_cpu(ev->opcode));
124
125failed:
126 kfree_skb(skb);
127 return ERR_PTR(-ENODATA);
128}
129
130struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
131 void *param, u32 timeout)
132{
133 DECLARE_WAITQUEUE(wait, current);
134 struct hci_request req;
135 int err = 0;
136
137 BT_DBG("%s", hdev->name);
138
139 hci_req_init(&req, hdev);
140
141 hci_req_add(&req, opcode, plen, param);
142
143 hdev->req_status = HCI_REQ_PEND;
144
145 err = hci_req_run(&req, hci_req_sync_complete);
146 if (err < 0)
147 return ERR_PTR(err);
148
149 add_wait_queue(&hdev->req_wait_q, &wait);
150 set_current_state(TASK_INTERRUPTIBLE);
151
152 schedule_timeout(timeout);
153
154 remove_wait_queue(&hdev->req_wait_q, &wait);
155
156 if (signal_pending(current))
157 return ERR_PTR(-EINTR);
158
159 switch (hdev->req_status) {
160 case HCI_REQ_DONE:
161 err = -bt_to_errno(hdev->req_result);
162 break;
163
164 case HCI_REQ_CANCELED:
165 err = -hdev->req_result;
166 break;
167
168 default:
169 err = -ETIMEDOUT;
170 break;
171 }
172
173 hdev->req_status = hdev->req_result = 0;
174
175 BT_DBG("%s end: err %d", hdev->name, err);
176
177 if (err < 0)
178 return ERR_PTR(err);
179
180 return hci_get_cmd_complete(hdev, opcode);
181}
182EXPORT_SYMBOL(__hci_cmd_sync);
183
82/* Execute request and wait for completion. */ 184/* Execute request and wait for completion. */
83static int __hci_req_sync(struct hci_dev *hdev, 185static int __hci_req_sync(struct hci_dev *hdev,
84 void (*func)(struct hci_request *req, 186 void (*func)(struct hci_request *req,