|
22 | 22 | #define MTK_SEC_MAP_COMMON_SIZE 12
|
23 | 23 | #define MTK_SEC_MAP_NEED_SEND_SIZE 52
|
24 | 24 |
|
| 25 | +/* It is for mt79xx iso data transmission setting */ |
| 26 | +#define MTK_ISO_THRESHOLD 264 |
| 27 | + |
25 | 28 | struct btmtk_patch_header {
|
26 | 29 | u8 datetime[16];
|
27 | 30 | u8 platform[4];
|
@@ -963,6 +966,308 @@ int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
|
963 | 966 | }
|
964 | 967 | EXPORT_SYMBOL_GPL(btmtk_usb_recv_acl);
|
965 | 968 |
|
| 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 | + |
966 | 1271 | int btmtk_usb_setup(struct hci_dev *hdev)
|
967 | 1272 | {
|
968 | 1273 | struct btmtk_data *btmtk_data = hci_get_priv(hdev);
|
@@ -1064,6 +1369,12 @@ int btmtk_usb_setup(struct hci_dev *hdev)
|
1064 | 1369 | hci_set_msft_opcode(hdev, 0xFD30);
|
1065 | 1370 | hci_set_aosp_capable(hdev);
|
1066 | 1371 |
|
| 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 | + |
1067 | 1378 | goto done;
|
1068 | 1379 | default:
|
1069 | 1380 | bt_dev_err(hdev, "Unsupported hardware variant (%08x)",
|
|
0 commit comments