Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
orangepi-xunlong
GitHub Repository: orangepi-xunlong/orangepi-build
Path: blob/next/external/cache/sources/rtk_hciattach/rtb_fwc.c
18115 views
1
/*
2
* Copyright (C) 2018 Realtek Semiconductor Corporation.
3
*
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
8
*
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
13
*/
14
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <stdint.h>
18
#include <string.h>
19
#include <sys/types.h>
20
#include <sys/stat.h>
21
#include <fcntl.h>
22
#include <errno.h>
23
#include <unistd.h>
24
#include <ctype.h>
25
26
#ifndef PATH_MAX
27
#define PATH_MAX 1024
28
#endif
29
30
#include "hciattach.h"
31
#include "rtb_fwc.h"
32
33
#define USE_CUSTOMER_ADDRESS
34
35
#define FIRMWARE_DIRECTORY "/lib/firmware/rtlbt/"
36
#define BT_CONFIG_DIRECTORY "/lib/firmware/rtlbt/"
37
38
#ifdef USE_CUSTOMER_ADDRESS
39
#define BT_ADDR_FILE "/opt/bdaddr"
40
static uint8_t customer_bdaddr = 0;
41
#endif
42
43
struct list_head {
44
struct list_head *next, *prev;
45
};
46
47
struct cfg_list_item {
48
struct list_head list;
49
uint16_t offset;
50
uint8_t len;
51
uint8_t data[0];
52
};
53
54
static struct list_head list_configs;
55
56
#define EXTRA_CONFIG_FILE "/opt/rtk_btconfig.txt"
57
static struct list_head list_extracfgs;
58
59
struct rtb_cfg_item {
60
uint16_t offset;
61
uint8_t len;
62
uint8_t data[0];
63
} __attribute__ ((packed));
64
65
#define RTB_CFG_HDR_LEN 6
66
67
struct rtb_patch_entry {
68
uint16_t chip_id;
69
uint16_t patch_len;
70
uint32_t soffset;
71
uint32_t svn_ver;
72
uint32_t coex_ver;
73
} __attribute__ ((packed));
74
75
struct rtb_patch_hdr {
76
uint8_t signature[8];
77
uint32_t fw_version;
78
uint16_t number_of_patch;
79
struct rtb_patch_entry entry[0];
80
} __attribute__ ((packed));
81
82
uint16_t project_id[]=
83
{
84
ROM_LMP_8723a,
85
ROM_LMP_8723b, /* RTL8723BS */
86
ROM_LMP_8821a, /* RTL8821AS */
87
ROM_LMP_8761a, /* RTL8761ATV */
88
89
ROM_LMP_8703a,
90
ROM_LMP_8763a,
91
ROM_LMP_8703b,
92
ROM_LMP_8723c, /* index 7 for 8723CS. What is for other 8723CS */
93
ROM_LMP_8822b, /* RTL8822BS */
94
ROM_LMP_8723b, /* RTL8723DS */
95
ROM_LMP_8821a, /* id 10 for RTL8821CS, lmp subver 0x8821 */
96
ROM_LMP_NONE,
97
ROM_LMP_NONE,
98
ROM_LMP_8822c, /* id 13 for RTL8822CS, lmp subver 0x8822 */
99
ROM_LMP_8761a, /* id 14 for 8761B */
100
};
101
102
static struct patch_info h4_patch_table[] = {
103
/* match flags, chip type, lmp subver, proj id(unused), hci_ver,
104
* hci_rev, ...
105
*/
106
107
/* RTL8761AT */
108
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8761AT,
109
0x8761, 0xffff, 0, 0x000a,
110
"rtl8761at_fw", "rtl8761at_config", "RTL8761AT" },
111
/* RTL8761ATF */
112
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8761ATF,
113
0x8761, 0xffff, 0, 0x000a,
114
"rtl8761atf_fw", "rtl8761atf_config", "RTL8761ATF" },
115
/* RTL8761B(8763) H4 Test Chip without download
116
* FW/Config is not used.
117
*/
118
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8761BTC,
119
0x8763, 0xffff, 0, 0x000b,
120
"rtl8761btc_fw", "rtl8761btc_config", "RTL8761BTC" },
121
/* RTL8761B H4 Test Chip wihtout download*/
122
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8761BH4,
123
0x8761, 0xffff, 0, 0x000b,
124
"rtl8761bh4_fw", "rtl8761bh4_config", "RTL8761BH4" },
125
126
/* RTL8723DS */
127
{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8723DS,
128
ROM_LMP_8723b, ROM_LMP_8723b, 8, 0x000d,
129
"rtl8723dsh4_fw", "rtl8723dsh4_config", "RTL8723DSH4"},
130
131
{ 0, 0, 0, ROM_LMP_NONE, 0, 0, "rtl_none_fw", "rtl_none_config", "NONE"}
132
};
133
134
static struct patch_info patch_table[] = {
135
/* match flags, chip type, lmp subver, proj id(unused), hci_ver,
136
* hci_rev, ...
137
*/
138
139
/* RTL8723AS */
140
{ 0, 0, ROM_LMP_8723a, ROM_LMP_8723a, 0, 0,
141
"rtl8723a_fw", "rtl8723a_config", "RTL8723AS"},
142
/* RTL8821CS */
143
{ RTL_FW_MATCH_HCI_REV, CHIP_8821CS,
144
ROM_LMP_8821a, ROM_LMP_8821a, 0, 0x000c,
145
"rtl8821c_fw", "rtl8821c_config", "RTL8821CS"},
146
/* RTL8821AS */
147
{ 0, 0, ROM_LMP_8821a, ROM_LMP_8821a, 0, 0,
148
"rtl8821a_fw", "rtl8821a_config", "RTL8821AS"},
149
/* RTL8761ATV */
150
{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, 0,
151
ROM_LMP_8761a, ROM_LMP_8761a, 0x06, 0x000a,
152
"rtl8761a_fw", "rtl8761a_config", "RTL8761ATV"},
153
/* RTL8761BTV */
154
{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8761B,
155
ROM_LMP_8761a, ROM_LMP_8761a, 0x0a, 0x000b,
156
"rtl8761b_fw", "rtl8761b_config", "RTL8761BTV"},
157
158
/* RTL8703AS
159
* RTL8822BS
160
* */
161
#ifdef RTL_8703A_SUPPORT
162
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8703AS,
163
ROM_LMP_8723b, ROM_LMP_8723b, 0, 0,
164
"rtl8703a_fw", "rtl8703a_config", "RTL8703AS"},
165
#endif
166
{ RTL_FW_MATCH_HCI_REV, CHIP_8822BS,
167
ROM_LMP_8822b, ROM_LMP_8822b, 0, 0x000b,
168
"rtl8822b_fw", "rtl8822b_config", "RTL8822BS"},
169
{ RTL_FW_MATCH_HCI_REV, CHIP_8822CS,
170
ROM_LMP_8822c, ROM_LMP_8822c, 0, 0x000c,
171
"rtl8822cs_fw", "rtl8822cs_config", "RTL8822CS"},
172
173
/* RTL8703BS
174
* RTL8723CS_XX
175
* RTL8723CS_CG
176
* RTL8723CS_VF
177
* Use the sampe lmp subversion 0x8703
178
* */
179
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8703BS,
180
ROM_LMP_8703b, ROM_LMP_8703b, 0, 0,
181
"rtl8703b_fw", "rtl8703b_config", "RTL8703BS"},
182
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_XX,
183
ROM_LMP_8703b, ROM_LMP_8723cs_xx, 0, 0,
184
"rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_XX"},
185
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_CG,
186
ROM_LMP_8703b, ROM_LMP_8723cs_cg, 0, 0,
187
"rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_CG"},
188
{ RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_VF,
189
ROM_LMP_8703b, ROM_LMP_8723cs_vf, 0, 0,
190
"rtl8723cs_fw", "rtl8723cs_config", "RTL8723CS_VF"},
191
192
/* RTL8723BS */
193
{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, 0,
194
ROM_LMP_8723b, ROM_LMP_8723b, 6, 0x000b,
195
"rtl8723b_fw", "rtl8723b_config", "RTL8723BS"},
196
/* RTL8723DS */
197
{ RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8723DS,
198
ROM_LMP_8723b, ROM_LMP_8723b, 8, 0x000d,
199
"rtl8723d_fw", "rtl8723d_config", "RTL8723DS"},
200
/* add entries here*/
201
202
{ 0, 0, 0, ROM_LMP_NONE, 0, 0, "rtl_none_fw", "rtl_none_config", "NONE"}
203
};
204
205
static __inline uint16_t get_unaligned_le16(uint8_t * p)
206
{
207
return (uint16_t) (*p) + ((uint16_t) (*(p + 1)) << 8);
208
}
209
210
static __inline uint32_t get_unaligned_le32(uint8_t * p)
211
{
212
return (uint32_t) (*p) + ((uint32_t) (*(p + 1)) << 8) +
213
((uint32_t) (*(p + 2)) << 16) + ((uint32_t) (*(p + 3)) << 24);
214
}
215
216
/* list head from kernel */
217
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
218
219
#define container_of(ptr, type, member) ({ \
220
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
221
(type *)( (char *)__mptr - offsetof(type,member) );})
222
223
#define list_entry(ptr, type, member) \
224
container_of(ptr, type, member)
225
226
#define list_for_each_safe(pos, n, head) \
227
for (pos = (head)->next, n = pos->next; pos != (head); \
228
pos = n, n = pos->next)
229
230
static inline void INIT_LIST_HEAD(struct list_head *list)
231
{
232
list->next = list;
233
list->prev = list;
234
}
235
236
static inline int list_empty(const struct list_head *head)
237
{
238
return head->next == head;
239
}
240
241
static inline void __list_add(struct list_head *_new,
242
struct list_head *prev,
243
struct list_head *next)
244
{
245
next->prev = _new;
246
_new->next = next;
247
_new->prev = prev;
248
prev->next = _new;
249
}
250
251
static inline void list_add_tail(struct list_head *_new, struct list_head *head)
252
{
253
__list_add(_new, head->prev, head);
254
}
255
256
static inline void __list_del(struct list_head *prev, struct list_head *next)
257
{
258
next->prev = prev;
259
prev->next = next;
260
}
261
262
#define LIST_POISON1 ((void *) 0x00100100)
263
#define LIST_POISON2 ((void *) 0x00200200)
264
static inline void list_del(struct list_head *entry)
265
{
266
__list_del(entry->prev, entry->next);
267
entry->next = (struct list_head*)LIST_POISON1;
268
entry->prev = (struct list_head*)LIST_POISON2;
269
}
270
271
static inline void __list_splice(const struct list_head *list,
272
struct list_head *prev,
273
struct list_head *next)
274
{
275
struct list_head *first = list->next;
276
struct list_head *last = list->prev;
277
278
first->prev = prev;
279
prev->next = first;
280
281
last->next = next;
282
next->prev = last;
283
}
284
285
static inline void list_splice_tail(struct list_head *list,
286
struct list_head *head)
287
{
288
if (!list_empty(list))
289
__list_splice(list, head->prev, head);
290
}
291
292
static int config_lists_init(void)
293
{
294
INIT_LIST_HEAD(&list_configs);
295
INIT_LIST_HEAD(&list_extracfgs);
296
297
return 0;
298
}
299
300
static void config_lists_free(void)
301
{
302
struct list_head *iter;
303
struct list_head *tmp;
304
struct list_head *head;
305
struct cfg_list_item *n;
306
307
if (!list_empty(&list_extracfgs))
308
list_splice_tail(&list_extracfgs, &list_configs);
309
head = &list_configs;
310
list_for_each_safe(iter, tmp, head) {
311
n = list_entry(iter, struct cfg_list_item, list);
312
if (n) {
313
list_del(&n->list);
314
free(n);
315
}
316
}
317
318
INIT_LIST_HEAD(&list_configs);
319
INIT_LIST_HEAD(&list_extracfgs);
320
}
321
322
static void line_process(char *buf, int len /*@unused@*/)
323
{
324
char *argv[32];
325
int argc = 0;
326
char *ptr = buf;
327
char *head = buf;
328
unsigned long int offset;
329
uint8_t l;
330
uint8_t i = 0;
331
struct cfg_list_item *item;
332
333
RS_INFO("%s", buf);
334
335
while ((ptr = strsep(&head, ", \t")) != NULL) {
336
if (!ptr[0])
337
continue;
338
argv[argc++] = ptr;
339
if (argc >= 32) {
340
RS_WARN("%s: Config item is too long", __func__);
341
break;
342
}
343
}
344
345
if (argc < 4) {
346
RS_WARN("%s: Invalid Config item, ignore", __func__);
347
return;
348
}
349
350
offset = strtoul(argv[0], NULL, 16);
351
offset = offset | (strtoul(argv[1], NULL, 16) << 8);
352
RS_INFO("Extra Config offset %04lx", offset);
353
l = (uint8_t)strtoul(argv[2], NULL, 16);
354
if (l != (uint8_t)(argc - 3)) {
355
RS_ERR("Invalid Config item len %u", l);
356
return;
357
}
358
359
item = malloc(sizeof(*item) + l);
360
if (!item) {
361
RS_WARN("%s: Cannot alloc mem for item, %04lx, %u", __func__,
362
offset, l);
363
return;
364
}
365
366
item->offset = (uint16_t)offset;
367
item->len = l;
368
for (i = 0; i < l; i++)
369
item->data[i] = (uint8_t)strtoul(argv[3 + i], NULL, 16);
370
list_add_tail(&item->list, &list_extracfgs);
371
}
372
373
static void config_process(uint8_t *buf, int len /*@unused@*/)
374
{
375
char *head = (void *)buf;
376
char *ptr = (void *)buf;
377
378
while ((ptr = strsep(&head, "\n\r")) != NULL) {
379
if (!ptr[0])
380
continue;
381
line_process(ptr, strlen(ptr) + 1);
382
}
383
}
384
385
static void parse_extra_config(const char *path)
386
{
387
int fd;
388
uint8_t buf[256];
389
int result;
390
391
fd = open(path, O_RDONLY);
392
if (fd == -1) {
393
RS_INFO("Couldnt open extra config %s, %s", path,
394
strerror(errno));
395
return;
396
}
397
398
result = read(fd, buf, sizeof(buf));
399
if (result == -1) {
400
RS_ERR("Couldnt read %s, %s", path, strerror(errno));
401
goto done;
402
} else if (result == 0) {
403
RS_ERR("File is empty");
404
goto done;
405
}
406
407
if (result > 254) {
408
RS_ERR("Extra Config file is too big");
409
goto done;
410
}
411
buf[result++] = '\n';
412
buf[result++] = '\0';
413
414
config_process(buf, result);
415
416
done:
417
close(fd);
418
}
419
420
/* Get the entry from patch_table according to LMP subversion */
421
struct patch_info *get_patch_entry(struct rtb_struct *btrtl)
422
{
423
struct patch_info *n = NULL;
424
425
if (btrtl->proto == HCI_UART_3WIRE)
426
n = patch_table;
427
else
428
n = h4_patch_table;
429
for (; n->lmp_subver; n++) {
430
if ((n->match_flags & RTL_FW_MATCH_CHIP_TYPE) &&
431
n->chip_type != btrtl->chip_type)
432
continue;
433
if ((n->match_flags & RTL_FW_MATCH_HCI_VER) &&
434
n->hci_ver != btrtl->hci_ver)
435
continue;
436
if ((n->match_flags & RTL_FW_MATCH_HCI_REV) &&
437
n->hci_rev != btrtl->hci_rev)
438
continue;
439
if (n->lmp_subver != btrtl->lmp_subver)
440
continue;
441
442
break;
443
}
444
445
return n;
446
}
447
448
#ifdef USE_CUSTOMER_ADDRESS
449
static int is_mac(uint8_t chip_type, uint16_t offset)
450
{
451
int result = 0;
452
453
switch (chip_type) {
454
case CHIP_8822BS:
455
case CHIP_8723DS:
456
case CHIP_8821CS:
457
case CHIP_8723CS_XX:
458
case CHIP_8723CS_CG:
459
case CHIP_8723CS_VF:
460
if (offset == 0x0044)
461
return 1;
462
break;
463
case CHIP_8822CS:
464
case CHIP_8761B:
465
if (offset == 0x0030)
466
return 1;
467
break;
468
case 0: /* special for not setting chip_type */
469
case CHIP_8761AT:
470
case CHIP_8761ATF:
471
case CHIP_8761BTC:
472
case CHIP_8723BS:
473
if (offset == 0x003c)
474
return 1;
475
break;
476
default:
477
break;
478
}
479
480
return result;
481
}
482
483
static void fill_mac_offset(uint8_t chip_type, uint8_t b[2])
484
{
485
switch (chip_type) {
486
case CHIP_8822BS:
487
case CHIP_8723DS:
488
case CHIP_8821CS:
489
b[0] = 0x44;
490
b[1] = 0x00;
491
break;
492
case CHIP_8822CS:
493
case CHIP_8761B:
494
b[0] = 0x30;
495
b[1] = 0x00;
496
break;
497
case 0: /* special for not setting chip_type */
498
case CHIP_8761AT:
499
case CHIP_8761ATF:
500
case CHIP_8761BTC:
501
case CHIP_8723BS:
502
b[0] = 0x3c;
503
b[1] = 0x00;
504
break;
505
}
506
}
507
#endif
508
509
static void merge_configs(uint8_t *cfg_buf, size_t *plen)
510
{
511
struct list_head *iter, *tmp;
512
struct cfg_list_item *item;
513
uint8_t *buf;
514
uint16_t tmp_len;
515
516
list_for_each_safe(iter, tmp, &list_extracfgs) {
517
struct list_head *iter2, *tmp2;
518
519
item = list_entry(iter, struct cfg_list_item, list);
520
list_for_each_safe(iter2, tmp2, &list_configs) {
521
struct cfg_list_item *n;
522
523
n = list_entry(iter2, struct cfg_list_item, list);
524
if (item->offset == n->offset) {
525
if (item->len == n->len) {
526
memcpy(n->data, item->data, n->len);
527
list_del(&item->list);
528
free(item);
529
break;
530
}
531
532
RS_WARN("item mismatch %04x %u %u",
533
item->offset, item->len,
534
n->len);
535
list_del(&item->list);
536
free(item);
537
}
538
}
539
}
540
541
buf = cfg_buf + *plen;
542
list_for_each_safe(iter, tmp, &list_extracfgs) {
543
item = list_entry(iter, struct cfg_list_item, list);
544
buf[0] = item->offset & 0xff;
545
buf[1] = (item->offset >> 8) & 0xff;
546
buf[2] = item->len;
547
memcpy(buf + 3, item->data, item->len);
548
buf += (3 + item->len);
549
*plen += (3 + item->len);
550
list_del(&item->list);
551
free(item);
552
}
553
554
tmp_len = *plen - 6;
555
556
cfg_buf[4] = (tmp_len & 0xff);
557
cfg_buf[5] = ((tmp_len >> 8) & 0xff);
558
}
559
560
/*
561
* Parse realtek Bluetooth config file.
562
* The content starts with vendor magic: 55 ab 23 87
563
*/
564
int rtb_parse_config(uint8_t *cfg_buf, size_t *plen, uint8_t bdaddr[6])
565
{
566
const uint8_t hdr[4] = { 0x55, 0xab, 0x23, 0x87 };
567
uint16_t cfg_len;
568
uint16_t tmp;
569
struct rtb_cfg_item *entry;
570
uint16_t i;
571
uint32_t baudrate = 0;
572
#ifdef USE_CUSTOMER_ADDRESS
573
uint8_t j = 0;
574
struct patch_info *pent = rtb_cfg.patch_ent;
575
int addr_found = 0;
576
#endif
577
struct cfg_list_item *item;
578
579
if (!cfg_buf || !plen) {
580
RS_ERR("%s: Invalid parameter", __func__);
581
return -1;
582
}
583
584
RS_INFO("Original Cfg len %u", (uint16_t)*plen);
585
if (memcmp(cfg_buf, hdr, 4)) {
586
RS_ERR("Signature %02x %02x %02x %02x is incorrect",
587
cfg_buf[0], cfg_buf[1], cfg_buf[2], cfg_buf[3]);
588
return -1;
589
}
590
591
cfg_len = ((uint16_t)cfg_buf[5] << 8) + cfg_buf[4];
592
if (cfg_len != *plen - RTB_CFG_HDR_LEN) {
593
RS_ERR("Config len %u is incorrect(%zd)", cfg_len,
594
*plen - RTB_CFG_HDR_LEN);
595
return -1;
596
}
597
598
entry = (struct rtb_cfg_item *)(cfg_buf + 6);
599
i = 0;
600
while (i < cfg_len) {
601
switch (le16_to_cpu(entry->offset)) {
602
#ifdef USE_CUSTOMER_ADDRESS
603
case 0x003c:
604
case 0x0044:
605
case 0x0030:
606
if (!customer_bdaddr)
607
break;
608
if (!is_mac(pent->chip_type, le16_to_cpu(entry->offset)))
609
break;
610
/* Replace the content with input bdaddr from extra
611
* config file
612
*/
613
for (j = 0; j < entry->len; j++)
614
entry->data[j] = bdaddr[j];
615
addr_found = 1;
616
RS_INFO("BT MAC found %02x:%02x:%02x:%02x:%02x:%02x",
617
entry->data[5], entry->data[4], entry->data[3],
618
entry->data[2], entry->data[1], entry->data[0]);
619
break;
620
#endif
621
case 0x000c:
622
#ifdef BAUDRATE_4BYTES
623
baudrate = get_unaligned_le32(entry->data);
624
#else
625
baudrate = get_unaligned_le16(entry->data);
626
#endif
627
RS_INFO("Config baudrate: %08x", baudrate);
628
629
if (entry->len > 12) {
630
uint8_t d = entry->data[12];
631
rtb_cfg.uart_flow_ctrl = (d & 0x4) ? 1 : 0;
632
RS_INFO("uart flow ctrl: %u",
633
rtb_cfg.uart_flow_ctrl);
634
}
635
break;
636
#ifdef RTL8723DSH4_UART_HWFLOWC
637
case 0x0018:
638
if (pent->chip_type == CHIP_8723DS &&
639
rtb_cfg.proto == HCI_UART_H4) {
640
if (entry->data[0] & (1 << 2))
641
rtb_cfg.uart_flow_ctrl = 1;
642
RS_INFO("8723DSH4: hw flow control %u",
643
rtb_cfg.uart_flow_ctrl);
644
if (entry->data[0] & 0x01) {
645
rtb_cfg.parenb = 1;
646
if (entry->data[0] & 0x02)
647
rtb_cfg.pareven = 1;
648
else
649
rtb_cfg.pareven = 0;
650
}
651
RS_INFO("8723DSH4: parity %u, even %u",
652
rtb_cfg.parenb,
653
rtb_cfg.pareven);
654
}
655
break;
656
#endif
657
default:
658
RS_DBG("cfg offset %04x, length %u", entry->offset,
659
entry->len);
660
break;
661
}
662
663
/* Add config item to list */
664
item = malloc(sizeof(*item) + entry->len);
665
if (item) {
666
item->offset = le16_to_cpu(entry->offset);
667
item->len = entry->len;
668
memcpy(item->data, entry->data, item->len);
669
list_add_tail(&item->list, &list_configs);
670
} else {
671
RS_ERR("Cannot alloc mem for entry %04x, %u",
672
entry->offset, entry->len);
673
}
674
675
tmp = entry->len + sizeof(struct rtb_cfg_item);
676
i += tmp;
677
entry = (struct rtb_cfg_item *)((uint8_t *)entry + tmp);
678
}
679
680
#ifdef USE_CUSTOMER_ADDRESS
681
if (!addr_found && customer_bdaddr) {
682
uint8_t *b;
683
uint16_t ofs;
684
685
b = cfg_buf + *plen;
686
fill_mac_offset(pent->chip_type, b);
687
ofs = (((uint16_t)b[1] << 8) | b[0]);
688
689
RS_INFO("Add bdaddr section, offset %02x%02x", b[1], b[0]);
690
b[2] = 6;
691
for (j = 0; j < 6; j++)
692
b[3 + j] = bdaddr[j];
693
694
*plen += 9;
695
tmp = *plen - 6;
696
697
cfg_buf[4] = (tmp & 0xff);
698
cfg_buf[5] = ((tmp >> 8) & 0xff);
699
700
/* Add address item to list */
701
item = malloc(sizeof(*item) + 6);
702
if (item) {
703
item->offset = ofs;
704
item->len = b[2];
705
memcpy(item->data, b + 3, 6);
706
list_add_tail(&item->list, &list_configs);
707
} else {
708
RS_ERR("Cannot alloc mem for entry %04x, %u",
709
entry->offset, entry->len);
710
}
711
}
712
#endif
713
714
/* plen, cfg_buf, head */
715
/* Merge configs */
716
merge_configs(cfg_buf, plen);
717
718
rtb_cfg.vendor_baud = baudrate;
719
return 0;
720
}
721
722
#ifdef USE_CUSTOMER_ADDRESS
723
int bachk(const char *str)
724
{
725
if (!str)
726
return -1;
727
728
if (strlen(str) != 17)
729
return -1;
730
731
while (*str) {
732
if (!isxdigit(*str++))
733
return -1;
734
735
if (!isxdigit(*str++))
736
return -1;
737
738
if (*str == 0)
739
break;
740
741
if (*str++ != ':')
742
return -1;
743
}
744
745
return 0;
746
}
747
/*
748
* Get random Bluetooth addr.
749
*/
750
/* static void rtb_get_ram_addr(char bt_addr[0])
751
* {
752
* srand(time(NULL) + getpid() + getpid() * 987654 + rand());
753
*
754
* uint32_t addr = rand();
755
* memcpy(bt_addr, &addr, sizeof(uint8_t));
756
* }
757
*/
758
759
/*
760
* Write the random addr to the BT_ADDR_FILE.
761
*/
762
/* static void rtb_write_btmac2file(char bt_addr[6])
763
* {
764
* int fd;
765
* fd = open(BT_ADDR_FILE, O_CREAT | O_RDWR | O_TRUNC);
766
*
767
* if (fd > 0) {
768
* chmod(BT_ADDR_FILE, 0666);
769
* char addr[18] = { 0 };
770
* addr[17] = '\0';
771
* sprintf(addr, "%2x:%2x:%2x:%2x:%2x:%2x", bt_addr[0], bt_addr[1],
772
* bt_addr[2], bt_addr[3], bt_addr[4], bt_addr[5]);
773
* write(fd, addr, strlen(addr));
774
* close(fd);
775
* } else {
776
* RS_ERR("open file error:%s\n", BT_ADDR_FILE);
777
* }
778
* }
779
*/
780
#endif
781
782
/*
783
* Read and parse Realtek Bluetooth Config file.
784
*/
785
uint8_t *rtb_read_config(struct rtb_struct *btrtl, int *cfg_len)
786
{
787
char *file_name;
788
uint8_t bdaddr[6];
789
struct stat st;
790
size_t file_len;
791
size_t tlength;
792
int fd;
793
uint8_t *buf;
794
#ifdef USE_CUSTOMER_ADDRESS
795
#define BDADDR_STRING_LEN 17
796
size_t size;
797
size_t result;
798
uint8_t tbuf[BDADDR_STRING_LEN + 1];
799
char *str;
800
int i = 0;
801
#endif
802
struct list_head *tmp, *iter;
803
804
if (!btrtl || !cfg_len) {
805
RS_ERR("%s: Invalid parameter", __func__);
806
return NULL;
807
}
808
809
config_lists_init();
810
811
#ifdef USE_CUSTOMER_ADDRESS
812
if (stat(BT_ADDR_FILE, &st) < 0) {
813
RS_INFO("Couldnt access customer BT MAC file %s",
814
BT_ADDR_FILE);
815
816
goto read_cfg;
817
}
818
819
size = st.st_size;
820
/* Only read the first 17-byte if the file length is larger */
821
if (size > BDADDR_STRING_LEN)
822
size = BDADDR_STRING_LEN;
823
824
fd = open(BT_ADDR_FILE, O_RDONLY);
825
if (fd == -1) {
826
RS_INFO("Couldnt open BT MAC file %s, %s", BT_ADDR_FILE,
827
strerror(errno));
828
} else {
829
memset(tbuf, 0, sizeof(tbuf));
830
result = read(fd, tbuf, size);
831
close(fd);
832
if (result == -1) {
833
RS_ERR("Couldnt read BT MAC file %s, err %s",
834
BT_ADDR_FILE, strerror(errno));
835
goto read_cfg;
836
}
837
838
if (bachk((const char *)tbuf) < 0) {
839
goto read_cfg;
840
}
841
842
str = (char *)tbuf;
843
for (i = 5; i >= 0; i--) {
844
bdaddr[i] = (uint8_t)strtoul(str, NULL, 16);
845
str += 3;
846
}
847
848
/* Reserve LAP addr from 0x9e8b00 to 0x9e8b3f,
849
* Change to 0x008bXX */
850
if (0x9e == bdaddr[3] && 0x8b == bdaddr[4] &&
851
bdaddr[5] <= 0x3f)
852
bdaddr[3] = 0x00;
853
854
RS_DBG("BT MAC %02x:%02x:%02x:%02x:%02x:%02x",
855
bdaddr[5], bdaddr[4], bdaddr[3], bdaddr[2],
856
bdaddr[1], bdaddr[0]);
857
customer_bdaddr = 1;
858
}
859
#endif
860
861
read_cfg:
862
*cfg_len = 0;
863
file_name = malloc(PATH_MAX);
864
if (!file_name) {
865
RS_ERR("Can't allocate memory for Config file name");
866
return NULL;
867
}
868
memset(file_name, 0, PATH_MAX);
869
snprintf(file_name, PATH_MAX, "%s%s", BT_CONFIG_DIRECTORY,
870
btrtl->patch_ent->config_file);
871
if (stat(file_name, &st) < 0) {
872
RS_ERR("Can't access Config file: %s, %s",
873
file_name, strerror(errno));
874
goto err_stat;
875
}
876
877
file_len = st.st_size;
878
879
if ((fd = open(file_name, O_RDONLY)) < 0) {
880
perror("Can't open Config file");
881
goto err_open;
882
}
883
884
tlength = file_len;
885
#ifdef USE_CUSTOMER_ADDRESS
886
tlength += 9;
887
#endif
888
889
parse_extra_config(EXTRA_CONFIG_FILE);
890
if (!list_empty(&list_extracfgs)) {
891
struct cfg_list_item *item;
892
893
list_for_each_safe(iter, tmp, &list_extracfgs) {
894
item = list_entry(iter, struct cfg_list_item, list);
895
tlength += (item->len + 3);
896
}
897
}
898
899
buf = malloc(tlength);
900
if (!buf) {
901
RS_ERR("Couldnt malloc buffer for Config %zd", tlength);
902
goto err_malloc;
903
}
904
905
result = read(fd, buf, file_len);
906
if (result < (ssize_t)file_len) {
907
perror("Can't read Config file");
908
goto err_read;
909
}
910
close(fd);
911
free(file_name);
912
913
result = rtb_parse_config(buf, &file_len, bdaddr);
914
config_lists_free();
915
if (result < 0) {
916
RS_ERR("Invalid Config content");
917
close(fd);
918
free(buf);
919
exit(EXIT_FAILURE);
920
}
921
util_hexdump((const uint8_t *)buf, file_len);
922
RS_INFO("Cfg length %u", (uint16_t)file_len);
923
RS_INFO("Vendor baud from Config file: %08x", rtb_cfg.vendor_baud);
924
925
*cfg_len = file_len;
926
927
return buf;
928
929
err_read:
930
free(buf);
931
err_malloc:
932
config_lists_free();
933
close(fd);
934
err_open:
935
err_stat:
936
free(file_name);
937
return NULL;
938
}
939
940
/*
941
* Read Realtek Bluetooth firmaware file.
942
*/
943
uint8_t *rtb_read_firmware(struct rtb_struct *btrtl, int *fw_len)
944
{
945
char *filename;
946
struct stat st;
947
int fd = -1;
948
size_t fwsize;
949
uint8_t *fw_buf;
950
ssize_t result;
951
952
if (!btrtl || !fw_len) {
953
RS_ERR("%s: Invalid parameter", __func__);
954
return NULL;
955
}
956
957
filename = malloc(PATH_MAX);
958
if (!filename) {
959
RS_ERR("Can't allocate memory for fw name");
960
return NULL;
961
}
962
963
snprintf(filename, PATH_MAX, "%s%s", FIRMWARE_DIRECTORY,
964
btrtl->patch_ent->patch_file);
965
966
if (stat(filename, &st) < 0) {
967
RS_ERR("Can't access firmware %s, %s", filename,
968
strerror(errno));
969
goto err_stat;
970
}
971
972
fwsize = st.st_size;
973
974
if ((fd = open(filename, O_RDONLY)) < 0) {
975
RS_ERR("Can't open firmware, %s", strerror(errno));
976
goto err_open;
977
}
978
979
fw_buf = malloc(fwsize);
980
if (!fw_buf) {
981
RS_ERR("Can't allocate memory for fw, %s", strerror(errno));
982
goto err_malloc;
983
}
984
985
result = read(fd, fw_buf, fwsize);
986
if (result != (ssize_t) fwsize) {
987
RS_ERR("Read FW %s error, %s", filename, strerror(errno));
988
goto err_read;
989
}
990
991
*fw_len = (int)result;
992
RS_INFO("Load FW %s OK, size %zd", filename, result);
993
994
close(fd);
995
free(filename);
996
997
return fw_buf;
998
999
err_read:
1000
free(fw_buf);
1001
*fw_len = 0;
1002
err_malloc:
1003
close(fd);
1004
err_open:
1005
err_stat:
1006
free(filename);
1007
return NULL;
1008
}
1009
1010
static uint8_t rtb_get_fw_project_id(uint8_t *p_buf)
1011
{
1012
uint8_t opcode;
1013
uint8_t len;
1014
uint8_t data = 0;
1015
1016
do {
1017
opcode = *p_buf;
1018
len = *(p_buf - 1);
1019
if (opcode == 0x00) {
1020
if (len == 1) {
1021
data = *(p_buf - 2);
1022
RS_INFO("%s: opcode %u, len %u, data %u",
1023
__func__, opcode, len, data);
1024
break;
1025
} else {
1026
RS_ERR("%s: Invalid len %u", __func__, len);
1027
}
1028
}
1029
p_buf -= len + 2;
1030
} while (*p_buf != 0xFF);
1031
1032
return data;
1033
}
1034
1035
struct rtb_patch_entry *rtb_get_patch_entry(void)
1036
{
1037
uint16_t i;
1038
struct rtb_patch_hdr *patch;
1039
struct rtb_patch_entry *entry;
1040
uint32_t tmp;
1041
uint8_t *ci_base; /* Chip id base */
1042
uint8_t *pl_base; /* Patch length base */
1043
uint8_t *so_base; /* Start offset base */
1044
1045
patch = (struct rtb_patch_hdr *)rtb_cfg.fw_buf;
1046
entry = (struct rtb_patch_entry *)malloc(sizeof(*entry));
1047
if (!entry) {
1048
RS_ERR("Failed to allocate mem for patch entry");
1049
return NULL;
1050
}
1051
1052
patch->number_of_patch = le16_to_cpu(patch->number_of_patch);
1053
1054
RS_DBG("FW version 0x%08x, Patch num %u",
1055
le32_to_cpu(patch->fw_version), patch->number_of_patch);
1056
1057
ci_base = rtb_cfg.fw_buf + 14;
1058
pl_base = ci_base + 2 * patch->number_of_patch;
1059
so_base = pl_base + 2 * patch->number_of_patch;
1060
for (i = 0; i < patch->number_of_patch; i++) {
1061
uint16_t chip_id = get_unaligned_le16(ci_base + 2 * i);
1062
1063
RS_INFO("Chip id 0x%04x", chip_id);
1064
if (chip_id == rtb_cfg.eversion + 1) {
1065
entry->chip_id = rtb_cfg.eversion + 1;
1066
entry->patch_len = get_unaligned_le16(pl_base + 2 * i);
1067
entry->soffset = get_unaligned_le32(so_base + 4 * i);
1068
RS_DBG("Patch length 0x%04x", entry->patch_len);
1069
RS_DBG("Start offset 0x%08x", entry->soffset);
1070
1071
entry->svn_ver = get_unaligned_le32(rtb_cfg.fw_buf +
1072
entry->soffset +
1073
entry->patch_len - 8);
1074
entry->coex_ver = get_unaligned_le32(rtb_cfg.fw_buf +
1075
entry->soffset +
1076
entry->patch_len - 12);
1077
1078
RS_INFO("Svn version: %8d", entry->svn_ver);
1079
tmp = ((entry->coex_ver >> 16) & 0x7ff) +
1080
(entry->coex_ver >> 27) * 10000;
1081
RS_INFO("Coexistence: BTCOEX_20%06d-%04x\n", tmp,
1082
(entry->coex_ver & 0xffff));
1083
1084
break;
1085
}
1086
}
1087
1088
if (i == patch->number_of_patch) {
1089
RS_ERR("Failed to get entry");
1090
free(entry);
1091
entry = NULL;
1092
}
1093
1094
return entry;
1095
}
1096
1097
uint8_t *rtb_get_final_patch(int fd, int proto, int *rlen)
1098
{
1099
struct rtb_struct *rtl = &rtb_cfg;
1100
uint8_t proj_id = 0;
1101
struct rtb_patch_entry *entry = NULL;
1102
struct rtb_patch_hdr *patch = (struct rtb_patch_hdr *)rtl->fw_buf;
1103
uint32_t svn_ver, coex_ver, tmp;
1104
const uint8_t rtb_patch_smagic[8] = {
1105
0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68
1106
};
1107
const uint8_t rtb_patch_emagic[4] = { 0x51, 0x04, 0xFD, 0x77 };
1108
uint8_t *buf;
1109
int len;
1110
1111
if (!rlen) {
1112
RS_ERR("%s: Invalid parameter", __func__);
1113
return NULL;
1114
}
1115
1116
/* Use single patch for 3wire && 8723a */
1117
if (proto == HCI_UART_3WIRE && rtl->lmp_subver == ROM_LMP_8723a) {
1118
if (!memcmp(rtl->fw_buf, rtb_patch_smagic, 8)) {
1119
RS_ERR("Unexpected signature");
1120
goto err;
1121
}
1122
1123
len = rtl->config_len + rtl->fw_len;
1124
buf = malloc(len);
1125
if (!buf) {
1126
RS_ERR("Can't alloc mem for fwc, %s", strerror(errno));
1127
goto err;
1128
} else {
1129
uint8_t *b;
1130
1131
RS_INFO("FWC copy directly");
1132
1133
b = rtl->fw_buf + rtl->fw_len;
1134
svn_ver = get_unaligned_le32(b - 8);
1135
coex_ver = get_unaligned_le32(b - 12);
1136
1137
RS_INFO("Svn version: %u\n", svn_ver);
1138
tmp = ((coex_ver >> 16) & 0x7ff) +
1139
(coex_ver >> 27) * 10000;
1140
RS_INFO("Coexistence: BTCOEX_20%06d-%04x\n", tmp,
1141
(coex_ver & 0xffff));
1142
1143
/* Copy Patch and Config */
1144
memcpy(buf, rtl->fw_buf, rtl->fw_len);
1145
if (rtl->config_len)
1146
memcpy(buf + rtl->fw_len,
1147
rtl->config_buf, rtl->config_len);
1148
rtl->dl_fw_flag = 1;
1149
*rlen = len;
1150
return buf;
1151
}
1152
}
1153
1154
if (memcmp(rtl->fw_buf, rtb_patch_smagic, 8)) {
1155
RS_ERR("Signature error");
1156
goto err;
1157
}
1158
1159
if (memcmp(rtl->fw_buf + rtl->fw_len - 4, rtb_patch_emagic, 4)) {
1160
RS_ERR("Extension section signature error");
1161
goto err;
1162
}
1163
1164
proj_id = rtb_get_fw_project_id(rtl->fw_buf + rtl->fw_len - 5);
1165
1166
#ifdef RTL_8703A_SUPPORT
1167
if (rtl->hci_ver == 0x4 && rtl->lmp_subver == ROM_LMP_8723b) {
1168
RS_INFO("HCI version = 0x4, IC is 8703A.");
1169
} else {
1170
RS_ERR("error: lmp_version %x, hci_version %x, project_id %x",
1171
rtl->lmp_subver, rtl->hci_ver, project_id[proj_id]);
1172
goto err;
1173
}
1174
#else
1175
if (rtl->lmp_subver != ROM_LMP_8703b) {
1176
if (rtl->lmp_subver != project_id[proj_id]) {
1177
RS_ERR("lmp_subver %04x, project id %04x, mismatch\n",
1178
rtl->lmp_subver, project_id[proj_id]);
1179
goto err;
1180
}
1181
} else {
1182
if (rtb_cfg.patch_ent->proj_id != project_id[proj_id]) {
1183
RS_ERR("proj_id %04x, version %04x from firmware "
1184
"project_id[%u], mismatch",
1185
rtb_cfg.patch_ent->proj_id,
1186
project_id[proj_id], proj_id);
1187
goto err;
1188
}
1189
}
1190
#endif
1191
1192
/* Entry is allocated dynamically. It should be freed later in the
1193
* function.
1194
*/
1195
entry = rtb_get_patch_entry();
1196
1197
if (entry) {
1198
len = entry->patch_len + rtl->config_len;
1199
} else {
1200
RS_ERR("Can't find the patch entry");
1201
goto err;
1202
}
1203
1204
buf = malloc(len);
1205
if (!buf) {
1206
RS_ERR("%s: Can't alloc memory for fwc, %s", __func__,
1207
strerror(errno));
1208
free(entry);
1209
goto err;
1210
} else {
1211
memcpy(buf, rtl->fw_buf + entry->soffset, entry->patch_len);
1212
memcpy(buf + entry->patch_len - 4, &patch->fw_version, 4);
1213
1214
if (rtl->config_len)
1215
memcpy(buf + entry->patch_len, rtl->config_buf,
1216
rtl->config_len);
1217
rtl->dl_fw_flag = 1;
1218
*rlen = len;
1219
}
1220
1221
RS_INFO("FW %s exists, Config file %s exists",
1222
(rtl->fw_len > 0) ? "" : "not",
1223
(rtl->config_len > 0) ? "" : "not");
1224
1225
free(entry);
1226
return buf;
1227
1228
err:
1229
rtl->dl_fw_flag = 0;
1230
*rlen = 0;
1231
return NULL;
1232
}
1233
1234
1235