Path: blob/next/external/cache/sources/rtk_hciattach/rtb_fwc.c
18115 views
/*1* Copyright (C) 2018 Realtek Semiconductor Corporation.2*3* This program is free software; you can redistribute it and/or modify4* it under the terms of the GNU General Public License as published by5* the Free Software Foundation; either version 2 of the License, or6* (at your option) any later version.7*8* This program is distributed in the hope that it will be useful,9* but WITHOUT ANY WARRANTY; without even the implied warranty of10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11* GNU General Public License for more details.12*/1314#include <stdio.h>15#include <stdlib.h>16#include <stdint.h>17#include <string.h>18#include <sys/types.h>19#include <sys/stat.h>20#include <fcntl.h>21#include <errno.h>22#include <unistd.h>23#include <ctype.h>2425#ifndef PATH_MAX26#define PATH_MAX 102427#endif2829#include "hciattach.h"30#include "rtb_fwc.h"3132#define USE_CUSTOMER_ADDRESS3334#define FIRMWARE_DIRECTORY "/lib/firmware/rtlbt/"35#define BT_CONFIG_DIRECTORY "/lib/firmware/rtlbt/"3637#ifdef USE_CUSTOMER_ADDRESS38#define BT_ADDR_FILE "/opt/bdaddr"39static uint8_t customer_bdaddr = 0;40#endif4142struct list_head {43struct list_head *next, *prev;44};4546struct cfg_list_item {47struct list_head list;48uint16_t offset;49uint8_t len;50uint8_t data[0];51};5253static struct list_head list_configs;5455#define EXTRA_CONFIG_FILE "/opt/rtk_btconfig.txt"56static struct list_head list_extracfgs;5758struct rtb_cfg_item {59uint16_t offset;60uint8_t len;61uint8_t data[0];62} __attribute__ ((packed));6364#define RTB_CFG_HDR_LEN 66566struct rtb_patch_entry {67uint16_t chip_id;68uint16_t patch_len;69uint32_t soffset;70uint32_t svn_ver;71uint32_t coex_ver;72} __attribute__ ((packed));7374struct rtb_patch_hdr {75uint8_t signature[8];76uint32_t fw_version;77uint16_t number_of_patch;78struct rtb_patch_entry entry[0];79} __attribute__ ((packed));8081uint16_t project_id[]=82{83ROM_LMP_8723a,84ROM_LMP_8723b, /* RTL8723BS */85ROM_LMP_8821a, /* RTL8821AS */86ROM_LMP_8761a, /* RTL8761ATV */8788ROM_LMP_8703a,89ROM_LMP_8763a,90ROM_LMP_8703b,91ROM_LMP_8723c, /* index 7 for 8723CS. What is for other 8723CS */92ROM_LMP_8822b, /* RTL8822BS */93ROM_LMP_8723b, /* RTL8723DS */94ROM_LMP_8821a, /* id 10 for RTL8821CS, lmp subver 0x8821 */95ROM_LMP_NONE,96ROM_LMP_NONE,97ROM_LMP_8822c, /* id 13 for RTL8822CS, lmp subver 0x8822 */98ROM_LMP_8761a, /* id 14 for 8761B */99};100101static struct patch_info h4_patch_table[] = {102/* match flags, chip type, lmp subver, proj id(unused), hci_ver,103* hci_rev, ...104*/105106/* RTL8761AT */107{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8761AT,1080x8761, 0xffff, 0, 0x000a,109"rtl8761at_fw", "rtl8761at_config", "RTL8761AT" },110/* RTL8761ATF */111{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8761ATF,1120x8761, 0xffff, 0, 0x000a,113"rtl8761atf_fw", "rtl8761atf_config", "RTL8761ATF" },114/* RTL8761B(8763) H4 Test Chip without download115* FW/Config is not used.116*/117{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8761BTC,1180x8763, 0xffff, 0, 0x000b,119"rtl8761btc_fw", "rtl8761btc_config", "RTL8761BTC" },120/* RTL8761B H4 Test Chip wihtout download*/121{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8761BH4,1220x8761, 0xffff, 0, 0x000b,123"rtl8761bh4_fw", "rtl8761bh4_config", "RTL8761BH4" },124125/* RTL8723DS */126{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8723DS,127ROM_LMP_8723b, ROM_LMP_8723b, 8, 0x000d,128"rtl8723dsh4_fw", "rtl8723dsh4_config", "RTL8723DSH4"},129130{ 0, 0, 0, ROM_LMP_NONE, 0, 0, "rtl_none_fw", "rtl_none_config", "NONE"}131};132133static struct patch_info patch_table[] = {134/* match flags, chip type, lmp subver, proj id(unused), hci_ver,135* hci_rev, ...136*/137138/* RTL8723AS */139{ 0, 0, ROM_LMP_8723a, ROM_LMP_8723a, 0, 0,140"rtl8723a_fw", "rtl8723a_config", "RTL8723AS"},141/* RTL8821CS */142{ RTL_FW_MATCH_HCI_REV, CHIP_8821CS,143ROM_LMP_8821a, ROM_LMP_8821a, 0, 0x000c,144"rtl8821c_fw", "rtl8821c_config", "RTL8821CS"},145/* RTL8821AS */146{ 0, 0, ROM_LMP_8821a, ROM_LMP_8821a, 0, 0,147"rtl8821a_fw", "rtl8821a_config", "RTL8821AS"},148/* RTL8761ATV */149{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, 0,150ROM_LMP_8761a, ROM_LMP_8761a, 0x06, 0x000a,151"rtl8761a_fw", "rtl8761a_config", "RTL8761ATV"},152/* RTL8761BTV */153{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8761B,154ROM_LMP_8761a, ROM_LMP_8761a, 0x0a, 0x000b,155"rtl8761b_fw", "rtl8761b_config", "RTL8761BTV"},156157/* RTL8703AS158* RTL8822BS159* */160#ifdef RTL_8703A_SUPPORT161{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8703AS,162ROM_LMP_8723b, ROM_LMP_8723b, 0, 0,163"rtl8703a_fw", "rtl8703a_config", "RTL8703AS"},164#endif165{ RTL_FW_MATCH_HCI_REV, CHIP_8822BS,166ROM_LMP_8822b, ROM_LMP_8822b, 0, 0x000b,167"rtl8822b_fw", "rtl8822b_config", "RTL8822BS"},168{ RTL_FW_MATCH_HCI_REV, CHIP_8822CS,169ROM_LMP_8822c, ROM_LMP_8822c, 0, 0x000c,170"rtl8822cs_fw", "rtl8822cs_config", "RTL8822CS"},171172/* RTL8703BS173* RTL8723CS_XX174* RTL8723CS_CG175* RTL8723CS_VF176* Use the sampe lmp subversion 0x8703177* */178{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8703BS,179ROM_LMP_8703b, ROM_LMP_8703b, 0, 0,180"rtl8703b_fw", "rtl8703b_config", "RTL8703BS"},181{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_XX,182ROM_LMP_8703b, ROM_LMP_8723cs_xx, 0, 0,183"rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_XX"},184{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_CG,185ROM_LMP_8703b, ROM_LMP_8723cs_cg, 0, 0,186"rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_CG"},187{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_VF,188ROM_LMP_8703b, ROM_LMP_8723cs_vf, 0, 0,189"rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_VF"},190191/* RTL8723BS */192{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, 0,193ROM_LMP_8723b, ROM_LMP_8723b, 6, 0x000b,194"rtl8723b_fw", "rtl8723b_config", "RTL8723BS"},195/* RTL8723DS */196{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8723DS,197ROM_LMP_8723b, ROM_LMP_8723b, 8, 0x000d,198"rtl8723d_fw", "rtl8723d_config", "RTL8723DS"},199/* add entries here*/200201{ 0, 0, 0, ROM_LMP_NONE, 0, 0, "rtl_none_fw", "rtl_none_config", "NONE"}202};203204static __inline uint16_t get_unaligned_le16(uint8_t * p)205{206return (uint16_t) (*p) + ((uint16_t) (*(p + 1)) << 8);207}208209static __inline uint32_t get_unaligned_le32(uint8_t * p)210{211return (uint32_t) (*p) + ((uint32_t) (*(p + 1)) << 8) +212((uint32_t) (*(p + 2)) << 16) + ((uint32_t) (*(p + 3)) << 24);213}214215/* list head from kernel */216#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)217218#define container_of(ptr, type, member) ({ \219const typeof( ((type *)0)->member ) *__mptr = (ptr); \220(type *)( (char *)__mptr - offsetof(type,member) );})221222#define list_entry(ptr, type, member) \223container_of(ptr, type, member)224225#define list_for_each_safe(pos, n, head) \226for (pos = (head)->next, n = pos->next; pos != (head); \227pos = n, n = pos->next)228229static inline void INIT_LIST_HEAD(struct list_head *list)230{231list->next = list;232list->prev = list;233}234235static inline int list_empty(const struct list_head *head)236{237return head->next == head;238}239240static inline void __list_add(struct list_head *_new,241struct list_head *prev,242struct list_head *next)243{244next->prev = _new;245_new->next = next;246_new->prev = prev;247prev->next = _new;248}249250static inline void list_add_tail(struct list_head *_new, struct list_head *head)251{252__list_add(_new, head->prev, head);253}254255static inline void __list_del(struct list_head *prev, struct list_head *next)256{257next->prev = prev;258prev->next = next;259}260261#define LIST_POISON1 ((void *) 0x00100100)262#define LIST_POISON2 ((void *) 0x00200200)263static inline void list_del(struct list_head *entry)264{265__list_del(entry->prev, entry->next);266entry->next = (struct list_head*)LIST_POISON1;267entry->prev = (struct list_head*)LIST_POISON2;268}269270static inline void __list_splice(const struct list_head *list,271struct list_head *prev,272struct list_head *next)273{274struct list_head *first = list->next;275struct list_head *last = list->prev;276277first->prev = prev;278prev->next = first;279280last->next = next;281next->prev = last;282}283284static inline void list_splice_tail(struct list_head *list,285struct list_head *head)286{287if (!list_empty(list))288__list_splice(list, head->prev, head);289}290291static int config_lists_init(void)292{293INIT_LIST_HEAD(&list_configs);294INIT_LIST_HEAD(&list_extracfgs);295296return 0;297}298299static void config_lists_free(void)300{301struct list_head *iter;302struct list_head *tmp;303struct list_head *head;304struct cfg_list_item *n;305306if (!list_empty(&list_extracfgs))307list_splice_tail(&list_extracfgs, &list_configs);308head = &list_configs;309list_for_each_safe(iter, tmp, head) {310n = list_entry(iter, struct cfg_list_item, list);311if (n) {312list_del(&n->list);313free(n);314}315}316317INIT_LIST_HEAD(&list_configs);318INIT_LIST_HEAD(&list_extracfgs);319}320321static void line_process(char *buf, int len /*@unused@*/)322{323char *argv[32];324int argc = 0;325char *ptr = buf;326char *head = buf;327unsigned long int offset;328uint8_t l;329uint8_t i = 0;330struct cfg_list_item *item;331332RS_INFO("%s", buf);333334while ((ptr = strsep(&head, ", \t")) != NULL) {335if (!ptr[0])336continue;337argv[argc++] = ptr;338if (argc >= 32) {339RS_WARN("%s: Config item is too long", __func__);340break;341}342}343344if (argc < 4) {345RS_WARN("%s: Invalid Config item, ignore", __func__);346return;347}348349offset = strtoul(argv[0], NULL, 16);350offset = offset | (strtoul(argv[1], NULL, 16) << 8);351RS_INFO("Extra Config offset %04lx", offset);352l = (uint8_t)strtoul(argv[2], NULL, 16);353if (l != (uint8_t)(argc - 3)) {354RS_ERR("Invalid Config item len %u", l);355return;356}357358item = malloc(sizeof(*item) + l);359if (!item) {360RS_WARN("%s: Cannot alloc mem for item, %04lx, %u", __func__,361offset, l);362return;363}364365item->offset = (uint16_t)offset;366item->len = l;367for (i = 0; i < l; i++)368item->data[i] = (uint8_t)strtoul(argv[3 + i], NULL, 16);369list_add_tail(&item->list, &list_extracfgs);370}371372static void config_process(uint8_t *buf, int len /*@unused@*/)373{374char *head = (void *)buf;375char *ptr = (void *)buf;376377while ((ptr = strsep(&head, "\n\r")) != NULL) {378if (!ptr[0])379continue;380line_process(ptr, strlen(ptr) + 1);381}382}383384static void parse_extra_config(const char *path)385{386int fd;387uint8_t buf[256];388int result;389390fd = open(path, O_RDONLY);391if (fd == -1) {392RS_INFO("Couldnt open extra config %s, %s", path,393strerror(errno));394return;395}396397result = read(fd, buf, sizeof(buf));398if (result == -1) {399RS_ERR("Couldnt read %s, %s", path, strerror(errno));400goto done;401} else if (result == 0) {402RS_ERR("File is empty");403goto done;404}405406if (result > 254) {407RS_ERR("Extra Config file is too big");408goto done;409}410buf[result++] = '\n';411buf[result++] = '\0';412413config_process(buf, result);414415done:416close(fd);417}418419/* Get the entry from patch_table according to LMP subversion */420struct patch_info *get_patch_entry(struct rtb_struct *btrtl)421{422struct patch_info *n = NULL;423424if (btrtl->proto == HCI_UART_3WIRE)425n = patch_table;426else427n = h4_patch_table;428for (; n->lmp_subver; n++) {429if ((n->match_flags & RTL_FW_MATCH_CHIP_TYPE) &&430n->chip_type != btrtl->chip_type)431continue;432if ((n->match_flags & RTL_FW_MATCH_HCI_VER) &&433n->hci_ver != btrtl->hci_ver)434continue;435if ((n->match_flags & RTL_FW_MATCH_HCI_REV) &&436n->hci_rev != btrtl->hci_rev)437continue;438if (n->lmp_subver != btrtl->lmp_subver)439continue;440441break;442}443444return n;445}446447#ifdef USE_CUSTOMER_ADDRESS448static int is_mac(uint8_t chip_type, uint16_t offset)449{450int result = 0;451452switch (chip_type) {453case CHIP_8822BS:454case CHIP_8723DS:455case CHIP_8821CS:456case CHIP_8723CS_XX:457case CHIP_8723CS_CG:458case CHIP_8723CS_VF:459if (offset == 0x0044)460return 1;461break;462case CHIP_8822CS:463case CHIP_8761B:464if (offset == 0x0030)465return 1;466break;467case 0: /* special for not setting chip_type */468case CHIP_8761AT:469case CHIP_8761ATF:470case CHIP_8761BTC:471case CHIP_8723BS:472if (offset == 0x003c)473return 1;474break;475default:476break;477}478479return result;480}481482static void fill_mac_offset(uint8_t chip_type, uint8_t b[2])483{484switch (chip_type) {485case CHIP_8822BS:486case CHIP_8723DS:487case CHIP_8821CS:488b[0] = 0x44;489b[1] = 0x00;490break;491case CHIP_8822CS:492case CHIP_8761B:493b[0] = 0x30;494b[1] = 0x00;495break;496case 0: /* special for not setting chip_type */497case CHIP_8761AT:498case CHIP_8761ATF:499case CHIP_8761BTC:500case CHIP_8723BS:501b[0] = 0x3c;502b[1] = 0x00;503break;504}505}506#endif507508static void merge_configs(uint8_t *cfg_buf, size_t *plen)509{510struct list_head *iter, *tmp;511struct cfg_list_item *item;512uint8_t *buf;513uint16_t tmp_len;514515list_for_each_safe(iter, tmp, &list_extracfgs) {516struct list_head *iter2, *tmp2;517518item = list_entry(iter, struct cfg_list_item, list);519list_for_each_safe(iter2, tmp2, &list_configs) {520struct cfg_list_item *n;521522n = list_entry(iter2, struct cfg_list_item, list);523if (item->offset == n->offset) {524if (item->len == n->len) {525memcpy(n->data, item->data, n->len);526list_del(&item->list);527free(item);528break;529}530531RS_WARN("item mismatch %04x %u %u",532item->offset, item->len,533n->len);534list_del(&item->list);535free(item);536}537}538}539540buf = cfg_buf + *plen;541list_for_each_safe(iter, tmp, &list_extracfgs) {542item = list_entry(iter, struct cfg_list_item, list);543buf[0] = item->offset & 0xff;544buf[1] = (item->offset >> 8) & 0xff;545buf[2] = item->len;546memcpy(buf + 3, item->data, item->len);547buf += (3 + item->len);548*plen += (3 + item->len);549list_del(&item->list);550free(item);551}552553tmp_len = *plen - 6;554555cfg_buf[4] = (tmp_len & 0xff);556cfg_buf[5] = ((tmp_len >> 8) & 0xff);557}558559/*560* Parse realtek Bluetooth config file.561* The content starts with vendor magic: 55 ab 23 87562*/563int rtb_parse_config(uint8_t *cfg_buf, size_t *plen, uint8_t bdaddr[6])564{565const uint8_t hdr[4] = { 0x55, 0xab, 0x23, 0x87 };566uint16_t cfg_len;567uint16_t tmp;568struct rtb_cfg_item *entry;569uint16_t i;570uint32_t baudrate = 0;571#ifdef USE_CUSTOMER_ADDRESS572uint8_t j = 0;573struct patch_info *pent = rtb_cfg.patch_ent;574int addr_found = 0;575#endif576struct cfg_list_item *item;577578if (!cfg_buf || !plen) {579RS_ERR("%s: Invalid parameter", __func__);580return -1;581}582583RS_INFO("Original Cfg len %u", (uint16_t)*plen);584if (memcmp(cfg_buf, hdr, 4)) {585RS_ERR("Signature %02x %02x %02x %02x is incorrect",586cfg_buf[0], cfg_buf[1], cfg_buf[2], cfg_buf[3]);587return -1;588}589590cfg_len = ((uint16_t)cfg_buf[5] << 8) + cfg_buf[4];591if (cfg_len != *plen - RTB_CFG_HDR_LEN) {592RS_ERR("Config len %u is incorrect(%zd)", cfg_len,593*plen - RTB_CFG_HDR_LEN);594return -1;595}596597entry = (struct rtb_cfg_item *)(cfg_buf + 6);598i = 0;599while (i < cfg_len) {600switch (le16_to_cpu(entry->offset)) {601#ifdef USE_CUSTOMER_ADDRESS602case 0x003c:603case 0x0044:604case 0x0030:605if (!customer_bdaddr)606break;607if (!is_mac(pent->chip_type, le16_to_cpu(entry->offset)))608break;609/* Replace the content with input bdaddr from extra610* config file611*/612for (j = 0; j < entry->len; j++)613entry->data[j] = bdaddr[j];614addr_found = 1;615RS_INFO("BT MAC found %02x:%02x:%02x:%02x:%02x:%02x",616entry->data[5], entry->data[4], entry->data[3],617entry->data[2], entry->data[1], entry->data[0]);618break;619#endif620case 0x000c:621#ifdef BAUDRATE_4BYTES622baudrate = get_unaligned_le32(entry->data);623#else624baudrate = get_unaligned_le16(entry->data);625#endif626RS_INFO("Config baudrate: %08x", baudrate);627628if (entry->len > 12) {629uint8_t d = entry->data[12];630rtb_cfg.uart_flow_ctrl = (d & 0x4) ? 1 : 0;631RS_INFO("uart flow ctrl: %u",632rtb_cfg.uart_flow_ctrl);633}634break;635#ifdef RTL8723DSH4_UART_HWFLOWC636case 0x0018:637if (pent->chip_type == CHIP_8723DS &&638rtb_cfg.proto == HCI_UART_H4) {639if (entry->data[0] & (1 << 2))640rtb_cfg.uart_flow_ctrl = 1;641RS_INFO("8723DSH4: hw flow control %u",642rtb_cfg.uart_flow_ctrl);643if (entry->data[0] & 0x01) {644rtb_cfg.parenb = 1;645if (entry->data[0] & 0x02)646rtb_cfg.pareven = 1;647else648rtb_cfg.pareven = 0;649}650RS_INFO("8723DSH4: parity %u, even %u",651rtb_cfg.parenb,652rtb_cfg.pareven);653}654break;655#endif656default:657RS_DBG("cfg offset %04x, length %u", entry->offset,658entry->len);659break;660}661662/* Add config item to list */663item = malloc(sizeof(*item) + entry->len);664if (item) {665item->offset = le16_to_cpu(entry->offset);666item->len = entry->len;667memcpy(item->data, entry->data, item->len);668list_add_tail(&item->list, &list_configs);669} else {670RS_ERR("Cannot alloc mem for entry %04x, %u",671entry->offset, entry->len);672}673674tmp = entry->len + sizeof(struct rtb_cfg_item);675i += tmp;676entry = (struct rtb_cfg_item *)((uint8_t *)entry + tmp);677}678679#ifdef USE_CUSTOMER_ADDRESS680if (!addr_found && customer_bdaddr) {681uint8_t *b;682uint16_t ofs;683684b = cfg_buf + *plen;685fill_mac_offset(pent->chip_type, b);686ofs = (((uint16_t)b[1] << 8) | b[0]);687688RS_INFO("Add bdaddr section, offset %02x%02x", b[1], b[0]);689b[2] = 6;690for (j = 0; j < 6; j++)691b[3 + j] = bdaddr[j];692693*plen += 9;694tmp = *plen - 6;695696cfg_buf[4] = (tmp & 0xff);697cfg_buf[5] = ((tmp >> 8) & 0xff);698699/* Add address item to list */700item = malloc(sizeof(*item) + 6);701if (item) {702item->offset = ofs;703item->len = b[2];704memcpy(item->data, b + 3, 6);705list_add_tail(&item->list, &list_configs);706} else {707RS_ERR("Cannot alloc mem for entry %04x, %u",708entry->offset, entry->len);709}710}711#endif712713/* plen, cfg_buf, head */714/* Merge configs */715merge_configs(cfg_buf, plen);716717rtb_cfg.vendor_baud = baudrate;718return 0;719}720721#ifdef USE_CUSTOMER_ADDRESS722int bachk(const char *str)723{724if (!str)725return -1;726727if (strlen(str) != 17)728return -1;729730while (*str) {731if (!isxdigit(*str++))732return -1;733734if (!isxdigit(*str++))735return -1;736737if (*str == 0)738break;739740if (*str++ != ':')741return -1;742}743744return 0;745}746/*747* Get random Bluetooth addr.748*/749/* static void rtb_get_ram_addr(char bt_addr[0])750* {751* srand(time(NULL) + getpid() + getpid() * 987654 + rand());752*753* uint32_t addr = rand();754* memcpy(bt_addr, &addr, sizeof(uint8_t));755* }756*/757758/*759* Write the random addr to the BT_ADDR_FILE.760*/761/* static void rtb_write_btmac2file(char bt_addr[6])762* {763* int fd;764* fd = open(BT_ADDR_FILE, O_CREAT | O_RDWR | O_TRUNC);765*766* if (fd > 0) {767* chmod(BT_ADDR_FILE, 0666);768* char addr[18] = { 0 };769* addr[17] = '\0';770* sprintf(addr, "%2x:%2x:%2x:%2x:%2x:%2x", bt_addr[0], bt_addr[1],771* bt_addr[2], bt_addr[3], bt_addr[4], bt_addr[5]);772* write(fd, addr, strlen(addr));773* close(fd);774* } else {775* RS_ERR("open file error:%s\n", BT_ADDR_FILE);776* }777* }778*/779#endif780781/*782* Read and parse Realtek Bluetooth Config file.783*/784uint8_t *rtb_read_config(struct rtb_struct *btrtl, int *cfg_len)785{786char *file_name;787uint8_t bdaddr[6];788struct stat st;789size_t file_len;790size_t tlength;791int fd;792uint8_t *buf;793#ifdef USE_CUSTOMER_ADDRESS794#define BDADDR_STRING_LEN 17795size_t size;796size_t result;797uint8_t tbuf[BDADDR_STRING_LEN + 1];798char *str;799int i = 0;800#endif801struct list_head *tmp, *iter;802803if (!btrtl || !cfg_len) {804RS_ERR("%s: Invalid parameter", __func__);805return NULL;806}807808config_lists_init();809810#ifdef USE_CUSTOMER_ADDRESS811if (stat(BT_ADDR_FILE, &st) < 0) {812RS_INFO("Couldnt access customer BT MAC file %s",813BT_ADDR_FILE);814815goto read_cfg;816}817818size = st.st_size;819/* Only read the first 17-byte if the file length is larger */820if (size > BDADDR_STRING_LEN)821size = BDADDR_STRING_LEN;822823fd = open(BT_ADDR_FILE, O_RDONLY);824if (fd == -1) {825RS_INFO("Couldnt open BT MAC file %s, %s", BT_ADDR_FILE,826strerror(errno));827} else {828memset(tbuf, 0, sizeof(tbuf));829result = read(fd, tbuf, size);830close(fd);831if (result == -1) {832RS_ERR("Couldnt read BT MAC file %s, err %s",833BT_ADDR_FILE, strerror(errno));834goto read_cfg;835}836837if (bachk((const char *)tbuf) < 0) {838goto read_cfg;839}840841str = (char *)tbuf;842for (i = 5; i >= 0; i--) {843bdaddr[i] = (uint8_t)strtoul(str, NULL, 16);844str += 3;845}846847/* Reserve LAP addr from 0x9e8b00 to 0x9e8b3f,848* Change to 0x008bXX */849if (0x9e == bdaddr[3] && 0x8b == bdaddr[4] &&850bdaddr[5] <= 0x3f)851bdaddr[3] = 0x00;852853RS_DBG("BT MAC %02x:%02x:%02x:%02x:%02x:%02x",854bdaddr[5], bdaddr[4], bdaddr[3], bdaddr[2],855bdaddr[1], bdaddr[0]);856customer_bdaddr = 1;857}858#endif859860read_cfg:861*cfg_len = 0;862file_name = malloc(PATH_MAX);863if (!file_name) {864RS_ERR("Can't allocate memory for Config file name");865return NULL;866}867memset(file_name, 0, PATH_MAX);868snprintf(file_name, PATH_MAX, "%s%s", BT_CONFIG_DIRECTORY,869btrtl->patch_ent->config_file);870if (stat(file_name, &st) < 0) {871RS_ERR("Can't access Config file: %s, %s",872file_name, strerror(errno));873goto err_stat;874}875876file_len = st.st_size;877878if ((fd = open(file_name, O_RDONLY)) < 0) {879perror("Can't open Config file");880goto err_open;881}882883tlength = file_len;884#ifdef USE_CUSTOMER_ADDRESS885tlength += 9;886#endif887888parse_extra_config(EXTRA_CONFIG_FILE);889if (!list_empty(&list_extracfgs)) {890struct cfg_list_item *item;891892list_for_each_safe(iter, tmp, &list_extracfgs) {893item = list_entry(iter, struct cfg_list_item, list);894tlength += (item->len + 3);895}896}897898buf = malloc(tlength);899if (!buf) {900RS_ERR("Couldnt malloc buffer for Config %zd", tlength);901goto err_malloc;902}903904result = read(fd, buf, file_len);905if (result < (ssize_t)file_len) {906perror("Can't read Config file");907goto err_read;908}909close(fd);910free(file_name);911912result = rtb_parse_config(buf, &file_len, bdaddr);913config_lists_free();914if (result < 0) {915RS_ERR("Invalid Config content");916close(fd);917free(buf);918exit(EXIT_FAILURE);919}920util_hexdump((const uint8_t *)buf, file_len);921RS_INFO("Cfg length %u", (uint16_t)file_len);922RS_INFO("Vendor baud from Config file: %08x", rtb_cfg.vendor_baud);923924*cfg_len = file_len;925926return buf;927928err_read:929free(buf);930err_malloc:931config_lists_free();932close(fd);933err_open:934err_stat:935free(file_name);936return NULL;937}938939/*940* Read Realtek Bluetooth firmaware file.941*/942uint8_t *rtb_read_firmware(struct rtb_struct *btrtl, int *fw_len)943{944char *filename;945struct stat st;946int fd = -1;947size_t fwsize;948uint8_t *fw_buf;949ssize_t result;950951if (!btrtl || !fw_len) {952RS_ERR("%s: Invalid parameter", __func__);953return NULL;954}955956filename = malloc(PATH_MAX);957if (!filename) {958RS_ERR("Can't allocate memory for fw name");959return NULL;960}961962snprintf(filename, PATH_MAX, "%s%s", FIRMWARE_DIRECTORY,963btrtl->patch_ent->patch_file);964965if (stat(filename, &st) < 0) {966RS_ERR("Can't access firmware %s, %s", filename,967strerror(errno));968goto err_stat;969}970971fwsize = st.st_size;972973if ((fd = open(filename, O_RDONLY)) < 0) {974RS_ERR("Can't open firmware, %s", strerror(errno));975goto err_open;976}977978fw_buf = malloc(fwsize);979if (!fw_buf) {980RS_ERR("Can't allocate memory for fw, %s", strerror(errno));981goto err_malloc;982}983984result = read(fd, fw_buf, fwsize);985if (result != (ssize_t) fwsize) {986RS_ERR("Read FW %s error, %s", filename, strerror(errno));987goto err_read;988}989990*fw_len = (int)result;991RS_INFO("Load FW %s OK, size %zd", filename, result);992993close(fd);994free(filename);995996return fw_buf;997998err_read:999free(fw_buf);1000*fw_len = 0;1001err_malloc:1002close(fd);1003err_open:1004err_stat:1005free(filename);1006return NULL;1007}10081009static uint8_t rtb_get_fw_project_id(uint8_t *p_buf)1010{1011uint8_t opcode;1012uint8_t len;1013uint8_t data = 0;10141015do {1016opcode = *p_buf;1017len = *(p_buf - 1);1018if (opcode == 0x00) {1019if (len == 1) {1020data = *(p_buf - 2);1021RS_INFO("%s: opcode %u, len %u, data %u",1022__func__, opcode, len, data);1023break;1024} else {1025RS_ERR("%s: Invalid len %u", __func__, len);1026}1027}1028p_buf -= len + 2;1029} while (*p_buf != 0xFF);10301031return data;1032}10331034struct rtb_patch_entry *rtb_get_patch_entry(void)1035{1036uint16_t i;1037struct rtb_patch_hdr *patch;1038struct rtb_patch_entry *entry;1039uint32_t tmp;1040uint8_t *ci_base; /* Chip id base */1041uint8_t *pl_base; /* Patch length base */1042uint8_t *so_base; /* Start offset base */10431044patch = (struct rtb_patch_hdr *)rtb_cfg.fw_buf;1045entry = (struct rtb_patch_entry *)malloc(sizeof(*entry));1046if (!entry) {1047RS_ERR("Failed to allocate mem for patch entry");1048return NULL;1049}10501051patch->number_of_patch = le16_to_cpu(patch->number_of_patch);10521053RS_DBG("FW version 0x%08x, Patch num %u",1054le32_to_cpu(patch->fw_version), patch->number_of_patch);10551056ci_base = rtb_cfg.fw_buf + 14;1057pl_base = ci_base + 2 * patch->number_of_patch;1058so_base = pl_base + 2 * patch->number_of_patch;1059for (i = 0; i < patch->number_of_patch; i++) {1060uint16_t chip_id = get_unaligned_le16(ci_base + 2 * i);10611062RS_INFO("Chip id 0x%04x", chip_id);1063if (chip_id == rtb_cfg.eversion + 1) {1064entry->chip_id = rtb_cfg.eversion + 1;1065entry->patch_len = get_unaligned_le16(pl_base + 2 * i);1066entry->soffset = get_unaligned_le32(so_base + 4 * i);1067RS_DBG("Patch length 0x%04x", entry->patch_len);1068RS_DBG("Start offset 0x%08x", entry->soffset);10691070entry->svn_ver = get_unaligned_le32(rtb_cfg.fw_buf +1071entry->soffset +1072entry->patch_len - 8);1073entry->coex_ver = get_unaligned_le32(rtb_cfg.fw_buf +1074entry->soffset +1075entry->patch_len - 12);10761077RS_INFO("Svn version: %8d", entry->svn_ver);1078tmp = ((entry->coex_ver >> 16) & 0x7ff) +1079(entry->coex_ver >> 27) * 10000;1080RS_INFO("Coexistence: BTCOEX_20%06d-%04x\n", tmp,1081(entry->coex_ver & 0xffff));10821083break;1084}1085}10861087if (i == patch->number_of_patch) {1088RS_ERR("Failed to get entry");1089free(entry);1090entry = NULL;1091}10921093return entry;1094}10951096uint8_t *rtb_get_final_patch(int fd, int proto, int *rlen)1097{1098struct rtb_struct *rtl = &rtb_cfg;1099uint8_t proj_id = 0;1100struct rtb_patch_entry *entry = NULL;1101struct rtb_patch_hdr *patch = (struct rtb_patch_hdr *)rtl->fw_buf;1102uint32_t svn_ver, coex_ver, tmp;1103const uint8_t rtb_patch_smagic[8] = {11040x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x681105};1106const uint8_t rtb_patch_emagic[4] = { 0x51, 0x04, 0xFD, 0x77 };1107uint8_t *buf;1108int len;11091110if (!rlen) {1111RS_ERR("%s: Invalid parameter", __func__);1112return NULL;1113}11141115/* Use single patch for 3wire && 8723a */1116if (proto == HCI_UART_3WIRE && rtl->lmp_subver == ROM_LMP_8723a) {1117if (!memcmp(rtl->fw_buf, rtb_patch_smagic, 8)) {1118RS_ERR("Unexpected signature");1119goto err;1120}11211122len = rtl->config_len + rtl->fw_len;1123buf = malloc(len);1124if (!buf) {1125RS_ERR("Can't alloc mem for fwc, %s", strerror(errno));1126goto err;1127} else {1128uint8_t *b;11291130RS_INFO("FWC copy directly");11311132b = rtl->fw_buf + rtl->fw_len;1133svn_ver = get_unaligned_le32(b - 8);1134coex_ver = get_unaligned_le32(b - 12);11351136RS_INFO("Svn version: %u\n", svn_ver);1137tmp = ((coex_ver >> 16) & 0x7ff) +1138(coex_ver >> 27) * 10000;1139RS_INFO("Coexistence: BTCOEX_20%06d-%04x\n", tmp,1140(coex_ver & 0xffff));11411142/* Copy Patch and Config */1143memcpy(buf, rtl->fw_buf, rtl->fw_len);1144if (rtl->config_len)1145memcpy(buf + rtl->fw_len,1146rtl->config_buf, rtl->config_len);1147rtl->dl_fw_flag = 1;1148*rlen = len;1149return buf;1150}1151}11521153if (memcmp(rtl->fw_buf, rtb_patch_smagic, 8)) {1154RS_ERR("Signature error");1155goto err;1156}11571158if (memcmp(rtl->fw_buf + rtl->fw_len - 4, rtb_patch_emagic, 4)) {1159RS_ERR("Extension section signature error");1160goto err;1161}11621163proj_id = rtb_get_fw_project_id(rtl->fw_buf + rtl->fw_len - 5);11641165#ifdef RTL_8703A_SUPPORT1166if (rtl->hci_ver == 0x4 && rtl->lmp_subver == ROM_LMP_8723b) {1167RS_INFO("HCI version = 0x4, IC is 8703A.");1168} else {1169RS_ERR("error: lmp_version %x, hci_version %x, project_id %x",1170rtl->lmp_subver, rtl->hci_ver, project_id[proj_id]);1171goto err;1172}1173#else1174if (rtl->lmp_subver != ROM_LMP_8703b) {1175if (rtl->lmp_subver != project_id[proj_id]) {1176RS_ERR("lmp_subver %04x, project id %04x, mismatch\n",1177rtl->lmp_subver, project_id[proj_id]);1178goto err;1179}1180} else {1181if (rtb_cfg.patch_ent->proj_id != project_id[proj_id]) {1182RS_ERR("proj_id %04x, version %04x from firmware "1183"project_id[%u], mismatch",1184rtb_cfg.patch_ent->proj_id,1185project_id[proj_id], proj_id);1186goto err;1187}1188}1189#endif11901191/* Entry is allocated dynamically. It should be freed later in the1192* function.1193*/1194entry = rtb_get_patch_entry();11951196if (entry) {1197len = entry->patch_len + rtl->config_len;1198} else {1199RS_ERR("Can't find the patch entry");1200goto err;1201}12021203buf = malloc(len);1204if (!buf) {1205RS_ERR("%s: Can't alloc memory for fwc, %s", __func__,1206strerror(errno));1207free(entry);1208goto err;1209} else {1210memcpy(buf, rtl->fw_buf + entry->soffset, entry->patch_len);1211memcpy(buf + entry->patch_len - 4, &patch->fw_version, 4);12121213if (rtl->config_len)1214memcpy(buf + entry->patch_len, rtl->config_buf,1215rtl->config_len);1216rtl->dl_fw_flag = 1;1217*rlen = len;1218}12191220RS_INFO("FW %s exists, Config file %s exists",1221(rtl->fw_len > 0) ? "" : "not",1222(rtl->config_len > 0) ? "" : "not");12231224free(entry);1225return buf;12261227err:1228rtl->dl_fw_flag = 0;1229*rlen = 0;1230return NULL;1231}1232123312341235