diff --git a/drivers/bluetooth/realtek/Makefile b/drivers/bluetooth/realtek/Makefile index d390fb98..8ab63f97 100644 --- a/drivers/bluetooth/realtek/Makefile +++ b/drivers/bluetooth/realtek/Makefile @@ -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 \ No newline at end of file + rtk_bt.o diff --git a/drivers/bluetooth/realtek/rtk_bt.c b/drivers/bluetooth/realtek/rtk_bt.c index defd5a79..95b7b7e4 100644 --- a/drivers/bluetooth/realtek/rtk_bt.c +++ b/drivers/bluetooth/realtek/rtk_bt.c @@ -15,13 +15,14 @@ #include #include #include +#include #include #include #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 #include -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 diff --git a/drivers/bluetooth/realtek/rtk_bt.h b/drivers/bluetooth/realtek/rtk_bt.h index b1612b08..9ed86dc5 100644 --- a/drivers/bluetooth/realtek/rtk_bt.h +++ b/drivers/bluetooth/realtek/rtk_bt.h @@ -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; }; diff --git a/drivers/bluetooth/realtek/rtk_coex.c b/drivers/bluetooth/realtek/rtk_coex.c index 6ccdea03..85eb91e0 100644 --- a/drivers/bluetooth/realtek/rtk_coex.c +++ b/drivers/bluetooth/realtek/rtk_coex.c @@ -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); } diff --git a/drivers/bluetooth/realtek/rtk_coex.h b/drivers/bluetooth/realtek/rtk_coex.h index ba9de4a6..5d5912ff 100644 --- a/drivers/bluetooth/realtek/rtk_coex.h +++ b/drivers/bluetooth/realtek/rtk_coex.h @@ -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; diff --git a/drivers/bluetooth/realtek/rtk_misc.c b/drivers/bluetooth/realtek/rtk_misc.c index 63dadded..4e0a1219 100644 --- a/drivers/bluetooth/realtek/rtk_misc.c +++ b/drivers/bluetooth/realtek/rtk_misc.c @@ -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; } diff --git a/drivers/bluetooth/realtek/rtk_misc.h b/drivers/bluetooth/realtek/rtk_misc.h index 84e856f3..4e0ad091 100644 --- a/drivers/bluetooth/realtek/rtk_misc.h +++ b/drivers/bluetooth/realtek/rtk_misc.h @@ -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