xref: /openbmc/linux/net/bluetooth/hci_sync.c (revision 6a98e3836fa2077b169f10a35c2ca9952d53f987)
1*6a98e383SMarcel Holtmann // SPDX-License-Identifier: GPL-2.0
2*6a98e383SMarcel Holtmann /*
3*6a98e383SMarcel Holtmann  * BlueZ - Bluetooth protocol stack for Linux
4*6a98e383SMarcel Holtmann  *
5*6a98e383SMarcel Holtmann  * Copyright (C) 2021 Intel Corporation
6*6a98e383SMarcel Holtmann  */
7*6a98e383SMarcel Holtmann 
8*6a98e383SMarcel Holtmann #include <net/bluetooth/bluetooth.h>
9*6a98e383SMarcel Holtmann #include <net/bluetooth/hci_core.h>
10*6a98e383SMarcel Holtmann #include <net/bluetooth/mgmt.h>
11*6a98e383SMarcel Holtmann 
12*6a98e383SMarcel Holtmann #include "hci_request.h"
13*6a98e383SMarcel Holtmann #include "smp.h"
14*6a98e383SMarcel Holtmann 
15*6a98e383SMarcel Holtmann static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
16*6a98e383SMarcel Holtmann 				  struct sk_buff *skb)
17*6a98e383SMarcel Holtmann {
18*6a98e383SMarcel Holtmann 	bt_dev_dbg(hdev, "result 0x%2.2x", result);
19*6a98e383SMarcel Holtmann 
20*6a98e383SMarcel Holtmann 	if (hdev->req_status != HCI_REQ_PEND)
21*6a98e383SMarcel Holtmann 		return;
22*6a98e383SMarcel Holtmann 
23*6a98e383SMarcel Holtmann 	hdev->req_result = result;
24*6a98e383SMarcel Holtmann 	hdev->req_status = HCI_REQ_DONE;
25*6a98e383SMarcel Holtmann 
26*6a98e383SMarcel Holtmann 	wake_up_interruptible(&hdev->req_wait_q);
27*6a98e383SMarcel Holtmann }
28*6a98e383SMarcel Holtmann 
29*6a98e383SMarcel Holtmann static struct sk_buff *hci_cmd_sync_alloc(struct hci_dev *hdev, u16 opcode,
30*6a98e383SMarcel Holtmann 					  u32 plen, const void *param,
31*6a98e383SMarcel Holtmann 					  struct sock *sk)
32*6a98e383SMarcel Holtmann {
33*6a98e383SMarcel Holtmann 	int len = HCI_COMMAND_HDR_SIZE + plen;
34*6a98e383SMarcel Holtmann 	struct hci_command_hdr *hdr;
35*6a98e383SMarcel Holtmann 	struct sk_buff *skb;
36*6a98e383SMarcel Holtmann 
37*6a98e383SMarcel Holtmann 	skb = bt_skb_alloc(len, GFP_ATOMIC);
38*6a98e383SMarcel Holtmann 	if (!skb)
39*6a98e383SMarcel Holtmann 		return NULL;
40*6a98e383SMarcel Holtmann 
41*6a98e383SMarcel Holtmann 	hdr = skb_put(skb, HCI_COMMAND_HDR_SIZE);
42*6a98e383SMarcel Holtmann 	hdr->opcode = cpu_to_le16(opcode);
43*6a98e383SMarcel Holtmann 	hdr->plen   = plen;
44*6a98e383SMarcel Holtmann 
45*6a98e383SMarcel Holtmann 	if (plen)
46*6a98e383SMarcel Holtmann 		skb_put_data(skb, param, plen);
47*6a98e383SMarcel Holtmann 
48*6a98e383SMarcel Holtmann 	bt_dev_dbg(hdev, "skb len %d", skb->len);
49*6a98e383SMarcel Holtmann 
50*6a98e383SMarcel Holtmann 	hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
51*6a98e383SMarcel Holtmann 	hci_skb_opcode(skb) = opcode;
52*6a98e383SMarcel Holtmann 
53*6a98e383SMarcel Holtmann 	return skb;
54*6a98e383SMarcel Holtmann }
55*6a98e383SMarcel Holtmann 
56*6a98e383SMarcel Holtmann static void hci_cmd_sync_add(struct hci_request *req, u16 opcode, u32 plen,
57*6a98e383SMarcel Holtmann 			     const void *param, u8 event, struct sock *sk)
58*6a98e383SMarcel Holtmann {
59*6a98e383SMarcel Holtmann 	struct hci_dev *hdev = req->hdev;
60*6a98e383SMarcel Holtmann 	struct sk_buff *skb;
61*6a98e383SMarcel Holtmann 
62*6a98e383SMarcel Holtmann 	bt_dev_dbg(hdev, "opcode 0x%4.4x plen %d", opcode, plen);
63*6a98e383SMarcel Holtmann 
64*6a98e383SMarcel Holtmann 	/* If an error occurred during request building, there is no point in
65*6a98e383SMarcel Holtmann 	 * queueing the HCI command. We can simply return.
66*6a98e383SMarcel Holtmann 	 */
67*6a98e383SMarcel Holtmann 	if (req->err)
68*6a98e383SMarcel Holtmann 		return;
69*6a98e383SMarcel Holtmann 
70*6a98e383SMarcel Holtmann 	skb = hci_cmd_sync_alloc(hdev, opcode, plen, param, sk);
71*6a98e383SMarcel Holtmann 	if (!skb) {
72*6a98e383SMarcel Holtmann 		bt_dev_err(hdev, "no memory for command (opcode 0x%4.4x)",
73*6a98e383SMarcel Holtmann 			   opcode);
74*6a98e383SMarcel Holtmann 		req->err = -ENOMEM;
75*6a98e383SMarcel Holtmann 		return;
76*6a98e383SMarcel Holtmann 	}
77*6a98e383SMarcel Holtmann 
78*6a98e383SMarcel Holtmann 	if (skb_queue_empty(&req->cmd_q))
79*6a98e383SMarcel Holtmann 		bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
80*6a98e383SMarcel Holtmann 
81*6a98e383SMarcel Holtmann 	bt_cb(skb)->hci.req_event = event;
82*6a98e383SMarcel Holtmann 
83*6a98e383SMarcel Holtmann 	skb_queue_tail(&req->cmd_q, skb);
84*6a98e383SMarcel Holtmann }
85*6a98e383SMarcel Holtmann 
86*6a98e383SMarcel Holtmann static int hci_cmd_sync_run(struct hci_request *req)
87*6a98e383SMarcel Holtmann {
88*6a98e383SMarcel Holtmann 	struct hci_dev *hdev = req->hdev;
89*6a98e383SMarcel Holtmann 	struct sk_buff *skb;
90*6a98e383SMarcel Holtmann 	unsigned long flags;
91*6a98e383SMarcel Holtmann 
92*6a98e383SMarcel Holtmann 	bt_dev_dbg(hdev, "length %u", skb_queue_len(&req->cmd_q));
93*6a98e383SMarcel Holtmann 
94*6a98e383SMarcel Holtmann 	/* If an error occurred during request building, remove all HCI
95*6a98e383SMarcel Holtmann 	 * commands queued on the HCI request queue.
96*6a98e383SMarcel Holtmann 	 */
97*6a98e383SMarcel Holtmann 	if (req->err) {
98*6a98e383SMarcel Holtmann 		skb_queue_purge(&req->cmd_q);
99*6a98e383SMarcel Holtmann 		return req->err;
100*6a98e383SMarcel Holtmann 	}
101*6a98e383SMarcel Holtmann 
102*6a98e383SMarcel Holtmann 	/* Do not allow empty requests */
103*6a98e383SMarcel Holtmann 	if (skb_queue_empty(&req->cmd_q))
104*6a98e383SMarcel Holtmann 		return -ENODATA;
105*6a98e383SMarcel Holtmann 
106*6a98e383SMarcel Holtmann 	skb = skb_peek_tail(&req->cmd_q);
107*6a98e383SMarcel Holtmann 	bt_cb(skb)->hci.req_complete_skb = hci_cmd_sync_complete;
108*6a98e383SMarcel Holtmann 	bt_cb(skb)->hci.req_flags |= HCI_REQ_SKB;
109*6a98e383SMarcel Holtmann 
110*6a98e383SMarcel Holtmann 	spin_lock_irqsave(&hdev->cmd_q.lock, flags);
111*6a98e383SMarcel Holtmann 	skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
112*6a98e383SMarcel Holtmann 	spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
113*6a98e383SMarcel Holtmann 
114*6a98e383SMarcel Holtmann 	queue_work(hdev->workqueue, &hdev->cmd_work);
115*6a98e383SMarcel Holtmann 
116*6a98e383SMarcel Holtmann 	return 0;
117*6a98e383SMarcel Holtmann }
118*6a98e383SMarcel Holtmann 
119*6a98e383SMarcel Holtmann /* This function requires the caller holds hdev->req_lock. */
120*6a98e383SMarcel Holtmann struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
121*6a98e383SMarcel Holtmann 				  const void *param, u8 event, u32 timeout,
122*6a98e383SMarcel Holtmann 				  struct sock *sk)
123*6a98e383SMarcel Holtmann {
124*6a98e383SMarcel Holtmann 	struct hci_request req;
125*6a98e383SMarcel Holtmann 	struct sk_buff *skb;
126*6a98e383SMarcel Holtmann 	int err = 0;
127*6a98e383SMarcel Holtmann 
128*6a98e383SMarcel Holtmann 	bt_dev_dbg(hdev, "");
129*6a98e383SMarcel Holtmann 
130*6a98e383SMarcel Holtmann 	hci_req_init(&req, hdev);
131*6a98e383SMarcel Holtmann 
132*6a98e383SMarcel Holtmann 	hci_cmd_sync_add(&req, opcode, plen, param, event, sk);
133*6a98e383SMarcel Holtmann 
134*6a98e383SMarcel Holtmann 	hdev->req_status = HCI_REQ_PEND;
135*6a98e383SMarcel Holtmann 
136*6a98e383SMarcel Holtmann 	err = hci_cmd_sync_run(&req);
137*6a98e383SMarcel Holtmann 	if (err < 0)
138*6a98e383SMarcel Holtmann 		return ERR_PTR(err);
139*6a98e383SMarcel Holtmann 
140*6a98e383SMarcel Holtmann 	err = wait_event_interruptible_timeout(hdev->req_wait_q,
141*6a98e383SMarcel Holtmann 					       hdev->req_status != HCI_REQ_PEND,
142*6a98e383SMarcel Holtmann 					       timeout);
143*6a98e383SMarcel Holtmann 
144*6a98e383SMarcel Holtmann 	if (err == -ERESTARTSYS)
145*6a98e383SMarcel Holtmann 		return ERR_PTR(-EINTR);
146*6a98e383SMarcel Holtmann 
147*6a98e383SMarcel Holtmann 	switch (hdev->req_status) {
148*6a98e383SMarcel Holtmann 	case HCI_REQ_DONE:
149*6a98e383SMarcel Holtmann 		err = -bt_to_errno(hdev->req_result);
150*6a98e383SMarcel Holtmann 		break;
151*6a98e383SMarcel Holtmann 
152*6a98e383SMarcel Holtmann 	case HCI_REQ_CANCELED:
153*6a98e383SMarcel Holtmann 		err = -hdev->req_result;
154*6a98e383SMarcel Holtmann 		break;
155*6a98e383SMarcel Holtmann 
156*6a98e383SMarcel Holtmann 	default:
157*6a98e383SMarcel Holtmann 		err = -ETIMEDOUT;
158*6a98e383SMarcel Holtmann 		break;
159*6a98e383SMarcel Holtmann 	}
160*6a98e383SMarcel Holtmann 
161*6a98e383SMarcel Holtmann 	hdev->req_status = 0;
162*6a98e383SMarcel Holtmann 	hdev->req_result = 0;
163*6a98e383SMarcel Holtmann 	skb = hdev->req_skb;
164*6a98e383SMarcel Holtmann 	hdev->req_skb = NULL;
165*6a98e383SMarcel Holtmann 
166*6a98e383SMarcel Holtmann 	bt_dev_dbg(hdev, "end: err %d", err);
167*6a98e383SMarcel Holtmann 
168*6a98e383SMarcel Holtmann 	if (err < 0) {
169*6a98e383SMarcel Holtmann 		kfree_skb(skb);
170*6a98e383SMarcel Holtmann 		return ERR_PTR(err);
171*6a98e383SMarcel Holtmann 	}
172*6a98e383SMarcel Holtmann 
173*6a98e383SMarcel Holtmann 	if (!skb)
174*6a98e383SMarcel Holtmann 		return ERR_PTR(-ENODATA);
175*6a98e383SMarcel Holtmann 
176*6a98e383SMarcel Holtmann 	return skb;
177*6a98e383SMarcel Holtmann }
178*6a98e383SMarcel Holtmann EXPORT_SYMBOL(__hci_cmd_sync_sk);
179*6a98e383SMarcel Holtmann 
180*6a98e383SMarcel Holtmann /* This function requires the caller holds hdev->req_lock. */
181*6a98e383SMarcel Holtmann struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
182*6a98e383SMarcel Holtmann 			       const void *param, u32 timeout)
183*6a98e383SMarcel Holtmann {
184*6a98e383SMarcel Holtmann 	return __hci_cmd_sync_sk(hdev, opcode, plen, param, 0, timeout, NULL);
185*6a98e383SMarcel Holtmann }
186*6a98e383SMarcel Holtmann EXPORT_SYMBOL(__hci_cmd_sync);
187*6a98e383SMarcel Holtmann 
188*6a98e383SMarcel Holtmann /* Send HCI command and wait for command complete event */
189*6a98e383SMarcel Holtmann struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
190*6a98e383SMarcel Holtmann 			     const void *param, u32 timeout)
191*6a98e383SMarcel Holtmann {
192*6a98e383SMarcel Holtmann 	struct sk_buff *skb;
193*6a98e383SMarcel Holtmann 
194*6a98e383SMarcel Holtmann 	if (!test_bit(HCI_UP, &hdev->flags))
195*6a98e383SMarcel Holtmann 		return ERR_PTR(-ENETDOWN);
196*6a98e383SMarcel Holtmann 
197*6a98e383SMarcel Holtmann 	bt_dev_dbg(hdev, "opcode 0x%4.4x plen %d", opcode, plen);
198*6a98e383SMarcel Holtmann 
199*6a98e383SMarcel Holtmann 	hci_req_sync_lock(hdev);
200*6a98e383SMarcel Holtmann 	skb = __hci_cmd_sync(hdev, opcode, plen, param, timeout);
201*6a98e383SMarcel Holtmann 	hci_req_sync_unlock(hdev);
202*6a98e383SMarcel Holtmann 
203*6a98e383SMarcel Holtmann 	return skb;
204*6a98e383SMarcel Holtmann }
205*6a98e383SMarcel Holtmann EXPORT_SYMBOL(hci_cmd_sync);
206*6a98e383SMarcel Holtmann 
207*6a98e383SMarcel Holtmann /* This function requires the caller holds hdev->req_lock. */
208*6a98e383SMarcel Holtmann struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
209*6a98e383SMarcel Holtmann 				  const void *param, u8 event, u32 timeout)
210*6a98e383SMarcel Holtmann {
211*6a98e383SMarcel Holtmann 	return __hci_cmd_sync_sk(hdev, opcode, plen, param, event, timeout,
212*6a98e383SMarcel Holtmann 				 NULL);
213*6a98e383SMarcel Holtmann }
214*6a98e383SMarcel Holtmann EXPORT_SYMBOL(__hci_cmd_sync_ev);
215*6a98e383SMarcel Holtmann 
216*6a98e383SMarcel Holtmann /* This function requires the caller holds hdev->req_lock. */
217*6a98e383SMarcel Holtmann int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
218*6a98e383SMarcel Holtmann 			     const void *param, u8 event, u32 timeout,
219*6a98e383SMarcel Holtmann 			     struct sock *sk)
220*6a98e383SMarcel Holtmann {
221*6a98e383SMarcel Holtmann 	struct sk_buff *skb;
222*6a98e383SMarcel Holtmann 	u8 status;
223*6a98e383SMarcel Holtmann 
224*6a98e383SMarcel Holtmann 	skb = __hci_cmd_sync_sk(hdev, opcode, plen, param, event, timeout, sk);
225*6a98e383SMarcel Holtmann 	if (IS_ERR_OR_NULL(skb)) {
226*6a98e383SMarcel Holtmann 		bt_dev_err(hdev, "Opcode 0x%4x failed: %ld", opcode,
227*6a98e383SMarcel Holtmann 			   PTR_ERR(skb));
228*6a98e383SMarcel Holtmann 		return PTR_ERR(skb);
229*6a98e383SMarcel Holtmann 	}
230*6a98e383SMarcel Holtmann 
231*6a98e383SMarcel Holtmann 	status = skb->data[0];
232*6a98e383SMarcel Holtmann 
233*6a98e383SMarcel Holtmann 	kfree_skb(skb);
234*6a98e383SMarcel Holtmann 
235*6a98e383SMarcel Holtmann 	return status;
236*6a98e383SMarcel Holtmann }
237*6a98e383SMarcel Holtmann EXPORT_SYMBOL(__hci_cmd_sync_status_sk);
238*6a98e383SMarcel Holtmann 
239*6a98e383SMarcel Holtmann int __hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
240*6a98e383SMarcel Holtmann 			  const void *param, u32 timeout)
241*6a98e383SMarcel Holtmann {
242*6a98e383SMarcel Holtmann 	return __hci_cmd_sync_status_sk(hdev, opcode, plen, param, 0, timeout,
243*6a98e383SMarcel Holtmann 					NULL);
244*6a98e383SMarcel Holtmann }
245*6a98e383SMarcel Holtmann EXPORT_SYMBOL(__hci_cmd_sync_status);
246*6a98e383SMarcel Holtmann 
247*6a98e383SMarcel Holtmann static void hci_cmd_sync_work(struct work_struct *work)
248*6a98e383SMarcel Holtmann {
249*6a98e383SMarcel Holtmann 	struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_sync_work);
250*6a98e383SMarcel Holtmann 	struct hci_cmd_sync_work_entry *entry;
251*6a98e383SMarcel Holtmann 	hci_cmd_sync_work_func_t func;
252*6a98e383SMarcel Holtmann 	hci_cmd_sync_work_destroy_t destroy;
253*6a98e383SMarcel Holtmann 	void *data;
254*6a98e383SMarcel Holtmann 
255*6a98e383SMarcel Holtmann 	bt_dev_dbg(hdev, "");
256*6a98e383SMarcel Holtmann 
257*6a98e383SMarcel Holtmann 	mutex_lock(&hdev->cmd_sync_work_lock);
258*6a98e383SMarcel Holtmann 	entry = list_first_entry(&hdev->cmd_sync_work_list,
259*6a98e383SMarcel Holtmann 				 struct hci_cmd_sync_work_entry, list);
260*6a98e383SMarcel Holtmann 	if (entry) {
261*6a98e383SMarcel Holtmann 		list_del(&entry->list);
262*6a98e383SMarcel Holtmann 		func = entry->func;
263*6a98e383SMarcel Holtmann 		data = entry->data;
264*6a98e383SMarcel Holtmann 		destroy = entry->destroy;
265*6a98e383SMarcel Holtmann 		kfree(entry);
266*6a98e383SMarcel Holtmann 	} else {
267*6a98e383SMarcel Holtmann 		func = NULL;
268*6a98e383SMarcel Holtmann 		data = NULL;
269*6a98e383SMarcel Holtmann 		destroy = NULL;
270*6a98e383SMarcel Holtmann 	}
271*6a98e383SMarcel Holtmann 	mutex_unlock(&hdev->cmd_sync_work_lock);
272*6a98e383SMarcel Holtmann 
273*6a98e383SMarcel Holtmann 	if (func) {
274*6a98e383SMarcel Holtmann 		int err;
275*6a98e383SMarcel Holtmann 
276*6a98e383SMarcel Holtmann 		hci_req_sync_lock(hdev);
277*6a98e383SMarcel Holtmann 
278*6a98e383SMarcel Holtmann 		err = func(hdev, data);
279*6a98e383SMarcel Holtmann 
280*6a98e383SMarcel Holtmann 		if (destroy)
281*6a98e383SMarcel Holtmann 			destroy(hdev, data, err);
282*6a98e383SMarcel Holtmann 
283*6a98e383SMarcel Holtmann 		hci_req_sync_unlock(hdev);
284*6a98e383SMarcel Holtmann 	}
285*6a98e383SMarcel Holtmann }
286*6a98e383SMarcel Holtmann 
287*6a98e383SMarcel Holtmann void hci_cmd_sync_init(struct hci_dev *hdev)
288*6a98e383SMarcel Holtmann {
289*6a98e383SMarcel Holtmann 	INIT_WORK(&hdev->cmd_sync_work, hci_cmd_sync_work);
290*6a98e383SMarcel Holtmann 	INIT_LIST_HEAD(&hdev->cmd_sync_work_list);
291*6a98e383SMarcel Holtmann 	mutex_init(&hdev->cmd_sync_work_lock);
292*6a98e383SMarcel Holtmann }
293*6a98e383SMarcel Holtmann 
294*6a98e383SMarcel Holtmann void hci_cmd_sync_clear(struct hci_dev *hdev)
295*6a98e383SMarcel Holtmann {
296*6a98e383SMarcel Holtmann 	struct hci_cmd_sync_work_entry *entry, *tmp;
297*6a98e383SMarcel Holtmann 
298*6a98e383SMarcel Holtmann 	cancel_work_sync(&hdev->cmd_sync_work);
299*6a98e383SMarcel Holtmann 
300*6a98e383SMarcel Holtmann 	list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
301*6a98e383SMarcel Holtmann 		if (entry->destroy)
302*6a98e383SMarcel Holtmann 			entry->destroy(hdev, entry->data, -ECANCELED);
303*6a98e383SMarcel Holtmann 
304*6a98e383SMarcel Holtmann 		list_del(&entry->list);
305*6a98e383SMarcel Holtmann 		kfree(entry);
306*6a98e383SMarcel Holtmann 	}
307*6a98e383SMarcel Holtmann }
308*6a98e383SMarcel Holtmann 
309*6a98e383SMarcel Holtmann int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
310*6a98e383SMarcel Holtmann 		       void *data, hci_cmd_sync_work_destroy_t destroy)
311*6a98e383SMarcel Holtmann {
312*6a98e383SMarcel Holtmann 	struct hci_cmd_sync_work_entry *entry;
313*6a98e383SMarcel Holtmann 
314*6a98e383SMarcel Holtmann 	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
315*6a98e383SMarcel Holtmann 	if (!entry)
316*6a98e383SMarcel Holtmann 		return -ENOMEM;
317*6a98e383SMarcel Holtmann 
318*6a98e383SMarcel Holtmann 	entry->func = func;
319*6a98e383SMarcel Holtmann 	entry->data = data;
320*6a98e383SMarcel Holtmann 	entry->destroy = destroy;
321*6a98e383SMarcel Holtmann 
322*6a98e383SMarcel Holtmann 	mutex_lock(&hdev->cmd_sync_work_lock);
323*6a98e383SMarcel Holtmann 	list_add_tail(&entry->list, &hdev->cmd_sync_work_list);
324*6a98e383SMarcel Holtmann 	mutex_unlock(&hdev->cmd_sync_work_lock);
325*6a98e383SMarcel Holtmann 
326*6a98e383SMarcel Holtmann 	queue_work(hdev->req_workqueue, &hdev->cmd_sync_work);
327*6a98e383SMarcel Holtmann 
328*6a98e383SMarcel Holtmann 	return 0;
329*6a98e383SMarcel Holtmann }
330*6a98e383SMarcel Holtmann EXPORT_SYMBOL(hci_cmd_sync_queue);
331