Commit | Line | Data |
---|---|---|
afd2daa2 MH |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | ||
3 | #include <linux/module.h> | |
4 | #include <linux/virtio.h> | |
5 | #include <linux/virtio_config.h> | |
6 | #include <linux/skbuff.h> | |
7 | ||
8 | #include <uapi/linux/virtio_ids.h> | |
9 | #include <uapi/linux/virtio_bt.h> | |
10 | ||
11 | #include <net/bluetooth/bluetooth.h> | |
12 | #include <net/bluetooth/hci_core.h> | |
13 | ||
14 | #define VERSION "0.1" | |
15 | ||
16 | enum { | |
17 | VIRTBT_VQ_TX, | |
18 | VIRTBT_VQ_RX, | |
19 | VIRTBT_NUM_VQS, | |
20 | }; | |
21 | ||
22 | struct virtio_bluetooth { | |
23 | struct virtio_device *vdev; | |
24 | struct virtqueue *vqs[VIRTBT_NUM_VQS]; | |
25 | struct work_struct rx; | |
26 | struct hci_dev *hdev; | |
27 | }; | |
28 | ||
29 | static int virtbt_add_inbuf(struct virtio_bluetooth *vbt) | |
30 | { | |
31 | struct virtqueue *vq = vbt->vqs[VIRTBT_VQ_RX]; | |
32 | struct scatterlist sg[1]; | |
33 | struct sk_buff *skb; | |
34 | int err; | |
35 | ||
36 | skb = alloc_skb(1000, GFP_KERNEL); | |
1cb027f2 CIK |
37 | if (!skb) |
38 | return -ENOMEM; | |
39 | ||
afd2daa2 MH |
40 | sg_init_one(sg, skb->data, 1000); |
41 | ||
42 | err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL); | |
43 | if (err < 0) { | |
44 | kfree_skb(skb); | |
45 | return err; | |
46 | } | |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
51 | static int virtbt_open(struct hci_dev *hdev) | |
52 | { | |
dc65b4b0 MT |
53 | return 0; |
54 | } | |
afd2daa2 | 55 | |
dc65b4b0 MT |
56 | static int virtbt_open_vdev(struct virtio_bluetooth *vbt) |
57 | { | |
afd2daa2 MH |
58 | if (virtbt_add_inbuf(vbt) < 0) |
59 | return -EIO; | |
60 | ||
61 | virtqueue_kick(vbt->vqs[VIRTBT_VQ_RX]); | |
62 | return 0; | |
63 | } | |
64 | ||
65 | static int virtbt_close(struct hci_dev *hdev) | |
66 | { | |
dc65b4b0 MT |
67 | return 0; |
68 | } | |
69 | ||
70 | static int virtbt_close_vdev(struct virtio_bluetooth *vbt) | |
71 | { | |
afd2daa2 MH |
72 | int i; |
73 | ||
74 | cancel_work_sync(&vbt->rx); | |
75 | ||
76 | for (i = 0; i < ARRAY_SIZE(vbt->vqs); i++) { | |
77 | struct virtqueue *vq = vbt->vqs[i]; | |
78 | struct sk_buff *skb; | |
79 | ||
80 | while ((skb = virtqueue_detach_unused_buf(vq))) | |
81 | kfree_skb(skb); | |
82 | } | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | static int virtbt_flush(struct hci_dev *hdev) | |
88 | { | |
89 | return 0; | |
90 | } | |
91 | ||
92 | static int virtbt_send_frame(struct hci_dev *hdev, struct sk_buff *skb) | |
93 | { | |
94 | struct virtio_bluetooth *vbt = hci_get_drvdata(hdev); | |
95 | struct scatterlist sg[1]; | |
96 | int err; | |
97 | ||
98 | memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); | |
99 | ||
100 | sg_init_one(sg, skb->data, skb->len); | |
101 | err = virtqueue_add_outbuf(vbt->vqs[VIRTBT_VQ_TX], sg, 1, skb, | |
102 | GFP_KERNEL); | |
103 | if (err) { | |
104 | kfree_skb(skb); | |
105 | return err; | |
106 | } | |
107 | ||
108 | virtqueue_kick(vbt->vqs[VIRTBT_VQ_TX]); | |
109 | return 0; | |
110 | } | |
111 | ||
112 | static int virtbt_setup_zephyr(struct hci_dev *hdev) | |
113 | { | |
114 | struct sk_buff *skb; | |
115 | ||
116 | /* Read Build Information */ | |
117 | skb = __hci_cmd_sync(hdev, 0xfc08, 0, NULL, HCI_INIT_TIMEOUT); | |
118 | if (IS_ERR(skb)) | |
119 | return PTR_ERR(skb); | |
120 | ||
121 | bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); | |
122 | ||
123 | hci_set_fw_info(hdev, "%s", skb->data + 1); | |
124 | ||
125 | kfree_skb(skb); | |
126 | return 0; | |
127 | } | |
128 | ||
129 | static int virtbt_set_bdaddr_zephyr(struct hci_dev *hdev, | |
130 | const bdaddr_t *bdaddr) | |
131 | { | |
132 | struct sk_buff *skb; | |
133 | ||
134 | /* Write BD_ADDR */ | |
135 | skb = __hci_cmd_sync(hdev, 0xfc06, 6, bdaddr, HCI_INIT_TIMEOUT); | |
136 | if (IS_ERR(skb)) | |
137 | return PTR_ERR(skb); | |
138 | ||
139 | kfree_skb(skb); | |
140 | return 0; | |
141 | } | |
142 | ||
143 | static int virtbt_setup_intel(struct hci_dev *hdev) | |
144 | { | |
145 | struct sk_buff *skb; | |
146 | ||
147 | /* Intel Read Version */ | |
148 | skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT); | |
149 | if (IS_ERR(skb)) | |
150 | return PTR_ERR(skb); | |
151 | ||
152 | kfree_skb(skb); | |
153 | return 0; | |
154 | } | |
155 | ||
156 | static int virtbt_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) | |
157 | { | |
158 | struct sk_buff *skb; | |
159 | ||
160 | /* Intel Write BD Address */ | |
161 | skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); | |
162 | if (IS_ERR(skb)) | |
163 | return PTR_ERR(skb); | |
164 | ||
165 | kfree_skb(skb); | |
166 | return 0; | |
167 | } | |
168 | ||
169 | static int virtbt_setup_realtek(struct hci_dev *hdev) | |
170 | { | |
171 | struct sk_buff *skb; | |
172 | ||
173 | /* Read ROM Version */ | |
174 | skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); | |
175 | if (IS_ERR(skb)) | |
176 | return PTR_ERR(skb); | |
177 | ||
178 | bt_dev_info(hdev, "ROM version %u", *((__u8 *) (skb->data + 1))); | |
179 | ||
180 | kfree_skb(skb); | |
181 | return 0; | |
182 | } | |
183 | ||
184 | static int virtbt_shutdown_generic(struct hci_dev *hdev) | |
185 | { | |
186 | struct sk_buff *skb; | |
187 | ||
188 | /* Reset */ | |
189 | skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); | |
190 | if (IS_ERR(skb)) | |
191 | return PTR_ERR(skb); | |
192 | ||
193 | kfree_skb(skb); | |
194 | return 0; | |
195 | } | |
196 | ||
197 | static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb) | |
198 | { | |
199 | __u8 pkt_type; | |
200 | ||
201 | pkt_type = *((__u8 *) skb->data); | |
202 | skb_pull(skb, 1); | |
203 | ||
204 | switch (pkt_type) { | |
205 | case HCI_EVENT_PKT: | |
206 | case HCI_ACLDATA_PKT: | |
207 | case HCI_SCODATA_PKT: | |
208 | case HCI_ISODATA_PKT: | |
209 | hci_skb_pkt_type(skb) = pkt_type; | |
210 | hci_recv_frame(vbt->hdev, skb); | |
211 | break; | |
1d068842 SH |
212 | default: |
213 | kfree_skb(skb); | |
214 | break; | |
afd2daa2 MH |
215 | } |
216 | } | |
217 | ||
218 | static void virtbt_rx_work(struct work_struct *work) | |
219 | { | |
220 | struct virtio_bluetooth *vbt = container_of(work, | |
221 | struct virtio_bluetooth, rx); | |
222 | struct sk_buff *skb; | |
223 | unsigned int len; | |
224 | ||
225 | skb = virtqueue_get_buf(vbt->vqs[VIRTBT_VQ_RX], &len); | |
226 | if (!skb) | |
227 | return; | |
228 | ||
160fbcf3 | 229 | skb_put(skb, len); |
afd2daa2 MH |
230 | virtbt_rx_handle(vbt, skb); |
231 | ||
232 | if (virtbt_add_inbuf(vbt) < 0) | |
233 | return; | |
234 | ||
235 | virtqueue_kick(vbt->vqs[VIRTBT_VQ_RX]); | |
236 | } | |
237 | ||
238 | static void virtbt_tx_done(struct virtqueue *vq) | |
239 | { | |
240 | struct sk_buff *skb; | |
241 | unsigned int len; | |
242 | ||
243 | while ((skb = virtqueue_get_buf(vq, &len))) | |
244 | kfree_skb(skb); | |
245 | } | |
246 | ||
247 | static void virtbt_rx_done(struct virtqueue *vq) | |
248 | { | |
249 | struct virtio_bluetooth *vbt = vq->vdev->priv; | |
250 | ||
251 | schedule_work(&vbt->rx); | |
252 | } | |
253 | ||
254 | static int virtbt_probe(struct virtio_device *vdev) | |
255 | { | |
256 | vq_callback_t *callbacks[VIRTBT_NUM_VQS] = { | |
257 | [VIRTBT_VQ_TX] = virtbt_tx_done, | |
258 | [VIRTBT_VQ_RX] = virtbt_rx_done, | |
259 | }; | |
260 | const char *names[VIRTBT_NUM_VQS] = { | |
261 | [VIRTBT_VQ_TX] = "tx", | |
262 | [VIRTBT_VQ_RX] = "rx", | |
263 | }; | |
264 | struct virtio_bluetooth *vbt; | |
265 | struct hci_dev *hdev; | |
266 | int err; | |
267 | __u8 type; | |
268 | ||
269 | if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) | |
270 | return -ENODEV; | |
271 | ||
272 | type = virtio_cread8(vdev, offsetof(struct virtio_bt_config, type)); | |
273 | ||
274 | switch (type) { | |
275 | case VIRTIO_BT_CONFIG_TYPE_PRIMARY: | |
276 | case VIRTIO_BT_CONFIG_TYPE_AMP: | |
277 | break; | |
278 | default: | |
279 | return -EINVAL; | |
280 | } | |
281 | ||
282 | vbt = kzalloc(sizeof(*vbt), GFP_KERNEL); | |
283 | if (!vbt) | |
284 | return -ENOMEM; | |
285 | ||
286 | vdev->priv = vbt; | |
287 | vbt->vdev = vdev; | |
288 | ||
289 | INIT_WORK(&vbt->rx, virtbt_rx_work); | |
290 | ||
291 | err = virtio_find_vqs(vdev, VIRTBT_NUM_VQS, vbt->vqs, callbacks, | |
292 | names, NULL); | |
293 | if (err) | |
294 | return err; | |
295 | ||
296 | hdev = hci_alloc_dev(); | |
297 | if (!hdev) { | |
298 | err = -ENOMEM; | |
299 | goto failed; | |
300 | } | |
301 | ||
302 | vbt->hdev = hdev; | |
303 | ||
304 | hdev->bus = HCI_VIRTIO; | |
305 | hdev->dev_type = type; | |
306 | hci_set_drvdata(hdev, vbt); | |
307 | ||
308 | hdev->open = virtbt_open; | |
309 | hdev->close = virtbt_close; | |
310 | hdev->flush = virtbt_flush; | |
311 | hdev->send = virtbt_send_frame; | |
312 | ||
313 | if (virtio_has_feature(vdev, VIRTIO_BT_F_VND_HCI)) { | |
314 | __u16 vendor; | |
315 | ||
47c50853 IS |
316 | if (virtio_has_feature(vdev, VIRTIO_BT_F_CONFIG_V2)) |
317 | virtio_cread(vdev, struct virtio_bt_config_v2, | |
318 | vendor, &vendor); | |
319 | else | |
320 | virtio_cread(vdev, struct virtio_bt_config, | |
321 | vendor, &vendor); | |
afd2daa2 MH |
322 | |
323 | switch (vendor) { | |
324 | case VIRTIO_BT_CONFIG_VENDOR_ZEPHYR: | |
325 | hdev->manufacturer = 1521; | |
326 | hdev->setup = virtbt_setup_zephyr; | |
327 | hdev->shutdown = virtbt_shutdown_generic; | |
328 | hdev->set_bdaddr = virtbt_set_bdaddr_zephyr; | |
329 | break; | |
330 | ||
331 | case VIRTIO_BT_CONFIG_VENDOR_INTEL: | |
332 | hdev->manufacturer = 2; | |
333 | hdev->setup = virtbt_setup_intel; | |
334 | hdev->shutdown = virtbt_shutdown_generic; | |
335 | hdev->set_bdaddr = virtbt_set_bdaddr_intel; | |
336 | set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); | |
337 | set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); | |
338 | set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); | |
339 | break; | |
340 | ||
341 | case VIRTIO_BT_CONFIG_VENDOR_REALTEK: | |
342 | hdev->manufacturer = 93; | |
343 | hdev->setup = virtbt_setup_realtek; | |
344 | hdev->shutdown = virtbt_shutdown_generic; | |
345 | set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); | |
346 | set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); | |
347 | break; | |
348 | } | |
349 | } | |
350 | ||
351 | if (virtio_has_feature(vdev, VIRTIO_BT_F_MSFT_EXT)) { | |
352 | __u16 msft_opcode; | |
353 | ||
47c50853 IS |
354 | if (virtio_has_feature(vdev, VIRTIO_BT_F_CONFIG_V2)) |
355 | virtio_cread(vdev, struct virtio_bt_config_v2, | |
356 | msft_opcode, &msft_opcode); | |
357 | else | |
358 | virtio_cread(vdev, struct virtio_bt_config, | |
359 | msft_opcode, &msft_opcode); | |
afd2daa2 MH |
360 | |
361 | hci_set_msft_opcode(hdev, msft_opcode); | |
362 | } | |
363 | ||
364 | if (virtio_has_feature(vdev, VIRTIO_BT_F_AOSP_EXT)) | |
365 | hci_set_aosp_capable(hdev); | |
366 | ||
367 | if (hci_register_dev(hdev) < 0) { | |
368 | hci_free_dev(hdev); | |
369 | err = -EBUSY; | |
370 | goto failed; | |
371 | } | |
372 | ||
dc65b4b0 MT |
373 | virtio_device_ready(vdev); |
374 | err = virtbt_open_vdev(vbt); | |
375 | if (err) | |
376 | goto open_failed; | |
377 | ||
afd2daa2 MH |
378 | return 0; |
379 | ||
dc65b4b0 MT |
380 | open_failed: |
381 | hci_free_dev(hdev); | |
afd2daa2 MH |
382 | failed: |
383 | vdev->config->del_vqs(vdev); | |
384 | return err; | |
385 | } | |
386 | ||
387 | static void virtbt_remove(struct virtio_device *vdev) | |
388 | { | |
389 | struct virtio_bluetooth *vbt = vdev->priv; | |
390 | struct hci_dev *hdev = vbt->hdev; | |
391 | ||
392 | hci_unregister_dev(hdev); | |
d9679d00 | 393 | virtio_reset_device(vdev); |
dc65b4b0 | 394 | virtbt_close_vdev(vbt); |
afd2daa2 MH |
395 | |
396 | hci_free_dev(hdev); | |
397 | vbt->hdev = NULL; | |
398 | ||
399 | vdev->config->del_vqs(vdev); | |
400 | kfree(vbt); | |
401 | } | |
402 | ||
403 | static struct virtio_device_id virtbt_table[] = { | |
404 | { VIRTIO_ID_BT, VIRTIO_DEV_ANY_ID }, | |
405 | { 0 }, | |
406 | }; | |
407 | ||
408 | MODULE_DEVICE_TABLE(virtio, virtbt_table); | |
409 | ||
410 | static const unsigned int virtbt_features[] = { | |
411 | VIRTIO_BT_F_VND_HCI, | |
412 | VIRTIO_BT_F_MSFT_EXT, | |
413 | VIRTIO_BT_F_AOSP_EXT, | |
47c50853 | 414 | VIRTIO_BT_F_CONFIG_V2, |
afd2daa2 MH |
415 | }; |
416 | ||
417 | static struct virtio_driver virtbt_driver = { | |
418 | .driver.name = KBUILD_MODNAME, | |
419 | .driver.owner = THIS_MODULE, | |
420 | .feature_table = virtbt_features, | |
421 | .feature_table_size = ARRAY_SIZE(virtbt_features), | |
422 | .id_table = virtbt_table, | |
423 | .probe = virtbt_probe, | |
424 | .remove = virtbt_remove, | |
425 | }; | |
426 | ||
427 | module_virtio_driver(virtbt_driver); | |
428 | ||
429 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | |
430 | MODULE_DESCRIPTION("Generic Bluetooth VIRTIO driver ver " VERSION); | |
431 | MODULE_VERSION(VERSION); | |
432 | MODULE_LICENSE("GPL"); |