mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-23 09:42:19 +03:00
rtk_btusb: Update driver version to 3.1.65ab490.20240531-141726
- Update driver to 3.1.65ab490.20240531-141726 - Add support for 8852CE Bug 4915378 Change-Id: Ib3f695047ee306fd07db424239c985195619aad1 Signed-off-by: Shobek Attupurath <sattupurath@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3237077 GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com> Reviewed-by: Ashutosh Jha <ajha@nvidia.com> Reviewed-by: Revanth Kumar Uppala <ruppala@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
7ea5704ca3
commit
3d15bb40b5
@@ -1,8 +1,22 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -22,7 +36,7 @@
|
||||
#include "rtk_bt.h"
|
||||
#include "rtk_misc.h"
|
||||
|
||||
#define VERSION "3.1.6fd4e69.20220818-105856"
|
||||
#define VERSION "3.1.65ab490.20240531-141726"
|
||||
|
||||
#ifdef BTCOEX
|
||||
#include "rtk_coex.h"
|
||||
@@ -35,95 +49,64 @@ static DEFINE_SEMAPHORE(switch_sem);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
|
||||
static bool reset = 0;
|
||||
static bool reset = true;
|
||||
#endif
|
||||
|
||||
static struct usb_driver btusb_driver;
|
||||
static struct usb_device_id btusb_table[] = {
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static u16 iso_min_conn_handle = 0x1b;
|
||||
#endif
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
/* Generic Bluetooth USB interface */
|
||||
{ USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct usb_device_id blacklist_table[] = {
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x0bda,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x13d3,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x0489,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x1358,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x04ca,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x2ff8,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x0b05,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x0930,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x10ec,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x04c5,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x0cb5,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x0cb8,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x04b8,
|
||||
}, { }
|
||||
};
|
||||
|
||||
@@ -148,20 +131,6 @@ static struct btusb_data *rtk_alloc(struct usb_interface *intf)
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, btusb_table);
|
||||
|
||||
static int inc_tx(struct btusb_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!rv)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
static inline void btusb_free_frags(struct btusb_data *data)
|
||||
{
|
||||
@@ -204,7 +173,11 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
@@ -259,15 +232,26 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
bt_cb(skb)->expect -= len;
|
||||
|
||||
if (skb->len == HCI_ACL_HDR_SIZE) {
|
||||
__le16 dlen = hci_acl_hdr(skb)->dlen;
|
||||
struct hci_acl_hdr *h = hci_acl_hdr(skb);
|
||||
__le16 dlen = h->dlen;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
__u16 handle = __le16_to_cpu(h->handle) & 0xfff;
|
||||
|
||||
if(handle >= iso_min_conn_handle) {
|
||||
bt_cb(skb)->pkt_type = HCI_ISODATA_PKT;
|
||||
}
|
||||
#endif
|
||||
/* Complete ACL header */
|
||||
bt_cb(skb)->expect = __le16_to_cpu(dlen);
|
||||
|
||||
@@ -293,10 +277,42 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
||||
return err;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
static 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err = 0;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
u16 wMaxPacketSize = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize);
|
||||
#endif
|
||||
|
||||
spin_lock(&data->rxlock);
|
||||
skb = data->sco_skb;
|
||||
@@ -316,7 +332,24 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
/* Gaps in audio could be heard while streaming WBS using USB
|
||||
* alt settings 3 on some platforms.
|
||||
* Add the function to detect it.
|
||||
*/
|
||||
if (test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags)) {
|
||||
err = btrtl_usb_recv_isoc(skb->len, skb->data, buffer,
|
||||
len, wMaxPacketSize);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
@@ -347,6 +380,21 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
static int inc_tx(struct btusb_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!rv)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void btusb_intr_complete(struct urb *urb)
|
||||
@@ -626,6 +674,51 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len,
|
||||
int mtu, struct btusb_data *data)
|
||||
{
|
||||
int i = 0, offset = 0;
|
||||
unsigned int interval;
|
||||
|
||||
BT_DBG("len %d mtu %d", len, mtu);
|
||||
|
||||
/* For mSBC ALT 6 settings some Realtek chips need to transmit the data
|
||||
* continuously without the zero length of USB packets.
|
||||
*/
|
||||
if (btrealtek_test_flag(data->hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP))
|
||||
goto ignore_usb_alt6_packet_flow;
|
||||
|
||||
/* For mSBC ALT 6 setting the host will send the packet at continuous
|
||||
* flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting
|
||||
* 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets.
|
||||
* To maintain the rate we send 63bytes of usb packets alternatively for
|
||||
* 7ms and 8ms to maintain the rate as 7.5ms.
|
||||
*/
|
||||
if (data->usb_alt6_packet_flow) {
|
||||
interval = 7;
|
||||
data->usb_alt6_packet_flow = false;
|
||||
} else {
|
||||
interval = 6;
|
||||
data->usb_alt6_packet_flow = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < interval; i++) {
|
||||
urb->iso_frame_desc[i].offset = offset;
|
||||
urb->iso_frame_desc[i].length = offset;
|
||||
}
|
||||
|
||||
ignore_usb_alt6_packet_flow:
|
||||
if (len && i < BTUSB_MAX_ISOC_FRAMES) {
|
||||
urb->iso_frame_desc[i].offset = offset;
|
||||
urb->iso_frame_desc[i].length = len;
|
||||
i++;
|
||||
}
|
||||
|
||||
urb->number_of_packets = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
|
||||
{
|
||||
int i, offset = 0;
|
||||
@@ -675,6 +768,12 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
|
||||
pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 2, 14)
|
||||
usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
|
||||
hdev, data->isoc_rx_ep->bInterval);
|
||||
|
||||
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
|
||||
#else
|
||||
urb->dev = data->udev;
|
||||
urb->pipe = pipe;
|
||||
urb->context = hdev;
|
||||
@@ -684,6 +783,7 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
|
||||
urb->transfer_buffer = buf;
|
||||
urb->transfer_buffer_length = size;
|
||||
#endif
|
||||
|
||||
__fill_isoc_descriptor(urb, size,
|
||||
le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
|
||||
@@ -734,8 +834,8 @@ static void btusb_isoc_tx_complete(struct urb *urb)
|
||||
struct sk_buff *skb = urb->context;
|
||||
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
||||
|
||||
RTKBT_DBG("%s: urb %p status %d count %d",__func__,
|
||||
urb, urb->status, urb->actual_length);
|
||||
RTKBT_DBG("%s: urb %p status %d count %d", __func__,
|
||||
urb, urb->status, urb->actual_length);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
goto done;
|
||||
@@ -751,6 +851,49 @@ done:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static int rtl_read_iso_handle_range(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct __rp {
|
||||
u8 status;
|
||||
u8 min_handle[2];
|
||||
} *rp;
|
||||
int ret = -EIO;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfdab, 0, NULL, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
|
||||
/* FIXME: if the return status is not zero, __hci_cmd_sync() would
|
||||
* return an error and we would not reach here.
|
||||
*/
|
||||
if (skb->data[0]) {
|
||||
RTKBT_ERR("%s: Read failed, status %0x", hdev->name,
|
||||
skb->data[0]);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (skb->len < sizeof(*rp)) {
|
||||
RTKBT_WARN("%s: The len %u of rp is too short", __func__,
|
||||
skb->len);
|
||||
goto err;
|
||||
}
|
||||
|
||||
rp = (void *)skb->data;
|
||||
iso_min_conn_handle = (u16)rp->min_handle[1] << 8 | rp->min_handle[0];
|
||||
RTKBT_DBG("ISO handle range (handle >= %04x)", iso_min_conn_handle);
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int btusb_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = GET_DRV_DATA(hdev);
|
||||
@@ -775,6 +918,10 @@ static int btusb_open(struct hci_dev *hdev)
|
||||
goto failed;
|
||||
/*******************************/
|
||||
|
||||
err = setup_btrealtek_flag(data->intf, hdev);
|
||||
if (err < 0)
|
||||
RTKBT_WARN("setup_btrealtek_flag incorrect!");
|
||||
|
||||
RTKBT_INFO("%s set HCI UP RUNNING", __func__);
|
||||
if (test_and_set_bit(HCI_UP, &hdev->flags))
|
||||
goto done;
|
||||
@@ -817,6 +964,32 @@ failed:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static int btusb_setup(struct hci_dev *hdev)
|
||||
{
|
||||
rtl_read_iso_handle_range(hdev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
|
||||
static int btusb_shutdown(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "HCI reset during shutdown failed");
|
||||
return ret;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void btusb_stop_traffic(struct btusb_data *data)
|
||||
{
|
||||
mdelay(URB_CANCELING_DELAY_MS); // Added by Realtek
|
||||
@@ -920,8 +1093,152 @@ static const char pkt_ind[][8] = {
|
||||
[HCI_COMMAND_PKT] = "cmd",
|
||||
[HCI_ACLDATA_PKT] = "acl",
|
||||
[HCI_SCODATA_PKT] = "sco",
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
[HCI_ISODATA_PKT] = "iso",
|
||||
#endif
|
||||
};
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dr = kmalloc(sizeof(*dr), GFP_KERNEL);
|
||||
if (!dr) {
|
||||
usb_free_urb(urb);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
dr->bRequestType = data->cmdreq_type;
|
||||
dr->bRequest = 0;
|
||||
dr->wIndex = 0;
|
||||
dr->wValue = 0;
|
||||
dr->wLength = __cpu_to_le16(skb->len);
|
||||
|
||||
pipe = usb_sndctrlpipe(data->udev, 0x00);
|
||||
|
||||
usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
|
||||
skb->data, skb->len, btusb_tx_complete, skb);
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
if (!data->bulk_tx_ep)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress);
|
||||
|
||||
usb_fill_bulk_urb(urb, data->udev, pipe,
|
||||
skb->data, skb->len, btusb_tx_complete, skb);
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
if (!data->isoc_tx_ep)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);
|
||||
|
||||
usb_fill_int_urb(urb, data->udev, pipe,
|
||||
skb->data, skb->len, btusb_isoc_tx_complete,
|
||||
skb, data->isoc_tx_ep->bInterval);
|
||||
|
||||
urb->transfer_flags = URB_ISO_ASAP;
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
if (data->isoc_altsetting == 6)
|
||||
__fill_isoc_descriptor_msbc(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize),
|
||||
data);
|
||||
else
|
||||
__fill_isoc_descriptor(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
|
||||
#else
|
||||
__fill_isoc_descriptor(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
|
||||
#endif
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
usb_anchor_urb(urb, &data->tx_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
if (err != -EPERM && err != -ENODEV)
|
||||
RTKBT_ERR("%s urb %p submission failed (%d)",
|
||||
hdev->name, urb, -err);
|
||||
kfree(urb->setup_packet);
|
||||
usb_unanchor_urb(urb);
|
||||
} else {
|
||||
usb_mark_last_busy(data->udev);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
bool suspending;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
suspending = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!suspending)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
if (!suspending)
|
||||
return submit_tx_urb(hdev, urb);
|
||||
|
||||
usb_anchor_urb(urb, &data->deferred);
|
||||
schedule_work(&data->waker);
|
||||
|
||||
usb_free_urb(urb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
@@ -931,14 +1248,20 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
||||
#endif
|
||||
|
||||
struct urb *urb;
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
|
||||
struct btusb_data *data = GET_DRV_DATA(hdev);
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
int err;
|
||||
#endif
|
||||
|
||||
//RTKBT_DBG("%s", hdev->name);
|
||||
// RTKBT_DBG("%s", hdev->name);
|
||||
|
||||
/* After Kernel version 4.4.0, move the check into the
|
||||
* hci_send_frame function before calling hdev->send
|
||||
*/
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
|
||||
/* If the parameter is wrong, the hdev isn't the correct
|
||||
* one. Then no HCI commands can be sent.
|
||||
@@ -946,13 +1269,15 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
RTKBT_ERR("HCI is not running");
|
||||
return -EBUSY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Before kernel/hci version 3.13.0, the skb->dev is set before
|
||||
* entering btusb_send_frame(). So there is no need to set it here.
|
||||
*
|
||||
* The skb->dev will be used in the callbacks when urb transfer
|
||||
* completes. See btusb_tx_complete() and btusb_isoc_tx_complete() */
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) && \
|
||||
HCI_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
|
||||
skb->dev = (void *)hdev;
|
||||
#endif
|
||||
|
||||
@@ -963,6 +1288,14 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
#ifdef BTCOEX
|
||||
rtk_btcoex_parse_cmd(skb->data, skb->len);
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
urb = alloc_ctrl_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.cmd_tx++;
|
||||
return submit_or_queue_tx_urb(hdev, urb);
|
||||
#else
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
@@ -988,11 +1321,24 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
hdev->stat.cmd_tx++;
|
||||
break;
|
||||
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
case HCI_ISODATA_PKT:
|
||||
#endif
|
||||
case HCI_ACLDATA_PKT:
|
||||
print_acl(skb, 1);
|
||||
#ifdef BTCOEX
|
||||
rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
|
||||
if(bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT)
|
||||
rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
urb = alloc_bulk_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.acl_tx++;
|
||||
return submit_or_queue_tx_urb(hdev, urb);
|
||||
#else
|
||||
if (!data->bulk_tx_ep)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1009,7 +1355,22 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
hdev->stat.acl_tx++;
|
||||
break;
|
||||
|
||||
#endif
|
||||
case HCI_SCODATA_PKT:
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
if (hci_conn_num(hdev, SCO_LINK) < 1)
|
||||
return -ENODEV;
|
||||
|
||||
urb = alloc_isoc_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.sco_tx++;
|
||||
return submit_tx_urb(hdev, urb);
|
||||
}
|
||||
|
||||
return -EILSEQ;
|
||||
#else
|
||||
if (!data->isoc_tx_ep || SCO_NUM < 1)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1035,6 +1396,7 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
|
||||
default:
|
||||
return -EILSEQ;
|
||||
|
||||
}
|
||||
|
||||
err = inc_tx(data);
|
||||
@@ -1057,12 +1419,14 @@ skip_waking:
|
||||
} else {
|
||||
usb_mark_last_busy(data->udev);
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
|
||||
done:
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
|
||||
static void btusb_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
@@ -1181,6 +1545,9 @@ static struct usb_host_interface *btusb_find_altsetting(struct btusb_data *data,
|
||||
|
||||
BT_DBG("Looking for Alt no :%d", alt);
|
||||
|
||||
if (!intf)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < intf->num_altsetting; i++) {
|
||||
if (intf->altsetting[i].desc.bAlternateSetting == alt)
|
||||
return &intf->altsetting[i];
|
||||
@@ -1221,7 +1588,14 @@ static void btusb_work(struct work_struct *work)
|
||||
new_alts = data->sco_num;
|
||||
}
|
||||
} else if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_TRANSP) {
|
||||
new_alts = btusb_find_altsetting(data, 6) ? 6 : 1;
|
||||
if (btusb_find_altsetting(data, 6))
|
||||
new_alts = 6;
|
||||
else if (btusb_find_altsetting(data, 3) &&
|
||||
hdev->sco_mtu >= 72 &&
|
||||
test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags))
|
||||
new_alts = 3;
|
||||
else
|
||||
new_alts = 1;
|
||||
}
|
||||
|
||||
if (btusb_switch_alt_setting(hdev, new_alts) < 0)
|
||||
@@ -1421,7 +1795,7 @@ static int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
result = __rtk_send_hci_cmd(udev, cmd, 3);
|
||||
kfree(cmd);
|
||||
msleep(100); /* From FW colleague's recommendation */
|
||||
result = download_lps_patch(intf);
|
||||
result = download_special_patch(intf, "lps_");
|
||||
#endif
|
||||
|
||||
#ifdef RTKBT_TV_POWERON_WHITELIST
|
||||
@@ -1540,13 +1914,23 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
struct usb_device *udev;
|
||||
udev = interface_to_usbdev(intf);
|
||||
|
||||
RTKBT_DBG("btusb_probe intf->cur_altsetting->desc.bInterfaceNumber %d",
|
||||
RTKBT_INFO("btusb_probe intf->cur_altsetting->desc.bInterfaceNumber %d",
|
||||
intf->cur_altsetting->desc.bInterfaceNumber);
|
||||
|
||||
/* interface numbers are hardcoded in the spec */
|
||||
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (!id->driver_info) {
|
||||
const struct usb_device_id *match;
|
||||
|
||||
match = usb_match_id(intf, blacklist_table);
|
||||
if (match)
|
||||
id = match;
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
flag1 = device_can_wakeup(&udev->dev);
|
||||
flag2 = device_may_wakeup(&udev->dev);
|
||||
@@ -1636,6 +2020,13 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->flush = btusb_flush;
|
||||
hdev->send = btusb_send_frame;
|
||||
hdev->notify = btusb_notify;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
hdev->setup = btusb_setup;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
|
||||
hdev->shutdown = btusb_shutdown;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
|
||||
hci_set_drvdata(hdev, data);
|
||||
@@ -1645,10 +2036,14 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->owner = THIS_MODULE;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
set_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags);
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
|
||||
if (!reset)
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
RTKBT_DBG("set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);");
|
||||
#endif
|
||||
|
||||
/* Interface numbers are hardcoded in the specification */
|
||||
|
||||
Reference in New Issue
Block a user