Skip to content

Commit 860ec31

Browse files
committed
Bluetooth: btusb: Add HCI Drv commands for configuring altsetting
JIRA: https://issues.redhat.com/browse/RHEL-93657 commit 7d70989 Author: Hsin-chen Chuang <chharry@chromium.org> Date: Wed Apr 16 09:53:36 2025 +0000 Bluetooth: btusb: Add HCI Drv commands for configuring altsetting Although commit 75ddcd5 ("Bluetooth: btusb: Configure altsetting for HCI_USER_CHANNEL") has enabled the HCI_USER_CHANNEL user to send out SCO data through USB Bluetooth chips, it's observed that with the patch HFP is flaky on most of the existing USB Bluetooth controllers: Intel chips sometimes send out no packet for Transparent codec; MTK chips may generate SCO data with a wrong handle for CVSD codec; RTK could split the data with a wrong packet size for Transparent codec; ... etc. To address the issue above one needs to reset the altsetting back to zero when there is no active SCO connection, which is the same as the BlueZ behavior, and another benefit is the bus doesn't need to reserve bandwidth when no SCO connection. This patch adds "Supported Altsettings" and "Switch Altsetting" commands that allow the user space program to configure the altsetting freely. This patch is tested on ChromeOS devices. The USB Bluetooth models (CVSD, TRANS alt3, and TRANS alt6) could pass the stress HFP test narrow band speech and wide band speech. Cc: chromeos-bluetooth-upstreaming@chromium.org Fixes: b16b327 ("Bluetooth: btusb: add sysfs attribute to control USB alt setting") Signed-off-by: Hsin-chen Chuang <chharry@chromium.org> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: David Marlin <dmarlin@redhat.com>
1 parent 127a225 commit 860ec31

File tree

1 file changed

+74
-1
lines changed

1 file changed

+74
-1
lines changed

drivers/bluetooth/btusb.c

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3743,12 +3743,31 @@ static ssize_t isoc_alt_store(struct device *dev,
37433743

37443744
static DEVICE_ATTR_RW(isoc_alt);
37453745

3746+
#define BTUSB_HCI_DRV_OP_SUPPORTED_ALTSETTINGS \
3747+
hci_opcode_pack(HCI_DRV_OGF_DRIVER_SPECIFIC, 0x0000)
3748+
#define BTUSB_HCI_DRV_SUPPORTED_ALTSETTINGS_SIZE 0
3749+
struct btusb_hci_drv_rp_supported_altsettings {
3750+
__u8 num;
3751+
__u8 altsettings[];
3752+
} __packed;
3753+
3754+
#define BTUSB_HCI_DRV_OP_SWITCH_ALTSETTING \
3755+
hci_opcode_pack(HCI_DRV_OGF_DRIVER_SPECIFIC, 0x0001)
3756+
#define BTUSB_HCI_DRV_SWITCH_ALTSETTING_SIZE 1
3757+
struct btusb_hci_drv_cmd_switch_altsetting {
3758+
__u8 altsetting;
3759+
} __packed;
3760+
37463761
static const struct {
37473762
u16 opcode;
37483763
const char *desc;
37493764
} btusb_hci_drv_supported_commands[] = {
37503765
/* Common commands */
37513766
{ HCI_DRV_OP_READ_INFO, "Read Info" },
3767+
3768+
/* Driver specific commands */
3769+
{ BTUSB_HCI_DRV_OP_SUPPORTED_ALTSETTINGS, "Supported Altsettings" },
3770+
{ BTUSB_HCI_DRV_OP_SWITCH_ALTSETTING, "Switch Altsetting" },
37523771
};
37533772
static int btusb_hci_drv_read_info(struct hci_dev *hdev, void *data,
37543773
u16 data_len)
@@ -3785,11 +3804,65 @@ static int btusb_hci_drv_read_info(struct hci_dev *hdev, void *data,
37853804
return err;
37863805
}
37873806

3807+
static int btusb_hci_drv_supported_altsettings(struct hci_dev *hdev, void *data,
3808+
u16 data_len)
3809+
{
3810+
struct btusb_data *drvdata = hci_get_drvdata(hdev);
3811+
struct btusb_hci_drv_rp_supported_altsettings *rp;
3812+
size_t rp_size;
3813+
int err;
3814+
u8 i;
3815+
3816+
/* There are at most 7 alt (0 - 6) */
3817+
rp = kmalloc(sizeof(*rp) + 7, GFP_KERNEL);
3818+
3819+
rp->num = 0;
3820+
if (!drvdata->isoc)
3821+
goto done;
3822+
3823+
for (i = 0; i <= 6; i++) {
3824+
if (btusb_find_altsetting(drvdata, i))
3825+
rp->altsettings[rp->num++] = i;
3826+
}
3827+
3828+
done:
3829+
rp_size = sizeof(*rp) + rp->num;
3830+
3831+
err = hci_drv_cmd_complete(hdev, BTUSB_HCI_DRV_OP_SUPPORTED_ALTSETTINGS,
3832+
HCI_DRV_STATUS_SUCCESS, rp, rp_size);
3833+
kfree(rp);
3834+
return err;
3835+
}
3836+
3837+
static int btusb_hci_drv_switch_altsetting(struct hci_dev *hdev, void *data,
3838+
u16 data_len)
3839+
{
3840+
struct btusb_hci_drv_cmd_switch_altsetting *cmd = data;
3841+
u8 status;
3842+
3843+
if (cmd->altsetting > 6) {
3844+
status = HCI_DRV_STATUS_INVALID_PARAMETERS;
3845+
} else {
3846+
if (btusb_switch_alt_setting(hdev, cmd->altsetting))
3847+
status = HCI_DRV_STATUS_UNSPECIFIED_ERROR;
3848+
else
3849+
status = HCI_DRV_STATUS_SUCCESS;
3850+
}
3851+
3852+
return hci_drv_cmd_status(hdev, BTUSB_HCI_DRV_OP_SWITCH_ALTSETTING,
3853+
status);
3854+
}
3855+
37883856
static const struct hci_drv_handler btusb_hci_drv_common_handlers[] = {
37893857
{ btusb_hci_drv_read_info, HCI_DRV_READ_INFO_SIZE },
37903858
};
37913859

3792-
static const struct hci_drv_handler btusb_hci_drv_specific_handlers[] = {};
3860+
static const struct hci_drv_handler btusb_hci_drv_specific_handlers[] = {
3861+
{ btusb_hci_drv_supported_altsettings,
3862+
BTUSB_HCI_DRV_SUPPORTED_ALTSETTINGS_SIZE },
3863+
{ btusb_hci_drv_switch_altsetting,
3864+
BTUSB_HCI_DRV_SWITCH_ALTSETTING_SIZE },
3865+
};
37933866

37943867
static struct hci_drv btusb_hci_drv = {
37953868
.common_handler_count = ARRAY_SIZE(btusb_hci_drv_common_handlers),

0 commit comments

Comments
 (0)