Skip to content

Commit baac627

Browse files
sathishnarasimmanJohan Hedberg
authored andcommitted
Bluetooth: btusb: handle mSBC audio over USB Endpoints
For mSBC encoded audio stream over usb transport, btusb driver to be set to alternate settings 6 as per BT core spec 5.0. The type of air mode is used to differenting which alt setting to be used. The changes are made considering some discussion over the similar patch submitted earlier from Kuba Pawlak (link below) https://www.spinics.net/lists/linux-bluetooth/msg64577.html Reported-by: kbuild test robot <[email protected]> Signed-off-by: Sathish Narasimman <[email protected]> Signed-off-by: Chethan T N <[email protected]> Signed-off-by: Hsin-Yu Chao <[email protected]> Signed-off-by: Amit K Bag <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]> Signed-off-by: Johan Hedberg <[email protected]>
1 parent 1f8330e commit baac627

File tree

1 file changed

+119
-37
lines changed

1 file changed

+119
-37
lines changed

drivers/bluetooth/btusb.c

Lines changed: 119 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@ struct btusb_data {
492492
__u8 cmdreq;
493493

494494
unsigned int sco_num;
495+
unsigned int air_mode;
496+
bool usb_alt6_packet_flow;
495497
int isoc_altsetting;
496498
int suspend_count;
497499

@@ -983,6 +985,42 @@ static void btusb_isoc_complete(struct urb *urb)
983985
}
984986
}
985987

988+
static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len,
989+
int mtu, struct btusb_data *data)
990+
{
991+
int i, offset = 0;
992+
unsigned int interval;
993+
994+
BT_DBG("len %d mtu %d", len, mtu);
995+
996+
/* For mSBC ALT 6 setting the host will send the packet at continuous
997+
* flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting
998+
* 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets.
999+
* To maintain the rate we send 63bytes of usb packets alternatively for
1000+
* 7ms and 8ms to maintain the rate as 7.5ms.
1001+
*/
1002+
if (data->usb_alt6_packet_flow) {
1003+
interval = 7;
1004+
data->usb_alt6_packet_flow = false;
1005+
} else {
1006+
interval = 6;
1007+
data->usb_alt6_packet_flow = true;
1008+
}
1009+
1010+
for (i = 0; i < interval; i++) {
1011+
urb->iso_frame_desc[i].offset = offset;
1012+
urb->iso_frame_desc[i].length = offset;
1013+
}
1014+
1015+
if (len && i < BTUSB_MAX_ISOC_FRAMES) {
1016+
urb->iso_frame_desc[i].offset = offset;
1017+
urb->iso_frame_desc[i].length = len;
1018+
i++;
1019+
}
1020+
1021+
urb->number_of_packets = i;
1022+
}
1023+
9861024
static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
9871025
{
9881026
int i, offset = 0;
@@ -1386,9 +1424,13 @@ static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
13861424

13871425
urb->transfer_flags = URB_ISO_ASAP;
13881426

1389-
__fill_isoc_descriptor(urb, skb->len,
1390-
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
1391-
1427+
if (data->isoc_altsetting == 6)
1428+
__fill_isoc_descriptor_msbc(urb, skb->len,
1429+
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize),
1430+
data);
1431+
else
1432+
__fill_isoc_descriptor(urb, skb->len,
1433+
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
13921434
skb->dev = (void *)hdev;
13931435

13941436
return urb;
@@ -1484,6 +1526,7 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
14841526

14851527
if (hci_conn_num(hdev, SCO_LINK) != data->sco_num) {
14861528
data->sco_num = hci_conn_num(hdev, SCO_LINK);
1529+
data->air_mode = evt;
14871530
schedule_work(&data->work);
14881531
}
14891532
}
@@ -1531,11 +1574,67 @@ static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
15311574
return 0;
15321575
}
15331576

1577+
static int btusb_switch_alt_setting(struct hci_dev *hdev, int new_alts)
1578+
{
1579+
struct btusb_data *data = hci_get_drvdata(hdev);
1580+
int err;
1581+
1582+
if (data->isoc_altsetting != new_alts) {
1583+
unsigned long flags;
1584+
1585+
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
1586+
usb_kill_anchored_urbs(&data->isoc_anchor);
1587+
1588+
/* When isochronous alternate setting needs to be
1589+
* changed, because SCO connection has been added
1590+
* or removed, a packet fragment may be left in the
1591+
* reassembling state. This could lead to wrongly
1592+
* assembled fragments.
1593+
*
1594+
* Clear outstanding fragment when selecting a new
1595+
* alternate setting.
1596+
*/
1597+
spin_lock_irqsave(&data->rxlock, flags);
1598+
kfree_skb(data->sco_skb);
1599+
data->sco_skb = NULL;
1600+
spin_unlock_irqrestore(&data->rxlock, flags);
1601+
1602+
err = __set_isoc_interface(hdev, new_alts);
1603+
if (err < 0)
1604+
return err;
1605+
}
1606+
1607+
if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
1608+
if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0)
1609+
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
1610+
else
1611+
btusb_submit_isoc_urb(hdev, GFP_KERNEL);
1612+
}
1613+
1614+
return 0;
1615+
}
1616+
1617+
static struct usb_host_interface *btusb_find_altsetting(struct btusb_data *data,
1618+
int alt)
1619+
{
1620+
struct usb_interface *intf = data->isoc;
1621+
int i;
1622+
1623+
BT_DBG("Looking for Alt no :%d", alt);
1624+
1625+
for (i = 0; i < intf->num_altsetting; i++) {
1626+
if (intf->altsetting[i].desc.bAlternateSetting == alt)
1627+
return &intf->altsetting[i];
1628+
}
1629+
1630+
return NULL;
1631+
}
1632+
15341633
static void btusb_work(struct work_struct *work)
15351634
{
15361635
struct btusb_data *data = container_of(work, struct btusb_data, work);
15371636
struct hci_dev *hdev = data->hdev;
1538-
int new_alts;
1637+
int new_alts = 0;
15391638
int err;
15401639

15411640
if (data->sco_num > 0) {
@@ -1550,44 +1649,27 @@ static void btusb_work(struct work_struct *work)
15501649
set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
15511650
}
15521651

1553-
if (hdev->voice_setting & 0x0020) {
1554-
static const int alts[3] = { 2, 4, 5 };
1555-
1556-
new_alts = alts[data->sco_num - 1];
1557-
} else {
1558-
new_alts = data->sco_num;
1559-
}
1560-
1561-
if (data->isoc_altsetting != new_alts) {
1562-
unsigned long flags;
1652+
if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_CVSD) {
1653+
if (hdev->voice_setting & 0x0020) {
1654+
static const int alts[3] = { 2, 4, 5 };
15631655

1564-
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
1565-
usb_kill_anchored_urbs(&data->isoc_anchor);
1566-
1567-
/* When isochronous alternate setting needs to be
1568-
* changed, because SCO connection has been added
1569-
* or removed, a packet fragment may be left in the
1570-
* reassembling state. This could lead to wrongly
1571-
* assembled fragments.
1572-
*
1573-
* Clear outstanding fragment when selecting a new
1574-
* alternate setting.
1575-
*/
1576-
spin_lock_irqsave(&data->rxlock, flags);
1577-
kfree_skb(data->sco_skb);
1578-
data->sco_skb = NULL;
1579-
spin_unlock_irqrestore(&data->rxlock, flags);
1656+
new_alts = alts[data->sco_num - 1];
1657+
} else {
1658+
new_alts = data->sco_num;
1659+
}
1660+
} else if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_TRANSP) {
15801661

1581-
if (__set_isoc_interface(hdev, new_alts) < 0)
1582-
return;
1583-
}
1662+
data->usb_alt6_packet_flow = true;
15841663

1585-
if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
1586-
if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0)
1587-
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
1664+
/* Check if Alt 6 is supported for Transparent audio */
1665+
if (btusb_find_altsetting(data, 6))
1666+
new_alts = 6;
15881667
else
1589-
btusb_submit_isoc_urb(hdev, GFP_KERNEL);
1668+
bt_dev_err(hdev, "Device does not support ALT setting 6");
15901669
}
1670+
1671+
if (btusb_switch_alt_setting(hdev, new_alts) < 0)
1672+
bt_dev_err(hdev, "set USB alt:(%d) failed!", new_alts);
15911673
} else {
15921674
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
15931675
usb_kill_anchored_urbs(&data->isoc_anchor);

0 commit comments

Comments
 (0)