external/bluetooth/bluez
Revision | de7b62e01ae65b3c7a8412515996387fbc431834 (tree) |
---|---|
Time | 2017-06-07 10:52:44 |
Author | Chih-Wei Huang <cwhuang@linu...> |
Commiter | Chih-Wei Huang |
Add RTL8723BS Bluetooth tool
Copy and modify from https://github.com/lwfinger/rtl8723bs_bt.
@@ -716,6 +716,25 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac | ||
716 | 716 | include $(BUILD_EXECUTABLE) |
717 | 717 | |
718 | 718 | # |
719 | +# rtk_hciattach | |
720 | +# | |
721 | + | |
722 | +include $(CLEAR_VARS) | |
723 | + | |
724 | +LOCAL_SRC_FILES := \ | |
725 | + bluez/tools/hciattach.c \ | |
726 | + bluez/tools/hciattach_rtk.c \ | |
727 | + | |
728 | +LOCAL_C_INCLUDES := \ | |
729 | + $(LOCAL_PATH)/bluez \ | |
730 | + | |
731 | +LOCAL_MODULE_TAGS := optional | |
732 | +LOCAL_MODULE := rtk_hciattach | |
733 | +LOCAL_PROPRIETARY_MODULE := true | |
734 | + | |
735 | +include $(BUILD_EXECUTABLE) | |
736 | + | |
737 | +# | |
719 | 738 | # brcm_patchram_plus |
720 | 739 | # |
721 | 740 | include $(CLEAR_VARS) |
@@ -146,6 +146,7 @@ int read_hci_event(int fd, unsigned char* buf, int size) | ||
146 | 146 | return count; |
147 | 147 | } |
148 | 148 | |
149 | +#if 0 | |
149 | 150 | /* |
150 | 151 | * Ericsson specific initialization |
151 | 152 | */ |
@@ -989,11 +990,28 @@ static int bcm2035(int fd, struct uart_t *u, struct termios *ti) | ||
989 | 990 | |
990 | 991 | return 0; |
991 | 992 | } |
993 | +#endif | |
994 | + | |
995 | +int rtk_init(int fd, int proto, int speed, struct termios *ti); | |
996 | +int rtk_post(int fd, int proto, struct termios *ti); | |
997 | + | |
998 | +static int realtek_init(int fd, struct uart_t *u, struct termios *ti) | |
999 | +{ | |
1000 | + fprintf(stderr, "Realtek Bluetooth init uart with init speed:%d, final_speed:%d, type:HCI UART %s\n", u->init_speed, u->speed, (u->proto == HCI_UART_H4)? "H4":"H5" ); | |
1001 | + return rtk_init(fd, u->proto, u->speed, ti); | |
1002 | +} | |
1003 | + | |
1004 | +static int realtek_post(int fd, struct uart_t *u, struct termios *ti) | |
1005 | +{ | |
1006 | + fprintf(stderr, "Realtek Bluetooth post process\n"); | |
1007 | + return rtk_post(fd, u->proto, ti); | |
1008 | +} | |
992 | 1009 | |
993 | 1010 | struct uart_t uart[] = { |
994 | 1011 | { "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, |
995 | 1012 | FLOW_CTL, DISABLE_PM, NULL, NULL }, |
996 | 1013 | |
1014 | +#if 0 | |
997 | 1015 | { "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, |
998 | 1016 | FLOW_CTL, DISABLE_PM, NULL, ericsson }, |
999 | 1017 |
@@ -1109,6 +1127,18 @@ struct uart_t uart[] = { | ||
1109 | 1127 | { "amp", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, |
1110 | 1128 | AMP_DEV, DISABLE_PM, NULL, NULL, NULL }, |
1111 | 1129 | |
1130 | +#endif | |
1131 | + | |
1132 | + /* Realtek Bluetooth H4*/ | |
1133 | + /* H4 will set 115200 baudrate and flow control enable by default*/ | |
1134 | + { "rtk_h4", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, | |
1135 | + 0, DISABLE_PM, NULL, realtek_init, realtek_post }, | |
1136 | + | |
1137 | + /* Realtek Bluetooth H5*/ | |
1138 | + /* H5 will set 115200 baudrate and flow control disable by default */ | |
1139 | + { "rtk_h5", 0x0000, 0x0000, HCI_UART_3WIRE, 115200, 115200, | |
1140 | + 0, DISABLE_PM, NULL, realtek_init, realtek_post }, | |
1141 | + | |
1112 | 1142 | { NULL, 0 } |
1113 | 1143 | }; |
1114 | 1144 |
@@ -1370,7 +1400,9 @@ int main(int argc, char *argv[]) | ||
1370 | 1400 | |
1371 | 1401 | /* 10 seconds should be enough for initialization */ |
1372 | 1402 | alarm(to); |
1403 | +#if 0 | |
1373 | 1404 | bcsp_max_retries = to; |
1405 | +#endif | |
1374 | 1406 | |
1375 | 1407 | n = init_uart(dev, u, send_break, raw); |
1376 | 1408 | if (n < 0) { |
@@ -0,0 +1,2454 @@ | ||
1 | +/** | |
2 | +*Copyright @ Realtek Semiconductor Corp. All Rights Reserved. | |
3 | +* | |
4 | + | |
5 | +*Module Name: | |
6 | +* hciattach_rtk.c | |
7 | +* | |
8 | +*Description: | |
9 | +* H4/H5 specific initialization | |
10 | +* | |
11 | +*Revision History: | |
12 | +* Date Version Author Comment | |
13 | +* ---------- --------- --------------- ----------------------- | |
14 | +* 2013-06-06 1.0.0 gordon_yang Create | |
15 | +* 2013-06-18 1.0.1 lory_xu add support for multi fw | |
16 | +* 2013-06-21 1.0.2 gordon_yang add timeout for get version cmd | |
17 | +* 2013-07-01 1.0.3 lory_xu close file handle | |
18 | +* 2013-07-01 2.0 champion_chen add IC check | |
19 | +* 2013-12-16 2.1 champion_chen fix bug in Additional packet number | |
20 | +* 2013-12-25 2.2 champion_chen open host flow control after send last fw packet | |
21 | +*/ | |
22 | + | |
23 | +#ifdef HAVE_CONFIG_H | |
24 | +#include <config.h> | |
25 | +#endif | |
26 | + | |
27 | +#include <stdio.h> | |
28 | +#include <errno.h> | |
29 | +#include <unistd.h> | |
30 | +#include <stdlib.h> | |
31 | +#include <termios.h> | |
32 | +#include <time.h> | |
33 | +#include <sys/time.h> | |
34 | +#include <sys/types.h> | |
35 | +#include <sys/param.h> | |
36 | +#include <sys/ioctl.h> | |
37 | +#include <sys/socket.h> | |
38 | +#include <sys/uio.h> | |
39 | +#include <sys/stat.h> | |
40 | +#include <fcntl.h> | |
41 | +#include <signal.h> | |
42 | +#include <stdint.h> | |
43 | +#include <string.h> | |
44 | +#include <endian.h> | |
45 | +#include <byteswap.h> | |
46 | +#include <netinet/in.h> | |
47 | + | |
48 | +#include "lib/bluetooth.h" | |
49 | +#include "hciattach.h" | |
50 | + | |
51 | +#define RTK_VERSION "2.5" | |
52 | + | |
53 | +#define BAUDRATE_4BYTES | |
54 | +//#define USE_CUSTUMER_ADDRESS | |
55 | +#define FIRMWARE_DIRECTORY "/lib/firmware/rtl_bt/" | |
56 | +#define BT_CONFIG_DIRECTORY "/lib/firmware/rtl_bt/" | |
57 | + | |
58 | +#ifdef USE_CUSTUMER_ADDRESS | |
59 | +#define BT_ADDR_DIR "/data/bt_mac/" | |
60 | +#define BT_ADDR_FILE "/data/bt_mac/btmac.txt" | |
61 | +#endif | |
62 | + | |
63 | +#if __BYTE_ORDER == __LITTLE_ENDIAN | |
64 | +#define cpu_to_le16(d) (d) | |
65 | +#define cpu_to_le32(d) (d) | |
66 | +#define le16_to_cpu(d) (d) | |
67 | +#define le32_to_cpu(d) (d) | |
68 | +#elif __BYTE_ORDER == __BIG_ENDIAN | |
69 | +#define cpu_to_le16(d) bswap_16(d) | |
70 | +#define cpu_to_le32(d) bswap_32(d) | |
71 | +#define le16_to_cpu(d) bswap_16(d) | |
72 | +#define le32_to_cpu(d) bswap_32(d) | |
73 | +#else | |
74 | +#error "Unknown byte order" | |
75 | +#endif | |
76 | + | |
77 | +typedef uint8_t RT_U8, *PRT_U8; | |
78 | +typedef int8_t RT_S8, *PRT_S8; | |
79 | +typedef uint16_t RT_U16, *PRT_U16; | |
80 | +typedef int32_t RT_S32, *PRT_S32; | |
81 | +typedef uint32_t RT_U32, *PRT_U32; | |
82 | + | |
83 | +RT_U8 DBG_ON = 1; | |
84 | +#define LOG_STR "Realtek Bluetooth" | |
85 | +#define RS_DBG(fmt, arg...) \ | |
86 | + do{ \ | |
87 | + if (DBG_ON) \ | |
88 | + fprintf(stderr, "%s :" fmt "\n" , LOG_STR, ##arg); \ | |
89 | + }while(0) | |
90 | + | |
91 | +#define RS_ERR(fmt, arg...) \ | |
92 | + do{ \ | |
93 | + fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg); \ | |
94 | + }while(0) | |
95 | + | |
96 | + | |
97 | +#define HCI_COMMAND_HDR_SIZE 3 | |
98 | +#define HCI_EVENT_HDR_SIZE 2 | |
99 | +#define RTK_PATCH_LENGTH_MAX 24576 //24*1024 | |
100 | +#define PATCH_DATA_FIELD_MAX_SIZE 252 | |
101 | +#define READ_DATA_SIZE 16 | |
102 | +#define H5_MAX_RETRY_COUNT 40 | |
103 | + | |
104 | +#define RTK_VENDOR_CONFIG_MAGIC 0x8723ab55 | |
105 | +const RT_U8 RTK_EPATCH_SIGNATURE[8] = {0x52,0x65,0x61,0x6C,0x74,0x65,0x63,0x68}; | |
106 | +const RT_U8 Extension_Section_SIGNATURE[4] = {0x51,0x04,0xFD,0x77}; | |
107 | + | |
108 | +#define HCI_CMD_READ_BD_ADDR 0x1009 | |
109 | +#define HCI_VENDOR_CHANGE_BDRATE 0xfc17 | |
110 | +#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d | |
111 | +#define HCI_VENDOR_READ_LMP_VERISION 0x1001 | |
112 | + | |
113 | +#define ROM_LMP_NONE 0x0000 | |
114 | +#define ROM_LMP_8723a 0x1200 | |
115 | +#define ROM_LMP_8723b 0x8723 | |
116 | +#define ROM_LMP_8821a 0x8821 | |
117 | +#define ROM_LMP_8761a 0x8761 | |
118 | + | |
119 | +/* HCI data types */ | |
120 | +#define H5_ACK_PKT 0x00 | |
121 | +#define HCI_COMMAND_PKT 0x01 | |
122 | +#define HCI_ACLDATA_PKT 0x02 | |
123 | +#define HCI_SCODATA_PKT 0x03 | |
124 | +#define HCI_EVENT_PKT 0x04 | |
125 | +#define H5_VDRSPEC_PKT 0x0E | |
126 | +#define H5_LINK_CTL_PKT 0x0F | |
127 | + | |
128 | +#define H5_HDR_SEQ(hdr) ((hdr)[0] & 0x07) | |
129 | +#define H5_HDR_ACK(hdr) (((hdr)[0] >> 3) & 0x07) | |
130 | +#define H5_HDR_CRC(hdr) (((hdr)[0] >> 6) & 0x01) | |
131 | +#define H5_HDR_RELIABLE(hdr) (((hdr)[0] >> 7) & 0x01) | |
132 | +#define H5_HDR_PKT_TYPE(hdr) ((hdr)[1] & 0x0f) | |
133 | +#define H5_HDR_LEN(hdr) ((((hdr)[1] >> 4) & 0xff) + ((hdr)[2] << 4)) | |
134 | +#define H5_HDR_SIZE 4 | |
135 | + | |
136 | +struct sk_buff | |
137 | +{ | |
138 | + RT_U32 max_len; | |
139 | + RT_U32 data_len; | |
140 | + RT_U8 data[0]; | |
141 | +}; | |
142 | + | |
143 | +/* Skb helpers */ | |
144 | +struct bt_skb_cb | |
145 | +{ | |
146 | + RT_U8 pkt_type; | |
147 | + RT_U8 incoming; | |
148 | + RT_U16 expect; | |
149 | + RT_U8 tx_seq; | |
150 | + RT_U8 retries; | |
151 | + RT_U8 sar; | |
152 | + unsigned short channel; | |
153 | +}; | |
154 | + | |
155 | +typedef struct { | |
156 | + uint8_t index; | |
157 | + uint8_t data[252]; | |
158 | +} __attribute__ ((packed)) download_vendor_patch_cp; | |
159 | + | |
160 | +struct hci_command_hdr { | |
161 | + RT_U16 opcode; | |
162 | + RT_U8 plen; | |
163 | +} __attribute__ ((packed)); | |
164 | + | |
165 | +struct hci_event_hdr { | |
166 | + RT_U8 evt; | |
167 | + RT_U8 plen; | |
168 | +} __attribute__ ((packed)); | |
169 | + | |
170 | +struct hci_ev_cmd_complete { | |
171 | + RT_U8 ncmd; | |
172 | + RT_U16 opcode; | |
173 | +} __attribute__ ((packed)); | |
174 | + | |
175 | +struct rtk_bt_vendor_config_entry{ | |
176 | + RT_U16 offset; | |
177 | + RT_U8 entry_len; | |
178 | + RT_U8 entry_data[0]; | |
179 | +} __attribute__ ((packed)); | |
180 | + | |
181 | +struct rtk_bt_vendor_config{ | |
182 | + RT_U32 signature; | |
183 | + RT_U16 data_len; | |
184 | + struct rtk_bt_vendor_config_entry entry[0]; | |
185 | +} __attribute__ ((packed)); | |
186 | + | |
187 | +struct rtk_epatch_entry{ | |
188 | + RT_U16 chipID; | |
189 | + RT_U16 patch_length; | |
190 | + RT_U32 start_offset; | |
191 | +} __attribute__ ((packed)); | |
192 | + | |
193 | +struct rtk_epatch{ | |
194 | + RT_U8 signature[8]; | |
195 | + RT_U32 fw_version; | |
196 | + RT_U16 number_of_patch; | |
197 | + struct rtk_epatch_entry entry[0]; | |
198 | +} __attribute__ ((packed)); | |
199 | + | |
200 | +struct rtk_extension_entry{ | |
201 | + uint8_t opcode; | |
202 | + uint8_t length; | |
203 | + uint8_t *data; | |
204 | +} __attribute__ ((packed)); | |
205 | + | |
206 | +typedef enum _RTK_ROM_VERSION_CMD_STATE | |
207 | +{ | |
208 | + cmd_not_send, | |
209 | + cmd_has_sent, | |
210 | + event_received | |
211 | +} RTK_ROM_VERSION_CMD_STATE; | |
212 | + | |
213 | +typedef enum _H5_RX_STATE | |
214 | +{ | |
215 | + H5_W4_PKT_DELIMITER, | |
216 | + H5_W4_PKT_START, | |
217 | + H5_W4_HDR, | |
218 | + H5_W4_DATA, | |
219 | + H5_W4_CRC | |
220 | +} H5_RX_STATE; | |
221 | + | |
222 | +typedef enum _H5_RX_ESC_STATE | |
223 | +{ | |
224 | + H5_ESCSTATE_NOESC, | |
225 | + H5_ESCSTATE_ESC | |
226 | +} H5_RX_ESC_STATE; | |
227 | + | |
228 | +typedef enum _H5_LINK_STATE | |
229 | +{ | |
230 | + H5_SYNC, | |
231 | + H5_CONFIG, | |
232 | + H5_INIT, | |
233 | + H5_PATCH, | |
234 | + H5_ACTIVE | |
235 | +} H5_LINK_STATE; | |
236 | + | |
237 | +typedef struct { | |
238 | +/**********************h5 releated*************************/ | |
239 | + RT_U8 rxseq_txack; /* expected rx seq number */ | |
240 | + RT_U8 rxack; /* last packet sent by us that the peer ack'ed */ | |
241 | + RT_U8 use_crc; | |
242 | + RT_U8 is_txack_req; /* txack required */ | |
243 | + RT_U8 msgq_txseq; /* next pkt seq */ | |
244 | + RT_U16 message_crc; | |
245 | + RT_U32 rx_count; /* expected pkts to recv */ | |
246 | + | |
247 | + H5_RX_STATE rx_state; | |
248 | + H5_RX_ESC_STATE rx_esc_state; | |
249 | + H5_LINK_STATE link_estab_state; | |
250 | + | |
251 | + struct sk_buff *rx_skb; | |
252 | + struct sk_buff *host_last_cmd; | |
253 | + | |
254 | + RT_U16 lmp_version; | |
255 | + RT_U8 eversion; | |
256 | + int h5_max_retries; | |
257 | + | |
258 | +/**********************patch releated************************/ | |
259 | + uint32_t baudrate; | |
260 | + uint8_t dl_fw_flag; | |
261 | + int serial_fd; | |
262 | + int hw_flow_control; | |
263 | + int final_speed; | |
264 | + int total_num; /* total pkt number */ | |
265 | + int tx_index; /* current sending pkt number */ | |
266 | + int rx_index; /* ack index from board */ | |
267 | + int fw_len; /* fw patch file len */ | |
268 | + int config_len; /* config patch file len */ | |
269 | + int total_len; /* fw & config extracted buf len */ | |
270 | + uint8_t *fw_buf; /* fw patch file buf */ | |
271 | + uint8_t *config_buf; /* config patch file buf */ | |
272 | + uint8_t *total_buf; /* fw & config extracted buf */ | |
273 | + RTK_ROM_VERSION_CMD_STATE rom_version_cmd_state; | |
274 | + RTK_ROM_VERSION_CMD_STATE hci_version_cmd_state; | |
275 | +}rtk_hw_cfg_t; | |
276 | + | |
277 | +static rtk_hw_cfg_t rtk_hw_cfg; | |
278 | + | |
279 | +uint16_t project_id[]= | |
280 | +{ | |
281 | + ROM_LMP_8723a, | |
282 | + ROM_LMP_8723b, | |
283 | + ROM_LMP_8821a, | |
284 | + ROM_LMP_8761a, | |
285 | + ROM_LMP_NONE | |
286 | +}; | |
287 | + | |
288 | + | |
289 | +// bite reverse in bytes | |
290 | +// 00000001 -> 10000000 | |
291 | +// 00000100 -> 00100000 | |
292 | +const RT_U8 byte_rev_table[256] = { | |
293 | + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, | |
294 | + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, | |
295 | + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, | |
296 | + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, | |
297 | + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, | |
298 | + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, | |
299 | + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, | |
300 | + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, | |
301 | + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, | |
302 | + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, | |
303 | + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, | |
304 | + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, | |
305 | + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, | |
306 | + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, | |
307 | + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, | |
308 | + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, | |
309 | + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, | |
310 | + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, | |
311 | + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, | |
312 | + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, | |
313 | + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, | |
314 | + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, | |
315 | + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, | |
316 | + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, | |
317 | + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, | |
318 | + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, | |
319 | + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, | |
320 | + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, | |
321 | + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, | |
322 | + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, | |
323 | + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, | |
324 | + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, | |
325 | +}; | |
326 | + | |
327 | +static __inline RT_U8 bit_rev8(RT_U8 byte) | |
328 | +{ | |
329 | + return byte_rev_table[byte]; | |
330 | +} | |
331 | + | |
332 | +static __inline RT_U16 bit_rev16(RT_U16 x) | |
333 | +{ | |
334 | + return (bit_rev8(x & 0xff) << 8) | bit_rev8(x >> 8); | |
335 | +} | |
336 | + | |
337 | +static const RT_U16 crc_table[] = | |
338 | +{ | |
339 | + 0x0000, 0x1081, 0x2102, 0x3183, | |
340 | + 0x4204, 0x5285, 0x6306, 0x7387, | |
341 | + 0x8408, 0x9489, 0xa50a, 0xb58b, | |
342 | + 0xc60c, 0xd68d, 0xe70e, 0xf78f | |
343 | +}; | |
344 | + | |
345 | +// Initialise the crc calculator | |
346 | +#define H5_CRC_INIT(x) x = 0xffff | |
347 | + | |
348 | +/** | |
349 | +* Malloc the socket buffer | |
350 | +* | |
351 | +* @param skb socket buffer | |
352 | +* @return the point to the malloc buffer | |
353 | +*/ | |
354 | +static __inline struct sk_buff * skb_alloc(unsigned int len) | |
355 | +{ | |
356 | + struct sk_buff *skb = NULL; | |
357 | + if ((skb = malloc(len + 8))) { | |
358 | + skb->max_len= len; | |
359 | + skb->data_len = 0; | |
360 | + } else { | |
361 | + RS_ERR("Allocate skb fails!!!"); | |
362 | + skb = NULL; | |
363 | + } | |
364 | + memset(skb->data, 0, len); | |
365 | + return skb; | |
366 | +} | |
367 | +/** | |
368 | +* Free the socket buffer | |
369 | +* | |
370 | +* @param skb socket buffer | |
371 | +*/ | |
372 | +static __inline void skb_free(struct sk_buff *skb) | |
373 | +{ | |
374 | + free(skb); | |
375 | + return; | |
376 | +} | |
377 | + | |
378 | +/** | |
379 | +* Increase the date length in sk_buffer by len, | |
380 | +* and return the increased header pointer | |
381 | +* | |
382 | +* @param skb socket buffer | |
383 | +* @param len length want to increase | |
384 | +* @return the pointer to increased header | |
385 | +*/ | |
386 | +static RT_U8 *skb_put(struct sk_buff* skb, RT_U32 len) | |
387 | +{ | |
388 | + RT_U32 old_len = skb->data_len; | |
389 | + if((skb->data_len + len) > (skb->max_len)) { | |
390 | + RS_ERR("Buffer too small"); | |
391 | + return NULL; | |
392 | + } | |
393 | + skb->data_len += len; | |
394 | + return (skb->data + old_len); | |
395 | +} | |
396 | + | |
397 | +/** | |
398 | +* decrease data length in sk_buffer by to len by cut the tail | |
399 | +* | |
400 | +* @warning len should be less than skb->len | |
401 | +* | |
402 | +* @param skb socket buffer | |
403 | +* @param len length want to be changed | |
404 | +*/ | |
405 | +static void skb_trim(struct sk_buff *skb, unsigned int len) | |
406 | +{ | |
407 | + if (skb->data_len > len) { | |
408 | + skb->data_len = len; | |
409 | + } else { | |
410 | + RS_ERR("Error: skb->data_len(%d) < len(%d)", skb->data_len, len); | |
411 | + } | |
412 | +} | |
413 | + | |
414 | +/** | |
415 | +* Decrease the data length in sk_buffer by len, | |
416 | +* and move the content forward to the header. | |
417 | +* the data in header will be removed. | |
418 | +* | |
419 | +* @param skb socket buffer | |
420 | +* @param len length of data | |
421 | +* @return new data | |
422 | +*/ | |
423 | +static RT_U8 * skb_pull(struct sk_buff * skb, RT_U32 len) | |
424 | +{ | |
425 | + skb->data_len -= len; | |
426 | + unsigned char *buf; | |
427 | + if (!(buf = malloc(skb->data_len))) { | |
428 | + RS_ERR("Unable to allocate file buffer"); | |
429 | + exit(1); | |
430 | + } | |
431 | + memcpy(buf, skb->data+len, skb->data_len); | |
432 | + memcpy(skb->data, buf, skb->data_len); | |
433 | + free(buf); | |
434 | + return (skb->data); | |
435 | +} | |
436 | +/** | |
437 | +* Add "d" into crc scope, caculate the new crc value | |
438 | +* | |
439 | +* @param crc crc data | |
440 | +* @param d one byte data | |
441 | +*/ | |
442 | +static void h5_crc_update(RT_U16 *crc, RT_U8 d) | |
443 | +{ | |
444 | + RT_U16 reg = *crc; | |
445 | + | |
446 | + reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; | |
447 | + reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; | |
448 | + | |
449 | + *crc = reg; | |
450 | +} | |
451 | + | |
452 | +struct __una_u16 { RT_U16 x; }; | |
453 | +static __inline RT_U16 __get_unaligned_cpu16(const void *p) | |
454 | +{ | |
455 | + const struct __una_u16 *ptr = (const struct __una_u16 *)p; | |
456 | + return ptr->x; | |
457 | +} | |
458 | + | |
459 | + | |
460 | +static __inline RT_U16 get_unaligned_be16(const void *p) | |
461 | +{ | |
462 | + return __get_unaligned_cpu16((const RT_U8 *)p); | |
463 | +} | |
464 | + | |
465 | +static __inline RT_U16 get_unaligned_le16(RT_U8 *p) | |
466 | +{ | |
467 | + return (RT_U16)(*p)+((RT_U16)(*(p+1))<<8); | |
468 | +} | |
469 | + | |
470 | +static __inline RT_U32 get_unaligned_le32(RT_U8 *p) | |
471 | +{ | |
472 | + return (RT_U32)(*p) + ((RT_U32)(*(p+1))<<8) + ((RT_U32)(*(p+2))<<16) + ((RT_U32)(*(p+3))<<24); | |
473 | +} | |
474 | + | |
475 | +/** | |
476 | +* Get crc data. | |
477 | +* | |
478 | +* @param h5 realtek h5 struct | |
479 | +* @return crc data | |
480 | +*/ | |
481 | +static RT_U16 h5_get_crc(rtk_hw_cfg_t *h5) | |
482 | +{ | |
483 | + RT_U16 crc = 0; | |
484 | + RT_U8 * data = h5->rx_skb->data + h5->rx_skb->data_len - 2; | |
485 | + crc = data[1] + (data[0] << 8); | |
486 | + return crc; | |
487 | +// return get_unaligned_be16(&h5->rx_skb->data[h5->rx_skb->data_len - 2]); | |
488 | +} | |
489 | + | |
490 | +/** | |
491 | +* Just add 0xc0 at the end of skb, | |
492 | +* we can also use this to add 0xc0 at start while there is no data in skb | |
493 | +* | |
494 | +* @param skb socket buffer | |
495 | +*/ | |
496 | +static void h5_slip_msgdelim(struct sk_buff *skb) | |
497 | +{ | |
498 | + const char pkt_delim = 0xc0; | |
499 | + memcpy(skb_put(skb, 1), &pkt_delim, 1); | |
500 | +} | |
501 | + | |
502 | +/** | |
503 | +* Slip ecode one byte in h5 proto, as follows: | |
504 | +* 0xc0 -> 0xdb, 0xdc | |
505 | +* 0xdb -> 0xdb, 0xdd | |
506 | +* 0x11 -> 0xdb, 0xde | |
507 | +* 0x13 -> 0xdb, 0xdf | |
508 | +* others will not change | |
509 | +* | |
510 | +* @param skb socket buffer | |
511 | +* @c pure data in the one byte | |
512 | +*/ | |
513 | +static void h5_slip_one_byte(struct sk_buff *skb, RT_U8 c) | |
514 | +{ | |
515 | + const RT_S8 esc_c0[2] = { 0xdb, 0xdc }; | |
516 | + const RT_S8 esc_db[2] = { 0xdb, 0xdd }; | |
517 | + const RT_S8 esc_11[2] = { 0xdb, 0xde }; | |
518 | + const RT_S8 esc_13[2] = { 0xdb, 0xdf }; | |
519 | + | |
520 | + switch (c) { | |
521 | + case 0xc0: | |
522 | + memcpy(skb_put(skb, 2), &esc_c0, 2); | |
523 | + break; | |
524 | + | |
525 | + case 0xdb: | |
526 | + memcpy(skb_put(skb, 2), &esc_db, 2); | |
527 | + break; | |
528 | + | |
529 | + case 0x11: | |
530 | + memcpy(skb_put(skb, 2), &esc_11, 2); | |
531 | + break; | |
532 | + | |
533 | + case 0x13: | |
534 | + memcpy(skb_put(skb, 2), &esc_13, 2); | |
535 | + break; | |
536 | + | |
537 | + default: | |
538 | + memcpy(skb_put(skb, 1), &c, 1); | |
539 | + break; | |
540 | + } | |
541 | +} | |
542 | + | |
543 | +/** | |
544 | +* Decode one byte in h5 proto, as follows: | |
545 | +* 0xdb, 0xdc -> 0xc0 | |
546 | +* 0xdb, 0xdd -> 0xdb | |
547 | +* 0xdb, 0xde -> 0x11 | |
548 | +* 0xdb, 0xdf -> 0x13 | |
549 | +* others will not change | |
550 | +* | |
551 | +* @param h5 realtek h5 struct | |
552 | +* @byte pure data in the one byte | |
553 | +*/ | |
554 | +static void h5_unslip_one_byte(rtk_hw_cfg_t *h5, unsigned char byte) | |
555 | +{ | |
556 | + const RT_U8 c0 = 0xc0, db = 0xdb; | |
557 | + const RT_U8 oof1 = 0x11, oof2 = 0x13; | |
558 | + | |
559 | + if (H5_ESCSTATE_NOESC == h5->rx_esc_state) { | |
560 | + if (0xdb == byte) { | |
561 | + h5->rx_esc_state = H5_ESCSTATE_ESC; | |
562 | + } else { | |
563 | + memcpy(skb_put(h5->rx_skb, 1), &byte, 1); | |
564 | + //Check Pkt Header's CRC enable bit | |
565 | + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) { | |
566 | + h5_crc_update(&h5->message_crc, byte); | |
567 | + } | |
568 | + h5->rx_count--; | |
569 | + } | |
570 | + } else if (H5_ESCSTATE_ESC == h5->rx_esc_state) { | |
571 | + switch (byte) { | |
572 | + case 0xdc: | |
573 | + memcpy(skb_put(h5->rx_skb, 1), &c0, 1); | |
574 | + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) | |
575 | + h5_crc_update(&h5->message_crc, 0xc0); | |
576 | + h5->rx_esc_state = H5_ESCSTATE_NOESC; | |
577 | + h5->rx_count--; | |
578 | + break; | |
579 | + | |
580 | + case 0xdd: | |
581 | + memcpy(skb_put(h5->rx_skb, 1), &db, 1); | |
582 | + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) | |
583 | + h5_crc_update(&h5->message_crc, 0xdb); | |
584 | + h5->rx_esc_state = H5_ESCSTATE_NOESC; | |
585 | + h5->rx_count--; | |
586 | + break; | |
587 | + | |
588 | + case 0xde: | |
589 | + memcpy(skb_put(h5->rx_skb, 1), &oof1, 1); | |
590 | + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) | |
591 | + h5_crc_update(&h5->message_crc, oof1); | |
592 | + h5->rx_esc_state = H5_ESCSTATE_NOESC; | |
593 | + h5->rx_count--; | |
594 | + break; | |
595 | + | |
596 | + case 0xdf: | |
597 | + memcpy(skb_put(h5->rx_skb, 1), &oof2, 1); | |
598 | + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) | |
599 | + h5_crc_update(&h5->message_crc, oof2); | |
600 | + h5->rx_esc_state = H5_ESCSTATE_NOESC; | |
601 | + h5->rx_count--; | |
602 | + break; | |
603 | + | |
604 | + default: | |
605 | + RS_ERR("Error: Invalid byte %02x after esc byte", byte); | |
606 | + skb_free(h5->rx_skb); | |
607 | + h5->rx_skb = NULL; | |
608 | + h5->rx_state = H5_W4_PKT_DELIMITER; | |
609 | + h5->rx_count = 0; | |
610 | + break; | |
611 | + } | |
612 | + } | |
613 | +} | |
614 | + | |
615 | +/** | |
616 | +* Prepare h5 packet, packet format as follow: | |
617 | +* | LSB 4 octets | 0 ~4095| 2 MSB | |
618 | +* |packet header | payload | data integrity check | | |
619 | +* | |
620 | +* pakcket header fromat is show below: | |
621 | +* | LSB 3 bits | 3 bits | 1 bits | 1 bits | | |
622 | +* | 4 bits | 12 bits | 8 bits MSB | |
623 | +* |sequence number | acknowledgement number | data integrity check present | reliable packet | | |
624 | +* |packet type | payload length | header checksum | |
625 | +* | |
626 | +* @param h5 realtek h5 struct | |
627 | +* @param data pure data | |
628 | +* @param len the length of data | |
629 | +* @param pkt_type packet type | |
630 | +* @return socket buff after prepare in h5 proto | |
631 | +*/ | |
632 | +static struct sk_buff * h5_prepare_pkt(rtk_hw_cfg_t *h5, RT_U8 *data, RT_S32 len, RT_S32 pkt_type) | |
633 | +{ | |
634 | + struct sk_buff *nskb; | |
635 | + RT_U8 hdr[4]; | |
636 | + RT_U16 H5_CRC_INIT(h5_txmsg_crc); | |
637 | + int rel, i; | |
638 | + | |
639 | + switch (pkt_type) { | |
640 | + case HCI_ACLDATA_PKT: | |
641 | + case HCI_COMMAND_PKT: | |
642 | + case HCI_EVENT_PKT: | |
643 | + rel = 1; // reliable | |
644 | + break; | |
645 | + | |
646 | + case H5_ACK_PKT: | |
647 | + case H5_VDRSPEC_PKT: | |
648 | + case H5_LINK_CTL_PKT: | |
649 | + rel = 0; // unreliable | |
650 | + break; | |
651 | + | |
652 | + default: | |
653 | + RS_ERR("Unknown packet type"); | |
654 | + return NULL; | |
655 | + } | |
656 | + | |
657 | + // Max len of packet: (original len +4(h5 hdr) +2(crc))*2 | |
658 | + // (because bytes 0xc0 and 0xdb are escaped, worst case is | |
659 | + // when the packet is all made of 0xc0 and 0xdb :) ) | |
660 | + // + 2 (0xc0 delimiters at start and end). | |
661 | + | |
662 | + nskb = skb_alloc((len + 6) * 2 + 2); | |
663 | + if (!nskb) | |
664 | + return NULL; | |
665 | + | |
666 | + //Add SLIP start byte: 0xc0 | |
667 | + h5_slip_msgdelim(nskb); | |
668 | + // set AckNumber in SlipHeader | |
669 | + hdr[0] = h5->rxseq_txack << 3; | |
670 | + h5->is_txack_req = 0; | |
671 | + | |
672 | + //RS_DBG("We request packet no(%u) to card", h5->rxseq_txack); | |
673 | + //RS_DBG("Sending packet with seqno %u and wait %u", h5->msgq_txseq, h5->rxseq_txack); | |
674 | + if (rel) { | |
675 | + // set reliable pkt bit and SeqNumber | |
676 | + hdr[0] |= 0x80 + h5->msgq_txseq; | |
677 | + //RS_DBG("Sending packet with seqno(%u)", h5->msgq_txseq); | |
678 | + ++(h5->msgq_txseq); | |
679 | + h5->msgq_txseq = (h5->msgq_txseq) & 0x07; | |
680 | + } | |
681 | + | |
682 | + // set DicPresent bit | |
683 | + if (h5->use_crc) | |
684 | + hdr[0] |= 0x40; | |
685 | + | |
686 | + // set packet type and payload length | |
687 | + hdr[1] = ((len << 4) & 0xff) | pkt_type; | |
688 | + hdr[2] = (RT_U8)(len >> 4); | |
689 | + // set checksum | |
690 | + hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); | |
691 | + | |
692 | + // Put h5 header */ | |
693 | + for (i = 0; i < 4; i++) { | |
694 | + h5_slip_one_byte(nskb, hdr[i]); | |
695 | + | |
696 | + if (h5->use_crc) | |
697 | + h5_crc_update(&h5_txmsg_crc, hdr[i]); | |
698 | + } | |
699 | + | |
700 | + // Put payload */ | |
701 | + for (i = 0; i < len; i++) { | |
702 | + h5_slip_one_byte(nskb, data[i]); | |
703 | + | |
704 | + if (h5->use_crc) | |
705 | + h5_crc_update(&h5_txmsg_crc, data[i]); | |
706 | + } | |
707 | + | |
708 | + // Put CRC */ | |
709 | + if (h5->use_crc) { | |
710 | + h5_txmsg_crc = bit_rev16(h5_txmsg_crc); | |
711 | + h5_slip_one_byte(nskb, (RT_U8) ((h5_txmsg_crc >> 8) & 0x00ff)); | |
712 | + h5_slip_one_byte(nskb, (RT_U8) (h5_txmsg_crc & 0x00ff)); | |
713 | + } | |
714 | + | |
715 | + // Add SLIP end byte: 0xc0 | |
716 | + h5_slip_msgdelim(nskb); | |
717 | + return nskb; | |
718 | +} | |
719 | +/** | |
720 | +* Removed controller acked packet from Host's unacked lists | |
721 | +* | |
722 | +* @param h5 realtek h5 struct | |
723 | +*/ | |
724 | +static void h5_remove_acked_pkt(rtk_hw_cfg_t *h5) | |
725 | +{ | |
726 | + int pkts_to_be_removed = 0; | |
727 | + int seqno = 0; | |
728 | + int i = 0; | |
729 | + | |
730 | + seqno = h5->msgq_txseq; | |
731 | + //pkts_to_be_removed = GetListLength(h5->unacked); | |
732 | + | |
733 | + while (pkts_to_be_removed) { | |
734 | + if (h5->rxack == seqno) | |
735 | + break; | |
736 | + | |
737 | + pkts_to_be_removed--; | |
738 | + seqno = (seqno - 1) & 0x07; | |
739 | + } | |
740 | + | |
741 | + if (h5->rxack != seqno) { | |
742 | + RS_DBG("Peer acked invalid packet"); | |
743 | + } | |
744 | + | |
745 | + //skb_queue_walk_safe(&h5->unack, skb, tmp) // remove ack'ed packet from h5->unack queue | |
746 | + for (i = 0; i < 5; ++i) { | |
747 | + if (i >= pkts_to_be_removed) | |
748 | + break; | |
749 | + i++; | |
750 | + //__skb_unlink(skb, &h5->unack); | |
751 | + //skb_free(skb); | |
752 | + } | |
753 | + | |
754 | + // if (skb_queue_empty(&h5->unack)) | |
755 | + // del_timer(&h5->th5); | |
756 | + // spin_unlock_irqrestore(&h5->unack.lock, flags); | |
757 | + | |
758 | + if (i != pkts_to_be_removed) | |
759 | + RS_DBG("Removed only (%u) out of (%u) pkts", i, pkts_to_be_removed); | |
760 | +} | |
761 | +/** | |
762 | +* Realtek send pure ack, send a packet only with an ack | |
763 | +* | |
764 | +* @param fd uart file descriptor | |
765 | +* | |
766 | +*/ | |
767 | +static void rtk_send_pure_ack_down(int fd) | |
768 | +{ | |
769 | + struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, NULL, 0, H5_ACK_PKT); | |
770 | + write(fd, nskb->data, nskb->data_len); | |
771 | + skb_free(nskb); | |
772 | + return; | |
773 | +} | |
774 | + | |
775 | +/** | |
776 | +* Parse hci event command complete, pull the cmd complete event header | |
777 | +* | |
778 | +* @param skb socket buffer | |
779 | +* | |
780 | +*/ | |
781 | +static void hci_event_cmd_complete(struct sk_buff* skb) | |
782 | +{ | |
783 | + struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data; | |
784 | + struct hci_ev_cmd_complete* ev = NULL; | |
785 | + RT_U16 opcode = 0; | |
786 | + RT_U8 status = 0; | |
787 | + | |
788 | + //pull hdr | |
789 | + skb_pull(skb, HCI_EVENT_HDR_SIZE); | |
790 | + ev = (struct hci_ev_cmd_complete*)skb->data; | |
791 | + opcode = le16_to_cpu(ev->opcode); | |
792 | + | |
793 | + RS_DBG("receive hci command complete event with command:%x\n", opcode); | |
794 | + | |
795 | + //pull command complete event header | |
796 | + skb_pull(skb, sizeof(struct hci_ev_cmd_complete)); | |
797 | + | |
798 | + switch (opcode) { | |
799 | + case HCI_VENDOR_CHANGE_BDRATE: | |
800 | + status = skb->data[0]; | |
801 | + RS_DBG("Change BD Rate with status:%x", status); | |
802 | + skb_free(rtk_hw_cfg.host_last_cmd); | |
803 | + rtk_hw_cfg.host_last_cmd = NULL; | |
804 | + rtk_hw_cfg.link_estab_state = H5_PATCH; | |
805 | + break; | |
806 | + | |
807 | + case HCI_CMD_READ_BD_ADDR: | |
808 | + status = skb->data[0]; | |
809 | + RS_DBG("Read BD Address with Status:%x", status); | |
810 | + if (!status) { | |
811 | + RS_DBG("BD Address: %8x%8x", *(int*)&skb->data[1], *(int*)&skb->data[5]); | |
812 | + } | |
813 | + break; | |
814 | + | |
815 | + case HCI_VENDOR_READ_LMP_VERISION: | |
816 | + rtk_hw_cfg.hci_version_cmd_state = event_received; | |
817 | + status = skb->data[0]; | |
818 | + RS_DBG("Read RTK LMP version with Status:%x", status); | |
819 | + if (0 == status) | |
820 | + rtk_hw_cfg.lmp_version = skb->data[7] | (skb->data[8] << 8); | |
821 | + else { | |
822 | + RS_ERR("READ_RTK_ROM_VERISION return status error!"); | |
823 | + //Need to do more | |
824 | + } | |
825 | + skb_free(rtk_hw_cfg.host_last_cmd); | |
826 | + rtk_hw_cfg.host_last_cmd = NULL; | |
827 | + break; | |
828 | + | |
829 | + case HCI_VENDOR_READ_RTK_ROM_VERISION: | |
830 | + rtk_hw_cfg.rom_version_cmd_state = event_received; | |
831 | + status = skb->data[0]; | |
832 | + RS_DBG("Read RTK rom version with Status:%x", status); | |
833 | + if (0 == status) | |
834 | + rtk_hw_cfg.eversion = skb->data[1]; | |
835 | + else if (1 == status) | |
836 | + rtk_hw_cfg.eversion = 0; | |
837 | + else { | |
838 | + RS_ERR("READ_RTK_ROM_VERISION return status error!"); | |
839 | + //Need to do more | |
840 | + } | |
841 | + | |
842 | + skb_free(rtk_hw_cfg.host_last_cmd); | |
843 | + rtk_hw_cfg.host_last_cmd = NULL; | |
844 | + break; | |
845 | + | |
846 | + default: | |
847 | + break; | |
848 | + } | |
849 | +} | |
850 | + | |
851 | +/** | |
852 | +* Check if it's a hci frame, if it is, complete it with response or parse the cmd complete event | |
853 | +* | |
854 | +* @param skb socket buffer | |
855 | +* | |
856 | +*/ | |
857 | +static void hci_recv_frame(struct sk_buff *skb) | |
858 | +{ | |
859 | + int len; | |
860 | + unsigned char h5sync[2] = {0x01, 0x7E}, | |
861 | + h5syncresp[2] = {0x02, 0x7D}, | |
862 | + h5_sync_resp_pkt[0x8] = {0xc0, 0x00, 0x2F, 0x00, 0xD0, 0x02, 0x7D, 0xc0}, | |
863 | + h5_conf_resp_pkt_to_Ctrl[0x8] = {0xc0, 0x00, 0x2F, 0x00, 0xD0, 0x04, 0x7B, 0xc0}, | |
864 | + h5conf[3] = {0x03, 0xFC, 0x10}, | |
865 | + h5confresp[3] = {0x04, 0x7B, 0x10}, | |
866 | + cmd_complete_evt_code = 0xe; | |
867 | + | |
868 | + if(rtk_hw_cfg.link_estab_state == H5_SYNC) { | |
869 | + if (!memcmp(skb->data, h5sync, 2)) { | |
870 | + RS_DBG("Get SYNC Pkt\n"); | |
871 | + len = write(rtk_hw_cfg.serial_fd, &h5_sync_resp_pkt,0x8); | |
872 | + } else if (!memcmp(skb->data, h5syncresp, 2)) { | |
873 | + RS_DBG("Get SYNC Resp Pkt\n"); | |
874 | + rtk_hw_cfg.link_estab_state = H5_CONFIG; | |
875 | + } | |
876 | + skb_free(skb); | |
877 | + } else if(rtk_hw_cfg.link_estab_state == H5_CONFIG) { | |
878 | + if (!memcmp(skb->data, h5sync, 0x2)) { | |
879 | + len = write(rtk_hw_cfg.serial_fd, &h5_sync_resp_pkt, 0x8); | |
880 | + RS_DBG("Get SYNC pkt-active mode\n"); | |
881 | + } else if (!memcmp(skb->data, h5conf, 0x2)) { | |
882 | + len = write(rtk_hw_cfg.serial_fd, &h5_conf_resp_pkt_to_Ctrl, 0x8); | |
883 | + RS_DBG("Get CONFG pkt-active mode\n"); | |
884 | + } else if (!memcmp(skb->data, h5confresp, 0x2)) { | |
885 | + RS_DBG("Get CONFG resp pkt-active mode\n"); | |
886 | + rtk_hw_cfg.link_estab_state = H5_INIT; | |
887 | + } else { | |
888 | + RS_DBG("H5_CONFIG receive event\n"); | |
889 | + rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd); | |
890 | + } | |
891 | + skb_free(skb); | |
892 | + } else if (rtk_hw_cfg.link_estab_state == H5_INIT) { | |
893 | + if (skb->data[0] == cmd_complete_evt_code) { | |
894 | + hci_event_cmd_complete(skb); | |
895 | + } | |
896 | + | |
897 | + rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd); | |
898 | + usleep(10000); | |
899 | + rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd); | |
900 | + usleep(10000); | |
901 | + rtk_send_pure_ack_down(rtk_hw_cfg.serial_fd); | |
902 | + skb_free(skb); | |
903 | + } else if(rtk_hw_cfg.link_estab_state == H5_PATCH) { | |
904 | + rtk_hw_cfg.rx_index = skb->data[6]; | |
905 | + if (rtk_hw_cfg.rx_index & 0x80) | |
906 | + rtk_hw_cfg.rx_index &= ~0x80; | |
907 | + | |
908 | + RS_DBG("rtk_hw_cfg.rx_index %d\n", rtk_hw_cfg.rx_index ); | |
909 | + if (rtk_hw_cfg.rx_index == rtk_hw_cfg.total_num) | |
910 | + rtk_hw_cfg.link_estab_state = H5_ACTIVE; | |
911 | + skb_free(skb); | |
912 | + } else { | |
913 | + RS_ERR("receive packets in active state"); | |
914 | + skb_free(skb); | |
915 | + } | |
916 | +} | |
917 | + | |
918 | +/** | |
919 | +* after rx data is parsed, and we got a rx frame saved in h5->rx_skb, | |
920 | +* this routinue is called. | |
921 | +* things todo in this function: | |
922 | +* 1. check if it's a hci frame, if it is, complete it with response or ack | |
923 | +* 2. see the ack number, free acked frame in queue | |
924 | +* 3. reset h5->rx_state, set rx_skb to null. | |
925 | +* | |
926 | +* @param h5 realtek h5 struct | |
927 | +* | |
928 | +*/ | |
929 | +static void h5_complete_rx_pkt(rtk_hw_cfg_t *h5) | |
930 | +{ | |
931 | + int pass_up = 1; | |
932 | + uint8_t* h5_hdr = NULL; | |
933 | + | |
934 | + h5_hdr = (uint8_t *)(h5->rx_skb->data); | |
935 | + if (H5_HDR_RELIABLE(h5_hdr)) { | |
936 | + RS_DBG("Received reliable seqno %u from card", h5->rxseq_txack); | |
937 | + h5->rxseq_txack = H5_HDR_SEQ(h5_hdr) + 1; | |
938 | + h5->rxseq_txack %= 8; | |
939 | + h5->is_txack_req = 1; | |
940 | + } | |
941 | + | |
942 | + h5->rxack = H5_HDR_ACK(h5_hdr); | |
943 | + | |
944 | + switch (H5_HDR_PKT_TYPE(h5_hdr)) { | |
945 | + case HCI_ACLDATA_PKT: | |
946 | + case HCI_EVENT_PKT: | |
947 | + case HCI_SCODATA_PKT: | |
948 | + case HCI_COMMAND_PKT: | |
949 | + case H5_LINK_CTL_PKT: | |
950 | + pass_up = 1; | |
951 | + break; | |
952 | + | |
953 | + default: | |
954 | + pass_up = 0; | |
955 | + break; | |
956 | + } | |
957 | + | |
958 | + h5_remove_acked_pkt(h5); | |
959 | + | |
960 | + if (pass_up) { | |
961 | + skb_pull(h5->rx_skb, H5_HDR_SIZE); | |
962 | + hci_recv_frame(h5->rx_skb); | |
963 | + } else { | |
964 | + skb_free(h5->rx_skb); | |
965 | + } | |
966 | + | |
967 | + h5->rx_state = H5_W4_PKT_DELIMITER; | |
968 | + h5->rx_skb = NULL; | |
969 | +} | |
970 | + | |
971 | +/** | |
972 | +* Parse the receive data in h5 proto. | |
973 | +* | |
974 | +* @param h5 realtek h5 struct | |
975 | +* @param data point to data received before parse | |
976 | +* @param count num of data | |
977 | +* @return reserved count | |
978 | +*/ | |
979 | +static int h5_recv(rtk_hw_cfg_t *h5, void *data, int count) | |
980 | +{ | |
981 | + unsigned char *ptr; | |
982 | + //RS_DBG("count %d rx_state %d rx_count %ld", count, h5->rx_state, h5->rx_count); | |
983 | + ptr = (unsigned char *)data; | |
984 | + | |
985 | + while (count) { | |
986 | + if (h5->rx_count) { | |
987 | + if (*ptr == 0xc0) { | |
988 | + RS_ERR("short h5 packet"); | |
989 | + skb_free(h5->rx_skb); | |
990 | + h5->rx_state = H5_W4_PKT_START; | |
991 | + h5->rx_count = 0; | |
992 | + } else | |
993 | + h5_unslip_one_byte(h5, *ptr); | |
994 | + | |
995 | + ptr++; count--; | |
996 | + continue; | |
997 | + } | |
998 | + | |
999 | + switch (h5->rx_state) { | |
1000 | + case H5_W4_HDR: | |
1001 | + /* check header checksum. see Core Spec V4 "3-wire uart" page 67 */ | |
1002 | + if ((0xff & (RT_U8) ~ (h5->rx_skb->data[0] + h5->rx_skb->data[1] + | |
1003 | + h5->rx_skb->data[2])) != h5->rx_skb->data[3]) { | |
1004 | + RS_ERR("h5 hdr checksum error!!!"); | |
1005 | + skb_free(h5->rx_skb); | |
1006 | + h5->rx_state = H5_W4_PKT_DELIMITER; | |
1007 | + h5->rx_count = 0; | |
1008 | + continue; | |
1009 | + } | |
1010 | + | |
1011 | + /* reliable pkt & h5->hdr->SeqNumber != h5->Rxseq_txack */ | |
1012 | + if (h5->rx_skb->data[0] & 0x80 | |
1013 | + && (h5->rx_skb->data[0] & 0x07) != h5->rxseq_txack) { | |
1014 | + RS_ERR("Out-of-order packet arrived, got(%u)expected(%u)", | |
1015 | + h5->rx_skb->data[0] & 0x07, h5->rxseq_txack); | |
1016 | + h5->is_txack_req = 1; | |
1017 | + | |
1018 | + skb_free(h5->rx_skb); | |
1019 | + h5->rx_state = H5_W4_PKT_DELIMITER; | |
1020 | + h5->rx_count = 0; | |
1021 | + | |
1022 | + /* depend on weather remote will reset ack numb or not!!!!!!special */ | |
1023 | + if (rtk_hw_cfg.tx_index == rtk_hw_cfg.total_num) { | |
1024 | + rtk_hw_cfg.rxseq_txack = h5->rx_skb->data[0] & 0x07; | |
1025 | + } | |
1026 | + continue; | |
1027 | + } | |
1028 | + h5->rx_state = H5_W4_DATA; | |
1029 | + h5->rx_count = (h5->rx_skb->data[1] >> 4) + (h5->rx_skb->data[2] << 4); | |
1030 | + continue; | |
1031 | + | |
1032 | + case H5_W4_DATA: | |
1033 | + /* pkt with crc */ | |
1034 | + if (h5->rx_skb->data[0] & 0x40){ | |
1035 | + h5->rx_state = H5_W4_CRC; | |
1036 | + h5->rx_count = 2; | |
1037 | + } else { | |
1038 | + h5_complete_rx_pkt(h5); | |
1039 | + //RS_DBG(DF_SLIP,("--------> H5_W4_DATA ACK\n")); | |
1040 | + } | |
1041 | + continue; | |
1042 | + | |
1043 | + case H5_W4_CRC: | |
1044 | + if (bit_rev16(h5->message_crc) != h5_get_crc(h5)) { | |
1045 | + RS_ERR("Checksum failed, computed(%04x)received(%04x)", | |
1046 | + bit_rev16(h5->message_crc), h5_get_crc(h5)); | |
1047 | + skb_free(h5->rx_skb); | |
1048 | + h5->rx_state = H5_W4_PKT_DELIMITER; | |
1049 | + h5->rx_count = 0; | |
1050 | + continue; | |
1051 | + } | |
1052 | + skb_trim(h5->rx_skb, h5->rx_skb->data_len - 2); | |
1053 | + h5_complete_rx_pkt(h5); | |
1054 | + continue; | |
1055 | + | |
1056 | + case H5_W4_PKT_DELIMITER: | |
1057 | + switch (*ptr) { | |
1058 | + case 0xc0: | |
1059 | + h5->rx_state = H5_W4_PKT_START; | |
1060 | + break; | |
1061 | + | |
1062 | + default: | |
1063 | + break; | |
1064 | + } | |
1065 | + ptr++; count--; | |
1066 | + break; | |
1067 | + | |
1068 | + case H5_W4_PKT_START: | |
1069 | + switch (*ptr) { | |
1070 | + case 0xc0: | |
1071 | + ptr++; count--; | |
1072 | + break; | |
1073 | + | |
1074 | + default: | |
1075 | + h5->rx_state = H5_W4_HDR; | |
1076 | + h5->rx_count = 4; | |
1077 | + h5->rx_esc_state = H5_ESCSTATE_NOESC; | |
1078 | + H5_CRC_INIT(h5->message_crc); | |
1079 | + | |
1080 | + // Do not increment ptr or decrement count | |
1081 | + // Allocate packet. Max len of a H5 pkt= | |
1082 | + // 0xFFF (payload) +4 (header) +2 (crc) | |
1083 | + h5->rx_skb = skb_alloc(0x1005); | |
1084 | + if (!h5->rx_skb) | |
1085 | + { | |
1086 | + h5->rx_state = H5_W4_PKT_DELIMITER; | |
1087 | + h5->rx_count = 0; | |
1088 | + return 0; | |
1089 | + } | |
1090 | + break; | |
1091 | + } | |
1092 | + break; | |
1093 | + | |
1094 | + default: | |
1095 | + break; | |
1096 | + } | |
1097 | + } | |
1098 | + return count; | |
1099 | +} | |
1100 | + | |
1101 | +/** | |
1102 | +* Read data to buf from uart. | |
1103 | +* | |
1104 | +* @param fd uart file descriptor | |
1105 | +* @param buf point to the addr where read data stored | |
1106 | +* @param count num of data want to read | |
1107 | +* @return num of data successfully read | |
1108 | +*/ | |
1109 | +static int read_check_rtk(int fd, void *buf, int count) | |
1110 | +{ | |
1111 | + int res; | |
1112 | + do { | |
1113 | + res = read(fd, buf, count); | |
1114 | + if (res != -1) { | |
1115 | + buf = (RT_U8*)buf + res; | |
1116 | + count -= res; | |
1117 | + return res; | |
1118 | + } | |
1119 | + } while (count && (errno == 0 || errno == EINTR)); | |
1120 | + return res; | |
1121 | +} | |
1122 | + | |
1123 | +/** | |
1124 | +* Retry to sync when timeout in h5 proto, max retry times is 10. | |
1125 | +* | |
1126 | +* @warning Each time to retry, the time for timeout will be set as 1s. | |
1127 | +* | |
1128 | +* @param sig signaction for timeout | |
1129 | +* | |
1130 | +*/ | |
1131 | +static void h5_tsync_sig_alarm(int sig) | |
1132 | +{ | |
1133 | + unsigned char h5sync[2] = {0x01, 0x7E}; | |
1134 | + static int retries = 0; | |
1135 | + struct itimerval value; | |
1136 | + | |
1137 | + if (retries < rtk_hw_cfg.h5_max_retries) { | |
1138 | + retries++; | |
1139 | + struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, h5sync, sizeof(h5sync), H5_LINK_CTL_PKT); | |
1140 | + int len = write(rtk_hw_cfg.serial_fd, nskb->data, nskb->data_len); | |
1141 | + RS_DBG("3-wire sync pattern resend : %d, len: %d\n", retries, len); | |
1142 | + | |
1143 | + skb_free(nskb); | |
1144 | + //gordon add 2013-6-7 retry per 250ms | |
1145 | + value.it_value.tv_sec = 0; | |
1146 | + value.it_value.tv_usec = 250000; | |
1147 | + value.it_interval.tv_sec = 0; | |
1148 | + value.it_interval.tv_usec = 250000; | |
1149 | + setitimer(ITIMER_REAL, &value, NULL); | |
1150 | + //gordon end | |
1151 | + | |
1152 | + return; | |
1153 | + } | |
1154 | + | |
1155 | + tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH); | |
1156 | + RS_ERR("H5 sync timed out\n"); | |
1157 | + exit(1); | |
1158 | +} | |
1159 | + | |
1160 | +/** | |
1161 | +* Retry to config when timeout in h5 proto, max retry times is 10. | |
1162 | +* | |
1163 | +* @warning Each time to retry, the time for timeout will be set as 1s. | |
1164 | +* | |
1165 | +* @param sig signaction for timeout | |
1166 | +* | |
1167 | +*/ | |
1168 | +static void h5_tconf_sig_alarm(int sig) | |
1169 | +{ | |
1170 | + unsigned char h5conf[3] = {0x03, 0xFC, 0x14}; | |
1171 | + static int retries = 0; | |
1172 | + struct itimerval value; | |
1173 | + | |
1174 | + if (retries < rtk_hw_cfg.h5_max_retries) { | |
1175 | + retries++; | |
1176 | + struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, h5conf, 3, H5_LINK_CTL_PKT); | |
1177 | + int len = write(rtk_hw_cfg.serial_fd, nskb->data, nskb->data_len); | |
1178 | + RS_DBG("3-wire config pattern resend : %d , len: %d", retries, len); | |
1179 | + skb_free(nskb); | |
1180 | + | |
1181 | + //gordon add 2013-6-7 retry per 250ms | |
1182 | + value.it_value.tv_sec = 0; | |
1183 | + value.it_value.tv_usec = 250000; | |
1184 | + value.it_interval.tv_sec = 0; | |
1185 | + value.it_interval.tv_usec = 250000; | |
1186 | + setitimer(ITIMER_REAL, &value, NULL); | |
1187 | + | |
1188 | + return; | |
1189 | + } | |
1190 | + | |
1191 | + tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH); | |
1192 | + RS_ERR("H5 config timed out\n"); | |
1193 | + exit(1); | |
1194 | +} | |
1195 | + | |
1196 | +/** | |
1197 | +* Retry to init when timeout in h5 proto, max retry times is 10. | |
1198 | +* | |
1199 | +* @warning Each time to retry, the time for timeout will be set as 1s. | |
1200 | +* | |
1201 | +* @param sig signaction for timeout | |
1202 | +* | |
1203 | +*/ | |
1204 | +static void h5_tinit_sig_alarm(int sig) | |
1205 | +{ | |
1206 | + static int retries = 0; | |
1207 | + if (retries < rtk_hw_cfg.h5_max_retries) { | |
1208 | + retries++; | |
1209 | + if (rtk_hw_cfg.host_last_cmd) { | |
1210 | + int len = write(rtk_hw_cfg.serial_fd, rtk_hw_cfg.host_last_cmd->data, rtk_hw_cfg.host_last_cmd->data_len); | |
1211 | + RS_DBG("3-wire change baudrate re send:%d, len:%d", retries, len); | |
1212 | + alarm(1); | |
1213 | + return; | |
1214 | + } else { | |
1215 | + RS_DBG("3-wire init timeout without last command stored\n"); | |
1216 | + } | |
1217 | + } | |
1218 | + | |
1219 | + tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH); | |
1220 | + RS_ERR("H5 init process timed out"); | |
1221 | + exit(1); | |
1222 | +} | |
1223 | + | |
1224 | +/** | |
1225 | +* Retry to download patch when timeout in h5 proto, max retry times is 10. | |
1226 | +* | |
1227 | +* @warning Each time to retry, the time for timeout will be set as 3s. | |
1228 | +* | |
1229 | +* @param sig signaction for timeout | |
1230 | +* | |
1231 | +*/ | |
1232 | +static void h5_tpatch_sig_alarm(int sig) | |
1233 | +{ | |
1234 | + static int retries = 0; | |
1235 | + if (retries < rtk_hw_cfg.h5_max_retries) { | |
1236 | + RS_ERR("patch timerout, retry:\n"); | |
1237 | + if (rtk_hw_cfg.host_last_cmd) { | |
1238 | + int len = write(rtk_hw_cfg.serial_fd, rtk_hw_cfg.host_last_cmd->data, rtk_hw_cfg.host_last_cmd->data_len); | |
1239 | + RS_DBG("3-wire download patch re send:%d", retries ); | |
1240 | + } | |
1241 | + retries++; | |
1242 | + alarm(3); | |
1243 | + return; | |
1244 | + } | |
1245 | + RS_ERR("H5 patch timed out\n"); | |
1246 | + exit(1); | |
1247 | +} | |
1248 | + | |
1249 | +/** | |
1250 | +* Download patch using hci. For h5 proto, not recv reply for 2s will timeout. | |
1251 | +* Call h5_tpatch_sig_alarm for retry. | |
1252 | +* | |
1253 | +* @param dd uart file descriptor | |
1254 | +* @param index current index | |
1255 | +* @param data point to the config file | |
1256 | +* @param len current buf length | |
1257 | +* @return #0 on success | |
1258 | +* | |
1259 | +*/ | |
1260 | +static int hci_download_patch(int dd, int index, uint8_t *data, int len,struct termios *ti) | |
1261 | +{ | |
1262 | + unsigned char hcipatch[256] = {0x20, 0xfc, 00}; | |
1263 | + unsigned char bytes[READ_DATA_SIZE]; | |
1264 | + int retlen; | |
1265 | + struct sigaction sa; | |
1266 | + | |
1267 | + sa.sa_handler = h5_tpatch_sig_alarm; | |
1268 | + sigaction(SIGALRM, &sa, NULL); | |
1269 | + alarm(2); | |
1270 | + | |
1271 | + download_vendor_patch_cp cp; | |
1272 | + memset(&cp, 0, sizeof(cp)); | |
1273 | + cp.index = index; | |
1274 | + if (data != NULL) { | |
1275 | + memcpy(cp.data, data, len); | |
1276 | + } | |
1277 | + | |
1278 | + int nValue = rtk_hw_cfg.total_num|0x80; | |
1279 | + if (index == nValue) { | |
1280 | + rtk_hw_cfg.tx_index = rtk_hw_cfg.total_num; | |
1281 | + } else { | |
1282 | + rtk_hw_cfg.tx_index = index; | |
1283 | + } | |
1284 | + hcipatch[2] = len+1; | |
1285 | + memcpy(hcipatch+3, &cp, len+1); | |
1286 | + | |
1287 | + struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, hcipatch, len+4, HCI_COMMAND_PKT); //data:len+head:4 | |
1288 | + | |
1289 | + if (rtk_hw_cfg.host_last_cmd) { | |
1290 | + skb_free(rtk_hw_cfg.host_last_cmd); | |
1291 | + rtk_hw_cfg.host_last_cmd = NULL; | |
1292 | + } | |
1293 | + | |
1294 | + rtk_hw_cfg.host_last_cmd = nskb; | |
1295 | + | |
1296 | + len = write(dd, nskb->data, nskb->data_len); | |
1297 | + RS_DBG("hci_download_patch tx_index:%d rx_index: %d\n", rtk_hw_cfg.tx_index, rtk_hw_cfg.rx_index); | |
1298 | + | |
1299 | + while (rtk_hw_cfg.rx_index != rtk_hw_cfg.tx_index ) { //receive data and wait last pkt | |
1300 | + if ((retlen = read_check_rtk(dd, &bytes, READ_DATA_SIZE)) == -1) { | |
1301 | + perror("read fail"); | |
1302 | + return -1; | |
1303 | + } | |
1304 | + h5_recv(&rtk_hw_cfg, &bytes, retlen); | |
1305 | + } | |
1306 | + | |
1307 | + alarm(0); | |
1308 | + | |
1309 | + return 0; | |
1310 | +} | |
1311 | + | |
1312 | +/** | |
1313 | +* Download h4 patch | |
1314 | +* | |
1315 | +* @param dd uart file descriptor | |
1316 | +* @param index current index | |
1317 | +* @param data point to the config file | |
1318 | +* @param len current buf length | |
1319 | +* @return ret_index | |
1320 | +* | |
1321 | +*/ | |
1322 | +static int hci_download_patch_h4(int dd, int index, uint8_t *data, int len) | |
1323 | +{ | |
1324 | + unsigned char bytes[257] = {0}; | |
1325 | + unsigned char buf[257] = {0x01, 0x20, 0xfc, 00}; | |
1326 | + uint16_t readbytes = 0; | |
1327 | + int cur_index = index; | |
1328 | + int ret_Index = -1; | |
1329 | + uint16_t res = 0; | |
1330 | + int i = 0; | |
1331 | + size_t total_len; | |
1332 | + uint16_t w_len; | |
1333 | + uint8_t rstatus; | |
1334 | + | |
1335 | + RS_DBG("dd:%d, index:%d, len:%d", dd, index, len); | |
1336 | + if (NULL != data) { | |
1337 | + memcpy(&buf[5], data, len); | |
1338 | + } | |
1339 | + | |
1340 | + buf[3] = len + 1; | |
1341 | + buf[4] = cur_index; | |
1342 | + total_len = len + 5; | |
1343 | + | |
1344 | + w_len = write(dd, buf, total_len); | |
1345 | + RS_DBG("h4 write success with len: %d\n", w_len); | |
1346 | + | |
1347 | + while(readbytes < 8) { | |
1348 | + res = read(dd, bytes+i, 8); | |
1349 | + if (res < 0) | |
1350 | + break; | |
1351 | + readbytes += res; | |
1352 | + i = readbytes; | |
1353 | + } | |
1354 | + | |
1355 | + if((0x04 == bytes[0]) && (0x20 == bytes[4]) && (0xfc == bytes[5])) { | |
1356 | + ret_Index = bytes[7]; | |
1357 | + rstatus = bytes[6]; | |
1358 | + RS_DBG("---->ret_Index:%d, ----->rstatus:%d\n", ret_Index, rstatus); | |
1359 | + if(0x00 != rstatus) { | |
1360 | + RS_ERR("---->read event status is wrong\n"); | |
1361 | + return -1; | |
1362 | + } | |
1363 | + } else { | |
1364 | + RS_ERR("==========>Didn't read curret data\n"); | |
1365 | + return -1; | |
1366 | + } | |
1367 | + | |
1368 | + return ret_Index; | |
1369 | +} | |
1370 | + | |
1371 | +/** | |
1372 | +* Realtek change speed with h4 proto. Using vendor specified command packet to achieve this. | |
1373 | +* | |
1374 | +* @warning before write, need to wait 1s for device up | |
1375 | +* | |
1376 | +* @param fd uart file descriptor | |
1377 | +* @param baudrate the speed want to change | |
1378 | +* @return #0 on success | |
1379 | +*/ | |
1380 | +static int rtk_vendor_change_speed_h4(int fd, RT_U32 baudrate) | |
1381 | +{ | |
1382 | + int res; | |
1383 | + unsigned char bytes[257]; | |
1384 | + RT_U8 cmd[8] = {0}; | |
1385 | + | |
1386 | + cmd[0] = 1; //cmd; | |
1387 | + cmd[1] = 0x17; //ocf | |
1388 | + cmd[2] = 0xfc; //ogf | |
1389 | + cmd[3] = 4; //length; | |
1390 | + | |
1391 | + baudrate = cpu_to_le32(baudrate); | |
1392 | +#ifdef BAUDRATE_4BYTES | |
1393 | + memcpy((RT_U16*)&cmd[4], &baudrate, 4); | |
1394 | +#else | |
1395 | + memcpy((RT_U16*)&cmd[4], &baudrate, 2); | |
1396 | + cmd[6] = 0; | |
1397 | + cmd[7] = 0; | |
1398 | +#endif | |
1399 | + | |
1400 | + //wait for a while for device to up, just h4 need it | |
1401 | + sleep(1); | |
1402 | + RS_DBG("baudrate in change speed command: 0x%x 0x%x 0x%x 0x%x \n", cmd[4], cmd[5], cmd[6], cmd[7]); | |
1403 | + | |
1404 | + if( write(fd, cmd, 8) != 8) | |
1405 | + { | |
1406 | + RS_ERR("H4 change uart speed error when writing vendor command"); | |
1407 | + return -1; | |
1408 | + } | |
1409 | + RS_DBG("H4 Change uart Baudrate after write "); | |
1410 | + res = read(fd, bytes, sizeof(bytes)); | |
1411 | + | |
1412 | + if((0x04 == bytes[0]) && (0x17 == bytes[4]) && (0xfc == bytes[5])) | |
1413 | + { | |
1414 | + RS_DBG("H4 change uart speed success, receving status:%x", bytes[6]); | |
1415 | + if (bytes[6] == 0) | |
1416 | + return 0; | |
1417 | + } | |
1418 | + return -1; | |
1419 | +} | |
1420 | + | |
1421 | +/** | |
1422 | +* Get firmware name, Generally is /system/etc/firmware/rtl8723as/rlt8723a_chip_b_cut_bt40_fw | |
1423 | +* | |
1424 | +*/ | |
1425 | +static const char *get_firmware_name() | |
1426 | +{ | |
1427 | + static char firmware_file_name[PATH_MAX] = {0}; | |
1428 | + int ret = 0; | |
1429 | + struct stat st; | |
1430 | + | |
1431 | + ret = sprintf(firmware_file_name, FIRMWARE_DIRECTORY"rtlbt_fw"); | |
1432 | + | |
1433 | + return firmware_file_name; | |
1434 | +} | |
1435 | + | |
1436 | +/** | |
1437 | +* Parse realtek Bluetooth config file. | |
1438 | +* The config file if begin with vendor magic: RTK_VENDOR_CONFIG_MAGIC(8723ab55) | |
1439 | +* bt_addr is followed by 0x3c offset, it will be changed by bt_addr param | |
1440 | +* proto, baudrate and flow control is followed by 0xc offset, | |
1441 | +* | |
1442 | +* @param config_buf point to config file content | |
1443 | +* @param filelen length of config file | |
1444 | +* @param bt_addr where bt addr is stored | |
1445 | +* @return baudrate in config file | |
1446 | +* | |
1447 | +*/ | |
1448 | + | |
1449 | +RT_U32 rtk_parse_config_file(RT_U8* config_buf, size_t filelen, char bt_addr[6]) | |
1450 | +{ | |
1451 | + struct rtk_bt_vendor_config* config = (struct rtk_bt_vendor_config*) config_buf; | |
1452 | + RT_U16 config_len = 0, temp = 0; | |
1453 | + struct rtk_bt_vendor_config_entry* entry = NULL; | |
1454 | + RT_U16 i; | |
1455 | + RT_U32 baudrate = 0; | |
1456 | + | |
1457 | + if(config == NULL) | |
1458 | + return 0; | |
1459 | + | |
1460 | + config_len = le16_to_cpu(config->data_len); | |
1461 | + entry = config->entry; | |
1462 | + | |
1463 | + if (le32_to_cpu(config->signature) != RTK_VENDOR_CONFIG_MAGIC) { | |
1464 | + RS_ERR("config signature magic number(%x) is not set to RTK_VENDOR_CONFIG_MAGIC", (unsigned int)config->signature); | |
1465 | + return 0; | |
1466 | + } | |
1467 | + | |
1468 | + if (config_len != filelen - sizeof(struct rtk_bt_vendor_config)) { | |
1469 | + RS_ERR("config len(%d) is not right(%zd)", config_len, filelen-sizeof(struct rtk_bt_vendor_config)); | |
1470 | + return 0; | |
1471 | + } | |
1472 | + | |
1473 | + for (i=0; i<config_len;) { | |
1474 | + | |
1475 | + switch(le16_to_cpu(entry->offset)) { | |
1476 | +#ifdef USE_CUSTUMER_ADDRESS | |
1477 | + case 0x3c: | |
1478 | + { | |
1479 | + int j=0; | |
1480 | + for (j=0; j<entry->entry_len; j++) | |
1481 | + entry->entry_data[j] = bt_addr[entry->entry_len - 1 - j]; | |
1482 | + break; | |
1483 | + } | |
1484 | +#endif | |
1485 | + case 0xc: | |
1486 | + { | |
1487 | +#ifdef BAUDRATE_4BYTES | |
1488 | + baudrate = get_unaligned_le32(entry->entry_data); | |
1489 | +#else | |
1490 | + baudrate = get_unaligned_le16(entry->entry_data); | |
1491 | +#endif | |
1492 | + | |
1493 | + if (entry->entry_len >= 12) { //0ffset 0x18 - 0xc | |
1494 | + rtk_hw_cfg.hw_flow_control = (entry->entry_data[12] & 0x4) ? 1:0; //0x18 byte bit2 | |
1495 | + } | |
1496 | + RS_DBG("config baud rate to :%x, hwflowcontrol:%x, %x", | |
1497 | + (unsigned int)baudrate, entry->entry_data[12], rtk_hw_cfg.hw_flow_control); | |
1498 | + break; | |
1499 | + } | |
1500 | + default: | |
1501 | + RS_DBG("config offset(%x),length(%x)", entry->offset, entry->entry_len); | |
1502 | + break; | |
1503 | + } | |
1504 | + temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry); | |
1505 | + i += temp; | |
1506 | + entry = (struct rtk_bt_vendor_config_entry *)((RT_U8*)entry + temp); | |
1507 | + } | |
1508 | + | |
1509 | + return baudrate; | |
1510 | +} | |
1511 | + | |
1512 | +#ifdef USE_CUSTUMER_ADDRESS | |
1513 | +/** | |
1514 | +* get random realtek Bluetooth addr. | |
1515 | +* | |
1516 | +* @param bt_addr where bt addr is stored | |
1517 | +* | |
1518 | +*/ | |
1519 | +static void rtk_get_ram_addr(char bt_addr[0]) | |
1520 | +{ | |
1521 | + srand(time(NULL)+getpid()+getpid()*987654+rand()); | |
1522 | + | |
1523 | + RT_U32 addr = rand(); | |
1524 | + memcpy(bt_addr, &addr, sizeof(RT_U8)); | |
1525 | +} | |
1526 | + | |
1527 | +/** | |
1528 | +* Write the random bt addr to the file /data/misc/bluetoothd/bt_mac/btmac.txt. | |
1529 | +* | |
1530 | +* @param bt_addr where bt addr is stored | |
1531 | +* | |
1532 | +*/ | |
1533 | +static void rtk_write_btmac2file(char bt_addr[6]) | |
1534 | +{ | |
1535 | + int fd; | |
1536 | + mkdir(BT_ADDR_DIR, 0777); | |
1537 | + fd = open(BT_ADDR_FILE, O_CREAT|O_RDWR|O_TRUNC); | |
1538 | + | |
1539 | + if(fd > 0) { | |
1540 | + chmod(BT_ADDR_FILE, 0666); | |
1541 | + char addr[18]={0}; | |
1542 | + addr[17] = '\0'; | |
1543 | + sprintf(addr, "%2x:%2x:%2x:%2x:%2x:%2x", bt_addr[0], bt_addr[1], bt_addr[2], bt_addr[3], bt_addr[4], bt_addr[5]); | |
1544 | + write(fd, addr, strlen(addr)); | |
1545 | + close(fd); | |
1546 | + } else { | |
1547 | + RS_ERR("open file error:%s\n", BT_ADDR_FILE); | |
1548 | + } | |
1549 | +} | |
1550 | +#endif | |
1551 | + | |
1552 | +/** | |
1553 | +* Get realtek Bluetooth config file. The bt addr arg is stored in /data/btmac.txt, if there is not this file, | |
1554 | +* change to /data/misc/bluetoothd/bt_mac/btmac.txt. If both of them are not found, using | |
1555 | +* random bt addr. | |
1556 | +* | |
1557 | +* @param config_buf point to the content of realtek Bluetooth config file | |
1558 | +* @param config_baud_rate the baudrate set in the config file | |
1559 | +* @return file_len the length of config file | |
1560 | +*/ | |
1561 | +int rtk_get_bt_config(unsigned char** config_buf, RT_U32* config_baud_rate) | |
1562 | +{ | |
1563 | + char bt_config_file_name[PATH_MAX] = {0}; | |
1564 | + RT_U8* bt_addr_temp = NULL; | |
1565 | + char bt_addr[6]={0x00, 0xe0, 0x4c, 0x88, 0x88, 0x88}; | |
1566 | + struct stat st; | |
1567 | + size_t filelen; | |
1568 | + int fd; | |
1569 | + FILE* file = NULL; | |
1570 | + int ret = 0; | |
1571 | + int i = 0; | |
1572 | + | |
1573 | +#ifdef USE_CUSTUMER_ADDRESS | |
1574 | + sprintf(bt_config_file_name, BT_ADDR_FILE); | |
1575 | + if (stat(bt_config_file_name, &st) < 0) { | |
1576 | + RS_ERR("can't access bt bt_mac_addr file:%s, try use ramdom BT Addr\n", bt_config_file_name); | |
1577 | + | |
1578 | + for(i = 0; i < 6; i++) | |
1579 | + rtk_get_ram_addr(&bt_addr[i]); | |
1580 | + rtk_write_btmac2file(bt_addr); | |
1581 | + goto GET_CONFIG; | |
1582 | + } | |
1583 | + | |
1584 | + | |
1585 | + filelen = st.st_size; | |
1586 | + if ((file= fopen(bt_config_file_name, "rb")) == NULL) { | |
1587 | + RS_ERR("Can't open bt btaddr file, just use preset BT Addr"); | |
1588 | + } else { | |
1589 | + int i = 0; | |
1590 | + char temp; | |
1591 | + fscanf(file, "%2x:%2x:%2x:%2x:%2x:%2x", (unsigned int *)&bt_addr[0], (unsigned int*)&bt_addr[1], (unsigned int*)&bt_addr[2], (unsigned int*)&bt_addr[3], (unsigned int*)&bt_addr[4], (unsigned int*)&bt_addr[5]); | |
1592 | + | |
1593 | + /*reserve LAP addr from 0x9e8b00 to 0x9e8b3f, change to 0x008b***/ | |
1594 | + if(0x9e == bt_addr[3] && 0x8b == bt_addr[4] && (bt_addr[5] <= 0x3f)){ | |
1595 | + bt_addr[3] = 0x00; | |
1596 | + } | |
1597 | + RS_DBG("BT MAC IS : %X,%X,%X,%X,%X,%X\n", bt_addr[0], bt_addr[1], bt_addr[2], bt_addr[3], bt_addr[4], bt_addr[5]); | |
1598 | + | |
1599 | + fclose(file); | |
1600 | + } | |
1601 | +#endif | |
1602 | + | |
1603 | +GET_CONFIG: | |
1604 | + ret = sprintf(bt_config_file_name, BT_CONFIG_DIRECTORY"rtlbt_config"); | |
1605 | + if (stat(bt_config_file_name, &st) < 0) { | |
1606 | + RS_ERR("can't access bt config file:%s, errno:%d\n", bt_config_file_name, errno); | |
1607 | + return -1; | |
1608 | + } | |
1609 | + | |
1610 | + filelen = st.st_size; | |
1611 | + | |
1612 | + if ((fd = open(bt_config_file_name, O_RDONLY)) < 0) { | |
1613 | + perror("Can't open bt config file"); | |
1614 | + return -1; | |
1615 | + } | |
1616 | + | |
1617 | + if ((*config_buf = malloc(filelen)) == NULL) { | |
1618 | + RS_DBG("malloc buffer for config file fail(%zd)\n", filelen); | |
1619 | + close(fd); | |
1620 | + return -1; | |
1621 | + } | |
1622 | + | |
1623 | + //we may need to parse this config file. | |
1624 | + //for easy debug, only get need data. | |
1625 | + | |
1626 | + if (read(fd, *config_buf, filelen) < (ssize_t)filelen) { | |
1627 | + perror("Can't load bt config file"); | |
1628 | + free(*config_buf); | |
1629 | + close(fd); | |
1630 | + return -1; | |
1631 | + } | |
1632 | + | |
1633 | + *config_baud_rate = rtk_parse_config_file(*config_buf, filelen, bt_addr); | |
1634 | + RS_DBG("Get config baud rate from config file:%x",(unsigned int) *config_baud_rate); | |
1635 | + | |
1636 | + close(fd); | |
1637 | + return filelen; | |
1638 | +} | |
1639 | + | |
1640 | +/** | |
1641 | +* Realtek change speed with h5 proto. Using vendor specified command packet to achieve this. | |
1642 | +* | |
1643 | +* @warning it will waiting 2s for reply. | |
1644 | +* | |
1645 | +* @param fd uart file descriptor | |
1646 | +* @param baudrate the speed want to change | |
1647 | +* | |
1648 | +*/ | |
1649 | +int rtk_vendor_change_speed_h5(int fd, RT_U32 baudrate) | |
1650 | +{ | |
1651 | + struct sk_buff* cmd_change_bdrate = NULL; | |
1652 | + unsigned char cmd[7] = {0}; | |
1653 | + int retlen; | |
1654 | + unsigned char bytes[READ_DATA_SIZE]; | |
1655 | + struct sigaction sa; | |
1656 | + | |
1657 | + sa.sa_handler = h5_tinit_sig_alarm; | |
1658 | + sigaction(SIGALRM, &sa, NULL); | |
1659 | + | |
1660 | + cmd[0] = 0x17; //ocf | |
1661 | + cmd[1] = 0xfc; //ogf, vendor specified | |
1662 | + | |
1663 | + cmd[2] = 4; //length; | |
1664 | + | |
1665 | + baudrate = cpu_to_le32(baudrate); | |
1666 | +#ifdef BAUDRATE_4BYTES | |
1667 | + memcpy((RT_U16*)&cmd[3], &baudrate, 4); | |
1668 | +#else | |
1669 | + memcpy((RT_U16*)&cmd[3], &baudrate, 2); | |
1670 | + | |
1671 | + cmd[5] = 0; | |
1672 | + cmd[6] = 0; | |
1673 | +#endif | |
1674 | + | |
1675 | + RS_DBG("baudrate in change speed command: 0x%x 0x%x 0x%x 0x%x \n", cmd[3], cmd[4], cmd[5], cmd[6]); | |
1676 | + | |
1677 | + cmd_change_bdrate = h5_prepare_pkt(&rtk_hw_cfg, cmd, 7, HCI_COMMAND_PKT); | |
1678 | + if (!cmd_change_bdrate) { | |
1679 | + RS_ERR("Prepare command packet for change speed fail"); | |
1680 | + return -1; | |
1681 | + } | |
1682 | + | |
1683 | + rtk_hw_cfg.host_last_cmd = cmd_change_bdrate; | |
1684 | + alarm(1); | |
1685 | + write(fd, cmd_change_bdrate->data, cmd_change_bdrate->data_len); | |
1686 | + | |
1687 | + while (rtk_hw_cfg.link_estab_state == H5_INIT) { | |
1688 | + if ((retlen = read_check_rtk(fd, &bytes, READ_DATA_SIZE)) == -1) { | |
1689 | + perror("read fail"); | |
1690 | + return -1; | |
1691 | + } | |
1692 | + //add pure ack check | |
1693 | + h5_recv(&rtk_hw_cfg, &bytes, retlen); | |
1694 | + } | |
1695 | + | |
1696 | + alarm(0); | |
1697 | + return 0; | |
1698 | +} | |
1699 | + | |
1700 | +/** | |
1701 | +* Init realtek Bluetooth h5 proto. h5 proto is added by realtek in the right kernel. | |
1702 | +* Generally there are two steps: h5 sync and h5 config | |
1703 | +* | |
1704 | +* @param fd uart file descriptor | |
1705 | +* @param ti termios struct | |
1706 | +* | |
1707 | +*/ | |
1708 | +int rtk_init_h5(int fd, struct termios *ti) | |
1709 | +{ | |
1710 | + unsigned char bytes[READ_DATA_SIZE]; | |
1711 | + struct sigaction sa; | |
1712 | + int retlen; | |
1713 | + struct itimerval value; | |
1714 | + | |
1715 | + /* set even parity */ | |
1716 | + ti->c_cflag |= PARENB; | |
1717 | + ti->c_cflag &= ~(PARODD); | |
1718 | + if (tcsetattr(fd, TCSANOW, ti) < 0) { | |
1719 | + RS_ERR("Can't set port settings"); | |
1720 | + return -1; | |
1721 | + } | |
1722 | + | |
1723 | + rtk_hw_cfg.h5_max_retries = H5_MAX_RETRY_COUNT; | |
1724 | + | |
1725 | + alarm(0); | |
1726 | + memset(&sa, 0, sizeof(sa)); | |
1727 | + sa.sa_flags = SA_NOCLDSTOP; | |
1728 | + sa.sa_handler = h5_tsync_sig_alarm; | |
1729 | + sigaction(SIGALRM, &sa, NULL); | |
1730 | + | |
1731 | + /* h5 sync */ | |
1732 | + h5_tsync_sig_alarm(0); | |
1733 | + rtk_hw_cfg.link_estab_state = H5_SYNC; | |
1734 | + while (rtk_hw_cfg.link_estab_state == H5_SYNC) { | |
1735 | + if ((retlen = read_check_rtk(fd, &bytes, READ_DATA_SIZE)) == -1) { | |
1736 | + RS_ERR("H5 Read Sync Response Failed"); | |
1737 | + | |
1738 | + value.it_value.tv_sec = 0; | |
1739 | + value.it_value.tv_usec = 0; | |
1740 | + value.it_interval.tv_sec = 0; | |
1741 | + value.it_interval.tv_usec = 0; | |
1742 | + setitimer(ITIMER_REAL, &value, NULL); | |
1743 | + | |
1744 | + return -1; | |
1745 | + } | |
1746 | + h5_recv(&rtk_hw_cfg, &bytes, retlen); | |
1747 | + } | |
1748 | + | |
1749 | + value.it_value.tv_sec = 0; | |
1750 | + value.it_value.tv_usec = 0; | |
1751 | + value.it_interval.tv_sec = 0; | |
1752 | + value.it_interval.tv_usec = 0; | |
1753 | + setitimer(ITIMER_REAL, &value, NULL); | |
1754 | + | |
1755 | + /* h5 config */ | |
1756 | + sa.sa_handler = h5_tconf_sig_alarm; | |
1757 | + sigaction(SIGALRM, &sa, NULL); | |
1758 | + h5_tconf_sig_alarm(0); | |
1759 | + while (rtk_hw_cfg.link_estab_state == H5_CONFIG) { | |
1760 | + if ((retlen = read_check_rtk(fd, &bytes, READ_DATA_SIZE)) == -1) { | |
1761 | + RS_ERR("H5 Read Config Response Failed"); | |
1762 | + value.it_value.tv_sec = 0; | |
1763 | + value.it_value.tv_usec = 0; | |
1764 | + value.it_interval.tv_sec = 0; | |
1765 | + value.it_interval.tv_usec = 0; | |
1766 | + setitimer(ITIMER_REAL, &value, NULL); | |
1767 | + return -1; | |
1768 | + } | |
1769 | + h5_recv(&rtk_hw_cfg, &bytes, retlen); | |
1770 | + } | |
1771 | + | |
1772 | + value.it_value.tv_sec = 0; | |
1773 | + value.it_value.tv_usec = 0; | |
1774 | + value.it_interval.tv_sec = 0; | |
1775 | + value.it_interval.tv_usec = 0; | |
1776 | + setitimer(ITIMER_REAL, &value, NULL); | |
1777 | + | |
1778 | + rtk_send_pure_ack_down(fd); | |
1779 | + RS_DBG("H5 init finished\n"); | |
1780 | + | |
1781 | + rtk_hw_cfg.rom_version_cmd_state = cmd_not_send; | |
1782 | + rtk_hw_cfg.hci_version_cmd_state = cmd_not_send; | |
1783 | + return 0; | |
1784 | +} | |
1785 | + | |
1786 | +/** | |
1787 | +* Download realtek firmware and config file from uart with the proto. | |
1788 | +* Parse the content to serval packets follow the proto and then write the packets from uart | |
1789 | +* | |
1790 | +* @param fd uart file descriptor | |
1791 | +* @param buf addr where stor the content of firmware and config file | |
1792 | +* @param filesize length of buf | |
1793 | +* @param is_sent_changerate if baudrate need to be changed | |
1794 | +* @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE | |
1795 | +* | |
1796 | +*/ | |
1797 | +static int rtk_download_fw_config(int fd, RT_U8* buf, size_t filesize, int is_sent_changerate, int proto,struct termios *ti) | |
1798 | +{ | |
1799 | + uint8_t iCurIndex = 0; | |
1800 | + uint8_t iCurLen = 0; | |
1801 | + uint8_t iEndIndex = 0; | |
1802 | + uint8_t iLastPacketLen = 0; | |
1803 | + uint8_t iAdditionPkt = 0; | |
1804 | + uint8_t iTotalIndex = 0; | |
1805 | + uint8_t iCmdSentNum = 0; | |
1806 | + unsigned char *bufpatch; | |
1807 | + | |
1808 | + iEndIndex = (uint8_t)((filesize-1)/PATCH_DATA_FIELD_MAX_SIZE); | |
1809 | + iLastPacketLen = (filesize)%PATCH_DATA_FIELD_MAX_SIZE; | |
1810 | + | |
1811 | + if(is_sent_changerate) | |
1812 | + iCmdSentNum++; | |
1813 | + if(rtk_hw_cfg.rom_version_cmd_state >= cmd_has_sent) | |
1814 | + iCmdSentNum++; | |
1815 | + if(rtk_hw_cfg.hci_version_cmd_state >= cmd_has_sent) | |
1816 | + iCmdSentNum++; | |
1817 | + | |
1818 | + iAdditionPkt = (iEndIndex+1+iCmdSentNum)%8?(8-(iEndIndex+1+iCmdSentNum)%8):0; | |
1819 | + iTotalIndex = iAdditionPkt + iEndIndex; | |
1820 | + rtk_hw_cfg.total_num = iTotalIndex; //init TotalIndex | |
1821 | + | |
1822 | + RS_DBG("iEndIndex:%d iLastPacketLen:%d iAdditionpkt:%d\n", iEndIndex, iLastPacketLen, iAdditionPkt); | |
1823 | + | |
1824 | + if (iLastPacketLen == 0) | |
1825 | + iLastPacketLen = PATCH_DATA_FIELD_MAX_SIZE; | |
1826 | + | |
1827 | + bufpatch = buf; | |
1828 | + | |
1829 | + int i; | |
1830 | + for (i=0; i<=iTotalIndex; i++) { | |
1831 | + if (iCurIndex < iEndIndex) { | |
1832 | + iCurIndex = iCurIndex&0x7F; | |
1833 | + iCurLen = PATCH_DATA_FIELD_MAX_SIZE; | |
1834 | + } else if (iCurIndex == iEndIndex) { //send last data packet | |
1835 | + if (iCurIndex == iTotalIndex) | |
1836 | + iCurIndex = iCurIndex | 0x80; | |
1837 | + else | |
1838 | + iCurIndex = iCurIndex&0x7F; | |
1839 | + iCurLen = iLastPacketLen; | |
1840 | + } else if (iCurIndex < iTotalIndex) { | |
1841 | + iCurIndex = iCurIndex&0x7F; | |
1842 | + bufpatch = NULL; | |
1843 | + iCurLen = 0; | |
1844 | + } else { //send end packet | |
1845 | + bufpatch = NULL; | |
1846 | + iCurLen = 0; | |
1847 | + iCurIndex = iCurIndex|0x80; | |
1848 | + } | |
1849 | + | |
1850 | + if (iCurIndex & 0x80) | |
1851 | + RS_DBG("Send FW last command"); | |
1852 | + | |
1853 | + if (proto == HCI_UART_H4) { | |
1854 | + iCurIndex = hci_download_patch_h4(fd, iCurIndex, bufpatch, iCurLen); | |
1855 | + if ((iCurIndex != i) && (i != rtk_hw_cfg.total_num)) { | |
1856 | + RS_DBG("index mismatch i:%d iCurIndex:%d, patch fail\n", i, iCurIndex); | |
1857 | + return -1; | |
1858 | + } | |
1859 | + } else if (proto == HCI_UART_3WIRE) { | |
1860 | + if (hci_download_patch(fd, iCurIndex, bufpatch, iCurLen, ti) < 0) | |
1861 | + return -1; | |
1862 | + } | |
1863 | + | |
1864 | + if (iCurIndex < iEndIndex) { | |
1865 | + bufpatch += PATCH_DATA_FIELD_MAX_SIZE; | |
1866 | + } | |
1867 | + iCurIndex ++; | |
1868 | + } | |
1869 | + | |
1870 | + //set last ack packet down | |
1871 | + if (proto == HCI_UART_3WIRE) { | |
1872 | + rtk_send_pure_ack_down(fd); | |
1873 | + } | |
1874 | + | |
1875 | + return 0; | |
1876 | +} | |
1877 | + | |
1878 | +/** | |
1879 | +* Get realtek Bluetooth firmaware file. The content will be saved in *fw_buf which is malloc here. | |
1880 | +* The length malloc here will be lager than length of firmware file if there is a config file. | |
1881 | +* The content of config file will copy to the tail of *fw_buf in rtk_config. | |
1882 | +* | |
1883 | +* @param fw_buf point to the addr where stored the content of firmware. | |
1884 | +* @param addi_len length of config file. | |
1885 | +* @return length of *fw_buf. | |
1886 | +* | |
1887 | +*/ | |
1888 | +int rtk_get_bt_firmware(RT_U8** fw_buf) | |
1889 | +{ | |
1890 | + const char *filename; | |
1891 | + struct stat st; | |
1892 | + int fd = -1; | |
1893 | + size_t fwsize; | |
1894 | + | |
1895 | + filename = get_firmware_name(); | |
1896 | + | |
1897 | + if (stat(filename, &st) < 0) { | |
1898 | + RS_ERR("Can't access firmware, errno:%d", errno); | |
1899 | + return -1; | |
1900 | + } | |
1901 | + | |
1902 | + fwsize = st.st_size; | |
1903 | + | |
1904 | + if ((fd = open(filename, O_RDONLY)) < 0) { | |
1905 | + RS_ERR("Can't open firmware, errno:%d", errno); | |
1906 | + return -1; | |
1907 | + } | |
1908 | + | |
1909 | + if (!(*fw_buf = malloc(fwsize))) { | |
1910 | + RS_ERR("Can't alloc memory for fw&config, errno:%d", errno); | |
1911 | + close(fd); | |
1912 | + return -1; | |
1913 | + } | |
1914 | + | |
1915 | + if (read(fd, *fw_buf, fwsize) < (ssize_t) fwsize) { | |
1916 | + free(*fw_buf); | |
1917 | + *fw_buf = NULL; | |
1918 | + close(fd); | |
1919 | + return -1; | |
1920 | + } | |
1921 | + RS_DBG("Load FW OK"); | |
1922 | + close(fd); | |
1923 | + return fwsize; | |
1924 | +} | |
1925 | + | |
1926 | +//These two function(rtk<-->uart speed transfer) need check Host uart speed at first!!!! IMPORTANT | |
1927 | +//add more speed if neccessary | |
1928 | +typedef struct _baudrate_ex | |
1929 | +{ | |
1930 | + RT_U32 rtk_speed; | |
1931 | + int uart_speed; | |
1932 | +}baudrate_ex; | |
1933 | + | |
1934 | +#ifdef BAUDRATE_4BYTES | |
1935 | +baudrate_ex baudrates[] = | |
1936 | +{ | |
1937 | + {0x0252C014, 115200}, | |
1938 | + {0x0252C00A, 230400}, | |
1939 | + {0x05F75004, 921600}, | |
1940 | + {0x00005004, 1000000}, | |
1941 | + {0x04928002, 1500000}, | |
1942 | + {0x01128002, 1500000}, //8761AT | |
1943 | + {0x00005002, 2000000}, | |
1944 | + {0x0000B001, 2500000}, | |
1945 | + {0x04928001, 3000000}, | |
1946 | + {0x052A6001, 3500000}, | |
1947 | + {0x00005001, 4000000}, | |
1948 | +}; | |
1949 | +#else | |
1950 | +baudrate_ex baudrates[] = | |
1951 | +{ | |
1952 | + {0x701d, 115200} | |
1953 | + {0x6004, 921600}, | |
1954 | + {0x4003, 1500000}, | |
1955 | + {0x5002, 2000000}, | |
1956 | + {0x8001, 3000000}, | |
1957 | + {0x9001, 3000000}, | |
1958 | + {0x7001, 3500000}, | |
1959 | + {0x5001, 4000000}, | |
1960 | +}; | |
1961 | +#endif | |
1962 | + | |
1963 | +/** | |
1964 | +* Change realtek Bluetooth speed to uart speed. It is matching in the struct baudrates: | |
1965 | +* | |
1966 | +* @code | |
1967 | +* baudrate_ex baudrates[] = | |
1968 | +* { | |
1969 | +* {0x7001, 3500000}, | |
1970 | +* {0x6004, 921600}, | |
1971 | +* {0x4003, 1500000}, | |
1972 | +* {0x5001, 4000000}, | |
1973 | +* {0x5002, 2000000}, | |
1974 | +* {0x8001, 3000000}, | |
1975 | +* {0x701d, 115200} | |
1976 | +* }; | |
1977 | +* @endcode | |
1978 | +* | |
1979 | +* If there is no match in baudrates, uart speed will be set as #115200. | |
1980 | +* | |
1981 | +* @param rtk_speed realtek Bluetooth speed | |
1982 | +* @param uart_speed uart speed | |
1983 | +* | |
1984 | +*/ | |
1985 | +static void rtk_speed_to_uart_speed(RT_U32 rtk_speed, RT_U32* uart_speed) | |
1986 | +{ | |
1987 | + *uart_speed = 115200; | |
1988 | + | |
1989 | + unsigned int i; | |
1990 | + for (i = 0; i < sizeof(baudrates)/sizeof(baudrate_ex); i++) | |
1991 | + { | |
1992 | + if (baudrates[i].rtk_speed == rtk_speed){ | |
1993 | + *uart_speed = baudrates[i].uart_speed; | |
1994 | + return; | |
1995 | + } | |
1996 | + } | |
1997 | + return; | |
1998 | +} | |
1999 | + | |
2000 | +/** | |
2001 | +* Change uart speed to realtek Bluetooth speed. It is matching in the struct baudrates: | |
2002 | +* | |
2003 | +* @code | |
2004 | +* baudrate_ex baudrates[] = | |
2005 | +* { | |
2006 | +* {0x7001, 3500000}, | |
2007 | +* {0x6004, 921600}, | |
2008 | +* {0x4003, 1500000}, | |
2009 | +* {0x5001, 4000000}, | |
2010 | +* {0x5002, 2000000}, | |
2011 | +* {0x8001, 3000000}, | |
2012 | +* {0x701d, 115200} | |
2013 | +* }; | |
2014 | +* @endcode | |
2015 | +* | |
2016 | +* If there is no match in baudrates, realtek Bluetooth speed will be set as #0x701D. | |
2017 | +* | |
2018 | +* @param uart_speed uart speed | |
2019 | +* @param rtk_speed realtek Bluetooth speed | |
2020 | +* | |
2021 | +*/ | |
2022 | +static inline void uart_speed_to_rtk_speed(int uart_speed, RT_U32* rtk_speed) | |
2023 | +{ | |
2024 | + *rtk_speed = 0x701D; | |
2025 | + | |
2026 | + unsigned int i; | |
2027 | + for (i=0; i< sizeof(baudrates)/sizeof(baudrate_ex); i++) | |
2028 | + { | |
2029 | + if (baudrates[i].uart_speed == uart_speed){ | |
2030 | + *rtk_speed = baudrates[i].rtk_speed; | |
2031 | + return; | |
2032 | + } | |
2033 | + } | |
2034 | + | |
2035 | + return; | |
2036 | +} | |
2037 | + | |
2038 | +static void rtk_get_eversion_timeout(int sig) | |
2039 | +{ | |
2040 | + static int retries = 0; | |
2041 | + int len = 0; | |
2042 | + | |
2043 | + RS_DBG("RTK get HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n"); | |
2044 | + if (retries < rtk_hw_cfg.h5_max_retries) { | |
2045 | + RS_DBG("rtk get eversion timerout, retry:%d\n", retries); | |
2046 | + if (rtk_hw_cfg.host_last_cmd) { | |
2047 | + len = write(rtk_hw_cfg.serial_fd, | |
2048 | + rtk_hw_cfg.host_last_cmd->data, rtk_hw_cfg.host_last_cmd->data_len); | |
2049 | + } | |
2050 | + retries++; | |
2051 | + alarm(3); | |
2052 | + return; | |
2053 | + } | |
2054 | + tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH); | |
2055 | + RS_ERR("rtk get eversion cmd complete event timed out\n"); | |
2056 | + exit(1); | |
2057 | +} | |
2058 | + | |
2059 | +/** | |
2060 | +* Send vendor cmd to get eversion: 0xfc6d | |
2061 | +* If Rom code does not support this cmd, use default. | |
2062 | +*/ | |
2063 | +void rtk_get_eversion(int dd) | |
2064 | +{ | |
2065 | + unsigned char bytes[READ_DATA_SIZE]; | |
2066 | + int retlen; | |
2067 | + struct sigaction sa; | |
2068 | + unsigned char read_rom_patch_cmd[3] = {0x6d, 0xfc, 00}; | |
2069 | + struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, read_rom_patch_cmd, 3, HCI_COMMAND_PKT); | |
2070 | + | |
2071 | + if (rtk_hw_cfg.host_last_cmd){ | |
2072 | + skb_free(rtk_hw_cfg.host_last_cmd); | |
2073 | + rtk_hw_cfg.host_last_cmd = NULL; | |
2074 | + } | |
2075 | + | |
2076 | + rtk_hw_cfg.host_last_cmd = nskb; | |
2077 | + | |
2078 | + write(dd, nskb->data, nskb->data_len); | |
2079 | + rtk_hw_cfg.rom_version_cmd_state = cmd_has_sent; | |
2080 | + RS_DBG("RTK send HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n"); | |
2081 | + | |
2082 | + alarm(0); | |
2083 | + memset(&sa, 0, sizeof(sa)); | |
2084 | + sa.sa_flags = SA_NOCLDSTOP; | |
2085 | + sa.sa_handler = rtk_get_eversion_timeout; | |
2086 | + sigaction(SIGALRM, &sa, NULL); | |
2087 | + | |
2088 | + alarm(3); | |
2089 | + while (rtk_hw_cfg.rom_version_cmd_state != event_received) { | |
2090 | + if ((retlen = read_check_rtk(dd, &bytes, READ_DATA_SIZE)) == -1) | |
2091 | + { | |
2092 | + perror("rtk get eversion: read fail"); | |
2093 | + return; | |
2094 | + } | |
2095 | + h5_recv(&rtk_hw_cfg, &bytes, retlen); | |
2096 | + } | |
2097 | + alarm(0); | |
2098 | + return; | |
2099 | +} | |
2100 | + | |
2101 | +static void rtk_get_lmp_version_timeout(int sig) | |
2102 | +{ | |
2103 | + static int retries = 0; | |
2104 | + RS_DBG("RTK get HCI_VENDOR_READ_RTK_LMP_VERISION_Command\n"); | |
2105 | + if (retries < rtk_hw_cfg.h5_max_retries) { | |
2106 | + RS_DBG("rtk get lmp version timeout, retry: %d\n", retries); | |
2107 | + if (rtk_hw_cfg.host_last_cmd) | |
2108 | + { | |
2109 | + int len = write(rtk_hw_cfg.serial_fd, | |
2110 | + rtk_hw_cfg.host_last_cmd->data, rtk_hw_cfg.host_last_cmd->data_len); | |
2111 | + } | |
2112 | + retries++; | |
2113 | + alarm(3); | |
2114 | + return; | |
2115 | + } | |
2116 | + tcflush(rtk_hw_cfg.serial_fd, TCIOFLUSH); | |
2117 | + RS_ERR("rtk get lmp version cmd complete event timed out\n"); | |
2118 | + exit(1); | |
2119 | +} | |
2120 | + | |
2121 | +void rtk_get_lmp_version(int dd) | |
2122 | +{ | |
2123 | + unsigned char bytes[READ_DATA_SIZE]; | |
2124 | + int retlen; | |
2125 | + struct sigaction sa; | |
2126 | + unsigned char read_rom_patch_cmd[3] = {0x01, 0x10, 00}; | |
2127 | + struct sk_buff *nskb = h5_prepare_pkt(&rtk_hw_cfg, read_rom_patch_cmd, 3, HCI_COMMAND_PKT); //data:len+head:4 | |
2128 | + | |
2129 | + if (rtk_hw_cfg.host_last_cmd){ | |
2130 | + skb_free(rtk_hw_cfg.host_last_cmd); | |
2131 | + rtk_hw_cfg.host_last_cmd = NULL; | |
2132 | + } | |
2133 | + | |
2134 | + rtk_hw_cfg.host_last_cmd = nskb; | |
2135 | + | |
2136 | + write(dd, nskb->data, nskb->data_len); | |
2137 | + rtk_hw_cfg.hci_version_cmd_state = cmd_has_sent; | |
2138 | + RS_DBG("RTK send HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n"); | |
2139 | + | |
2140 | + alarm(0); | |
2141 | + memset(&sa, 0, sizeof(sa)); | |
2142 | + sa.sa_flags = SA_NOCLDSTOP; | |
2143 | + sa.sa_handler = rtk_get_lmp_version_timeout; | |
2144 | + sigaction(SIGALRM, &sa, NULL); | |
2145 | + | |
2146 | + alarm(3); | |
2147 | + while (rtk_hw_cfg.hci_version_cmd_state != event_received) { | |
2148 | + if ((retlen = read_check_rtk(dd, &bytes, READ_DATA_SIZE)) == -1) | |
2149 | + { | |
2150 | + perror("read fail"); | |
2151 | + return; | |
2152 | + } | |
2153 | + h5_recv(&rtk_hw_cfg, &bytes, retlen); | |
2154 | + } | |
2155 | + alarm(0); | |
2156 | + return; | |
2157 | +} | |
2158 | + | |
2159 | +uint8_t rtk_get_fw_project_id(uint8_t *p_buf) | |
2160 | +{ | |
2161 | + uint8_t opcode; | |
2162 | + uint8_t len; | |
2163 | + uint8_t data = 0; | |
2164 | + | |
2165 | + do { | |
2166 | + opcode = *p_buf; | |
2167 | + len = *(p_buf - 1); | |
2168 | + if (opcode == 0x00) { | |
2169 | + if (len == 1) { | |
2170 | + data = *(p_buf - 2); | |
2171 | + RS_DBG("rtk_get_fw_project_id: opcode %d, len %d, data %d", opcode, len, data); | |
2172 | + break; | |
2173 | + } else { | |
2174 | + RS_ERR("rtk_get_fw_project_id: invalid len %d", len); | |
2175 | + } | |
2176 | + } | |
2177 | + p_buf -= len + 2; | |
2178 | + } while (*p_buf != 0xFF); | |
2179 | + | |
2180 | + return data; | |
2181 | +} | |
2182 | + | |
2183 | +struct rtk_epatch_entry *rtk_get_patch_entry(void) | |
2184 | +{ | |
2185 | + uint16_t i; | |
2186 | + struct rtk_epatch *patch; | |
2187 | + struct rtk_epatch_entry *entry; | |
2188 | + uint8_t *p; | |
2189 | + uint16_t chip_id; | |
2190 | + | |
2191 | + patch = (struct rtk_epatch *)rtk_hw_cfg.fw_buf; | |
2192 | + entry = (struct rtk_epatch_entry *)malloc(sizeof(*entry)); | |
2193 | + if(!entry) { | |
2194 | + RS_ERR("failed to allocate mem for patch entry"); | |
2195 | + return NULL; | |
2196 | + } | |
2197 | + | |
2198 | + patch->number_of_patch = le16_to_cpu(patch->number_of_patch); | |
2199 | + | |
2200 | + RS_DBG("fw_ver 0x%08x, patch_num %d", | |
2201 | + le32_to_cpu(patch->fw_version), patch->number_of_patch); | |
2202 | + | |
2203 | + for (i = 0; i < patch->number_of_patch; i++) { | |
2204 | + if(get_unaligned_le16(rtk_hw_cfg.fw_buf+14+2*i) == rtk_hw_cfg.eversion + 1) { | |
2205 | + entry->chipID = rtk_hw_cfg.eversion + 1; | |
2206 | + entry->patch_length = get_unaligned_le16(rtk_hw_cfg.fw_buf+14+2*patch->number_of_patch+2*i); | |
2207 | + entry->start_offset = get_unaligned_le32(rtk_hw_cfg.fw_buf+14+4*patch->number_of_patch+4*i); | |
2208 | + RS_DBG("patch length is 0x%x", entry->patch_length); | |
2209 | + RS_DBG("start offset is 0x%x", entry->start_offset); | |
2210 | + break; | |
2211 | + } | |
2212 | + | |
2213 | + } | |
2214 | + | |
2215 | + if (i == patch->number_of_patch) { | |
2216 | + RS_ERR("failed to get etnry"); | |
2217 | + free(entry); | |
2218 | + entry = NULL; | |
2219 | + } | |
2220 | + | |
2221 | + return entry; | |
2222 | +} | |
2223 | + | |
2224 | +void rtk_get_final_patch(int fd, int proto) | |
2225 | +{ | |
2226 | + uint8_t proj_id = 0; | |
2227 | + struct rtk_epatch_entry* entry = NULL; | |
2228 | + struct rtk_epatch *patch = (struct rtk_epatch *)rtk_hw_cfg.fw_buf; | |
2229 | + | |
2230 | + if (proto == HCI_UART_3WIRE) { | |
2231 | + rtk_get_lmp_version(fd); | |
2232 | + RS_DBG("gLmpVersion = 0x%x", rtk_hw_cfg.lmp_version); | |
2233 | + } | |
2234 | + | |
2235 | + if ((proto == HCI_UART_H4) || ((proto == HCI_UART_3WIRE) && (rtk_hw_cfg.lmp_version == ROM_LMP_8723a))){ | |
2236 | + if(memcmp(rtk_hw_cfg.fw_buf, RTK_EPATCH_SIGNATURE, 8) == 0){ | |
2237 | + RS_ERR("Check signature error!"); | |
2238 | + rtk_hw_cfg.dl_fw_flag = 0; | |
2239 | + goto free_buf; | |
2240 | + } else { | |
2241 | + rtk_hw_cfg.total_len = rtk_hw_cfg.config_len + rtk_hw_cfg.fw_len; | |
2242 | + if (!(rtk_hw_cfg.total_buf = malloc(rtk_hw_cfg.total_len))) { | |
2243 | + RS_ERR("Can't alloc memory for fw&config, errno:%d", errno); | |
2244 | + rtk_hw_cfg.dl_fw_flag = 0; | |
2245 | + rtk_hw_cfg.total_len = 0; | |
2246 | + goto free_buf; | |
2247 | + } else { | |
2248 | + RS_DBG("fw copy directy"); | |
2249 | + memcpy(rtk_hw_cfg.total_buf, rtk_hw_cfg.fw_buf, rtk_hw_cfg.fw_len); | |
2250 | + if (rtk_hw_cfg.config_len) | |
2251 | + memcpy(rtk_hw_cfg.total_buf+rtk_hw_cfg.fw_len, rtk_hw_cfg.config_buf, rtk_hw_cfg.config_len); | |
2252 | + rtk_hw_cfg.dl_fw_flag = 1; | |
2253 | + goto free_buf; | |
2254 | + } | |
2255 | + } | |
2256 | + } | |
2257 | + | |
2258 | + rtk_get_eversion(fd); | |
2259 | + RS_DBG("rtk_hw_cfg.eversion = %d", rtk_hw_cfg.eversion); | |
2260 | + | |
2261 | + if (memcmp(rtk_hw_cfg.fw_buf, RTK_EPATCH_SIGNATURE, 8)) { | |
2262 | + RS_DBG("check signature error!"); | |
2263 | + rtk_hw_cfg.dl_fw_flag = 0; | |
2264 | + goto free_buf; | |
2265 | + } | |
2266 | + | |
2267 | + if (memcmp(rtk_hw_cfg.fw_buf + rtk_hw_cfg.fw_len - 4, Extension_Section_SIGNATURE, 4)) { | |
2268 | + RS_ERR("check extension section signature error"); | |
2269 | + rtk_hw_cfg.dl_fw_flag = 0; | |
2270 | + goto free_buf; | |
2271 | + } | |
2272 | + | |
2273 | + proj_id = rtk_get_fw_project_id(rtk_hw_cfg.fw_buf + rtk_hw_cfg.fw_len - 5); | |
2274 | + if(rtk_hw_cfg.lmp_version != project_id[proj_id]) { | |
2275 | + RS_ERR("lmp_version is %x, project_id is %x, does not match!!!", | |
2276 | + rtk_hw_cfg.lmp_version, project_id[proj_id]); | |
2277 | + rtk_hw_cfg.dl_fw_flag = 0; | |
2278 | + goto free_buf; | |
2279 | + } | |
2280 | + | |
2281 | + entry = rtk_get_patch_entry(); | |
2282 | + | |
2283 | + if(entry) | |
2284 | + rtk_hw_cfg.total_len = entry->patch_length + rtk_hw_cfg.config_len; | |
2285 | + else { | |
2286 | + rtk_hw_cfg.dl_fw_flag = 0; | |
2287 | + goto free_buf; | |
2288 | + } | |
2289 | + | |
2290 | + if (!(rtk_hw_cfg.total_buf = malloc(rtk_hw_cfg.total_len))) { | |
2291 | + RS_ERR("Can't alloc memory for multi fw&config, errno:%d", errno); | |
2292 | + rtk_hw_cfg.dl_fw_flag = 0; | |
2293 | + rtk_hw_cfg.total_len = 0; | |
2294 | + goto free_buf; | |
2295 | + } else { | |
2296 | + memcpy(rtk_hw_cfg.total_buf, rtk_hw_cfg.fw_buf + entry->start_offset, entry->patch_length); | |
2297 | + memcpy(rtk_hw_cfg.total_buf + entry->patch_length - 4, &patch->fw_version, 4); | |
2298 | + if (rtk_hw_cfg.config_len) | |
2299 | + memcpy(rtk_hw_cfg.total_buf+entry->patch_length, rtk_hw_cfg.config_buf, rtk_hw_cfg.config_len); | |
2300 | + rtk_hw_cfg.dl_fw_flag = 1; | |
2301 | + } | |
2302 | + | |
2303 | + RS_DBG("fw:%s exists, config file:%s exists", (rtk_hw_cfg.fw_len>0)?"":"not", (rtk_hw_cfg.config_len>0)?"":"not"); | |
2304 | + | |
2305 | +free_buf: | |
2306 | + if (rtk_hw_cfg.fw_len > 0) { | |
2307 | + free(rtk_hw_cfg.fw_buf); | |
2308 | + rtk_hw_cfg.fw_len = 0; | |
2309 | + } | |
2310 | + | |
2311 | + if (rtk_hw_cfg.config_len > 0) { | |
2312 | + free(rtk_hw_cfg.config_buf); | |
2313 | + rtk_hw_cfg.config_len = 0; | |
2314 | + } | |
2315 | + | |
2316 | + if(entry) | |
2317 | + free(entry); | |
2318 | +} | |
2319 | + | |
2320 | +/** | |
2321 | +* Config realtek Bluetooth. The configuration parameter is get from config file and fw. | |
2322 | +* Config file is rtk8723_bt_config. which is set in rtk_get_bt_config. | |
2323 | +* fw file is "rlt8723a_chip_b_cut_bt40_fw", which is set in get_firmware_name. | |
2324 | +* | |
2325 | +* @warning maybe only one of config file and fw file exists. The bt_addr arg is stored in "/data/btmac.txt" | |
2326 | +* or "/data/misc/bluetoothd/bt_mac/btmac.txt", | |
2327 | +* | |
2328 | +* @param fd uart file descriptor | |
2329 | +* @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE | |
2330 | +* @param speed init_speed in uart struct | |
2331 | +* @param ti termios struct | |
2332 | +* @returns #0 on success | |
2333 | +*/ | |
2334 | +static int rtk_config(int fd, int proto, int speed, struct termios *ti) | |
2335 | +{ | |
2336 | + int final_speed = 0; | |
2337 | + int ret = 0; | |
2338 | + | |
2339 | + rtk_hw_cfg.config_len = rtk_get_bt_config(&rtk_hw_cfg.config_buf, &rtk_hw_cfg.baudrate); | |
2340 | + if (rtk_hw_cfg.config_len < 0) { | |
2341 | + RS_ERR("Get Config file error, just use efuse settings"); | |
2342 | + rtk_hw_cfg.config_len = 0; | |
2343 | + } | |
2344 | + | |
2345 | + rtk_hw_cfg.fw_len = rtk_get_bt_firmware(&rtk_hw_cfg.fw_buf); | |
2346 | + if (rtk_hw_cfg.fw_len < 0) { | |
2347 | + RS_ERR("Get BT firmware error"); | |
2348 | + rtk_hw_cfg.fw_len = 0; | |
2349 | + return -1; | |
2350 | + }else { | |
2351 | + rtk_get_final_patch(fd, proto); | |
2352 | + } | |
2353 | + | |
2354 | + if (rtk_hw_cfg.total_len > RTK_PATCH_LENGTH_MAX) { | |
2355 | + RS_ERR("total length of fw&config larger than allowed"); | |
2356 | + return -1; | |
2357 | + } | |
2358 | + | |
2359 | + /* change baudrate if needed */ | |
2360 | + if (rtk_hw_cfg.baudrate == 0) { | |
2361 | + uart_speed_to_rtk_speed(speed, &rtk_hw_cfg.baudrate); | |
2362 | + RS_DBG("no config file to set uart baudrate, use input parameters:%x, %x", | |
2363 | + (unsigned int)speed, (unsigned int)rtk_hw_cfg.baudrate); | |
2364 | + goto SET_FLOW_CONTRL; | |
2365 | + } else | |
2366 | + rtk_speed_to_uart_speed(rtk_hw_cfg.baudrate, (RT_U32*)&(rtk_hw_cfg.final_speed)); | |
2367 | + | |
2368 | + if (proto == HCI_UART_3WIRE) | |
2369 | + rtk_vendor_change_speed_h5(fd, rtk_hw_cfg.baudrate); | |
2370 | + else | |
2371 | + rtk_vendor_change_speed_h4(fd, rtk_hw_cfg.baudrate); | |
2372 | + | |
2373 | + usleep(50000); | |
2374 | + final_speed = rtk_hw_cfg.final_speed ? rtk_hw_cfg.final_speed : speed; | |
2375 | + RS_DBG("final_speed %d\n",final_speed); | |
2376 | + if (set_speed(fd, ti, final_speed) < 0) { | |
2377 | + RS_ERR("Can't set baud rate:%x, %x, %x", final_speed, rtk_hw_cfg.final_speed, speed); | |
2378 | + return -1; | |
2379 | + } | |
2380 | + | |
2381 | +SET_FLOW_CONTRL: | |
2382 | + if (rtk_hw_cfg.hw_flow_control) { | |
2383 | + RS_DBG("hw flow control enable"); | |
2384 | + ti->c_cflag |= CRTSCTS; | |
2385 | + | |
2386 | + if (tcsetattr(fd, TCSANOW, ti) < 0) { | |
2387 | + RS_ERR("Can't set port settings"); | |
2388 | + return -1; | |
2389 | + } | |
2390 | + } else { | |
2391 | + RS_DBG("hw flow control disable"); | |
2392 | + ti->c_cflag &= ~CRTSCTS; | |
2393 | + } | |
2394 | + | |
2395 | + /* wait for while for controller to setup */ | |
2396 | + usleep(10000); | |
2397 | + | |
2398 | + if ((rtk_hw_cfg.total_len > 0) && (rtk_hw_cfg.dl_fw_flag)) { | |
2399 | + rtk_hw_cfg.link_estab_state = H5_PATCH; | |
2400 | + rtk_hw_cfg.rx_index = -1; | |
2401 | + | |
2402 | + ret = rtk_download_fw_config(fd, rtk_hw_cfg.total_buf, rtk_hw_cfg.total_len, rtk_hw_cfg.baudrate, proto, ti); | |
2403 | + free(rtk_hw_cfg.total_buf); | |
2404 | + | |
2405 | + if (ret < 0) | |
2406 | + return ret; | |
2407 | + } | |
2408 | + RS_DBG("Init Process finished"); | |
2409 | + return 0; | |
2410 | +} | |
2411 | + | |
2412 | +/** | |
2413 | +* Init uart by realtek Bluetooth. | |
2414 | +* | |
2415 | +* @param fd uart file descriptor | |
2416 | +* @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE | |
2417 | +* @param speed init_speed in uart struct | |
2418 | +* @param ti termios struct | |
2419 | +* @returns #0 on success, depend on rtk_config | |
2420 | +*/ | |
2421 | +int rtk_init(int fd, int proto, int speed, struct termios *ti) | |
2422 | +{ | |
2423 | + struct sigaction sa; | |
2424 | + int retlen; | |
2425 | + RS_DBG("Realtek hciattach version %s \n", RTK_VERSION); | |
2426 | + | |
2427 | + memset(&rtk_hw_cfg, 0, sizeof(rtk_hw_cfg)); | |
2428 | + rtk_hw_cfg.serial_fd = fd; | |
2429 | + rtk_hw_cfg.dl_fw_flag = 1; | |
2430 | + | |
2431 | + /* h4 will do nothing for init */ | |
2432 | + if (proto == HCI_UART_3WIRE) { | |
2433 | + if(rtk_init_h5(fd, ti) < 0) | |
2434 | + return -1;; | |
2435 | + } | |
2436 | + | |
2437 | + return rtk_config(fd, proto, speed, ti); | |
2438 | +} | |
2439 | + | |
2440 | +/** | |
2441 | +* Post uart by realtek Bluetooth. If gFinalSpeed is set, set uart speed with it. | |
2442 | +* | |
2443 | +* @param fd uart file descriptor | |
2444 | +* @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE | |
2445 | +* @param ti termios struct | |
2446 | +* @returns #0 on success. | |
2447 | +*/ | |
2448 | +int rtk_post(int fd, int proto, struct termios *ti) | |
2449 | +{ | |
2450 | + if (rtk_hw_cfg.final_speed) | |
2451 | + return set_speed(fd, ti, rtk_hw_cfg.final_speed); | |
2452 | + | |
2453 | + return 0; | |
2454 | +} |