mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +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
(cherry picked from commit 3d15bb40b5)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3233099
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>
This commit is contained in:
committed by
Jon Hunter
parent
13859c153d
commit
1f6ba48285
@@ -1,24 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
CONFIG_BTUSB_AUTOSUSPEND = n
|
||||
CONFIG_BTUSB_WAKEUP_HOST = n
|
||||
CONFIG_BTCOEX = y
|
||||
|
||||
ifeq ($(CONFIG_BTUSB_AUTOSUSPEND), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTUSB_AUTOSUSPEND
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BTUSB_WAKEUP_HOST), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTUSB_WAKEUP_HOST
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BTCOEX), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTCOEX
|
||||
endif
|
||||
|
||||
ifndef CONFIG_TEGRA_SYSTEM_TYPE_ACK
|
||||
obj-m := rtk_btusb.o
|
||||
rtk_btusb-objs := rtk_coex.o \
|
||||
rtk_misc.o \
|
||||
rtk_bt.o
|
||||
endif
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m := rtk_btusb.o
|
||||
rtk_btusb-y = rtk_coex.o rtk_misc.o rtk_bt.o
|
||||
else
|
||||
PWD := $(shell pwd)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.mod.c *.mod.o *.ko *.symvers *.order *.a
|
||||
|
||||
endif
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
// 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
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_BT_H__
|
||||
#define __RTK_BT_H__
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -30,14 +41,17 @@
|
||||
/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
|
||||
#define HCI_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#ifdef CONFIG_BTCOEX
|
||||
#define CONFIG_BTCOEX 1
|
||||
#define CONFIG_BTUSB_WAKEUP_HOST 0
|
||||
|
||||
#if CONFIG_BTCOEX
|
||||
#define BTCOEX
|
||||
#endif
|
||||
|
||||
/***********************************
|
||||
** Realtek - For rtk_btusb driver **
|
||||
***********************************/
|
||||
#ifdef CONFIG_BTUSB_WAKEUP_HOST
|
||||
#if CONFIG_BTUSB_WAKEUP_HOST
|
||||
#define BTUSB_WAKEUP_HOST
|
||||
#endif
|
||||
|
||||
@@ -84,6 +98,7 @@ int btusb_send_frame(struct sk_buff *skb);
|
||||
#define BTUSB_ISOC_RUNNING 2
|
||||
#define BTUSB_SUSPENDING 3
|
||||
#define BTUSB_DID_ISO_RESUME 4
|
||||
#define BTUSB_USE_ALT3_FOR_WBS 15
|
||||
|
||||
struct btusb_data {
|
||||
struct hci_dev *hdev;
|
||||
@@ -125,6 +140,7 @@ struct btusb_data {
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
unsigned int air_mode;
|
||||
bool usb_alt6_packet_flow;
|
||||
#endif
|
||||
int isoc_altsetting;
|
||||
int suspend_count;
|
||||
@@ -136,6 +152,3 @@ struct btusb_data {
|
||||
struct notifier_block shutdown_notifier;
|
||||
void *context;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __RTK_BT_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,23 @@
|
||||
// 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
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_COEX_H__
|
||||
#define __RTK_COEX_H__
|
||||
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
@@ -38,6 +49,13 @@
|
||||
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
|
||||
#define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a
|
||||
|
||||
#define HCI_EV_LE_CIS_EST 0x19
|
||||
#define HCI_EV_LE_CREATE_BIG_CPL 0x1b
|
||||
#define HCI_EV_LE_TERM_BIG_CPL 0x1c
|
||||
#define HCI_EV_LE_BIG_SYNC_EST 0x1d
|
||||
#define HCI_EV_LE_BIG_SYNC_LOST 0x1e
|
||||
#define HCI_EV_LE_REMOVE_ISO_DATA_PATH 0x23
|
||||
|
||||
//vendor cmd to fw
|
||||
#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_LEGACY_COMMAND 0xfc19
|
||||
@@ -140,7 +158,11 @@ enum {
|
||||
profile_hogp = 5,
|
||||
profile_voice = 6,
|
||||
profile_sink = 7,
|
||||
profile_max = 8
|
||||
profile_lea_src = 8,
|
||||
profile_opprx = 9,
|
||||
profile_lea_snk = 10,
|
||||
profile_a2dpsink = 11,
|
||||
profile_max = 12
|
||||
};
|
||||
|
||||
#define A2DP_SIGNAL 0x01
|
||||
@@ -159,7 +181,10 @@ typedef struct {
|
||||
//profile info for each connection
|
||||
typedef struct rtl_hci_conn {
|
||||
struct list_head list;
|
||||
uint16_t handle;
|
||||
u16 big_handle;
|
||||
u16 handle;
|
||||
u8 direction;
|
||||
u8 remove_path;
|
||||
struct delayed_work a2dp_count_work;
|
||||
struct delayed_work pan_count_work;
|
||||
struct delayed_work hogp_count_work;
|
||||
@@ -170,7 +195,7 @@ typedef struct rtl_hci_conn {
|
||||
uint8_t type; // 0:l2cap, 1:sco/esco, 2:le
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[8];
|
||||
int8_t profile_refcount[profile_max];
|
||||
} rtk_conn_prof, *prtk_conn_prof;
|
||||
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
@@ -204,21 +229,40 @@ struct rtl_btinfo_ctl {
|
||||
};
|
||||
#endif /* RTB_SOFTWARE_MAILBOX */
|
||||
|
||||
#define HCI_PT_CMD 0x01
|
||||
#define HCI_PT_EVT 0x02
|
||||
#define HCI_PT_L2SIG_RX 0x03
|
||||
#define HCI_PT_L2SIG_TX 0x04
|
||||
#define HCI_PT_L2DATA_RX 0x05
|
||||
#define HCI_PT_L2DATA_TX 0x06
|
||||
|
||||
struct rtl_hci_hdr {
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
#define MAX_LEN_OF_HCI_EV 32
|
||||
#define NUM_RTL_HCI_EV 32
|
||||
struct rtl_hci_ev {
|
||||
__u8 data[MAX_LEN_OF_HCI_EV];
|
||||
__u16 len;
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
|
||||
/* private */
|
||||
__u8 data[MAX_LEN_OF_HCI_EV];
|
||||
};
|
||||
|
||||
#define L2_MAX_SUBSEC_LEN 128
|
||||
#define L2_MAX_PKTS 16
|
||||
struct rtl_l2_buff {
|
||||
__u8 data[L2_MAX_SUBSEC_LEN];
|
||||
__u16 len;
|
||||
__u16 out;
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
|
||||
/* private */
|
||||
__u8 data[L2_MAX_SUBSEC_LEN];
|
||||
__u16 out;
|
||||
};
|
||||
|
||||
struct rtl_coex_struct {
|
||||
@@ -236,18 +280,18 @@ struct rtl_coex_struct {
|
||||
struct delayed_work sock_work;
|
||||
#endif
|
||||
struct workqueue_struct *fw_wq;
|
||||
struct workqueue_struct *timer_wq;
|
||||
struct delayed_work fw_work;
|
||||
struct delayed_work l2_work;
|
||||
struct delayed_work cmd_work;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
struct sock *sk;
|
||||
#endif
|
||||
struct urb *urb;
|
||||
spinlock_t spin_lock_sock;
|
||||
spinlock_t spin_lock_profile;
|
||||
struct mutex profile_mutex;
|
||||
struct mutex conn_mutex;
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[8];
|
||||
int8_t profile_refcount[profile_max];
|
||||
uint8_t ispairing;
|
||||
uint8_t isinquirying;
|
||||
uint8_t ispaging;
|
||||
@@ -266,11 +310,8 @@ struct rtl_coex_struct {
|
||||
uint8_t wifi_on;
|
||||
uint8_t sock_open;
|
||||
#endif
|
||||
unsigned long cmd_last_tx;
|
||||
|
||||
/* hci ev buff */
|
||||
struct list_head ev_used_list;
|
||||
struct list_head ev_free_list;
|
||||
unsigned long cmd_last_tx;
|
||||
|
||||
spinlock_t rxlock;
|
||||
__u8 pkt_type;
|
||||
@@ -279,16 +320,18 @@ struct rtl_coex_struct {
|
||||
__u16 elen;
|
||||
__u8 back_buff[HCI_MAX_EVENT_SIZE];
|
||||
|
||||
/* l2cap rx buff */
|
||||
struct list_head l2_used_list;
|
||||
struct list_head ev_free_list;
|
||||
struct list_head l2_free_list;
|
||||
struct list_head hci_pkt_list;
|
||||
|
||||
/* buff addr and size */
|
||||
spinlock_t buff_lock;
|
||||
unsigned long pages_addr;
|
||||
unsigned long buff_size;
|
||||
|
||||
#define RTL_COEX_RUNNING (1 << 0)
|
||||
#define RTL_COEX_RUNNING 1
|
||||
#define RTL_COEX_PKT_COUNTING 2
|
||||
#define RTL_COEX_CONN_REMOVING 3
|
||||
unsigned long flags;
|
||||
|
||||
};
|
||||
@@ -363,6 +406,3 @@ void rtk_btcoex_close(void);
|
||||
void rtk_btcoex_probe(struct hci_dev *hdev);
|
||||
void rtk_btcoex_init(void);
|
||||
void rtk_btcoex_exit(void);
|
||||
|
||||
|
||||
#endif /* __RTK_COEX_H__ */
|
||||
@@ -1,8 +1,22 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB download firmware 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>
|
||||
@@ -30,6 +44,7 @@
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
@@ -54,7 +69,7 @@ struct cfg_list_item {
|
||||
struct list_head list;
|
||||
u16 offset;
|
||||
u8 len;
|
||||
u8 data[];
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
static struct list_head list_configs;
|
||||
@@ -84,6 +99,7 @@ static struct list_head list_extracfgs;
|
||||
#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d
|
||||
#define HCI_VENDOR_READ_LMP_VERISION 0x1001
|
||||
#define HCI_VENDOR_READ_CMD 0xfc61
|
||||
#define HCI_VENDOR_WRITE_CMD 0xfc62
|
||||
|
||||
#define ROM_LMP_NONE 0x0000
|
||||
#define ROM_LMP_8723a 0x1200
|
||||
@@ -92,6 +108,9 @@ static struct list_head list_extracfgs;
|
||||
#define ROM_LMP_8761a 0X8761
|
||||
#define ROM_LMP_8822b 0X8822
|
||||
#define ROM_LMP_8852a 0x8852
|
||||
#define ROM_LMP_8851b 0x8851
|
||||
#define ROM_LMP_8922a 0x8922
|
||||
#define ROM_LMP_8723c 0x8703
|
||||
|
||||
#define PATCH_SNIPPETS 0x01
|
||||
#define PATCH_DUMMY_HEADER 0x02
|
||||
@@ -163,41 +182,30 @@ static const uint8_t RTK_EPATCH_SIGNATURE_NEW[8] =
|
||||
//Extension Section IGNATURE:0x77FD0451
|
||||
static const uint8_t Extension_Section_SIGNATURE[4] = { 0x51, 0x04, 0xFD, 0x77 };
|
||||
|
||||
static uint16_t project_id[] = {
|
||||
ROM_LMP_8723a,
|
||||
ROM_LMP_8723b,
|
||||
ROM_LMP_8821a,
|
||||
ROM_LMP_8761a,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b,
|
||||
ROM_LMP_8723b, /* RTL8723DU */
|
||||
ROM_LMP_8821a, /* RTL8821CU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b, /* RTL8822CU */
|
||||
ROM_LMP_8761a, /* index 14 for 8761BU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8852a, /* index 18 for 8852AU */
|
||||
ROM_LMP_8723b, /* index 19 for 8723FU */
|
||||
ROM_LMP_8852a, /* index 20 for 8852BU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8852a, /* index 25 for 8852CU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b, /* index 33 for 8822EU */
|
||||
static const struct {
|
||||
__u16 lmp_subver;
|
||||
__u8 id;
|
||||
} project_id_to_lmp_subver[] = {
|
||||
{ ROM_LMP_8723a, 0 },
|
||||
{ ROM_LMP_8723b, 1 },
|
||||
{ ROM_LMP_8821a, 2 },
|
||||
{ ROM_LMP_8761a, 3 },
|
||||
{ ROM_LMP_8723c, 7 },
|
||||
{ ROM_LMP_8822b, 8 }, /* 8822B */
|
||||
{ ROM_LMP_8723b, 9 }, /* 8723D */
|
||||
{ ROM_LMP_8821a, 10 }, /* 8821C */
|
||||
{ ROM_LMP_8822b, 13 }, /* 8822C */
|
||||
{ ROM_LMP_8761a, 14 }, /* 8761B */
|
||||
{ ROM_LMP_8852a, 18 }, /* 8852A */
|
||||
{ ROM_LMP_8723b, 19 }, /* 8733B */
|
||||
{ ROM_LMP_8852a, 20 }, /* 8852B */
|
||||
{ ROM_LMP_8852a, 25 }, /* 8852C */
|
||||
{ ROM_LMP_8822b, 33 }, /* 8822E */
|
||||
{ ROM_LMP_8851b, 36 }, /* 8851B */
|
||||
{ ROM_LMP_8852a, 42 }, /* 8852D */
|
||||
{ ROM_LMP_8922a, 44 }, /* 8922A */
|
||||
{ ROM_LMP_8852a, 47 }, /* 8852BT */
|
||||
{ ROM_LMP_8761a, 51 }, /* 8761C */
|
||||
};
|
||||
|
||||
enum rtk_endpoit {
|
||||
@@ -215,10 +223,16 @@ enum rtk_endpoit {
|
||||
#define RTL8822CU 0x73
|
||||
#define RTL8761BU 0x74
|
||||
#define RTL8852AU 0x75
|
||||
#define RTL8723FU 0x76
|
||||
#define RTL8733BU 0x76
|
||||
#define RTL8852BU 0x77
|
||||
#define RTL8852CU 0x78
|
||||
#define RTL8822EU 0x79
|
||||
#define RTL8851BU 0x7A
|
||||
#define RTL8852DU 0x7B
|
||||
#define RTL8922AU 0x7C
|
||||
#define RTL8852BTU 0x7D
|
||||
#define RTL8761CU 0x80
|
||||
#define RTL8723CU 0x81
|
||||
|
||||
typedef struct {
|
||||
uint16_t prod_id;
|
||||
@@ -279,7 +293,7 @@ static uint8_t g_key_id = 0;
|
||||
|
||||
static dev_data *dev_data_find(struct usb_interface *intf);
|
||||
static patch_info *get_patch_entry(struct usb_device *udev);
|
||||
static int load_firmware(dev_data * dev_entry, uint8_t ** buff);
|
||||
static int load_firmware(dev_data *dev_entry, xchange_data *xdata);
|
||||
static void init_xdata(xchange_data * xdata, dev_data * dev_entry);
|
||||
static int check_fw_version(xchange_data * xdata);
|
||||
static int download_data(xchange_data * xdata);
|
||||
@@ -344,6 +358,8 @@ static patch_info fw_patch_table[] = {
|
||||
{0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU */
|
||||
{0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU for LiteOn */
|
||||
|
||||
{0xb703, 0x8703, "mp_rtl8723cu_fw", "rtl8723cu_fw", "rtl8723cu_config", RTL8723CU}, /* RTL8723CU */
|
||||
|
||||
{0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
|
||||
{0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
|
||||
{0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
|
||||
@@ -377,6 +393,7 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
|
||||
{0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
|
||||
{0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU */
|
||||
{0x053b, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU for Epson*/
|
||||
|
||||
{0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
|
||||
{0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
|
||||
@@ -405,6 +422,7 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE-VS */
|
||||
|
||||
{0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BU only */
|
||||
{0x876e, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BUE */
|
||||
{0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU */
|
||||
{0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU BT only */
|
||||
|
||||
@@ -425,14 +443,13 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
|
||||
{0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
{0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
{0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
{0xb733, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
{0xb73a, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
{0xf72b, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
|
||||
{0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", RTL8852BU}, /* RTL8851AU */
|
||||
{0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BU */
|
||||
@@ -453,6 +470,7 @@ static patch_info fw_patch_table[] = {
|
||||
{0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BE */
|
||||
|
||||
{0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CU */
|
||||
{0xc85d, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CU */
|
||||
{0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
@@ -464,6 +482,23 @@ static patch_info fw_patch_table[] = {
|
||||
{0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
|
||||
{0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
|
||||
|
||||
{0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", RTL8851BU}, /* RTL8851BU */
|
||||
|
||||
{0xd85a, 0x8852, "mp_rtl8852du_fw", "rtl8852du_fw", "rtl8852du_config", RTL8852DU}, /* RTL8852DU */
|
||||
|
||||
{0x892a, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AU */
|
||||
{0x8922, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa890, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa891, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa892, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xd922, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xb85f, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
|
||||
{0xc852, 0x8852, "mp_rtl8852btu_fw", "rtl8852btu_fw", "rtl8852btu_config", RTL8852BTU}, /* RTL8852BTU */
|
||||
{0x8520, 0x8852, "mp_rtl8852btu_fw", "rtl8852btu_fw", "rtl8852btu_config", RTL8852BTU}, /* RTL8852BTE */
|
||||
|
||||
{0xc761, 0x8761, "mp_rtl8761cu_fw", "rtl8761cu_mx_fw", "rtl8761cu_mx_config", RTL8761CU}, /* RTL8761CU */
|
||||
|
||||
/* NOTE: must append patch entries above the null entry */
|
||||
{0, 0, NULL, NULL, NULL, 0}
|
||||
};
|
||||
@@ -746,6 +781,7 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
max_patch_size = 25 * 1024;
|
||||
break;
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8821CU:
|
||||
@@ -754,10 +790,11 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
case RTL8852AU:
|
||||
max_patch_size = 0x114D0 + 529; /* 69.2KB */
|
||||
break;
|
||||
case RTL8723FU:
|
||||
case RTL8733BU:
|
||||
max_patch_size = 0xC4Cf + 529; /* 49.2KB */
|
||||
break;
|
||||
case RTL8852BU:
|
||||
case RTL8851BU:
|
||||
max_patch_size = 0x104D0 + 529; /* 65KB */
|
||||
break;
|
||||
case RTL8852CU:
|
||||
@@ -766,6 +803,18 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
case RTL8822EU:
|
||||
max_patch_size = 0x24620 + 529; /* 145KB */
|
||||
break;
|
||||
case RTL8852DU:
|
||||
max_patch_size = 0x20D90 + 529; /* 131KB */
|
||||
break;
|
||||
case RTL8922AU:
|
||||
max_patch_size = 0x23810 + 529; /* 142KB */
|
||||
break;
|
||||
case RTL8852BTU:
|
||||
max_patch_size = 0x27E00 + 529; /* 159.5KB */
|
||||
break;
|
||||
case RTL8761CU:
|
||||
max_patch_size = 1024 * 1024; /* 1MB */
|
||||
break;
|
||||
default:
|
||||
max_patch_size = 40 * 1024;
|
||||
break;
|
||||
@@ -774,11 +823,64 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
return max_patch_size;
|
||||
}
|
||||
|
||||
static int rtk_vendor_write(dev_data * dev_entry)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
xchange_data *xdata = NULL;
|
||||
unsigned char cmd_buf[] = {0x31, 0x90, 0xd0, 0x29, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00};
|
||||
|
||||
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
|
||||
if (NULL == xdata) {
|
||||
ret_val = 0xFE;
|
||||
RTKBT_DBG("NULL == xdata");
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_xdata(xdata, dev_entry);
|
||||
|
||||
xdata->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_WRITE_CMD);
|
||||
xdata->cmd_hdr->plen = 9;
|
||||
memcpy(xdata->send_pkt, &(xdata->cmd_hdr->opcode), 2);
|
||||
memcpy(xdata->send_pkt+2, &(xdata->cmd_hdr->plen), 1);
|
||||
|
||||
memcpy(xdata->send_pkt+3, cmd_buf, sizeof(cmd_buf));
|
||||
|
||||
xdata->pkt_len = CMD_HDR_LEN + 9;
|
||||
|
||||
ret_val = send_hci_cmd(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("%s: Failed to send HCI command.", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret_val = rcv_hci_evt(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("%s: Failed to receive HCI event.", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret_val = 0;
|
||||
end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
kfree(xdata->send_pkt);
|
||||
if (xdata->rcv_pkt)
|
||||
kfree(xdata->rcv_pkt);
|
||||
kfree(xdata);
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int check_fw_chip_ver(dev_data * dev_entry, xchange_data * xdata)
|
||||
{
|
||||
int ret_val;
|
||||
uint16_t chip = 0;
|
||||
uint16_t chip_ver = 0;
|
||||
uint16_t lmp_subver, hci_rev;
|
||||
patch_info *patch_entry;
|
||||
struct hci_rp_read_local_version *read_ver_rsp;
|
||||
|
||||
chip = rtk_vendor_read(dev_entry, READ_CHIP_TYPE);
|
||||
if(chip == 0x8822) {
|
||||
@@ -801,9 +903,16 @@ static int check_fw_chip_ver(dev_data * dev_entry, xchange_data * xdata)
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
}
|
||||
return ret_val;
|
||||
} else {
|
||||
patch_entry = xdata->dev_entry->patch_entry;
|
||||
read_ver_rsp = (struct hci_rp_read_local_version *)(xdata->rsp_para);
|
||||
lmp_subver = le16_to_cpu(read_ver_rsp->lmp_subver);
|
||||
hci_rev = le16_to_cpu(read_ver_rsp->hci_rev);
|
||||
if (lmp_subver == 0x8852 && hci_rev == 0x000d)
|
||||
ret_val = rtk_vendor_write(dev_entry);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int download_patch(struct usb_interface *intf)
|
||||
@@ -836,7 +945,7 @@ int download_patch(struct usb_interface *intf)
|
||||
if (ret_val != 0 )
|
||||
goto patch_end;
|
||||
|
||||
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
|
||||
xdata->fw_len = load_firmware(dev_entry, xdata);
|
||||
if (xdata->fw_len <= 0) {
|
||||
RTKBT_ERR("load firmware failed!");
|
||||
ret_val = -1;
|
||||
@@ -875,7 +984,7 @@ int download_patch(struct usb_interface *intf)
|
||||
|
||||
ret_val = 0;
|
||||
patch_fail:
|
||||
kfree(fw_buf);
|
||||
vfree(fw_buf);
|
||||
patch_end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
@@ -893,7 +1002,7 @@ patch_end:
|
||||
* -1: error
|
||||
* 0: download patch successfully
|
||||
* >0: patch already exists */
|
||||
int download_lps_patch(struct usb_interface *intf)
|
||||
int download_special_patch(struct usb_interface *intf, const char *special_name)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
patch_info *pinfo;
|
||||
@@ -935,15 +1044,18 @@ int download_lps_patch(struct usb_interface *intf)
|
||||
}
|
||||
goto patch_end;
|
||||
}
|
||||
|
||||
memset(name1, 0, sizeof(name1));
|
||||
memset(name2, 0, sizeof(name2));
|
||||
origin_name1 = dev_entry->patch_entry->patch_name;
|
||||
origin_name2 = dev_entry->patch_entry->config_name;
|
||||
snprintf(name1, sizeof(name1), "lps_%s", origin_name1);
|
||||
snprintf(name2, sizeof(name2), "lps_%s", origin_name2);
|
||||
memcpy(name1, special_name, strlen(special_name));
|
||||
strncat(name1, origin_name1, sizeof(name1) - 1 - strlen(special_name));
|
||||
memcpy(name2, special_name, strlen(special_name));
|
||||
strncat(name2, origin_name2, sizeof(name2) - 1 - strlen(special_name));
|
||||
dev_entry->patch_entry->patch_name = name1;
|
||||
dev_entry->patch_entry->config_name = name2;
|
||||
RTKBT_INFO("Loading %s and %s", name1, name2);
|
||||
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
|
||||
xdata->fw_len = load_firmware(dev_entry, xdata);
|
||||
dev_entry->patch_entry->patch_name = origin_name1;
|
||||
dev_entry->patch_entry->config_name = origin_name2;
|
||||
if (xdata->fw_len <= 0) {
|
||||
@@ -955,11 +1067,13 @@ int download_lps_patch(struct usb_interface *intf)
|
||||
fw_buf = xdata->fw_data;
|
||||
|
||||
pinfo = dev_entry->patch_entry;
|
||||
/*
|
||||
if (!pinfo) {
|
||||
RTKBT_ERR("%s: No patch entry", __func__);
|
||||
result = -1;
|
||||
goto patch_fail;
|
||||
}
|
||||
*/
|
||||
max_patch_size = get_max_patch_size(pinfo->chip_type);
|
||||
if (xdata->fw_len > max_patch_size) {
|
||||
result = -1;
|
||||
@@ -998,6 +1112,39 @@ patch_end:
|
||||
}
|
||||
#endif
|
||||
|
||||
int setup_btrealtek_flag(struct usb_interface *intf, struct hci_dev *hdev)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
patch_info *pinfo;
|
||||
int ret_val = 0;
|
||||
|
||||
dev_entry = dev_data_find(intf);
|
||||
if (NULL == dev_entry) {
|
||||
ret_val = -1;
|
||||
RTKBT_ERR("%s: NULL == dev_entry", __func__);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
pinfo = dev_entry->patch_entry;
|
||||
if (!pinfo) {
|
||||
RTKBT_ERR("%s: No patch entry", __func__);
|
||||
ret_val = -1;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
switch (pinfo->chip_type){
|
||||
case RTL8852CU:
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
int set_scan(struct usb_interface *intf)
|
||||
{
|
||||
@@ -1045,7 +1192,7 @@ end:
|
||||
|
||||
dev_data *dev_data_find(struct usb_interface * intf)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
dev_data *dev_entry = NULL;
|
||||
|
||||
list_for_each_entry(dev_entry, &dev_data_list, list_node) {
|
||||
if (dev_entry->intf == intf) {
|
||||
@@ -1088,6 +1235,7 @@ static int is_mac(u8 chip_type, u16 offset)
|
||||
switch (chip_type) {
|
||||
case RTL8822BU:
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8821CU:
|
||||
if (offset == 0x0044)
|
||||
return 1;
|
||||
@@ -1095,10 +1243,15 @@ static int is_mac(u8 chip_type, u16 offset)
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8852AU:
|
||||
case RTL8723FU:
|
||||
case RTL8733BU:
|
||||
case RTL8852BU:
|
||||
case RTL8852CU:
|
||||
case RTL8822EU:
|
||||
case RTL8851BU:
|
||||
case RTL8852DU:
|
||||
case RTL8922AU:
|
||||
case RTL8852BTU:
|
||||
case RTL8761CU:
|
||||
if (offset == 0x0030)
|
||||
return 1;
|
||||
break;
|
||||
@@ -1116,15 +1269,21 @@ static uint16_t get_mac_offset(u8 chip_type)
|
||||
switch (chip_type) {
|
||||
case RTL8822BU:
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8821CU:
|
||||
return 0x0044;
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8852AU:
|
||||
case RTL8723FU:
|
||||
case RTL8733BU:
|
||||
case RTL8852BU:
|
||||
case RTL8852CU:
|
||||
case RTL8822EU:
|
||||
case RTL8851BU:
|
||||
case RTL8852DU:
|
||||
case RTL8922AU:
|
||||
case RTL8852BTU:
|
||||
case RTL8761CU:
|
||||
return 0x0030;
|
||||
case RTLPREVIOUS:
|
||||
return 0x003c;
|
||||
@@ -1452,14 +1611,12 @@ static uint8_t *rtb_get_patch_header(int *len,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
RTKBT_ERR("Wrong Opcode");
|
||||
goto wrong_opcode;
|
||||
RTKBT_INFO("Unknown Opcode. Ignore");
|
||||
}
|
||||
section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len);
|
||||
}
|
||||
*len = patch_len;
|
||||
|
||||
wrong_opcode:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1743,7 +1900,7 @@ static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
|
||||
xchange_data *xdata = NULL;
|
||||
unsigned char cmd_ct_buf[] = {0x10, 0x38, 0x04, 0x28, 0x80};
|
||||
unsigned char cmd_cv_buf[] = {0x10, 0x3A, 0x04, 0x28, 0x80};
|
||||
unsigned char cmd_sec_buf[] = {0x10, 0xA4, 0x0D, 0x00, 0xb0};
|
||||
unsigned char cmd_sec_buf[] = {0x10, 0xA4, 0xAD, 0x00, 0xb0};
|
||||
|
||||
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
|
||||
if (NULL == xdata) {
|
||||
@@ -1811,7 +1968,6 @@ static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
read_end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
@@ -1823,7 +1979,57 @@ read_end:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
static int needs_hci_upgrade(xchange_data *xdata, u8 *buf, u32 buf_len)
|
||||
{
|
||||
struct {
|
||||
u8 status;
|
||||
u8 subopcode;
|
||||
u8 ota;
|
||||
} __attribute__((packed)) *evt_params;
|
||||
#define UPG_DL_BLOCK_SIZE 128
|
||||
#define UPG_SUBCMD_CODE 0x01
|
||||
u8 len = UPG_DL_BLOCK_SIZE;
|
||||
u8 *cmd_params;
|
||||
int ret;
|
||||
|
||||
cmd_params = xdata->req_para;
|
||||
evt_params = (void *)xdata->rsp_para;
|
||||
xdata->cmd_hdr->opcode = cpu_to_le16(0xfdbb);
|
||||
if (buf_len < len)
|
||||
len = buf_len;
|
||||
xdata->cmd_hdr->plen = 1 + len;
|
||||
xdata->pkt_len = sizeof(*xdata->cmd_hdr) + xdata->cmd_hdr->plen;
|
||||
*cmd_params++ = UPG_SUBCMD_CODE;
|
||||
memcpy(cmd_params, buf, len);
|
||||
|
||||
ret = send_hci_cmd(xdata);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rcv_hci_evt(xdata);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (evt_params->status) {
|
||||
RTKBT_ERR("needs_hci_upgrade: status %02x", evt_params->status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (evt_params->subopcode != UPG_SUBCMD_CODE) {
|
||||
RTKBT_ERR("needs_hci_upgrade: return subopcode %02x",
|
||||
evt_params->subopcode);
|
||||
return -2;
|
||||
}
|
||||
|
||||
RTKBT_INFO("needs_hci_upgrade: state %02x", evt_params->ota);
|
||||
|
||||
return evt_params->ota;
|
||||
}
|
||||
|
||||
/* buff: points to the allocated buffer that stores extracted fw and config
|
||||
* This function returns the total length of extracted fw and config
|
||||
*/
|
||||
int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
struct usb_device *udev;
|
||||
@@ -1835,12 +2041,13 @@ int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
uint8_t need_download_fw = 1;
|
||||
uint16_t lmp_version;
|
||||
struct rtk_epatch_entry current_entry = { 0 };
|
||||
|
||||
struct list_head *pos, *next;
|
||||
struct patch_node *tmp;
|
||||
struct patch_node patch_node_hdr;
|
||||
int i;
|
||||
|
||||
RTKBT_DBG("load_firmware start");
|
||||
|
||||
udev = dev_entry->udev;
|
||||
patch_entry = dev_entry->patch_entry;
|
||||
lmp_version = patch_entry->lmp_sub;
|
||||
@@ -1853,16 +2060,13 @@ int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
ret_val = request_firmware(&fw, fw_name, &udev->dev);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("request_firmware error");
|
||||
fw_len = 0;
|
||||
kfree(config_file_buf);
|
||||
config_file_buf = NULL;
|
||||
goto fw_fail;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&patch_node_hdr.list);
|
||||
|
||||
epatch_buf = kzalloc(fw->size, GFP_KERNEL);
|
||||
if (NULL == epatch_buf)
|
||||
epatch_buf = vzalloc(fw->size);
|
||||
if (!epatch_buf)
|
||||
goto alloc_fail;
|
||||
|
||||
memcpy(epatch_buf, fw->data, fw->size);
|
||||
@@ -1874,137 +2078,174 @@ int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) == 0) {
|
||||
RTKBT_ERR("8723a Check signature error!");
|
||||
need_download_fw = 0;
|
||||
} else {
|
||||
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
|
||||
RTKBT_ERR("Can't alloc memory for fw&config");
|
||||
buf_len = -1;
|
||||
} else {
|
||||
RTKBT_DBG("8723a, fw copy direct");
|
||||
memcpy(buf, epatch_buf, fw->size);
|
||||
if (config_len) {
|
||||
memcpy(&buf[buf_len - config_len],
|
||||
config_file_buf, config_len);
|
||||
}
|
||||
}
|
||||
goto sign_err;
|
||||
}
|
||||
} else {
|
||||
RTKBT_ERR("This is not 8723a, use new patch style!");
|
||||
|
||||
/* Get version from ROM */
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
|
||||
if (gEVersion == 0xFE) {
|
||||
RTKBT_ERR("%s: Read ROM version failure", __func__);
|
||||
need_download_fw = 0;
|
||||
fw_len = 0;
|
||||
goto alloc_fail;
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
}
|
||||
|
||||
/* check Signature and Extension Section Field */
|
||||
if (((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) != 0) && (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) != 0))||
|
||||
memcmp(epatch_buf + buf_len - config_len - 4,
|
||||
Extension_Section_SIGNATURE, 4) != 0) {
|
||||
RTKBT_ERR("Check SIGNATURE error! do not download fw");
|
||||
need_download_fw = 0;
|
||||
} else {
|
||||
proj_id =
|
||||
rtk_get_fw_project_id(epatch_buf + buf_len -
|
||||
config_len - 5);
|
||||
RTKBT_DBG("8723a, fw copy direct");
|
||||
memcpy(buf, epatch_buf, fw->size);
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
|
||||
if (lmp_version != project_id[proj_id]) {
|
||||
RTKBT_ERR
|
||||
("lmp_version is %x, project_id is %x, does not match!!!",
|
||||
lmp_version, project_id[proj_id]);
|
||||
need_download_fw = 0;
|
||||
} else {
|
||||
RTKBT_DBG
|
||||
("lmp_version is %x, project_id is %x, match!",
|
||||
lmp_version, project_id[proj_id]);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int key_id = rtk_vendor_read(dev_entry, READ_SEC_PROJ);
|
||||
RTKBT_DBG("%s: key id %d", __func__, key_id);
|
||||
if (key_id < 0) {
|
||||
RTKBT_ERR("%s: Read key id failure", __func__);
|
||||
need_download_fw = 0;
|
||||
fw_len = 0;
|
||||
goto alloc_fail;
|
||||
}
|
||||
rtb_get_patch_header(&buf_len, &patch_node_hdr, epatch_buf, key_id);
|
||||
if(buf_len == 0)
|
||||
goto alloc_fail;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
buf_len += config_len;
|
||||
} else {
|
||||
rtk_get_patch_entry(epatch_buf, ¤t_entry);
|
||||
RTKBT_ERR("This is not 8723a, use new patch style!");
|
||||
|
||||
if (current_entry.patch_length == 0)
|
||||
goto alloc_fail;
|
||||
/* Get version from ROM */
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
|
||||
if (gEVersion == 0xFE) {
|
||||
RTKBT_ERR("%s: Read ROM version failure", __func__);
|
||||
need_download_fw = 0;
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
buf_len = current_entry.patch_length + config_len;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
}
|
||||
/* check Signature and Extension Section Field */
|
||||
if ((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) &&
|
||||
memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8)) ||
|
||||
memcmp(epatch_buf + buf_len - config_len - 4,
|
||||
Extension_Section_SIGNATURE, 4) != 0) {
|
||||
RTKBT_ERR("Check SIGNATURE error! do not download fw");
|
||||
need_download_fw = 0;
|
||||
goto sign_err;
|
||||
}
|
||||
|
||||
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
|
||||
RTKBT_ERR
|
||||
("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
} else {
|
||||
if(memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int tmp_len = 0;
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list)
|
||||
{
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
RTKBT_DBG("len = 0x%x", tmp->len);
|
||||
memcpy(buf + tmp_len, tmp->payload, tmp->len);
|
||||
tmp_len += tmp->len;
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
if (config_len) {
|
||||
memcpy(&buf
|
||||
[buf_len - config_len],
|
||||
config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
} else {
|
||||
memcpy(buf,
|
||||
epatch_buf +
|
||||
current_entry.start_offset,
|
||||
current_entry.patch_length);
|
||||
memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4); /*fw version */
|
||||
if (config_len) {
|
||||
memcpy(&buf
|
||||
[buf_len - config_len],
|
||||
config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
proj_id = rtk_get_fw_project_id(epatch_buf + buf_len - config_len - 5);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(project_id_to_lmp_subver); i++) {
|
||||
if (proj_id == project_id_to_lmp_subver[i].id &&
|
||||
lmp_version == project_id_to_lmp_subver[i].lmp_subver) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) {
|
||||
RTKBT_ERR("lmp_version %04x, project_id %u, does not match!!!",
|
||||
lmp_version, proj_id);
|
||||
need_download_fw = 0;
|
||||
goto proj_id_err;
|
||||
}
|
||||
|
||||
RTKBT_DBG("lmp_version is %04x, project_id is %u, match!",
|
||||
lmp_version, proj_id);
|
||||
|
||||
if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int key_id = rtk_vendor_read(dev_entry, READ_SEC_PROJ);
|
||||
int tmp_len = 0;
|
||||
|
||||
RTKBT_DBG("%s: key id %d", __func__, key_id);
|
||||
if (key_id < 0) {
|
||||
RTKBT_ERR("%s: Read key id failure", __func__);
|
||||
need_download_fw = 0;
|
||||
fw_len = 0;
|
||||
goto extract_err;
|
||||
}
|
||||
rtb_get_patch_header(&buf_len, &patch_node_hdr, epatch_buf,
|
||||
key_id);
|
||||
if (!buf_len)
|
||||
goto extract_err;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
buf_len += config_len;
|
||||
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
}
|
||||
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list) {
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
RTKBT_DBG("len = 0x%x", tmp->len);
|
||||
memcpy(buf + tmp_len, tmp->payload, tmp->len);
|
||||
tmp_len += tmp->len;
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
} else {
|
||||
rtk_get_patch_entry(epatch_buf, ¤t_entry);
|
||||
|
||||
if (current_entry.patch_length == 0)
|
||||
goto extract_err;
|
||||
|
||||
buf_len = current_entry.patch_length + config_len;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
}
|
||||
|
||||
memcpy(buf, epatch_buf + current_entry.start_offset,
|
||||
current_entry.patch_length);
|
||||
/* Copy fw version */
|
||||
memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4);
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
|
||||
if (patch_entry->chip_type == RTL8761CU) {
|
||||
if (needs_hci_upgrade(xdata, buf, buf_len) <= 0) {
|
||||
if (config_len > 0) {
|
||||
memmove(buf, buf + buf_len - config_len,
|
||||
config_len);
|
||||
buf_len = config_len;
|
||||
} else {
|
||||
#define FAKE_SEG_LEN 16
|
||||
if (buf_len > FAKE_SEG_LEN)
|
||||
buf_len = FAKE_SEG_LEN;
|
||||
memset(buf, 0, buf_len);
|
||||
}
|
||||
} else {
|
||||
/* It does not need to download config when upgrading */
|
||||
buf_len -= config_len;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
RTKBT_DBG("fw:%s exists, config file:%s exists",
|
||||
(buf_len > 0) ? "" : "not", (config_len > 0) ? "" : "not");
|
||||
if (buf && (buf_len > 0) && (need_download_fw)) {
|
||||
buf_len > 0 ? "" : "not", config_len > 0 ? "" : "not");
|
||||
if (buf && buf_len > 0 && need_download_fw) {
|
||||
fw_len = buf_len;
|
||||
*buff = buf;
|
||||
xdata->fw_data = buf;
|
||||
}
|
||||
|
||||
RTKBT_DBG("load_firmware done");
|
||||
|
||||
alloc_buf_err:
|
||||
extract_err:
|
||||
/* Make sure all the patch nodes freed */
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list) {
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
proj_id_err:
|
||||
sign_err:
|
||||
alloc_fail:
|
||||
release_firmware(fw);
|
||||
|
||||
if (epatch_buf)
|
||||
kfree(epatch_buf);
|
||||
vfree(epatch_buf);
|
||||
|
||||
fw_fail:
|
||||
if (config_file_buf)
|
||||
kfree(config_file_buf);
|
||||
fw_fail:
|
||||
|
||||
if (fw_len == 0)
|
||||
kfree(buf);
|
||||
vfree(buf);
|
||||
|
||||
return fw_len;
|
||||
}
|
||||
@@ -2149,7 +2390,7 @@ int download_data(xchange_data * xdata)
|
||||
uint8_t *pcur;
|
||||
int pkt_len, frag_num, frag_len;
|
||||
int i, ret_val;
|
||||
int j;
|
||||
int j = 0;
|
||||
|
||||
RTKBT_DBG("download_data start");
|
||||
|
||||
@@ -2161,12 +2402,11 @@ int download_data(xchange_data * xdata)
|
||||
frag_len = PATCH_SEG_MAX;
|
||||
|
||||
for (i = 0; i < frag_num; i++) {
|
||||
if (i > 0x7f)
|
||||
j = (i & 0x7f) + 1;
|
||||
else
|
||||
j = i;
|
||||
cmd_para->index = j++;
|
||||
|
||||
if(cmd_para->index == 0x7f)
|
||||
j = 1;
|
||||
|
||||
cmd_para->index = j;
|
||||
if (i == (frag_num - 1)) {
|
||||
cmd_para->index |= DATA_END;
|
||||
frag_len = xdata->fw_len % PATCH_SEG_MAX;
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB download firmware 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
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_MISC_H__
|
||||
#define __RTK_MISC_H__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@@ -14,6 +26,8 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#define CONFIG_BTUSB_AUTOSUSPEND 0
|
||||
|
||||
/* Download LPS patch when host suspends or power off
|
||||
* LPS patch name: lps_rtl8xxx_fw
|
||||
* LPS config name: lps_rtl8xxx_config
|
||||
@@ -33,19 +47,21 @@
|
||||
#if 1
|
||||
#define RTKBT_DBG(fmt, arg...) printk(KERN_DEBUG "rtk_btusb: " fmt "\n" , ## arg)
|
||||
#define RTKBT_INFO(fmt, arg...) printk(KERN_INFO "rtk_btusb: " fmt "\n" , ## arg)
|
||||
#define RTKBT_WARN(fmt, arg...) printk(KERN_DEBUG "rtk_btusb: " fmt "\n", ## arg)
|
||||
#define RTKBT_WARN(fmt, arg...) printk(KERN_WARNING "rtk_btusb: " fmt "\n", ## arg)
|
||||
#else
|
||||
#define RTKBT_DBG(fmt, arg...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define RTKBT_ERR(fmt, arg...) printk(KERN_DEBUG "rtk_btusb: " fmt "\n" , ## arg)
|
||||
#define RTKBT_ERR(fmt, arg...) printk(KERN_ERR "rtk_btusb: " fmt "\n" , ## arg)
|
||||
#else
|
||||
#define RTKBT_ERR(fmt, arg...)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
|
||||
#define USB_RPM
|
||||
#define USB_RPM 1
|
||||
#else
|
||||
#define USB_RPM 0
|
||||
#endif
|
||||
|
||||
#define CONFIG_NEEDS_BINDING
|
||||
@@ -56,7 +72,7 @@
|
||||
#endif
|
||||
|
||||
/* USB SS */
|
||||
#if (defined CONFIG_BTUSB_AUTOSUSPEND) && (defined USB_RPM)
|
||||
#if (CONFIG_BTUSB_AUTOSUSPEND && USB_RPM)
|
||||
#define BTUSB_RPM
|
||||
#endif
|
||||
|
||||
@@ -82,12 +98,41 @@ struct api_context {
|
||||
int status;
|
||||
};
|
||||
|
||||
int download_lps_patch(struct usb_interface *intf);
|
||||
int download_special_patch(struct usb_interface *intf, const char *special_name);
|
||||
#endif
|
||||
|
||||
int setup_btrealtek_flag(struct usb_interface *intf, struct hci_dev *hdev);
|
||||
|
||||
enum {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
REALTEK_ALT6_CONTINUOUS_TX_CHIP,
|
||||
#endif
|
||||
|
||||
__REALTEK_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct btrealtek_data {
|
||||
DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS);
|
||||
};
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
|
||||
static inline void *hci_get_priv(struct hci_dev *hdev)
|
||||
{
|
||||
return (char *)hdev + sizeof(*hdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
#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 defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
int set_scan(struct usb_interface *intf);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __RTK_MISC_H__ */
|
||||
Reference in New Issue
Block a user