1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2013 Realtek Semiconductor Corp.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
5*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
6*4882a593Smuzhiyun * the Free Software Foundation; either version 2 of the License, or
7*4882a593Smuzhiyun * (at your option) any later version.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
10*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*4882a593Smuzhiyun * GNU General Public License for more details.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Module Name:
15*4882a593Smuzhiyun * hciattach_rtk.c
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * Description:
18*4882a593Smuzhiyun * H4/H5 specific initialization
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * Revision History:
21*4882a593Smuzhiyun * Date Version Author Comment
22*4882a593Smuzhiyun * ---------- --------- --------------- -----------------------
23*4882a593Smuzhiyun * 2013-06-06 1.0.0 gordon_yang Create
24*4882a593Smuzhiyun * 2013-06-18 1.0.1 lory_xu add support for multi fw
25*4882a593Smuzhiyun * 2013-06-21 1.0.2 gordon_yang add timeout for get version cmd
26*4882a593Smuzhiyun * 2013-07-01 1.0.3 lory_xu close file handle
27*4882a593Smuzhiyun * 2013-07-01 2.0 champion_chen add IC check
28*4882a593Smuzhiyun * 2013-12-16 2.1 champion_chen fix bug in Additional packet number
29*4882a593Smuzhiyun * 2013-12-25 2.2 champion_chen open host flow control after send last fw packet
30*4882a593Smuzhiyun */
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #ifdef HAVE_CONFIG_H
33*4882a593Smuzhiyun #include <config.h>
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #include <stdio.h>
37*4882a593Smuzhiyun #include <errno.h>
38*4882a593Smuzhiyun #include <unistd.h>
39*4882a593Smuzhiyun #include <stdlib.h>
40*4882a593Smuzhiyun #include <termios.h>
41*4882a593Smuzhiyun #include <time.h>
42*4882a593Smuzhiyun #include <sys/time.h>
43*4882a593Smuzhiyun #include <sys/types.h>
44*4882a593Smuzhiyun #include <sys/param.h>
45*4882a593Smuzhiyun #include <sys/ioctl.h>
46*4882a593Smuzhiyun #include <sys/socket.h>
47*4882a593Smuzhiyun #include <sys/uio.h>
48*4882a593Smuzhiyun #include <sys/stat.h>
49*4882a593Smuzhiyun #include <fcntl.h>
50*4882a593Smuzhiyun #include <signal.h>
51*4882a593Smuzhiyun #include <stdint.h>
52*4882a593Smuzhiyun #include <string.h>
53*4882a593Smuzhiyun #include <endian.h>
54*4882a593Smuzhiyun #include <byteswap.h>
55*4882a593Smuzhiyun #include <netinet/in.h>
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #include "hciattach.h"
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #define RTK_VERSION "4.1"
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* #define RTL_8703A_SUPPORT */
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #define USE_CUSTOMER_ADDRESS
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun #define BAUDRATE_4BYTES
66*4882a593Smuzhiyun #define FIRMWARE_DIRECTORY "/lib/firmware/rtlbt/"
67*4882a593Smuzhiyun #define BT_CONFIG_DIRECTORY "/lib/firmware/rtlbt/"
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun #ifdef USE_CUSTOMER_ADDRESS
70*4882a593Smuzhiyun #define BT_ADDR_FILE "/opt/bdaddr"
71*4882a593Smuzhiyun static uint8_t customer_bdaddr = 0;
72*4882a593Smuzhiyun #endif
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun #define CONFIG_TXPOWER (1 << 0)
75*4882a593Smuzhiyun #define CONFIG_XTAL (1 << 1)
76*4882a593Smuzhiyun #define CONFIG_BTMAC (1 << 2)
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun #define EXTRA_CONFIG_OPTION
79*4882a593Smuzhiyun #ifdef EXTRA_CONFIG_OPTION
80*4882a593Smuzhiyun #define EXTRA_CONFIG_FILE "/opt/rtk_btconfig.txt"
81*4882a593Smuzhiyun static uint32_t config_flags;
82*4882a593Smuzhiyun static uint8_t txpower_cfg[4];
83*4882a593Smuzhiyun static uint8_t txpower_len;
84*4882a593Smuzhiyun static uint8_t xtal_cfg;
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun #if __BYTE_ORDER == __LITTLE_ENDIAN
88*4882a593Smuzhiyun #define cpu_to_le16(d) (d)
89*4882a593Smuzhiyun #define cpu_to_le32(d) (d)
90*4882a593Smuzhiyun #define le16_to_cpu(d) (d)
91*4882a593Smuzhiyun #define le32_to_cpu(d) (d)
92*4882a593Smuzhiyun #elif __BYTE_ORDER == __BIG_ENDIAN
93*4882a593Smuzhiyun #define cpu_to_le16(d) bswap_16(d)
94*4882a593Smuzhiyun #define cpu_to_le32(d) bswap_32(d)
95*4882a593Smuzhiyun #define le16_to_cpu(d) bswap_16(d)
96*4882a593Smuzhiyun #define le32_to_cpu(d) bswap_32(d)
97*4882a593Smuzhiyun #else
98*4882a593Smuzhiyun #error "Unknown byte order"
99*4882a593Smuzhiyun #endif
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun typedef uint8_t RT_U8, *PRT_U8;
102*4882a593Smuzhiyun typedef int8_t RT_S8, *PRT_S8;
103*4882a593Smuzhiyun typedef uint16_t RT_U16, *PRT_U16;
104*4882a593Smuzhiyun typedef int32_t RT_S32, *PRT_S32;
105*4882a593Smuzhiyun typedef uint32_t RT_U32, *PRT_U32;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun RT_U8 DBG_ON = 1;
108*4882a593Smuzhiyun #define LOG_STR "Realtek Bluetooth"
109*4882a593Smuzhiyun #define RS_DBG(fmt, arg...) \
110*4882a593Smuzhiyun do{ \
111*4882a593Smuzhiyun if (DBG_ON) \
112*4882a593Smuzhiyun fprintf(stderr, "%s :" fmt "\n" , LOG_STR, ##arg); \
113*4882a593Smuzhiyun }while(0)
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun #define RS_INFO(fmt, arg...) \
116*4882a593Smuzhiyun do{ \
117*4882a593Smuzhiyun fprintf(stderr, "%s :" fmt "\n", LOG_STR, ##arg); \
118*4882a593Smuzhiyun }while(0)
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun #define RS_ERR(fmt, arg...) \
121*4882a593Smuzhiyun do{ \
122*4882a593Smuzhiyun fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg); \
123*4882a593Smuzhiyun }while(0)
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun #define HCI_COMMAND_HDR_SIZE 3
126*4882a593Smuzhiyun #define HCI_EVENT_HDR_SIZE 2
127*4882a593Smuzhiyun /* #define RTK_PATCH_LENGTH_MAX 24576 */ //24*1024
128*4882a593Smuzhiyun #define RTK_PATCH_LENGTH_MAX (40 * 1024)
129*4882a593Smuzhiyun #define PATCH_DATA_FIELD_MAX_SIZE 252
130*4882a593Smuzhiyun #define READ_DATA_SIZE 16
131*4882a593Smuzhiyun #define H5_MAX_RETRY_COUNT 40
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun #define RTK_VENDOR_CONFIG_MAGIC 0x8723ab55
134*4882a593Smuzhiyun const RT_U8 RTK_EPATCH_SIGNATURE[8] =
135*4882a593Smuzhiyun { 0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68 };
136*4882a593Smuzhiyun const RT_U8 Extension_Section_SIGNATURE[4] = { 0x51, 0x04, 0xFD, 0x77 };
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun #define HCI_CMD_READ_BD_ADDR 0x1009
139*4882a593Smuzhiyun #define HCI_VENDOR_CHANGE_BDRATE 0xfc17
140*4882a593Smuzhiyun #define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d
141*4882a593Smuzhiyun #define HCI_CMD_READ_LOCAL_VERISION 0x1001
142*4882a593Smuzhiyun #define HCI_VENDOR_READ_CHIP_TYPE 0xfc61
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun #define ROM_LMP_NONE 0x0000
145*4882a593Smuzhiyun #define ROM_LMP_8723a 0x1200
146*4882a593Smuzhiyun #define ROM_LMP_8723b 0x8723
147*4882a593Smuzhiyun #define ROM_LMP_8821a 0x8821
148*4882a593Smuzhiyun #define ROM_LMP_8761a 0x8761
149*4882a593Smuzhiyun #define ROM_LMP_8761btc 0x8763
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun #define ROM_LMP_8703a 0x87b3
152*4882a593Smuzhiyun #define ROM_LMP_8763a 0x8763
153*4882a593Smuzhiyun #define ROM_LMP_8703b 0x8703
154*4882a593Smuzhiyun #define ROM_LMP_8723c 0x87c3 /* ??????? */
155*4882a593Smuzhiyun #define ROM_LMP_8822b 0x8822
156*4882a593Smuzhiyun #define ROM_LMP_8723cs_xx 0x8704
157*4882a593Smuzhiyun #define ROM_LMP_8723cs_cg 0x8705
158*4882a593Smuzhiyun #define ROM_LMP_8723cs_vf 0x8706
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* Chip type */
161*4882a593Smuzhiyun #define CHIP_8703AS 1
162*4882a593Smuzhiyun #define CHIP_8723CS_CG 3
163*4882a593Smuzhiyun #define CHIP_8723CS_VF 4
164*4882a593Smuzhiyun #define CHIP_RTL8723CS_XX 5
165*4882a593Smuzhiyun #define CHIP_8703BS 7
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /* software id */
168*4882a593Smuzhiyun #define CHIP_UNKNOWN 0x00
169*4882a593Smuzhiyun #define CHIP_8761AT 0x1F
170*4882a593Smuzhiyun #define CHIP_8761ATF 0x2F
171*4882a593Smuzhiyun #define CHIP_8761BTC 0x3F
172*4882a593Smuzhiyun #define CHIP_8761B 0x4F
173*4882a593Smuzhiyun #define CHIP_BEFORE 0x6F
174*4882a593Smuzhiyun #define CHIP_8822BS 0x70
175*4882a593Smuzhiyun #define CHIP_8723DS 0x71
176*4882a593Smuzhiyun #define CHIP_8821CS 0x72
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* HCI data types */
179*4882a593Smuzhiyun #define H5_ACK_PKT 0x00
180*4882a593Smuzhiyun #define HCI_COMMAND_PKT 0x01
181*4882a593Smuzhiyun #define HCI_ACLDATA_PKT 0x02
182*4882a593Smuzhiyun #define HCI_SCODATA_PKT 0x03
183*4882a593Smuzhiyun #define HCI_EVENT_PKT 0x04
184*4882a593Smuzhiyun #define H5_VDRSPEC_PKT 0x0E
185*4882a593Smuzhiyun #define H5_LINK_CTL_PKT 0x0F
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun #define H5_HDR_SEQ(hdr) ((hdr)[0] & 0x07)
188*4882a593Smuzhiyun #define H5_HDR_ACK(hdr) (((hdr)[0] >> 3) & 0x07)
189*4882a593Smuzhiyun #define H5_HDR_CRC(hdr) (((hdr)[0] >> 6) & 0x01)
190*4882a593Smuzhiyun #define H5_HDR_RELIABLE(hdr) (((hdr)[0] >> 7) & 0x01)
191*4882a593Smuzhiyun #define H5_HDR_PKT_TYPE(hdr) ((hdr)[1] & 0x0f)
192*4882a593Smuzhiyun #define H5_HDR_LEN(hdr) ((((hdr)[1] >> 4) & 0xff) + ((hdr)[2] << 4))
193*4882a593Smuzhiyun #define H5_HDR_SIZE 4
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun struct sk_buff {
196*4882a593Smuzhiyun RT_U32 max_len;
197*4882a593Smuzhiyun RT_U32 data_len;
198*4882a593Smuzhiyun RT_U8 data[0];
199*4882a593Smuzhiyun };
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /* Skb helpers */
202*4882a593Smuzhiyun struct bt_skb_cb {
203*4882a593Smuzhiyun RT_U8 pkt_type;
204*4882a593Smuzhiyun RT_U8 incoming;
205*4882a593Smuzhiyun RT_U16 expect;
206*4882a593Smuzhiyun RT_U8 tx_seq;
207*4882a593Smuzhiyun RT_U8 retries;
208*4882a593Smuzhiyun RT_U8 sar;
209*4882a593Smuzhiyun unsigned short channel;
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun typedef struct {
213*4882a593Smuzhiyun uint8_t index;
214*4882a593Smuzhiyun uint8_t data[252];
215*4882a593Smuzhiyun } __attribute__ ((packed)) download_vendor_patch_cp;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun struct hci_command_hdr {
218*4882a593Smuzhiyun RT_U16 opcode;
219*4882a593Smuzhiyun RT_U8 plen;
220*4882a593Smuzhiyun } __attribute__ ((packed));
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun struct hci_event_hdr {
223*4882a593Smuzhiyun RT_U8 evt;
224*4882a593Smuzhiyun RT_U8 plen;
225*4882a593Smuzhiyun } __attribute__ ((packed));
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun struct hci_ev_cmd_complete {
228*4882a593Smuzhiyun RT_U8 ncmd;
229*4882a593Smuzhiyun RT_U16 opcode;
230*4882a593Smuzhiyun } __attribute__ ((packed));
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun struct rtk_bt_vendor_config_entry {
233*4882a593Smuzhiyun RT_U16 offset;
234*4882a593Smuzhiyun RT_U8 entry_len;
235*4882a593Smuzhiyun RT_U8 entry_data[0];
236*4882a593Smuzhiyun } __attribute__ ((packed));
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun struct rtk_bt_vendor_config {
239*4882a593Smuzhiyun RT_U32 signature;
240*4882a593Smuzhiyun RT_U16 data_len;
241*4882a593Smuzhiyun struct rtk_bt_vendor_config_entry entry[0];
242*4882a593Smuzhiyun } __attribute__ ((packed));
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun struct rtk_epatch_entry {
245*4882a593Smuzhiyun RT_U16 chipID;
246*4882a593Smuzhiyun RT_U16 patch_length;
247*4882a593Smuzhiyun RT_U32 start_offset;
248*4882a593Smuzhiyun RT_U32 svn_ver;
249*4882a593Smuzhiyun RT_U32 coex_ver;
250*4882a593Smuzhiyun } __attribute__ ((packed));
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun struct rtk_epatch {
253*4882a593Smuzhiyun RT_U8 signature[8];
254*4882a593Smuzhiyun RT_U32 fw_version;
255*4882a593Smuzhiyun RT_U16 number_of_patch;
256*4882a593Smuzhiyun struct rtk_epatch_entry entry[0];
257*4882a593Smuzhiyun } __attribute__ ((packed));
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun struct rtk_extension_entry {
260*4882a593Smuzhiyun uint8_t opcode;
261*4882a593Smuzhiyun uint8_t length;
262*4882a593Smuzhiyun uint8_t *data;
263*4882a593Smuzhiyun } __attribute__ ((packed));
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun typedef enum _RTK_ROM_VERSION_CMD_STATE {
266*4882a593Smuzhiyun cmd_not_send,
267*4882a593Smuzhiyun cmd_has_sent,
268*4882a593Smuzhiyun event_received
269*4882a593Smuzhiyun } RTK_ROM_VERSION_CMD_STATE;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun typedef enum _H5_RX_STATE {
272*4882a593Smuzhiyun H5_W4_PKT_DELIMITER,
273*4882a593Smuzhiyun H5_W4_PKT_START,
274*4882a593Smuzhiyun H5_W4_HDR,
275*4882a593Smuzhiyun H5_W4_DATA,
276*4882a593Smuzhiyun H5_W4_CRC
277*4882a593Smuzhiyun } H5_RX_STATE;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun typedef enum _H5_RX_ESC_STATE {
280*4882a593Smuzhiyun H5_ESCSTATE_NOESC,
281*4882a593Smuzhiyun H5_ESCSTATE_ESC
282*4882a593Smuzhiyun } H5_RX_ESC_STATE;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun typedef enum _H5_LINK_STATE {
285*4882a593Smuzhiyun H5_SYNC,
286*4882a593Smuzhiyun H5_CONFIG,
287*4882a593Smuzhiyun H5_INIT,
288*4882a593Smuzhiyun H5_PATCH,
289*4882a593Smuzhiyun H5_ACTIVE
290*4882a593Smuzhiyun } H5_LINK_STATE;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun uint16_t project_id[]=
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun ROM_LMP_8723a,
295*4882a593Smuzhiyun ROM_LMP_8723b, /* RTL8723BS */
296*4882a593Smuzhiyun ROM_LMP_8821a, /* RTL8821AS */
297*4882a593Smuzhiyun ROM_LMP_8761a, /* RTL8761ATV */
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun ROM_LMP_8703a,
300*4882a593Smuzhiyun ROM_LMP_8763a,
301*4882a593Smuzhiyun ROM_LMP_8703b,
302*4882a593Smuzhiyun ROM_LMP_8723c, /* index 7 for 8723CS. What is for other 8723CS */
303*4882a593Smuzhiyun ROM_LMP_8822b, /* RTL8822BS */
304*4882a593Smuzhiyun ROM_LMP_8723b, /* RTL8723DS */
305*4882a593Smuzhiyun ROM_LMP_8821a, /* id 10 for RTL8821CS, lmp subver 0x8821 */
306*4882a593Smuzhiyun ROM_LMP_NONE
307*4882a593Smuzhiyun };
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun #define RTL_FW_MATCH_CHIP_TYPE (1 << 0)
310*4882a593Smuzhiyun #define RTL_FW_MATCH_HCI_VER (1 << 1)
311*4882a593Smuzhiyun #define RTL_FW_MATCH_HCI_REV (1 << 2)
312*4882a593Smuzhiyun struct patch_info {
313*4882a593Smuzhiyun uint32_t match_flags;
314*4882a593Smuzhiyun uint8_t chip_type;
315*4882a593Smuzhiyun uint16_t lmp_subver;
316*4882a593Smuzhiyun uint16_t proj_id;
317*4882a593Smuzhiyun uint8_t hci_ver;
318*4882a593Smuzhiyun uint16_t hci_rev;
319*4882a593Smuzhiyun char *patch_file;
320*4882a593Smuzhiyun char *config_file;
321*4882a593Smuzhiyun char *ic_name;
322*4882a593Smuzhiyun };
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun static struct patch_info h4_patch_table[] = {
325*4882a593Smuzhiyun /* match flags, chip type, lmp subver, proj id(unused), hci_ver,
326*4882a593Smuzhiyun * hci_rev, ...
327*4882a593Smuzhiyun */
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun /* RTL8761AT */
330*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_8761AT,
331*4882a593Smuzhiyun 0x8761, 0xffff, 0, 0x000a,
332*4882a593Smuzhiyun "rtl8761at_fw", "rtl8761at_config", "RTL8761AT" },
333*4882a593Smuzhiyun /* RTL8761ATF */
334*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_8761ATF,
335*4882a593Smuzhiyun 0x8761, 0xffff, 0, 0x000a,
336*4882a593Smuzhiyun "rtl8761atf_fw", "rtl8761atf_config", "RTL8761ATF" },
337*4882a593Smuzhiyun /* RTL8761B TC
338*4882a593Smuzhiyun * FW/Config is not used.
339*4882a593Smuzhiyun */
340*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_8761BTC,
341*4882a593Smuzhiyun 0x8763, 0xffff, 0, 0x000b,
342*4882a593Smuzhiyun "rtl8761btc_fw", "rtl8761btc_config", "RTL8761BTC" },
343*4882a593Smuzhiyun /* RTL8761B */
344*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_8761B,
345*4882a593Smuzhiyun 0x8761, 0xffff, 0, 0x000b,
346*4882a593Smuzhiyun "rtl8761b_fw", "rtl8761b_config", "RTL8761B" },
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun { 0, 0, 0, ROM_LMP_NONE, 0, 0, "rtl_none_fw", "rtl_none_config", "NONE"}
349*4882a593Smuzhiyun };
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun static struct patch_info patch_table[] = {
352*4882a593Smuzhiyun /* match flags, chip type, lmp subver, proj id(unused), hci_ver,
353*4882a593Smuzhiyun * hci_rev, ...
354*4882a593Smuzhiyun */
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* RTL8723AS */
357*4882a593Smuzhiyun { 0, 0, ROM_LMP_8723a, ROM_LMP_8723a, 0, 0,
358*4882a593Smuzhiyun "rtl8723a_fw", "rtl8723a_config", "RTL8723AS"},
359*4882a593Smuzhiyun /* RTL8821CS */
360*4882a593Smuzhiyun { RTL_FW_MATCH_HCI_REV, CHIP_8821CS,
361*4882a593Smuzhiyun ROM_LMP_8821a, ROM_LMP_8821a, 0, 0x000c,
362*4882a593Smuzhiyun "rtl8821c_fw", "rtl8821c_config", "RTL8821CS"},
363*4882a593Smuzhiyun /* RTL8821AS */
364*4882a593Smuzhiyun { 0, 0, ROM_LMP_8821a, ROM_LMP_8821a, 0, 0,
365*4882a593Smuzhiyun "rtl8821a_fw", "rtl8821a_config", "RTL8821AS"},
366*4882a593Smuzhiyun /* RTL8761ATV */
367*4882a593Smuzhiyun { 0, 0, ROM_LMP_8761a, ROM_LMP_8761a, 0, 0,
368*4882a593Smuzhiyun "rtl8761a_fw", "rtl8761a_config", "RTL8761ATV"},
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun /* RTL8703AS
371*4882a593Smuzhiyun * RTL8822BS
372*4882a593Smuzhiyun * */
373*4882a593Smuzhiyun #ifdef RTL_8703A_SUPPORT
374*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_8703AS,
375*4882a593Smuzhiyun ROM_LMP_8723b, ROM_LMP_8723b, 0, 0,
376*4882a593Smuzhiyun "rtl8703a_fw", "rtl8703a_config", "RTL8703AS"},
377*4882a593Smuzhiyun #endif
378*4882a593Smuzhiyun { 0, CHIP_8822BS, ROM_LMP_8822b, ROM_LMP_8822b, 0, 0,
379*4882a593Smuzhiyun "rtl8822b_fw", "rtl8822b_config", "RTL8822BS"},
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun /* RTL8703BS
382*4882a593Smuzhiyun * RTL8723CS_XX
383*4882a593Smuzhiyun * RTL8723CS_CG
384*4882a593Smuzhiyun * RTL8723CS_VF
385*4882a593Smuzhiyun * */
386*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_8703BS,
387*4882a593Smuzhiyun ROM_LMP_8703b, ROM_LMP_8703b, 0, 0,
388*4882a593Smuzhiyun "rtl8703b_fw", "rtl8703b_config", "RTL8703BS"},
389*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_RTL8723CS_XX,
390*4882a593Smuzhiyun ROM_LMP_8703b, ROM_LMP_8723cs_xx, 0, 0,
391*4882a593Smuzhiyun "rtl8723cs_xx_fw", "rtl8723cs_xx_config", "RTL8723CS_XX"},
392*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_CG,
393*4882a593Smuzhiyun ROM_LMP_8703b, ROM_LMP_8723cs_cg, 0, 0,
394*4882a593Smuzhiyun "rtl8723cs_cg_fw", "rtl8723cs_cg_config", "RTL8723CS_CG"},
395*4882a593Smuzhiyun { RTL_FW_MATCH_CHIP_TYPE, CHIP_8723CS_VF,
396*4882a593Smuzhiyun ROM_LMP_8703b, ROM_LMP_8723cs_vf, 0, 0,
397*4882a593Smuzhiyun "rtl8723cs_vf_fw", "rtl8723cs_vf_config", "RTL8723CS_VF"},
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun /* RTL8723BS */
400*4882a593Smuzhiyun { RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, 0,
401*4882a593Smuzhiyun ROM_LMP_8723b, ROM_LMP_8723b, 6, 0x000b,
402*4882a593Smuzhiyun "rtl8723b_fw", "rtl8723b_config", "RTL8723BS"},
403*4882a593Smuzhiyun /* RTL8723DS */
404*4882a593Smuzhiyun { RTL_FW_MATCH_HCI_VER | RTL_FW_MATCH_HCI_REV, CHIP_8723DS,
405*4882a593Smuzhiyun ROM_LMP_8723b, ROM_LMP_8723b, 8, 0x000d,
406*4882a593Smuzhiyun "rtl8723d_fw", "rtl8723d_config", "RTL8723DS"},
407*4882a593Smuzhiyun /* add entries here*/
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun { 0, 0, 0, ROM_LMP_NONE, 0, 0, "rtl_none_fw", "rtl_none_config", "NONE"}
410*4882a593Smuzhiyun };
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun typedef struct btrtl_info {
413*4882a593Smuzhiyun /**********************h5 releated*************************/
414*4882a593Smuzhiyun RT_U8 rxseq_txack; /* expected rx seq number */
415*4882a593Smuzhiyun RT_U8 rxack; /* last packet sent by us that the peer ack'ed */
416*4882a593Smuzhiyun RT_U8 use_crc;
417*4882a593Smuzhiyun RT_U8 is_txack_req; /* txack required */
418*4882a593Smuzhiyun RT_U8 msgq_txseq; /* next pkt seq */
419*4882a593Smuzhiyun RT_U16 message_crc;
420*4882a593Smuzhiyun RT_U32 rx_count; /* expected pkts to recv */
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun H5_RX_STATE rx_state;
423*4882a593Smuzhiyun H5_RX_ESC_STATE rx_esc_state;
424*4882a593Smuzhiyun H5_LINK_STATE link_estab_state;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun struct sk_buff *rx_skb;
427*4882a593Smuzhiyun struct sk_buff *host_last_cmd;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun uint16_t num_of_cmd_sent;
430*4882a593Smuzhiyun RT_U16 lmp_subver;
431*4882a593Smuzhiyun uint16_t hci_rev;
432*4882a593Smuzhiyun uint8_t hci_ver;
433*4882a593Smuzhiyun RT_U8 eversion;
434*4882a593Smuzhiyun int h5_max_retries;
435*4882a593Smuzhiyun RT_U8 chip_type;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /**********************patch related************************/
438*4882a593Smuzhiyun uint32_t baudrate;
439*4882a593Smuzhiyun uint8_t dl_fw_flag;
440*4882a593Smuzhiyun int serial_fd;
441*4882a593Smuzhiyun int hw_flow_control;
442*4882a593Smuzhiyun int final_speed;
443*4882a593Smuzhiyun int total_num; /* total pkt number */
444*4882a593Smuzhiyun int tx_index; /* current sending pkt number */
445*4882a593Smuzhiyun int rx_index; /* ack index from board */
446*4882a593Smuzhiyun int fw_len; /* fw patch file len */
447*4882a593Smuzhiyun int config_len; /* config patch file len */
448*4882a593Smuzhiyun int total_len; /* fw & config extracted buf len */
449*4882a593Smuzhiyun uint8_t *fw_buf; /* fw patch file buf */
450*4882a593Smuzhiyun uint8_t *config_buf; /* config patch file buf */
451*4882a593Smuzhiyun uint8_t *total_buf; /* fw & config extracted buf */
452*4882a593Smuzhiyun RTK_ROM_VERSION_CMD_STATE rom_version_cmd_state;
453*4882a593Smuzhiyun RTK_ROM_VERSION_CMD_STATE hci_version_cmd_state;
454*4882a593Smuzhiyun RTK_ROM_VERSION_CMD_STATE chip_type_cmd_state;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun struct patch_info *patch_ent;
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun int proto;
459*4882a593Smuzhiyun } rtk_hw_cfg_t;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun static rtk_hw_cfg_t rtk_hw_cfg;
462*4882a593Smuzhiyun
util_hexdump(const uint8_t * buf,size_t len)463*4882a593Smuzhiyun void util_hexdump(const uint8_t *buf, size_t len)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun static const char hexdigits[] = "0123456789abcdef";
466*4882a593Smuzhiyun char str[16 * 3];
467*4882a593Smuzhiyun size_t i;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun if (!buf || !len)
470*4882a593Smuzhiyun return;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun for (i = 0; i < len; i++) {
473*4882a593Smuzhiyun str[((i % 16) * 3)] = hexdigits[buf[i] >> 4];
474*4882a593Smuzhiyun str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
475*4882a593Smuzhiyun str[((i % 16) * 3) + 2] = ' ';
476*4882a593Smuzhiyun if ((i + 1) % 16 == 0) {
477*4882a593Smuzhiyun str[16 * 3 - 1] = '\0';
478*4882a593Smuzhiyun RS_INFO("%s", str);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun if (i % 16 > 0) {
483*4882a593Smuzhiyun str[(i % 16) * 3 - 1] = '\0';
484*4882a593Smuzhiyun RS_INFO("%s", str);
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun #ifdef EXTRA_CONFIG_OPTION
489*4882a593Smuzhiyun
xtalset_supported(void)490*4882a593Smuzhiyun static inline int xtalset_supported(void)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun struct patch_info *pent = rtk_hw_cfg.patch_ent;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun /* Only support rtl8723ds, rtl8822bs and rtl8821cs xtal config */
495*4882a593Smuzhiyun if (pent->chip_type != CHIP_8723DS &&
496*4882a593Smuzhiyun pent->chip_type != CHIP_8822BS &&
497*4882a593Smuzhiyun pent->chip_type != CHIP_8821CS)
498*4882a593Smuzhiyun return 0;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun return 1;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
line_proc(char * buff,int len)503*4882a593Smuzhiyun static void line_proc(char *buff, int len)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun char *argv[32];
506*4882a593Smuzhiyun int nargs = 0;
507*4882a593Smuzhiyun RS_INFO("%s", buff);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun while (nargs < 32) {
510*4882a593Smuzhiyun /* skip any white space */
511*4882a593Smuzhiyun while ((*buff == ' ') || (*buff == '\t') ||
512*4882a593Smuzhiyun *buff == ',') {
513*4882a593Smuzhiyun ++buff;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun if (*buff == '\0') {
517*4882a593Smuzhiyun /* end of line, no more args */
518*4882a593Smuzhiyun argv[nargs] = NULL;
519*4882a593Smuzhiyun break;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun /* begin of argument string */
523*4882a593Smuzhiyun argv[nargs++] = buff;
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun /* find end of string */
526*4882a593Smuzhiyun while (*buff && (*buff != ' ') && (*buff != '\t')) {
527*4882a593Smuzhiyun ++buff;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun if (*buff == '\r' || *buff == '\n')
531*4882a593Smuzhiyun ++buff;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun if (*buff == '\0') {
534*4882a593Smuzhiyun /* end of line, no more args */
535*4882a593Smuzhiyun argv[nargs] = NULL;
536*4882a593Smuzhiyun break;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun *buff++ = '\0'; /* terminate current arg */
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun /* valid config */
543*4882a593Smuzhiyun if (nargs >= 4) {
544*4882a593Smuzhiyun unsigned long int offset;
545*4882a593Smuzhiyun uint8_t l;
546*4882a593Smuzhiyun uint8_t i = 0;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun offset = strtoul(argv[0], NULL, 16);
549*4882a593Smuzhiyun offset = offset | (strtoul(argv[1], NULL, 16) << 8);
550*4882a593Smuzhiyun RS_INFO("extra config offset %04lx", offset);
551*4882a593Smuzhiyun l = strtoul(argv[2], NULL, 16);
552*4882a593Smuzhiyun if (l != (uint8_t)(nargs - 3)) {
553*4882a593Smuzhiyun RS_ERR("invalid len %u", l);
554*4882a593Smuzhiyun return;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun if (offset == 0x015b && l <= 4) {
558*4882a593Smuzhiyun /* Tx power */
559*4882a593Smuzhiyun for (i = 0; i < l; i++)
560*4882a593Smuzhiyun txpower_cfg[i] = (uint8_t)strtoul(argv[3 + i], NULL, 16);
561*4882a593Smuzhiyun txpower_len = l;
562*4882a593Smuzhiyun config_flags |= CONFIG_TXPOWER;
563*4882a593Smuzhiyun } else if (offset == 0x01e6) {
564*4882a593Smuzhiyun /* XTAL for 8822B, 8821C 8723D */
565*4882a593Smuzhiyun xtal_cfg = (uint8_t)strtoul(argv[3], NULL, 16);
566*4882a593Smuzhiyun config_flags |= CONFIG_XTAL;
567*4882a593Smuzhiyun } else {
568*4882a593Smuzhiyun RS_ERR("extra config %04lx is not supported", offset);
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
config_proc(uint8_t * buff,int len)573*4882a593Smuzhiyun static void config_proc(uint8_t *buff, int len)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun uint8_t *head = buff;
576*4882a593Smuzhiyun uint8_t *ptr = buff;
577*4882a593Smuzhiyun int l;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun while (len > 0) {
580*4882a593Smuzhiyun ptr = strchr(head, '\n');
581*4882a593Smuzhiyun if (!ptr)
582*4882a593Smuzhiyun break;
583*4882a593Smuzhiyun *ptr++ = '\0';
584*4882a593Smuzhiyun while (*head == ' ' || *head == '\t')
585*4882a593Smuzhiyun head++;
586*4882a593Smuzhiyun l = ptr - head;
587*4882a593Smuzhiyun if (l > 0 && *head != '#')
588*4882a593Smuzhiyun line_proc(head, l);
589*4882a593Smuzhiyun head = ptr;
590*4882a593Smuzhiyun len -= l;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
config_file_proc(const char * path)594*4882a593Smuzhiyun static void config_file_proc(const char *path)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun int fd;
597*4882a593Smuzhiyun uint8_t buff[256];
598*4882a593Smuzhiyun int result;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun fd = open(path, O_RDONLY);
601*4882a593Smuzhiyun if (fd == -1) {
602*4882a593Smuzhiyun RS_INFO("Couldnt open extra config %s, %s", path, strerror(errno));
603*4882a593Smuzhiyun return;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun result = read(fd, buff, sizeof(buff));
607*4882a593Smuzhiyun if (result == -1) {
608*4882a593Smuzhiyun RS_ERR("Couldnt read %s, %s", path, strerror(errno));
609*4882a593Smuzhiyun close(fd);
610*4882a593Smuzhiyun return;
611*4882a593Smuzhiyun } else if (result == 0) {
612*4882a593Smuzhiyun RS_ERR("File is empty");
613*4882a593Smuzhiyun close(fd);
614*4882a593Smuzhiyun return;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun config_proc(buff, result);
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun close(fd);
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun #endif
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun /* Get the entry from patch_table according to LMP subversion */
get_patch_entry(struct btrtl_info * btrtl)624*4882a593Smuzhiyun struct patch_info *get_patch_entry(struct btrtl_info *btrtl)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun struct patch_info *n = NULL;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun if (btrtl->proto == HCI_UART_3WIRE)
629*4882a593Smuzhiyun n = patch_table;
630*4882a593Smuzhiyun else
631*4882a593Smuzhiyun n = h4_patch_table;
632*4882a593Smuzhiyun for (; n->lmp_subver; n++) {
633*4882a593Smuzhiyun if ((n->match_flags & RTL_FW_MATCH_CHIP_TYPE) &&
634*4882a593Smuzhiyun n->chip_type != btrtl->chip_type)
635*4882a593Smuzhiyun continue;
636*4882a593Smuzhiyun if ((n->match_flags & RTL_FW_MATCH_HCI_VER) &&
637*4882a593Smuzhiyun n->hci_ver != btrtl->hci_ver)
638*4882a593Smuzhiyun continue;
639*4882a593Smuzhiyun if ((n->match_flags & RTL_FW_MATCH_HCI_REV) &&
640*4882a593Smuzhiyun n->hci_rev != btrtl->hci_rev)
641*4882a593Smuzhiyun continue;
642*4882a593Smuzhiyun if (n->lmp_subver != btrtl->lmp_subver)
643*4882a593Smuzhiyun continue;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun break;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun return n;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun // bite reverse in bytes
652*4882a593Smuzhiyun // 00000001 -> 10000000
653*4882a593Smuzhiyun // 00000100 -> 00100000
654*4882a593Smuzhiyun const RT_U8 byte_rev_table[256] = {
655*4882a593Smuzhiyun 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
656*4882a593Smuzhiyun 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
657*4882a593Smuzhiyun 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
658*4882a593Smuzhiyun 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
659*4882a593Smuzhiyun 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
660*4882a593Smuzhiyun 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
661*4882a593Smuzhiyun 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
662*4882a593Smuzhiyun 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
663*4882a593Smuzhiyun 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
664*4882a593Smuzhiyun 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
665*4882a593Smuzhiyun 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
666*4882a593Smuzhiyun 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
667*4882a593Smuzhiyun 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
668*4882a593Smuzhiyun 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
669*4882a593Smuzhiyun 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
670*4882a593Smuzhiyun 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
671*4882a593Smuzhiyun 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
672*4882a593Smuzhiyun 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
673*4882a593Smuzhiyun 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
674*4882a593Smuzhiyun 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
675*4882a593Smuzhiyun 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
676*4882a593Smuzhiyun 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
677*4882a593Smuzhiyun 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
678*4882a593Smuzhiyun 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
679*4882a593Smuzhiyun 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
680*4882a593Smuzhiyun 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
681*4882a593Smuzhiyun 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
682*4882a593Smuzhiyun 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
683*4882a593Smuzhiyun 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
684*4882a593Smuzhiyun 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
685*4882a593Smuzhiyun 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
686*4882a593Smuzhiyun 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
687*4882a593Smuzhiyun };
688*4882a593Smuzhiyun
bit_rev8(RT_U8 byte)689*4882a593Smuzhiyun static __inline RT_U8 bit_rev8(RT_U8 byte)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun return byte_rev_table[byte];
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
bit_rev16(RT_U16 x)694*4882a593Smuzhiyun static __inline RT_U16 bit_rev16(RT_U16 x)
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun return (bit_rev8(x & 0xff) << 8) | bit_rev8(x >> 8);
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun static const RT_U16 crc_table[] = {
700*4882a593Smuzhiyun 0x0000, 0x1081, 0x2102, 0x3183,
701*4882a593Smuzhiyun 0x4204, 0x5285, 0x6306, 0x7387,
702*4882a593Smuzhiyun 0x8408, 0x9489, 0xa50a, 0xb58b,
703*4882a593Smuzhiyun 0xc60c, 0xd68d, 0xe70e, 0xf78f
704*4882a593Smuzhiyun };
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun // Initialise the crc calculator
707*4882a593Smuzhiyun #define H5_CRC_INIT(x) x = 0xffff
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun /**
710*4882a593Smuzhiyun * Malloc the socket buffer
711*4882a593Smuzhiyun *
712*4882a593Smuzhiyun * @param skb socket buffer
713*4882a593Smuzhiyun * @return the point to the malloc buffer
714*4882a593Smuzhiyun */
skb_alloc(unsigned int len)715*4882a593Smuzhiyun static __inline struct sk_buff *skb_alloc(unsigned int len)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun struct sk_buff *skb = NULL;
718*4882a593Smuzhiyun if ((skb = malloc(len + 8))) {
719*4882a593Smuzhiyun skb->max_len = len;
720*4882a593Smuzhiyun skb->data_len = 0;
721*4882a593Smuzhiyun } else {
722*4882a593Smuzhiyun RS_ERR("Allocate skb fails!!!");
723*4882a593Smuzhiyun skb = NULL;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun memset(skb->data, 0, len);
726*4882a593Smuzhiyun return skb;
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun /**
730*4882a593Smuzhiyun * Free the socket buffer
731*4882a593Smuzhiyun *
732*4882a593Smuzhiyun * @param skb socket buffer
733*4882a593Smuzhiyun */
skb_free(struct sk_buff * skb)734*4882a593Smuzhiyun static __inline void skb_free(struct sk_buff *skb)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun free(skb);
737*4882a593Smuzhiyun return;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun /**
741*4882a593Smuzhiyun * Increase the date length in sk_buffer by len,
742*4882a593Smuzhiyun * and return the increased header pointer
743*4882a593Smuzhiyun *
744*4882a593Smuzhiyun * @param skb socket buffer
745*4882a593Smuzhiyun * @param len length want to increase
746*4882a593Smuzhiyun * @return the pointer to increased header
747*4882a593Smuzhiyun */
skb_put(struct sk_buff * skb,RT_U32 len)748*4882a593Smuzhiyun static RT_U8 *skb_put(struct sk_buff *skb, RT_U32 len)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun RT_U32 old_len = skb->data_len;
751*4882a593Smuzhiyun if ((skb->data_len + len) > (skb->max_len)) {
752*4882a593Smuzhiyun RS_ERR("Buffer too small");
753*4882a593Smuzhiyun return NULL;
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun skb->data_len += len;
756*4882a593Smuzhiyun return (skb->data + old_len);
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /**
760*4882a593Smuzhiyun * decrease data length in sk_buffer by to len by cut the tail
761*4882a593Smuzhiyun *
762*4882a593Smuzhiyun * @warning len should be less than skb->len
763*4882a593Smuzhiyun *
764*4882a593Smuzhiyun * @param skb socket buffer
765*4882a593Smuzhiyun * @param len length want to be changed
766*4882a593Smuzhiyun */
skb_trim(struct sk_buff * skb,unsigned int len)767*4882a593Smuzhiyun static void skb_trim(struct sk_buff *skb, unsigned int len)
768*4882a593Smuzhiyun {
769*4882a593Smuzhiyun if (skb->data_len > len) {
770*4882a593Smuzhiyun skb->data_len = len;
771*4882a593Smuzhiyun } else {
772*4882a593Smuzhiyun RS_ERR("Error: skb->data_len(%d) < len(%d)", skb->data_len,
773*4882a593Smuzhiyun len);
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun /**
778*4882a593Smuzhiyun * Decrease the data length in sk_buffer by len,
779*4882a593Smuzhiyun * and move the content forward to the header.
780*4882a593Smuzhiyun * the data in header will be removed.
781*4882a593Smuzhiyun *
782*4882a593Smuzhiyun * @param skb socket buffer
783*4882a593Smuzhiyun * @param len length of data
784*4882a593Smuzhiyun * @return new data
785*4882a593Smuzhiyun */
skb_pull(struct sk_buff * skb,RT_U32 len)786*4882a593Smuzhiyun static RT_U8 *skb_pull(struct sk_buff *skb, RT_U32 len)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun skb->data_len -= len;
789*4882a593Smuzhiyun unsigned char *buf;
790*4882a593Smuzhiyun if (!(buf = malloc(skb->data_len))) {
791*4882a593Smuzhiyun RS_ERR("Unable to allocate file buffer");
792*4882a593Smuzhiyun exit(1);
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun memcpy(buf, skb->data + len, skb->data_len);
795*4882a593Smuzhiyun memcpy(skb->data, buf, skb->data_len);
796*4882a593Smuzhiyun free(buf);
797*4882a593Smuzhiyun return (skb->data);
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun /**
801*4882a593Smuzhiyun * Add "d" into crc scope, caculate the new crc value
802*4882a593Smuzhiyun *
803*4882a593Smuzhiyun * @param crc crc data
804*4882a593Smuzhiyun * @param d one byte data
805*4882a593Smuzhiyun */
h5_crc_update(RT_U16 * crc,RT_U8 d)806*4882a593Smuzhiyun static void h5_crc_update(RT_U16 * crc, RT_U8 d)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun RT_U16 reg = *crc;
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
811*4882a593Smuzhiyun reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun *crc = reg;
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun struct __una_u16 {
817*4882a593Smuzhiyun RT_U16 x;
818*4882a593Smuzhiyun };
__get_unaligned_cpu16(const void * p)819*4882a593Smuzhiyun static __inline RT_U16 __get_unaligned_cpu16(const void *p)
820*4882a593Smuzhiyun {
821*4882a593Smuzhiyun const struct __una_u16 *ptr = (const struct __una_u16 *)p;
822*4882a593Smuzhiyun return ptr->x;
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
get_unaligned_be16(const void * p)825*4882a593Smuzhiyun static __inline RT_U16 get_unaligned_be16(const void *p)
826*4882a593Smuzhiyun {
827*4882a593Smuzhiyun return __get_unaligned_cpu16((const RT_U8 *)p);
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun
get_unaligned_le16(RT_U8 * p)830*4882a593Smuzhiyun static __inline RT_U16 get_unaligned_le16(RT_U8 * p)
831*4882a593Smuzhiyun {
832*4882a593Smuzhiyun return (RT_U16) (*p) + ((RT_U16) (*(p + 1)) << 8);
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun
get_unaligned_le32(RT_U8 * p)835*4882a593Smuzhiyun static __inline RT_U32 get_unaligned_le32(RT_U8 * p)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun return (RT_U32) (*p) + ((RT_U32) (*(p + 1)) << 8) +
838*4882a593Smuzhiyun ((RT_U32) (*(p + 2)) << 16) + ((RT_U32) (*(p + 3)) << 24);
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun /**
842*4882a593Smuzhiyun * Get crc data.
843*4882a593Smuzhiyun *
844*4882a593Smuzhiyun * @param h5 realtek h5 struct
845*4882a593Smuzhiyun * @return crc data
846*4882a593Smuzhiyun */
h5_get_crc(rtk_hw_cfg_t * h5)847*4882a593Smuzhiyun static RT_U16 h5_get_crc(rtk_hw_cfg_t * h5)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun RT_U16 crc = 0;
850*4882a593Smuzhiyun RT_U8 *data = h5->rx_skb->data + h5->rx_skb->data_len - 2;
851*4882a593Smuzhiyun crc = data[1] + (data[0] << 8);
852*4882a593Smuzhiyun return crc;
853*4882a593Smuzhiyun // return get_unaligned_be16(&h5->rx_skb->data[h5->rx_skb->data_len - 2]);
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun /**
857*4882a593Smuzhiyun * Just add 0xc0 at the end of skb,
858*4882a593Smuzhiyun * we can also use this to add 0xc0 at start while there is no data in skb
859*4882a593Smuzhiyun *
860*4882a593Smuzhiyun * @param skb socket buffer
861*4882a593Smuzhiyun */
h5_slip_msgdelim(struct sk_buff * skb)862*4882a593Smuzhiyun static void h5_slip_msgdelim(struct sk_buff *skb)
863*4882a593Smuzhiyun {
864*4882a593Smuzhiyun const char pkt_delim = 0xc0;
865*4882a593Smuzhiyun memcpy(skb_put(skb, 1), &pkt_delim, 1);
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun /**
869*4882a593Smuzhiyun * Slip ecode one byte in h5 proto, as follows:
870*4882a593Smuzhiyun * 0xc0 -> 0xdb, 0xdc
871*4882a593Smuzhiyun * 0xdb -> 0xdb, 0xdd
872*4882a593Smuzhiyun * 0x11 -> 0xdb, 0xde
873*4882a593Smuzhiyun * 0x13 -> 0xdb, 0xdf
874*4882a593Smuzhiyun * others will not change
875*4882a593Smuzhiyun *
876*4882a593Smuzhiyun * @param skb socket buffer
877*4882a593Smuzhiyun * @c pure data in the one byte
878*4882a593Smuzhiyun */
h5_slip_one_byte(struct sk_buff * skb,RT_U8 c)879*4882a593Smuzhiyun static void h5_slip_one_byte(struct sk_buff *skb, RT_U8 c)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun const RT_S8 esc_c0[2] = { 0xdb, 0xdc };
882*4882a593Smuzhiyun const RT_S8 esc_db[2] = { 0xdb, 0xdd };
883*4882a593Smuzhiyun const RT_S8 esc_11[2] = { 0xdb, 0xde };
884*4882a593Smuzhiyun const RT_S8 esc_13[2] = { 0xdb, 0xdf };
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun switch (c) {
887*4882a593Smuzhiyun case 0xc0:
888*4882a593Smuzhiyun memcpy(skb_put(skb, 2), &esc_c0, 2);
889*4882a593Smuzhiyun break;
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun case 0xdb:
892*4882a593Smuzhiyun memcpy(skb_put(skb, 2), &esc_db, 2);
893*4882a593Smuzhiyun break;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun case 0x11:
896*4882a593Smuzhiyun memcpy(skb_put(skb, 2), &esc_11, 2);
897*4882a593Smuzhiyun break;
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun case 0x13:
900*4882a593Smuzhiyun memcpy(skb_put(skb, 2), &esc_13, 2);
901*4882a593Smuzhiyun break;
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun default:
904*4882a593Smuzhiyun memcpy(skb_put(skb, 1), &c, 1);
905*4882a593Smuzhiyun break;
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun /**
910*4882a593Smuzhiyun * Decode one byte in h5 proto, as follows:
911*4882a593Smuzhiyun * 0xdb, 0xdc -> 0xc0
912*4882a593Smuzhiyun * 0xdb, 0xdd -> 0xdb
913*4882a593Smuzhiyun * 0xdb, 0xde -> 0x11
914*4882a593Smuzhiyun * 0xdb, 0xdf -> 0x13
915*4882a593Smuzhiyun * others will not change
916*4882a593Smuzhiyun *
917*4882a593Smuzhiyun * @param h5 realtek h5 struct
918*4882a593Smuzhiyun * @byte pure data in the one byte
919*4882a593Smuzhiyun */
h5_unslip_one_byte(rtk_hw_cfg_t * h5,unsigned char byte)920*4882a593Smuzhiyun static void h5_unslip_one_byte(rtk_hw_cfg_t * h5, unsigned char byte)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun const RT_U8 c0 = 0xc0, db = 0xdb;
923*4882a593Smuzhiyun const RT_U8 oof1 = 0x11, oof2 = 0x13;
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun if (H5_ESCSTATE_NOESC == h5->rx_esc_state) {
926*4882a593Smuzhiyun if (0xdb == byte) {
927*4882a593Smuzhiyun h5->rx_esc_state = H5_ESCSTATE_ESC;
928*4882a593Smuzhiyun } else {
929*4882a593Smuzhiyun memcpy(skb_put(h5->rx_skb, 1), &byte, 1);
930*4882a593Smuzhiyun //Check Pkt Header's CRC enable bit
931*4882a593Smuzhiyun if ((h5->rx_skb->data[0] & 0x40) != 0
932*4882a593Smuzhiyun && h5->rx_state != H5_W4_CRC) {
933*4882a593Smuzhiyun h5_crc_update(&h5->message_crc, byte);
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun h5->rx_count--;
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun } else if (H5_ESCSTATE_ESC == h5->rx_esc_state) {
938*4882a593Smuzhiyun switch (byte) {
939*4882a593Smuzhiyun case 0xdc:
940*4882a593Smuzhiyun memcpy(skb_put(h5->rx_skb, 1), &c0, 1);
941*4882a593Smuzhiyun if ((h5->rx_skb->data[0] & 0x40) != 0
942*4882a593Smuzhiyun && h5->rx_state != H5_W4_CRC)
943*4882a593Smuzhiyun h5_crc_update(&h5->message_crc, 0xc0);
944*4882a593Smuzhiyun h5->rx_esc_state = H5_ESCSTATE_NOESC;
945*4882a593Smuzhiyun h5->rx_count--;
946*4882a593Smuzhiyun break;
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun case 0xdd:
949*4882a593Smuzhiyun memcpy(skb_put(h5->rx_skb, 1), &db, 1);
950*4882a593Smuzhiyun if ((h5->rx_skb->data[0] & 0x40) != 0
951*4882a593Smuzhiyun && h5->rx_state != H5_W4_CRC)
952*4882a593Smuzhiyun h5_crc_update(&h5->message_crc, 0xdb);
953*4882a593Smuzhiyun h5->rx_esc_state = H5_ESCSTATE_NOESC;
954*4882a593Smuzhiyun h5->rx_count--;
955*4882a593Smuzhiyun break;
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun case 0xde:
958*4882a593Smuzhiyun memcpy(skb_put(h5->rx_skb, 1), &oof1, 1);
959*4882a593Smuzhiyun if ((h5->rx_skb->data[0] & 0x40) != 0
960*4882a593Smuzhiyun && h5->rx_state != H5_W4_CRC)
961*4882a593Smuzhiyun h5_crc_update(&h5->message_crc, oof1);
962*4882a593Smuzhiyun h5->rx_esc_state = H5_ESCSTATE_NOESC;
963*4882a593Smuzhiyun h5->rx_count--;
964*4882a593Smuzhiyun break;
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun case 0xdf:
967*4882a593Smuzhiyun memcpy(skb_put(h5->rx_skb, 1), &oof2, 1);
968*4882a593Smuzhiyun if ((h5->rx_skb->data[0] & 0x40) != 0
969*4882a593Smuzhiyun && h5->rx_state != H5_W4_CRC)
970*4882a593Smuzhiyun h5_crc_update(&h5->message_crc, oof2);
971*4882a593Smuzhiyun h5->rx_esc_state = H5_ESCSTATE_NOESC;
972*4882a593Smuzhiyun h5->rx_count--;
973*4882a593Smuzhiyun break;
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun default:
976*4882a593Smuzhiyun RS_ERR("Error: Invalid byte %02x after esc byte", byte);
977*4882a593Smuzhiyun skb_free(h5->rx_skb);
978*4882a593Smuzhiyun h5->rx_skb = NULL;
979*4882a593Smuzhiyun h5->rx_state = H5_W4_PKT_DELIMITER;
980*4882a593Smuzhiyun h5->rx_count = 0;
981*4882a593Smuzhiyun break;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun /**
987*4882a593Smuzhiyun * Prepare h5 packet, packet format as follow:
988*4882a593Smuzhiyun * | LSB 4 octets | 0 ~4095| 2 MSB
989*4882a593Smuzhiyun * |packet header | payload | data integrity check |
990*4882a593Smuzhiyun *
991*4882a593Smuzhiyun * pakcket header fromat is show below:
992*4882a593Smuzhiyun * | LSB 3 bits | 3 bits | 1 bits | 1 bits |
993*4882a593Smuzhiyun * | 4 bits | 12 bits | 8 bits MSB
994*4882a593Smuzhiyun * |sequence number | acknowledgement number | data integrity check present | reliable packet |
995*4882a593Smuzhiyun * |packet type | payload length | header checksum
996*4882a593Smuzhiyun *
997*4882a593Smuzhiyun * @param h5 realtek h5 struct
998*4882a593Smuzhiyun * @param data pure data
999*4882a593Smuzhiyun * @param len the length of data
1000*4882a593Smuzhiyun * @param pkt_type packet type
1001*4882a593Smuzhiyun * @return socket buff after prepare in h5 proto
1002*4882a593Smuzhiyun */
h5_prepare_pkt(rtk_hw_cfg_t * h5,RT_U8 * data,RT_S32 len,RT_S32 pkt_type)1003*4882a593Smuzhiyun static struct sk_buff *h5_prepare_pkt(rtk_hw_cfg_t * h5, RT_U8 * data,
1004*4882a593Smuzhiyun RT_S32 len, RT_S32 pkt_type)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun struct sk_buff *nskb;
1007*4882a593Smuzhiyun RT_U8 hdr[4];
1008*4882a593Smuzhiyun RT_U16 H5_CRC_INIT(h5_txmsg_crc);
1009*4882a593Smuzhiyun int rel, i;
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun switch (pkt_type) {
1012*4882a593Smuzhiyun case HCI_ACLDATA_PKT:
1013*4882a593Smuzhiyun case HCI_COMMAND_PKT:
1014*4882a593Smuzhiyun case HCI_EVENT_PKT:
1015*4882a593Smuzhiyun rel = 1; // reliable
1016*4882a593Smuzhiyun break;
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun case H5_ACK_PKT:
1019*4882a593Smuzhiyun case H5_VDRSPEC_PKT:
1020*4882a593Smuzhiyun case H5_LINK_CTL_PKT:
1021*4882a593Smuzhiyun rel = 0; // unreliable
1022*4882a593Smuzhiyun break;
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun default:
1025*4882a593Smuzhiyun RS_ERR("Unknown packet type");
1026*4882a593Smuzhiyun return NULL;
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun // Max len of packet: (original len +4(h5 hdr) +2(crc))*2
1030*4882a593Smuzhiyun // (because bytes 0xc0 and 0xdb are escaped, worst case is
1031*4882a593Smuzhiyun // when the packet is all made of 0xc0 and 0xdb :) )
1032*4882a593Smuzhiyun // + 2 (0xc0 delimiters at start and end).
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun nskb = skb_alloc((len + 6) * 2 + 2);
1035*4882a593Smuzhiyun if (!nskb)
1036*4882a593Smuzhiyun return NULL;
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun //Add SLIP start byte: 0xc0
1039*4882a593Smuzhiyun h5_slip_msgdelim(nskb);
1040*4882a593Smuzhiyun // set AckNumber in SlipHeader
1041*4882a593Smuzhiyun hdr[0] = h5->rxseq_txack << 3;
1042*4882a593Smuzhiyun h5->is_txack_req = 0;
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun //RS_DBG("We request packet no(%u) to card", h5->rxseq_txack);
1045*4882a593Smuzhiyun //RS_DBG("Sending packet with seqno %u and wait %u", h5->msgq_txseq, h5->rxseq_txack);
1046*4882a593Smuzhiyun if (rel) {
1047*4882a593Smuzhiyun // set reliable pkt bit and SeqNumber
1048*4882a593Smuzhiyun hdr[0] |= 0x80 + h5->msgq_txseq;
1049*4882a593Smuzhiyun //RS_DBG("Sending packet with seqno(%u)", h5->msgq_txseq);
1050*4882a593Smuzhiyun ++(h5->msgq_txseq);
1051*4882a593Smuzhiyun h5->msgq_txseq = (h5->msgq_txseq) & 0x07;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun // set DicPresent bit
1054*4882a593Smuzhiyun if (h5->use_crc)
1055*4882a593Smuzhiyun hdr[0] |= 0x40;
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun // set packet type and payload length
1058*4882a593Smuzhiyun hdr[1] = ((len << 4) & 0xff) | pkt_type;
1059*4882a593Smuzhiyun hdr[2] = (RT_U8) (len >> 4);
1060*4882a593Smuzhiyun // set checksum
1061*4882a593Smuzhiyun hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]);
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun // Put h5 header */
1064*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
1065*4882a593Smuzhiyun h5_slip_one_byte(nskb, hdr[i]);
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun if (h5->use_crc)
1068*4882a593Smuzhiyun h5_crc_update(&h5_txmsg_crc, hdr[i]);
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun // Put payload */
1072*4882a593Smuzhiyun for (i = 0; i < len; i++) {
1073*4882a593Smuzhiyun h5_slip_one_byte(nskb, data[i]);
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun if (h5->use_crc)
1076*4882a593Smuzhiyun h5_crc_update(&h5_txmsg_crc, data[i]);
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun // Put CRC */
1080*4882a593Smuzhiyun if (h5->use_crc) {
1081*4882a593Smuzhiyun h5_txmsg_crc = bit_rev16(h5_txmsg_crc);
1082*4882a593Smuzhiyun h5_slip_one_byte(nskb, (RT_U8) ((h5_txmsg_crc >> 8) & 0x00ff));
1083*4882a593Smuzhiyun h5_slip_one_byte(nskb, (RT_U8) (h5_txmsg_crc & 0x00ff));
1084*4882a593Smuzhiyun }
1085*4882a593Smuzhiyun // Add SLIP end byte: 0xc0
1086*4882a593Smuzhiyun h5_slip_msgdelim(nskb);
1087*4882a593Smuzhiyun return nskb;
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun /**
1091*4882a593Smuzhiyun * Removed controller acked packet from Host's unacked lists
1092*4882a593Smuzhiyun *
1093*4882a593Smuzhiyun * @param h5 realtek h5 struct
1094*4882a593Smuzhiyun */
h5_remove_acked_pkt(rtk_hw_cfg_t * h5)1095*4882a593Smuzhiyun static void h5_remove_acked_pkt(rtk_hw_cfg_t * h5)
1096*4882a593Smuzhiyun {
1097*4882a593Smuzhiyun int pkts_to_be_removed = 0;
1098*4882a593Smuzhiyun int seqno = 0;
1099*4882a593Smuzhiyun int i = 0;
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun seqno = h5->msgq_txseq;
1102*4882a593Smuzhiyun //pkts_to_be_removed = GetListLength(h5->unacked);
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun while (pkts_to_be_removed) {
1105*4882a593Smuzhiyun if (h5->rxack == seqno)
1106*4882a593Smuzhiyun break;
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun pkts_to_be_removed--;
1109*4882a593Smuzhiyun seqno = (seqno - 1) & 0x07;
1110*4882a593Smuzhiyun }
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun if (h5->rxack != seqno) {
1113*4882a593Smuzhiyun RS_DBG("Peer acked invalid packet");
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun //skb_queue_walk_safe(&h5->unack, skb, tmp) // remove ack'ed packet from h5->unack queue
1116*4882a593Smuzhiyun for (i = 0; i < 5; ++i) {
1117*4882a593Smuzhiyun if (i >= pkts_to_be_removed)
1118*4882a593Smuzhiyun break;
1119*4882a593Smuzhiyun i++;
1120*4882a593Smuzhiyun //__skb_unlink(skb, &h5->unack);
1121*4882a593Smuzhiyun //skb_free(skb);
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun // if (skb_queue_empty(&h5->unack))
1125*4882a593Smuzhiyun // del_timer(&h5->th5);
1126*4882a593Smuzhiyun // spin_unlock_irqrestore(&h5->unack.lock, flags);
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun if (i != pkts_to_be_removed)
1129*4882a593Smuzhiyun RS_DBG("Removed only (%u) out of (%u) pkts", i,
1130*4882a593Smuzhiyun pkts_to_be_removed);
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun /**
1134*4882a593Smuzhiyun * Realtek send pure ack, send a packet only with an ack
1135*4882a593Smuzhiyun *
1136*4882a593Smuzhiyun * @param fd uart file descriptor
1137*4882a593Smuzhiyun *
1138*4882a593Smuzhiyun */
rtk_send_pure_ack_down(int fd)1139*4882a593Smuzhiyun static void rtk_send_pure_ack_down(int fd)
1140*4882a593Smuzhiyun {
1141*4882a593Smuzhiyun struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, NULL, 0, H5_ACK_PKT);
1142*4882a593Smuzhiyun write(fd, nskb->data, nskb->data_len);
1143*4882a593Smuzhiyun skb_free(nskb);
1144*4882a593Smuzhiyun return;
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun
1147*4882a593Smuzhiyun /**
1148*4882a593Smuzhiyun * Parse hci event command complete, pull the cmd complete event header
1149*4882a593Smuzhiyun *
1150*4882a593Smuzhiyun * @param skb socket buffer
1151*4882a593Smuzhiyun *
1152*4882a593Smuzhiyun */
hci_event_cmd_complete(struct sk_buff * skb)1153*4882a593Smuzhiyun static void hci_event_cmd_complete(struct sk_buff *skb)
1154*4882a593Smuzhiyun {
1155*4882a593Smuzhiyun struct hci_event_hdr *hdr = (struct hci_event_hdr *)skb->data;
1156*4882a593Smuzhiyun struct hci_ev_cmd_complete *ev = NULL;
1157*4882a593Smuzhiyun RT_U16 opcode = 0;
1158*4882a593Smuzhiyun RT_U8 status = 0;
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun //pull hdr
1161*4882a593Smuzhiyun skb_pull(skb, HCI_EVENT_HDR_SIZE);
1162*4882a593Smuzhiyun ev = (struct hci_ev_cmd_complete *)skb->data;
1163*4882a593Smuzhiyun opcode = le16_to_cpu(ev->opcode);
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun RS_DBG("receive hci command complete event with command:%x\n", opcode);
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun //pull command complete event header
1168*4882a593Smuzhiyun skb_pull(skb, sizeof(struct hci_ev_cmd_complete));
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun switch (opcode) {
1171*4882a593Smuzhiyun case HCI_VENDOR_CHANGE_BDRATE:
1172*4882a593Smuzhiyun status = skb->data[0];
1173*4882a593Smuzhiyun RS_DBG("Change BD Rate with status:%x", status);
1174*4882a593Smuzhiyun skb_free(rtk_hw_cfg.host_last_cmd);
1175*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = NULL;
1176*4882a593Smuzhiyun rtk_hw_cfg.link_estab_state = H5_PATCH;
1177*4882a593Smuzhiyun break;
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun case HCI_CMD_READ_BD_ADDR:
1180*4882a593Smuzhiyun status = skb->data[0];
1181*4882a593Smuzhiyun RS_DBG("Read BD Address with Status:%x", status);
1182*4882a593Smuzhiyun if (!status) {
1183*4882a593Smuzhiyun RS_DBG("BD Address: %8x%8x", *(int *)&skb->data[1],
1184*4882a593Smuzhiyun *(int *)&skb->data[5]);
1185*4882a593Smuzhiyun }
1186*4882a593Smuzhiyun break;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun case HCI_CMD_READ_LOCAL_VERISION:
1189*4882a593Smuzhiyun rtk_hw_cfg.hci_version_cmd_state = event_received;
1190*4882a593Smuzhiyun status = skb->data[0];
1191*4882a593Smuzhiyun RS_DBG("Read Local Version Information with Status:%x", status);
1192*4882a593Smuzhiyun if (0 == status) {
1193*4882a593Smuzhiyun rtk_hw_cfg.hci_ver = skb->data[1];
1194*4882a593Smuzhiyun rtk_hw_cfg.hci_rev = (skb->data[2] | skb->data[3] << 8);
1195*4882a593Smuzhiyun rtk_hw_cfg.lmp_subver =
1196*4882a593Smuzhiyun (skb->data[7] | (skb->data[8] << 8));
1197*4882a593Smuzhiyun RS_DBG("HCI Version 0x%02x", rtk_hw_cfg.hci_ver);
1198*4882a593Smuzhiyun RS_DBG("HCI Revision 0x%04x", rtk_hw_cfg.hci_rev);
1199*4882a593Smuzhiyun RS_DBG("LMP Subversion 0x%04x", rtk_hw_cfg.lmp_subver);
1200*4882a593Smuzhiyun } else {
1201*4882a593Smuzhiyun RS_ERR("Read Local Version Info status error!");
1202*4882a593Smuzhiyun //Need to do more
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun skb_free(rtk_hw_cfg.host_last_cmd);
1205*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = NULL;
1206*4882a593Smuzhiyun break;
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun case HCI_VENDOR_READ_RTK_ROM_VERISION:
1209*4882a593Smuzhiyun rtk_hw_cfg.rom_version_cmd_state = event_received;
1210*4882a593Smuzhiyun status = skb->data[0];
1211*4882a593Smuzhiyun RS_DBG("Read RTK rom version with Status:%x", status);
1212*4882a593Smuzhiyun if (0 == status)
1213*4882a593Smuzhiyun rtk_hw_cfg.eversion = skb->data[1];
1214*4882a593Smuzhiyun else if (1 == status)
1215*4882a593Smuzhiyun rtk_hw_cfg.eversion = 0;
1216*4882a593Smuzhiyun else {
1217*4882a593Smuzhiyun RS_ERR("READ_RTK_ROM_VERISION return status error!");
1218*4882a593Smuzhiyun //Need to do more
1219*4882a593Smuzhiyun }
1220*4882a593Smuzhiyun
1221*4882a593Smuzhiyun skb_free(rtk_hw_cfg.host_last_cmd);
1222*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = NULL;
1223*4882a593Smuzhiyun break;
1224*4882a593Smuzhiyun case HCI_VENDOR_READ_CHIP_TYPE:
1225*4882a593Smuzhiyun rtk_hw_cfg.chip_type_cmd_state = event_received;
1226*4882a593Smuzhiyun status = skb->data[0];
1227*4882a593Smuzhiyun RS_DBG("Read RTK chip type with Status:%x", status);
1228*4882a593Smuzhiyun if (0 == status)
1229*4882a593Smuzhiyun rtk_hw_cfg.chip_type= (skb->data[1] & 0x0f);
1230*4882a593Smuzhiyun else
1231*4882a593Smuzhiyun RS_ERR("READ_RTK_CHIP_TYPE return status error!");
1232*4882a593Smuzhiyun skb_free(rtk_hw_cfg.host_last_cmd);
1233*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = NULL;
1234*4882a593Smuzhiyun break;
1235*4882a593Smuzhiyun default:
1236*4882a593Smuzhiyun return;
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun rtk_hw_cfg.num_of_cmd_sent++;
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun /**
1242*4882a593Smuzhiyun * Check if it's a hci frame, if it is, complete it with response or parse the cmd complete event
1243*4882a593Smuzhiyun *
1244*4882a593Smuzhiyun * @param skb socket buffer
1245*4882a593Smuzhiyun *
1246*4882a593Smuzhiyun */
hci_recv_frame(struct sk_buff * skb)1247*4882a593Smuzhiyun static void hci_recv_frame(struct sk_buff *skb)
1248*4882a593Smuzhiyun {
1249*4882a593Smuzhiyun int len;
1250*4882a593Smuzhiyun unsigned char h5sync[2] = { 0x01, 0x7E }, h5syncresp[2] = {
1251*4882a593Smuzhiyun 0x02, 0x7D}, h5_sync_resp_pkt[0x8] = {
1252*4882a593Smuzhiyun 0xc0, 0x00, 0x2F, 0x00, 0xD0, 0x02, 0x7D, 0xc0},
1253*4882a593Smuzhiyun h5_conf_resp_pkt_to_Ctrl[0x8] = {
1254*4882a593Smuzhiyun 0xc0, 0x00, 0x2F, 0x00, 0xD0, 0x04, 0x7B, 0xc0}, h5conf[3] = {
1255*4882a593Smuzhiyun 0x03, 0xFC, 0x10}, h5confresp[3] = {
1256*4882a593Smuzhiyun 0x04, 0x7B, 0x10}, cmd_complete_evt_code = 0xe;
1257*4882a593Smuzhiyun
1258*4882a593Smuzhiyun if (rtk_hw_cfg.link_estab_state == H5_SYNC) {
1259*4882a593Smuzhiyun if (!memcmp(skb->data, h5sync, 2)) {
1260*4882a593Smuzhiyun RS_DBG("Get SYNC Pkt\n");
1261*4882a593Smuzhiyun len =
1262*4882a593Smuzhiyun write(rtk_hw_cfg.serial_fd, &h5_sync_resp_pkt, 0x8);
1263*4882a593Smuzhiyun } else if (!memcmp(skb->data, h5syncresp, 2)) {
1264*4882a593Smuzhiyun RS_DBG("Get SYNC Resp Pkt\n");
1265*4882a593Smuzhiyun rtk_hw_cfg.link_estab_state = H5_CONFIG;
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun skb_free(skb);
1268*4882a593Smuzhiyun } else if (rtk_hw_cfg.link_estab_state == H5_CONFIG) {
1269*4882a593Smuzhiyun if (!memcmp(skb->data, h5sync, 0x2)) {
1270*4882a593Smuzhiyun len =
1271*4882a593Smuzhiyun write(rtk_hw_cfg.serial_fd, &h5_sync_resp_pkt, 0x8);
1272*4882a593Smuzhiyun RS_DBG("Get SYNC pkt-active mode\n");
1273*4882a593Smuzhiyun } else if (!memcmp(skb->data, h5conf, 0x2)) {
1274*4882a593Smuzhiyun len =
1275*4882a593Smuzhiyun write(rtk_hw_cfg.serial_fd,
1276*4882a593Smuzhiyun &h5_conf_resp_pkt_to_Ctrl, 0x8);
1277*4882a593Smuzhiyun RS_DBG("Get CONFG pkt-active mode\n");
1278*4882a593Smuzhiyun } else if (!memcmp(skb->data, h5confresp, 0x2)) {
1279*4882a593Smuzhiyun RS_DBG("Get CONFG resp pkt-active mode\n");
1280*4882a593Smuzhiyun rtk_hw_cfg.link_estab_state = H5_INIT;
1281*4882a593Smuzhiyun } else {
1282*4882a593Smuzhiyun RS_DBG("H5_CONFIG receive event\n");
1283*4882a593Smuzhiyun rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd);
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun skb_free(skb);
1286*4882a593Smuzhiyun } else if (rtk_hw_cfg.link_estab_state == H5_INIT) {
1287*4882a593Smuzhiyun if (skb->data[0] == cmd_complete_evt_code) {
1288*4882a593Smuzhiyun hci_event_cmd_complete(skb);
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd);
1292*4882a593Smuzhiyun usleep(10000);
1293*4882a593Smuzhiyun rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd);
1294*4882a593Smuzhiyun usleep(10000);
1295*4882a593Smuzhiyun rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd);
1296*4882a593Smuzhiyun skb_free(skb);
1297*4882a593Smuzhiyun } else if (rtk_hw_cfg.link_estab_state == H5_PATCH) {
1298*4882a593Smuzhiyun if (skb->data[0] != 0x0e) {
1299*4882a593Smuzhiyun RS_DBG("Received event 0x%x\n", skb->data[0]);
1300*4882a593Smuzhiyun skb_free(skb);
1301*4882a593Smuzhiyun rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd);
1302*4882a593Smuzhiyun return;
1303*4882a593Smuzhiyun }
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun rtk_hw_cfg.rx_index = skb->data[6];
1306*4882a593Smuzhiyun
1307*4882a593Smuzhiyun RS_DBG("rtk_hw_cfg.rx_index %d\n", rtk_hw_cfg.rx_index);
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun /* Download fw/config done */
1310*4882a593Smuzhiyun if (rtk_hw_cfg.rx_index & 0x80) {
1311*4882a593Smuzhiyun rtk_hw_cfg.rx_index &= ~0x80;
1312*4882a593Smuzhiyun rtk_hw_cfg.link_estab_state = H5_ACTIVE;
1313*4882a593Smuzhiyun }
1314*4882a593Smuzhiyun
1315*4882a593Smuzhiyun skb_free(skb);
1316*4882a593Smuzhiyun } else {
1317*4882a593Smuzhiyun RS_ERR("receive packets in active state");
1318*4882a593Smuzhiyun skb_free(skb);
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun }
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun /**
1323*4882a593Smuzhiyun * after rx data is parsed, and we got a rx frame saved in h5->rx_skb,
1324*4882a593Smuzhiyun * this routinue is called.
1325*4882a593Smuzhiyun * things todo in this function:
1326*4882a593Smuzhiyun * 1. check if it's a hci frame, if it is, complete it with response or ack
1327*4882a593Smuzhiyun * 2. see the ack number, free acked frame in queue
1328*4882a593Smuzhiyun * 3. reset h5->rx_state, set rx_skb to null.
1329*4882a593Smuzhiyun *
1330*4882a593Smuzhiyun * @param h5 realtek h5 struct
1331*4882a593Smuzhiyun *
1332*4882a593Smuzhiyun */
h5_complete_rx_pkt(rtk_hw_cfg_t * h5)1333*4882a593Smuzhiyun static void h5_complete_rx_pkt(rtk_hw_cfg_t * h5)
1334*4882a593Smuzhiyun {
1335*4882a593Smuzhiyun int pass_up = 1;
1336*4882a593Smuzhiyun uint8_t *h5_hdr = NULL;
1337*4882a593Smuzhiyun
1338*4882a593Smuzhiyun h5_hdr = (uint8_t *) (h5->rx_skb->data);
1339*4882a593Smuzhiyun if (H5_HDR_RELIABLE(h5_hdr)) {
1340*4882a593Smuzhiyun RS_DBG("Received reliable seqno %u from card", h5->rxseq_txack);
1341*4882a593Smuzhiyun h5->rxseq_txack = H5_HDR_SEQ(h5_hdr) + 1;
1342*4882a593Smuzhiyun h5->rxseq_txack %= 8;
1343*4882a593Smuzhiyun h5->is_txack_req = 1;
1344*4882a593Smuzhiyun }
1345*4882a593Smuzhiyun
1346*4882a593Smuzhiyun h5->rxack = H5_HDR_ACK(h5_hdr);
1347*4882a593Smuzhiyun
1348*4882a593Smuzhiyun switch (H5_HDR_PKT_TYPE(h5_hdr)) {
1349*4882a593Smuzhiyun case HCI_ACLDATA_PKT:
1350*4882a593Smuzhiyun case HCI_EVENT_PKT:
1351*4882a593Smuzhiyun case HCI_SCODATA_PKT:
1352*4882a593Smuzhiyun case HCI_COMMAND_PKT:
1353*4882a593Smuzhiyun case H5_LINK_CTL_PKT:
1354*4882a593Smuzhiyun pass_up = 1;
1355*4882a593Smuzhiyun break;
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun default:
1358*4882a593Smuzhiyun pass_up = 0;
1359*4882a593Smuzhiyun break;
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun
1362*4882a593Smuzhiyun h5_remove_acked_pkt(h5);
1363*4882a593Smuzhiyun
1364*4882a593Smuzhiyun if (pass_up) {
1365*4882a593Smuzhiyun skb_pull(h5->rx_skb, H5_HDR_SIZE);
1366*4882a593Smuzhiyun hci_recv_frame(h5->rx_skb);
1367*4882a593Smuzhiyun } else {
1368*4882a593Smuzhiyun skb_free(h5->rx_skb);
1369*4882a593Smuzhiyun }
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun h5->rx_state = H5_W4_PKT_DELIMITER;
1372*4882a593Smuzhiyun h5->rx_skb = NULL;
1373*4882a593Smuzhiyun }
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun /**
1376*4882a593Smuzhiyun * Parse the receive data in h5 proto.
1377*4882a593Smuzhiyun *
1378*4882a593Smuzhiyun * @param h5 realtek h5 struct
1379*4882a593Smuzhiyun * @param data point to data received before parse
1380*4882a593Smuzhiyun * @param count num of data
1381*4882a593Smuzhiyun * @return reserved count
1382*4882a593Smuzhiyun */
h5_recv(rtk_hw_cfg_t * h5,void * data,int count)1383*4882a593Smuzhiyun static int h5_recv(rtk_hw_cfg_t * h5, void *data, int count)
1384*4882a593Smuzhiyun {
1385*4882a593Smuzhiyun unsigned char *ptr;
1386*4882a593Smuzhiyun //RS_DBG("count %d rx_state %d rx_count %ld", count, h5->rx_state, h5->rx_count);
1387*4882a593Smuzhiyun ptr = (unsigned char *)data;
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun while (count) {
1390*4882a593Smuzhiyun if (h5->rx_count) {
1391*4882a593Smuzhiyun if (*ptr == 0xc0) {
1392*4882a593Smuzhiyun RS_ERR("short h5 packet");
1393*4882a593Smuzhiyun skb_free(h5->rx_skb);
1394*4882a593Smuzhiyun h5->rx_state = H5_W4_PKT_START;
1395*4882a593Smuzhiyun h5->rx_count = 0;
1396*4882a593Smuzhiyun } else
1397*4882a593Smuzhiyun h5_unslip_one_byte(h5, *ptr);
1398*4882a593Smuzhiyun
1399*4882a593Smuzhiyun ptr++;
1400*4882a593Smuzhiyun count--;
1401*4882a593Smuzhiyun continue;
1402*4882a593Smuzhiyun }
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun switch (h5->rx_state) {
1405*4882a593Smuzhiyun case H5_W4_HDR:
1406*4882a593Smuzhiyun /* check header checksum. see Core Spec V4 "3-wire uart" page 67 */
1407*4882a593Smuzhiyun if ((0xff & (RT_U8) ~
1408*4882a593Smuzhiyun (h5->rx_skb->data[0] + h5->rx_skb->data[1] +
1409*4882a593Smuzhiyun h5->rx_skb->data[2])) != h5->rx_skb->data[3]) {
1410*4882a593Smuzhiyun RS_ERR("h5 hdr checksum error!!!");
1411*4882a593Smuzhiyun skb_free(h5->rx_skb);
1412*4882a593Smuzhiyun h5->rx_state = H5_W4_PKT_DELIMITER;
1413*4882a593Smuzhiyun h5->rx_count = 0;
1414*4882a593Smuzhiyun continue;
1415*4882a593Smuzhiyun }
1416*4882a593Smuzhiyun
1417*4882a593Smuzhiyun /* reliable pkt & h5->hdr->SeqNumber != h5->Rxseq_txack */
1418*4882a593Smuzhiyun if (h5->rx_skb->data[0] & 0x80
1419*4882a593Smuzhiyun && (h5->rx_skb->data[0] & 0x07) !=
1420*4882a593Smuzhiyun h5->rxseq_txack) {
1421*4882a593Smuzhiyun RS_ERR
1422*4882a593Smuzhiyun ("Out-of-order packet arrived, got(%u)expected(%u)",
1423*4882a593Smuzhiyun h5->rx_skb->data[0] & 0x07,
1424*4882a593Smuzhiyun h5->rxseq_txack);
1425*4882a593Smuzhiyun h5->is_txack_req = 1;
1426*4882a593Smuzhiyun
1427*4882a593Smuzhiyun skb_free(h5->rx_skb);
1428*4882a593Smuzhiyun h5->rx_state = H5_W4_PKT_DELIMITER;
1429*4882a593Smuzhiyun h5->rx_count = 0;
1430*4882a593Smuzhiyun
1431*4882a593Smuzhiyun /* depend on weather remote will reset ack numb or not!!!!!!special */
1432*4882a593Smuzhiyun if (rtk_hw_cfg.tx_index == rtk_hw_cfg.total_num) {
1433*4882a593Smuzhiyun rtk_hw_cfg.rxseq_txack =
1434*4882a593Smuzhiyun h5->rx_skb->data[0] & 0x07;
1435*4882a593Smuzhiyun }
1436*4882a593Smuzhiyun continue;
1437*4882a593Smuzhiyun }
1438*4882a593Smuzhiyun h5->rx_state = H5_W4_DATA;
1439*4882a593Smuzhiyun h5->rx_count =
1440*4882a593Smuzhiyun (h5->rx_skb->data[1] >> 4) +
1441*4882a593Smuzhiyun (h5->rx_skb->data[2] << 4);
1442*4882a593Smuzhiyun continue;
1443*4882a593Smuzhiyun
1444*4882a593Smuzhiyun case H5_W4_DATA:
1445*4882a593Smuzhiyun /* pkt with crc */
1446*4882a593Smuzhiyun if (h5->rx_skb->data[0] & 0x40) {
1447*4882a593Smuzhiyun h5->rx_state = H5_W4_CRC;
1448*4882a593Smuzhiyun h5->rx_count = 2;
1449*4882a593Smuzhiyun } else {
1450*4882a593Smuzhiyun h5_complete_rx_pkt(h5);
1451*4882a593Smuzhiyun //RS_DBG(DF_SLIP,("--------> H5_W4_DATA ACK\n"));
1452*4882a593Smuzhiyun }
1453*4882a593Smuzhiyun continue;
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun case H5_W4_CRC:
1456*4882a593Smuzhiyun if (bit_rev16(h5->message_crc) != h5_get_crc(h5)) {
1457*4882a593Smuzhiyun RS_ERR
1458*4882a593Smuzhiyun ("Checksum failed, computed(%04x)received(%04x)",
1459*4882a593Smuzhiyun bit_rev16(h5->message_crc),
1460*4882a593Smuzhiyun h5_get_crc(h5));
1461*4882a593Smuzhiyun skb_free(h5->rx_skb);
1462*4882a593Smuzhiyun h5->rx_state = H5_W4_PKT_DELIMITER;
1463*4882a593Smuzhiyun h5->rx_count = 0;
1464*4882a593Smuzhiyun continue;
1465*4882a593Smuzhiyun }
1466*4882a593Smuzhiyun skb_trim(h5->rx_skb, h5->rx_skb->data_len - 2);
1467*4882a593Smuzhiyun h5_complete_rx_pkt(h5);
1468*4882a593Smuzhiyun continue;
1469*4882a593Smuzhiyun
1470*4882a593Smuzhiyun case H5_W4_PKT_DELIMITER:
1471*4882a593Smuzhiyun switch (*ptr) {
1472*4882a593Smuzhiyun case 0xc0:
1473*4882a593Smuzhiyun h5->rx_state = H5_W4_PKT_START;
1474*4882a593Smuzhiyun break;
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun default:
1477*4882a593Smuzhiyun break;
1478*4882a593Smuzhiyun }
1479*4882a593Smuzhiyun ptr++;
1480*4882a593Smuzhiyun count--;
1481*4882a593Smuzhiyun break;
1482*4882a593Smuzhiyun
1483*4882a593Smuzhiyun case H5_W4_PKT_START:
1484*4882a593Smuzhiyun switch (*ptr) {
1485*4882a593Smuzhiyun case 0xc0:
1486*4882a593Smuzhiyun ptr++;
1487*4882a593Smuzhiyun count--;
1488*4882a593Smuzhiyun break;
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun default:
1491*4882a593Smuzhiyun h5->rx_state = H5_W4_HDR;
1492*4882a593Smuzhiyun h5->rx_count = 4;
1493*4882a593Smuzhiyun h5->rx_esc_state = H5_ESCSTATE_NOESC;
1494*4882a593Smuzhiyun H5_CRC_INIT(h5->message_crc);
1495*4882a593Smuzhiyun
1496*4882a593Smuzhiyun // Do not increment ptr or decrement count
1497*4882a593Smuzhiyun // Allocate packet. Max len of a H5 pkt=
1498*4882a593Smuzhiyun // 0xFFF (payload) +4 (header) +2 (crc)
1499*4882a593Smuzhiyun h5->rx_skb = skb_alloc(0x1005);
1500*4882a593Smuzhiyun if (!h5->rx_skb) {
1501*4882a593Smuzhiyun h5->rx_state = H5_W4_PKT_DELIMITER;
1502*4882a593Smuzhiyun h5->rx_count = 0;
1503*4882a593Smuzhiyun return 0;
1504*4882a593Smuzhiyun }
1505*4882a593Smuzhiyun break;
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun break;
1508*4882a593Smuzhiyun
1509*4882a593Smuzhiyun default:
1510*4882a593Smuzhiyun break;
1511*4882a593Smuzhiyun }
1512*4882a593Smuzhiyun }
1513*4882a593Smuzhiyun return count;
1514*4882a593Smuzhiyun }
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun /**
1517*4882a593Smuzhiyun * Read data to buf from uart.
1518*4882a593Smuzhiyun *
1519*4882a593Smuzhiyun * @param fd uart file descriptor
1520*4882a593Smuzhiyun * @param buf point to the addr where read data stored
1521*4882a593Smuzhiyun * @param count num of data want to read
1522*4882a593Smuzhiyun * @return num of data successfully read
1523*4882a593Smuzhiyun */
read_check_rtk(int fd,void * buf,int count)1524*4882a593Smuzhiyun static int read_check_rtk(int fd, void *buf, int count)
1525*4882a593Smuzhiyun {
1526*4882a593Smuzhiyun int res;
1527*4882a593Smuzhiyun do {
1528*4882a593Smuzhiyun res = read(fd, buf, count);
1529*4882a593Smuzhiyun if (res != -1) {
1530*4882a593Smuzhiyun buf = (RT_U8 *) buf + res;
1531*4882a593Smuzhiyun count -= res;
1532*4882a593Smuzhiyun return res;
1533*4882a593Smuzhiyun }
1534*4882a593Smuzhiyun } while (count && (errno == 0 || errno == EINTR));
1535*4882a593Smuzhiyun return res;
1536*4882a593Smuzhiyun }
1537*4882a593Smuzhiyun
1538*4882a593Smuzhiyun /**
1539*4882a593Smuzhiyun * Retry to sync when timeout in h5 proto, max retry times is 10.
1540*4882a593Smuzhiyun *
1541*4882a593Smuzhiyun * @warning Each time to retry, the time for timeout will be set as 1s.
1542*4882a593Smuzhiyun *
1543*4882a593Smuzhiyun * @param sig signaction for timeout
1544*4882a593Smuzhiyun *
1545*4882a593Smuzhiyun */
h5_tsync_sig_alarm(int sig)1546*4882a593Smuzhiyun static void h5_tsync_sig_alarm(int sig)
1547*4882a593Smuzhiyun {
1548*4882a593Smuzhiyun unsigned char h5sync[2] = { 0x01, 0x7E };
1549*4882a593Smuzhiyun static int retries = 0;
1550*4882a593Smuzhiyun struct itimerval value;
1551*4882a593Smuzhiyun
1552*4882a593Smuzhiyun if (retries < rtk_hw_cfg.h5_max_retries) {
1553*4882a593Smuzhiyun retries++;
1554*4882a593Smuzhiyun struct sk_buff *nskb =
1555*4882a593Smuzhiyun h5_prepare_pkt(&rtk_hw_cfg, h5sync, sizeof(h5sync),
1556*4882a593Smuzhiyun H5_LINK_CTL_PKT);
1557*4882a593Smuzhiyun int len =
1558*4882a593Smuzhiyun write(rtk_hw_cfg.serial_fd, nskb->data, nskb->data_len);
1559*4882a593Smuzhiyun RS_DBG("3-wire sync pattern resend : %d, len: %d\n", retries,
1560*4882a593Smuzhiyun len);
1561*4882a593Smuzhiyun
1562*4882a593Smuzhiyun skb_free(nskb);
1563*4882a593Smuzhiyun //gordon add 2013-6-7 retry per 250ms
1564*4882a593Smuzhiyun value.it_value.tv_sec = 0;
1565*4882a593Smuzhiyun value.it_value.tv_usec = 250000;
1566*4882a593Smuzhiyun value.it_interval.tv_sec = 0;
1567*4882a593Smuzhiyun value.it_interval.tv_usec = 250000;
1568*4882a593Smuzhiyun setitimer(ITIMER_REAL, &value, NULL);
1569*4882a593Smuzhiyun //gordon end
1570*4882a593Smuzhiyun
1571*4882a593Smuzhiyun return;
1572*4882a593Smuzhiyun }
1573*4882a593Smuzhiyun
1574*4882a593Smuzhiyun tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH);
1575*4882a593Smuzhiyun RS_ERR("H5 sync timed out\n");
1576*4882a593Smuzhiyun exit(1);
1577*4882a593Smuzhiyun }
1578*4882a593Smuzhiyun
1579*4882a593Smuzhiyun /**
1580*4882a593Smuzhiyun * Retry to config when timeout in h5 proto, max retry times is 10.
1581*4882a593Smuzhiyun *
1582*4882a593Smuzhiyun * @warning Each time to retry, the time for timeout will be set as 1s.
1583*4882a593Smuzhiyun *
1584*4882a593Smuzhiyun * @param sig signaction for timeout
1585*4882a593Smuzhiyun *
1586*4882a593Smuzhiyun */
h5_tconf_sig_alarm(int sig)1587*4882a593Smuzhiyun static void h5_tconf_sig_alarm(int sig)
1588*4882a593Smuzhiyun {
1589*4882a593Smuzhiyun unsigned char h5conf[3] = { 0x03, 0xFC, 0x14 };
1590*4882a593Smuzhiyun static int retries = 0;
1591*4882a593Smuzhiyun struct itimerval value;
1592*4882a593Smuzhiyun
1593*4882a593Smuzhiyun if (retries < rtk_hw_cfg.h5_max_retries) {
1594*4882a593Smuzhiyun retries++;
1595*4882a593Smuzhiyun struct sk_buff *nskb =
1596*4882a593Smuzhiyun h5_prepare_pkt(&rtk_hw_cfg, h5conf, 3, H5_LINK_CTL_PKT);
1597*4882a593Smuzhiyun int len =
1598*4882a593Smuzhiyun write(rtk_hw_cfg.serial_fd, nskb->data, nskb->data_len);
1599*4882a593Smuzhiyun RS_DBG("3-wire config pattern resend : %d , len: %d", retries,
1600*4882a593Smuzhiyun len);
1601*4882a593Smuzhiyun skb_free(nskb);
1602*4882a593Smuzhiyun
1603*4882a593Smuzhiyun //gordon add 2013-6-7 retry per 250ms
1604*4882a593Smuzhiyun value.it_value.tv_sec = 0;
1605*4882a593Smuzhiyun value.it_value.tv_usec = 250000;
1606*4882a593Smuzhiyun value.it_interval.tv_sec = 0;
1607*4882a593Smuzhiyun value.it_interval.tv_usec = 250000;
1608*4882a593Smuzhiyun setitimer(ITIMER_REAL, &value, NULL);
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun return;
1611*4882a593Smuzhiyun }
1612*4882a593Smuzhiyun
1613*4882a593Smuzhiyun tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH);
1614*4882a593Smuzhiyun RS_ERR("H5 config timed out\n");
1615*4882a593Smuzhiyun exit(1);
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun /**
1619*4882a593Smuzhiyun * Retry to init when timeout in h5 proto, max retry times is 10.
1620*4882a593Smuzhiyun *
1621*4882a593Smuzhiyun * @warning Each time to retry, the time for timeout will be set as 1s.
1622*4882a593Smuzhiyun *
1623*4882a593Smuzhiyun * @param sig signaction for timeout
1624*4882a593Smuzhiyun *
1625*4882a593Smuzhiyun */
h5_tinit_sig_alarm(int sig)1626*4882a593Smuzhiyun static void h5_tinit_sig_alarm(int sig)
1627*4882a593Smuzhiyun {
1628*4882a593Smuzhiyun static int retries = 0;
1629*4882a593Smuzhiyun if (retries < rtk_hw_cfg.h5_max_retries) {
1630*4882a593Smuzhiyun retries++;
1631*4882a593Smuzhiyun if (rtk_hw_cfg.host_last_cmd) {
1632*4882a593Smuzhiyun int len =
1633*4882a593Smuzhiyun write(rtk_hw_cfg.serial_fd,
1634*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd->data,
1635*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd->data_len);
1636*4882a593Smuzhiyun RS_DBG("3-wire change baudrate re send:%d, len:%d",
1637*4882a593Smuzhiyun retries, len);
1638*4882a593Smuzhiyun alarm(1);
1639*4882a593Smuzhiyun return;
1640*4882a593Smuzhiyun } else {
1641*4882a593Smuzhiyun RS_DBG
1642*4882a593Smuzhiyun ("3-wire init timeout without last command stored\n");
1643*4882a593Smuzhiyun }
1644*4882a593Smuzhiyun }
1645*4882a593Smuzhiyun
1646*4882a593Smuzhiyun tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH);
1647*4882a593Smuzhiyun RS_ERR("H5 init process timed out");
1648*4882a593Smuzhiyun exit(1);
1649*4882a593Smuzhiyun }
1650*4882a593Smuzhiyun
1651*4882a593Smuzhiyun /**
1652*4882a593Smuzhiyun * Retry to download patch when timeout in h5 proto, max retry times is 10.
1653*4882a593Smuzhiyun *
1654*4882a593Smuzhiyun * @warning Each time to retry, the time for timeout will be set as 3s.
1655*4882a593Smuzhiyun *
1656*4882a593Smuzhiyun * @param sig signaction for timeout
1657*4882a593Smuzhiyun *
1658*4882a593Smuzhiyun */
h5_tpatch_sig_alarm(int sig)1659*4882a593Smuzhiyun static void h5_tpatch_sig_alarm(int sig)
1660*4882a593Smuzhiyun {
1661*4882a593Smuzhiyun static int retries = 0;
1662*4882a593Smuzhiyun if (retries < rtk_hw_cfg.h5_max_retries) {
1663*4882a593Smuzhiyun RS_ERR("patch timerout, retry:\n");
1664*4882a593Smuzhiyun if (rtk_hw_cfg.host_last_cmd) {
1665*4882a593Smuzhiyun int len =
1666*4882a593Smuzhiyun write(rtk_hw_cfg.serial_fd,
1667*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd->data,
1668*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd->data_len);
1669*4882a593Smuzhiyun RS_DBG("3-wire download patch re send:%d", retries);
1670*4882a593Smuzhiyun }
1671*4882a593Smuzhiyun retries++;
1672*4882a593Smuzhiyun alarm(3);
1673*4882a593Smuzhiyun return;
1674*4882a593Smuzhiyun }
1675*4882a593Smuzhiyun RS_ERR("H5 patch timed out\n");
1676*4882a593Smuzhiyun exit(1);
1677*4882a593Smuzhiyun }
1678*4882a593Smuzhiyun
1679*4882a593Smuzhiyun /**
1680*4882a593Smuzhiyun * Download patch using hci. For h5 proto, not recv reply for 2s will timeout.
1681*4882a593Smuzhiyun * Call h5_tpatch_sig_alarm for retry.
1682*4882a593Smuzhiyun *
1683*4882a593Smuzhiyun * @param dd uart file descriptor
1684*4882a593Smuzhiyun * @param index current index
1685*4882a593Smuzhiyun * @param data point to the config file
1686*4882a593Smuzhiyun * @param len current buf length
1687*4882a593Smuzhiyun * @return #0 on success
1688*4882a593Smuzhiyun *
1689*4882a593Smuzhiyun */
hci_download_patch(int dd,int index,uint8_t * data,int len,struct termios * ti)1690*4882a593Smuzhiyun static int hci_download_patch(int dd, int index, uint8_t * data, int len,
1691*4882a593Smuzhiyun struct termios *ti)
1692*4882a593Smuzhiyun {
1693*4882a593Smuzhiyun unsigned char hcipatch[256] = { 0x20, 0xfc, 00 };
1694*4882a593Smuzhiyun unsigned char bytes[READ_DATA_SIZE];
1695*4882a593Smuzhiyun int retlen;
1696*4882a593Smuzhiyun struct sigaction sa;
1697*4882a593Smuzhiyun
1698*4882a593Smuzhiyun sa.sa_handler = h5_tpatch_sig_alarm;
1699*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
1700*4882a593Smuzhiyun alarm(2);
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun download_vendor_patch_cp cp;
1703*4882a593Smuzhiyun memset(&cp, 0, sizeof(cp));
1704*4882a593Smuzhiyun cp.index = index;
1705*4882a593Smuzhiyun if (data != NULL) {
1706*4882a593Smuzhiyun memcpy(cp.data, data, len);
1707*4882a593Smuzhiyun }
1708*4882a593Smuzhiyun
1709*4882a593Smuzhiyun if (index & 0x80)
1710*4882a593Smuzhiyun rtk_hw_cfg.tx_index = index & 0x7f;
1711*4882a593Smuzhiyun else
1712*4882a593Smuzhiyun rtk_hw_cfg.tx_index = index;
1713*4882a593Smuzhiyun
1714*4882a593Smuzhiyun hcipatch[2] = len + 1;
1715*4882a593Smuzhiyun memcpy(hcipatch + 3, &cp, len + 1);
1716*4882a593Smuzhiyun
1717*4882a593Smuzhiyun struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, hcipatch, len + 4, HCI_COMMAND_PKT); //data:len+head:4
1718*4882a593Smuzhiyun
1719*4882a593Smuzhiyun if (rtk_hw_cfg.host_last_cmd) {
1720*4882a593Smuzhiyun skb_free(rtk_hw_cfg.host_last_cmd);
1721*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = NULL;
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun
1724*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = nskb;
1725*4882a593Smuzhiyun
1726*4882a593Smuzhiyun len = write(dd, nskb->data, nskb->data_len);
1727*4882a593Smuzhiyun RS_DBG("hci_download_patch tx_index:%d rx_index: %d\n",
1728*4882a593Smuzhiyun rtk_hw_cfg.tx_index, rtk_hw_cfg.rx_index);
1729*4882a593Smuzhiyun
1730*4882a593Smuzhiyun while (rtk_hw_cfg.rx_index != rtk_hw_cfg.tx_index) { //receive data and wait last pkt
1731*4882a593Smuzhiyun if ((retlen = read_check_rtk(dd, &bytes, READ_DATA_SIZE)) == -1) {
1732*4882a593Smuzhiyun RS_ERR("read fail\n");
1733*4882a593Smuzhiyun return -1;
1734*4882a593Smuzhiyun }
1735*4882a593Smuzhiyun h5_recv(&rtk_hw_cfg, &bytes, retlen);
1736*4882a593Smuzhiyun }
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun alarm(0);
1739*4882a593Smuzhiyun
1740*4882a593Smuzhiyun return 0;
1741*4882a593Smuzhiyun }
1742*4882a593Smuzhiyun
1743*4882a593Smuzhiyun #define READ_TRY_MAX 6
os_read(int fd,uint8_t * buff,int len)1744*4882a593Smuzhiyun int os_read(int fd, uint8_t * buff, int len)
1745*4882a593Smuzhiyun {
1746*4882a593Smuzhiyun int n;
1747*4882a593Smuzhiyun int i;
1748*4882a593Smuzhiyun int try = 0;
1749*4882a593Smuzhiyun
1750*4882a593Smuzhiyun i = 0;
1751*4882a593Smuzhiyun n = 0;
1752*4882a593Smuzhiyun while (n < len) {
1753*4882a593Smuzhiyun i = read(fd, buff + n, len - n);
1754*4882a593Smuzhiyun if (i > 0)
1755*4882a593Smuzhiyun n += i;
1756*4882a593Smuzhiyun else if (i == 0) {
1757*4882a593Smuzhiyun RS_DBG("read nothing.");
1758*4882a593Smuzhiyun continue;
1759*4882a593Smuzhiyun } else {
1760*4882a593Smuzhiyun RS_ERR("read error, %s\n", strerror(errno));
1761*4882a593Smuzhiyun try++;
1762*4882a593Smuzhiyun if (try > READ_TRY_MAX) {
1763*4882a593Smuzhiyun RS_ERR("read reaches max try number.\n");
1764*4882a593Smuzhiyun return -1;
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun continue;
1767*4882a593Smuzhiyun }
1768*4882a593Smuzhiyun }
1769*4882a593Smuzhiyun
1770*4882a593Smuzhiyun return n;
1771*4882a593Smuzhiyun }
1772*4882a593Smuzhiyun
1773*4882a593Smuzhiyun #define DUMP_HCI_EVT
1774*4882a593Smuzhiyun #ifdef DUMP_HCI_EVT
1775*4882a593Smuzhiyun #define HCI_DUMP_BUF_LEN 128
1776*4882a593Smuzhiyun static char hci_dump_buf[HCI_DUMP_BUF_LEN];
hci_dump_evt(uint8_t * buf,uint16_t len)1777*4882a593Smuzhiyun void hci_dump_evt(uint8_t * buf, uint16_t len)
1778*4882a593Smuzhiyun {
1779*4882a593Smuzhiyun int n;
1780*4882a593Smuzhiyun int i;
1781*4882a593Smuzhiyun
1782*4882a593Smuzhiyun if (!buf || !len) {
1783*4882a593Smuzhiyun RS_ERR("Invalid parameters %p, %u.\n", buf, len);
1784*4882a593Smuzhiyun return;
1785*4882a593Smuzhiyun }
1786*4882a593Smuzhiyun
1787*4882a593Smuzhiyun n = 0;
1788*4882a593Smuzhiyun for (i = 0; i < len; i++) {
1789*4882a593Smuzhiyun n += sprintf(hci_dump_buf + n, "%02x ", buf[i]);
1790*4882a593Smuzhiyun if ((i + 1) % 16 == 0) {
1791*4882a593Smuzhiyun RS_DBG(" %s\n", hci_dump_buf);
1792*4882a593Smuzhiyun n = 0;
1793*4882a593Smuzhiyun }
1794*4882a593Smuzhiyun }
1795*4882a593Smuzhiyun
1796*4882a593Smuzhiyun if (i % 16)
1797*4882a593Smuzhiyun RS_DBG(" %s\n", hci_dump_buf);
1798*4882a593Smuzhiyun }
1799*4882a593Smuzhiyun #endif
1800*4882a593Smuzhiyun
read_hci_evt(int fd,uint8_t * buff,uint8_t evt_code)1801*4882a593Smuzhiyun int read_hci_evt(int fd, uint8_t * buff, uint8_t evt_code)
1802*4882a593Smuzhiyun {
1803*4882a593Smuzhiyun uint8_t *evt_buff = buff;
1804*4882a593Smuzhiyun int ret;
1805*4882a593Smuzhiyun int try_type = 0;
1806*4882a593Smuzhiyun uint8_t vendor_evt = 0xff;
1807*4882a593Smuzhiyun
1808*4882a593Smuzhiyun start_read:
1809*4882a593Smuzhiyun do {
1810*4882a593Smuzhiyun ret = os_read(fd, evt_buff, 1);
1811*4882a593Smuzhiyun if (ret == 1 && evt_buff[0] == 0x04)
1812*4882a593Smuzhiyun break;
1813*4882a593Smuzhiyun else {
1814*4882a593Smuzhiyun RS_DBG("no pkt type, continue.");
1815*4882a593Smuzhiyun try_type++;
1816*4882a593Smuzhiyun continue;
1817*4882a593Smuzhiyun }
1818*4882a593Smuzhiyun } while (try_type < 6);
1819*4882a593Smuzhiyun
1820*4882a593Smuzhiyun if (try_type >= 6)
1821*4882a593Smuzhiyun return -1;
1822*4882a593Smuzhiyun
1823*4882a593Smuzhiyun ret = os_read(fd, evt_buff + 1, 1);
1824*4882a593Smuzhiyun if (ret < 0) {
1825*4882a593Smuzhiyun RS_ERR("%s: failed to read event code\n", __func__);
1826*4882a593Smuzhiyun return -1;
1827*4882a593Smuzhiyun }
1828*4882a593Smuzhiyun
1829*4882a593Smuzhiyun ret = os_read(fd, evt_buff + 2, 1);
1830*4882a593Smuzhiyun if (ret < 0) {
1831*4882a593Smuzhiyun RS_ERR("%s: failed to read parameter total len.\n", __func__);
1832*4882a593Smuzhiyun return -1;
1833*4882a593Smuzhiyun }
1834*4882a593Smuzhiyun
1835*4882a593Smuzhiyun ret = os_read(fd, evt_buff + 3, evt_buff[2]);
1836*4882a593Smuzhiyun if (ret < 0) {
1837*4882a593Smuzhiyun RS_ERR("%s: failed to read payload of event.\n", __func__);
1838*4882a593Smuzhiyun return -1;
1839*4882a593Smuzhiyun }
1840*4882a593Smuzhiyun #ifdef DUMP_HCI_EVT
1841*4882a593Smuzhiyun hci_dump_evt(evt_buff, ret + 3);
1842*4882a593Smuzhiyun #endif
1843*4882a593Smuzhiyun
1844*4882a593Smuzhiyun /* This event to wake up host. */
1845*4882a593Smuzhiyun if (evt_buff[1] == vendor_evt) {
1846*4882a593Smuzhiyun try_type = 0;
1847*4882a593Smuzhiyun RS_DBG("%s: found vendor evt, continue reading.\n", __func__);
1848*4882a593Smuzhiyun goto start_read;
1849*4882a593Smuzhiyun }
1850*4882a593Smuzhiyun
1851*4882a593Smuzhiyun if (evt_buff[1] != evt_code) {
1852*4882a593Smuzhiyun RS_ERR("%s: event code mismatches, %x, expect %x.\n",
1853*4882a593Smuzhiyun __func__, evt_buff[1], evt_code);
1854*4882a593Smuzhiyun return -1;
1855*4882a593Smuzhiyun }
1856*4882a593Smuzhiyun
1857*4882a593Smuzhiyun return (ret + 3);
1858*4882a593Smuzhiyun }
1859*4882a593Smuzhiyun
1860*4882a593Smuzhiyun /**
1861*4882a593Smuzhiyun * Download h4 patch
1862*4882a593Smuzhiyun *
1863*4882a593Smuzhiyun * @param dd uart file descriptor
1864*4882a593Smuzhiyun * @param index current index
1865*4882a593Smuzhiyun * @param data point to the config file
1866*4882a593Smuzhiyun * @param len current buf length
1867*4882a593Smuzhiyun * @return ret_index
1868*4882a593Smuzhiyun *
1869*4882a593Smuzhiyun */
hci_download_patch_h4(int dd,int index,uint8_t * data,int len)1870*4882a593Smuzhiyun static int hci_download_patch_h4(int dd, int index, uint8_t * data, int len)
1871*4882a593Smuzhiyun {
1872*4882a593Smuzhiyun unsigned char bytes[257] = { 0 };
1873*4882a593Smuzhiyun unsigned char buf[257] = { 0x01, 0x20, 0xfc, 00 };
1874*4882a593Smuzhiyun uint16_t readbytes = 0;
1875*4882a593Smuzhiyun int cur_index = index;
1876*4882a593Smuzhiyun int ret_Index = -1;
1877*4882a593Smuzhiyun uint16_t res = 0;
1878*4882a593Smuzhiyun int i = 0;
1879*4882a593Smuzhiyun size_t total_len;
1880*4882a593Smuzhiyun uint16_t w_len;
1881*4882a593Smuzhiyun uint8_t rstatus;
1882*4882a593Smuzhiyun int ret;
1883*4882a593Smuzhiyun uint8_t opcode[2] = {
1884*4882a593Smuzhiyun 0x20, 0xfc,
1885*4882a593Smuzhiyun };
1886*4882a593Smuzhiyun
1887*4882a593Smuzhiyun RS_DBG("dd:%d, index:%d, len:%d", dd, index, len);
1888*4882a593Smuzhiyun if (NULL != data) {
1889*4882a593Smuzhiyun memcpy(&buf[5], data, len);
1890*4882a593Smuzhiyun }
1891*4882a593Smuzhiyun
1892*4882a593Smuzhiyun buf[3] = len + 1;
1893*4882a593Smuzhiyun buf[4] = cur_index;
1894*4882a593Smuzhiyun total_len = len + 5;
1895*4882a593Smuzhiyun
1896*4882a593Smuzhiyun w_len = write(dd, buf, total_len);
1897*4882a593Smuzhiyun RS_DBG("h4 write success with len: %d\n", w_len);
1898*4882a593Smuzhiyun
1899*4882a593Smuzhiyun ret = read_hci_evt(dd, bytes, 0x0e);
1900*4882a593Smuzhiyun if (ret < 0) {
1901*4882a593Smuzhiyun RS_ERR("%s: read hci evt error.\n", __func__);
1902*4882a593Smuzhiyun return -1;
1903*4882a593Smuzhiyun }
1904*4882a593Smuzhiyun
1905*4882a593Smuzhiyun /* RS_DBG("%s: bytes: %x %x %x %x %x %x.\n",
1906*4882a593Smuzhiyun * __func__, bytes[0], bytes[1], bytes[2],
1907*4882a593Smuzhiyun * bytes[3], bytes[4], bytes[5]); */
1908*4882a593Smuzhiyun
1909*4882a593Smuzhiyun if ((0x04 == bytes[0]) && (opcode[0] == bytes[4])
1910*4882a593Smuzhiyun && (opcode[1] == bytes[5])) {
1911*4882a593Smuzhiyun ret_Index = bytes[7];
1912*4882a593Smuzhiyun rstatus = bytes[6];
1913*4882a593Smuzhiyun RS_DBG("---->ret_Index:%d, ----->rstatus:%d\n", ret_Index,
1914*4882a593Smuzhiyun rstatus);
1915*4882a593Smuzhiyun if (0x00 != rstatus) {
1916*4882a593Smuzhiyun RS_ERR("---->read event status is wrong\n");
1917*4882a593Smuzhiyun return -1;
1918*4882a593Smuzhiyun }
1919*4882a593Smuzhiyun } else {
1920*4882a593Smuzhiyun RS_ERR("==========>Didn't read curret data\n");
1921*4882a593Smuzhiyun return -1;
1922*4882a593Smuzhiyun }
1923*4882a593Smuzhiyun
1924*4882a593Smuzhiyun return ret_Index;
1925*4882a593Smuzhiyun }
1926*4882a593Smuzhiyun
1927*4882a593Smuzhiyun /**
1928*4882a593Smuzhiyun * Realtek change speed with h4 proto. Using vendor specified command packet to achieve this.
1929*4882a593Smuzhiyun *
1930*4882a593Smuzhiyun * @warning before write, need to wait 1s for device up
1931*4882a593Smuzhiyun *
1932*4882a593Smuzhiyun * @param fd uart file descriptor
1933*4882a593Smuzhiyun * @param baudrate the speed want to change
1934*4882a593Smuzhiyun * @return #0 on success
1935*4882a593Smuzhiyun */
rtk_vendor_change_speed_h4(int fd,RT_U32 baudrate)1936*4882a593Smuzhiyun static int rtk_vendor_change_speed_h4(int fd, RT_U32 baudrate)
1937*4882a593Smuzhiyun {
1938*4882a593Smuzhiyun int res;
1939*4882a593Smuzhiyun unsigned char bytes[257];
1940*4882a593Smuzhiyun RT_U8 cmd[8] = { 0 };
1941*4882a593Smuzhiyun
1942*4882a593Smuzhiyun cmd[0] = 1; //cmd;
1943*4882a593Smuzhiyun cmd[1] = 0x17; //ocf
1944*4882a593Smuzhiyun cmd[2] = 0xfc; //ogf
1945*4882a593Smuzhiyun cmd[3] = 4; //length;
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun baudrate = cpu_to_le32(baudrate);
1948*4882a593Smuzhiyun #ifdef BAUDRATE_4BYTES
1949*4882a593Smuzhiyun memcpy((RT_U16 *) & cmd[4], &baudrate, 4);
1950*4882a593Smuzhiyun #else
1951*4882a593Smuzhiyun memcpy((RT_U16 *) & cmd[4], &baudrate, 2);
1952*4882a593Smuzhiyun cmd[6] = 0;
1953*4882a593Smuzhiyun cmd[7] = 0;
1954*4882a593Smuzhiyun #endif
1955*4882a593Smuzhiyun
1956*4882a593Smuzhiyun //wait for a while for device to up, just h4 need it
1957*4882a593Smuzhiyun sleep(1);
1958*4882a593Smuzhiyun RS_DBG("baudrate in change speed command: 0x%x 0x%x 0x%x 0x%x \n",
1959*4882a593Smuzhiyun cmd[4], cmd[5], cmd[6], cmd[7]);
1960*4882a593Smuzhiyun
1961*4882a593Smuzhiyun if (write(fd, cmd, 8) != 8) {
1962*4882a593Smuzhiyun RS_ERR
1963*4882a593Smuzhiyun ("H4 change uart speed error when writing vendor command");
1964*4882a593Smuzhiyun return -1;
1965*4882a593Smuzhiyun }
1966*4882a593Smuzhiyun RS_DBG("H4 Change uart Baudrate after write ");
1967*4882a593Smuzhiyun
1968*4882a593Smuzhiyun res = read_hci_evt(fd, bytes, 0x0e);
1969*4882a593Smuzhiyun if (res < 0) {
1970*4882a593Smuzhiyun RS_ERR("%s: Failed to read hci evt.\n", __func__);
1971*4882a593Smuzhiyun return -1;
1972*4882a593Smuzhiyun }
1973*4882a593Smuzhiyun
1974*4882a593Smuzhiyun if ((0x04 == bytes[0]) && (0x17 == bytes[4]) && (0xfc == bytes[5])) {
1975*4882a593Smuzhiyun RS_DBG("H4 change uart speed success, receving status:%x",
1976*4882a593Smuzhiyun bytes[6]);
1977*4882a593Smuzhiyun if (bytes[6] == 0)
1978*4882a593Smuzhiyun return 0;
1979*4882a593Smuzhiyun }
1980*4882a593Smuzhiyun return -1;
1981*4882a593Smuzhiyun }
1982*4882a593Smuzhiyun
1983*4882a593Smuzhiyun /**
1984*4882a593Smuzhiyun * Parse realtek Bluetooth config file.
1985*4882a593Smuzhiyun * The config file if begin with vendor magic: RTK_VENDOR_CONFIG_MAGIC(8723ab55)
1986*4882a593Smuzhiyun * bt_addr is followed by 0x3c offset, it will be changed by bt_addr param
1987*4882a593Smuzhiyun * proto, baudrate and flow control is followed by 0xc offset,
1988*4882a593Smuzhiyun *
1989*4882a593Smuzhiyun * @param config_buf point to config file content
1990*4882a593Smuzhiyun * @param *plen length of config file
1991*4882a593Smuzhiyun * @param bt_addr where bt addr is stored
1992*4882a593Smuzhiyun * @return
1993*4882a593Smuzhiyun * 1. new config buf
1994*4882a593Smuzhiyun * 2. new config length *plen
1995*4882a593Smuzhiyun * 3. result (for baudrate)
1996*4882a593Smuzhiyun *
1997*4882a593Smuzhiyun */
1998*4882a593Smuzhiyun
rtk_parse_config_file(RT_U8 * config_buf,size_t * plen,uint8_t bt_addr[6],uint32_t * result)1999*4882a593Smuzhiyun uint8_t *rtk_parse_config_file(RT_U8 *config_buf, size_t *plen,
2000*4882a593Smuzhiyun uint8_t bt_addr[6], uint32_t *result)
2001*4882a593Smuzhiyun {
2002*4882a593Smuzhiyun
2003*4882a593Smuzhiyun struct rtk_bt_vendor_config *config =
2004*4882a593Smuzhiyun (struct rtk_bt_vendor_config *)config_buf;
2005*4882a593Smuzhiyun RT_U16 config_len = 0, temp = 0;
2006*4882a593Smuzhiyun struct rtk_bt_vendor_config_entry *entry = NULL;
2007*4882a593Smuzhiyun RT_U16 i;
2008*4882a593Smuzhiyun RT_U32 baudrate = 0;
2009*4882a593Smuzhiyun uint32_t flags = 0;
2010*4882a593Smuzhiyun uint32_t add_flags;
2011*4882a593Smuzhiyun #ifdef USE_CUSTOMER_ADDRESS
2012*4882a593Smuzhiyun uint8_t j = 0;
2013*4882a593Smuzhiyun struct patch_info *pent = rtk_hw_cfg.patch_ent;
2014*4882a593Smuzhiyun #endif
2015*4882a593Smuzhiyun #ifdef EXTRA_CONFIG_OPTION
2016*4882a593Smuzhiyun uint8_t *head = config_buf;
2017*4882a593Smuzhiyun
2018*4882a593Smuzhiyun add_flags = config_flags;
2019*4882a593Smuzhiyun #endif
2020*4882a593Smuzhiyun
2021*4882a593Smuzhiyun if (!config || !plen)
2022*4882a593Smuzhiyun return NULL;
2023*4882a593Smuzhiyun
2024*4882a593Smuzhiyun RS_INFO("Original Cfg len %u", *plen);
2025*4882a593Smuzhiyun config_len = le16_to_cpu(config->data_len);
2026*4882a593Smuzhiyun entry = config->entry;
2027*4882a593Smuzhiyun
2028*4882a593Smuzhiyun if (le32_to_cpu(config->signature) != RTK_VENDOR_CONFIG_MAGIC) {
2029*4882a593Smuzhiyun RS_ERR("signature magic number(%x) is incorrect",
2030*4882a593Smuzhiyun (unsigned int)config->signature);
2031*4882a593Smuzhiyun return NULL;
2032*4882a593Smuzhiyun }
2033*4882a593Smuzhiyun
2034*4882a593Smuzhiyun if (config_len != *plen - sizeof(struct rtk_bt_vendor_config)) {
2035*4882a593Smuzhiyun RS_ERR("config len(%d) is incorrect(%zd)", config_len,
2036*4882a593Smuzhiyun *plen - sizeof(struct rtk_bt_vendor_config));
2037*4882a593Smuzhiyun return NULL;
2038*4882a593Smuzhiyun }
2039*4882a593Smuzhiyun
2040*4882a593Smuzhiyun for (i = 0; i < config_len;) {
2041*4882a593Smuzhiyun
2042*4882a593Smuzhiyun switch (le16_to_cpu(entry->offset)) {
2043*4882a593Smuzhiyun #ifdef USE_CUSTOMER_ADDRESS
2044*4882a593Smuzhiyun case 0x003c:
2045*4882a593Smuzhiyun case 0x0044:
2046*4882a593Smuzhiyun if (!customer_bdaddr)
2047*4882a593Smuzhiyun break;
2048*4882a593Smuzhiyun if (pent->chip_type > CHIP_BEFORE &&
2049*4882a593Smuzhiyun le16_to_cpu(entry->offset) != 0x44)
2050*4882a593Smuzhiyun break;
2051*4882a593Smuzhiyun if (pent->chip_type <= CHIP_BEFORE &&
2052*4882a593Smuzhiyun le16_to_cpu(entry->offset) != 0x3c)
2053*4882a593Smuzhiyun break;
2054*4882a593Smuzhiyun for (j = 0; j < entry->entry_len; j++)
2055*4882a593Smuzhiyun entry->entry_data[j] = bt_addr[j];
2056*4882a593Smuzhiyun flags |= CONFIG_BTMAC;
2057*4882a593Smuzhiyun RS_INFO("BT MAC found %02x:%02x:%02x:%02x:%02x:%02x",
2058*4882a593Smuzhiyun entry->entry_data[5],
2059*4882a593Smuzhiyun entry->entry_data[4],
2060*4882a593Smuzhiyun entry->entry_data[3],
2061*4882a593Smuzhiyun entry->entry_data[2],
2062*4882a593Smuzhiyun entry->entry_data[1],
2063*4882a593Smuzhiyun entry->entry_data[0]);
2064*4882a593Smuzhiyun break;
2065*4882a593Smuzhiyun #endif
2066*4882a593Smuzhiyun case 0xc:
2067*4882a593Smuzhiyun {
2068*4882a593Smuzhiyun #ifdef BAUDRATE_4BYTES
2069*4882a593Smuzhiyun baudrate =
2070*4882a593Smuzhiyun get_unaligned_le32(entry->entry_data);
2071*4882a593Smuzhiyun #else
2072*4882a593Smuzhiyun baudrate =
2073*4882a593Smuzhiyun get_unaligned_le16(entry->entry_data);
2074*4882a593Smuzhiyun #endif
2075*4882a593Smuzhiyun
2076*4882a593Smuzhiyun if (entry->entry_len >= 12) //0ffset 0x18 - 0xc
2077*4882a593Smuzhiyun {
2078*4882a593Smuzhiyun rtk_hw_cfg.hw_flow_control = (entry->entry_data[12] & 0x4) ? 1 : 0; //0x18 byte bit2
2079*4882a593Smuzhiyun //rtk_hw_cfg.hw_flow_control = 0;
2080*4882a593Smuzhiyun }
2081*4882a593Smuzhiyun RS_DBG
2082*4882a593Smuzhiyun ("config baud rate to :0x%08x, hwflowcontrol:%x, %x",
2083*4882a593Smuzhiyun (unsigned int)baudrate,
2084*4882a593Smuzhiyun entry->entry_data[12],
2085*4882a593Smuzhiyun rtk_hw_cfg.hw_flow_control);
2086*4882a593Smuzhiyun break;
2087*4882a593Smuzhiyun }
2088*4882a593Smuzhiyun #ifdef EXTRA_CONFIG_OPTION
2089*4882a593Smuzhiyun case 0x015b:
2090*4882a593Smuzhiyun if (!(add_flags & CONFIG_TXPOWER))
2091*4882a593Smuzhiyun break;
2092*4882a593Smuzhiyun add_flags &= ~CONFIG_TXPOWER;
2093*4882a593Smuzhiyun if (txpower_len != entry->entry_len) {
2094*4882a593Smuzhiyun RS_ERR("invalid tx power cfg len %u, %u",
2095*4882a593Smuzhiyun txpower_len, entry->entry_len);
2096*4882a593Smuzhiyun break;
2097*4882a593Smuzhiyun }
2098*4882a593Smuzhiyun memcpy(entry->entry_data, txpower_cfg, txpower_len);
2099*4882a593Smuzhiyun RS_INFO("Replace Tx power Cfg %02x %02x %02x %02x",
2100*4882a593Smuzhiyun txpower_cfg[0], txpower_cfg[1], txpower_cfg[2],
2101*4882a593Smuzhiyun txpower_cfg[3]);
2102*4882a593Smuzhiyun break;
2103*4882a593Smuzhiyun case 0x01e6:
2104*4882a593Smuzhiyun if (!(add_flags & CONFIG_XTAL))
2105*4882a593Smuzhiyun break;
2106*4882a593Smuzhiyun add_flags &= ~CONFIG_XTAL;
2107*4882a593Smuzhiyun RS_INFO("Replace XTAL Cfg 0x%02x", xtal_cfg);
2108*4882a593Smuzhiyun entry->entry_data[0] = xtal_cfg;
2109*4882a593Smuzhiyun break;
2110*4882a593Smuzhiyun #endif
2111*4882a593Smuzhiyun default:
2112*4882a593Smuzhiyun RS_DBG("cfg offset (%04x),length (%02x)", entry->offset,
2113*4882a593Smuzhiyun entry->entry_len);
2114*4882a593Smuzhiyun break;
2115*4882a593Smuzhiyun }
2116*4882a593Smuzhiyun temp = entry->entry_len +
2117*4882a593Smuzhiyun sizeof(struct rtk_bt_vendor_config_entry);
2118*4882a593Smuzhiyun i += temp;
2119*4882a593Smuzhiyun entry = (struct rtk_bt_vendor_config_entry *)((RT_U8 *)entry +
2120*4882a593Smuzhiyun temp);
2121*4882a593Smuzhiyun }
2122*4882a593Smuzhiyun
2123*4882a593Smuzhiyun #ifdef USE_CUSTOMER_ADDRESS
2124*4882a593Smuzhiyun if (!(flags & CONFIG_BTMAC) && customer_bdaddr) {
2125*4882a593Smuzhiyun uint8_t *b;
2126*4882a593Smuzhiyun
2127*4882a593Smuzhiyun b = config_buf + *plen;
2128*4882a593Smuzhiyun if (pent->chip_type > CHIP_BEFORE) {
2129*4882a593Smuzhiyun b[0] = 0x44;
2130*4882a593Smuzhiyun b[1] = 0x00;
2131*4882a593Smuzhiyun } else {
2132*4882a593Smuzhiyun b[0] = 0x3c;
2133*4882a593Smuzhiyun b[1] = 0x00;
2134*4882a593Smuzhiyun }
2135*4882a593Smuzhiyun RS_INFO("add bdaddr sec, offset %02x%02x", b[1], b[0]);
2136*4882a593Smuzhiyun b[2] = 6;
2137*4882a593Smuzhiyun for (j = 0; j < 6; j++)
2138*4882a593Smuzhiyun b[3 + j] = bt_addr[j];
2139*4882a593Smuzhiyun
2140*4882a593Smuzhiyun *plen += 9;
2141*4882a593Smuzhiyun config_len += 9;
2142*4882a593Smuzhiyun temp = *plen - 6;
2143*4882a593Smuzhiyun
2144*4882a593Smuzhiyun config_buf[4] = (temp & 0xff);
2145*4882a593Smuzhiyun config_buf[5] = ((temp >> 8) & 0xff);
2146*4882a593Smuzhiyun }
2147*4882a593Smuzhiyun #endif
2148*4882a593Smuzhiyun
2149*4882a593Smuzhiyun #ifdef EXTRA_CONFIG_OPTION
2150*4882a593Smuzhiyun temp = *plen;
2151*4882a593Smuzhiyun if (add_flags & CONFIG_TXPOWER)
2152*4882a593Smuzhiyun temp += (2 + 1 + txpower_len);
2153*4882a593Smuzhiyun if ((add_flags & CONFIG_XTAL))
2154*4882a593Smuzhiyun temp += (2 + 1 + 1);
2155*4882a593Smuzhiyun
2156*4882a593Smuzhiyun if (add_flags) {
2157*4882a593Smuzhiyun RS_INFO("Add extra configs");
2158*4882a593Smuzhiyun config_buf = head;
2159*4882a593Smuzhiyun temp -= sizeof(struct rtk_bt_vendor_config);
2160*4882a593Smuzhiyun config_buf[4] = (temp & 0xff);
2161*4882a593Smuzhiyun config_buf[5] = ((temp >> 8) & 0xff);
2162*4882a593Smuzhiyun config_buf += *plen;
2163*4882a593Smuzhiyun if (add_flags & CONFIG_TXPOWER) {
2164*4882a593Smuzhiyun RS_INFO("Add Tx power Cfg");
2165*4882a593Smuzhiyun *config_buf++ = 0x5b;
2166*4882a593Smuzhiyun *config_buf++ = 0x01;
2167*4882a593Smuzhiyun *config_buf++ = txpower_len;
2168*4882a593Smuzhiyun memcpy(config_buf, txpower_cfg, txpower_len);
2169*4882a593Smuzhiyun config_buf += txpower_len;
2170*4882a593Smuzhiyun }
2171*4882a593Smuzhiyun if ((add_flags & CONFIG_XTAL)) {
2172*4882a593Smuzhiyun RS_INFO("Add XTAL Cfg");
2173*4882a593Smuzhiyun *config_buf++ = 0xe6;
2174*4882a593Smuzhiyun *config_buf++ = 0x01;
2175*4882a593Smuzhiyun *config_buf++ = 1;
2176*4882a593Smuzhiyun *config_buf++ = xtal_cfg;
2177*4882a593Smuzhiyun }
2178*4882a593Smuzhiyun *plen = config_buf - head;
2179*4882a593Smuzhiyun config_buf = head;
2180*4882a593Smuzhiyun }
2181*4882a593Smuzhiyun #endif
2182*4882a593Smuzhiyun
2183*4882a593Smuzhiyun done:
2184*4882a593Smuzhiyun *result = baudrate;
2185*4882a593Smuzhiyun return config_buf;
2186*4882a593Smuzhiyun }
2187*4882a593Smuzhiyun
2188*4882a593Smuzhiyun #ifdef USE_CUSTOMER_ADDRESS
bachk(const char * str)2189*4882a593Smuzhiyun int bachk(const char *str)
2190*4882a593Smuzhiyun {
2191*4882a593Smuzhiyun if (!str)
2192*4882a593Smuzhiyun return -1;
2193*4882a593Smuzhiyun
2194*4882a593Smuzhiyun if (strlen(str) != 17)
2195*4882a593Smuzhiyun return -1;
2196*4882a593Smuzhiyun
2197*4882a593Smuzhiyun while (*str) {
2198*4882a593Smuzhiyun if (!isxdigit(*str++))
2199*4882a593Smuzhiyun return -1;
2200*4882a593Smuzhiyun
2201*4882a593Smuzhiyun if (!isxdigit(*str++))
2202*4882a593Smuzhiyun return -1;
2203*4882a593Smuzhiyun
2204*4882a593Smuzhiyun if (*str == 0)
2205*4882a593Smuzhiyun break;
2206*4882a593Smuzhiyun
2207*4882a593Smuzhiyun if (*str++ != ':')
2208*4882a593Smuzhiyun return -1;
2209*4882a593Smuzhiyun }
2210*4882a593Smuzhiyun
2211*4882a593Smuzhiyun return 0;
2212*4882a593Smuzhiyun }
2213*4882a593Smuzhiyun /**
2214*4882a593Smuzhiyun * get random realtek Bluetooth addr.
2215*4882a593Smuzhiyun *
2216*4882a593Smuzhiyun * @param bt_addr where bt addr is stored
2217*4882a593Smuzhiyun *
2218*4882a593Smuzhiyun */
2219*4882a593Smuzhiyun /* static void rtk_get_ram_addr(char bt_addr[0])
2220*4882a593Smuzhiyun * {
2221*4882a593Smuzhiyun * srand(time(NULL) + getpid() + getpid() * 987654 + rand());
2222*4882a593Smuzhiyun *
2223*4882a593Smuzhiyun * RT_U32 addr = rand();
2224*4882a593Smuzhiyun * memcpy(bt_addr, &addr, sizeof(RT_U8));
2225*4882a593Smuzhiyun * }
2226*4882a593Smuzhiyun */
2227*4882a593Smuzhiyun
2228*4882a593Smuzhiyun /**
2229*4882a593Smuzhiyun * Write the random bt addr to the file /data/misc/bluetoothd/bt_mac/btmac.txt.
2230*4882a593Smuzhiyun *
2231*4882a593Smuzhiyun * @param bt_addr where bt addr is stored
2232*4882a593Smuzhiyun *
2233*4882a593Smuzhiyun */
2234*4882a593Smuzhiyun /* static void rtk_write_btmac2file(char bt_addr[6])
2235*4882a593Smuzhiyun * {
2236*4882a593Smuzhiyun * int fd;
2237*4882a593Smuzhiyun * fd = open(BT_ADDR_FILE, O_CREAT | O_RDWR | O_TRUNC);
2238*4882a593Smuzhiyun *
2239*4882a593Smuzhiyun * if (fd > 0) {
2240*4882a593Smuzhiyun * chmod(BT_ADDR_FILE, 0666);
2241*4882a593Smuzhiyun * char addr[18] = { 0 };
2242*4882a593Smuzhiyun * addr[17] = '\0';
2243*4882a593Smuzhiyun * sprintf(addr, "%2x:%2x:%2x:%2x:%2x:%2x", bt_addr[0], bt_addr[1],
2244*4882a593Smuzhiyun * bt_addr[2], bt_addr[3], bt_addr[4], bt_addr[5]);
2245*4882a593Smuzhiyun * write(fd, addr, strlen(addr));
2246*4882a593Smuzhiyun * close(fd);
2247*4882a593Smuzhiyun * } else {
2248*4882a593Smuzhiyun * RS_ERR("open file error:%s\n", BT_ADDR_FILE);
2249*4882a593Smuzhiyun * }
2250*4882a593Smuzhiyun * }
2251*4882a593Smuzhiyun */
2252*4882a593Smuzhiyun #endif
2253*4882a593Smuzhiyun
2254*4882a593Smuzhiyun /**
2255*4882a593Smuzhiyun * Get realtek Bluetooth config file. The bt addr arg is stored in /data/btmac.txt, if there is not this file,
2256*4882a593Smuzhiyun * change to /data/misc/bluetoothd/bt_mac/btmac.txt. If both of them are not found, using
2257*4882a593Smuzhiyun * random bt addr.
2258*4882a593Smuzhiyun *
2259*4882a593Smuzhiyun * @param config_buf point to the content of realtek Bluetooth config file
2260*4882a593Smuzhiyun * @param config_baud_rate the baudrate set in the config file
2261*4882a593Smuzhiyun * @return file_len the length of config file
2262*4882a593Smuzhiyun */
rtk_get_bt_config(struct btrtl_info * btrtl,uint8_t ** config_buf,RT_U32 * config_baud_rate)2263*4882a593Smuzhiyun int rtk_get_bt_config(struct btrtl_info *btrtl, uint8_t **config_buf,
2264*4882a593Smuzhiyun RT_U32 *config_baud_rate)
2265*4882a593Smuzhiyun {
2266*4882a593Smuzhiyun char bt_config_file_name[PATH_MAX] = { 0 };
2267*4882a593Smuzhiyun RT_U8 *bt_addr_temp = NULL;
2268*4882a593Smuzhiyun uint8_t bt_addr[6] = { 0x00, 0xe0, 0x4c, 0x88, 0x88, 0x88 };
2269*4882a593Smuzhiyun struct stat st;
2270*4882a593Smuzhiyun size_t filelen;
2271*4882a593Smuzhiyun size_t tlength;
2272*4882a593Smuzhiyun int fd;
2273*4882a593Smuzhiyun int ret = 0;
2274*4882a593Smuzhiyun int i = 0;
2275*4882a593Smuzhiyun
2276*4882a593Smuzhiyun #ifdef USE_CUSTOMER_ADDRESS
2277*4882a593Smuzhiyun #define BDADDR_STRING_LEN 17
2278*4882a593Smuzhiyun size_t size;
2279*4882a593Smuzhiyun size_t result;
2280*4882a593Smuzhiyun uint8_t tbuf[BDADDR_STRING_LEN + 1];
2281*4882a593Smuzhiyun char *str;
2282*4882a593Smuzhiyun
2283*4882a593Smuzhiyun if (stat(BT_ADDR_FILE, &st) < 0) {
2284*4882a593Smuzhiyun RS_INFO("Couldnt access customer BT MAC file %s",
2285*4882a593Smuzhiyun BT_ADDR_FILE);
2286*4882a593Smuzhiyun
2287*4882a593Smuzhiyun /* for (i = 0; i < 6; i++)
2288*4882a593Smuzhiyun * rtk_get_ram_addr(&bt_addr[i]);
2289*4882a593Smuzhiyun * rtk_write_btmac2file(bt_addr);
2290*4882a593Smuzhiyun */
2291*4882a593Smuzhiyun goto GET_CONFIG;
2292*4882a593Smuzhiyun }
2293*4882a593Smuzhiyun
2294*4882a593Smuzhiyun size = st.st_size;
2295*4882a593Smuzhiyun /* Only read the first 17-byte if the file length is larger */
2296*4882a593Smuzhiyun if (size > BDADDR_STRING_LEN)
2297*4882a593Smuzhiyun size = BDADDR_STRING_LEN;
2298*4882a593Smuzhiyun
2299*4882a593Smuzhiyun fd = open(BT_ADDR_FILE, O_RDONLY);
2300*4882a593Smuzhiyun if (fd == -1) {
2301*4882a593Smuzhiyun RS_ERR("Couldnt open BT MAC file %s, %s", BT_ADDR_FILE,
2302*4882a593Smuzhiyun strerror(errno));
2303*4882a593Smuzhiyun } else {
2304*4882a593Smuzhiyun memset(tbuf, 0, sizeof(tbuf));
2305*4882a593Smuzhiyun result = read(fd, tbuf, size);
2306*4882a593Smuzhiyun close(fd);
2307*4882a593Smuzhiyun if (result == -1) {
2308*4882a593Smuzhiyun RS_ERR("Couldnt read BT MAC file %s, err %s",
2309*4882a593Smuzhiyun BT_ADDR_FILE, strerror(errno));
2310*4882a593Smuzhiyun goto GET_CONFIG;
2311*4882a593Smuzhiyun }
2312*4882a593Smuzhiyun
2313*4882a593Smuzhiyun if (bachk(tbuf) < 0) {
2314*4882a593Smuzhiyun goto GET_CONFIG;
2315*4882a593Smuzhiyun }
2316*4882a593Smuzhiyun
2317*4882a593Smuzhiyun str = tbuf;
2318*4882a593Smuzhiyun for (i = 5; i >= 0; i--) {
2319*4882a593Smuzhiyun bt_addr[i] = (uint8_t)strtoul(str, NULL, 16);
2320*4882a593Smuzhiyun str += 3;
2321*4882a593Smuzhiyun }
2322*4882a593Smuzhiyun
2323*4882a593Smuzhiyun /*reserve LAP addr from 0x9e8b00 to 0x9e8b3f, change to 0x008b** */
2324*4882a593Smuzhiyun if (0x9e == bt_addr[3] && 0x8b == bt_addr[4]
2325*4882a593Smuzhiyun && (bt_addr[5] <= 0x3f)) {
2326*4882a593Smuzhiyun bt_addr[3] = 0x00;
2327*4882a593Smuzhiyun }
2328*4882a593Smuzhiyun
2329*4882a593Smuzhiyun RS_DBG("BT MAC is %02x:%02x:%02x:%02x:%02x:%02x",
2330*4882a593Smuzhiyun bt_addr[5], bt_addr[4],
2331*4882a593Smuzhiyun bt_addr[3], bt_addr[2],
2332*4882a593Smuzhiyun bt_addr[1], bt_addr[0]);
2333*4882a593Smuzhiyun customer_bdaddr = 1;
2334*4882a593Smuzhiyun }
2335*4882a593Smuzhiyun #endif
2336*4882a593Smuzhiyun
2337*4882a593Smuzhiyun GET_CONFIG:
2338*4882a593Smuzhiyun //ret = sprintf(bt_config_file_name, BT_CONFIG_DIRECTORY "rtlbt_config");
2339*4882a593Smuzhiyun ret = sprintf(bt_config_file_name, "%s", BT_CONFIG_DIRECTORY);
2340*4882a593Smuzhiyun strcat(bt_config_file_name, btrtl->patch_ent->config_file);
2341*4882a593Smuzhiyun if (stat(bt_config_file_name, &st) < 0) {
2342*4882a593Smuzhiyun RS_ERR("can't access bt config file:%s, errno:%d\n",
2343*4882a593Smuzhiyun bt_config_file_name, errno);
2344*4882a593Smuzhiyun return -1;
2345*4882a593Smuzhiyun }
2346*4882a593Smuzhiyun
2347*4882a593Smuzhiyun filelen = st.st_size;
2348*4882a593Smuzhiyun
2349*4882a593Smuzhiyun if ((fd = open(bt_config_file_name, O_RDONLY)) < 0) {
2350*4882a593Smuzhiyun perror("Can't open bt config file");
2351*4882a593Smuzhiyun return -1;
2352*4882a593Smuzhiyun }
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun tlength = filelen;
2355*4882a593Smuzhiyun #ifdef USE_CUSTOMER_ADDRESS
2356*4882a593Smuzhiyun tlength += 9;
2357*4882a593Smuzhiyun #endif
2358*4882a593Smuzhiyun
2359*4882a593Smuzhiyun #ifdef EXTRA_CONFIG_OPTION
2360*4882a593Smuzhiyun config_file_proc(EXTRA_CONFIG_FILE);
2361*4882a593Smuzhiyun if (!xtalset_supported())
2362*4882a593Smuzhiyun config_flags &= ~CONFIG_XTAL;
2363*4882a593Smuzhiyun if (config_flags & CONFIG_TXPOWER)
2364*4882a593Smuzhiyun tlength += 7;
2365*4882a593Smuzhiyun if (config_flags & CONFIG_XTAL)
2366*4882a593Smuzhiyun tlength += 4;
2367*4882a593Smuzhiyun #endif
2368*4882a593Smuzhiyun
2369*4882a593Smuzhiyun if ((*config_buf = malloc(tlength)) == NULL) {
2370*4882a593Smuzhiyun RS_DBG("Couldnt malloc buffer for config (%zd)\n", tlength);
2371*4882a593Smuzhiyun close(fd);
2372*4882a593Smuzhiyun return -1;
2373*4882a593Smuzhiyun }
2374*4882a593Smuzhiyun //we may need to parse this config file.
2375*4882a593Smuzhiyun //for easy debug, only get need data.
2376*4882a593Smuzhiyun
2377*4882a593Smuzhiyun if (read(fd, *config_buf, filelen) < (ssize_t) filelen) {
2378*4882a593Smuzhiyun perror("Can't load bt config file");
2379*4882a593Smuzhiyun free(*config_buf);
2380*4882a593Smuzhiyun close(fd);
2381*4882a593Smuzhiyun return -1;
2382*4882a593Smuzhiyun }
2383*4882a593Smuzhiyun
2384*4882a593Smuzhiyun *config_buf = rtk_parse_config_file(*config_buf, &filelen, bt_addr,
2385*4882a593Smuzhiyun config_baud_rate);
2386*4882a593Smuzhiyun util_hexdump((const uint8_t *)*config_buf, filelen);
2387*4882a593Smuzhiyun RS_INFO("Cfg length %u", filelen);
2388*4882a593Smuzhiyun RS_DBG("Get config baud rate from config file:%x",
2389*4882a593Smuzhiyun (unsigned int)*config_baud_rate);
2390*4882a593Smuzhiyun
2391*4882a593Smuzhiyun close(fd);
2392*4882a593Smuzhiyun return filelen;
2393*4882a593Smuzhiyun }
2394*4882a593Smuzhiyun
2395*4882a593Smuzhiyun /**
2396*4882a593Smuzhiyun * Realtek change speed with h5 proto. Using vendor specified command packet to achieve this.
2397*4882a593Smuzhiyun *
2398*4882a593Smuzhiyun * @warning it will waiting 2s for reply.
2399*4882a593Smuzhiyun *
2400*4882a593Smuzhiyun * @param fd uart file descriptor
2401*4882a593Smuzhiyun * @param baudrate the speed want to change
2402*4882a593Smuzhiyun *
2403*4882a593Smuzhiyun */
rtk_vendor_change_speed_h5(int fd,RT_U32 baudrate)2404*4882a593Smuzhiyun int rtk_vendor_change_speed_h5(int fd, RT_U32 baudrate)
2405*4882a593Smuzhiyun {
2406*4882a593Smuzhiyun struct sk_buff *cmd_change_bdrate = NULL;
2407*4882a593Smuzhiyun unsigned char cmd[7] = { 0 };
2408*4882a593Smuzhiyun int retlen;
2409*4882a593Smuzhiyun unsigned char bytes[READ_DATA_SIZE];
2410*4882a593Smuzhiyun struct sigaction sa;
2411*4882a593Smuzhiyun
2412*4882a593Smuzhiyun sa.sa_handler = h5_tinit_sig_alarm;
2413*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
2414*4882a593Smuzhiyun
2415*4882a593Smuzhiyun cmd[0] = 0x17; //ocf
2416*4882a593Smuzhiyun cmd[1] = 0xfc; //ogf, vendor specified
2417*4882a593Smuzhiyun
2418*4882a593Smuzhiyun cmd[2] = 4; //length;
2419*4882a593Smuzhiyun
2420*4882a593Smuzhiyun baudrate = cpu_to_le32(baudrate);
2421*4882a593Smuzhiyun #ifdef BAUDRATE_4BYTES
2422*4882a593Smuzhiyun memcpy((RT_U16 *) & cmd[3], &baudrate, 4);
2423*4882a593Smuzhiyun #else
2424*4882a593Smuzhiyun memcpy((RT_U16 *) & cmd[3], &baudrate, 2);
2425*4882a593Smuzhiyun
2426*4882a593Smuzhiyun cmd[5] = 0;
2427*4882a593Smuzhiyun cmd[6] = 0;
2428*4882a593Smuzhiyun #endif
2429*4882a593Smuzhiyun
2430*4882a593Smuzhiyun RS_DBG("baudrate in change speed command: 0x%x 0x%x 0x%x 0x%x \n",
2431*4882a593Smuzhiyun cmd[3], cmd[4], cmd[5], cmd[6]);
2432*4882a593Smuzhiyun
2433*4882a593Smuzhiyun cmd_change_bdrate =
2434*4882a593Smuzhiyun h5_prepare_pkt(&rtk_hw_cfg, cmd, 7, HCI_COMMAND_PKT);
2435*4882a593Smuzhiyun if (!cmd_change_bdrate) {
2436*4882a593Smuzhiyun RS_ERR("Prepare command packet for change speed fail");
2437*4882a593Smuzhiyun return -1;
2438*4882a593Smuzhiyun }
2439*4882a593Smuzhiyun
2440*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = cmd_change_bdrate;
2441*4882a593Smuzhiyun alarm(1);
2442*4882a593Smuzhiyun write(fd, cmd_change_bdrate->data, cmd_change_bdrate->data_len);
2443*4882a593Smuzhiyun
2444*4882a593Smuzhiyun while (rtk_hw_cfg.link_estab_state == H5_INIT) {
2445*4882a593Smuzhiyun if ((retlen = read_check_rtk(fd, &bytes, READ_DATA_SIZE)) == -1) {
2446*4882a593Smuzhiyun perror("read fail");
2447*4882a593Smuzhiyun return -1;
2448*4882a593Smuzhiyun }
2449*4882a593Smuzhiyun //add pure ack check
2450*4882a593Smuzhiyun h5_recv(&rtk_hw_cfg, &bytes, retlen);
2451*4882a593Smuzhiyun }
2452*4882a593Smuzhiyun
2453*4882a593Smuzhiyun alarm(0);
2454*4882a593Smuzhiyun return 0;
2455*4882a593Smuzhiyun }
2456*4882a593Smuzhiyun
2457*4882a593Smuzhiyun /**
2458*4882a593Smuzhiyun * Init realtek Bluetooth h5 proto. h5 proto is added by realtek in the right kernel.
2459*4882a593Smuzhiyun * Generally there are two steps: h5 sync and h5 config
2460*4882a593Smuzhiyun *
2461*4882a593Smuzhiyun * @param fd uart file descriptor
2462*4882a593Smuzhiyun * @param ti termios struct
2463*4882a593Smuzhiyun *
2464*4882a593Smuzhiyun */
rtk_init_h5(int fd,struct termios * ti)2465*4882a593Smuzhiyun int rtk_init_h5(int fd, struct termios *ti)
2466*4882a593Smuzhiyun {
2467*4882a593Smuzhiyun unsigned char bytes[READ_DATA_SIZE];
2468*4882a593Smuzhiyun struct sigaction sa;
2469*4882a593Smuzhiyun int retlen;
2470*4882a593Smuzhiyun struct itimerval value;
2471*4882a593Smuzhiyun
2472*4882a593Smuzhiyun /* set even parity */
2473*4882a593Smuzhiyun ti->c_cflag |= PARENB;
2474*4882a593Smuzhiyun ti->c_cflag &= ~(PARODD);
2475*4882a593Smuzhiyun if (tcsetattr(fd, TCSANOW, ti) < 0) {
2476*4882a593Smuzhiyun RS_ERR("Can't set port settings");
2477*4882a593Smuzhiyun return -1;
2478*4882a593Smuzhiyun }
2479*4882a593Smuzhiyun
2480*4882a593Smuzhiyun rtk_hw_cfg.h5_max_retries = H5_MAX_RETRY_COUNT;
2481*4882a593Smuzhiyun
2482*4882a593Smuzhiyun alarm(0);
2483*4882a593Smuzhiyun memset(&sa, 0, sizeof(sa));
2484*4882a593Smuzhiyun sa.sa_flags = SA_NOCLDSTOP;
2485*4882a593Smuzhiyun sa.sa_handler = h5_tsync_sig_alarm;
2486*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
2487*4882a593Smuzhiyun
2488*4882a593Smuzhiyun /* h5 sync */
2489*4882a593Smuzhiyun h5_tsync_sig_alarm(0);
2490*4882a593Smuzhiyun rtk_hw_cfg.link_estab_state = H5_SYNC;
2491*4882a593Smuzhiyun while (rtk_hw_cfg.link_estab_state == H5_SYNC) {
2492*4882a593Smuzhiyun if ((retlen = read_check_rtk(fd, &bytes, READ_DATA_SIZE)) == -1) {
2493*4882a593Smuzhiyun RS_ERR("H5 Read Sync Response Failed");
2494*4882a593Smuzhiyun
2495*4882a593Smuzhiyun value.it_value.tv_sec = 0;
2496*4882a593Smuzhiyun value.it_value.tv_usec = 0;
2497*4882a593Smuzhiyun value.it_interval.tv_sec = 0;
2498*4882a593Smuzhiyun value.it_interval.tv_usec = 0;
2499*4882a593Smuzhiyun setitimer(ITIMER_REAL, &value, NULL);
2500*4882a593Smuzhiyun
2501*4882a593Smuzhiyun return -1;
2502*4882a593Smuzhiyun }
2503*4882a593Smuzhiyun h5_recv(&rtk_hw_cfg, &bytes, retlen);
2504*4882a593Smuzhiyun }
2505*4882a593Smuzhiyun
2506*4882a593Smuzhiyun value.it_value.tv_sec = 0;
2507*4882a593Smuzhiyun value.it_value.tv_usec = 0;
2508*4882a593Smuzhiyun value.it_interval.tv_sec = 0;
2509*4882a593Smuzhiyun value.it_interval.tv_usec = 0;
2510*4882a593Smuzhiyun setitimer(ITIMER_REAL, &value, NULL);
2511*4882a593Smuzhiyun
2512*4882a593Smuzhiyun /* h5 config */
2513*4882a593Smuzhiyun sa.sa_handler = h5_tconf_sig_alarm;
2514*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
2515*4882a593Smuzhiyun h5_tconf_sig_alarm(0);
2516*4882a593Smuzhiyun while (rtk_hw_cfg.link_estab_state == H5_CONFIG) {
2517*4882a593Smuzhiyun if ((retlen = read_check_rtk(fd, &bytes, READ_DATA_SIZE)) == -1) {
2518*4882a593Smuzhiyun RS_ERR("H5 Read Config Response Failed");
2519*4882a593Smuzhiyun value.it_value.tv_sec = 0;
2520*4882a593Smuzhiyun value.it_value.tv_usec = 0;
2521*4882a593Smuzhiyun value.it_interval.tv_sec = 0;
2522*4882a593Smuzhiyun value.it_interval.tv_usec = 0;
2523*4882a593Smuzhiyun setitimer(ITIMER_REAL, &value, NULL);
2524*4882a593Smuzhiyun return -1;
2525*4882a593Smuzhiyun }
2526*4882a593Smuzhiyun h5_recv(&rtk_hw_cfg, &bytes, retlen);
2527*4882a593Smuzhiyun }
2528*4882a593Smuzhiyun
2529*4882a593Smuzhiyun value.it_value.tv_sec = 0;
2530*4882a593Smuzhiyun value.it_value.tv_usec = 0;
2531*4882a593Smuzhiyun value.it_interval.tv_sec = 0;
2532*4882a593Smuzhiyun value.it_interval.tv_usec = 0;
2533*4882a593Smuzhiyun setitimer(ITIMER_REAL, &value, NULL);
2534*4882a593Smuzhiyun
2535*4882a593Smuzhiyun rtk_send_pure_ack_down(fd);
2536*4882a593Smuzhiyun RS_DBG("H5 init finished\n");
2537*4882a593Smuzhiyun
2538*4882a593Smuzhiyun rtk_hw_cfg.rom_version_cmd_state = cmd_not_send;
2539*4882a593Smuzhiyun rtk_hw_cfg.hci_version_cmd_state = cmd_not_send;
2540*4882a593Smuzhiyun return 0;
2541*4882a593Smuzhiyun }
2542*4882a593Smuzhiyun
2543*4882a593Smuzhiyun /**
2544*4882a593Smuzhiyun * Download realtek firmware and config file from uart with the proto.
2545*4882a593Smuzhiyun * Parse the content to serval packets follow the proto and then write the packets from uart
2546*4882a593Smuzhiyun *
2547*4882a593Smuzhiyun * @param fd uart file descriptor
2548*4882a593Smuzhiyun * @param buf addr where stor the content of firmware and config file
2549*4882a593Smuzhiyun * @param filesize length of buf
2550*4882a593Smuzhiyun * @param is_sent_changerate if baudrate need to be changed
2551*4882a593Smuzhiyun * @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE
2552*4882a593Smuzhiyun *
2553*4882a593Smuzhiyun */
rtk_download_fw_config(int fd,RT_U8 * buf,size_t filesize,int is_sent_changerate,int proto,struct termios * ti)2554*4882a593Smuzhiyun static int rtk_download_fw_config(int fd, RT_U8 * buf, size_t filesize,
2555*4882a593Smuzhiyun int is_sent_changerate, int proto,
2556*4882a593Smuzhiyun struct termios *ti)
2557*4882a593Smuzhiyun {
2558*4882a593Smuzhiyun uint8_t iCurIndex = 0;
2559*4882a593Smuzhiyun uint8_t iCurLen = 0;
2560*4882a593Smuzhiyun uint8_t iEndIndex = 0;
2561*4882a593Smuzhiyun uint8_t iLastPacketLen = 0;
2562*4882a593Smuzhiyun uint8_t iAdditionPkt = 0;
2563*4882a593Smuzhiyun uint8_t iTotalIndex = 0;
2564*4882a593Smuzhiyun uint8_t iCmdSentNum = 0;
2565*4882a593Smuzhiyun unsigned char *bufpatch;
2566*4882a593Smuzhiyun uint8_t i, j;
2567*4882a593Smuzhiyun
2568*4882a593Smuzhiyun iEndIndex = (uint8_t) ((filesize - 1) / PATCH_DATA_FIELD_MAX_SIZE);
2569*4882a593Smuzhiyun iLastPacketLen = (filesize) % PATCH_DATA_FIELD_MAX_SIZE;
2570*4882a593Smuzhiyun
2571*4882a593Smuzhiyun /* if (is_sent_changerate)
2572*4882a593Smuzhiyun * iCmdSentNum++;
2573*4882a593Smuzhiyun * if (rtk_hw_cfg.rom_version_cmd_state >= cmd_has_sent)
2574*4882a593Smuzhiyun * iCmdSentNum++;
2575*4882a593Smuzhiyun * if (rtk_hw_cfg.hci_version_cmd_state >= cmd_has_sent)
2576*4882a593Smuzhiyun * iCmdSentNum++; */
2577*4882a593Smuzhiyun iCmdSentNum += rtk_hw_cfg.num_of_cmd_sent;
2578*4882a593Smuzhiyun
2579*4882a593Smuzhiyun iAdditionPkt =
2580*4882a593Smuzhiyun (iEndIndex + 1 + iCmdSentNum) % 8 ? (8 -
2581*4882a593Smuzhiyun (iEndIndex + 1 +
2582*4882a593Smuzhiyun iCmdSentNum) % 8) : 0;
2583*4882a593Smuzhiyun iTotalIndex = iAdditionPkt + iEndIndex;
2584*4882a593Smuzhiyun rtk_hw_cfg.total_num = iTotalIndex; //init TotalIndex
2585*4882a593Smuzhiyun
2586*4882a593Smuzhiyun RS_DBG("iEndIndex:%d iLastPacketLen:%d iAdditionpkt:%d\n", iEndIndex,
2587*4882a593Smuzhiyun iLastPacketLen, iAdditionPkt);
2588*4882a593Smuzhiyun
2589*4882a593Smuzhiyun if (iLastPacketLen == 0)
2590*4882a593Smuzhiyun iLastPacketLen = PATCH_DATA_FIELD_MAX_SIZE;
2591*4882a593Smuzhiyun
2592*4882a593Smuzhiyun bufpatch = buf;
2593*4882a593Smuzhiyun
2594*4882a593Smuzhiyun for (i = 0; i <= iTotalIndex; i++) {
2595*4882a593Smuzhiyun /* Index will roll over when it reaches 0x80. */
2596*4882a593Smuzhiyun if (i > 0x7f)
2597*4882a593Smuzhiyun j = (i & 0x7f) + 1;
2598*4882a593Smuzhiyun else
2599*4882a593Smuzhiyun j = i;
2600*4882a593Smuzhiyun
2601*4882a593Smuzhiyun if (i < iEndIndex) {
2602*4882a593Smuzhiyun iCurIndex = j;
2603*4882a593Smuzhiyun iCurLen = PATCH_DATA_FIELD_MAX_SIZE;
2604*4882a593Smuzhiyun } else if (i == iEndIndex) {
2605*4882a593Smuzhiyun /* Send last data packets */
2606*4882a593Smuzhiyun if (i == iTotalIndex)
2607*4882a593Smuzhiyun iCurIndex = j | 0x80;
2608*4882a593Smuzhiyun else
2609*4882a593Smuzhiyun iCurIndex = j;
2610*4882a593Smuzhiyun iCurLen = iLastPacketLen;
2611*4882a593Smuzhiyun } else if (i < iTotalIndex) {
2612*4882a593Smuzhiyun /* Send additional packets */
2613*4882a593Smuzhiyun iCurIndex = j;
2614*4882a593Smuzhiyun bufpatch = NULL;
2615*4882a593Smuzhiyun iCurLen = 0;
2616*4882a593Smuzhiyun RS_DBG("Send additional packet %u", iCurIndex);
2617*4882a593Smuzhiyun } else {
2618*4882a593Smuzhiyun /* Send end packet */
2619*4882a593Smuzhiyun iCurIndex = j | 0x80;
2620*4882a593Smuzhiyun bufpatch = NULL;
2621*4882a593Smuzhiyun iCurLen = 0;
2622*4882a593Smuzhiyun RS_DBG("Send end packet %u", iCurIndex);
2623*4882a593Smuzhiyun }
2624*4882a593Smuzhiyun
2625*4882a593Smuzhiyun if (iCurIndex & 0x80)
2626*4882a593Smuzhiyun RS_DBG("Send FW last command");
2627*4882a593Smuzhiyun
2628*4882a593Smuzhiyun if (proto == HCI_UART_H4) {
2629*4882a593Smuzhiyun iCurIndex = hci_download_patch_h4(fd, iCurIndex,
2630*4882a593Smuzhiyun bufpatch, iCurLen);
2631*4882a593Smuzhiyun if ((iCurIndex != j) && (i != rtk_hw_cfg.total_num)) {
2632*4882a593Smuzhiyun RS_DBG(
2633*4882a593Smuzhiyun "index mismatch j %d, iCurIndex:%d, fail\n",
2634*4882a593Smuzhiyun j, iCurIndex);
2635*4882a593Smuzhiyun return -1;
2636*4882a593Smuzhiyun }
2637*4882a593Smuzhiyun } else if (proto == HCI_UART_3WIRE) {
2638*4882a593Smuzhiyun if (hci_download_patch(fd, iCurIndex, bufpatch, iCurLen,
2639*4882a593Smuzhiyun ti) < 0)
2640*4882a593Smuzhiyun return -1;
2641*4882a593Smuzhiyun }
2642*4882a593Smuzhiyun
2643*4882a593Smuzhiyun if (iCurIndex < iEndIndex) {
2644*4882a593Smuzhiyun bufpatch += PATCH_DATA_FIELD_MAX_SIZE;
2645*4882a593Smuzhiyun }
2646*4882a593Smuzhiyun }
2647*4882a593Smuzhiyun
2648*4882a593Smuzhiyun /* Set last ack packet down */
2649*4882a593Smuzhiyun if (proto == HCI_UART_3WIRE) {
2650*4882a593Smuzhiyun rtk_send_pure_ack_down(fd);
2651*4882a593Smuzhiyun }
2652*4882a593Smuzhiyun
2653*4882a593Smuzhiyun return 0;
2654*4882a593Smuzhiyun }
2655*4882a593Smuzhiyun
2656*4882a593Smuzhiyun /**
2657*4882a593Smuzhiyun * Get realtek Bluetooth firmaware file. The content will be saved in *fw_buf which is malloc here.
2658*4882a593Smuzhiyun * The length malloc here will be lager than length of firmware file if there is a config file.
2659*4882a593Smuzhiyun * The content of config file will copy to the tail of *fw_buf in rtk_config.
2660*4882a593Smuzhiyun *
2661*4882a593Smuzhiyun * @param fw_buf point to the addr where stored the content of firmware.
2662*4882a593Smuzhiyun * @param addi_len length of config file.
2663*4882a593Smuzhiyun * @return length of *fw_buf.
2664*4882a593Smuzhiyun *
2665*4882a593Smuzhiyun */
rtk_get_bt_firmware(struct btrtl_info * btrtl,RT_U8 ** fw_buf)2666*4882a593Smuzhiyun int rtk_get_bt_firmware(struct btrtl_info *btrtl, RT_U8 **fw_buf)
2667*4882a593Smuzhiyun {
2668*4882a593Smuzhiyun const char *filename;
2669*4882a593Smuzhiyun struct stat st;
2670*4882a593Smuzhiyun int fd = -1;
2671*4882a593Smuzhiyun size_t fwsize;
2672*4882a593Smuzhiyun static char firmware_file_name[PATH_MAX] = { 0 };
2673*4882a593Smuzhiyun int ret = 0;
2674*4882a593Smuzhiyun
2675*4882a593Smuzhiyun sprintf(firmware_file_name, "%s", FIRMWARE_DIRECTORY);
2676*4882a593Smuzhiyun strcat(firmware_file_name, btrtl->patch_ent->patch_file);
2677*4882a593Smuzhiyun filename = firmware_file_name;
2678*4882a593Smuzhiyun
2679*4882a593Smuzhiyun if (stat(filename, &st) < 0) {
2680*4882a593Smuzhiyun RS_ERR("Can't access firmware %s, %s", filename,
2681*4882a593Smuzhiyun strerror(errno));
2682*4882a593Smuzhiyun return -1;
2683*4882a593Smuzhiyun }
2684*4882a593Smuzhiyun
2685*4882a593Smuzhiyun fwsize = st.st_size;
2686*4882a593Smuzhiyun
2687*4882a593Smuzhiyun if ((fd = open(filename, O_RDONLY)) < 0) {
2688*4882a593Smuzhiyun RS_ERR("Can't open firmware, errno:%d", errno);
2689*4882a593Smuzhiyun return -1;
2690*4882a593Smuzhiyun }
2691*4882a593Smuzhiyun
2692*4882a593Smuzhiyun if (!(*fw_buf = malloc(fwsize))) {
2693*4882a593Smuzhiyun RS_ERR("Can't alloc memory for fw&config, errno:%d", errno);
2694*4882a593Smuzhiyun close(fd);
2695*4882a593Smuzhiyun return -1;
2696*4882a593Smuzhiyun }
2697*4882a593Smuzhiyun
2698*4882a593Smuzhiyun if (read(fd, *fw_buf, fwsize) < (ssize_t) fwsize) {
2699*4882a593Smuzhiyun free(*fw_buf);
2700*4882a593Smuzhiyun *fw_buf = NULL;
2701*4882a593Smuzhiyun close(fd);
2702*4882a593Smuzhiyun return -1;
2703*4882a593Smuzhiyun }
2704*4882a593Smuzhiyun RS_DBG("Load FW OK");
2705*4882a593Smuzhiyun close(fd);
2706*4882a593Smuzhiyun return fwsize;
2707*4882a593Smuzhiyun }
2708*4882a593Smuzhiyun
2709*4882a593Smuzhiyun //These two function(rtk<-->uart speed transfer) need check Host uart speed at first!!!! IMPORTANT
2710*4882a593Smuzhiyun //add more speed if neccessary
2711*4882a593Smuzhiyun typedef struct _baudrate_ex {
2712*4882a593Smuzhiyun RT_U32 rtk_speed;
2713*4882a593Smuzhiyun int uart_speed;
2714*4882a593Smuzhiyun } baudrate_ex;
2715*4882a593Smuzhiyun
2716*4882a593Smuzhiyun #ifdef BAUDRATE_4BYTES
2717*4882a593Smuzhiyun baudrate_ex baudrates[] = {
2718*4882a593Smuzhiyun #ifdef RTL_8703A_SUPPORT
2719*4882a593Smuzhiyun {0x00004003, 1500000}, /* for rtl8703as */
2720*4882a593Smuzhiyun #endif
2721*4882a593Smuzhiyun {0x0252C014, 115200},
2722*4882a593Smuzhiyun {0x0252C00A, 230400},
2723*4882a593Smuzhiyun {0x05F75004, 921600},
2724*4882a593Smuzhiyun {0x00005004, 1000000},
2725*4882a593Smuzhiyun {0x04928002, 1500000},
2726*4882a593Smuzhiyun {0x01128002, 1500000}, //8761AT
2727*4882a593Smuzhiyun {0x00005002, 2000000},
2728*4882a593Smuzhiyun {0x0000B001, 2500000},
2729*4882a593Smuzhiyun {0x04928001, 3000000},
2730*4882a593Smuzhiyun {0x052A6001, 3500000},
2731*4882a593Smuzhiyun {0x00005001, 4000000},
2732*4882a593Smuzhiyun };
2733*4882a593Smuzhiyun #else
2734*4882a593Smuzhiyun baudrate_ex baudrates[] = {
2735*4882a593Smuzhiyun {0x701d, 115200}
2736*4882a593Smuzhiyun {0x6004, 921600},
2737*4882a593Smuzhiyun {0x4003, 1500000},
2738*4882a593Smuzhiyun {0x5002, 2000000},
2739*4882a593Smuzhiyun {0x8001, 3000000},
2740*4882a593Smuzhiyun {0x9001, 3000000},
2741*4882a593Smuzhiyun {0x7001, 3500000},
2742*4882a593Smuzhiyun {0x5001, 4000000},
2743*4882a593Smuzhiyun };
2744*4882a593Smuzhiyun #endif
2745*4882a593Smuzhiyun
2746*4882a593Smuzhiyun /**
2747*4882a593Smuzhiyun * Change realtek Bluetooth speed to uart speed. It is matching in the struct baudrates:
2748*4882a593Smuzhiyun *
2749*4882a593Smuzhiyun * @code
2750*4882a593Smuzhiyun * baudrate_ex baudrates[] =
2751*4882a593Smuzhiyun * {
2752*4882a593Smuzhiyun * {0x7001, 3500000},
2753*4882a593Smuzhiyun * {0x6004, 921600},
2754*4882a593Smuzhiyun * {0x4003, 1500000},
2755*4882a593Smuzhiyun * {0x5001, 4000000},
2756*4882a593Smuzhiyun * {0x5002, 2000000},
2757*4882a593Smuzhiyun * {0x8001, 3000000},
2758*4882a593Smuzhiyun * {0x701d, 115200}
2759*4882a593Smuzhiyun * };
2760*4882a593Smuzhiyun * @endcode
2761*4882a593Smuzhiyun *
2762*4882a593Smuzhiyun * If there is no match in baudrates, uart speed will be set as #115200.
2763*4882a593Smuzhiyun *
2764*4882a593Smuzhiyun * @param rtk_speed realtek Bluetooth speed
2765*4882a593Smuzhiyun * @param uart_speed uart speed
2766*4882a593Smuzhiyun *
2767*4882a593Smuzhiyun */
rtk_speed_to_uart_speed(RT_U32 rtk_speed,RT_U32 * uart_speed)2768*4882a593Smuzhiyun static void rtk_speed_to_uart_speed(RT_U32 rtk_speed, RT_U32 * uart_speed)
2769*4882a593Smuzhiyun {
2770*4882a593Smuzhiyun *uart_speed = 115200;
2771*4882a593Smuzhiyun
2772*4882a593Smuzhiyun unsigned int i;
2773*4882a593Smuzhiyun for (i = 0; i < sizeof(baudrates) / sizeof(baudrate_ex); i++) {
2774*4882a593Smuzhiyun if (baudrates[i].rtk_speed == rtk_speed) {
2775*4882a593Smuzhiyun *uart_speed = baudrates[i].uart_speed;
2776*4882a593Smuzhiyun return;
2777*4882a593Smuzhiyun }
2778*4882a593Smuzhiyun }
2779*4882a593Smuzhiyun return;
2780*4882a593Smuzhiyun }
2781*4882a593Smuzhiyun
2782*4882a593Smuzhiyun /**
2783*4882a593Smuzhiyun * Change uart speed to realtek Bluetooth speed. It is matching in the struct baudrates:
2784*4882a593Smuzhiyun *
2785*4882a593Smuzhiyun * @code
2786*4882a593Smuzhiyun * baudrate_ex baudrates[] =
2787*4882a593Smuzhiyun * {
2788*4882a593Smuzhiyun * {0x7001, 3500000},
2789*4882a593Smuzhiyun * {0x6004, 921600},
2790*4882a593Smuzhiyun * {0x4003, 1500000},
2791*4882a593Smuzhiyun * {0x5001, 4000000},
2792*4882a593Smuzhiyun * {0x5002, 2000000},
2793*4882a593Smuzhiyun * {0x8001, 3000000},
2794*4882a593Smuzhiyun * {0x701d, 115200}
2795*4882a593Smuzhiyun * };
2796*4882a593Smuzhiyun * @endcode
2797*4882a593Smuzhiyun *
2798*4882a593Smuzhiyun * If there is no match in baudrates, realtek Bluetooth speed will be set as #0x701D.
2799*4882a593Smuzhiyun *
2800*4882a593Smuzhiyun * @param uart_speed uart speed
2801*4882a593Smuzhiyun * @param rtk_speed realtek Bluetooth speed
2802*4882a593Smuzhiyun *
2803*4882a593Smuzhiyun */
uart_speed_to_rtk_speed(int uart_speed,RT_U32 * rtk_speed)2804*4882a593Smuzhiyun static inline void uart_speed_to_rtk_speed(int uart_speed, RT_U32 * rtk_speed)
2805*4882a593Smuzhiyun {
2806*4882a593Smuzhiyun *rtk_speed = 0x701D;
2807*4882a593Smuzhiyun
2808*4882a593Smuzhiyun unsigned int i;
2809*4882a593Smuzhiyun for (i = 0; i < sizeof(baudrates) / sizeof(baudrate_ex); i++) {
2810*4882a593Smuzhiyun if (baudrates[i].uart_speed == uart_speed) {
2811*4882a593Smuzhiyun *rtk_speed = baudrates[i].rtk_speed;
2812*4882a593Smuzhiyun return;
2813*4882a593Smuzhiyun }
2814*4882a593Smuzhiyun }
2815*4882a593Smuzhiyun
2816*4882a593Smuzhiyun return;
2817*4882a593Smuzhiyun }
2818*4882a593Smuzhiyun
rtk_get_chip_type_timeout(int sig)2819*4882a593Smuzhiyun static void rtk_get_chip_type_timeout(int sig)
2820*4882a593Smuzhiyun {
2821*4882a593Smuzhiyun static int retries = 0;
2822*4882a593Smuzhiyun int len = 0;
2823*4882a593Smuzhiyun struct btrtl_info *btrtl = &rtk_hw_cfg;
2824*4882a593Smuzhiyun
2825*4882a593Smuzhiyun RS_INFO("RTK get HCI_VENDOR_READ_RTK_CHIP_TYPE_Command\n");
2826*4882a593Smuzhiyun if (retries < btrtl->h5_max_retries) {
2827*4882a593Smuzhiyun RS_DBG("rtk get chip type timerout, retry:%d\n", retries);
2828*4882a593Smuzhiyun if (btrtl->host_last_cmd) {
2829*4882a593Smuzhiyun len = write(btrtl->serial_fd,
2830*4882a593Smuzhiyun btrtl->host_last_cmd->data,
2831*4882a593Smuzhiyun btrtl->host_last_cmd->data_len);
2832*4882a593Smuzhiyun }
2833*4882a593Smuzhiyun retries++;
2834*4882a593Smuzhiyun alarm(3);
2835*4882a593Smuzhiyun return;
2836*4882a593Smuzhiyun }
2837*4882a593Smuzhiyun tcflush(btrtl->serial_fd, TCIOFLUSH);
2838*4882a593Smuzhiyun RS_ERR("rtk get chip type cmd complete event timed out\n");
2839*4882a593Smuzhiyun exit(1);
2840*4882a593Smuzhiyun }
2841*4882a593Smuzhiyun
rtk_get_chip_type(int dd)2842*4882a593Smuzhiyun void rtk_get_chip_type(int dd)
2843*4882a593Smuzhiyun {
2844*4882a593Smuzhiyun unsigned char bytes[READ_DATA_SIZE];
2845*4882a593Smuzhiyun int retlen;
2846*4882a593Smuzhiyun struct sigaction sa;
2847*4882a593Smuzhiyun /* 0xB000A094 */
2848*4882a593Smuzhiyun unsigned char cmd_buff[] = {0x61, 0xfc,
2849*4882a593Smuzhiyun 0x05, 0x00, 0x94, 0xa0, 0x00, 0xb0};
2850*4882a593Smuzhiyun struct sk_buff *nskb;
2851*4882a593Smuzhiyun struct btrtl_info *btrtl = &rtk_hw_cfg;
2852*4882a593Smuzhiyun
2853*4882a593Smuzhiyun nskb = h5_prepare_pkt(btrtl, cmd_buff, sizeof(cmd_buff),
2854*4882a593Smuzhiyun HCI_COMMAND_PKT);
2855*4882a593Smuzhiyun if (btrtl->host_last_cmd){
2856*4882a593Smuzhiyun skb_free(btrtl->host_last_cmd);
2857*4882a593Smuzhiyun btrtl->host_last_cmd = NULL;
2858*4882a593Smuzhiyun }
2859*4882a593Smuzhiyun
2860*4882a593Smuzhiyun btrtl->host_last_cmd = nskb;
2861*4882a593Smuzhiyun
2862*4882a593Smuzhiyun write(dd, nskb->data, nskb->data_len);
2863*4882a593Smuzhiyun RS_INFO("RTK send HCI_VENDOR_READ_CHIP_TYPE_Command\n");
2864*4882a593Smuzhiyun
2865*4882a593Smuzhiyun alarm(0);
2866*4882a593Smuzhiyun memset(&sa, 0, sizeof(sa));
2867*4882a593Smuzhiyun sa.sa_flags = SA_NOCLDSTOP;
2868*4882a593Smuzhiyun sa.sa_handler = rtk_get_chip_type_timeout;
2869*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
2870*4882a593Smuzhiyun
2871*4882a593Smuzhiyun alarm(3);
2872*4882a593Smuzhiyun while (btrtl->chip_type_cmd_state != event_received) {
2873*4882a593Smuzhiyun if ((retlen = read_check_rtk(dd, &bytes, READ_DATA_SIZE)) == -1) {
2874*4882a593Smuzhiyun perror("rtk get chip type: read fail");
2875*4882a593Smuzhiyun return;
2876*4882a593Smuzhiyun }
2877*4882a593Smuzhiyun h5_recv(btrtl, &bytes, retlen);
2878*4882a593Smuzhiyun }
2879*4882a593Smuzhiyun alarm(0);
2880*4882a593Smuzhiyun return;
2881*4882a593Smuzhiyun }
2882*4882a593Smuzhiyun
rtk_get_eversion_timeout(int sig)2883*4882a593Smuzhiyun static void rtk_get_eversion_timeout(int sig)
2884*4882a593Smuzhiyun {
2885*4882a593Smuzhiyun static int retries = 0;
2886*4882a593Smuzhiyun int len = 0;
2887*4882a593Smuzhiyun
2888*4882a593Smuzhiyun RS_DBG("RTK get HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n");
2889*4882a593Smuzhiyun if (retries < rtk_hw_cfg.h5_max_retries) {
2890*4882a593Smuzhiyun RS_DBG("rtk get eversion timerout, retry:%d\n", retries);
2891*4882a593Smuzhiyun if (rtk_hw_cfg.host_last_cmd) {
2892*4882a593Smuzhiyun len = write(rtk_hw_cfg.serial_fd,
2893*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd->data,
2894*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd->data_len);
2895*4882a593Smuzhiyun }
2896*4882a593Smuzhiyun retries++;
2897*4882a593Smuzhiyun alarm(3);
2898*4882a593Smuzhiyun return;
2899*4882a593Smuzhiyun }
2900*4882a593Smuzhiyun tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH);
2901*4882a593Smuzhiyun RS_ERR("rtk get eversion cmd complete event timed out\n");
2902*4882a593Smuzhiyun exit(1);
2903*4882a593Smuzhiyun }
2904*4882a593Smuzhiyun
2905*4882a593Smuzhiyun /**
2906*4882a593Smuzhiyun * Send vendor cmd to get eversion: 0xfc6d
2907*4882a593Smuzhiyun * If Rom code does not support this cmd, use default.
2908*4882a593Smuzhiyun */
rtk_get_eversion(int dd)2909*4882a593Smuzhiyun void rtk_get_eversion(int dd)
2910*4882a593Smuzhiyun {
2911*4882a593Smuzhiyun unsigned char bytes[READ_DATA_SIZE];
2912*4882a593Smuzhiyun int retlen;
2913*4882a593Smuzhiyun struct sigaction sa;
2914*4882a593Smuzhiyun unsigned char read_rom_patch_cmd[3] = { 0x6d, 0xfc, 00 };
2915*4882a593Smuzhiyun struct sk_buff *nskb =
2916*4882a593Smuzhiyun h5_prepare_pkt(&rtk_hw_cfg, read_rom_patch_cmd, 3, HCI_COMMAND_PKT);
2917*4882a593Smuzhiyun
2918*4882a593Smuzhiyun if (rtk_hw_cfg.host_last_cmd) {
2919*4882a593Smuzhiyun skb_free(rtk_hw_cfg.host_last_cmd);
2920*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = NULL;
2921*4882a593Smuzhiyun }
2922*4882a593Smuzhiyun
2923*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = nskb;
2924*4882a593Smuzhiyun
2925*4882a593Smuzhiyun write(dd, nskb->data, nskb->data_len);
2926*4882a593Smuzhiyun rtk_hw_cfg.rom_version_cmd_state = cmd_has_sent;
2927*4882a593Smuzhiyun RS_DBG("RTK send HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n");
2928*4882a593Smuzhiyun
2929*4882a593Smuzhiyun alarm(0);
2930*4882a593Smuzhiyun memset(&sa, 0, sizeof(sa));
2931*4882a593Smuzhiyun sa.sa_flags = SA_NOCLDSTOP;
2932*4882a593Smuzhiyun sa.sa_handler = rtk_get_eversion_timeout;
2933*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
2934*4882a593Smuzhiyun
2935*4882a593Smuzhiyun alarm(3);
2936*4882a593Smuzhiyun while (rtk_hw_cfg.rom_version_cmd_state != event_received) {
2937*4882a593Smuzhiyun if ((retlen = read_check_rtk(dd, &bytes, READ_DATA_SIZE)) == -1) {
2938*4882a593Smuzhiyun perror("rtk get eversion: read fail");
2939*4882a593Smuzhiyun return;
2940*4882a593Smuzhiyun }
2941*4882a593Smuzhiyun h5_recv(&rtk_hw_cfg, &bytes, retlen);
2942*4882a593Smuzhiyun }
2943*4882a593Smuzhiyun alarm(0);
2944*4882a593Smuzhiyun return;
2945*4882a593Smuzhiyun }
2946*4882a593Smuzhiyun
rtk_get_lmp_version_timeout(int sig)2947*4882a593Smuzhiyun static void rtk_get_lmp_version_timeout(int sig)
2948*4882a593Smuzhiyun {
2949*4882a593Smuzhiyun static int retries = 0;
2950*4882a593Smuzhiyun RS_DBG("RTK get HCI_VENDOR_READ_RTK_LMP_VERISION_Command\n");
2951*4882a593Smuzhiyun if (retries < rtk_hw_cfg.h5_max_retries) {
2952*4882a593Smuzhiyun RS_DBG("rtk get lmp version timeout, retry: %d\n", retries);
2953*4882a593Smuzhiyun if (rtk_hw_cfg.host_last_cmd) {
2954*4882a593Smuzhiyun int len = write(rtk_hw_cfg.serial_fd,
2955*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd->data,
2956*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd->data_len);
2957*4882a593Smuzhiyun }
2958*4882a593Smuzhiyun retries++;
2959*4882a593Smuzhiyun alarm(3);
2960*4882a593Smuzhiyun return;
2961*4882a593Smuzhiyun }
2962*4882a593Smuzhiyun tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH);
2963*4882a593Smuzhiyun RS_ERR("rtk get lmp version cmd complete event timed out\n");
2964*4882a593Smuzhiyun exit(1);
2965*4882a593Smuzhiyun }
2966*4882a593Smuzhiyun
rtk_get_lmp_version(int dd)2967*4882a593Smuzhiyun void rtk_get_lmp_version(int dd)
2968*4882a593Smuzhiyun {
2969*4882a593Smuzhiyun unsigned char bytes[READ_DATA_SIZE];
2970*4882a593Smuzhiyun int retlen;
2971*4882a593Smuzhiyun struct sigaction sa;
2972*4882a593Smuzhiyun unsigned char read_rom_patch_cmd[3] = { 0x01, 0x10, 00 };
2973*4882a593Smuzhiyun struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, read_rom_patch_cmd, 3, HCI_COMMAND_PKT); //data:len+head:4
2974*4882a593Smuzhiyun
2975*4882a593Smuzhiyun if (rtk_hw_cfg.host_last_cmd) {
2976*4882a593Smuzhiyun skb_free(rtk_hw_cfg.host_last_cmd);
2977*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = NULL;
2978*4882a593Smuzhiyun }
2979*4882a593Smuzhiyun
2980*4882a593Smuzhiyun rtk_hw_cfg.host_last_cmd = nskb;
2981*4882a593Smuzhiyun
2982*4882a593Smuzhiyun write(dd, nskb->data, nskb->data_len);
2983*4882a593Smuzhiyun rtk_hw_cfg.hci_version_cmd_state = cmd_has_sent;
2984*4882a593Smuzhiyun RS_DBG("RTK send HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n");
2985*4882a593Smuzhiyun
2986*4882a593Smuzhiyun alarm(0);
2987*4882a593Smuzhiyun memset(&sa, 0, sizeof(sa));
2988*4882a593Smuzhiyun sa.sa_flags = SA_NOCLDSTOP;
2989*4882a593Smuzhiyun sa.sa_handler = rtk_get_lmp_version_timeout;
2990*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
2991*4882a593Smuzhiyun
2992*4882a593Smuzhiyun alarm(3);
2993*4882a593Smuzhiyun while (rtk_hw_cfg.hci_version_cmd_state != event_received) {
2994*4882a593Smuzhiyun if ((retlen = read_check_rtk(dd, &bytes, READ_DATA_SIZE)) == -1) {
2995*4882a593Smuzhiyun perror("read fail");
2996*4882a593Smuzhiyun return;
2997*4882a593Smuzhiyun }
2998*4882a593Smuzhiyun h5_recv(&rtk_hw_cfg, &bytes, retlen);
2999*4882a593Smuzhiyun }
3000*4882a593Smuzhiyun alarm(0);
3001*4882a593Smuzhiyun return;
3002*4882a593Smuzhiyun }
3003*4882a593Smuzhiyun
3004*4882a593Smuzhiyun static int rtk_max_retries = 5;
3005*4882a593Smuzhiyun
rtk_local_ver_sig_alarm(int sig)3006*4882a593Smuzhiyun static void rtk_local_ver_sig_alarm(int sig)
3007*4882a593Smuzhiyun {
3008*4882a593Smuzhiyun uint8_t cmd[4] = { 0x01, 0x01, 0x10, 0x00 };
3009*4882a593Smuzhiyun static int retries;
3010*4882a593Smuzhiyun
3011*4882a593Smuzhiyun if (retries < rtk_max_retries) {
3012*4882a593Smuzhiyun retries++;
3013*4882a593Smuzhiyun if (write(rtk_hw_cfg.serial_fd, cmd, sizeof(cmd)) < 0)
3014*4882a593Smuzhiyun return;
3015*4882a593Smuzhiyun alarm(1);
3016*4882a593Smuzhiyun return;
3017*4882a593Smuzhiyun }
3018*4882a593Smuzhiyun
3019*4882a593Smuzhiyun tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH);
3020*4882a593Smuzhiyun RS_ERR("init timed out, read local ver fails");
3021*4882a593Smuzhiyun exit(1);
3022*4882a593Smuzhiyun }
3023*4882a593Smuzhiyun
rtk_hci_local_ver(int fd)3024*4882a593Smuzhiyun static void rtk_hci_local_ver(int fd)
3025*4882a593Smuzhiyun {
3026*4882a593Smuzhiyun struct sigaction sa;
3027*4882a593Smuzhiyun uint8_t result[258];
3028*4882a593Smuzhiyun int ret;
3029*4882a593Smuzhiyun
3030*4882a593Smuzhiyun alarm(0);
3031*4882a593Smuzhiyun
3032*4882a593Smuzhiyun memset(&sa, 0, sizeof(sa));
3033*4882a593Smuzhiyun sa.sa_flags = SA_NOCLDSTOP;
3034*4882a593Smuzhiyun sa.sa_handler = rtk_local_ver_sig_alarm;
3035*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
3036*4882a593Smuzhiyun
3037*4882a593Smuzhiyun rtk_local_ver_sig_alarm(0);
3038*4882a593Smuzhiyun
3039*4882a593Smuzhiyun while (1) {
3040*4882a593Smuzhiyun ret = read_hci_evt(fd, result, 0x0e);
3041*4882a593Smuzhiyun /* break down is not needed if read fails, because the program
3042*4882a593Smuzhiyun * will exit when alarm timeout
3043*4882a593Smuzhiyun */
3044*4882a593Smuzhiyun if (ret < 0)
3045*4882a593Smuzhiyun RS_ERR("%s: Read HCI event error.", __func__);
3046*4882a593Smuzhiyun else
3047*4882a593Smuzhiyun break;
3048*4882a593Smuzhiyun }
3049*4882a593Smuzhiyun
3050*4882a593Smuzhiyun /* Cancel pending alarm */
3051*4882a593Smuzhiyun alarm(0);
3052*4882a593Smuzhiyun
3053*4882a593Smuzhiyun if (ret != 15) {
3054*4882a593Smuzhiyun RS_ERR("%s: incorrect complete event, len %u", __func__, ret);
3055*4882a593Smuzhiyun exit(1);
3056*4882a593Smuzhiyun }
3057*4882a593Smuzhiyun
3058*4882a593Smuzhiyun if (result[6]) {
3059*4882a593Smuzhiyun RS_ERR("%s: status is %u", __func__, result[6]);
3060*4882a593Smuzhiyun exit(1);
3061*4882a593Smuzhiyun }
3062*4882a593Smuzhiyun
3063*4882a593Smuzhiyun rtk_hw_cfg.hci_rev = (uint32_t)result[9] << 8 | result[8];
3064*4882a593Smuzhiyun rtk_hw_cfg.lmp_subver = (uint32_t)result[14] << 8 | result[13];
3065*4882a593Smuzhiyun }
3066*4882a593Smuzhiyun
rtk_rom_ver_sig_alarm(int sig)3067*4882a593Smuzhiyun static void rtk_rom_ver_sig_alarm(int sig)
3068*4882a593Smuzhiyun {
3069*4882a593Smuzhiyun uint8_t cmd[4] = { 0x01, 0x6d, 0xfc, 0x00 };
3070*4882a593Smuzhiyun static int retries;
3071*4882a593Smuzhiyun
3072*4882a593Smuzhiyun if (retries < rtk_max_retries) {
3073*4882a593Smuzhiyun retries++;
3074*4882a593Smuzhiyun if (write(rtk_hw_cfg.serial_fd, cmd, sizeof(cmd)) < 0)
3075*4882a593Smuzhiyun return;
3076*4882a593Smuzhiyun alarm(1);
3077*4882a593Smuzhiyun return;
3078*4882a593Smuzhiyun }
3079*4882a593Smuzhiyun
3080*4882a593Smuzhiyun tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH);
3081*4882a593Smuzhiyun RS_ERR("init timed out, read rom ver fails");
3082*4882a593Smuzhiyun exit(1);
3083*4882a593Smuzhiyun }
3084*4882a593Smuzhiyun
rtk_hci_rom_ver(int fd)3085*4882a593Smuzhiyun static void rtk_hci_rom_ver(int fd)
3086*4882a593Smuzhiyun {
3087*4882a593Smuzhiyun struct sigaction sa;
3088*4882a593Smuzhiyun uint8_t result[256];
3089*4882a593Smuzhiyun int ret;
3090*4882a593Smuzhiyun
3091*4882a593Smuzhiyun alarm(0);
3092*4882a593Smuzhiyun
3093*4882a593Smuzhiyun memset(&sa, 0, sizeof(sa));
3094*4882a593Smuzhiyun sa.sa_flags = SA_NOCLDSTOP;
3095*4882a593Smuzhiyun sa.sa_handler = rtk_rom_ver_sig_alarm;
3096*4882a593Smuzhiyun sigaction(SIGALRM, &sa, NULL);
3097*4882a593Smuzhiyun
3098*4882a593Smuzhiyun rtk_rom_ver_sig_alarm(0);
3099*4882a593Smuzhiyun
3100*4882a593Smuzhiyun while (1) {
3101*4882a593Smuzhiyun ret = read_hci_evt(fd, result, 0x0e);
3102*4882a593Smuzhiyun /* break down is not needed if read fails, because the program
3103*4882a593Smuzhiyun * will exit when alarm timeout
3104*4882a593Smuzhiyun */
3105*4882a593Smuzhiyun if (ret < 0)
3106*4882a593Smuzhiyun RS_ERR("%s: Read HCI event error.", __func__);
3107*4882a593Smuzhiyun else
3108*4882a593Smuzhiyun break;
3109*4882a593Smuzhiyun }
3110*4882a593Smuzhiyun
3111*4882a593Smuzhiyun /* Cancel pending alarm */
3112*4882a593Smuzhiyun alarm(0);
3113*4882a593Smuzhiyun
3114*4882a593Smuzhiyun if (ret != 8) {
3115*4882a593Smuzhiyun RS_ERR("%s: incorrect complete event, len %u", __func__, ret);
3116*4882a593Smuzhiyun exit(1);
3117*4882a593Smuzhiyun }
3118*4882a593Smuzhiyun
3119*4882a593Smuzhiyun if (result[6]) {
3120*4882a593Smuzhiyun RS_ERR("%s: status is %u", __func__, result[6]);
3121*4882a593Smuzhiyun rtk_hw_cfg.eversion = 0;
3122*4882a593Smuzhiyun } else
3123*4882a593Smuzhiyun rtk_hw_cfg.eversion = result[7];
3124*4882a593Smuzhiyun }
3125*4882a593Smuzhiyun
rtk_get_fw_project_id(uint8_t * p_buf)3126*4882a593Smuzhiyun uint8_t rtk_get_fw_project_id(uint8_t * p_buf)
3127*4882a593Smuzhiyun {
3128*4882a593Smuzhiyun uint8_t opcode;
3129*4882a593Smuzhiyun uint8_t len;
3130*4882a593Smuzhiyun uint8_t data = 0;
3131*4882a593Smuzhiyun
3132*4882a593Smuzhiyun do {
3133*4882a593Smuzhiyun opcode = *p_buf;
3134*4882a593Smuzhiyun len = *(p_buf - 1);
3135*4882a593Smuzhiyun if (opcode == 0x00) {
3136*4882a593Smuzhiyun if (len == 1) {
3137*4882a593Smuzhiyun data = *(p_buf - 2);
3138*4882a593Smuzhiyun RS_DBG
3139*4882a593Smuzhiyun ("rtk_get_fw_project_id: opcode %d, len %d, data %d",
3140*4882a593Smuzhiyun opcode, len, data);
3141*4882a593Smuzhiyun break;
3142*4882a593Smuzhiyun } else {
3143*4882a593Smuzhiyun RS_ERR("rtk_get_fw_project_id: invalid len %d",
3144*4882a593Smuzhiyun len);
3145*4882a593Smuzhiyun }
3146*4882a593Smuzhiyun }
3147*4882a593Smuzhiyun p_buf -= len + 2;
3148*4882a593Smuzhiyun } while (*p_buf != 0xFF);
3149*4882a593Smuzhiyun
3150*4882a593Smuzhiyun return data;
3151*4882a593Smuzhiyun }
3152*4882a593Smuzhiyun
rtk_get_patch_entry(void)3153*4882a593Smuzhiyun struct rtk_epatch_entry *rtk_get_patch_entry(void)
3154*4882a593Smuzhiyun {
3155*4882a593Smuzhiyun uint16_t i;
3156*4882a593Smuzhiyun struct rtk_epatch *patch;
3157*4882a593Smuzhiyun struct rtk_epatch_entry *entry;
3158*4882a593Smuzhiyun uint8_t *p;
3159*4882a593Smuzhiyun uint16_t chip_id;
3160*4882a593Smuzhiyun uint32_t tmp;
3161*4882a593Smuzhiyun
3162*4882a593Smuzhiyun patch = (struct rtk_epatch *)rtk_hw_cfg.fw_buf;
3163*4882a593Smuzhiyun entry = (struct rtk_epatch_entry *)malloc(sizeof(*entry));
3164*4882a593Smuzhiyun if (!entry) {
3165*4882a593Smuzhiyun RS_ERR("failed to allocate mem for patch entry");
3166*4882a593Smuzhiyun return NULL;
3167*4882a593Smuzhiyun }
3168*4882a593Smuzhiyun
3169*4882a593Smuzhiyun patch->number_of_patch = le16_to_cpu(patch->number_of_patch);
3170*4882a593Smuzhiyun
3171*4882a593Smuzhiyun RS_DBG("fw_ver 0x%08x, patch_num %d",
3172*4882a593Smuzhiyun le32_to_cpu(patch->fw_version), patch->number_of_patch);
3173*4882a593Smuzhiyun
3174*4882a593Smuzhiyun for (i = 0; i < patch->number_of_patch; i++) {
3175*4882a593Smuzhiyun RS_DBG("chip id 0x%04x",
3176*4882a593Smuzhiyun get_unaligned_le16(rtk_hw_cfg.fw_buf + 14 + 2 * i));
3177*4882a593Smuzhiyun if (get_unaligned_le16(rtk_hw_cfg.fw_buf + 14 + 2 * i) ==
3178*4882a593Smuzhiyun rtk_hw_cfg.eversion + 1) {
3179*4882a593Smuzhiyun entry->chipID = rtk_hw_cfg.eversion + 1;
3180*4882a593Smuzhiyun entry->patch_length =
3181*4882a593Smuzhiyun get_unaligned_le16(rtk_hw_cfg.fw_buf + 14 +
3182*4882a593Smuzhiyun 2 * patch->number_of_patch +
3183*4882a593Smuzhiyun 2 * i);
3184*4882a593Smuzhiyun entry->start_offset =
3185*4882a593Smuzhiyun get_unaligned_le32(rtk_hw_cfg.fw_buf + 14 +
3186*4882a593Smuzhiyun 4 * patch->number_of_patch +
3187*4882a593Smuzhiyun 4 * i);
3188*4882a593Smuzhiyun RS_DBG("patch length is 0x%x", entry->patch_length);
3189*4882a593Smuzhiyun RS_DBG("start offset is 0x%x", entry->start_offset);
3190*4882a593Smuzhiyun
3191*4882a593Smuzhiyun entry->svn_ver = get_unaligned_le32(rtk_hw_cfg.fw_buf +
3192*4882a593Smuzhiyun entry->start_offset +
3193*4882a593Smuzhiyun entry->patch_length - 8);
3194*4882a593Smuzhiyun entry->coex_ver = get_unaligned_le32(rtk_hw_cfg.fw_buf +
3195*4882a593Smuzhiyun entry->start_offset +
3196*4882a593Smuzhiyun entry->patch_length - 12);
3197*4882a593Smuzhiyun
3198*4882a593Smuzhiyun RS_INFO("Svn version: %8d\n", entry->svn_ver);
3199*4882a593Smuzhiyun tmp = ((entry->coex_ver >> 16) & 0x7ff) +
3200*4882a593Smuzhiyun (entry->coex_ver >> 27) * 10000;
3201*4882a593Smuzhiyun RS_INFO("Coexistence: BTCOEX_20%06d-%04x\n", tmp,
3202*4882a593Smuzhiyun (entry->coex_ver & 0xffff));
3203*4882a593Smuzhiyun
3204*4882a593Smuzhiyun break;
3205*4882a593Smuzhiyun }
3206*4882a593Smuzhiyun
3207*4882a593Smuzhiyun }
3208*4882a593Smuzhiyun
3209*4882a593Smuzhiyun if (i == patch->number_of_patch) {
3210*4882a593Smuzhiyun RS_ERR("failed to get entry");
3211*4882a593Smuzhiyun free(entry);
3212*4882a593Smuzhiyun entry = NULL;
3213*4882a593Smuzhiyun }
3214*4882a593Smuzhiyun
3215*4882a593Smuzhiyun return entry;
3216*4882a593Smuzhiyun }
3217*4882a593Smuzhiyun
rtk_get_final_patch(int fd,int proto)3218*4882a593Smuzhiyun void rtk_get_final_patch(int fd, int proto)
3219*4882a593Smuzhiyun {
3220*4882a593Smuzhiyun struct btrtl_info *rtl = &rtk_hw_cfg;
3221*4882a593Smuzhiyun uint8_t proj_id = 0;
3222*4882a593Smuzhiyun struct rtk_epatch_entry *entry = NULL;
3223*4882a593Smuzhiyun struct rtk_epatch *patch = (struct rtk_epatch *)rtl->fw_buf;
3224*4882a593Smuzhiyun uint32_t svn_ver, coex_ver, tmp;
3225*4882a593Smuzhiyun
3226*4882a593Smuzhiyun if ((proto == HCI_UART_H4) ||
3227*4882a593Smuzhiyun ((proto == HCI_UART_3WIRE) && (rtl->lmp_subver == ROM_LMP_8723a))) {
3228*4882a593Smuzhiyun if (memcmp(rtl->fw_buf, RTK_EPATCH_SIGNATURE, 8) == 0) {
3229*4882a593Smuzhiyun RS_ERR("Check signature error!");
3230*4882a593Smuzhiyun rtl->dl_fw_flag = 0;
3231*4882a593Smuzhiyun goto free_buf;
3232*4882a593Smuzhiyun } else {
3233*4882a593Smuzhiyun rtl->total_len = rtl->config_len + rtl->fw_len;
3234*4882a593Smuzhiyun if (!(rtl->total_buf = malloc(rtl->total_len))) {
3235*4882a593Smuzhiyun RS_ERR("Can't alloc mem for fw/config, errno:%d",
3236*4882a593Smuzhiyun errno);
3237*4882a593Smuzhiyun rtl->dl_fw_flag = 0;
3238*4882a593Smuzhiyun rtl->total_len = 0;
3239*4882a593Smuzhiyun goto free_buf;
3240*4882a593Smuzhiyun } else {
3241*4882a593Smuzhiyun RS_DBG("fw copy directy");
3242*4882a593Smuzhiyun
3243*4882a593Smuzhiyun svn_ver = get_unaligned_le32(
3244*4882a593Smuzhiyun rtl->fw_buf + rtl->fw_len - 8);
3245*4882a593Smuzhiyun coex_ver = get_unaligned_le32(
3246*4882a593Smuzhiyun rtl->fw_buf + rtl->fw_len - 12);
3247*4882a593Smuzhiyun
3248*4882a593Smuzhiyun RS_INFO("Svn version: %8d\n", svn_ver);
3249*4882a593Smuzhiyun tmp = ((coex_ver >> 16) & 0x7ff) +
3250*4882a593Smuzhiyun (coex_ver >> 27) * 10000;
3251*4882a593Smuzhiyun RS_INFO("Coexistence: BTCOEX_20%06d-%04x\n", tmp,
3252*4882a593Smuzhiyun (coex_ver & 0xffff));
3253*4882a593Smuzhiyun
3254*4882a593Smuzhiyun memcpy(rtl->total_buf, rtl->fw_buf,
3255*4882a593Smuzhiyun rtl->fw_len);
3256*4882a593Smuzhiyun if (rtl->config_len)
3257*4882a593Smuzhiyun memcpy(rtl->total_buf +
3258*4882a593Smuzhiyun rtl->fw_len,
3259*4882a593Smuzhiyun rtl->config_buf,
3260*4882a593Smuzhiyun rtl->config_len);
3261*4882a593Smuzhiyun rtl->dl_fw_flag = 1;
3262*4882a593Smuzhiyun goto free_buf;
3263*4882a593Smuzhiyun }
3264*4882a593Smuzhiyun }
3265*4882a593Smuzhiyun }
3266*4882a593Smuzhiyun
3267*4882a593Smuzhiyun if (memcmp(rtl->fw_buf, RTK_EPATCH_SIGNATURE, 8)) {
3268*4882a593Smuzhiyun RS_DBG("check signature error!");
3269*4882a593Smuzhiyun rtl->dl_fw_flag = 0;
3270*4882a593Smuzhiyun goto free_buf;
3271*4882a593Smuzhiyun }
3272*4882a593Smuzhiyun
3273*4882a593Smuzhiyun if (memcmp
3274*4882a593Smuzhiyun (rtl->fw_buf + rtl->fw_len - 4,
3275*4882a593Smuzhiyun Extension_Section_SIGNATURE, 4)) {
3276*4882a593Smuzhiyun RS_ERR("check extension section signature error");
3277*4882a593Smuzhiyun rtl->dl_fw_flag = 0;
3278*4882a593Smuzhiyun goto free_buf;
3279*4882a593Smuzhiyun }
3280*4882a593Smuzhiyun
3281*4882a593Smuzhiyun proj_id = rtk_get_fw_project_id(rtl->fw_buf + rtl->fw_len - 5);
3282*4882a593Smuzhiyun
3283*4882a593Smuzhiyun #ifdef RTL_8703A_SUPPORT
3284*4882a593Smuzhiyun if (rtl->hci_ver == 0x4 && rtl->lmp_subver == ROM_LMP_8723b) {
3285*4882a593Smuzhiyun RS_DBG("HCI version = 0x4, IC is 8703A.");
3286*4882a593Smuzhiyun } else {
3287*4882a593Smuzhiyun RS_ERR("error: lmp_version %x, hci_version %x, project_id %x",
3288*4882a593Smuzhiyun rtl->lmp_subver, rtl->hci_ver, project_id[proj_id]);
3289*4882a593Smuzhiyun rtk_hw_cfg.dl_fw_flag = 0;
3290*4882a593Smuzhiyun goto free_buf;
3291*4882a593Smuzhiyun }
3292*4882a593Smuzhiyun #else
3293*4882a593Smuzhiyun if (rtl->lmp_subver != ROM_LMP_8703b) {
3294*4882a593Smuzhiyun if (rtl->lmp_subver != project_id[proj_id]) {
3295*4882a593Smuzhiyun RS_ERR("lmp_subver %04x, project id %04x, mismatch\n",
3296*4882a593Smuzhiyun rtl->lmp_subver, project_id[proj_id]);
3297*4882a593Smuzhiyun rtl->dl_fw_flag = 0;
3298*4882a593Smuzhiyun goto free_buf;
3299*4882a593Smuzhiyun }
3300*4882a593Smuzhiyun } else {
3301*4882a593Smuzhiyun /* if (rtk_hw_cfg.patch_ent->proj_id != project_id[proj_id]) {
3302*4882a593Smuzhiyun * RS_ERR("proj_id %04x, version %04x from firmware "
3303*4882a593Smuzhiyun * "project_id[%u], mismatch\n",
3304*4882a593Smuzhiyun * rtk_hw_cfg.patch_ent->proj_id,
3305*4882a593Smuzhiyun * project_id[proj_id], proj_id);
3306*4882a593Smuzhiyun * rtk_hw_cfg.dl_fw_flag = 0;
3307*4882a593Smuzhiyun * goto free_buf;
3308*4882a593Smuzhiyun * } */
3309*4882a593Smuzhiyun }
3310*4882a593Smuzhiyun #endif
3311*4882a593Smuzhiyun
3312*4882a593Smuzhiyun entry = rtk_get_patch_entry();
3313*4882a593Smuzhiyun
3314*4882a593Smuzhiyun if (entry)
3315*4882a593Smuzhiyun rtl->total_len =
3316*4882a593Smuzhiyun entry->patch_length + rtl->config_len;
3317*4882a593Smuzhiyun else {
3318*4882a593Smuzhiyun rtl->dl_fw_flag = 0;
3319*4882a593Smuzhiyun goto free_buf;
3320*4882a593Smuzhiyun }
3321*4882a593Smuzhiyun
3322*4882a593Smuzhiyun if (!(rtl->total_buf = malloc(rtl->total_len))) {
3323*4882a593Smuzhiyun RS_ERR("Can't alloc memory for multi fw&config, errno:%d",
3324*4882a593Smuzhiyun errno);
3325*4882a593Smuzhiyun rtl->dl_fw_flag = 0;
3326*4882a593Smuzhiyun rtl->total_len = 0;
3327*4882a593Smuzhiyun goto free_buf;
3328*4882a593Smuzhiyun } else {
3329*4882a593Smuzhiyun memcpy(rtl->total_buf,
3330*4882a593Smuzhiyun rtl->fw_buf + entry->start_offset,
3331*4882a593Smuzhiyun entry->patch_length);
3332*4882a593Smuzhiyun memcpy(rtl->total_buf + entry->patch_length - 4,
3333*4882a593Smuzhiyun &patch->fw_version, 4);
3334*4882a593Smuzhiyun
3335*4882a593Smuzhiyun if (rtl->config_len)
3336*4882a593Smuzhiyun memcpy(rtl->total_buf + entry->patch_length,
3337*4882a593Smuzhiyun rtl->config_buf, rtl->config_len);
3338*4882a593Smuzhiyun rtl->dl_fw_flag = 1;
3339*4882a593Smuzhiyun }
3340*4882a593Smuzhiyun
3341*4882a593Smuzhiyun RS_DBG("fw:%s exists, config file:%s exists",
3342*4882a593Smuzhiyun (rtl->fw_len > 0) ? "" : "not",
3343*4882a593Smuzhiyun (rtl->config_len > 0) ? "" : "not");
3344*4882a593Smuzhiyun
3345*4882a593Smuzhiyun free_buf:
3346*4882a593Smuzhiyun if (rtl->fw_len > 0) {
3347*4882a593Smuzhiyun free(rtl->fw_buf);
3348*4882a593Smuzhiyun rtl->fw_len = 0;
3349*4882a593Smuzhiyun }
3350*4882a593Smuzhiyun
3351*4882a593Smuzhiyun if (rtl->config_len > 0) {
3352*4882a593Smuzhiyun free(rtl->config_buf);
3353*4882a593Smuzhiyun rtl->config_len = 0;
3354*4882a593Smuzhiyun }
3355*4882a593Smuzhiyun
3356*4882a593Smuzhiyun if (entry)
3357*4882a593Smuzhiyun free(entry);
3358*4882a593Smuzhiyun }
3359*4882a593Smuzhiyun
3360*4882a593Smuzhiyun /**
3361*4882a593Smuzhiyun * Config realtek Bluetooth. The configuration parameter is get from config file and fw.
3362*4882a593Smuzhiyun * Config file is rtk8723_bt_config. which is set in rtk_get_bt_config.
3363*4882a593Smuzhiyun * fw file is "rlt8723a_chip_b_cut_bt40_fw", which is set in get_firmware_name.
3364*4882a593Smuzhiyun *
3365*4882a593Smuzhiyun * @warning maybe only one of config file and fw file exists. The bt_addr arg is stored in "/data/btmac.txt"
3366*4882a593Smuzhiyun * or "/data/misc/bluetoothd/bt_mac/btmac.txt",
3367*4882a593Smuzhiyun *
3368*4882a593Smuzhiyun * @param fd uart file descriptor
3369*4882a593Smuzhiyun * @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE
3370*4882a593Smuzhiyun * @param speed init_speed in uart struct
3371*4882a593Smuzhiyun * @param ti termios struct
3372*4882a593Smuzhiyun * @returns #0 on success
3373*4882a593Smuzhiyun */
rtk_config(int fd,int proto,int speed,struct termios * ti)3374*4882a593Smuzhiyun static int rtk_config(int fd, int proto, int speed, struct termios *ti)
3375*4882a593Smuzhiyun {
3376*4882a593Smuzhiyun int final_speed = 0;
3377*4882a593Smuzhiyun int ret = 0;
3378*4882a593Smuzhiyun struct btrtl_info *btrtl = &rtk_hw_cfg;
3379*4882a593Smuzhiyun
3380*4882a593Smuzhiyun btrtl->proto = proto;
3381*4882a593Smuzhiyun
3382*4882a593Smuzhiyun /* Get Local Version Information and RTK ROM version */
3383*4882a593Smuzhiyun if (proto == HCI_UART_3WIRE) {
3384*4882a593Smuzhiyun RS_INFO("H5 IC");
3385*4882a593Smuzhiyun rtk_get_lmp_version(fd);
3386*4882a593Smuzhiyun rtk_get_eversion(fd);
3387*4882a593Smuzhiyun } else {
3388*4882a593Smuzhiyun RS_INFO("H4 IC");
3389*4882a593Smuzhiyun rtk_hci_local_ver(fd);
3390*4882a593Smuzhiyun rtk_hci_rom_ver(fd);
3391*4882a593Smuzhiyun if (rtk_hw_cfg.lmp_subver == ROM_LMP_8761btc) {
3392*4882a593Smuzhiyun rtk_hw_cfg.chip_type = CHIP_8761BTC;
3393*4882a593Smuzhiyun rtk_hw_cfg.hw_flow_control = 1;
3394*4882a593Smuzhiyun /* TODO: Change to different uart baud */
3395*4882a593Smuzhiyun uart_speed_to_rtk_speed(1500000, &rtk_hw_cfg.baudrate);
3396*4882a593Smuzhiyun goto change_baud;
3397*4882a593Smuzhiyun }
3398*4882a593Smuzhiyun
3399*4882a593Smuzhiyun if (rtk_hw_cfg.lmp_subver == ROM_LMP_8761a) {
3400*4882a593Smuzhiyun if (rtk_hw_cfg.hci_rev == 0x000b) {
3401*4882a593Smuzhiyun rtk_hw_cfg.chip_type = CHIP_8761B;
3402*4882a593Smuzhiyun rtk_hw_cfg.hw_flow_control = 1;
3403*4882a593Smuzhiyun /* TODO: Change to different uart baud */
3404*4882a593Smuzhiyun uart_speed_to_rtk_speed(1500000, &rtk_hw_cfg.baudrate);
3405*4882a593Smuzhiyun goto change_baud;
3406*4882a593Smuzhiyun } else if (rtk_hw_cfg.hci_rev == 0x000a) {
3407*4882a593Smuzhiyun if (rtk_hw_cfg.eversion == 3)
3408*4882a593Smuzhiyun rtk_hw_cfg.chip_type = CHIP_8761ATF;
3409*4882a593Smuzhiyun else if (rtk_hw_cfg.eversion == 2)
3410*4882a593Smuzhiyun rtk_hw_cfg.chip_type = CHIP_8761AT;
3411*4882a593Smuzhiyun else
3412*4882a593Smuzhiyun rtk_hw_cfg.chip_type = CHIP_UNKNOWN;
3413*4882a593Smuzhiyun }
3414*4882a593Smuzhiyun }
3415*4882a593Smuzhiyun }
3416*4882a593Smuzhiyun
3417*4882a593Smuzhiyun RS_INFO("LMP Subversion 0x%04x", btrtl->lmp_subver);
3418*4882a593Smuzhiyun RS_INFO("EVersion %d", btrtl->eversion);
3419*4882a593Smuzhiyun
3420*4882a593Smuzhiyun switch (rtk_hw_cfg.lmp_subver) {
3421*4882a593Smuzhiyun case ROM_LMP_8723a:
3422*4882a593Smuzhiyun break;
3423*4882a593Smuzhiyun case ROM_LMP_8723b:
3424*4882a593Smuzhiyun #ifdef RTL_8703A_SUPPORT
3425*4882a593Smuzhiyun /* Set chip type for matching fw/config entry */
3426*4882a593Smuzhiyun rtl->chip_type = CHIP_8703AS;
3427*4882a593Smuzhiyun #endif
3428*4882a593Smuzhiyun break;
3429*4882a593Smuzhiyun case ROM_LMP_8821a:
3430*4882a593Smuzhiyun break;
3431*4882a593Smuzhiyun case ROM_LMP_8761a:
3432*4882a593Smuzhiyun break;
3433*4882a593Smuzhiyun case ROM_LMP_8703b:
3434*4882a593Smuzhiyun rtk_get_chip_type(fd);
3435*4882a593Smuzhiyun break;
3436*4882a593Smuzhiyun }
3437*4882a593Smuzhiyun
3438*4882a593Smuzhiyun btrtl->patch_ent = get_patch_entry(btrtl);
3439*4882a593Smuzhiyun if (btrtl->patch_ent) {
3440*4882a593Smuzhiyun RS_INFO("IC: %s\n", btrtl->patch_ent->ic_name);
3441*4882a593Smuzhiyun RS_INFO("Firmware/config: %s, %s\n",
3442*4882a593Smuzhiyun btrtl->patch_ent->patch_file,
3443*4882a593Smuzhiyun btrtl->patch_ent->config_file);
3444*4882a593Smuzhiyun } else {
3445*4882a593Smuzhiyun RS_ERR("Can not find firmware/config entry\n");
3446*4882a593Smuzhiyun return -1;
3447*4882a593Smuzhiyun }
3448*4882a593Smuzhiyun
3449*4882a593Smuzhiyun rtk_hw_cfg.config_len =
3450*4882a593Smuzhiyun rtk_get_bt_config(btrtl, &btrtl->config_buf, &btrtl->baudrate);
3451*4882a593Smuzhiyun if (rtk_hw_cfg.config_len < 0) {
3452*4882a593Smuzhiyun RS_ERR("Get Config file error, just use efuse settings");
3453*4882a593Smuzhiyun rtk_hw_cfg.config_len = 0;
3454*4882a593Smuzhiyun }
3455*4882a593Smuzhiyun
3456*4882a593Smuzhiyun rtk_hw_cfg.fw_len = rtk_get_bt_firmware(btrtl, &btrtl->fw_buf);
3457*4882a593Smuzhiyun if (rtk_hw_cfg.fw_len < 0) {
3458*4882a593Smuzhiyun RS_ERR("Get BT firmware error");
3459*4882a593Smuzhiyun rtk_hw_cfg.fw_len = 0;
3460*4882a593Smuzhiyun return -1;
3461*4882a593Smuzhiyun } else {
3462*4882a593Smuzhiyun rtk_get_final_patch(fd, proto);
3463*4882a593Smuzhiyun }
3464*4882a593Smuzhiyun
3465*4882a593Smuzhiyun if (rtk_hw_cfg.total_len > RTK_PATCH_LENGTH_MAX) {
3466*4882a593Smuzhiyun RS_ERR("total length of fw&config larger than allowed");
3467*4882a593Smuzhiyun return -1;
3468*4882a593Smuzhiyun }
3469*4882a593Smuzhiyun
3470*4882a593Smuzhiyun RS_INFO("Total len %d for fw/config", rtk_hw_cfg.total_len);
3471*4882a593Smuzhiyun
3472*4882a593Smuzhiyun change_baud:
3473*4882a593Smuzhiyun /* change baudrate if needed
3474*4882a593Smuzhiyun * rtk_hw_cfg.baudrate is a __u32/__u16 vendor-specific variable
3475*4882a593Smuzhiyun * parsed from config file
3476*4882a593Smuzhiyun * */
3477*4882a593Smuzhiyun if (rtk_hw_cfg.baudrate == 0) {
3478*4882a593Smuzhiyun uart_speed_to_rtk_speed(speed, &rtk_hw_cfg.baudrate);
3479*4882a593Smuzhiyun RS_DBG("No cfg file, set baudrate, : %u, 0x%08x",
3480*4882a593Smuzhiyun (unsigned int)speed, (unsigned int)rtk_hw_cfg.baudrate);
3481*4882a593Smuzhiyun goto SET_FLOW_CONTRL;
3482*4882a593Smuzhiyun } else
3483*4882a593Smuzhiyun rtk_speed_to_uart_speed(rtk_hw_cfg.baudrate,
3484*4882a593Smuzhiyun (RT_U32 *) & (rtk_hw_cfg.final_speed));
3485*4882a593Smuzhiyun
3486*4882a593Smuzhiyun if (proto == HCI_UART_3WIRE)
3487*4882a593Smuzhiyun rtk_vendor_change_speed_h5(fd, rtk_hw_cfg.baudrate);
3488*4882a593Smuzhiyun else
3489*4882a593Smuzhiyun rtk_vendor_change_speed_h4(fd, rtk_hw_cfg.baudrate);
3490*4882a593Smuzhiyun
3491*4882a593Smuzhiyun usleep(50000);
3492*4882a593Smuzhiyun final_speed = rtk_hw_cfg.final_speed ? rtk_hw_cfg.final_speed : speed;
3493*4882a593Smuzhiyun RS_DBG("final_speed %d\n", final_speed);
3494*4882a593Smuzhiyun if (set_speed(fd, ti, final_speed) < 0) {
3495*4882a593Smuzhiyun RS_ERR("Can't set baud rate:%x, %x, %x", final_speed,
3496*4882a593Smuzhiyun rtk_hw_cfg.final_speed, speed);
3497*4882a593Smuzhiyun return -1;
3498*4882a593Smuzhiyun }
3499*4882a593Smuzhiyun
3500*4882a593Smuzhiyun SET_FLOW_CONTRL:
3501*4882a593Smuzhiyun if (rtk_hw_cfg.hw_flow_control) {
3502*4882a593Smuzhiyun RS_DBG("hw flow control enable");
3503*4882a593Smuzhiyun ti->c_cflag |= CRTSCTS;
3504*4882a593Smuzhiyun
3505*4882a593Smuzhiyun if (tcsetattr(fd, TCSANOW, ti) < 0) {
3506*4882a593Smuzhiyun RS_ERR("Can't set port settings");
3507*4882a593Smuzhiyun return -1;
3508*4882a593Smuzhiyun }
3509*4882a593Smuzhiyun } else {
3510*4882a593Smuzhiyun RS_DBG("hw flow control disable");
3511*4882a593Smuzhiyun ti->c_cflag &= ~CRTSCTS;
3512*4882a593Smuzhiyun }
3513*4882a593Smuzhiyun
3514*4882a593Smuzhiyun /* wait for while for controller to setup */
3515*4882a593Smuzhiyun usleep(10000);
3516*4882a593Smuzhiyun
3517*4882a593Smuzhiyun /* For 8761B Test chip, no patch to download */
3518*4882a593Smuzhiyun if (rtk_hw_cfg.chip_type == CHIP_8761BTC ||
3519*4882a593Smuzhiyun rtk_hw_cfg.chip_type == CHIP_8761B)
3520*4882a593Smuzhiyun goto done;
3521*4882a593Smuzhiyun
3522*4882a593Smuzhiyun if ((rtk_hw_cfg.total_len > 0) && (rtk_hw_cfg.dl_fw_flag)) {
3523*4882a593Smuzhiyun rtk_hw_cfg.link_estab_state = H5_PATCH;
3524*4882a593Smuzhiyun rtk_hw_cfg.rx_index = -1;
3525*4882a593Smuzhiyun
3526*4882a593Smuzhiyun ret =
3527*4882a593Smuzhiyun rtk_download_fw_config(fd, rtk_hw_cfg.total_buf,
3528*4882a593Smuzhiyun rtk_hw_cfg.total_len,
3529*4882a593Smuzhiyun rtk_hw_cfg.baudrate, proto, ti);
3530*4882a593Smuzhiyun free(rtk_hw_cfg.total_buf);
3531*4882a593Smuzhiyun
3532*4882a593Smuzhiyun if (ret < 0)
3533*4882a593Smuzhiyun return ret;
3534*4882a593Smuzhiyun }
3535*4882a593Smuzhiyun
3536*4882a593Smuzhiyun done:
3537*4882a593Smuzhiyun RS_DBG("Init Process finished");
3538*4882a593Smuzhiyun return 0;
3539*4882a593Smuzhiyun }
3540*4882a593Smuzhiyun
3541*4882a593Smuzhiyun /**
3542*4882a593Smuzhiyun * Init uart by realtek Bluetooth.
3543*4882a593Smuzhiyun *
3544*4882a593Smuzhiyun * @param fd uart file descriptor
3545*4882a593Smuzhiyun * @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE
3546*4882a593Smuzhiyun * @param speed init_speed in uart struct
3547*4882a593Smuzhiyun * @param ti termios struct
3548*4882a593Smuzhiyun * @returns #0 on success, depend on rtk_config
3549*4882a593Smuzhiyun */
rtk_init(int fd,int proto,int speed,struct termios * ti)3550*4882a593Smuzhiyun int rtk_init(int fd, int proto, int speed, struct termios *ti)
3551*4882a593Smuzhiyun {
3552*4882a593Smuzhiyun struct sigaction sa;
3553*4882a593Smuzhiyun int retlen;
3554*4882a593Smuzhiyun RS_DBG("Realtek hciattach version %s \n", RTK_VERSION);
3555*4882a593Smuzhiyun
3556*4882a593Smuzhiyun memset(&rtk_hw_cfg, 0, sizeof(rtk_hw_cfg));
3557*4882a593Smuzhiyun rtk_hw_cfg.serial_fd = fd;
3558*4882a593Smuzhiyun rtk_hw_cfg.dl_fw_flag = 1;
3559*4882a593Smuzhiyun
3560*4882a593Smuzhiyun /* h4 will do nothing for init */
3561*4882a593Smuzhiyun if (proto == HCI_UART_3WIRE) {
3562*4882a593Smuzhiyun if (rtk_init_h5(fd, ti) < 0)
3563*4882a593Smuzhiyun return -1;;
3564*4882a593Smuzhiyun }
3565*4882a593Smuzhiyun
3566*4882a593Smuzhiyun return rtk_config(fd, proto, speed, ti);
3567*4882a593Smuzhiyun }
3568*4882a593Smuzhiyun
3569*4882a593Smuzhiyun /**
3570*4882a593Smuzhiyun * Post uart by realtek Bluetooth. If gFinalSpeed is set, set uart speed with it.
3571*4882a593Smuzhiyun *
3572*4882a593Smuzhiyun * @param fd uart file descriptor
3573*4882a593Smuzhiyun * @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE
3574*4882a593Smuzhiyun * @param ti termios struct
3575*4882a593Smuzhiyun * @returns #0 on success.
3576*4882a593Smuzhiyun */
rtk_post(int fd,int proto,struct termios * ti)3577*4882a593Smuzhiyun int rtk_post(int fd, int proto, struct termios *ti)
3578*4882a593Smuzhiyun {
3579*4882a593Smuzhiyun if (rtk_hw_cfg.final_speed)
3580*4882a593Smuzhiyun return set_speed(fd, ti, rtk_hw_cfg.final_speed);
3581*4882a593Smuzhiyun
3582*4882a593Smuzhiyun return 0;
3583*4882a593Smuzhiyun }
3584