@@ -781,6 +781,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
case CHIP_ID_8852C:
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
+ btrealtek_set_flag(hdev, REALTEK_WBS_FILTER);
hci_set_aosp_capable(hdev);
break;
default:
@@ -937,6 +938,33 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
}
EXPORT_SYMBOL_GPL(btrtl_get_uart_settings);
+int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *p, int len,
+ u16 wMaxPacketSize)
+{
+ u8 *prev;
+
+ if (pos >= HCI_SCO_HDR_SIZE && pos >= wMaxPacketSize &&
+ len == wMaxPacketSize && !(pos % wMaxPacketSize) &&
+ wMaxPacketSize >= 10 && p[0] == data[0] && p[1] == data[1]) {
+ prev = data + (pos - wMaxPacketSize);
+
+ /* Detect the sco data of usb isoc pkt duplication. */
+ if (!memcmp(p + 2, prev + 2, 8))
+ return -EILSEQ;
+
+ if (wMaxPacketSize >= 12 &&
+ p[2] == prev[6] && p[3] == prev[7] &&
+ p[4] == prev[4] && p[5] == prev[5] &&
+ p[6] == prev[10] && p[7] == prev[11] &&
+ p[8] == prev[8] && p[9] == prev[9]) {
+ return -EILSEQ;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btrtl_usb_recv_isoc);
+
MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>");
MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION);
MODULE_VERSION(VERSION);
@@ -47,6 +47,27 @@ struct rtl_vendor_config {
struct rtl_vendor_config_entry entry[];
} __packed;
+enum {
+ REALTEK_WBS_FILTER,
+
+ __REALTEK_NUM_FLAGS,
+};
+
+struct btrealtek_data {
+ DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS);
+};
+
+#define btrealtek_set_flag(hdev, nr) \
+ do { \
+ struct btrealtek_data *realtek = hci_get_priv((hdev)); \
+ set_bit((nr), realtek->flags); \
+ } while (0)
+
+#define btrealtek_get_flag(hdev) \
+ (((struct btrealtek_data *)hci_get_priv(hdev))->flags)
+
+#define btrealtek_test_flag(hdev, nr) test_bit((nr), btrealtek_get_flag(hdev))
+
#if IS_ENABLED(CONFIG_BT_RTL)
struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
@@ -62,6 +83,8 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev,
unsigned int *controller_baudrate,
u32 *device_baudrate, bool *flow_control);
+int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *buffer, int len,
+ u16 wMaxPacketSize);
#else
@@ -105,4 +128,10 @@ static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
return -ENOENT;
}
+static inline int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *buffer, int len,
+ u16 wMaxPacketSize)
+{
+ return -EOPNOTSUPP;
+}
+
#endif
@@ -956,6 +956,7 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
struct sk_buff *skb;
unsigned long flags;
int err = 0;
+ u16 wMaxPacketSize = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize);
spin_lock_irqsave(&data->rxlock, flags);
skb = data->sco_skb;
@@ -975,6 +976,19 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
}
len = min_t(uint, hci_skb_expect(skb), count);
+
+ /* Gaps in audio could be heard while streaming WBS using USB
+ * alt settings 3 on some platforms, since this is only used
+ * with RTK chips so let vendor function detect it.
+ */
+ if (test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags) &&
+ btrealtek_test_flag(data->hdev, REALTEK_WBS_FILTER)) {
+ err = btrtl_usb_recv_isoc(skb->len, skb->data, buffer,
+ len, wMaxPacketSize);
+ if (err)
+ break;
+ }
+
skb_put_data(skb, buffer, len);
count -= len;