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