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