Skip to content

Commit ceac1cb

Browse files
ChrisCH-LuVudentz
authored andcommitted
Bluetooth: btusb: mediatek: add ISO data transmission functions
This patch implements functions for ISO data send and receive in btusb driver for MediaTek's controller. MediaTek defines a specific interrupt endpoint for ISO data transmissin because the characteristics of interrupt endpoint are similar to the application of ISO data which can support guaranteed transmissin bandwidth, enough maximum data length and error checking mechanism. Driver sets up ISO interface and endpoints in btusb_mtk_setup and clears the setup in btusb_mtk_shutdown. These flow can't move to btmtk.c due to btusb_driver is only defined in btusb.c when claiming/relaesing interface. ISO packet anchor stops when driver suspending and resubmit interrupt urb for ISO data when driver resuming. Signed-off-by: Chris Lu <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 6dc22ab commit ceac1cb

File tree

3 files changed

+415
-0
lines changed

3 files changed

+415
-0
lines changed

drivers/bluetooth/btmtk.c

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#define MTK_SEC_MAP_COMMON_SIZE 12
2323
#define MTK_SEC_MAP_NEED_SEND_SIZE 52
2424

25+
/* It is for mt79xx iso data transmission setting */
26+
#define MTK_ISO_THRESHOLD 264
27+
2528
struct btmtk_patch_header {
2629
u8 datetime[16];
2730
u8 platform[4];
@@ -963,6 +966,308 @@ int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
963966
}
964967
EXPORT_SYMBOL_GPL(btmtk_usb_recv_acl);
965968

969+
static int btmtk_isopkt_pad(struct hci_dev *hdev, struct sk_buff *skb)
970+
{
971+
if (skb->len > MTK_ISO_THRESHOLD)
972+
return -EINVAL;
973+
974+
if (skb_pad(skb, MTK_ISO_THRESHOLD - skb->len))
975+
return -ENOMEM;
976+
977+
__skb_put(skb, MTK_ISO_THRESHOLD - skb->len);
978+
979+
return 0;
980+
}
981+
982+
static int __set_mtk_intr_interface(struct hci_dev *hdev)
983+
{
984+
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
985+
struct usb_interface *intf = btmtk_data->isopkt_intf;
986+
int i, err;
987+
988+
if (!btmtk_data->isopkt_intf)
989+
return -ENODEV;
990+
991+
err = usb_set_interface(btmtk_data->udev, MTK_ISO_IFNUM, 1);
992+
if (err < 0) {
993+
bt_dev_err(hdev, "setting interface failed (%d)", -err);
994+
return err;
995+
}
996+
997+
btmtk_data->isopkt_tx_ep = NULL;
998+
btmtk_data->isopkt_rx_ep = NULL;
999+
1000+
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
1001+
struct usb_endpoint_descriptor *ep_desc;
1002+
1003+
ep_desc = &intf->cur_altsetting->endpoint[i].desc;
1004+
1005+
if (!btmtk_data->isopkt_tx_ep &&
1006+
usb_endpoint_is_int_out(ep_desc)) {
1007+
btmtk_data->isopkt_tx_ep = ep_desc;
1008+
continue;
1009+
}
1010+
1011+
if (!btmtk_data->isopkt_rx_ep &&
1012+
usb_endpoint_is_int_in(ep_desc)) {
1013+
btmtk_data->isopkt_rx_ep = ep_desc;
1014+
continue;
1015+
}
1016+
}
1017+
1018+
if (!btmtk_data->isopkt_tx_ep ||
1019+
!btmtk_data->isopkt_rx_ep) {
1020+
bt_dev_err(hdev, "invalid interrupt descriptors");
1021+
return -ENODEV;
1022+
}
1023+
1024+
return 0;
1025+
}
1026+
1027+
struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev, struct sk_buff *skb,
1028+
usb_complete_t tx_complete)
1029+
{
1030+
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
1031+
struct urb *urb;
1032+
unsigned int pipe;
1033+
1034+
if (!btmtk_data->isopkt_tx_ep)
1035+
return ERR_PTR(-ENODEV);
1036+
1037+
urb = usb_alloc_urb(0, GFP_KERNEL);
1038+
if (!urb)
1039+
return ERR_PTR(-ENOMEM);
1040+
1041+
if (btmtk_isopkt_pad(hdev, skb))
1042+
return ERR_PTR(-EINVAL);
1043+
1044+
pipe = usb_sndintpipe(btmtk_data->udev,
1045+
btmtk_data->isopkt_tx_ep->bEndpointAddress);
1046+
1047+
usb_fill_int_urb(urb, btmtk_data->udev, pipe,
1048+
skb->data, skb->len, tx_complete,
1049+
skb, btmtk_data->isopkt_tx_ep->bInterval);
1050+
1051+
skb->dev = (void *)hdev;
1052+
1053+
return urb;
1054+
}
1055+
EXPORT_SYMBOL_GPL(alloc_mtk_intr_urb);
1056+
1057+
static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
1058+
{
1059+
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
1060+
struct sk_buff *skb;
1061+
unsigned long flags;
1062+
int err = 0;
1063+
1064+
spin_lock_irqsave(&btmtk_data->isorxlock, flags);
1065+
skb = btmtk_data->isopkt_skb;
1066+
1067+
while (count) {
1068+
int len;
1069+
1070+
if (!skb) {
1071+
skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC);
1072+
if (!skb) {
1073+
err = -ENOMEM;
1074+
break;
1075+
}
1076+
1077+
hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
1078+
hci_skb_expect(skb) = HCI_ISO_HDR_SIZE;
1079+
}
1080+
1081+
len = min_t(uint, hci_skb_expect(skb), count);
1082+
skb_put_data(skb, buffer, len);
1083+
1084+
count -= len;
1085+
buffer += len;
1086+
hci_skb_expect(skb) -= len;
1087+
1088+
if (skb->len == HCI_ISO_HDR_SIZE) {
1089+
__le16 dlen = ((struct hci_iso_hdr *)skb->data)->dlen;
1090+
1091+
/* Complete ISO header */
1092+
hci_skb_expect(skb) = __le16_to_cpu(dlen);
1093+
1094+
if (skb_tailroom(skb) < hci_skb_expect(skb)) {
1095+
kfree_skb(skb);
1096+
skb = NULL;
1097+
1098+
err = -EILSEQ;
1099+
break;
1100+
}
1101+
}
1102+
1103+
if (!hci_skb_expect(skb)) {
1104+
/* Complete frame */
1105+
hci_recv_frame(hdev, skb);
1106+
skb = NULL;
1107+
}
1108+
}
1109+
1110+
btmtk_data->isopkt_skb = skb;
1111+
spin_unlock_irqrestore(&btmtk_data->isorxlock, flags);
1112+
1113+
return err;
1114+
}
1115+
1116+
static void btmtk_intr_complete(struct urb *urb)
1117+
{
1118+
struct hci_dev *hdev = urb->context;
1119+
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
1120+
int err;
1121+
1122+
BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
1123+
urb->actual_length);
1124+
1125+
if (!test_bit(HCI_RUNNING, &hdev->flags))
1126+
return;
1127+
1128+
if (hdev->suspended)
1129+
return;
1130+
1131+
if (urb->status == 0) {
1132+
hdev->stat.byte_rx += urb->actual_length;
1133+
1134+
if (btmtk_recv_isopkt(hdev, urb->transfer_buffer,
1135+
urb->actual_length) < 0) {
1136+
bt_dev_err(hdev, "corrupted iso packet");
1137+
hdev->stat.err_rx++;
1138+
}
1139+
} else if (urb->status == -ENOENT) {
1140+
/* Avoid suspend failed when usb_kill_urb */
1141+
return;
1142+
}
1143+
1144+
usb_mark_last_busy(btmtk_data->udev);
1145+
usb_anchor_urb(urb, &btmtk_data->isopkt_anchor);
1146+
1147+
err = usb_submit_urb(urb, GFP_ATOMIC);
1148+
if (err < 0) {
1149+
/* -EPERM: urb is being killed;
1150+
* -ENODEV: device got disconnected
1151+
*/
1152+
if (err != -EPERM && err != -ENODEV)
1153+
bt_dev_err(hdev, "urb %p failed to resubmit (%d)",
1154+
urb, -err);
1155+
if (err != -EPERM)
1156+
hci_cmd_sync_cancel(hdev, -err);
1157+
usb_unanchor_urb(urb);
1158+
}
1159+
}
1160+
1161+
static int btmtk_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
1162+
{
1163+
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
1164+
unsigned char *buf;
1165+
unsigned int pipe;
1166+
struct urb *urb;
1167+
int err, size;
1168+
1169+
BT_DBG("%s", hdev->name);
1170+
1171+
if (!btmtk_data->isopkt_rx_ep)
1172+
return -ENODEV;
1173+
1174+
urb = usb_alloc_urb(0, mem_flags);
1175+
if (!urb)
1176+
return -ENOMEM;
1177+
size = le16_to_cpu(btmtk_data->isopkt_rx_ep->wMaxPacketSize);
1178+
1179+
buf = kmalloc(size, mem_flags);
1180+
if (!buf) {
1181+
usb_free_urb(urb);
1182+
return -ENOMEM;
1183+
}
1184+
1185+
pipe = usb_rcvintpipe(btmtk_data->udev,
1186+
btmtk_data->isopkt_rx_ep->bEndpointAddress);
1187+
1188+
usb_fill_int_urb(urb, btmtk_data->udev, pipe, buf, size,
1189+
btmtk_intr_complete, hdev,
1190+
btmtk_data->isopkt_rx_ep->bInterval);
1191+
1192+
urb->transfer_flags |= URB_FREE_BUFFER;
1193+
1194+
usb_mark_last_busy(btmtk_data->udev);
1195+
usb_anchor_urb(urb, &btmtk_data->isopkt_anchor);
1196+
1197+
err = usb_submit_urb(urb, mem_flags);
1198+
if (err < 0) {
1199+
if (err != -EPERM && err != -ENODEV)
1200+
bt_dev_err(hdev, "urb %p submission failed (%d)",
1201+
urb, -err);
1202+
usb_unanchor_urb(urb);
1203+
}
1204+
1205+
usb_free_urb(urb);
1206+
1207+
return err;
1208+
}
1209+
1210+
static int btmtk_usb_isointf_init(struct hci_dev *hdev)
1211+
{
1212+
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
1213+
u8 iso_param[2] = { 0x08, 0x01 };
1214+
struct sk_buff *skb;
1215+
int err;
1216+
1217+
init_usb_anchor(&btmtk_data->isopkt_anchor);
1218+
spin_lock_init(&btmtk_data->isorxlock);
1219+
1220+
__set_mtk_intr_interface(hdev);
1221+
1222+
err = btmtk_submit_intr_urb(hdev, GFP_KERNEL);
1223+
if (err < 0) {
1224+
usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
1225+
bt_dev_err(hdev, "ISO intf not support (%d)", err);
1226+
return err;
1227+
}
1228+
1229+
skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param,
1230+
HCI_INIT_TIMEOUT);
1231+
if (IS_ERR(skb)) {
1232+
bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb));
1233+
return PTR_ERR(skb);
1234+
}
1235+
kfree_skb(skb);
1236+
1237+
return 0;
1238+
}
1239+
1240+
int btmtk_usb_resume(struct hci_dev *hdev)
1241+
{
1242+
/* This function describes the specific additional steps taken by MediaTek
1243+
* when Bluetooth usb driver's resume function is called.
1244+
*/
1245+
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
1246+
1247+
/* Resubmit urb for iso data transmission */
1248+
if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags)) {
1249+
if (btmtk_submit_intr_urb(hdev, GFP_NOIO) < 0)
1250+
clear_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags);
1251+
}
1252+
1253+
return 0;
1254+
}
1255+
EXPORT_SYMBOL_GPL(btmtk_usb_resume);
1256+
1257+
int btmtk_usb_suspend(struct hci_dev *hdev)
1258+
{
1259+
/* This function describes the specific additional steps taken by MediaTek
1260+
* when Bluetooth usb driver's suspend function is called.
1261+
*/
1262+
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
1263+
1264+
/* Stop urb anchor for iso data transmission */
1265+
usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
1266+
1267+
return 0;
1268+
}
1269+
EXPORT_SYMBOL_GPL(btmtk_usb_suspend);
1270+
9661271
int btmtk_usb_setup(struct hci_dev *hdev)
9671272
{
9681273
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
@@ -1064,6 +1369,12 @@ int btmtk_usb_setup(struct hci_dev *hdev)
10641369
hci_set_msft_opcode(hdev, 0xFD30);
10651370
hci_set_aosp_capable(hdev);
10661371

1372+
/* Set up ISO interface after protocol enabled */
1373+
if (test_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags)) {
1374+
if (!btmtk_usb_isointf_init(hdev))
1375+
set_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags);
1376+
}
1377+
10671378
goto done;
10681379
default:
10691380
bt_dev_err(hdev, "Unsupported hardware variant (%08x)",

0 commit comments

Comments
 (0)