From: Tedd Ho-Jeong An <hj.tedd.an@gmail.com>
To: linux-bluetooth@vger.kernel.org
Cc: Tedd Ho-Jeong An <tedd.an@intel.com>
Subject: [RFC PATCH] Bluetooth: vhci: Add new packet type for VHCI
Date: Thu, 28 Oct 2021 23:13:45 -0700 [thread overview]
Message-ID: <20211029061345.676005-1-hj.tedd.an@gmail.com> (raw)
From: Tedd Ho-Jeong An <tedd.an@intel.com>
Current implementation uses the Vendor packet type (0xff) with opcode
parameter. But there is no way to expand the opcode and no available bits
to use. Also it cannot be changed due to the backward compatibility
with older kernel.
So, this patch adds new packet type dedicated for VHCI(0xfe) to support
configuring the VHCI device with quarks and flags while creating the
VHCI driver.
Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
---
drivers/bluetooth/hci_vhci.c | 161 ++++++++++++++++++++++++++++++-----
include/net/bluetooth/hci.h | 1 +
2 files changed, 140 insertions(+), 22 deletions(-)
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 49ac884d996e..4ae1e861b3a8 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -30,6 +30,20 @@
static bool amp;
+struct vhci_ext_create_device_req {
+ __u8 dev_type;
+ __u32 flags;
+} __packed;
+
+#define VHCI_FLAG_QUIRK_RAW_DEVICE 0x01
+#define VHCI_FLAG_QUIRK_EXTERNAL_CONFIG 0x02
+#define VHCI_FLAG_QUIRKS_INVALID_BDADDR 0x04
+
+struct vhci_ext_create_device_resp {
+ __u8 dev_type;
+ __u16 index;
+} __packed;
+
struct vhci_data {
struct hci_dev *hdev;
@@ -278,6 +292,38 @@ static int vhci_setup(struct hci_dev *hdev)
return 0;
}
+static void vhci_create_debugfs(struct hci_dev *hdev)
+{
+ struct vhci_data *data = hci_get_drvdata(hdev);
+
+ debugfs_create_file("force_suspend", 0644, hdev->debugfs, data,
+ &force_suspend_fops);
+
+ debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data,
+ &force_wakeup_fops);
+
+ if (IS_ENABLED(CONFIG_BT_MSFTEXT))
+ debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data,
+ &msft_opcode_fops);
+
+ if (IS_ENABLED(CONFIG_BT_AOSPEXT))
+ debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data,
+ &aosp_capable_fops);
+}
+
+static void vhci_setup_hdev(struct hci_dev *hdev)
+{
+ hdev->open = vhci_open_dev;
+ hdev->close = vhci_close_dev;
+ hdev->flush = vhci_flush;
+ hdev->send = vhci_send_frame;
+ hdev->get_data_path_id = vhci_get_data_path_id;
+ hdev->get_codec_config_data = vhci_get_codec_config_data;
+ hdev->wakeup = vhci_wakeup;
+ hdev->setup = vhci_setup;
+ set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
+}
+
static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
{
struct hci_dev *hdev;
@@ -313,15 +359,7 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
hdev->dev_type = dev_type;
hci_set_drvdata(hdev, data);
- hdev->open = vhci_open_dev;
- hdev->close = vhci_close_dev;
- hdev->flush = vhci_flush;
- hdev->send = vhci_send_frame;
- hdev->get_data_path_id = vhci_get_data_path_id;
- hdev->get_codec_config_data = vhci_get_codec_config_data;
- hdev->wakeup = vhci_wakeup;
- hdev->setup = vhci_setup;
- set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
+ vhci_setup_hdev(hdev);
/* bit 6 is for external configuration */
if (opcode & 0x40)
@@ -339,19 +377,7 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
return -EBUSY;
}
- debugfs_create_file("force_suspend", 0644, hdev->debugfs, data,
- &force_suspend_fops);
-
- debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data,
- &force_wakeup_fops);
-
- if (IS_ENABLED(CONFIG_BT_MSFTEXT))
- debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data,
- &msft_opcode_fops);
-
- if (IS_ENABLED(CONFIG_BT_AOSPEXT))
- debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data,
- &aosp_capable_fops);
+ vhci_create_debugfs(hdev);
hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
@@ -364,6 +390,67 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
return 0;
}
+static int __vhci_ext_create_device(struct vhci_data *data, __u8 dev_type,
+ __u32 flags)
+{
+ struct hci_dev *hdev;
+ struct sk_buff *skb;
+ struct vhci_ext_create_device_resp *resp;
+
+ if (data->hdev)
+ return -EBADFD;
+
+ if (dev_type != HCI_PRIMARY && dev_type != HCI_AMP)
+ return -EINVAL;
+
+ skb = bt_skb_alloc(sizeof(*resp) + 1, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ data->hdev = hdev;
+
+ hdev->bus = HCI_VIRTUAL;
+ hdev->dev_type = dev_type;
+ hci_set_drvdata(hdev, data);
+
+ vhci_setup_hdev(hdev);
+
+ /* Check quirks and set it for hdev */
+ if (flags & VHCI_FLAG_QUIRK_EXTERNAL_CONFIG)
+ set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
+
+ if (flags & VHCI_FLAG_QUIRK_RAW_DEVICE)
+ set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+
+ if (flags & VHCI_FLAG_QUIRKS_INVALID_BDADDR)
+ set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
+
+ if (hci_register_dev(hdev) < 0) {
+ BT_ERR("Can't register HCI device");
+ hci_free_dev(hdev);
+ data->hdev = NULL;
+ kfree_skb(skb);
+ return -EBUSY;
+ }
+
+ vhci_create_debugfs(hdev);
+
+ hci_skb_pkt_type(skb) = HCI_VHCI_PKT;
+ skb_put_u8(skb, HCI_VHCI_PKT);
+ skb_put_u8(skb, dev_type);
+ put_unaligned_le16(hdev->id, skb_put(skb, 2));
+ skb_queue_tail(&data->readq, skb);
+
+ wake_up_interruptible(&data->read_wait);
+ return 0;
+}
+
static int vhci_create_device(struct vhci_data *data, __u8 opcode)
{
int err;
@@ -375,6 +462,18 @@ static int vhci_create_device(struct vhci_data *data, __u8 opcode)
return err;
}
+static int vhci_ext_create_device(struct vhci_data *data, __u8 dev_type,
+ __u32 flags)
+{
+ int err;
+
+ mutex_lock(&data->open_mutex);
+ err = __vhci_ext_create_device(data, dev_type, flags);
+ mutex_unlock(&data->open_mutex);
+
+ return err;
+}
+
static inline ssize_t vhci_get_user(struct vhci_data *data,
struct iov_iter *from)
{
@@ -429,6 +528,24 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
ret = vhci_create_device(data, opcode);
break;
+ /* This packet type is for VHCI specific command */
+ case HCI_VHCI_PKT:
+ cancel_delayed_work_sync(&data->open_timeout);
+ struct vhci_ext_create_device_req *req;
+
+ if (skb->len != sizeof(*req)) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ req = (void *)skb->data;
+ skb_pull(skb, sizeof(*req));
+
+ ret = vhci_ext_create_device(data, req->dev_type, req->flags);
+
+ kfree_skb(skb);
+ break;
+
default:
kfree_skb(skb);
return -EINVAL;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 63065bc01b76..35d720f9e17a 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -355,6 +355,7 @@ enum {
#define HCI_EVENT_PKT 0x04
#define HCI_ISODATA_PKT 0x05
#define HCI_DIAG_PKT 0xf0
+#define HCI_VHCI_PKT 0xfe
#define HCI_VENDOR_PKT 0xff
/* HCI packet types */
--
2.25.1
next reply other threads:[~2021-10-29 6:13 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-29 6:13 Tedd Ho-Jeong An [this message]
2021-10-29 8:31 ` [RFC PATCH] Bluetooth: vhci: Add new packet type for VHCI Marcel Holtmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211029061345.676005-1-hj.tedd.an@gmail.com \
--to=hj.tedd.an@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=tedd.an@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).