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:
Sushil Kumar Singh
2023-01-19 22:25:01 +05:30
committed by mobile promotions
parent 6e2e6973cd
commit 5bc80fd7c9
7 changed files with 772 additions and 310 deletions

View File

@@ -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, &current_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, &current_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;
}