Message ID | 20210406141258.258544-1-marcel@holtmann.org (mailing list archive) |
---|---|
State | Accepted |
Delegated to: | Luiz Von Dentz |
Headers | show |
Series | Bluetooth: Add support for virtio transport driver | expand |
This is automated email and please do not reply to this email! Dear submitter, Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series: PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=461599 ---Test result--- ############################## Test: CheckPatch - FAIL Bluetooth: Add support for virtio transport driver WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #43: new file mode 100644 WARNING: Improper SPDX comment style for 'include/uapi/linux/virtio_bt.h', please use '/*' instead #455: FILE: include/uapi/linux/virtio_bt.h:1: +// SPDX-License-Identifier: BSD-3-Clause WARNING: Missing or malformed SPDX-License-Identifier tag in line 1 #455: FILE: include/uapi/linux/virtio_bt.h:1: +// SPDX-License-Identifier: BSD-3-Clause total: 0 errors, 3 warnings, 461 lines checked NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. "[PATCH] Bluetooth: Add support for virtio transport driver" has style problems, please review. NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS. ############################## Test: CheckGitLint - PASS ############################## Test: CheckBuildK - PASS ############################## Test: CheckTestRunner: Setup - PASS ############################## Test: CheckTestRunner: l2cap-tester - PASS Total: 40, Passed: 34 (85.0%), Failed: 0, Not Run: 6 ############################## Test: CheckTestRunner: bnep-tester - PASS Total: 1, Passed: 1 (100.0%), Failed: 0, Not Run: 0 ############################## Test: CheckTestRunner: mgmt-tester - PASS Total: 416, Passed: 402 (96.6%), Failed: 0, Not Run: 14 ############################## Test: CheckTestRunner: rfcomm-tester - PASS Total: 9, Passed: 9 (100.0%), Failed: 0, Not Run: 0 ############################## Test: CheckTestRunner: sco-tester - PASS Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0 ############################## Test: CheckTestRunner: smp-tester - PASS Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0 ############################## Test: CheckTestRunner: userchan-tester - PASS Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0 --- Regards, Linux Bluetooth
Hi Marcel,
I love your patch! Perhaps something to improve:
[auto build test WARNING on bluetooth-next/master]
[also build test WARNING on linus/master v5.12-rc6 next-20210406]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Marcel-Holtmann/Bluetooth-Add-support-for-virtio-transport-driver/20210406-221514
base: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
config: x86_64-randconfig-a011-20210406 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project a46f59a747a7273cc439efaf3b4f98d8b63d2f20)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# https://github.com/0day-ci/linux/commit/189912fb9343a7f898dbab721e7c4a70957e235b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Marcel-Holtmann/Bluetooth-Add-support-for-virtio-transport-driver/20210406-221514
git checkout 189912fb9343a7f898dbab721e7c4a70957e235b
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
In file included from <built-in>:1:
>> ./usr/include/linux/virtio_bt.h:1:1: warning: // comments are not allowed in this language [-Wcomment]
// SPDX-License-Identifier: BSD-3-Clause
^
1 warning generated.
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Marcel, I love your patch! Yet something to improve: [auto build test ERROR on bluetooth-next/master] [also build test ERROR on linus/master v5.12-rc6 next-20210406] [cannot apply to bluetooth/master] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Marcel-Holtmann/Bluetooth-Add-support-for-virtio-transport-driver/20210406-221514 base: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master config: um-allmodconfig (attached as .config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0 reproduce (this is a W=1 build): # https://github.com/0day-ci/linux/commit/189912fb9343a7f898dbab721e7c4a70957e235b git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Marcel-Holtmann/Bluetooth-Add-support-for-virtio-transport-driver/20210406-221514 git checkout 189912fb9343a7f898dbab721e7c4a70957e235b # save the attached .config to linux build tree make W=1 ARCH=um If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): cc1: warning: arch/um/include/uapi: No such file or directory [-Wmissing-include-dirs] drivers/bluetooth/virtio_bt.c: In function 'virtbt_probe': >> drivers/bluetooth/virtio_bt.c:343:3: error: implicit declaration of function 'hci_set_aosp_capable'; did you mean 'lmp_transp_capable'? [-Werror=implicit-function-declaration] 343 | hci_set_aosp_capable(hdev); | ^~~~~~~~~~~~~~~~~~~~ | lmp_transp_capable cc1: some warnings being treated as errors vim +343 drivers/bluetooth/virtio_bt.c 240 241 static int virtbt_probe(struct virtio_device *vdev) 242 { 243 vq_callback_t *callbacks[VIRTBT_NUM_VQS] = { 244 [VIRTBT_VQ_TX] = virtbt_tx_done, 245 [VIRTBT_VQ_RX] = virtbt_rx_done, 246 }; 247 const char *names[VIRTBT_NUM_VQS] = { 248 [VIRTBT_VQ_TX] = "tx", 249 [VIRTBT_VQ_RX] = "rx", 250 }; 251 struct virtio_bluetooth *vbt; 252 struct hci_dev *hdev; 253 int err; 254 __u8 type; 255 256 if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) 257 return -ENODEV; 258 259 type = virtio_cread8(vdev, offsetof(struct virtio_bt_config, type)); 260 261 switch (type) { 262 case VIRTIO_BT_CONFIG_TYPE_PRIMARY: 263 case VIRTIO_BT_CONFIG_TYPE_AMP: 264 break; 265 default: 266 return -EINVAL; 267 } 268 269 vbt = kzalloc(sizeof(*vbt), GFP_KERNEL); 270 if (!vbt) 271 return -ENOMEM; 272 273 vdev->priv = vbt; 274 vbt->vdev = vdev; 275 276 INIT_WORK(&vbt->rx, virtbt_rx_work); 277 278 err = virtio_find_vqs(vdev, VIRTBT_NUM_VQS, vbt->vqs, callbacks, 279 names, NULL); 280 if (err) 281 return err; 282 283 hdev = hci_alloc_dev(); 284 if (!hdev) { 285 err = -ENOMEM; 286 goto failed; 287 } 288 289 vbt->hdev = hdev; 290 291 hdev->bus = HCI_VIRTIO; 292 hdev->dev_type = type; 293 hci_set_drvdata(hdev, vbt); 294 295 hdev->open = virtbt_open; 296 hdev->close = virtbt_close; 297 hdev->flush = virtbt_flush; 298 hdev->send = virtbt_send_frame; 299 300 if (virtio_has_feature(vdev, VIRTIO_BT_F_VND_HCI)) { 301 __u16 vendor; 302 303 virtio_cread(vdev, struct virtio_bt_config, vendor, &vendor); 304 305 switch (vendor) { 306 case VIRTIO_BT_CONFIG_VENDOR_ZEPHYR: 307 hdev->manufacturer = 1521; 308 hdev->setup = virtbt_setup_zephyr; 309 hdev->shutdown = virtbt_shutdown_generic; 310 hdev->set_bdaddr = virtbt_set_bdaddr_zephyr; 311 break; 312 313 case VIRTIO_BT_CONFIG_VENDOR_INTEL: 314 hdev->manufacturer = 2; 315 hdev->setup = virtbt_setup_intel; 316 hdev->shutdown = virtbt_shutdown_generic; 317 hdev->set_bdaddr = virtbt_set_bdaddr_intel; 318 set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); 319 set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); 320 set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); 321 break; 322 323 case VIRTIO_BT_CONFIG_VENDOR_REALTEK: 324 hdev->manufacturer = 93; 325 hdev->setup = virtbt_setup_realtek; 326 hdev->shutdown = virtbt_shutdown_generic; 327 set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); 328 set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); 329 break; 330 } 331 } 332 333 if (virtio_has_feature(vdev, VIRTIO_BT_F_MSFT_EXT)) { 334 __u16 msft_opcode; 335 336 virtio_cread(vdev, struct virtio_bt_config, 337 msft_opcode, &msft_opcode); 338 339 hci_set_msft_opcode(hdev, msft_opcode); 340 } 341 342 if (virtio_has_feature(vdev, VIRTIO_BT_F_AOSP_EXT)) > 343 hci_set_aosp_capable(hdev); 344 345 if (hci_register_dev(hdev) < 0) { 346 hci_free_dev(hdev); 347 err = -EBUSY; 348 goto failed; 349 } 350 351 return 0; 352 353 failed: 354 vdev->config->del_vqs(vdev); 355 return err; 356 } 357 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Marcel, On Tue, Apr 06, 2021 at 04:12:58PM +0200, Marcel Holtmann wrote: > diff --git a/include/uapi/linux/virtio_bt.h b/include/uapi/linux/virtio_bt.h > new file mode 100644 > index 000000000000..0cedceaacf88 > --- /dev/null > +++ b/include/uapi/linux/virtio_bt.h > @@ -0,0 +1,31 @@ > +// SPDX-License-Identifier: BSD-3-Clause > + > +#ifndef _UAPI_LINUX_VIRTIO_BT_H > +#define _UAPI_LINUX_VIRTIO_BT_H > + > +#include <linux/virtio_types.h> > + > +/* Feature bits */ > +#define VIRTIO_BT_F_VND_HCI 0 /* Indicates vendor command support */ > +#define VIRTIO_BT_F_MSFT_EXT 1 /* Indicates MSFT vendor support */ > +#define VIRTIO_BT_F_AOSP_EXT 2 /* Indicates AOSP vendor support */ > + > +enum virtio_bt_config_type { > + VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0, > + VIRTIO_BT_CONFIG_TYPE_AMP = 1, > +}; > + > +enum virtio_bt_config_vendor { > + VIRTIO_BT_CONFIG_VENDOR_NONE = 0, > + VIRTIO_BT_CONFIG_VENDOR_ZEPHYR = 1, > + VIRTIO_BT_CONFIG_VENDOR_INTEL = 2, > + VIRTIO_BT_CONFIG_VENDOR_REALTEK = 3, > +}; > + > +struct virtio_bt_config { > + __u8 type; > + __u16 vendor; > + __u16 msft_opcode; > +} __attribute__((packed)); Config fields should be naturally aligned, because the virtio spec says (4.1.3.1 Driver Requirements: PCI Device Layout). For device configuration access, the driver MUST use 8-bit wide accesses for 8-bit wide fields, 16-bit wide and aligned accesses for 16-bit wide fields and 32-bit wide and aligned accesses for 32-bit and 64-bit wide fields. > + > +#endif /* _UAPI_LINUX_VIRTIO_BT_H */ > diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h > index bc1c0621f5ed..b4f468e9441d 100644 > --- a/include/uapi/linux/virtio_ids.h > +++ b/include/uapi/linux/virtio_ids.h > @@ -53,6 +53,7 @@ > #define VIRTIO_ID_MEM 24 /* virtio mem */ > #define VIRTIO_ID_FS 26 /* virtio filesystem */ > #define VIRTIO_ID_PMEM 27 /* virtio pmem */ > +#define VIRTIO_ID_BT 28 /* virtio bluetooth */ ID 28 is already reserved for virtio-rpmb: https://github.com/oasis-tcs/virtio-spec/issues/58 To avoid major compatibility pains going forward I think this should be changed to ID 40 before v5.13. It won't be easy to fix afterwards since it's UAPI. Probably a good idea to fix or revert virtio_bt.h as well before it's too late. Patches to the virtio headers should Cc virtualization@lists.linux-foundation.org and perhaps virtio-dev@lists.oasis-open.org because they can provide guidance about this. Thanks, Jean > #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */ > > #endif /* _LINUX_VIRTIO_IDS_H */ > -- > 2.30.2 >
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 4e73a531b377..851842372c9b 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -425,4 +425,14 @@ config BT_HCIRSI Say Y here to compile support for HCI over Redpine into the kernel or say M to compile as a module. +config BT_VIRTIO + tristate "Virtio Bluetooth driver" + depends on VIRTIO + help + Virtio Bluetooth support driver. + This driver supports Virtio Bluetooth devices. + + Say Y here to compile support for HCI over Virtio into the + kernel or say M to compile as a module. + endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 1a58a3ae142c..16286ea2655d 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -26,6 +26,8 @@ obj-$(CONFIG_BT_BCM) += btbcm.o obj-$(CONFIG_BT_RTL) += btrtl.o obj-$(CONFIG_BT_QCA) += btqca.o +obj-$(CONFIG_BT_VIRTIO) += virtio_bt.o + obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o obj-$(CONFIG_BT_HCIRSI) += btrsi.o diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c new file mode 100644 index 000000000000..c804db7e90f8 --- /dev/null +++ b/drivers/bluetooth/virtio_bt.c @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/module.h> +#include <linux/virtio.h> +#include <linux/virtio_config.h> +#include <linux/skbuff.h> + +#include <uapi/linux/virtio_ids.h> +#include <uapi/linux/virtio_bt.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#define VERSION "0.1" + +enum { + VIRTBT_VQ_TX, + VIRTBT_VQ_RX, + VIRTBT_NUM_VQS, +}; + +struct virtio_bluetooth { + struct virtio_device *vdev; + struct virtqueue *vqs[VIRTBT_NUM_VQS]; + struct work_struct rx; + struct hci_dev *hdev; +}; + +static int virtbt_add_inbuf(struct virtio_bluetooth *vbt) +{ + struct virtqueue *vq = vbt->vqs[VIRTBT_VQ_RX]; + struct scatterlist sg[1]; + struct sk_buff *skb; + int err; + + skb = alloc_skb(1000, GFP_KERNEL); + sg_init_one(sg, skb->data, 1000); + + err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL); + if (err < 0) { + kfree_skb(skb); + return err; + } + + return 0; +} + +static int virtbt_open(struct hci_dev *hdev) +{ + struct virtio_bluetooth *vbt = hci_get_drvdata(hdev); + + if (virtbt_add_inbuf(vbt) < 0) + return -EIO; + + virtqueue_kick(vbt->vqs[VIRTBT_VQ_RX]); + return 0; +} + +static int virtbt_close(struct hci_dev *hdev) +{ + struct virtio_bluetooth *vbt = hci_get_drvdata(hdev); + int i; + + cancel_work_sync(&vbt->rx); + + for (i = 0; i < ARRAY_SIZE(vbt->vqs); i++) { + struct virtqueue *vq = vbt->vqs[i]; + struct sk_buff *skb; + + while ((skb = virtqueue_detach_unused_buf(vq))) + kfree_skb(skb); + } + + return 0; +} + +static int virtbt_flush(struct hci_dev *hdev) +{ + return 0; +} + +static int virtbt_send_frame(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct virtio_bluetooth *vbt = hci_get_drvdata(hdev); + struct scatterlist sg[1]; + int err; + + memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); + + sg_init_one(sg, skb->data, skb->len); + err = virtqueue_add_outbuf(vbt->vqs[VIRTBT_VQ_TX], sg, 1, skb, + GFP_KERNEL); + if (err) { + kfree_skb(skb); + return err; + } + + virtqueue_kick(vbt->vqs[VIRTBT_VQ_TX]); + return 0; +} + +static int virtbt_setup_zephyr(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + /* Read Build Information */ + skb = __hci_cmd_sync(hdev, 0xfc08, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); + + hci_set_fw_info(hdev, "%s", skb->data + 1); + + kfree_skb(skb); + return 0; +} + +static int virtbt_set_bdaddr_zephyr(struct hci_dev *hdev, + const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + + /* Write BD_ADDR */ + skb = __hci_cmd_sync(hdev, 0xfc06, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + return 0; +} + +static int virtbt_setup_intel(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + /* Intel Read Version */ + skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + return 0; +} + +static int virtbt_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + + /* Intel Write BD Address */ + skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + return 0; +} + +static int virtbt_setup_realtek(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + /* Read ROM Version */ + skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + bt_dev_info(hdev, "ROM version %u", *((__u8 *) (skb->data + 1))); + + kfree_skb(skb); + return 0; +} + +static int virtbt_shutdown_generic(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + /* Reset */ + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + return 0; +} + +static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb) +{ + __u8 pkt_type; + + pkt_type = *((__u8 *) skb->data); + skb_pull(skb, 1); + + switch (pkt_type) { + case HCI_EVENT_PKT: + case HCI_ACLDATA_PKT: + case HCI_SCODATA_PKT: + case HCI_ISODATA_PKT: + hci_skb_pkt_type(skb) = pkt_type; + hci_recv_frame(vbt->hdev, skb); + break; + } +} + +static void virtbt_rx_work(struct work_struct *work) +{ + struct virtio_bluetooth *vbt = container_of(work, + struct virtio_bluetooth, rx); + struct sk_buff *skb; + unsigned int len; + + skb = virtqueue_get_buf(vbt->vqs[VIRTBT_VQ_RX], &len); + if (!skb) + return; + + skb->len = len; + virtbt_rx_handle(vbt, skb); + + if (virtbt_add_inbuf(vbt) < 0) + return; + + virtqueue_kick(vbt->vqs[VIRTBT_VQ_RX]); +} + +static void virtbt_tx_done(struct virtqueue *vq) +{ + struct sk_buff *skb; + unsigned int len; + + while ((skb = virtqueue_get_buf(vq, &len))) + kfree_skb(skb); +} + +static void virtbt_rx_done(struct virtqueue *vq) +{ + struct virtio_bluetooth *vbt = vq->vdev->priv; + + schedule_work(&vbt->rx); +} + +static int virtbt_probe(struct virtio_device *vdev) +{ + vq_callback_t *callbacks[VIRTBT_NUM_VQS] = { + [VIRTBT_VQ_TX] = virtbt_tx_done, + [VIRTBT_VQ_RX] = virtbt_rx_done, + }; + const char *names[VIRTBT_NUM_VQS] = { + [VIRTBT_VQ_TX] = "tx", + [VIRTBT_VQ_RX] = "rx", + }; + struct virtio_bluetooth *vbt; + struct hci_dev *hdev; + int err; + __u8 type; + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + return -ENODEV; + + type = virtio_cread8(vdev, offsetof(struct virtio_bt_config, type)); + + switch (type) { + case VIRTIO_BT_CONFIG_TYPE_PRIMARY: + case VIRTIO_BT_CONFIG_TYPE_AMP: + break; + default: + return -EINVAL; + } + + vbt = kzalloc(sizeof(*vbt), GFP_KERNEL); + if (!vbt) + return -ENOMEM; + + vdev->priv = vbt; + vbt->vdev = vdev; + + INIT_WORK(&vbt->rx, virtbt_rx_work); + + err = virtio_find_vqs(vdev, VIRTBT_NUM_VQS, vbt->vqs, callbacks, + names, NULL); + if (err) + return err; + + hdev = hci_alloc_dev(); + if (!hdev) { + err = -ENOMEM; + goto failed; + } + + vbt->hdev = hdev; + + hdev->bus = HCI_VIRTIO; + hdev->dev_type = type; + hci_set_drvdata(hdev, vbt); + + hdev->open = virtbt_open; + hdev->close = virtbt_close; + hdev->flush = virtbt_flush; + hdev->send = virtbt_send_frame; + + if (virtio_has_feature(vdev, VIRTIO_BT_F_VND_HCI)) { + __u16 vendor; + + virtio_cread(vdev, struct virtio_bt_config, vendor, &vendor); + + switch (vendor) { + case VIRTIO_BT_CONFIG_VENDOR_ZEPHYR: + hdev->manufacturer = 1521; + hdev->setup = virtbt_setup_zephyr; + hdev->shutdown = virtbt_shutdown_generic; + hdev->set_bdaddr = virtbt_set_bdaddr_zephyr; + break; + + case VIRTIO_BT_CONFIG_VENDOR_INTEL: + hdev->manufacturer = 2; + hdev->setup = virtbt_setup_intel; + hdev->shutdown = virtbt_shutdown_generic; + hdev->set_bdaddr = virtbt_set_bdaddr_intel; + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); + set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); + break; + + case VIRTIO_BT_CONFIG_VENDOR_REALTEK: + hdev->manufacturer = 93; + hdev->setup = virtbt_setup_realtek; + hdev->shutdown = virtbt_shutdown_generic; + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); + set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); + break; + } + } + + if (virtio_has_feature(vdev, VIRTIO_BT_F_MSFT_EXT)) { + __u16 msft_opcode; + + virtio_cread(vdev, struct virtio_bt_config, + msft_opcode, &msft_opcode); + + hci_set_msft_opcode(hdev, msft_opcode); + } + + if (virtio_has_feature(vdev, VIRTIO_BT_F_AOSP_EXT)) + hci_set_aosp_capable(hdev); + + if (hci_register_dev(hdev) < 0) { + hci_free_dev(hdev); + err = -EBUSY; + goto failed; + } + + return 0; + +failed: + vdev->config->del_vqs(vdev); + return err; +} + +static void virtbt_remove(struct virtio_device *vdev) +{ + struct virtio_bluetooth *vbt = vdev->priv; + struct hci_dev *hdev = vbt->hdev; + + hci_unregister_dev(hdev); + vdev->config->reset(vdev); + + hci_free_dev(hdev); + vbt->hdev = NULL; + + vdev->config->del_vqs(vdev); + kfree(vbt); +} + +static struct virtio_device_id virtbt_table[] = { + { VIRTIO_ID_BT, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +MODULE_DEVICE_TABLE(virtio, virtbt_table); + +static const unsigned int virtbt_features[] = { + VIRTIO_BT_F_VND_HCI, + VIRTIO_BT_F_MSFT_EXT, + VIRTIO_BT_F_AOSP_EXT, +}; + +static struct virtio_driver virtbt_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .feature_table = virtbt_features, + .feature_table_size = ARRAY_SIZE(virtbt_features), + .id_table = virtbt_table, + .probe = virtbt_probe, + .remove = virtbt_remove, +}; + +module_virtio_driver(virtbt_driver); + +MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); +MODULE_DESCRIPTION("Generic Bluetooth VIRTIO driver ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/virtio_bt.h b/include/uapi/linux/virtio_bt.h new file mode 100644 index 000000000000..0cedceaacf88 --- /dev/null +++ b/include/uapi/linux/virtio_bt.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _UAPI_LINUX_VIRTIO_BT_H +#define _UAPI_LINUX_VIRTIO_BT_H + +#include <linux/virtio_types.h> + +/* Feature bits */ +#define VIRTIO_BT_F_VND_HCI 0 /* Indicates vendor command support */ +#define VIRTIO_BT_F_MSFT_EXT 1 /* Indicates MSFT vendor support */ +#define VIRTIO_BT_F_AOSP_EXT 2 /* Indicates AOSP vendor support */ + +enum virtio_bt_config_type { + VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0, + VIRTIO_BT_CONFIG_TYPE_AMP = 1, +}; + +enum virtio_bt_config_vendor { + VIRTIO_BT_CONFIG_VENDOR_NONE = 0, + VIRTIO_BT_CONFIG_VENDOR_ZEPHYR = 1, + VIRTIO_BT_CONFIG_VENDOR_INTEL = 2, + VIRTIO_BT_CONFIG_VENDOR_REALTEK = 3, +}; + +struct virtio_bt_config { + __u8 type; + __u16 vendor; + __u16 msft_opcode; +} __attribute__((packed)); + +#endif /* _UAPI_LINUX_VIRTIO_BT_H */ diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index bc1c0621f5ed..b4f468e9441d 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -53,6 +53,7 @@ #define VIRTIO_ID_MEM 24 /* virtio mem */ #define VIRTIO_ID_FS 26 /* virtio filesystem */ #define VIRTIO_ID_PMEM 27 /* virtio pmem */ +#define VIRTIO_ID_BT 28 /* virtio bluetooth */ #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */ #endif /* _LINUX_VIRTIO_IDS_H */
This adds support for Bluetooth HCI transport over virtio. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> --- drivers/bluetooth/Kconfig | 10 + drivers/bluetooth/Makefile | 2 + drivers/bluetooth/virtio_bt.c | 401 ++++++++++++++++++++++++++++++++ include/uapi/linux/virtio_bt.h | 31 +++ include/uapi/linux/virtio_ids.h | 1 + 5 files changed, 445 insertions(+) create mode 100644 drivers/bluetooth/virtio_bt.c create mode 100644 include/uapi/linux/virtio_bt.h