mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 02:01:36 +03:00
realtek:bt Add new bt-usb driver release package.
1. Update to VERSION "3.1.6fd4e69.20220818-105856" 2. Update the fw file for RTL8851A, RTL8852B 3. rtk_coex: Support vendor cmd for reporting the profile and state of each connection 4. rtk_bt/rtk_misc/rtk_coex/hci_ldisc/btrtksdio: fix the issues by coverity scan and Sparse build 5. rtk_bt: Add shutdown wakeup and fix failure of usb enumeration 6. rtk_bt: Add marco to distinguish powerkey or anykey wakeup Bug 3528414 Change-Id: Ia44029f189f8fc2cd62160dbc763c6e91e8cd9b4 Signed-off-by: Sushil Singh <sushilkumars@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2876940 GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com> Tested-by: Revanth Kumar Uppala <ruppala@nvidia.com> Reviewed-by: Revanth Kumar Uppala <ruppala@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
6e2e6973cd
commit
5bc80fd7c9
@@ -1,6 +1,22 @@
|
||||
# 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
|
||||
|
||||
obj-m := rtk_btusb.o
|
||||
rtk_btusb-objs := rtk_coex.o \
|
||||
rtk_misc.o \
|
||||
rtk_bt.o
|
||||
rtk_bt.o
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <net/sock.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "rtk_bt.h"
|
||||
#include "rtk_misc.h"
|
||||
|
||||
#define VERSION "3.1.f363121.20220505-144113"
|
||||
#define VERSION "3.1.6fd4e69.20220818-105856"
|
||||
|
||||
#ifdef BTCOEX
|
||||
#include "rtk_coex.h"
|
||||
@@ -30,7 +31,7 @@
|
||||
#ifdef RTKBT_SWITCH_PATCH
|
||||
#include <linux/semaphore.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
DEFINE_SEMAPHORE(switch_sem);
|
||||
static DEFINE_SEMAPHORE(switch_sem);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
|
||||
@@ -774,7 +775,10 @@ static int btusb_open(struct hci_dev *hdev)
|
||||
goto failed;
|
||||
/*******************************/
|
||||
|
||||
RTKBT_INFO("%s set HCI_RUNNING", __func__);
|
||||
RTKBT_INFO("%s set HCI UP RUNNING", __func__);
|
||||
if (test_and_set_bit(HCI_UP, &hdev->flags))
|
||||
goto done;
|
||||
|
||||
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
|
||||
goto done;
|
||||
|
||||
@@ -912,7 +916,7 @@ static int btusb_flush(struct hci_dev *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char pkt_ind[][8] = {
|
||||
static const char pkt_ind[][8] = {
|
||||
[HCI_COMMAND_PKT] = "cmd",
|
||||
[HCI_ACLDATA_PKT] = "acl",
|
||||
[HCI_SCODATA_PKT] = "sco",
|
||||
@@ -1329,7 +1333,7 @@ static int rtkbt_lookup_le_device_poweron_whitelist(struct hci_dev *hdev,
|
||||
}
|
||||
#endif
|
||||
|
||||
int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
static int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
ulong pm_event, void *unused)
|
||||
{
|
||||
struct btusb_data *data;
|
||||
@@ -1418,13 +1422,6 @@ int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
kfree(cmd);
|
||||
msleep(100); /* From FW colleague's recommendation */
|
||||
result = download_lps_patch(intf);
|
||||
|
||||
/* Tell the controller to wake up host if received special
|
||||
* advertising packet
|
||||
*/
|
||||
set_scan(intf);
|
||||
|
||||
/* Send special vendor commands */
|
||||
#endif
|
||||
|
||||
#ifdef RTKBT_TV_POWERON_WHITELIST
|
||||
@@ -1433,6 +1430,17 @@ int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
RTKBT_ERR("rtkbt_lookup_le_device_poweron_whitelist error: %d", result);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
#ifdef RTKBT_POWERKEY_WAKEUP
|
||||
/* Tell the controller to wake up host if received special
|
||||
* advertising packet
|
||||
*/
|
||||
set_scan(intf);
|
||||
#endif
|
||||
/* Send special vendor commands */
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
case PM_POST_SUSPEND:
|
||||
@@ -1466,7 +1474,7 @@ int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BTUSB_RPM
|
||||
#ifdef BTUSB_RPM
|
||||
RTKBT_DBG("%s: Re-enable autosuspend", __func__);
|
||||
/* pm_runtime_use_autosuspend(&udev->dev);
|
||||
* pm_runtime_set_autosuspend_delay(&udev->dev, 2000);
|
||||
@@ -1491,6 +1499,36 @@ int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int rtkbt_shutdown_notify(struct notifier_block *notifier,
|
||||
ulong pm_event, void *unused)
|
||||
{
|
||||
struct btusb_data *data;
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct hci_dev *hdev;
|
||||
/* int err; */
|
||||
|
||||
data = container_of(notifier, struct btusb_data, shutdown_notifier);
|
||||
udev = data->udev;
|
||||
intf = data->intf;
|
||||
hdev = data->hdev;
|
||||
|
||||
RTKBT_DBG("%s: pm_event %ld", __func__, pm_event);
|
||||
switch (pm_event) {
|
||||
case SYS_POWER_OFF:
|
||||
case SYS_RESTART:
|
||||
#ifdef RTKBT_SHUTDOWN_WAKEUP
|
||||
RTKBT_DBG("%s: power off", __func__);
|
||||
set_scan(intf);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int btusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
@@ -1513,7 +1551,7 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
flag1 = device_can_wakeup(&udev->dev);
|
||||
flag2 = device_may_wakeup(&udev->dev);
|
||||
RTKBT_DBG("btusb_probe can_wakeup %x, may wakeup %x", flag1, flag2);
|
||||
#if BTUSB_WAKEUP_HOST
|
||||
#ifdef BTUSB_WAKEUP_HOST
|
||||
device_wakeup_enable(&udev->dev);
|
||||
#endif
|
||||
//device_wakeup_enable(&udev->dev);
|
||||
@@ -1533,6 +1571,10 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
|
||||
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
|
||||
ep_desc = &intf->cur_altsetting->endpoint[i].desc;
|
||||
if (!data->intr_ep && usb_endpoint_is_bulk_in(ep_desc) && (ep_desc->bEndpointAddress == 0x81)) {
|
||||
data->intr_ep = ep_desc;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) {
|
||||
data->intr_ep = ep_desc;
|
||||
@@ -1639,6 +1681,9 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
data->pm_notifier.notifier_call = rtkbt_pm_notify;
|
||||
register_pm_notifier(&data->pm_notifier);
|
||||
|
||||
/* Register POWER-OFF notifier */
|
||||
data->shutdown_notifier.notifier_call = rtkbt_shutdown_notify;
|
||||
register_reboot_notifier(&data->shutdown_notifier);
|
||||
#ifdef BTCOEX
|
||||
rtk_btcoex_probe(hdev);
|
||||
#endif
|
||||
@@ -1665,6 +1710,7 @@ static void btusb_disconnect(struct usb_interface *intf)
|
||||
|
||||
/* Un-register PM notifier */
|
||||
unregister_pm_notifier(&data->pm_notifier);
|
||||
unregister_reboot_notifier(&data->shutdown_notifier);
|
||||
|
||||
/*******************************/
|
||||
patch_remove(intf);
|
||||
@@ -1846,7 +1892,8 @@ static struct usb_driver btusb_driver = {
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = btusb_suspend,
|
||||
.resume = btusb_resume,
|
||||
#ifdef RTKBT_SWITCH_PATCH
|
||||
#if defined RTKBT_SWITCH_PATCH || defined RTKBT_SUSPEND_WAKEUP || defined \
|
||||
RTKBT_SHUTDOWN_WAKEUP
|
||||
.reset_resume = btusb_resume,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -30,12 +30,16 @@
|
||||
/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
|
||||
#define HCI_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#ifdef CONFIG_BTCOEX
|
||||
#define BTCOEX
|
||||
#endif
|
||||
|
||||
/***********************************
|
||||
** Realtek - For rtk_btusb driver **
|
||||
***********************************/
|
||||
#define BTUSB_WAKEUP_HOST 0 /* 1 enable; 0 disable */
|
||||
#ifdef CONFIG_BTUSB_WAKEUP_HOST
|
||||
#define BTUSB_WAKEUP_HOST
|
||||
#endif
|
||||
|
||||
#define URB_CANCELING_DELAY_MS 10 // Added by Realtek
|
||||
#if HCI_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
|
||||
@@ -44,12 +48,6 @@
|
||||
#define HDEV_BUS hdev->type
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
|
||||
#define USB_RPM 1
|
||||
#else
|
||||
#define USB_RPM 0
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
|
||||
#define NUM_REASSEMBLY 3
|
||||
#endif
|
||||
@@ -135,6 +133,7 @@ struct btusb_data {
|
||||
int (*recv_bulk) (struct btusb_data * data, void *buffer, int count);
|
||||
#endif
|
||||
struct notifier_block pm_notifier;
|
||||
struct notifier_block shutdown_notifier;
|
||||
void *context;
|
||||
};
|
||||
|
||||
|
||||
@@ -60,12 +60,16 @@ static u8 rtw_coex_on;
|
||||
#endif
|
||||
|
||||
#define is_profile_connected(profile) ((btrtl_coex.profile_bitmap & BIT(profile)) > 0)
|
||||
#define is_profile_busy(profile) ((btrtl_coex.profile_status & BIT(profile)) > 0)
|
||||
#define is_profile_busy(conn, profile) ((conn->profile_status & BIT(profile)) > 0)
|
||||
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
static void rtk_handle_event_from_wifi(uint8_t * msg);
|
||||
#endif
|
||||
|
||||
static void count_a2dp_packet_timeout(struct work_struct *work);
|
||||
static void count_pan_packet_timeout(struct work_struct *work);
|
||||
static void count_hogp_packet_timeout(struct work_struct *work);
|
||||
|
||||
static int rtl_alloc_buff(struct rtl_coex_struct *coex)
|
||||
{
|
||||
struct rtl_hci_ev *ev;
|
||||
@@ -226,12 +230,12 @@ static int rtl_l2_node_to_used(struct rtl_coex_struct *coex,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int8_t psm_to_profile_index(uint16_t psm)
|
||||
static uint8_t psm_to_profile_index(uint16_t psm)
|
||||
{
|
||||
switch (psm) {
|
||||
case PSM_AVCTP:
|
||||
case PSM_SDP:
|
||||
return -1; //ignore
|
||||
return 0xFF; //ignore
|
||||
|
||||
case PSM_HID:
|
||||
case PSM_HID_INT:
|
||||
@@ -252,7 +256,7 @@ static int8_t psm_to_profile_index(uint16_t psm)
|
||||
}
|
||||
}
|
||||
|
||||
static rtk_prof_info *find_by_psm(u16 psm)
|
||||
static rtk_prof_info *find_by_psm(u16 handle, u16 psm)
|
||||
{
|
||||
struct list_head *head = &btrtl_coex.profile_list;
|
||||
struct list_head *iter = NULL;
|
||||
@@ -261,65 +265,59 @@ static rtk_prof_info *find_by_psm(u16 psm)
|
||||
|
||||
list_for_each_safe(iter, temp, head) {
|
||||
desc = list_entry(iter, rtk_prof_info, list);
|
||||
if (desc->psm == psm)
|
||||
if ((handle & 0xfff) == (desc->handle & 0xfff) &&
|
||||
desc->psm == psm)
|
||||
return desc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rtk_check_setup_timer(int8_t profile_index)
|
||||
static void rtk_check_setup_timer(rtk_conn_prof * phci_conn, uint8_t profile_index)
|
||||
{
|
||||
int delay = msecs_to_jiffies(1000);
|
||||
if (profile_index == profile_a2dp) {
|
||||
btrtl_coex.a2dp_packet_count = 0;
|
||||
btrtl_coex.a2dp_count_timer.expires =
|
||||
jiffies + msecs_to_jiffies(1000);
|
||||
mod_timer(&btrtl_coex.a2dp_count_timer,
|
||||
btrtl_coex.a2dp_count_timer.expires);
|
||||
phci_conn->a2dp_packet_count = 0;
|
||||
queue_delayed_work(btrtl_coex.timer_wq, &phci_conn->a2dp_count_work, delay);
|
||||
}
|
||||
|
||||
if (profile_index == profile_pan) {
|
||||
btrtl_coex.pan_packet_count = 0;
|
||||
btrtl_coex.pan_count_timer.expires =
|
||||
jiffies + msecs_to_jiffies(1000);
|
||||
mod_timer(&btrtl_coex.pan_count_timer,
|
||||
btrtl_coex.pan_count_timer.expires);
|
||||
phci_conn->pan_packet_count = 0;
|
||||
queue_delayed_work(btrtl_coex.timer_wq, &phci_conn->pan_count_work, delay);
|
||||
}
|
||||
|
||||
/* hogp & voice share one timer now */
|
||||
if ((profile_index == profile_hogp) || (profile_index == profile_voice)) {
|
||||
if ((0 == btrtl_coex.profile_refcount[profile_hogp])
|
||||
&& (0 == btrtl_coex.profile_refcount[profile_voice])) {
|
||||
btrtl_coex.hogp_packet_count = 0;
|
||||
btrtl_coex.voice_packet_count = 0;
|
||||
btrtl_coex.hogp_count_timer.expires =
|
||||
jiffies + msecs_to_jiffies(1000);
|
||||
mod_timer(&btrtl_coex.hogp_count_timer,
|
||||
btrtl_coex.hogp_count_timer.expires);
|
||||
phci_conn->hogp_packet_count = 0;
|
||||
phci_conn->voice_packet_count = 0;
|
||||
queue_delayed_work(btrtl_coex.timer_wq, &phci_conn->hogp_count_work, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rtk_check_del_timer(int8_t profile_index)
|
||||
static void rtk_check_del_timer(uint8_t profile_index, rtk_conn_prof * phci_conn)
|
||||
{
|
||||
RTKBT_DBG("%s: handle 0x%4x", __func__, phci_conn->handle);
|
||||
if (profile_a2dp == profile_index) {
|
||||
btrtl_coex.a2dp_packet_count = 0;
|
||||
del_timer_sync(&btrtl_coex.a2dp_count_timer);
|
||||
phci_conn->a2dp_packet_count = 0;
|
||||
cancel_delayed_work_sync(&phci_conn->a2dp_count_work);
|
||||
}
|
||||
if (profile_pan == profile_index) {
|
||||
btrtl_coex.pan_packet_count = 0;
|
||||
del_timer_sync(&btrtl_coex.pan_count_timer);
|
||||
phci_conn->pan_packet_count = 0;
|
||||
cancel_delayed_work_sync(&phci_conn->pan_count_work);
|
||||
}
|
||||
if (profile_hogp == profile_index) {
|
||||
btrtl_coex.hogp_packet_count = 0;
|
||||
phci_conn->hogp_packet_count = 0;
|
||||
if (btrtl_coex.profile_refcount[profile_voice] == 0) {
|
||||
del_timer_sync(&btrtl_coex.hogp_count_timer);
|
||||
cancel_delayed_work_sync(&phci_conn->hogp_count_work);
|
||||
}
|
||||
}
|
||||
if (profile_voice == profile_index) {
|
||||
btrtl_coex.voice_packet_count = 0;
|
||||
phci_conn->voice_packet_count = 0;
|
||||
if (btrtl_coex.profile_refcount[profile_hogp] == 0) {
|
||||
del_timer_sync(&btrtl_coex.hogp_count_timer);
|
||||
cancel_delayed_work_sync(&phci_conn->hogp_count_work);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,7 +333,7 @@ static rtk_conn_prof *find_connection_by_handle(struct rtl_coex_struct * coex,
|
||||
|
||||
list_for_each_safe(iter, temp, head) {
|
||||
desc = list_entry(iter, rtk_conn_prof, list);
|
||||
if ((handle & 0xEFF) == desc->handle) {
|
||||
if ((handle & 0xFFF) == desc->handle) {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@@ -363,11 +361,17 @@ static void add_connection_to_hash(struct rtl_coex_struct * coex,
|
||||
{
|
||||
struct list_head *head = &coex->conn_hash;
|
||||
list_add_tail(&desc->list, head);
|
||||
INIT_DELAYED_WORK(&desc->a2dp_count_work, (void *)count_a2dp_packet_timeout);
|
||||
INIT_DELAYED_WORK(&desc->pan_count_work, (void *)count_pan_packet_timeout);
|
||||
INIT_DELAYED_WORK(&desc->hogp_count_work, (void *)count_hogp_packet_timeout);
|
||||
}
|
||||
|
||||
static void delete_connection_from_hash(rtk_conn_prof * desc)
|
||||
{
|
||||
if (desc) {
|
||||
cancel_delayed_work_sync(&desc->a2dp_count_work);
|
||||
cancel_delayed_work_sync(&desc->pan_count_work);
|
||||
cancel_delayed_work_sync(&desc->hogp_count_work);
|
||||
list_del(&desc->list);
|
||||
kfree(desc);
|
||||
}
|
||||
@@ -382,6 +386,9 @@ static void flush_connection_hash(struct rtl_coex_struct * coex)
|
||||
list_for_each_safe(iter, temp, head) {
|
||||
desc = list_entry(iter, rtk_conn_prof, list);
|
||||
if (desc) {
|
||||
cancel_delayed_work_sync(&desc->a2dp_count_work);
|
||||
cancel_delayed_work_sync(&desc->pan_count_work);
|
||||
cancel_delayed_work_sync(&desc->hogp_count_work);
|
||||
list_del(&desc->list);
|
||||
kfree(desc);
|
||||
}
|
||||
@@ -396,16 +403,11 @@ static void init_profile_hash(struct rtl_coex_struct * coex)
|
||||
}
|
||||
|
||||
static uint8_t list_allocate_add(uint16_t handle, uint16_t psm,
|
||||
int8_t profile_index, uint16_t dcid,
|
||||
uint8_t profile_index, uint16_t dcid,
|
||||
uint16_t scid)
|
||||
{
|
||||
rtk_prof_info *pprof_info = NULL;
|
||||
|
||||
if (profile_index < 0) {
|
||||
RTKBT_ERR("PSM 0x%x do not need parse", psm);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pprof_info = kmalloc(sizeof(rtk_prof_info), GFP_ATOMIC);
|
||||
|
||||
if (NULL == pprof_info) {
|
||||
@@ -417,7 +419,7 @@ static uint8_t list_allocate_add(uint16_t handle, uint16_t psm,
|
||||
* a2dp signal channel will be created first than media channel.
|
||||
*/
|
||||
if (psm == PSM_AVDTP) {
|
||||
rtk_prof_info *pinfo = find_by_psm(psm);
|
||||
rtk_prof_info *pinfo = find_by_psm(handle, psm);
|
||||
if (!pinfo) {
|
||||
pprof_info->flags = A2DP_SIGNAL;
|
||||
RTKBT_INFO("%s: Add a2dp signal channel", __func__);
|
||||
@@ -459,7 +461,15 @@ static void flush_profile_hash(struct rtl_coex_struct * coex)
|
||||
spin_lock(&btrtl_coex.spin_lock_profile);
|
||||
list_for_each_safe(iter, temp, head) {
|
||||
desc = list_entry(iter, rtk_prof_info, list);
|
||||
delete_profile_from_hash(desc);
|
||||
if (desc) {
|
||||
RTKBT_DBG("Delete profile: hndl 0x%04x, psm 0x%04x, "
|
||||
"dcid 0x%04x, scid 0x%04x", desc->handle,
|
||||
desc->psm, desc->dcid, desc->scid);
|
||||
|
||||
list_del(&desc->list);
|
||||
kfree(desc);
|
||||
desc = NULL;
|
||||
}
|
||||
}
|
||||
//INIT_LIST_HEAD(head);
|
||||
spin_unlock(&btrtl_coex.spin_lock_profile);
|
||||
@@ -594,6 +604,7 @@ static void rtk_vendor_cmd_to_fw(uint16_t opcode, uint8_t parameter_len,
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t profileinfo_cmd = 0;
|
||||
static void rtk_notify_profileinfo_to_fw(void)
|
||||
{
|
||||
struct list_head *head = NULL;
|
||||
@@ -612,7 +623,11 @@ static void rtk_notify_profileinfo_to_fw(void)
|
||||
handle_number++;
|
||||
}
|
||||
|
||||
buffer_size = 1 + handle_number * 3 + 1;
|
||||
if(!profileinfo_cmd) {
|
||||
buffer_size = 1 + handle_number * 3 + 1;
|
||||
} else {
|
||||
buffer_size = 1 + handle_number * 6;
|
||||
}
|
||||
|
||||
p_buf = kmalloc(buffer_size, GFP_ATOMIC);
|
||||
|
||||
@@ -621,41 +636,55 @@ static void rtk_notify_profileinfo_to_fw(void)
|
||||
return;
|
||||
}
|
||||
p = p_buf;
|
||||
*p++ = handle_number;
|
||||
|
||||
RTKBT_DBG("%s: BufferSize %u", __func__, buffer_size);
|
||||
*p++ = handle_number;
|
||||
RTKBT_DBG("%s: NumberOfHandles %u", __func__, handle_number);
|
||||
head = &btrtl_coex.conn_hash;
|
||||
list_for_each(iter, head) {
|
||||
hci_conn = list_entry(iter, rtk_conn_prof, list);
|
||||
if (hci_conn && hci_conn->profile_bitmap) {
|
||||
UINT16_TO_STREAM(p, hci_conn->handle);
|
||||
RTKBT_DBG("%s: handle 0x%04x", __func__,
|
||||
hci_conn->handle);
|
||||
*p++ = hci_conn->profile_bitmap;
|
||||
RTKBT_DBG("%s: profile_bitmap 0x%02x", __func__,
|
||||
hci_conn->profile_bitmap);
|
||||
if(!profileinfo_cmd) {
|
||||
UINT16_TO_STREAM(p, hci_conn->handle);
|
||||
RTKBT_DBG("%s: handle 0x%04x", __func__,
|
||||
hci_conn->handle);
|
||||
*p++ = hci_conn->profile_bitmap;
|
||||
} else {
|
||||
UINT16_TO_STREAM(p, hci_conn->handle);
|
||||
UINT16_TO_STREAM(p, hci_conn->profile_bitmap);
|
||||
RTKBT_DBG("%s: profile_bitmap 0x%02x", __func__,
|
||||
hci_conn->profile_bitmap);
|
||||
UINT16_TO_STREAM(p, hci_conn->profile_status);
|
||||
RTKBT_DBG("%s: profile_status 0x%02x", __func__,
|
||||
hci_conn->profile_status);
|
||||
}
|
||||
handle_number--;
|
||||
}
|
||||
if (0 == handle_number)
|
||||
break;
|
||||
}
|
||||
|
||||
*p++ = btrtl_coex.profile_status;
|
||||
RTKBT_DBG("%s: profile_status 0x%02x", __func__,
|
||||
btrtl_coex.profile_status);
|
||||
|
||||
rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, buffer_size,
|
||||
if(!profileinfo_cmd) {
|
||||
*p++ = btrtl_coex.profile_status;
|
||||
rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_LEGACY_COMMAND, buffer_size,
|
||||
p_buf);
|
||||
} else {
|
||||
rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, buffer_size,
|
||||
p_buf);
|
||||
}
|
||||
|
||||
kfree(p_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
static void update_profile_state(uint8_t profile_index, uint8_t is_busy)
|
||||
static void update_profile_state(rtk_conn_prof * phci_conn,
|
||||
uint8_t profile_index, uint8_t is_busy)
|
||||
{
|
||||
uint8_t need_update = FALSE;
|
||||
|
||||
RTKBT_DBG("%s: is_busy %d, profile_index %x", __func__,
|
||||
is_busy, profile_index);
|
||||
|
||||
if ((btrtl_coex.profile_bitmap & BIT(profile_index)) == 0) {
|
||||
RTKBT_ERR("%s: : ERROR!!! profile(Index: %x) does not exist",
|
||||
__func__, profile_index);
|
||||
@@ -663,36 +692,34 @@ static void update_profile_state(uint8_t profile_index, uint8_t is_busy)
|
||||
}
|
||||
|
||||
if (is_busy) {
|
||||
if ((btrtl_coex.profile_status & BIT(profile_index)) == 0) {
|
||||
if ((phci_conn->profile_status & BIT(profile_index)) == 0) {
|
||||
need_update = TRUE;
|
||||
btrtl_coex.profile_status |= BIT(profile_index);
|
||||
phci_conn->profile_status |= BIT(profile_index);
|
||||
}
|
||||
} else {
|
||||
if ((btrtl_coex.profile_status & BIT(profile_index)) > 0) {
|
||||
if ((phci_conn->profile_status & BIT(profile_index)) > 0) {
|
||||
need_update = TRUE;
|
||||
btrtl_coex.profile_status &= ~(BIT(profile_index));
|
||||
phci_conn->profile_status &= ~(BIT(profile_index));
|
||||
}
|
||||
}
|
||||
|
||||
if (need_update) {
|
||||
RTKBT_DBG("%s: btrtl_coex.profie_bitmap = %x",
|
||||
__func__, btrtl_coex.profile_bitmap);
|
||||
RTKBT_DBG("%s: btrtl_coex.profile_status = %x",
|
||||
__func__, btrtl_coex.profile_status);
|
||||
RTKBT_DBG("%s: btrtl_coex.profile_status 0x%02x, phci_conn->profile_status 0x%02x",
|
||||
__func__, btrtl_coex.profile_status, phci_conn->profile_status);
|
||||
rtk_notify_profileinfo_to_fw();
|
||||
}
|
||||
}
|
||||
|
||||
static void update_profile_connection(rtk_conn_prof * phci_conn,
|
||||
int8_t profile_index, uint8_t is_add)
|
||||
uint8_t profile_index, uint8_t is_add)
|
||||
{
|
||||
uint8_t need_update = FALSE;
|
||||
uint8_t kk;
|
||||
|
||||
RTKBT_DBG("%s: is_add %d, profile_index %x", __func__,
|
||||
is_add, profile_index);
|
||||
if (profile_index < 0)
|
||||
return;
|
||||
|
||||
if (is_add) {
|
||||
if (btrtl_coex.profile_refcount[profile_index] == 0) {
|
||||
@@ -703,14 +730,13 @@ static void update_profile_connection(rtk_conn_prof * phci_conn,
|
||||
if (profile_index == profile_sco)
|
||||
btrtl_coex.profile_status |=
|
||||
BIT(profile_index);
|
||||
|
||||
rtk_check_setup_timer(profile_index);
|
||||
}
|
||||
btrtl_coex.profile_refcount[profile_index]++;
|
||||
|
||||
if (0 == phci_conn->profile_refcount[profile_index]) {
|
||||
need_update = TRUE;
|
||||
phci_conn->profile_bitmap |= BIT(profile_index);
|
||||
rtk_check_setup_timer(phci_conn, profile_index);
|
||||
}
|
||||
phci_conn->profile_refcount[profile_index]++;
|
||||
} else {
|
||||
@@ -729,7 +755,6 @@ static void update_profile_connection(rtk_conn_prof * phci_conn,
|
||||
|
||||
/* if profile does not exist, status is meaningless */
|
||||
btrtl_coex.profile_status &= ~(BIT(profile_index));
|
||||
rtk_check_del_timer(profile_index);
|
||||
}
|
||||
|
||||
phci_conn->profile_refcount[profile_index]--;
|
||||
@@ -737,20 +762,22 @@ static void update_profile_connection(rtk_conn_prof * phci_conn,
|
||||
need_update = TRUE;
|
||||
phci_conn->profile_bitmap &= ~(BIT(profile_index));
|
||||
|
||||
phci_conn->profile_status &= ~(BIT(profile_index));
|
||||
rtk_check_del_timer(profile_index, phci_conn);
|
||||
/* clear profile_hid_interval if need */
|
||||
if ((profile_hid == profile_index)
|
||||
&& (phci_conn->
|
||||
profile_bitmap & (BIT(profile_hid_interval)))) {
|
||||
phci_conn->profile_bitmap &=
|
||||
~(BIT(profile_hid_interval));
|
||||
btrtl_coex.
|
||||
phci_conn->
|
||||
profile_refcount[profile_hid_interval]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RTKBT_DBG("%s: btrtl_coex.profile_bitmap 0x%02x", __func__,
|
||||
btrtl_coex.profile_bitmap);
|
||||
RTKBT_DBG("%s: phci_conn->profile_bitmap 0x%02x", __func__,
|
||||
phci_conn->profile_bitmap);
|
||||
for (kk = 0; kk < 8; kk++)
|
||||
RTKBT_DBG("%s: btrtl_coex.profile_refcount[%d] = %d",
|
||||
__func__, kk,
|
||||
@@ -781,10 +808,10 @@ static void update_hid_active_state(uint16_t handle, uint16_t interval)
|
||||
need_update = 1;
|
||||
phci_conn->profile_bitmap |= BIT(profile_hid_interval);
|
||||
|
||||
btrtl_coex.profile_refcount[profile_hid_interval]++;
|
||||
if (btrtl_coex.
|
||||
phci_conn->profile_refcount[profile_hid_interval]++;
|
||||
if (phci_conn->
|
||||
profile_refcount[profile_hid_interval] == 1)
|
||||
btrtl_coex.profile_status |=
|
||||
phci_conn->profile_status |=
|
||||
BIT(profile_hid);
|
||||
}
|
||||
} else {
|
||||
@@ -793,10 +820,10 @@ static void update_hid_active_state(uint16_t handle, uint16_t interval)
|
||||
phci_conn->profile_bitmap &=
|
||||
~(BIT(profile_hid_interval));
|
||||
|
||||
btrtl_coex.profile_refcount[profile_hid_interval]--;
|
||||
if (btrtl_coex.
|
||||
phci_conn->profile_refcount[profile_hid_interval]--;
|
||||
if (phci_conn->
|
||||
profile_refcount[profile_hid_interval] == 0)
|
||||
btrtl_coex.profile_status &=
|
||||
phci_conn->profile_status &=
|
||||
~(BIT(profile_hid));
|
||||
}
|
||||
}
|
||||
@@ -810,9 +837,9 @@ static uint8_t handle_l2cap_con_req(uint16_t handle, uint16_t psm,
|
||||
{
|
||||
uint8_t status = FALSE;
|
||||
rtk_prof_info *prof_info = NULL;
|
||||
int8_t profile_index = psm_to_profile_index(psm);
|
||||
uint8_t profile_index = psm_to_profile_index(psm);
|
||||
|
||||
if (profile_index < 0) {
|
||||
if (profile_index == 0xFF) {
|
||||
RTKBT_DBG("PSM(0x%04x) do not need parse", psm);
|
||||
return status;
|
||||
}
|
||||
@@ -940,7 +967,7 @@ static const char alloc_methods[2][12] = {
|
||||
|
||||
static const uint8_t subbands[2] = { 4, 8 };
|
||||
|
||||
void print_sbc_header(struct sbc_frame_hdr *hdr)
|
||||
static void print_sbc_header(struct sbc_frame_hdr *hdr)
|
||||
{
|
||||
RTKBT_DBG("syncword: %02x", hdr->syncword);
|
||||
RTKBT_DBG("freq %skHz", sample_freqs[hdr->sampling_frequency]);
|
||||
@@ -979,19 +1006,19 @@ static void packets_count(uint16_t handle, uint16_t scid, uint16_t length,
|
||||
/* avdtp media data */
|
||||
if (prof_info->profile_index == profile_a2dp &&
|
||||
prof_info->flags == A2DP_MEDIA) {
|
||||
if (!is_profile_busy(profile_a2dp)) {
|
||||
if (!is_profile_busy(hci_conn, profile_a2dp)) {
|
||||
struct sbc_frame_hdr *sbc_header;
|
||||
struct rtp_header *rtph;
|
||||
u8 bitpool;
|
||||
|
||||
update_profile_state(profile_a2dp, TRUE);
|
||||
update_profile_state(hci_conn, profile_a2dp, TRUE);
|
||||
if (!direction) {
|
||||
if (!(hci_conn->profile_bitmap & BIT(profile_sink))) {
|
||||
btrtl_coex.profile_bitmap |= BIT(profile_sink);
|
||||
hci_conn->profile_bitmap |= BIT(profile_sink);
|
||||
update_profile_connection(hci_conn, profile_sink, 1);
|
||||
}
|
||||
update_profile_state(profile_sink, TRUE);
|
||||
update_profile_state(hci_conn, profile_sink, TRUE);
|
||||
}
|
||||
|
||||
/* We assume it is SBC if the packet length
|
||||
@@ -1019,90 +1046,82 @@ static void packets_count(uint16_t handle, uint16_t scid, uint16_t length,
|
||||
1, &bitpool);
|
||||
}
|
||||
}
|
||||
btrtl_coex.a2dp_packet_count++;
|
||||
hci_conn->a2dp_packet_count++;
|
||||
}
|
||||
|
||||
if (prof_info->profile_index == profile_pan)
|
||||
btrtl_coex.pan_packet_count++;
|
||||
hci_conn->pan_packet_count++;
|
||||
}
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
|
||||
static void count_a2dp_packet_timeout(struct timer_list *unused)
|
||||
#else
|
||||
static void count_a2dp_packet_timeout(unsigned long data)
|
||||
#endif
|
||||
static void count_a2dp_packet_timeout(struct work_struct *work)
|
||||
{
|
||||
if (btrtl_coex.a2dp_packet_count)
|
||||
rtk_conn_prof *hci_conn = container_of(work, rtk_conn_prof,
|
||||
a2dp_count_work.work);
|
||||
if (hci_conn->a2dp_packet_count)
|
||||
RTKBT_DBG("%s: a2dp_packet_count %d", __func__,
|
||||
btrtl_coex.a2dp_packet_count);
|
||||
if (btrtl_coex.a2dp_packet_count == 0) {
|
||||
if (is_profile_busy(profile_a2dp)) {
|
||||
hci_conn->a2dp_packet_count);
|
||||
if (hci_conn->a2dp_packet_count == 0) {
|
||||
if (is_profile_busy(hci_conn, profile_a2dp)) {
|
||||
RTKBT_DBG("%s: a2dp busy->idle!", __func__);
|
||||
update_profile_state(profile_a2dp, FALSE);
|
||||
update_profile_state(hci_conn, profile_a2dp, FALSE);
|
||||
if (btrtl_coex.profile_bitmap & BIT(profile_sink))
|
||||
update_profile_state(profile_sink, FALSE);
|
||||
update_profile_state(hci_conn, profile_sink, FALSE);
|
||||
}
|
||||
}
|
||||
btrtl_coex.a2dp_packet_count = 0;
|
||||
mod_timer(&btrtl_coex.a2dp_count_timer,
|
||||
jiffies + msecs_to_jiffies(1000));
|
||||
hci_conn->a2dp_packet_count = 0;
|
||||
|
||||
queue_delayed_work(btrtl_coex.timer_wq, &hci_conn->a2dp_count_work, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
|
||||
static void count_pan_packet_timeout(struct timer_list *unused)
|
||||
#else
|
||||
static void count_pan_packet_timeout(unsigned long data)
|
||||
#endif
|
||||
static void count_pan_packet_timeout(struct work_struct *work)
|
||||
{
|
||||
if (btrtl_coex.pan_packet_count)
|
||||
rtk_conn_prof *hci_conn = container_of(work, rtk_conn_prof,
|
||||
pan_count_work.work);
|
||||
if (hci_conn->pan_packet_count)
|
||||
RTKBT_DBG("%s: pan_packet_count %d", __func__,
|
||||
btrtl_coex.pan_packet_count);
|
||||
if (btrtl_coex.pan_packet_count < PAN_PACKET_COUNT) {
|
||||
if (is_profile_busy(profile_pan)) {
|
||||
hci_conn->pan_packet_count);
|
||||
if (hci_conn->pan_packet_count < PAN_PACKET_COUNT) {
|
||||
if (is_profile_busy(hci_conn, profile_pan)) {
|
||||
RTKBT_DBG("%s: pan busy->idle!", __func__);
|
||||
update_profile_state(profile_pan, FALSE);
|
||||
update_profile_state(hci_conn, profile_pan, FALSE);
|
||||
}
|
||||
} else {
|
||||
if (!is_profile_busy(profile_pan)) {
|
||||
if (!is_profile_busy(hci_conn, profile_pan)) {
|
||||
RTKBT_DBG("timeout_handler: pan idle->busy!");
|
||||
update_profile_state(profile_pan, TRUE);
|
||||
update_profile_state(hci_conn, profile_pan, TRUE);
|
||||
}
|
||||
}
|
||||
btrtl_coex.pan_packet_count = 0;
|
||||
mod_timer(&btrtl_coex.pan_count_timer,
|
||||
jiffies + msecs_to_jiffies(1000));
|
||||
hci_conn->pan_packet_count = 0;
|
||||
queue_delayed_work(btrtl_coex.timer_wq, &hci_conn->pan_count_work, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
|
||||
static void count_hogp_packet_timeout(struct timer_list *unused)
|
||||
#else
|
||||
static void count_hogp_packet_timeout(unsigned long data)
|
||||
#endif
|
||||
static void count_hogp_packet_timeout(struct work_struct *work)
|
||||
{
|
||||
if (btrtl_coex.hogp_packet_count)
|
||||
rtk_conn_prof *hci_conn = container_of(work, rtk_conn_prof,
|
||||
hogp_count_work.work);
|
||||
if (hci_conn->hogp_packet_count)
|
||||
RTKBT_DBG("%s: hogp_packet_count %d", __func__,
|
||||
btrtl_coex.hogp_packet_count);
|
||||
if (btrtl_coex.hogp_packet_count == 0) {
|
||||
if (is_profile_busy(profile_hogp)) {
|
||||
hci_conn->hogp_packet_count);
|
||||
if (hci_conn->hogp_packet_count == 0) {
|
||||
if (is_profile_busy(hci_conn, profile_hogp)) {
|
||||
RTKBT_DBG("%s: hogp busy->idle!", __func__);
|
||||
update_profile_state(profile_hogp, FALSE);
|
||||
update_profile_state(hci_conn, profile_hogp, FALSE);
|
||||
}
|
||||
}
|
||||
btrtl_coex.hogp_packet_count = 0;
|
||||
hci_conn->hogp_packet_count = 0;
|
||||
|
||||
if (btrtl_coex.voice_packet_count)
|
||||
if (hci_conn->voice_packet_count)
|
||||
RTKBT_DBG("%s: voice_packet_count %d", __func__,
|
||||
btrtl_coex.voice_packet_count);
|
||||
if (btrtl_coex.voice_packet_count == 0) {
|
||||
if (is_profile_busy(profile_voice)) {
|
||||
hci_conn->voice_packet_count);
|
||||
if (hci_conn->voice_packet_count == 0) {
|
||||
if (is_profile_busy(hci_conn, profile_voice)) {
|
||||
RTKBT_DBG("%s: voice busy->idle!", __func__);
|
||||
update_profile_state(profile_voice, FALSE);
|
||||
update_profile_state(hci_conn, profile_voice, FALSE);
|
||||
}
|
||||
}
|
||||
btrtl_coex.voice_packet_count = 0;
|
||||
mod_timer(&btrtl_coex.hogp_count_timer,
|
||||
jiffies + msecs_to_jiffies(1000));
|
||||
hci_conn->voice_packet_count = 0;
|
||||
queue_delayed_work(btrtl_coex.timer_wq, &hci_conn->hogp_count_work, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
@@ -1768,6 +1787,15 @@ static void rtk_handle_cmd_complete_evt(u8 total_len, u8 * p)
|
||||
rtk_parse_vendor_mailbox_cmd_evt(p, total_len);
|
||||
}
|
||||
#endif
|
||||
if (opcode == HCI_VENDOR_SET_PROFILE_REPORT_COMMAND) {
|
||||
//0x01-unknown hci command
|
||||
if((*p++) == 0x01) {
|
||||
RTKBT_DBG("unknown hci command");
|
||||
return;
|
||||
} else {
|
||||
profileinfo_cmd = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rtk_handle_cmd_status_evt(u8 * p)
|
||||
@@ -1989,7 +2017,7 @@ static u8 disconn_profile(struct rtl_hci_conn *conn, u8 pfe_index)
|
||||
|
||||
/* if profile does not exist, status is meaningless */
|
||||
btrtl_coex.profile_status &= ~(BIT(pfe_index));
|
||||
rtk_check_del_timer(pfe_index);
|
||||
rtk_check_del_timer(pfe_index, conn);
|
||||
}
|
||||
|
||||
if (conn->profile_refcount[pfe_index])
|
||||
@@ -2179,11 +2207,11 @@ static void rtk_parse_event_data(struct rtl_coex_struct *coex,
|
||||
}
|
||||
}
|
||||
|
||||
const char l2_dir_str[][4] = {
|
||||
static const char l2_dir_str[][4] = {
|
||||
"RX", "TX",
|
||||
};
|
||||
|
||||
void rtl_process_l2_sig(struct rtl_l2_buff *l2)
|
||||
static void rtl_process_l2_sig(struct rtl_l2_buff *l2)
|
||||
{
|
||||
/* u8 flag; */
|
||||
u8 code;
|
||||
@@ -2371,6 +2399,7 @@ static inline int cmd_cmplt_filter_out(u8 *buf)
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
case HCI_VENDOR_MAILBOX_CMD:
|
||||
#endif
|
||||
case HCI_VENDOR_SET_PROFILE_REPORT_COMMAND:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
@@ -2391,7 +2420,7 @@ static inline int cmd_status_filter_out(u8 *buf)
|
||||
}
|
||||
}
|
||||
|
||||
int ev_filter_out(u8 *buf)
|
||||
static int ev_filter_out(u8 *buf)
|
||||
{
|
||||
switch (buf[0]) {
|
||||
case HCI_EV_INQUIRY_COMPLETE:
|
||||
@@ -2890,6 +2919,14 @@ static inline void rtl_free_frags(struct rtl_coex_struct *coex)
|
||||
spin_unlock_irqrestore(&coex->rxlock, flags);
|
||||
}
|
||||
|
||||
static void check_profileinfo_cmd(void)
|
||||
{
|
||||
//1 + 6 * handle_bumfer, handle_number = 0
|
||||
uint8_t profileinfo_buf[] = {0x00};
|
||||
rtk_vendor_cmd_to_fw(HCI_VENDOR_SET_PROFILE_REPORT_COMMAND, 1,
|
||||
profileinfo_buf);
|
||||
}
|
||||
|
||||
void rtk_btcoex_open(struct hci_dev *hdev)
|
||||
{
|
||||
if (test_and_set_bit(RTL_COEX_RUNNING, &btrtl_coex.flags)) {
|
||||
@@ -2915,22 +2952,6 @@ void rtk_btcoex_open(struct hci_dev *hdev)
|
||||
#endif /* RTB_SOFTWARE_MAILBOX */
|
||||
INIT_DELAYED_WORK(&btrtl_coex.l2_work, (void *)rtl_l2_work);
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 0)
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
timer_setup(&btrtl_coex.polling_timer, polling_bt_info, 0);
|
||||
#endif
|
||||
timer_setup(&btrtl_coex.a2dp_count_timer, count_a2dp_packet_timeout, 0);
|
||||
timer_setup(&btrtl_coex.pan_count_timer, count_pan_packet_timeout, 0);
|
||||
timer_setup(&btrtl_coex.hogp_count_timer, count_hogp_packet_timeout, 0);
|
||||
#else
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
setup_timer(&btrtl_coex.polling_timer, polling_bt_info, 0);
|
||||
#endif
|
||||
setup_timer(&btrtl_coex.a2dp_count_timer, count_a2dp_packet_timeout, 0);
|
||||
setup_timer(&btrtl_coex.pan_count_timer, count_pan_packet_timeout, 0);
|
||||
setup_timer(&btrtl_coex.hogp_count_timer, count_hogp_packet_timeout, 0);
|
||||
#endif
|
||||
|
||||
btrtl_coex.hdev = hdev;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
btrtl_coex.wifi_on = 0;
|
||||
@@ -2950,7 +2971,7 @@ void rtk_btcoex_open(struct hci_dev *hdev)
|
||||
#endif
|
||||
rtkbt_coexmsg_send(invite_req, sizeof(invite_req));
|
||||
#endif
|
||||
|
||||
check_profileinfo_cmd();
|
||||
/* Just for test */
|
||||
//ctl.polling_enable = 1;
|
||||
//ctl.polling_time = 1;
|
||||
@@ -2993,10 +3014,6 @@ void rtk_btcoex_close(void)
|
||||
}
|
||||
#endif /* RTB_SOFTWARE_MAILBOX */
|
||||
|
||||
del_timer_sync(&btrtl_coex.a2dp_count_timer);
|
||||
del_timer_sync(&btrtl_coex.pan_count_timer);
|
||||
del_timer_sync(&btrtl_coex.hogp_count_timer);
|
||||
|
||||
cancel_delayed_work_sync(&btrtl_coex.fw_work);
|
||||
cancel_delayed_work_sync(&btrtl_coex.l2_work);
|
||||
|
||||
@@ -3008,6 +3025,7 @@ void rtk_btcoex_close(void)
|
||||
btrtl_coex.profile_refcount[kk] = 0;
|
||||
|
||||
rtl_free_frags(&btrtl_coex);
|
||||
profileinfo_cmd = 0;
|
||||
RTKBT_DBG("-x");
|
||||
}
|
||||
|
||||
@@ -3033,6 +3051,7 @@ void rtk_btcoex_init(void)
|
||||
#endif
|
||||
#endif /* RTB_SOFTWARE_MAILBOX */
|
||||
btrtl_coex.fw_wq = create_workqueue("btfwwork");
|
||||
btrtl_coex.timer_wq = create_workqueue("bttimerwork");
|
||||
rtl_alloc_buff(&btrtl_coex);
|
||||
spin_lock_init(&btrtl_coex.rxlock);
|
||||
}
|
||||
@@ -3051,5 +3070,7 @@ void rtk_btcoex_exit(void)
|
||||
#endif
|
||||
flush_workqueue(btrtl_coex.fw_wq);
|
||||
destroy_workqueue(btrtl_coex.fw_wq);
|
||||
flush_workqueue(btrtl_coex.timer_wq);
|
||||
destroy_workqueue(btrtl_coex.timer_wq);
|
||||
rtl_free_buff(&btrtl_coex);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
|
||||
//vendor cmd to fw
|
||||
#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_COMMAND 0xfc19
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_LEGACY_COMMAND 0xfc19
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_COMMAND 0xfc1B
|
||||
#define HCI_VENDOR_MAILBOX_CMD 0xfc8f
|
||||
#define HCI_VENDOR_SET_BITPOOL 0xfc51
|
||||
|
||||
@@ -127,7 +128,7 @@
|
||||
#define PSM_AVDTP 0x0019
|
||||
#define PSM_FTP 0x1001
|
||||
#define PSM_BIP 0x1003
|
||||
#define PSM_OPP 0x1015
|
||||
#define PSM_OPP 0x1005
|
||||
//--add more if needed--//
|
||||
|
||||
enum {
|
||||
@@ -159,8 +160,16 @@ typedef struct {
|
||||
typedef struct rtl_hci_conn {
|
||||
struct list_head list;
|
||||
uint16_t handle;
|
||||
struct delayed_work a2dp_count_work;
|
||||
struct delayed_work pan_count_work;
|
||||
struct delayed_work hogp_count_work;
|
||||
uint32_t a2dp_packet_count;
|
||||
uint32_t pan_packet_count;
|
||||
uint32_t hogp_packet_count;
|
||||
uint32_t voice_packet_count;
|
||||
uint8_t type; // 0:l2cap, 1:sco/esco, 2:le
|
||||
uint8_t profile_bitmap;
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[8];
|
||||
} rtk_conn_prof, *prtk_conn_prof;
|
||||
|
||||
@@ -222,14 +231,12 @@ struct rtl_coex_struct {
|
||||
struct sockaddr_in wifi_addr;
|
||||
struct timer_list polling_timer;
|
||||
#endif
|
||||
struct timer_list a2dp_count_timer;
|
||||
struct timer_list pan_count_timer;
|
||||
struct timer_list hogp_count_timer;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
struct workqueue_struct *sock_wq;
|
||||
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;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
@@ -238,12 +245,8 @@ struct rtl_coex_struct {
|
||||
struct urb *urb;
|
||||
spinlock_t spin_lock_sock;
|
||||
spinlock_t spin_lock_profile;
|
||||
uint32_t a2dp_packet_count;
|
||||
uint32_t pan_packet_count;
|
||||
uint32_t hogp_packet_count;
|
||||
uint32_t voice_packet_count;
|
||||
uint8_t profile_bitmap;
|
||||
uint8_t profile_status;
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[8];
|
||||
uint8_t ispairing;
|
||||
uint8_t isinquirying;
|
||||
|
||||
@@ -83,6 +83,7 @@ static struct list_head list_extracfgs;
|
||||
#define HCI_VENDOR_CHANGE_BDRATE 0xfc17
|
||||
#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d
|
||||
#define HCI_VENDOR_READ_LMP_VERISION 0x1001
|
||||
#define HCI_VENDOR_READ_CMD 0xfc61
|
||||
|
||||
#define ROM_LMP_NONE 0x0000
|
||||
#define ROM_LMP_8723a 0x1200
|
||||
@@ -92,11 +93,34 @@ static struct list_head list_extracfgs;
|
||||
#define ROM_LMP_8822b 0X8822
|
||||
#define ROM_LMP_8852a 0x8852
|
||||
|
||||
#define PATCH_SNIPPETS 0x01
|
||||
#define PATCH_DUMMY_HEADER 0x02
|
||||
#define PATCH_SECURITY_HEADER 0x03
|
||||
#define PATCH_OTA_FLAG 0x04
|
||||
#define SECTION_HEADER_SIZE 8
|
||||
|
||||
struct rtk_eversion_evt {
|
||||
uint8_t status;
|
||||
uint8_t version;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtk_security_proj_evt {
|
||||
uint8_t status;
|
||||
uint8_t key_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtk_chip_type_evt {
|
||||
uint8_t status;
|
||||
uint16_t chip;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum rtk_read_class {
|
||||
READ_NONE = 0,
|
||||
READ_CHIP_TYPE = 1,
|
||||
READ_CHIP_VER = 2,
|
||||
READ_SEC_PROJ = 3
|
||||
};
|
||||
|
||||
struct rtk_epatch_entry {
|
||||
uint16_t chipID;
|
||||
uint16_t patch_length;
|
||||
@@ -105,8 +129,8 @@ struct rtk_epatch_entry {
|
||||
|
||||
struct rtk_epatch {
|
||||
uint8_t signature[8];
|
||||
uint32_t fw_version;
|
||||
uint16_t number_of_total_patch;
|
||||
__le32 fw_version;
|
||||
__le16 number_of_total_patch;
|
||||
struct rtk_epatch_entry entry[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
@@ -116,13 +140,30 @@ struct rtk_extension_entry {
|
||||
uint8_t *data;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
//signature: Realtech
|
||||
const uint8_t RTK_EPATCH_SIGNATURE[8] =
|
||||
{ 0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68 };
|
||||
//Extension Section IGNATURE:0x77FD0451
|
||||
const uint8_t Extension_Section_SIGNATURE[4] = { 0x51, 0x04, 0xFD, 0x77 };
|
||||
struct rtb_section_hdr {
|
||||
uint32_t opcode;
|
||||
uint32_t section_len;
|
||||
uint32_t soffset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
uint16_t project_id[] = {
|
||||
struct rtb_new_patch_hdr {
|
||||
uint8_t signature[8];
|
||||
uint8_t fw_version[8];
|
||||
__le32 number_of_section;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
//signature: Realtech
|
||||
static const uint8_t RTK_EPATCH_SIGNATURE[8] =
|
||||
{ 0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68 };
|
||||
|
||||
//signature: RTBTCore
|
||||
static const uint8_t RTK_EPATCH_SIGNATURE_NEW[8] =
|
||||
{ 0x52, 0x54, 0x42, 0x54, 0x43, 0x6F, 0x72, 0x65 };
|
||||
|
||||
//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,
|
||||
@@ -149,6 +190,14 @@ uint16_t project_id[] = {
|
||||
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 */
|
||||
};
|
||||
|
||||
enum rtk_endpoit {
|
||||
@@ -169,6 +218,7 @@ enum rtk_endpoit {
|
||||
#define RTL8723FU 0x76
|
||||
#define RTL8852BU 0x77
|
||||
#define RTL8852CU 0x78
|
||||
#define RTL8822EU 0x79
|
||||
|
||||
typedef struct {
|
||||
uint16_t prod_id;
|
||||
@@ -210,21 +260,22 @@ typedef struct {
|
||||
} __attribute__ ((packed)) download_rp;
|
||||
|
||||
#define RTK_VENDOR_CONFIG_MAGIC 0x8723ab55
|
||||
const u8 cfg_magic[4] = { 0x55, 0xab, 0x23, 0x87 };
|
||||
static const u8 cfg_magic[4] = { 0x55, 0xab, 0x23, 0x87 };
|
||||
struct rtk_bt_vendor_config_entry {
|
||||
uint16_t offset;
|
||||
__le16 offset;
|
||||
uint8_t entry_len;
|
||||
uint8_t entry_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtk_bt_vendor_config {
|
||||
uint32_t signature;
|
||||
uint16_t data_len;
|
||||
__le32 signature;
|
||||
__le16 data_len;
|
||||
struct rtk_bt_vendor_config_entry entry[0];
|
||||
} __attribute__ ((packed));
|
||||
#define BT_CONFIG_HDRLEN sizeof(struct rtk_bt_vendor_config)
|
||||
|
||||
static uint8_t gEVersion = 0xFF;
|
||||
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);
|
||||
@@ -235,6 +286,7 @@ static int download_data(xchange_data * xdata);
|
||||
static int send_hci_cmd(xchange_data * xdata);
|
||||
static int rcv_hci_evt(xchange_data * xdata);
|
||||
static uint8_t rtk_get_eversion(dev_data * dev_entry);
|
||||
static int rtk_vendor_read(dev_data * dev_entry, uint8_t class);
|
||||
|
||||
static patch_info fw_patch_table[] = {
|
||||
/* { pid, lmp_sub, mp_fw_name, fw_name, config_name, chip_type } */
|
||||
@@ -313,6 +365,9 @@ static patch_info fw_patch_table[] = {
|
||||
{0x3533, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
|
||||
{0x3538, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
|
||||
{0x3539, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
|
||||
{0x3558, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
|
||||
{0x3559, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
|
||||
{0x3581, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
|
||||
{0x3540, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
|
||||
{0x3541, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for GSD */
|
||||
{0x3543, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for GSD */
|
||||
@@ -321,7 +376,7 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
|
||||
{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_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8821DU */
|
||||
{0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU */
|
||||
|
||||
{0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
|
||||
{0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
|
||||
@@ -379,8 +434,8 @@ static patch_info fw_patch_table[] = {
|
||||
{0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
{0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
|
||||
{0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", RTL8852BU}, /* RTL8851AU */
|
||||
{0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BU */
|
||||
{0x8851, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8851AU */
|
||||
{0xb85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BE */
|
||||
{0xb85c, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BE */
|
||||
{0x3571, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BE */
|
||||
@@ -406,13 +461,16 @@ static patch_info fw_patch_table[] = {
|
||||
{0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
|
||||
{0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
|
||||
{0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
|
||||
|
||||
/* NOTE: must append patch entries above the null entry */
|
||||
{0, 0, NULL, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
static LIST_HEAD(dev_data_list);
|
||||
|
||||
void util_hexdump(const u8 *buf, size_t len)
|
||||
static void util_hexdump(const u8 *buf, size_t len)
|
||||
{
|
||||
static const char hexdigits[] = "0123456789abcdef";
|
||||
char str[16 * 3];
|
||||
@@ -452,48 +510,6 @@ int __rtk_send_hci_cmd(struct usb_device *udev, u8 *buf, u16 size)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int __rtk_recv_hci_evt(struct usb_device *udev, u8 *buf, u8 len, u16 opcode)
|
||||
{
|
||||
int recv_length = 0;
|
||||
int result = 0;
|
||||
int i;
|
||||
unsigned int pipe = usb_rcvintpipe(udev, 1);
|
||||
struct hci_event_hdr *hdr;
|
||||
struct hci_ev_cmd_complete *cmd_cmpl;
|
||||
|
||||
if (len < sizeof(*hdr) + sizeof(*cmd_cmpl)) {
|
||||
RTKBT_ERR("%s: Invalid buf length %u", __func__, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
for (i = 0; i < 5; i++) {
|
||||
result = usb_interrupt_msg(udev, pipe,
|
||||
(void *)buf, PKT_LEN,
|
||||
&recv_length, MSG_TO);
|
||||
if (result >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
RTKBT_ERR("%s; Couldn't receive HCI event, err %d",
|
||||
__func__, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Ignore the event which is not command complete event */
|
||||
if (recv_length < sizeof(*hdr) + sizeof(*cmd_cmpl))
|
||||
continue;
|
||||
|
||||
hdr = (struct hci_event_hdr *)buf;
|
||||
cmd_cmpl = (struct hci_ev_cmd_complete *)(buf + sizeof(*hdr));
|
||||
if (hdr->evt == 0x0e) {
|
||||
if (opcode == cmd_cmpl->opcode)
|
||||
return recv_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
|
||||
@@ -643,7 +659,7 @@ int patch_add(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
udev = interface_to_usbdev(intf);
|
||||
#if BTUSB_RPM
|
||||
#ifdef BTUSB_RPM
|
||||
RTKBT_DBG("auto suspend is enabled");
|
||||
usb_enable_autosuspend(udev);
|
||||
pm_runtime_set_autosuspend_delay(&(udev->dev), 2000);
|
||||
@@ -679,7 +695,7 @@ void patch_remove(struct usb_interface *intf)
|
||||
struct usb_device *udev;
|
||||
|
||||
udev = interface_to_usbdev(intf);
|
||||
#if BTUSB_RPM
|
||||
#ifdef BTUSB_RPM
|
||||
usb_disable_autosuspend(udev);
|
||||
#endif
|
||||
|
||||
@@ -747,6 +763,9 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
case RTL8852CU:
|
||||
max_patch_size = 0x130D0 + 529; /* 76.2KB */
|
||||
break;
|
||||
case RTL8822EU:
|
||||
max_patch_size = 0x24620 + 529; /* 145KB */
|
||||
break;
|
||||
default:
|
||||
max_patch_size = 40 * 1024;
|
||||
break;
|
||||
@@ -755,6 +774,38 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
return max_patch_size;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
chip = rtk_vendor_read(dev_entry, READ_CHIP_TYPE);
|
||||
if(chip == 0x8822) {
|
||||
chip_ver = rtk_vendor_read(dev_entry, READ_CHIP_VER);
|
||||
if(chip_ver == 0x000e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret_val = check_fw_version(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("Failed to get Local Version Information");
|
||||
return ret_val;
|
||||
|
||||
} else if (ret_val > 0) {
|
||||
RTKBT_DBG("Firmware already exists");
|
||||
/* Patch alread exists, just return */
|
||||
if (gEVersion == 0xff) {
|
||||
RTKBT_DBG("global_version is not set, get it!");
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int download_patch(struct usb_interface *intf)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
@@ -781,21 +832,10 @@ int download_patch(struct usb_interface *intf)
|
||||
|
||||
init_xdata(xdata, dev_entry);
|
||||
|
||||
ret_val = check_fw_version(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("Failed to get Local Version Information");
|
||||
ret_val = check_fw_chip_ver(dev_entry, xdata);
|
||||
if (ret_val != 0 )
|
||||
goto patch_end;
|
||||
|
||||
} else if (ret_val > 0) {
|
||||
RTKBT_DBG("Firmware already exists");
|
||||
/* Patch alread exists, just return */
|
||||
if (gEVersion == 0xff) {
|
||||
RTKBT_DBG("global_version is not set, get it!");
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
}
|
||||
goto patch_end;
|
||||
}
|
||||
|
||||
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
|
||||
if (xdata->fw_len <= 0) {
|
||||
RTKBT_ERR("load firmware failed!");
|
||||
@@ -856,6 +896,7 @@ patch_end:
|
||||
int download_lps_patch(struct usb_interface *intf)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
patch_info *pinfo;
|
||||
xchange_data *xdata = NULL;
|
||||
uint8_t *fw_buf;
|
||||
int result;
|
||||
@@ -863,6 +904,7 @@ int download_lps_patch(struct usb_interface *intf)
|
||||
char *origin_name1;
|
||||
char name2[64];
|
||||
char *origin_name2;
|
||||
int max_patch_size = 0;
|
||||
|
||||
RTKBT_DBG("Download LPS Patch start");
|
||||
dev_entry = dev_data_find(intf);
|
||||
@@ -956,6 +998,7 @@ patch_end:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
int set_scan(struct usb_interface *intf)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
@@ -989,7 +1032,6 @@ int set_scan(struct usb_interface *intf)
|
||||
if (result < 0)
|
||||
goto end;
|
||||
|
||||
result = rcv_hci_evt(xdata);
|
||||
end:
|
||||
kfree(xdata->send_pkt);
|
||||
kfree(xdata->rcv_pkt);
|
||||
@@ -999,6 +1041,7 @@ end:
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
dev_data *dev_data_find(struct usb_interface * intf)
|
||||
{
|
||||
@@ -1055,6 +1098,7 @@ static int is_mac(u8 chip_type, u16 offset)
|
||||
case RTL8723FU:
|
||||
case RTL8852BU:
|
||||
case RTL8852CU:
|
||||
case RTL8822EU:
|
||||
if (offset == 0x0030)
|
||||
return 1;
|
||||
break;
|
||||
@@ -1080,6 +1124,7 @@ static uint16_t get_mac_offset(u8 chip_type)
|
||||
case RTL8723FU:
|
||||
case RTL8852BU:
|
||||
case RTL8852CU:
|
||||
case RTL8822EU:
|
||||
return 0x0030;
|
||||
case RTLPREVIOUS:
|
||||
return 0x003c;
|
||||
@@ -1148,7 +1193,7 @@ static void merge_configs(struct list_head *head, struct list_head *head2)
|
||||
}
|
||||
}
|
||||
|
||||
int rtk_parse_config_file(u8 *config_buf, int filelen)
|
||||
static int rtk_parse_config_file(u8 *config_buf, int filelen)
|
||||
{
|
||||
struct rtk_bt_vendor_config *config = (void *)config_buf;
|
||||
u16 config_len = 0, temp = 0;
|
||||
@@ -1196,10 +1241,10 @@ int rtk_parse_config_file(u8 *config_buf, int filelen)
|
||||
temp);
|
||||
}
|
||||
|
||||
return 0;;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t rtk_get_fw_project_id(uint8_t * p_buf)
|
||||
static uint8_t rtk_get_fw_project_id(uint8_t * p_buf)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t len;
|
||||
@@ -1227,43 +1272,234 @@ uint8_t rtk_get_fw_project_id(uint8_t * p_buf)
|
||||
return data;
|
||||
}
|
||||
|
||||
static void rtk_get_patch_entry(uint8_t * epatch_buf,
|
||||
struct rtb_ota_flag {
|
||||
uint8_t eco;
|
||||
uint8_t enable;
|
||||
uint16_t reserve;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtb_security_hdr {
|
||||
uint8_t eco;
|
||||
uint8_t pri;
|
||||
uint8_t key_id;
|
||||
uint8_t reserve;
|
||||
uint32_t security_len;
|
||||
uint8_t *payload;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtb_dummy_hdr {
|
||||
uint8_t eco;
|
||||
uint8_t pri;
|
||||
uint8_t reserve;
|
||||
uint32_t dummy_len;
|
||||
uint8_t *payload;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtb_snippet_hdr {
|
||||
uint8_t eco;
|
||||
uint8_t pri;
|
||||
uint16_t reserve;
|
||||
uint32_t snippet_len;
|
||||
uint8_t *payload;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct patch_node {
|
||||
uint8_t eco;
|
||||
uint8_t pri;
|
||||
uint8_t key_id;
|
||||
uint8_t reserve;
|
||||
uint32_t len;
|
||||
uint8_t *payload;
|
||||
struct list_head list;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Add a node to alist that is in ascending order. */
|
||||
static void insert_queue_sort(struct list_head *head, struct patch_node *node)
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct list_head *next;
|
||||
struct patch_node *tmp;
|
||||
|
||||
if(!head || !node) {
|
||||
return;
|
||||
}
|
||||
list_for_each_safe(pos, next, head) {
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
if(tmp->pri >= node->pri)
|
||||
break;
|
||||
}
|
||||
__list_add(&node->list, pos->prev, pos);
|
||||
}
|
||||
|
||||
static int insert_patch(struct patch_node *patch_node_hdr, uint8_t *section_pos,
|
||||
uint32_t opcode, uint32_t *patch_len, uint8_t *sec_flag)
|
||||
{
|
||||
struct patch_node *tmp;
|
||||
int i;
|
||||
uint32_t numbers;
|
||||
uint32_t section_len = 0;
|
||||
uint8_t eco = 0;
|
||||
uint8_t *pos = section_pos + 8;
|
||||
|
||||
numbers = get_unaligned_le16(pos);
|
||||
RTKBT_DBG("number 0x%04x", numbers);
|
||||
|
||||
pos += 4;
|
||||
for (i = 0; i < numbers; i++) {
|
||||
eco = (uint8_t)*(pos);
|
||||
RTKBT_DBG("eco 0x%02x, Eversion:%02x", eco, gEVersion);
|
||||
if (eco == gEVersion + 1) {
|
||||
tmp = (struct patch_node*)kzalloc(sizeof(struct patch_node), GFP_KERNEL);
|
||||
tmp->pri = (uint8_t)*(pos + 1);
|
||||
if(opcode == PATCH_SECURITY_HEADER)
|
||||
tmp->key_id = (uint8_t)*(pos + 1);
|
||||
|
||||
section_len = get_unaligned_le32(pos + 4);
|
||||
tmp->len = section_len;
|
||||
*patch_len += section_len;
|
||||
RTKBT_DBG("Pri:%d, Patch length 0x%04x", tmp->pri, tmp->len);
|
||||
tmp->payload = pos + 8;
|
||||
if(opcode != PATCH_SECURITY_HEADER) {
|
||||
insert_queue_sort(&(patch_node_hdr->list), tmp);
|
||||
} else {
|
||||
if((g_key_id == tmp->key_id) && (g_key_id > 0)) {
|
||||
insert_queue_sort(&(patch_node_hdr->list), tmp);
|
||||
*sec_flag = 1;
|
||||
} else {
|
||||
pos += (8 + section_len);
|
||||
kfree(tmp);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
section_len = get_unaligned_le32(pos + 4);
|
||||
RTKBT_DBG("Patch length 0x%04x", section_len);
|
||||
}
|
||||
pos += (8 + section_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t *rtb_get_patch_header(int *len,
|
||||
struct patch_node *patch_node_hdr, uint8_t * epatch_buf,
|
||||
uint8_t key_id)
|
||||
{
|
||||
uint16_t i, j;
|
||||
struct rtb_new_patch_hdr *new_patch;
|
||||
uint8_t sec_flag = 0;
|
||||
uint32_t number_of_ota_flag;
|
||||
uint32_t patch_len = 0;
|
||||
uint8_t *section_pos;
|
||||
uint8_t *ota_flag_pos;
|
||||
uint32_t number_of_section;
|
||||
|
||||
struct rtb_section_hdr section_hdr;
|
||||
struct rtb_ota_flag ota_flag;
|
||||
|
||||
new_patch = (struct rtb_new_patch_hdr *)epatch_buf;
|
||||
number_of_section = le32_to_cpu(new_patch->number_of_section);
|
||||
|
||||
RTKBT_DBG("FW version 0x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x",
|
||||
*(epatch_buf + 8), *(epatch_buf + 9), *(epatch_buf + 10),
|
||||
*(epatch_buf + 11),*(epatch_buf + 12), *(epatch_buf + 13),
|
||||
*(epatch_buf + 14), *(epatch_buf + 15));
|
||||
|
||||
section_pos = epatch_buf + 20;
|
||||
|
||||
for (i = 0; i < number_of_section; i++) {
|
||||
section_hdr.opcode = get_unaligned_le32(section_pos);
|
||||
section_hdr.section_len = get_unaligned_le32(section_pos + 4);
|
||||
RTKBT_DBG("opcode 0x%04x", section_hdr.opcode);
|
||||
|
||||
switch (section_hdr.opcode) {
|
||||
case PATCH_SNIPPETS:
|
||||
insert_patch(patch_node_hdr, section_pos, PATCH_SNIPPETS, &patch_len, NULL);
|
||||
break;
|
||||
case PATCH_SECURITY_HEADER:
|
||||
if(!g_key_id)
|
||||
break;
|
||||
|
||||
sec_flag = 0;
|
||||
insert_patch(patch_node_hdr, section_pos, PATCH_SECURITY_HEADER, &patch_len, &sec_flag);
|
||||
if(sec_flag)
|
||||
break;
|
||||
|
||||
for (i = 0; i < number_of_section; i++) {
|
||||
section_hdr.opcode = get_unaligned_le32(section_pos);
|
||||
section_hdr.section_len = get_unaligned_le32(section_pos + 4);
|
||||
if(section_hdr.opcode == PATCH_DUMMY_HEADER) {
|
||||
insert_patch(patch_node_hdr, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL);
|
||||
}
|
||||
section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len);
|
||||
}
|
||||
break;
|
||||
case PATCH_DUMMY_HEADER:
|
||||
if(g_key_id) {
|
||||
break;
|
||||
}
|
||||
insert_patch(patch_node_hdr, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL);
|
||||
break;
|
||||
case PATCH_OTA_FLAG:
|
||||
ota_flag_pos = section_pos + 4;
|
||||
number_of_ota_flag = get_unaligned_le32(ota_flag_pos);
|
||||
ota_flag.eco = (uint8_t)*(ota_flag_pos + 1);
|
||||
if (ota_flag.eco == gEVersion + 1) {
|
||||
for (j = 0; j < number_of_ota_flag; j++) {
|
||||
if (ota_flag.eco == gEVersion + 1) {
|
||||
ota_flag.enable = get_unaligned_le32(ota_flag_pos + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
RTKBT_ERR("Wrong Opcode");
|
||||
goto wrong_opcode;
|
||||
}
|
||||
section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len);
|
||||
}
|
||||
*len = patch_len;
|
||||
|
||||
wrong_opcode:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rtk_get_patch_entry(uint8_t * epatch_buf,
|
||||
struct rtk_epatch_entry *entry)
|
||||
{
|
||||
uint32_t svn_ver;
|
||||
uint32_t coex_ver;
|
||||
uint32_t tmp;
|
||||
uint16_t i;
|
||||
uint16_t number_of_total_patch;
|
||||
struct rtk_epatch *epatch_info = (struct rtk_epatch *)epatch_buf;
|
||||
|
||||
epatch_info->number_of_total_patch =
|
||||
number_of_total_patch =
|
||||
le16_to_cpu(epatch_info->number_of_total_patch);
|
||||
RTKBT_DBG("fw_version = 0x%x", le32_to_cpu(epatch_info->fw_version));
|
||||
RTKBT_DBG("number_of_total_patch = %d",
|
||||
epatch_info->number_of_total_patch);
|
||||
RTKBT_DBG("number_of_total_patch = %d", number_of_total_patch);
|
||||
|
||||
/* get right epatch entry */
|
||||
for (i = 0; i < epatch_info->number_of_total_patch; i++) {
|
||||
for (i = 0; i < number_of_total_patch; i++) {
|
||||
if (get_unaligned_le16(epatch_buf + 14 + 2 * i) ==
|
||||
gEVersion + 1) {
|
||||
entry->chipID = gEVersion + 1;
|
||||
entry->patch_length = get_unaligned_le16(epatch_buf +
|
||||
14 +
|
||||
2 * epatch_info->number_of_total_patch +
|
||||
2 * number_of_total_patch +
|
||||
2 * i);
|
||||
entry->start_offset = get_unaligned_le32(epatch_buf +
|
||||
14 +
|
||||
4 * epatch_info-> number_of_total_patch +
|
||||
4 * number_of_total_patch +
|
||||
4 * i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= epatch_info->number_of_total_patch) {
|
||||
if (i >= number_of_total_patch) {
|
||||
entry->patch_length = 0;
|
||||
entry->start_offset = 0;
|
||||
RTKBT_ERR("No corresponding patch found\n");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
svn_ver = get_unaligned_le32(epatch_buf +
|
||||
@@ -1281,9 +1517,11 @@ static void rtk_get_patch_entry(uint8_t * epatch_buf,
|
||||
tmp = ((coex_ver >> 16) & 0x7ff) + (coex_ver >> 27) * 10000;
|
||||
RTKBT_DBG("Coexistence: BTCOEX_20%06d-%04x",
|
||||
tmp, (coex_ver & 0xffff));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bachk(const char *str)
|
||||
static int bachk(const char *str)
|
||||
{
|
||||
if (!str)
|
||||
return -1;
|
||||
@@ -1392,7 +1630,7 @@ static u8 *load_config(dev_data *dev_entry, int *length)
|
||||
RTKBT_INFO("config filename %s", config_name);
|
||||
result = request_firmware(&fw, config_name, &udev->dev);
|
||||
if (result < 0)
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
file_sz = fw->size;
|
||||
buf = (u8 *)fw->data;
|
||||
@@ -1496,6 +1734,95 @@ done:
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
|
||||
{
|
||||
struct rtk_chip_type_evt *chip_type;
|
||||
struct rtk_security_proj_evt *sec_proj;
|
||||
patch_info *patch_entry;
|
||||
int ret_val = 0;
|
||||
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};
|
||||
|
||||
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
|
||||
if (NULL == xdata) {
|
||||
ret_val = 0xFE;
|
||||
RTKBT_DBG("NULL == xdata");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
init_xdata(xdata, dev_entry);
|
||||
|
||||
xdata->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_READ_CMD);
|
||||
xdata->cmd_hdr->plen = 5;
|
||||
memcpy(xdata->send_pkt, &(xdata->cmd_hdr->opcode), 2);
|
||||
memcpy(xdata->send_pkt+2, &(xdata->cmd_hdr->plen), 1);
|
||||
|
||||
switch (class) {
|
||||
case READ_CHIP_TYPE:
|
||||
memcpy(xdata->send_pkt+3, cmd_ct_buf, sizeof(cmd_ct_buf));
|
||||
break;
|
||||
case READ_CHIP_VER:
|
||||
memcpy(xdata->send_pkt+3, cmd_cv_buf, sizeof(cmd_cv_buf));
|
||||
break;
|
||||
case READ_SEC_PROJ:
|
||||
memcpy(xdata->send_pkt+3, cmd_sec_buf, sizeof(cmd_sec_buf));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
xdata->pkt_len = CMD_HDR_LEN + 5;
|
||||
|
||||
ret_val = send_hci_cmd(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("Failed to send read RTK chip_type cmd.");
|
||||
ret_val = 0xFE;
|
||||
goto read_end;
|
||||
}
|
||||
|
||||
ret_val = rcv_hci_evt(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("Failed to receive HCI event for chip type.");
|
||||
ret_val = 0xFE;
|
||||
goto read_end;
|
||||
}
|
||||
|
||||
patch_entry = xdata->dev_entry->patch_entry;
|
||||
if(class == READ_SEC_PROJ){
|
||||
sec_proj = (struct rtk_security_proj_evt *)(xdata->rsp_para);
|
||||
RTKBT_DBG("sec_proj->status = 0x%x, sec_proj->key_id = 0x%x",
|
||||
sec_proj->status, sec_proj->key_id);
|
||||
if (sec_proj->status) {
|
||||
ret_val = 0;
|
||||
} else {
|
||||
ret_val = sec_proj->key_id;
|
||||
g_key_id = sec_proj->key_id;
|
||||
}
|
||||
} else {
|
||||
chip_type = (struct rtk_chip_type_evt *)(xdata->rsp_para);
|
||||
RTKBT_DBG("chip_type->status = 0x%x, chip_type->chip = 0x%x",
|
||||
chip_type->status, chip_type->chip);
|
||||
if (chip_type->status) {
|
||||
ret_val = 0;
|
||||
} else {
|
||||
ret_val = chip_type->chip;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
read_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;
|
||||
}
|
||||
|
||||
int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
@@ -1509,6 +1836,10 @@ int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
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;
|
||||
|
||||
RTKBT_DBG("load_firmware start");
|
||||
udev = dev_entry->udev;
|
||||
patch_entry = dev_entry->patch_entry;
|
||||
@@ -1518,15 +1849,18 @@ int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
config_file_buf = load_config(dev_entry, &config_len);
|
||||
|
||||
fw_name = patch_entry->patch_name;
|
||||
RTKBT_ERR("fw name is %s", fw_name);
|
||||
RTKBT_DBG("fw name is %s", fw_name);
|
||||
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)
|
||||
goto alloc_fail;
|
||||
@@ -1567,7 +1901,7 @@ int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
}
|
||||
|
||||
/* check Signature and Extension Section Field */
|
||||
if ((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) != 0) ||
|
||||
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");
|
||||
@@ -1586,30 +1920,65 @@ int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
RTKBT_DBG
|
||||
("lmp_version is %x, project_id is %x, match!",
|
||||
lmp_version, project_id[proj_id]);
|
||||
rtk_get_patch_entry(epatch_buf, ¤t_entry);
|
||||
|
||||
if (current_entry.patch_length == 0)
|
||||
goto alloc_fail;
|
||||
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);
|
||||
|
||||
buf_len =
|
||||
current_entry.patch_length + config_len;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
if (current_entry.patch_length == 0)
|
||||
goto alloc_fail;
|
||||
|
||||
buf_len = current_entry.patch_length + config_len;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
}
|
||||
|
||||
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
|
||||
RTKBT_ERR
|
||||
("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
} 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1662,6 +2031,7 @@ int check_fw_version(xchange_data * xdata)
|
||||
patch_info *patch_entry;
|
||||
int ret_val;
|
||||
int retry = 0;
|
||||
uint16_t lmp_subver, hci_rev, manufacturer;
|
||||
|
||||
/* Ensure that the first cmd is hci reset after system suspend
|
||||
* or system reboot */
|
||||
@@ -1686,14 +2056,14 @@ get_ver:
|
||||
|
||||
patch_entry = xdata->dev_entry->patch_entry;
|
||||
read_ver_rsp = (struct hci_rp_read_local_version *)(xdata->rsp_para);
|
||||
read_ver_rsp->lmp_subver = le16_to_cpu(read_ver_rsp->lmp_subver);
|
||||
read_ver_rsp->hci_rev = le16_to_cpu(read_ver_rsp->hci_rev);
|
||||
read_ver_rsp->manufacturer = le16_to_cpu(read_ver_rsp->manufacturer);
|
||||
lmp_subver = le16_to_cpu(read_ver_rsp->lmp_subver);
|
||||
hci_rev = le16_to_cpu(read_ver_rsp->hci_rev);
|
||||
manufacturer = le16_to_cpu(read_ver_rsp->manufacturer);
|
||||
|
||||
RTKBT_DBG("read_ver_rsp->lmp_subver = 0x%x", read_ver_rsp->lmp_subver);
|
||||
RTKBT_DBG("read_ver_rsp->hci_rev = 0x%x", read_ver_rsp->hci_rev);
|
||||
RTKBT_DBG("read_ver_rsp->lmp_subver = 0x%x", lmp_subver);
|
||||
RTKBT_DBG("read_ver_rsp->hci_rev = 0x%x", hci_rev);
|
||||
RTKBT_DBG("patch_entry->lmp_sub = 0x%x", patch_entry->lmp_sub);
|
||||
if (patch_entry->lmp_sub != read_ver_rsp->lmp_subver) {
|
||||
if (patch_entry->lmp_sub != lmp_subver) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,12 @@
|
||||
* Download normal patch when host resume or power on */
|
||||
/* #define RTKBT_SWITCH_PATCH */
|
||||
|
||||
/* RTKBT Power-on for sideband wake-up by LE Advertising from Remote. */
|
||||
/* Note that it's necessary to apply TV FW Patch. */
|
||||
/* #define RTKBT_SUSPEND_WAKEUP */
|
||||
/* #define RTKBT_SHUTDOWN_WAKEUP */
|
||||
#define RTKBT_POWERKEY_WAKEUP
|
||||
|
||||
/* RTKBT Power-on Whitelist for sideband wake-up by LE Advertising from Remote.
|
||||
* Note that it's necessary to apply TV FW Patch. */
|
||||
/* #define RTKBT_TV_POWERON_WHITELIST */
|
||||
@@ -39,9 +45,7 @@
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
|
||||
#define USB_RPM 1
|
||||
#else
|
||||
#define USB_RPM 0
|
||||
#define USB_RPM
|
||||
#endif
|
||||
|
||||
#define CONFIG_NEEDS_BINDING
|
||||
@@ -51,9 +55,10 @@
|
||||
#undef CONFIG_NEEDS_BINDING
|
||||
#endif
|
||||
|
||||
|
||||
/* 1 SS enable; 0 SS disable */
|
||||
#define BTUSB_RPM (0*USB_RPM)
|
||||
/* USB SS */
|
||||
#if (defined CONFIG_BTUSB_AUTOSUSPEND) && (defined USB_RPM)
|
||||
#define BTUSB_RPM
|
||||
#endif
|
||||
|
||||
#define PRINT_CMD_EVENT 0
|
||||
#define PRINT_ACL_DATA 0
|
||||
@@ -67,7 +72,6 @@ extern void print_acl(struct sk_buff *skb, int dataOut);
|
||||
|
||||
#if defined RTKBT_SWITCH_PATCH || defined RTKBT_TV_POWERON_WHITELIST
|
||||
int __rtk_send_hci_cmd(struct usb_device *udev, u8 *buf, u16 size);
|
||||
int __rtk_recv_hci_evt(struct usb_device *udev, u8 *buf, u8 len, u16 opcode);
|
||||
#endif
|
||||
|
||||
#ifdef RTKBT_SWITCH_PATCH
|
||||
@@ -79,8 +83,10 @@ struct api_context {
|
||||
};
|
||||
|
||||
int download_lps_patch(struct usb_interface *intf);
|
||||
int set_scan(struct usb_interface *intf);
|
||||
#endif
|
||||
|
||||
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
int set_scan(struct usb_interface *intf);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user