xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bluetooth_usb_driver/rtk_misc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  *  Realtek Bluetooth USB download firmware driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  This program is free software; you can redistribute it and/or modify
7*4882a593Smuzhiyun  *  it under the terms of the GNU General Public License as published by
8*4882a593Smuzhiyun  *  the Free Software Foundation; either version 2 of the License, or
9*4882a593Smuzhiyun  *  (at your option) any later version.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *  This program is distributed in the hope that it will be useful,
12*4882a593Smuzhiyun  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13*4882a593Smuzhiyun  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*4882a593Smuzhiyun  *  GNU General Public License for more details.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  *  You should have received a copy of the GNU General Public License
17*4882a593Smuzhiyun  *  along with this program; if not, write to the Free Software
18*4882a593Smuzhiyun  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <linux/kernel.h>
23*4882a593Smuzhiyun #include <linux/module.h>
24*4882a593Smuzhiyun #include <linux/init.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <linux/types.h>
27*4882a593Smuzhiyun #include <linux/sched.h>
28*4882a593Smuzhiyun #include <linux/errno.h>
29*4882a593Smuzhiyun #include <linux/skbuff.h>
30*4882a593Smuzhiyun #include <linux/usb.h>
31*4882a593Smuzhiyun #include <linux/dcache.h>
32*4882a593Smuzhiyun #include <linux/in.h>
33*4882a593Smuzhiyun #include <net/sock.h>
34*4882a593Smuzhiyun #include <asm/unaligned.h>
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #include <linux/interrupt.h>
37*4882a593Smuzhiyun #include <linux/module.h>
38*4882a593Smuzhiyun #include <linux/slab.h>
39*4882a593Smuzhiyun #include <linux/types.h>
40*4882a593Smuzhiyun #include <linux/sched.h>
41*4882a593Smuzhiyun #include <linux/skbuff.h>
42*4882a593Smuzhiyun #include <linux/errno.h>
43*4882a593Smuzhiyun #include <linux/usb.h>
44*4882a593Smuzhiyun #include <linux/cdev.h>
45*4882a593Smuzhiyun #include <linux/device.h>
46*4882a593Smuzhiyun #include <linux/poll.h>
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #include <linux/version.h>
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
51*4882a593Smuzhiyun #include <linux/pm_runtime.h>
52*4882a593Smuzhiyun #endif
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #include <linux/firmware.h>
55*4882a593Smuzhiyun #include <linux/suspend.h>
56*4882a593Smuzhiyun #include <net/bluetooth/bluetooth.h>
57*4882a593Smuzhiyun #include <net/bluetooth/hci_core.h>
58*4882a593Smuzhiyun #include <net/bluetooth/hci.h>
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #include "rtk_misc.h"
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #include <linux/file.h>
63*4882a593Smuzhiyun #include <linux/ctype.h>
64*4882a593Smuzhiyun #define BDADDR_STRING_LEN	17
65*4882a593Smuzhiyun #define BDADDR_FILE		"/opt/bdaddr"
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun struct cfg_list_item {
68*4882a593Smuzhiyun 	struct list_head list;
69*4882a593Smuzhiyun 	u16 offset;
70*4882a593Smuzhiyun 	u8 len;
71*4882a593Smuzhiyun 	u8 data[0];
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun static struct list_head list_configs;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #define EXTRA_CONFIG_FILE	"/opt/rtk_btconfig.txt"
77*4882a593Smuzhiyun static struct list_head list_extracfgs;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define CMD_CMP_EVT		    0x0e
80*4882a593Smuzhiyun #define PKT_LEN			    300
81*4882a593Smuzhiyun #define MSG_TO			    1000	//us
82*4882a593Smuzhiyun #define PATCH_SEG_MAX	    252
83*4882a593Smuzhiyun #define DATA_END		    0x80
84*4882a593Smuzhiyun #define DOWNLOAD_OPCODE	    0xfc20
85*4882a593Smuzhiyun /* This command is used only for TV patch
86*4882a593Smuzhiyun  * if host is going to suspend state, it should send this command to
87*4882a593Smuzhiyun  * Controller. Controller will scan the special advertising packet
88*4882a593Smuzhiyun  * which indicates Controller to wake up host */
89*4882a593Smuzhiyun #define STARTSCAN_OPCODE	    0xfc28
90*4882a593Smuzhiyun #define TRUE			    1
91*4882a593Smuzhiyun #define FALSE			    0
92*4882a593Smuzhiyun #define CMD_HDR_LEN		    sizeof(struct hci_command_hdr)
93*4882a593Smuzhiyun #define EVT_HDR_LEN		    sizeof(struct hci_event_hdr)
94*4882a593Smuzhiyun #define CMD_CMP_LEN		    sizeof(struct hci_ev_cmd_complete)
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define HCI_CMD_READ_BD_ADDR                0x1009
97*4882a593Smuzhiyun #define HCI_VENDOR_CHANGE_BDRATE            0xfc17
98*4882a593Smuzhiyun #define HCI_VENDOR_READ_RTK_ROM_VERISION    0xfc6d
99*4882a593Smuzhiyun #define HCI_VENDOR_READ_LMP_VERISION        0x1001
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun #define ROM_LMP_NONE                0x0000
102*4882a593Smuzhiyun #define ROM_LMP_8723a               0x1200
103*4882a593Smuzhiyun #define ROM_LMP_8723b               0x8723
104*4882a593Smuzhiyun #define ROM_LMP_8821a               0X8821
105*4882a593Smuzhiyun #define ROM_LMP_8761a               0X8761
106*4882a593Smuzhiyun #define ROM_LMP_8822b               0X8822
107*4882a593Smuzhiyun #define ROM_LMP_8852a               0x8852
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun struct rtk_eversion_evt {
110*4882a593Smuzhiyun 	uint8_t status;
111*4882a593Smuzhiyun 	uint8_t version;
112*4882a593Smuzhiyun } __attribute__ ((packed));
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun struct rtk_epatch_entry {
115*4882a593Smuzhiyun 	uint16_t chipID;
116*4882a593Smuzhiyun 	uint16_t patch_length;
117*4882a593Smuzhiyun 	uint32_t start_offset;
118*4882a593Smuzhiyun } __attribute__ ((packed));
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun struct rtk_epatch {
121*4882a593Smuzhiyun 	uint8_t signature[8];
122*4882a593Smuzhiyun 	uint32_t fw_version;
123*4882a593Smuzhiyun 	uint16_t number_of_total_patch;
124*4882a593Smuzhiyun 	struct rtk_epatch_entry entry[0];
125*4882a593Smuzhiyun } __attribute__ ((packed));
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun struct rtk_extension_entry {
128*4882a593Smuzhiyun 	uint8_t opcode;
129*4882a593Smuzhiyun 	uint8_t length;
130*4882a593Smuzhiyun 	uint8_t *data;
131*4882a593Smuzhiyun } __attribute__ ((packed));
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun //signature: Realtech
134*4882a593Smuzhiyun const uint8_t RTK_EPATCH_SIGNATURE[8] =
135*4882a593Smuzhiyun     { 0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68 };
136*4882a593Smuzhiyun //Extension Section IGNATURE:0x77FD0451
137*4882a593Smuzhiyun const uint8_t Extension_Section_SIGNATURE[4] = { 0x51, 0x04, 0xFD, 0x77 };
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun uint16_t project_id[] = {
140*4882a593Smuzhiyun 	ROM_LMP_8723a,
141*4882a593Smuzhiyun 	ROM_LMP_8723b,
142*4882a593Smuzhiyun 	ROM_LMP_8821a,
143*4882a593Smuzhiyun 	ROM_LMP_8761a,
144*4882a593Smuzhiyun 	ROM_LMP_NONE,
145*4882a593Smuzhiyun 	ROM_LMP_NONE,
146*4882a593Smuzhiyun 	ROM_LMP_NONE,
147*4882a593Smuzhiyun 	ROM_LMP_NONE,
148*4882a593Smuzhiyun 	ROM_LMP_8822b,
149*4882a593Smuzhiyun 	ROM_LMP_8723b, /* RTL8723DU */
150*4882a593Smuzhiyun 	ROM_LMP_8821a, /* RTL8821CU */
151*4882a593Smuzhiyun 	ROM_LMP_NONE,
152*4882a593Smuzhiyun 	ROM_LMP_NONE,
153*4882a593Smuzhiyun 	ROM_LMP_8822b, /* RTL8822CU */
154*4882a593Smuzhiyun 	ROM_LMP_8761a, /* index 14 for 8761BU */
155*4882a593Smuzhiyun 	ROM_LMP_NONE,
156*4882a593Smuzhiyun 	ROM_LMP_NONE,
157*4882a593Smuzhiyun 	ROM_LMP_NONE,
158*4882a593Smuzhiyun 	ROM_LMP_8852a, /* index 18 for 8852AU */
159*4882a593Smuzhiyun 	ROM_LMP_8723b, /* index 19 for 8723FU */
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun enum rtk_endpoit {
163*4882a593Smuzhiyun 	CTRL_EP = 0,
164*4882a593Smuzhiyun 	INTR_EP = 1,
165*4882a593Smuzhiyun 	BULK_EP = 2,
166*4882a593Smuzhiyun 	ISOC_EP = 3
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun /* software id */
170*4882a593Smuzhiyun #define RTLPREVIOUS	0x00
171*4882a593Smuzhiyun #define RTL8822BU	0x70
172*4882a593Smuzhiyun #define RTL8723DU	0x71
173*4882a593Smuzhiyun #define RTL8821CU	0x72
174*4882a593Smuzhiyun #define RTL8822CU	0x73
175*4882a593Smuzhiyun #define RTL8761BU	0x74
176*4882a593Smuzhiyun #define RTL8852AU	0x75
177*4882a593Smuzhiyun #define RTL8723FU	0x76
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun typedef struct {
180*4882a593Smuzhiyun 	uint16_t prod_id;
181*4882a593Smuzhiyun 	uint16_t lmp_sub;
182*4882a593Smuzhiyun 	char *	 mp_patch_name;
183*4882a593Smuzhiyun 	char *	 patch_name;
184*4882a593Smuzhiyun 	char *	 config_name;
185*4882a593Smuzhiyun 	u8       chip_type;
186*4882a593Smuzhiyun } patch_info;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun typedef struct {
189*4882a593Smuzhiyun 	struct list_head list_node;
190*4882a593Smuzhiyun 	struct usb_interface *intf;
191*4882a593Smuzhiyun 	struct usb_device *udev;
192*4882a593Smuzhiyun 	patch_info *patch_entry;
193*4882a593Smuzhiyun } dev_data;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun typedef struct {
196*4882a593Smuzhiyun 	dev_data *dev_entry;
197*4882a593Smuzhiyun 	int pipe_in, pipe_out;
198*4882a593Smuzhiyun 	uint8_t *send_pkt;
199*4882a593Smuzhiyun 	uint8_t *rcv_pkt;
200*4882a593Smuzhiyun 	struct hci_command_hdr *cmd_hdr;
201*4882a593Smuzhiyun 	struct hci_event_hdr *evt_hdr;
202*4882a593Smuzhiyun 	struct hci_ev_cmd_complete *cmd_cmp;
203*4882a593Smuzhiyun 	uint8_t *req_para, *rsp_para;
204*4882a593Smuzhiyun 	uint8_t *fw_data;
205*4882a593Smuzhiyun 	int pkt_len, fw_len;
206*4882a593Smuzhiyun } xchange_data;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun typedef struct {
209*4882a593Smuzhiyun 	uint8_t index;
210*4882a593Smuzhiyun 	uint8_t data[PATCH_SEG_MAX];
211*4882a593Smuzhiyun } __attribute__ ((packed)) download_cp;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun typedef struct {
214*4882a593Smuzhiyun 	uint8_t status;
215*4882a593Smuzhiyun 	uint8_t index;
216*4882a593Smuzhiyun } __attribute__ ((packed)) download_rp;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun #define RTK_VENDOR_CONFIG_MAGIC 0x8723ab55
219*4882a593Smuzhiyun const u8 cfg_magic[4] = { 0x55, 0xab, 0x23, 0x87 };
220*4882a593Smuzhiyun struct rtk_bt_vendor_config_entry {
221*4882a593Smuzhiyun 	uint16_t offset;
222*4882a593Smuzhiyun 	uint8_t entry_len;
223*4882a593Smuzhiyun 	uint8_t entry_data[0];
224*4882a593Smuzhiyun } __attribute__ ((packed));
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun struct rtk_bt_vendor_config {
227*4882a593Smuzhiyun 	uint32_t signature;
228*4882a593Smuzhiyun 	uint16_t data_len;
229*4882a593Smuzhiyun 	struct rtk_bt_vendor_config_entry entry[0];
230*4882a593Smuzhiyun } __attribute__ ((packed));
231*4882a593Smuzhiyun #define BT_CONFIG_HDRLEN		sizeof(struct rtk_bt_vendor_config)
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun static uint8_t gEVersion = 0xFF;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun static dev_data *dev_data_find(struct usb_interface *intf);
236*4882a593Smuzhiyun static patch_info *get_patch_entry(struct usb_device *udev);
237*4882a593Smuzhiyun static int load_firmware(dev_data * dev_entry, uint8_t ** buff);
238*4882a593Smuzhiyun static void init_xdata(xchange_data * xdata, dev_data * dev_entry);
239*4882a593Smuzhiyun static int check_fw_version(xchange_data * xdata);
240*4882a593Smuzhiyun static int download_data(xchange_data * xdata);
241*4882a593Smuzhiyun static int send_hci_cmd(xchange_data * xdata);
242*4882a593Smuzhiyun static int rcv_hci_evt(xchange_data * xdata);
243*4882a593Smuzhiyun static uint8_t rtk_get_eversion(dev_data * dev_entry);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun static patch_info fw_patch_table[] = {
246*4882a593Smuzhiyun /* { pid, lmp_sub, mp_fw_name, fw_name, config_name, chip_type } */
247*4882a593Smuzhiyun 	{0x1724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* RTL8723A */
248*4882a593Smuzhiyun 	{0x8723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* 8723AE */
249*4882a593Smuzhiyun 	{0xA723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* 8723AE for LI */
250*4882a593Smuzhiyun 	{0x0723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* 8723AE */
251*4882a593Smuzhiyun 	{0x3394, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* 8723AE for Azurewave */
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	{0x0724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* 8723AU */
254*4882a593Smuzhiyun 	{0x8725, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* 8723AU */
255*4882a593Smuzhiyun 	{0x872A, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* 8723AU */
256*4882a593Smuzhiyun 	{0x872B, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", RTLPREVIOUS},	/* 8723AU */
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	{0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BU */
259*4882a593Smuzhiyun 	{0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BU */
260*4882a593Smuzhiyun 	{0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE for LC */
261*4882a593Smuzhiyun 	{0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE */
262*4882a593Smuzhiyun 	{0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE */
263*4882a593Smuzhiyun 	{0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE for HP */
264*4882a593Smuzhiyun 	{0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE */
265*4882a593Smuzhiyun 	{0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE */
266*4882a593Smuzhiyun 	{0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE */
267*4882a593Smuzhiyun 	{0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE */
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	{0x3410, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE for Azurewave */
270*4882a593Smuzhiyun 	{0x3416, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE for Azurewave */
271*4882a593Smuzhiyun 	{0x3459, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE for Azurewave */
272*4882a593Smuzhiyun 	{0xE085, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE for Foxconn */
273*4882a593Smuzhiyun 	{0xE08B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE for Foxconn */
274*4882a593Smuzhiyun 	{0xE09E, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", RTLPREVIOUS},	/* RTL8723BE for Foxconn */
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	{0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", RTLPREVIOUS},	/* RTL8761AU only */
277*4882a593Smuzhiyun 	{0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", RTLPREVIOUS},	/* RTL8761AW + 8192EU */
278*4882a593Smuzhiyun 	{0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", RTLPREVIOUS},	/* RTL8761AW + 8192EU */
279*4882a593Smuzhiyun 	{0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", RTLPREVIOUS},	/* RTL8761AU + 8192EE */
280*4882a593Smuzhiyun 	{0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", RTLPREVIOUS},	/* RTL8761AUV only */
281*4882a593Smuzhiyun 	{0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", RTLPREVIOUS},	/* RTL8761AU + 8192EE for LI */
282*4882a593Smuzhiyun 	{0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", RTLPREVIOUS},	/* RTL8761AU + 8812AE */
283*4882a593Smuzhiyun 	{0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", RTLPREVIOUS},	/* RTL8761AU + 8814AE */
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	{0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", RTLPREVIOUS},	/* RTL8821AE */
286*4882a593Smuzhiyun 	{0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", RTLPREVIOUS},	/* RTL8821AE */
287*4882a593Smuzhiyun 	{0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", RTLPREVIOUS},	/* RTL8821AU */
288*4882a593Smuzhiyun 	{0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", RTLPREVIOUS},	/* RTL8821AE */
289*4882a593Smuzhiyun 	{0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", RTLPREVIOUS},	/* RTL8821AE */
290*4882a593Smuzhiyun 	{0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", RTLPREVIOUS},	/* RTL8821AE */
291*4882a593Smuzhiyun 	{0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", RTLPREVIOUS},	/* RTL8821AE */
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	{0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", RTL8822BU}, /* RTL8822BU */
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	{0xd720, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU */
296*4882a593Smuzhiyun 	{0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU */
297*4882a593Smuzhiyun 	{0xd739, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU */
298*4882a593Smuzhiyun 	{0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU */
299*4882a593Smuzhiyun 	{0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU for LiteOn */
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	{0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
302*4882a593Smuzhiyun 	{0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
303*4882a593Smuzhiyun 	{0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
304*4882a593Smuzhiyun 	{0xc823, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
305*4882a593Smuzhiyun 	{0xc824, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
306*4882a593Smuzhiyun 	{0xc825, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
307*4882a593Smuzhiyun 	{0xc827, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
308*4882a593Smuzhiyun 	{0xc025, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
309*4882a593Smuzhiyun 	{0xc024, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
310*4882a593Smuzhiyun 	{0xc030, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
311*4882a593Smuzhiyun 	{0xb00a, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
312*4882a593Smuzhiyun 	{0xb00e, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
313*4882a593Smuzhiyun 	{0xc032, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
314*4882a593Smuzhiyun 	{0x4000, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for LiteOn */
315*4882a593Smuzhiyun 	{0x4001, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for LiteOn */
316*4882a593Smuzhiyun 	{0x3529, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
317*4882a593Smuzhiyun 	{0x3530, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
318*4882a593Smuzhiyun 	{0x3532, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
319*4882a593Smuzhiyun 	{0x3533, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
320*4882a593Smuzhiyun 	{0x3538, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
321*4882a593Smuzhiyun 	{0x3539, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for Azurewave */
322*4882a593Smuzhiyun 	{0x3540, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
323*4882a593Smuzhiyun 	{0x3541, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for GSD */
324*4882a593Smuzhiyun 	{0x3543, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE for GSD */
325*4882a593Smuzhiyun 	{0xc80c, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CUH */
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	{0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
328*4882a593Smuzhiyun 	{0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
329*4882a593Smuzhiyun 	{0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
330*4882a593Smuzhiyun 	{0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
331*4882a593Smuzhiyun 	{0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
332*4882a593Smuzhiyun 	{0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
333*4882a593Smuzhiyun 	{0xb00d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
334*4882a593Smuzhiyun 	{0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
335*4882a593Smuzhiyun 	{0xc126, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
336*4882a593Smuzhiyun 	{0xc127, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
337*4882a593Smuzhiyun 	{0xc128, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
338*4882a593Smuzhiyun 	{0xc129, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
339*4882a593Smuzhiyun 	{0xc131, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
340*4882a593Smuzhiyun 	{0xc136, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
341*4882a593Smuzhiyun 	{0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE for Azurewave */
342*4882a593Smuzhiyun 	{0x3548, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE for Azurewave */
343*4882a593Smuzhiyun 	{0xc125, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
344*4882a593Smuzhiyun 	{0x4005, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE for LiteOn */
345*4882a593Smuzhiyun 	{0x3051, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE for LiteOn */
346*4882a593Smuzhiyun 	{0x18ef, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
347*4882a593Smuzhiyun 	{0x161f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
348*4882a593Smuzhiyun 	{0x3053, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
349*4882a593Smuzhiyun 	{0xc547, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
350*4882a593Smuzhiyun 	{0x3553, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
351*4882a593Smuzhiyun 	{0x3555, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
352*4882a593Smuzhiyun 	{0xc82f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE-VS */
353*4882a593Smuzhiyun 	{0xc02f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE-VS */
354*4882a593Smuzhiyun 	{0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE-VS */
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	{0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BU only */
357*4882a593Smuzhiyun 	{0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU */
358*4882a593Smuzhiyun 	{0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU BT only */
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	{0x885a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AU */
361*4882a593Smuzhiyun 	{0x8852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
362*4882a593Smuzhiyun 	{0xa852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
363*4882a593Smuzhiyun 	{0x2852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
364*4882a593Smuzhiyun 	{0x385a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
365*4882a593Smuzhiyun 	{0x3852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
366*4882a593Smuzhiyun 	{0x1852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
367*4882a593Smuzhiyun 	{0x4852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
368*4882a593Smuzhiyun 	{0x4006, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
369*4882a593Smuzhiyun 	{0x3561, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
370*4882a593Smuzhiyun 	{0x3562, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
371*4882a593Smuzhiyun 	{0x588a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
372*4882a593Smuzhiyun 	{0x589a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
373*4882a593Smuzhiyun 	{0x590a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
374*4882a593Smuzhiyun 	{0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
375*4882a593Smuzhiyun 	{0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
376*4882a593Smuzhiyun 	{0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
377*4882a593Smuzhiyun 	{0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
378*4882a593Smuzhiyun 	{0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
379*4882a593Smuzhiyun 	{0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
380*4882a593Smuzhiyun 	{0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	{0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
383*4882a593Smuzhiyun 	{0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
384*4882a593Smuzhiyun 	{0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun /* NOTE: must append patch entries above the null entry */
387*4882a593Smuzhiyun 	{0, 0, NULL, NULL, NULL, 0}
388*4882a593Smuzhiyun };
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun static LIST_HEAD(dev_data_list);
391*4882a593Smuzhiyun 
util_hexdump(const u8 * buf,size_t len)392*4882a593Smuzhiyun void util_hexdump(const u8 *buf, size_t len)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	static const char hexdigits[] = "0123456789abcdef";
395*4882a593Smuzhiyun 	char str[16 * 3];
396*4882a593Smuzhiyun 	size_t i;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	if (!buf || !len)
399*4882a593Smuzhiyun 		return;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
402*4882a593Smuzhiyun 		str[((i % 16) * 3)] = hexdigits[buf[i] >> 4];
403*4882a593Smuzhiyun 		str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
404*4882a593Smuzhiyun 		str[((i % 16) * 3) + 2] = ' ';
405*4882a593Smuzhiyun 		if ((i + 1) % 16 == 0) {
406*4882a593Smuzhiyun 			str[16 * 3 - 1] = '\0';
407*4882a593Smuzhiyun 			RTKBT_DBG("%s", str);
408*4882a593Smuzhiyun 		}
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	if (i % 16 > 0) {
412*4882a593Smuzhiyun 		str[(i % 16) * 3 - 1] = '\0';
413*4882a593Smuzhiyun 		RTKBT_DBG("%s", str);
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun #if defined RTKBT_SWITCH_PATCH || defined RTKBT_TV_POWERON_WHITELIST
__rtk_send_hci_cmd(struct usb_device * udev,u8 * buf,u16 size)418*4882a593Smuzhiyun int __rtk_send_hci_cmd(struct usb_device *udev, u8 *buf, u16 size)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	int result;
421*4882a593Smuzhiyun 	unsigned int pipe = usb_sndctrlpipe(udev, 0);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	result = usb_control_msg(udev, pipe, 0, USB_TYPE_CLASS, 0, 0,
424*4882a593Smuzhiyun 				 buf, size, 1000); /* 1000 msecs */
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (result < 0)
427*4882a593Smuzhiyun 		RTKBT_ERR("%s: Couldn't send hci cmd, err %d",
428*4882a593Smuzhiyun 			  __func__, result);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	return result;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun 
__rtk_recv_hci_evt(struct usb_device * udev,u8 * buf,u8 len,u16 opcode)433*4882a593Smuzhiyun int __rtk_recv_hci_evt(struct usb_device *udev, u8 *buf, u8 len, u16 opcode)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	int recv_length = 0;
436*4882a593Smuzhiyun 	int result = 0;
437*4882a593Smuzhiyun 	int i;
438*4882a593Smuzhiyun 	unsigned int pipe = usb_rcvintpipe(udev, 1);
439*4882a593Smuzhiyun 	struct hci_event_hdr *hdr;
440*4882a593Smuzhiyun 	struct hci_ev_cmd_complete *cmd_cmpl;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	if (len < sizeof(*hdr) + sizeof(*cmd_cmpl)) {
443*4882a593Smuzhiyun 		RTKBT_ERR("%s: Invalid buf length %u", __func__, len);
444*4882a593Smuzhiyun 		return -1;
445*4882a593Smuzhiyun 	}
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	while (1) {
448*4882a593Smuzhiyun 		for (i = 0; i < 5; i++) {
449*4882a593Smuzhiyun 			result = usb_interrupt_msg(udev, pipe,
450*4882a593Smuzhiyun 					      (void *)buf, PKT_LEN,
451*4882a593Smuzhiyun 					      &recv_length, MSG_TO);
452*4882a593Smuzhiyun 			if (result >= 0)
453*4882a593Smuzhiyun 				break;
454*4882a593Smuzhiyun 		}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 		if (result < 0) {
457*4882a593Smuzhiyun 			RTKBT_ERR("%s; Couldn't receive HCI event, err %d",
458*4882a593Smuzhiyun 				  __func__, result);
459*4882a593Smuzhiyun 			return result;
460*4882a593Smuzhiyun 		}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 		/* Ignore the event which is not command complete event */
463*4882a593Smuzhiyun 		if (recv_length < sizeof(*hdr) + sizeof(*cmd_cmpl))
464*4882a593Smuzhiyun 			continue;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 		hdr = (struct hci_event_hdr *)buf;
467*4882a593Smuzhiyun 		cmd_cmpl = (struct hci_ev_cmd_complete *)(buf + sizeof(*hdr));
468*4882a593Smuzhiyun 		if (hdr->evt == 0x0e) {
469*4882a593Smuzhiyun 			if (opcode == cmd_cmpl->opcode)
470*4882a593Smuzhiyun 				return recv_length;
471*4882a593Smuzhiyun 		}
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun #endif
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
file_inode(const struct file * f)477*4882a593Smuzhiyun static inline struct inode *file_inode(const struct file *f)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun 	return f->f_path.dentry->d_inode;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun #endif
482*4882a593Smuzhiyun 
config_lists_init(void)483*4882a593Smuzhiyun static int config_lists_init(void)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	INIT_LIST_HEAD(&list_configs);
486*4882a593Smuzhiyun 	INIT_LIST_HEAD(&list_extracfgs);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	return 0;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
config_lists_free(void)491*4882a593Smuzhiyun static void config_lists_free(void)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	struct list_head *iter;
494*4882a593Smuzhiyun 	struct list_head *tmp;
495*4882a593Smuzhiyun 	struct list_head *head;
496*4882a593Smuzhiyun 	struct cfg_list_item *n;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	if (!list_empty(&list_extracfgs))
499*4882a593Smuzhiyun 		list_splice_tail(&list_extracfgs, &list_configs);
500*4882a593Smuzhiyun 	head = &list_configs;
501*4882a593Smuzhiyun 	list_for_each_safe(iter, tmp, head) {
502*4882a593Smuzhiyun 		n = list_entry(iter, struct cfg_list_item, list);
503*4882a593Smuzhiyun 		if (n) {
504*4882a593Smuzhiyun 			list_del(&n->list);
505*4882a593Smuzhiyun 			kfree(n);
506*4882a593Smuzhiyun 		}
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	INIT_LIST_HEAD(&list_configs);
510*4882a593Smuzhiyun 	INIT_LIST_HEAD(&list_extracfgs);
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
line_process(char * buf,int len)513*4882a593Smuzhiyun static void line_process(char *buf, int len)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun 	char *argv[32];
516*4882a593Smuzhiyun 	int argc = 0;
517*4882a593Smuzhiyun 	unsigned long offset;
518*4882a593Smuzhiyun 	u8 l;
519*4882a593Smuzhiyun 	u8 i = 0;
520*4882a593Smuzhiyun 	char *ptr = buf;
521*4882a593Smuzhiyun 	char *head = buf;
522*4882a593Smuzhiyun 	struct cfg_list_item *item;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	while ((ptr = strsep(&head, ", \t")) != NULL) {
525*4882a593Smuzhiyun 		if (!ptr[0])
526*4882a593Smuzhiyun 			continue;
527*4882a593Smuzhiyun 		argv[argc++] = ptr;
528*4882a593Smuzhiyun 		if (argc >= 32) {
529*4882a593Smuzhiyun 			RTKBT_WARN("%s: Config item is too long", __func__);
530*4882a593Smuzhiyun 			break;
531*4882a593Smuzhiyun 		}
532*4882a593Smuzhiyun 	}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	if (argc < 4) {
535*4882a593Smuzhiyun 		RTKBT_WARN("%s: Invalid Config item, ignore", __func__);
536*4882a593Smuzhiyun 		return;
537*4882a593Smuzhiyun 	}
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	offset = simple_strtoul(argv[0], NULL, 16);
540*4882a593Smuzhiyun 	offset = offset | (simple_strtoul(argv[1], NULL, 16) << 8);
541*4882a593Smuzhiyun 	l = (u8)simple_strtoul(argv[2], NULL, 16);
542*4882a593Smuzhiyun 	if (l != (u8)(argc - 3)) {
543*4882a593Smuzhiyun 		RTKBT_ERR("invalid len %u", l);
544*4882a593Smuzhiyun 		return;
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	item = kzalloc(sizeof(*item) + l, GFP_KERNEL);
548*4882a593Smuzhiyun 	if (!item) {
549*4882a593Smuzhiyun 		RTKBT_WARN("%s: Cannot alloc mem for item, %04lx, %u", __func__,
550*4882a593Smuzhiyun 			   offset, l);
551*4882a593Smuzhiyun 		return;
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	item->offset = (u16)offset;
555*4882a593Smuzhiyun 	item->len = l;
556*4882a593Smuzhiyun 	for (i = 0; i < l; i++)
557*4882a593Smuzhiyun 		item->data[i] = (u8)simple_strtoul(argv[3 + i], NULL, 16);
558*4882a593Smuzhiyun 	list_add_tail(&item->list, &list_extracfgs);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun 
config_process(u8 * buff,int len)561*4882a593Smuzhiyun static void config_process(u8 *buff, int len)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	char *head = (void *)buff;
564*4882a593Smuzhiyun 	char *ptr = (void *)buff;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	while ((ptr = strsep(&head, "\n\r")) != NULL) {
567*4882a593Smuzhiyun 		if (!ptr[0])
568*4882a593Smuzhiyun 			continue;
569*4882a593Smuzhiyun 		line_process(ptr, strlen(ptr) + 1);
570*4882a593Smuzhiyun 	}
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun 
config_file_proc(const char * path)573*4882a593Smuzhiyun static void config_file_proc(const char *path)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun 	int size;
576*4882a593Smuzhiyun 	int rc;
577*4882a593Smuzhiyun 	struct file *file;
578*4882a593Smuzhiyun 	u8 tbuf[256];
579*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
580*4882a593Smuzhiyun 	loff_t pos = 0;
581*4882a593Smuzhiyun #endif
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	file = filp_open(path, O_RDONLY, 0);
584*4882a593Smuzhiyun 	if (IS_ERR(file))
585*4882a593Smuzhiyun 		return;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	if (!S_ISREG(file_inode(file)->i_mode))
588*4882a593Smuzhiyun 		return;
589*4882a593Smuzhiyun 	size = i_size_read(file_inode(file));
590*4882a593Smuzhiyun 	if (size <= 0)
591*4882a593Smuzhiyun 		return;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	memset(tbuf, 0, sizeof(tbuf));
594*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
595*4882a593Smuzhiyun 	rc = kernel_read(file, tbuf, size, &pos);
596*4882a593Smuzhiyun #else
597*4882a593Smuzhiyun 	rc = kernel_read(file, 0, tbuf, size);
598*4882a593Smuzhiyun #endif
599*4882a593Smuzhiyun 	fput(file);
600*4882a593Smuzhiyun 	if (rc != size) {
601*4882a593Smuzhiyun 		if (rc >= 0)
602*4882a593Smuzhiyun 			rc = -EIO;
603*4882a593Smuzhiyun 		return;
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	tbuf[rc++] = '\n';
607*4882a593Smuzhiyun 	tbuf[rc++] = '\0';
608*4882a593Smuzhiyun 	config_process(tbuf, rc);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
patch_add(struct usb_interface * intf)611*4882a593Smuzhiyun int patch_add(struct usb_interface *intf)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	dev_data *dev_entry;
614*4882a593Smuzhiyun 	struct usb_device *udev;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	RTKBT_DBG("patch_add");
617*4882a593Smuzhiyun 	dev_entry = dev_data_find(intf);
618*4882a593Smuzhiyun 	if (NULL != dev_entry) {
619*4882a593Smuzhiyun 		return -1;
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	udev = interface_to_usbdev(intf);
623*4882a593Smuzhiyun #if BTUSB_RPM
624*4882a593Smuzhiyun 	RTKBT_DBG("auto suspend is enabled");
625*4882a593Smuzhiyun 	usb_enable_autosuspend(udev);
626*4882a593Smuzhiyun 	pm_runtime_set_autosuspend_delay(&(udev->dev), 2000);
627*4882a593Smuzhiyun #else
628*4882a593Smuzhiyun 	RTKBT_DBG("auto suspend is disabled");
629*4882a593Smuzhiyun 	usb_disable_autosuspend(udev);
630*4882a593Smuzhiyun #endif
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	dev_entry = kzalloc(sizeof(dev_data), GFP_KERNEL);
633*4882a593Smuzhiyun 	dev_entry->intf = intf;
634*4882a593Smuzhiyun 	dev_entry->udev = udev;
635*4882a593Smuzhiyun 	dev_entry->patch_entry = get_patch_entry(udev);
636*4882a593Smuzhiyun 	if (NULL == dev_entry->patch_entry) {
637*4882a593Smuzhiyun 		kfree(dev_entry);
638*4882a593Smuzhiyun 		return -1;
639*4882a593Smuzhiyun 	}
640*4882a593Smuzhiyun 	list_add(&dev_entry->list_node, &dev_data_list);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	/* Should reset the gEVersion to 0xff, otherwise the stored gEVersion
643*4882a593Smuzhiyun 	 * would cause rtk_get_eversion() returning previous gEVersion if
644*4882a593Smuzhiyun 	 * change to different ECO chip.
645*4882a593Smuzhiyun 	 * This would cause downloading wrong patch, and the controller can't
646*4882a593Smuzhiyun 	 * work. */
647*4882a593Smuzhiyun 	RTKBT_DBG("%s: Reset gEVersion to 0xff", __func__);
648*4882a593Smuzhiyun 	gEVersion = 0xff;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	return 0;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun 
patch_remove(struct usb_interface * intf)653*4882a593Smuzhiyun void patch_remove(struct usb_interface *intf)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun 	dev_data *dev_entry;
656*4882a593Smuzhiyun 	struct usb_device *udev;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	udev = interface_to_usbdev(intf);
659*4882a593Smuzhiyun #if BTUSB_RPM
660*4882a593Smuzhiyun 	usb_disable_autosuspend(udev);
661*4882a593Smuzhiyun #endif
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	dev_entry = dev_data_find(intf);
664*4882a593Smuzhiyun 	if (NULL == dev_entry) {
665*4882a593Smuzhiyun 		return;
666*4882a593Smuzhiyun 	}
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	RTKBT_DBG("patch_remove");
669*4882a593Smuzhiyun 	list_del(&dev_entry->list_node);
670*4882a593Smuzhiyun 	kfree(dev_entry);
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun 
send_reset_command(xchange_data * xdata)673*4882a593Smuzhiyun static int send_reset_command(xchange_data *xdata)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun 	int ret_val;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	RTKBT_DBG("HCI reset.");
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	xdata->cmd_hdr->opcode = cpu_to_le16(HCI_OP_RESET);
680*4882a593Smuzhiyun 	xdata->cmd_hdr->plen = 0;
681*4882a593Smuzhiyun 	xdata->pkt_len = CMD_HDR_LEN;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	ret_val = send_hci_cmd(xdata);
684*4882a593Smuzhiyun 	if (ret_val < 0) {
685*4882a593Smuzhiyun 		RTKBT_ERR("failed to send hci cmd.");
686*4882a593Smuzhiyun 		return ret_val;
687*4882a593Smuzhiyun 	}
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	ret_val = rcv_hci_evt(xdata);
690*4882a593Smuzhiyun 	if (ret_val < 0) {
691*4882a593Smuzhiyun 		RTKBT_ERR("failed to recv hci event.");
692*4882a593Smuzhiyun 		return ret_val;
693*4882a593Smuzhiyun 	}
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	return 0;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun 
get_max_patch_size(u8 chip_type)698*4882a593Smuzhiyun static inline int get_max_patch_size(u8 chip_type)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun 	int max_patch_size = 0;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	switch (chip_type) {
703*4882a593Smuzhiyun 	case RTLPREVIOUS:
704*4882a593Smuzhiyun 		max_patch_size = 24 * 1024;
705*4882a593Smuzhiyun 		break;
706*4882a593Smuzhiyun 	case RTL8822BU:
707*4882a593Smuzhiyun 		max_patch_size = 25 * 1024;
708*4882a593Smuzhiyun 		break;
709*4882a593Smuzhiyun 	case RTL8723DU:
710*4882a593Smuzhiyun 	case RTL8822CU:
711*4882a593Smuzhiyun 	case RTL8761BU:
712*4882a593Smuzhiyun 	case RTL8821CU:
713*4882a593Smuzhiyun 		max_patch_size = 40 * 1024;
714*4882a593Smuzhiyun 		break;
715*4882a593Smuzhiyun 	case RTL8852AU:
716*4882a593Smuzhiyun 	case RTL8723FU:
717*4882a593Smuzhiyun 		max_patch_size = 40 * 1024 + 529;
718*4882a593Smuzhiyun 		break;
719*4882a593Smuzhiyun 	default:
720*4882a593Smuzhiyun 		max_patch_size = 40 * 1024;
721*4882a593Smuzhiyun 		break;
722*4882a593Smuzhiyun 	}
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	return max_patch_size;
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun 
download_patch(struct usb_interface * intf)727*4882a593Smuzhiyun int download_patch(struct usb_interface *intf)
728*4882a593Smuzhiyun {
729*4882a593Smuzhiyun 	dev_data *dev_entry;
730*4882a593Smuzhiyun 	patch_info *pinfo;
731*4882a593Smuzhiyun 	xchange_data *xdata = NULL;
732*4882a593Smuzhiyun 	uint8_t *fw_buf;
733*4882a593Smuzhiyun 	int ret_val;
734*4882a593Smuzhiyun 	int max_patch_size = 0;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	RTKBT_DBG("download_patch start");
737*4882a593Smuzhiyun 	dev_entry = dev_data_find(intf);
738*4882a593Smuzhiyun 	if (NULL == dev_entry) {
739*4882a593Smuzhiyun 		ret_val = -1;
740*4882a593Smuzhiyun 		RTKBT_ERR("NULL == dev_entry");
741*4882a593Smuzhiyun 		goto patch_end;
742*4882a593Smuzhiyun 	}
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
745*4882a593Smuzhiyun 	if (NULL == xdata) {
746*4882a593Smuzhiyun 		ret_val = -1;
747*4882a593Smuzhiyun 		RTKBT_DBG("NULL == xdata");
748*4882a593Smuzhiyun 		goto patch_end;
749*4882a593Smuzhiyun 	}
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	init_xdata(xdata, dev_entry);
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	ret_val = check_fw_version(xdata);
754*4882a593Smuzhiyun 	if (ret_val < 0) {
755*4882a593Smuzhiyun 		RTKBT_ERR("Failed to get Local Version Information");
756*4882a593Smuzhiyun 		goto patch_end;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	} else if (ret_val > 0) {
759*4882a593Smuzhiyun 		RTKBT_DBG("Firmware already exists");
760*4882a593Smuzhiyun 		/* Patch alread exists, just return */
761*4882a593Smuzhiyun 		if (gEVersion == 0xff) {
762*4882a593Smuzhiyun 			RTKBT_DBG("global_version is not set, get it!");
763*4882a593Smuzhiyun 			gEVersion = rtk_get_eversion(dev_entry);
764*4882a593Smuzhiyun 		}
765*4882a593Smuzhiyun 		goto patch_end;
766*4882a593Smuzhiyun 	}
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
769*4882a593Smuzhiyun 	if (xdata->fw_len <= 0) {
770*4882a593Smuzhiyun 		RTKBT_ERR("load firmware failed!");
771*4882a593Smuzhiyun 		ret_val = -1;
772*4882a593Smuzhiyun 		goto patch_end;
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	fw_buf = xdata->fw_data;
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	pinfo = dev_entry->patch_entry;
778*4882a593Smuzhiyun 	if (!pinfo) {
779*4882a593Smuzhiyun 		RTKBT_ERR("%s: No patch entry", __func__);
780*4882a593Smuzhiyun 		ret_val = -1;
781*4882a593Smuzhiyun 		goto patch_fail;
782*4882a593Smuzhiyun 	}
783*4882a593Smuzhiyun 	max_patch_size = get_max_patch_size(pinfo->chip_type);
784*4882a593Smuzhiyun 	if (xdata->fw_len > max_patch_size) {
785*4882a593Smuzhiyun 		RTKBT_ERR("FW/CONFIG total length larger than allowed %d",
786*4882a593Smuzhiyun 			  max_patch_size);
787*4882a593Smuzhiyun 		ret_val = -1;
788*4882a593Smuzhiyun 		goto patch_fail;
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	ret_val = download_data(xdata);
792*4882a593Smuzhiyun 	if (ret_val < 0) {
793*4882a593Smuzhiyun 		RTKBT_ERR("download_data failed, err %d", ret_val);
794*4882a593Smuzhiyun 		goto patch_fail;
795*4882a593Smuzhiyun 	}
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	ret_val = check_fw_version(xdata);
798*4882a593Smuzhiyun 	if (ret_val <= 0) {
799*4882a593Smuzhiyun 		RTKBT_ERR("%s: Read Local Version Info failure after download",
800*4882a593Smuzhiyun 			  __func__);
801*4882a593Smuzhiyun 		ret_val = -1;
802*4882a593Smuzhiyun 		goto patch_fail;
803*4882a593Smuzhiyun 	}
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	ret_val = 0;
806*4882a593Smuzhiyun patch_fail:
807*4882a593Smuzhiyun 	kfree(fw_buf);
808*4882a593Smuzhiyun patch_end:
809*4882a593Smuzhiyun 	if (xdata != NULL) {
810*4882a593Smuzhiyun 		if (xdata->send_pkt)
811*4882a593Smuzhiyun 			kfree(xdata->send_pkt);
812*4882a593Smuzhiyun 		if (xdata->rcv_pkt)
813*4882a593Smuzhiyun 			kfree(xdata->rcv_pkt);
814*4882a593Smuzhiyun 		kfree(xdata);
815*4882a593Smuzhiyun 	}
816*4882a593Smuzhiyun 	RTKBT_DBG("Rtk patch end %d", ret_val);
817*4882a593Smuzhiyun 	return ret_val;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun #ifdef RTKBT_SWITCH_PATCH
821*4882a593Smuzhiyun /* @return:
822*4882a593Smuzhiyun  * -1: error
823*4882a593Smuzhiyun  * 0: download patch successfully
824*4882a593Smuzhiyun  * >0: patch already exists  */
download_lps_patch(struct usb_interface * intf)825*4882a593Smuzhiyun int download_lps_patch(struct usb_interface *intf)
826*4882a593Smuzhiyun {
827*4882a593Smuzhiyun 	dev_data *dev_entry;
828*4882a593Smuzhiyun 	xchange_data *xdata = NULL;
829*4882a593Smuzhiyun 	uint8_t *fw_buf;
830*4882a593Smuzhiyun 	int result;
831*4882a593Smuzhiyun 	char name1[64];
832*4882a593Smuzhiyun 	char *origin_name1;
833*4882a593Smuzhiyun 	char name2[64];
834*4882a593Smuzhiyun 	char *origin_name2;
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	RTKBT_DBG("Download LPS Patch start");
837*4882a593Smuzhiyun 	dev_entry = dev_data_find(intf);
838*4882a593Smuzhiyun 	if (!dev_entry) {
839*4882a593Smuzhiyun 		RTKBT_ERR("No Patch found");
840*4882a593Smuzhiyun 		return -1;
841*4882a593Smuzhiyun 	}
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
844*4882a593Smuzhiyun 	if (!xdata) {
845*4882a593Smuzhiyun 		RTKBT_ERR("Couldn't alloc xdata");
846*4882a593Smuzhiyun 		return -1;
847*4882a593Smuzhiyun 	}
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	init_xdata(xdata, dev_entry);
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	result = check_fw_version(xdata);
852*4882a593Smuzhiyun 	if (result < 0) {
853*4882a593Smuzhiyun 		RTKBT_ERR("Failed to get Local Version Information");
854*4882a593Smuzhiyun 		goto patch_end;
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	} else if (result > 0) {
857*4882a593Smuzhiyun 		RTKBT_DBG("Firmware already exists");
858*4882a593Smuzhiyun 		/* Patch alread exists, just return */
859*4882a593Smuzhiyun 		if (gEVersion == 0xff) {
860*4882a593Smuzhiyun 			RTKBT_DBG("global_version is not set, get it!");
861*4882a593Smuzhiyun 			gEVersion = rtk_get_eversion(dev_entry);
862*4882a593Smuzhiyun 		}
863*4882a593Smuzhiyun 		goto patch_end;
864*4882a593Smuzhiyun 	}
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	origin_name1 = dev_entry->patch_entry->patch_name;
867*4882a593Smuzhiyun 	origin_name2 = dev_entry->patch_entry->config_name;
868*4882a593Smuzhiyun 	snprintf(name1, sizeof(name1), "lps_%s", origin_name1);
869*4882a593Smuzhiyun 	snprintf(name2, sizeof(name2), "lps_%s", origin_name2);
870*4882a593Smuzhiyun 	dev_entry->patch_entry->patch_name = name1;
871*4882a593Smuzhiyun 	dev_entry->patch_entry->config_name = name2;
872*4882a593Smuzhiyun 	RTKBT_INFO("Loading %s and %s", name1, name2);
873*4882a593Smuzhiyun 	xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
874*4882a593Smuzhiyun 	dev_entry->patch_entry->patch_name = origin_name1;
875*4882a593Smuzhiyun 	dev_entry->patch_entry->config_name = origin_name2;
876*4882a593Smuzhiyun 	if (xdata->fw_len <= 0) {
877*4882a593Smuzhiyun 		result = -1;
878*4882a593Smuzhiyun 		RTKBT_ERR("load firmware failed!");
879*4882a593Smuzhiyun 		goto patch_end;
880*4882a593Smuzhiyun 	}
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	fw_buf = xdata->fw_data;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	pinfo = dev_entry->patch_entry;
885*4882a593Smuzhiyun 	if (!pinfo) {
886*4882a593Smuzhiyun 		RTKBT_ERR("%s: No patch entry", __func__);
887*4882a593Smuzhiyun 		result = -1;
888*4882a593Smuzhiyun 		goto patch_fail;
889*4882a593Smuzhiyun 	}
890*4882a593Smuzhiyun 	max_patch_size = get_max_patch_size(pinfo->chip_type);
891*4882a593Smuzhiyun 	if (xdata->fw_len > max_patch_size) {
892*4882a593Smuzhiyun 		result = -1;
893*4882a593Smuzhiyun 		RTKBT_ERR("FW/CONFIG total length larger than allowed %d",
894*4882a593Smuzhiyun 			  max_patch_size);
895*4882a593Smuzhiyun 		goto patch_fail;
896*4882a593Smuzhiyun 	}
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	result = download_data(xdata);
899*4882a593Smuzhiyun 	if (result < 0) {
900*4882a593Smuzhiyun 		RTKBT_ERR("download_data failed, err %d", result);
901*4882a593Smuzhiyun 		goto patch_fail;
902*4882a593Smuzhiyun 	}
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	result = check_fw_version(xdata);
905*4882a593Smuzhiyun 	if (result <= 0) {
906*4882a593Smuzhiyun 		RTKBT_ERR("%s: Read Local Version Info failure after download",
907*4882a593Smuzhiyun 			  __func__);
908*4882a593Smuzhiyun 		result = -1;
909*4882a593Smuzhiyun 		goto patch_fail;
910*4882a593Smuzhiyun 	}
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	result = 0;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun patch_fail:
915*4882a593Smuzhiyun 	kfree(fw_buf);
916*4882a593Smuzhiyun patch_end:
917*4882a593Smuzhiyun 	if (xdata->send_pkt)
918*4882a593Smuzhiyun 		kfree(xdata->send_pkt);
919*4882a593Smuzhiyun 	if (xdata->rcv_pkt)
920*4882a593Smuzhiyun 		kfree(xdata->rcv_pkt);
921*4882a593Smuzhiyun 	kfree(xdata);
922*4882a593Smuzhiyun 	RTKBT_DBG("Download LPS Patch end %d", result);
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	return result;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun #endif
927*4882a593Smuzhiyun 
set_scan(struct usb_interface * intf)928*4882a593Smuzhiyun int set_scan(struct usb_interface *intf)
929*4882a593Smuzhiyun {
930*4882a593Smuzhiyun 	dev_data *dev_entry;
931*4882a593Smuzhiyun 	xchange_data *xdata = NULL;
932*4882a593Smuzhiyun 	int result;
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	RTKBT_DBG("%s", __func__);
935*4882a593Smuzhiyun 	dev_entry = dev_data_find(intf);
936*4882a593Smuzhiyun 	if (!dev_entry)
937*4882a593Smuzhiyun 		return -1;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
940*4882a593Smuzhiyun 	if (!xdata) {
941*4882a593Smuzhiyun 		RTKBT_ERR("Could not alloc xdata");
942*4882a593Smuzhiyun 		return -1;
943*4882a593Smuzhiyun 	}
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	init_xdata(xdata, dev_entry);
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	xdata->cmd_hdr->opcode = cpu_to_le16(STARTSCAN_OPCODE);
948*4882a593Smuzhiyun 	xdata->cmd_hdr->plen = 1;
949*4882a593Smuzhiyun 	xdata->pkt_len = CMD_HDR_LEN + 1;
950*4882a593Smuzhiyun 	xdata->send_pkt[CMD_HDR_LEN] = 1;
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	result = send_hci_cmd(xdata);
953*4882a593Smuzhiyun 	if (result < 0)
954*4882a593Smuzhiyun 		goto end;
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun 	result = rcv_hci_evt(xdata);
957*4882a593Smuzhiyun end:
958*4882a593Smuzhiyun 	if (xdata) {
959*4882a593Smuzhiyun 		if (xdata->send_pkt)
960*4882a593Smuzhiyun 			kfree(xdata->send_pkt);
961*4882a593Smuzhiyun 		if (xdata->rcv_pkt)
962*4882a593Smuzhiyun 			kfree(xdata->rcv_pkt);
963*4882a593Smuzhiyun 		kfree(xdata);
964*4882a593Smuzhiyun 	}
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	RTKBT_DBG("%s done", __func__);
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 	return result;
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun 
dev_data_find(struct usb_interface * intf)971*4882a593Smuzhiyun dev_data *dev_data_find(struct usb_interface * intf)
972*4882a593Smuzhiyun {
973*4882a593Smuzhiyun 	dev_data *dev_entry;
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 	list_for_each_entry(dev_entry, &dev_data_list, list_node) {
976*4882a593Smuzhiyun 		if (dev_entry->intf == intf) {
977*4882a593Smuzhiyun 			patch_info *patch = dev_entry->patch_entry;
978*4882a593Smuzhiyun 			if (!patch)
979*4882a593Smuzhiyun 				return NULL;
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 			RTKBT_INFO("chip type value: 0x%02x", patch->chip_type);
982*4882a593Smuzhiyun 			return dev_entry;
983*4882a593Smuzhiyun 		}
984*4882a593Smuzhiyun 	}
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	return NULL;
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun 
get_patch_entry(struct usb_device * udev)989*4882a593Smuzhiyun patch_info *get_patch_entry(struct usb_device * udev)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun 	patch_info *patch_entry;
992*4882a593Smuzhiyun 	uint16_t pid;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	patch_entry = fw_patch_table;
995*4882a593Smuzhiyun 	pid = le16_to_cpu(udev->descriptor.idProduct);
996*4882a593Smuzhiyun 	RTKBT_DBG("pid = 0x%x", pid);
997*4882a593Smuzhiyun 	while (pid != patch_entry->prod_id) {
998*4882a593Smuzhiyun 		if (0 == patch_entry->prod_id) {
999*4882a593Smuzhiyun 			RTKBT_DBG
1000*4882a593Smuzhiyun 			    ("get_patch_entry =NULL, can not find device pid in patch_table");
1001*4882a593Smuzhiyun 			return NULL;	//break;
1002*4882a593Smuzhiyun 		}
1003*4882a593Smuzhiyun 		patch_entry++;
1004*4882a593Smuzhiyun 	}
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	return patch_entry;
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun 
is_mac(u8 chip_type,u16 offset)1009*4882a593Smuzhiyun static int is_mac(u8 chip_type, u16 offset)
1010*4882a593Smuzhiyun {
1011*4882a593Smuzhiyun 	int result = 0;
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 	switch (chip_type) {
1014*4882a593Smuzhiyun 	case RTL8822BU:
1015*4882a593Smuzhiyun 	case RTL8723DU:
1016*4882a593Smuzhiyun 	case RTL8821CU:
1017*4882a593Smuzhiyun 		if (offset == 0x0044)
1018*4882a593Smuzhiyun 			return 1;
1019*4882a593Smuzhiyun 		break;
1020*4882a593Smuzhiyun 	case RTL8822CU:
1021*4882a593Smuzhiyun 	case RTL8761BU:
1022*4882a593Smuzhiyun 	case RTL8852AU:
1023*4882a593Smuzhiyun 	case RTL8723FU:
1024*4882a593Smuzhiyun 		if (offset == 0x0030)
1025*4882a593Smuzhiyun 			return 1;
1026*4882a593Smuzhiyun 		break;
1027*4882a593Smuzhiyun 	case RTLPREVIOUS:
1028*4882a593Smuzhiyun 		if (offset == 0x003c)
1029*4882a593Smuzhiyun 			return 1;
1030*4882a593Smuzhiyun 		break;
1031*4882a593Smuzhiyun 	}
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	return result;
1034*4882a593Smuzhiyun }
1035*4882a593Smuzhiyun 
get_mac_offset(u8 chip_type)1036*4882a593Smuzhiyun static uint16_t get_mac_offset(u8 chip_type)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun 	switch (chip_type) {
1039*4882a593Smuzhiyun 	case RTL8822BU:
1040*4882a593Smuzhiyun 	case RTL8723DU:
1041*4882a593Smuzhiyun 	case RTL8821CU:
1042*4882a593Smuzhiyun 		return 0x0044;
1043*4882a593Smuzhiyun 	case RTL8822CU:
1044*4882a593Smuzhiyun 	case RTL8761BU:
1045*4882a593Smuzhiyun 	case RTL8852AU:
1046*4882a593Smuzhiyun 	case RTL8723FU:
1047*4882a593Smuzhiyun 		return 0x0030;
1048*4882a593Smuzhiyun 	case RTLPREVIOUS:
1049*4882a593Smuzhiyun 		return 0x003c;
1050*4882a593Smuzhiyun 	default:
1051*4882a593Smuzhiyun 		return 0x003c;
1052*4882a593Smuzhiyun 	}
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun 
merge_configs(struct list_head * head,struct list_head * head2)1055*4882a593Smuzhiyun static void merge_configs(struct list_head *head, struct list_head *head2)
1056*4882a593Smuzhiyun {
1057*4882a593Smuzhiyun 	struct list_head *epos, *enext;
1058*4882a593Smuzhiyun 	struct list_head *pos, *next;
1059*4882a593Smuzhiyun 	struct cfg_list_item *n;
1060*4882a593Smuzhiyun 	struct cfg_list_item *extra;
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	if (!head || !head2)
1063*4882a593Smuzhiyun 		return;
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun 	if (list_empty(head2))
1066*4882a593Smuzhiyun 		return;
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	if (list_empty(head)) {
1069*4882a593Smuzhiyun 		list_splice_tail(head2, head);
1070*4882a593Smuzhiyun 		INIT_LIST_HEAD(head2);
1071*4882a593Smuzhiyun 		return;
1072*4882a593Smuzhiyun 	}
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	/* Add or update & replace */
1075*4882a593Smuzhiyun 	list_for_each_safe(epos, enext, head2) {
1076*4882a593Smuzhiyun 		extra = list_entry(epos, struct cfg_list_item, list);
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 		list_for_each_safe(pos, next, head) {
1079*4882a593Smuzhiyun 			n = list_entry(pos, struct cfg_list_item, list);
1080*4882a593Smuzhiyun 			if (extra->offset == n->offset) {
1081*4882a593Smuzhiyun 				if (extra->len < n->len) {
1082*4882a593Smuzhiyun 					/* Update the cfg data */
1083*4882a593Smuzhiyun 					RTKBT_INFO("Update cfg: ofs %04x len %u",
1084*4882a593Smuzhiyun 						   n->offset, n->len);
1085*4882a593Smuzhiyun 					memcpy(n->data, extra->data,
1086*4882a593Smuzhiyun 					       extra->len);
1087*4882a593Smuzhiyun 					list_del(epos);
1088*4882a593Smuzhiyun 					kfree(extra);
1089*4882a593Smuzhiyun 				} else {
1090*4882a593Smuzhiyun 					/* Replace the item */
1091*4882a593Smuzhiyun 					list_del(epos);
1092*4882a593Smuzhiyun 					list_replace_init(pos, epos);
1093*4882a593Smuzhiyun 					/* free the old item */
1094*4882a593Smuzhiyun 					kfree(n);
1095*4882a593Smuzhiyun 				}
1096*4882a593Smuzhiyun 			}
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 		}
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	}
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	if (list_empty(head2))
1103*4882a593Smuzhiyun 		return;
1104*4882a593Smuzhiyun 	list_for_each_safe(epos, enext, head2) {
1105*4882a593Smuzhiyun 		extra = list_entry(epos, struct cfg_list_item, list);
1106*4882a593Smuzhiyun 		RTKBT_INFO("Add new cfg: ofs %04x, len %u", extra->offset,
1107*4882a593Smuzhiyun 			   extra->len);
1108*4882a593Smuzhiyun 		/* Add the item to list */
1109*4882a593Smuzhiyun 		list_del(epos);
1110*4882a593Smuzhiyun 		list_add_tail(epos, head);
1111*4882a593Smuzhiyun 	}
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun 
rtk_parse_config_file(u8 * config_buf,int filelen)1114*4882a593Smuzhiyun int rtk_parse_config_file(u8 *config_buf, int filelen)
1115*4882a593Smuzhiyun {
1116*4882a593Smuzhiyun 	struct rtk_bt_vendor_config *config = (void *)config_buf;
1117*4882a593Smuzhiyun 	u16 config_len = 0, temp = 0;
1118*4882a593Smuzhiyun 	struct rtk_bt_vendor_config_entry *entry = NULL;
1119*4882a593Smuzhiyun 	u32 i = 0;
1120*4882a593Smuzhiyun 	struct cfg_list_item *item;
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 	if (!config_buf)
1123*4882a593Smuzhiyun 		return -EINVAL;
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 	config_len = le16_to_cpu(config->data_len);
1126*4882a593Smuzhiyun 	entry = config->entry;
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 	if (le32_to_cpu(config->signature) != RTK_VENDOR_CONFIG_MAGIC) {
1129*4882a593Smuzhiyun 		RTKBT_ERR("sig magic num %08x,  not rtk vendor magic %08x",
1130*4882a593Smuzhiyun 			  config->signature, RTK_VENDOR_CONFIG_MAGIC);
1131*4882a593Smuzhiyun 		return -1;
1132*4882a593Smuzhiyun 	}
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 	if (config_len != filelen - BT_CONFIG_HDRLEN) {
1135*4882a593Smuzhiyun 		RTKBT_ERR("config length %u is not right %u", config_len,
1136*4882a593Smuzhiyun 			  (u16)(filelen - BT_CONFIG_HDRLEN));
1137*4882a593Smuzhiyun 		return -1;
1138*4882a593Smuzhiyun 	}
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	for (i = 0; i < config_len;) {
1141*4882a593Smuzhiyun 		/* Add config item to list */
1142*4882a593Smuzhiyun 		item = kzalloc(sizeof(*item) + entry->entry_len, GFP_KERNEL);
1143*4882a593Smuzhiyun 		if (item) {
1144*4882a593Smuzhiyun 			item->offset = le16_to_cpu(entry->offset);
1145*4882a593Smuzhiyun 			item->len = entry->entry_len;
1146*4882a593Smuzhiyun 			memcpy(item->data, entry->entry_data, item->len);
1147*4882a593Smuzhiyun 			list_add_tail(&item->list, &list_configs);
1148*4882a593Smuzhiyun 		} else {
1149*4882a593Smuzhiyun 			RTKBT_ERR("Cannot alloc mem for entry %04x, %u",
1150*4882a593Smuzhiyun 				  entry->offset, entry->entry_len);
1151*4882a593Smuzhiyun 			break;
1152*4882a593Smuzhiyun 		}
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 		temp = entry->entry_len +
1155*4882a593Smuzhiyun 			sizeof(struct rtk_bt_vendor_config_entry);
1156*4882a593Smuzhiyun 		i += temp;
1157*4882a593Smuzhiyun 		entry =
1158*4882a593Smuzhiyun 		    (struct rtk_bt_vendor_config_entry *)((uint8_t *) entry +
1159*4882a593Smuzhiyun 							  temp);
1160*4882a593Smuzhiyun 	}
1161*4882a593Smuzhiyun 
1162*4882a593Smuzhiyun 	return 0;;
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun 
rtk_get_fw_project_id(uint8_t * p_buf)1165*4882a593Smuzhiyun uint8_t rtk_get_fw_project_id(uint8_t * p_buf)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun 	uint8_t opcode;
1168*4882a593Smuzhiyun 	uint8_t len;
1169*4882a593Smuzhiyun 	uint8_t data = 0;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	do {
1172*4882a593Smuzhiyun 		opcode = *p_buf;
1173*4882a593Smuzhiyun 		len = *(p_buf - 1);
1174*4882a593Smuzhiyun 		if (opcode == 0x00) {
1175*4882a593Smuzhiyun 			if (len == 1) {
1176*4882a593Smuzhiyun 				data = *(p_buf - 2);
1177*4882a593Smuzhiyun 				RTKBT_DBG
1178*4882a593Smuzhiyun 				    ("rtk_get_fw_project_id: opcode %d, len %d, data %d",
1179*4882a593Smuzhiyun 				     opcode, len, data);
1180*4882a593Smuzhiyun 				break;
1181*4882a593Smuzhiyun 			} else {
1182*4882a593Smuzhiyun 				RTKBT_ERR
1183*4882a593Smuzhiyun 				    ("rtk_get_fw_project_id: invalid len %d",
1184*4882a593Smuzhiyun 				     len);
1185*4882a593Smuzhiyun 			}
1186*4882a593Smuzhiyun 		}
1187*4882a593Smuzhiyun 		p_buf -= len + 2;
1188*4882a593Smuzhiyun 	} while (*p_buf != 0xFF);
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 	return data;
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun 
rtk_get_patch_entry(uint8_t * epatch_buf,struct rtk_epatch_entry * entry)1193*4882a593Smuzhiyun static void rtk_get_patch_entry(uint8_t * epatch_buf,
1194*4882a593Smuzhiyun 				struct rtk_epatch_entry *entry)
1195*4882a593Smuzhiyun {
1196*4882a593Smuzhiyun 	uint32_t svn_ver;
1197*4882a593Smuzhiyun 	uint32_t coex_ver;
1198*4882a593Smuzhiyun 	uint32_t tmp;
1199*4882a593Smuzhiyun 	uint16_t i;
1200*4882a593Smuzhiyun 	struct rtk_epatch *epatch_info = (struct rtk_epatch *)epatch_buf;
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	epatch_info->number_of_total_patch =
1203*4882a593Smuzhiyun 	    le16_to_cpu(epatch_info->number_of_total_patch);
1204*4882a593Smuzhiyun 	RTKBT_DBG("fw_version = 0x%x", le32_to_cpu(epatch_info->fw_version));
1205*4882a593Smuzhiyun 	RTKBT_DBG("number_of_total_patch = %d",
1206*4882a593Smuzhiyun 		  epatch_info->number_of_total_patch);
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	/* get right epatch entry */
1209*4882a593Smuzhiyun 	for (i = 0; i < epatch_info->number_of_total_patch; i++) {
1210*4882a593Smuzhiyun 		if (get_unaligned_le16(epatch_buf + 14 + 2 * i) ==
1211*4882a593Smuzhiyun 		    gEVersion + 1) {
1212*4882a593Smuzhiyun 			entry->chipID = gEVersion + 1;
1213*4882a593Smuzhiyun 			entry->patch_length = get_unaligned_le16(epatch_buf +
1214*4882a593Smuzhiyun 					14 +
1215*4882a593Smuzhiyun 					2 * epatch_info->number_of_total_patch +
1216*4882a593Smuzhiyun 					2 * i);
1217*4882a593Smuzhiyun 			entry->start_offset = get_unaligned_le32(epatch_buf +
1218*4882a593Smuzhiyun 					14 +
1219*4882a593Smuzhiyun 					4 * epatch_info-> number_of_total_patch +
1220*4882a593Smuzhiyun 					4 * i);
1221*4882a593Smuzhiyun 			break;
1222*4882a593Smuzhiyun 		}
1223*4882a593Smuzhiyun 	}
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 	if (i >= epatch_info->number_of_total_patch) {
1226*4882a593Smuzhiyun 		entry->patch_length = 0;
1227*4882a593Smuzhiyun 		entry->start_offset = 0;
1228*4882a593Smuzhiyun 		RTKBT_ERR("No corresponding patch found\n");
1229*4882a593Smuzhiyun 		return;
1230*4882a593Smuzhiyun 	}
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	svn_ver = get_unaligned_le32(epatch_buf +
1233*4882a593Smuzhiyun 				entry->start_offset +
1234*4882a593Smuzhiyun 				entry->patch_length - 8);
1235*4882a593Smuzhiyun 	coex_ver = get_unaligned_le32(epatch_buf +
1236*4882a593Smuzhiyun 				entry->start_offset +
1237*4882a593Smuzhiyun 				entry->patch_length - 12);
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun 	RTKBT_DBG("chipID %d", entry->chipID);
1240*4882a593Smuzhiyun 	RTKBT_DBG("patch_length 0x%04x", entry->patch_length);
1241*4882a593Smuzhiyun 	RTKBT_DBG("start_offset 0x%08x", entry->start_offset);
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	RTKBT_DBG("Svn version: %8d", svn_ver);
1244*4882a593Smuzhiyun 	tmp = ((coex_ver >> 16) & 0x7ff) + (coex_ver >> 27) * 10000;
1245*4882a593Smuzhiyun 	RTKBT_DBG("Coexistence: BTCOEX_20%06d-%04x",
1246*4882a593Smuzhiyun 		  tmp, (coex_ver & 0xffff));
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun 
bachk(const char * str)1249*4882a593Smuzhiyun int bachk(const char *str)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun 	if (!str)
1252*4882a593Smuzhiyun 		return -1;
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 	if (strlen(str) != 17)
1255*4882a593Smuzhiyun 		return -1;
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	while (*str) {
1258*4882a593Smuzhiyun 		if (!isxdigit(*str++))
1259*4882a593Smuzhiyun 			return -1;
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun 		if (!isxdigit(*str++))
1262*4882a593Smuzhiyun 			return -1;
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 		if (*str == 0)
1265*4882a593Smuzhiyun 			break;
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 		if (*str++ != ':')
1268*4882a593Smuzhiyun 			return -1;
1269*4882a593Smuzhiyun 	}
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun 	return 0;
1272*4882a593Smuzhiyun }
1273*4882a593Smuzhiyun 
request_bdaddr(u8 * buf)1274*4882a593Smuzhiyun static int request_bdaddr(u8 *buf)
1275*4882a593Smuzhiyun {
1276*4882a593Smuzhiyun 	int size;
1277*4882a593Smuzhiyun 	int rc;
1278*4882a593Smuzhiyun 	struct file *file;
1279*4882a593Smuzhiyun 	u8 tbuf[BDADDR_STRING_LEN + 1];
1280*4882a593Smuzhiyun 	char *str;
1281*4882a593Smuzhiyun 	int i;
1282*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
1283*4882a593Smuzhiyun 	loff_t pos = 0;
1284*4882a593Smuzhiyun #endif
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	if (!buf)
1287*4882a593Smuzhiyun 		return -EINVAL;
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun 	file = filp_open(BDADDR_FILE, O_RDONLY, 0);
1290*4882a593Smuzhiyun 	if (IS_ERR(file))
1291*4882a593Smuzhiyun 		return -ENOENT;
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun 	if (!S_ISREG(file_inode(file)->i_mode))
1294*4882a593Smuzhiyun 		return -EINVAL;
1295*4882a593Smuzhiyun 	size = i_size_read(file_inode(file));
1296*4882a593Smuzhiyun 	if (size <= 0)
1297*4882a593Smuzhiyun 		return -EINVAL;
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	if (size > BDADDR_STRING_LEN)
1300*4882a593Smuzhiyun 		size = BDADDR_STRING_LEN;
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 	memset(tbuf, 0, sizeof(tbuf));
1303*4882a593Smuzhiyun 	RTKBT_INFO("size = %d", size);
1304*4882a593Smuzhiyun #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
1305*4882a593Smuzhiyun 	rc = kernel_read(file, tbuf, size, &pos);
1306*4882a593Smuzhiyun #else
1307*4882a593Smuzhiyun 	rc = kernel_read(file, 0, tbuf, size);
1308*4882a593Smuzhiyun #endif
1309*4882a593Smuzhiyun 	fput(file);
1310*4882a593Smuzhiyun 	if (rc != size) {
1311*4882a593Smuzhiyun 		if (rc >= 0)
1312*4882a593Smuzhiyun 			rc = -EIO;
1313*4882a593Smuzhiyun 		goto fail;
1314*4882a593Smuzhiyun 	}
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	if (bachk(tbuf) < 0) {
1317*4882a593Smuzhiyun 		rc = -EINVAL;
1318*4882a593Smuzhiyun 		goto fail;
1319*4882a593Smuzhiyun 	}
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	str = tbuf;
1322*4882a593Smuzhiyun 	for (i = 5; i >= 0; i--) {
1323*4882a593Smuzhiyun 		buf[i] = simple_strtol(str, NULL, 16);
1324*4882a593Smuzhiyun 		str += 3;
1325*4882a593Smuzhiyun 	}
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 	return size;
1328*4882a593Smuzhiyun fail:
1329*4882a593Smuzhiyun 	return rc;
1330*4882a593Smuzhiyun }
1331*4882a593Smuzhiyun 
load_config(dev_data * dev_entry,int * length)1332*4882a593Smuzhiyun static u8 *load_config(dev_data *dev_entry, int *length)
1333*4882a593Smuzhiyun {
1334*4882a593Smuzhiyun 	patch_info *patch_entry;
1335*4882a593Smuzhiyun 	const char *config_name;
1336*4882a593Smuzhiyun 	const struct firmware *fw;
1337*4882a593Smuzhiyun 	struct usb_device *udev;
1338*4882a593Smuzhiyun 	int result;
1339*4882a593Smuzhiyun 	u8 *buf;
1340*4882a593Smuzhiyun 	u8 *p;
1341*4882a593Smuzhiyun 	u16 config_len;
1342*4882a593Smuzhiyun 	u16 dlen;
1343*4882a593Smuzhiyun 	u8 tmp_buf[32];
1344*4882a593Smuzhiyun 	int file_sz;
1345*4882a593Smuzhiyun 	struct cfg_list_item *n;
1346*4882a593Smuzhiyun 	struct list_head *pos, *next;
1347*4882a593Smuzhiyun 	u8 chip_type;
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	config_lists_init();
1350*4882a593Smuzhiyun 	patch_entry = dev_entry->patch_entry;
1351*4882a593Smuzhiyun 	config_name = patch_entry->config_name;
1352*4882a593Smuzhiyun 	udev = dev_entry->udev;
1353*4882a593Smuzhiyun 	chip_type = patch_entry->chip_type;
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun 	RTKBT_INFO("config filename %s", config_name);
1356*4882a593Smuzhiyun 	result = request_firmware(&fw, config_name, &udev->dev);
1357*4882a593Smuzhiyun 	if (result < 0)
1358*4882a593Smuzhiyun 		return 0;
1359*4882a593Smuzhiyun 
1360*4882a593Smuzhiyun 	file_sz = fw->size;
1361*4882a593Smuzhiyun 	buf = (u8 *)fw->data;
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun 	/* Load extra configs */
1364*4882a593Smuzhiyun 	config_file_proc(EXTRA_CONFIG_FILE);
1365*4882a593Smuzhiyun 	list_for_each_safe(pos, next, &list_extracfgs) {
1366*4882a593Smuzhiyun 		n = list_entry(pos, struct cfg_list_item, list);
1367*4882a593Smuzhiyun 		RTKBT_INFO("extra cfg: ofs %04x, len %u", n->offset, n->len);
1368*4882a593Smuzhiyun 	}
1369*4882a593Smuzhiyun 
1370*4882a593Smuzhiyun 	/* Load extra bdaddr config */
1371*4882a593Smuzhiyun 	memset(tmp_buf, 0, sizeof(tmp_buf));
1372*4882a593Smuzhiyun 	result = request_bdaddr(tmp_buf);
1373*4882a593Smuzhiyun 	if (result > 0) {
1374*4882a593Smuzhiyun 		n = kzalloc(sizeof(*n) + 6, GFP_KERNEL);
1375*4882a593Smuzhiyun 		if (n) {
1376*4882a593Smuzhiyun 			n->offset = get_mac_offset(patch_entry->chip_type);
1377*4882a593Smuzhiyun 			n->len = 6;
1378*4882a593Smuzhiyun 			memcpy(n->data, tmp_buf, 6);
1379*4882a593Smuzhiyun 			list_add_tail(&n->list, &list_extracfgs);
1380*4882a593Smuzhiyun 		} else {
1381*4882a593Smuzhiyun 			RTKBT_WARN("Couldn't alloc mem for bdaddr");
1382*4882a593Smuzhiyun 		}
1383*4882a593Smuzhiyun 	} else {
1384*4882a593Smuzhiyun 		if (result == -ENOENT)
1385*4882a593Smuzhiyun 			RTKBT_WARN("no bdaddr file %s", BDADDR_FILE);
1386*4882a593Smuzhiyun 		else
1387*4882a593Smuzhiyun 			RTKBT_WARN("invalid customer bdaddr %d", result);
1388*4882a593Smuzhiyun 	}
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	RTKBT_INFO("Origin cfg len %u", (u16)file_sz);
1391*4882a593Smuzhiyun 	util_hexdump((const u8 *)buf, file_sz);
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	result = rtk_parse_config_file(buf, file_sz);
1394*4882a593Smuzhiyun 	if (result < 0) {
1395*4882a593Smuzhiyun 		RTKBT_ERR("Parse config file error");
1396*4882a593Smuzhiyun 		buf = NULL;
1397*4882a593Smuzhiyun 		goto done;
1398*4882a593Smuzhiyun 	}
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	merge_configs(&list_configs, &list_extracfgs);
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 	/* Calculate the config_len */
1403*4882a593Smuzhiyun 	config_len = 4; /* magic word length */
1404*4882a593Smuzhiyun 	config_len += 2; /* data length field */
1405*4882a593Smuzhiyun 	dlen = 0;
1406*4882a593Smuzhiyun 	list_for_each_safe(pos, next, &list_configs) {
1407*4882a593Smuzhiyun 		n = list_entry(pos, struct cfg_list_item, list);
1408*4882a593Smuzhiyun 		switch (n->offset) {
1409*4882a593Smuzhiyun 		case 0x003c:
1410*4882a593Smuzhiyun 		case 0x0030:
1411*4882a593Smuzhiyun 		case 0x0044:
1412*4882a593Smuzhiyun 			if (is_mac(chip_type, n->offset) && n->len == 6) {
1413*4882a593Smuzhiyun 				char s[18];
1414*4882a593Smuzhiyun 				sprintf(s, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
1415*4882a593Smuzhiyun 					n->data[5], n->data[4],
1416*4882a593Smuzhiyun 					n->data[3], n->data[2],
1417*4882a593Smuzhiyun 					n->data[1], n->data[0]);
1418*4882a593Smuzhiyun 				RTKBT_INFO("bdaddr ofs %04x, %s", n->offset, s);
1419*4882a593Smuzhiyun 			}
1420*4882a593Smuzhiyun 			break;
1421*4882a593Smuzhiyun 		default:
1422*4882a593Smuzhiyun 			break;
1423*4882a593Smuzhiyun 		}
1424*4882a593Smuzhiyun 
1425*4882a593Smuzhiyun 		config_len += (3 + n->len);
1426*4882a593Smuzhiyun 		dlen += (3 + n->len);
1427*4882a593Smuzhiyun 	}
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 
1430*4882a593Smuzhiyun 	buf = kzalloc(config_len, GFP_KERNEL);
1431*4882a593Smuzhiyun 	if (!buf) {
1432*4882a593Smuzhiyun 		RTKBT_ERR("Couldn't alloc buf for configs");
1433*4882a593Smuzhiyun 		goto done;
1434*4882a593Smuzhiyun 	}
1435*4882a593Smuzhiyun 
1436*4882a593Smuzhiyun 	/* Save configs to a buffer */
1437*4882a593Smuzhiyun 	memcpy(buf, cfg_magic, 4);
1438*4882a593Smuzhiyun 	buf[4] = dlen & 0xff;
1439*4882a593Smuzhiyun 	buf[5] = (dlen >> 8) & 0xff;
1440*4882a593Smuzhiyun 	p = buf + 6;
1441*4882a593Smuzhiyun 	list_for_each_safe(pos, next, &list_configs) {
1442*4882a593Smuzhiyun 		n = list_entry(pos, struct cfg_list_item, list);
1443*4882a593Smuzhiyun 		p[0] = n->offset & 0xff;
1444*4882a593Smuzhiyun 		p[1] = (n->offset >> 8) & 0xff;
1445*4882a593Smuzhiyun 		p[2] = n->len;
1446*4882a593Smuzhiyun 		memcpy(p + 3, n->data, n->len);
1447*4882a593Smuzhiyun 		p += (3 + n->len);
1448*4882a593Smuzhiyun 	}
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun 	RTKBT_INFO("New cfg len %u", config_len);
1451*4882a593Smuzhiyun 	util_hexdump((const u8 *)buf, config_len);
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun 	*length = config_len;
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun done:
1456*4882a593Smuzhiyun 	config_lists_free();
1457*4882a593Smuzhiyun 	release_firmware(fw);
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 	return buf;
1460*4882a593Smuzhiyun }
1461*4882a593Smuzhiyun 
load_firmware(dev_data * dev_entry,uint8_t ** buff)1462*4882a593Smuzhiyun int load_firmware(dev_data * dev_entry, uint8_t ** buff)
1463*4882a593Smuzhiyun {
1464*4882a593Smuzhiyun 	const struct firmware *fw;
1465*4882a593Smuzhiyun 	struct usb_device *udev;
1466*4882a593Smuzhiyun 	patch_info *patch_entry;
1467*4882a593Smuzhiyun 	char *fw_name;
1468*4882a593Smuzhiyun 	int fw_len = 0, ret_val = 0, config_len = 0, buf_len = -1;
1469*4882a593Smuzhiyun 	uint8_t *buf = *buff, *config_file_buf = NULL, *epatch_buf = NULL;
1470*4882a593Smuzhiyun 	uint8_t proj_id = 0;
1471*4882a593Smuzhiyun 	uint8_t need_download_fw = 1;
1472*4882a593Smuzhiyun 	uint16_t lmp_version;
1473*4882a593Smuzhiyun 	struct rtk_epatch_entry current_entry = { 0 };
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	RTKBT_DBG("load_firmware start");
1476*4882a593Smuzhiyun 	udev = dev_entry->udev;
1477*4882a593Smuzhiyun 	patch_entry = dev_entry->patch_entry;
1478*4882a593Smuzhiyun 	lmp_version = patch_entry->lmp_sub;
1479*4882a593Smuzhiyun 	RTKBT_DBG("lmp_version = 0x%04x", lmp_version);
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 	config_file_buf = load_config(dev_entry, &config_len);
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 	fw_name = patch_entry->patch_name;
1484*4882a593Smuzhiyun 	RTKBT_ERR("fw name is  %s", fw_name);
1485*4882a593Smuzhiyun 	ret_val = request_firmware(&fw, fw_name, &udev->dev);
1486*4882a593Smuzhiyun 	if (ret_val < 0) {
1487*4882a593Smuzhiyun 		fw_len = 0;
1488*4882a593Smuzhiyun 		kfree(config_file_buf);
1489*4882a593Smuzhiyun 		config_file_buf = NULL;
1490*4882a593Smuzhiyun 		goto fw_fail;
1491*4882a593Smuzhiyun 	}
1492*4882a593Smuzhiyun 
1493*4882a593Smuzhiyun 	epatch_buf = kzalloc(fw->size, GFP_KERNEL);
1494*4882a593Smuzhiyun 	if (NULL == epatch_buf)
1495*4882a593Smuzhiyun 		goto alloc_fail;
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	memcpy(epatch_buf, fw->data, fw->size);
1498*4882a593Smuzhiyun 	buf_len = fw->size + config_len;
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun 	if (lmp_version == ROM_LMP_8723a) {
1501*4882a593Smuzhiyun 		RTKBT_DBG("This is 8723a, use old patch style!");
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 		if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) == 0) {
1504*4882a593Smuzhiyun 			RTKBT_ERR("8723a Check signature error!");
1505*4882a593Smuzhiyun 			need_download_fw = 0;
1506*4882a593Smuzhiyun 		} else {
1507*4882a593Smuzhiyun 			if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
1508*4882a593Smuzhiyun 				RTKBT_ERR("Can't alloc memory for fw&config");
1509*4882a593Smuzhiyun 				buf_len = -1;
1510*4882a593Smuzhiyun 			} else {
1511*4882a593Smuzhiyun 				RTKBT_DBG("8723a, fw copy direct");
1512*4882a593Smuzhiyun 				memcpy(buf, epatch_buf, fw->size);
1513*4882a593Smuzhiyun 				if (config_len) {
1514*4882a593Smuzhiyun 					memcpy(&buf[buf_len - config_len],
1515*4882a593Smuzhiyun 					       config_file_buf, config_len);
1516*4882a593Smuzhiyun 				}
1517*4882a593Smuzhiyun 			}
1518*4882a593Smuzhiyun 		}
1519*4882a593Smuzhiyun 	} else {
1520*4882a593Smuzhiyun 		RTKBT_ERR("This is not 8723a, use new patch style!");
1521*4882a593Smuzhiyun 
1522*4882a593Smuzhiyun 		/* Get version from ROM */
1523*4882a593Smuzhiyun 		gEVersion = rtk_get_eversion(dev_entry);
1524*4882a593Smuzhiyun 		RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
1525*4882a593Smuzhiyun 		if (gEVersion == 0xFE) {
1526*4882a593Smuzhiyun 			RTKBT_ERR("%s: Read ROM version failure", __func__);
1527*4882a593Smuzhiyun 			need_download_fw = 0;
1528*4882a593Smuzhiyun 			fw_len = 0;
1529*4882a593Smuzhiyun 			goto alloc_fail;
1530*4882a593Smuzhiyun 		}
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 		/* check Signature and Extension Section Field */
1533*4882a593Smuzhiyun 		if ((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) != 0) ||
1534*4882a593Smuzhiyun 		    memcmp(epatch_buf + buf_len - config_len - 4,
1535*4882a593Smuzhiyun 			   Extension_Section_SIGNATURE, 4) != 0) {
1536*4882a593Smuzhiyun 			RTKBT_ERR("Check SIGNATURE error! do not download fw");
1537*4882a593Smuzhiyun 			need_download_fw = 0;
1538*4882a593Smuzhiyun 		} else {
1539*4882a593Smuzhiyun 			proj_id =
1540*4882a593Smuzhiyun 			    rtk_get_fw_project_id(epatch_buf + buf_len -
1541*4882a593Smuzhiyun 						  config_len - 5);
1542*4882a593Smuzhiyun 
1543*4882a593Smuzhiyun 			if (lmp_version != project_id[proj_id]) {
1544*4882a593Smuzhiyun 				RTKBT_ERR
1545*4882a593Smuzhiyun 				    ("lmp_version is %x, project_id is %x, does not match!!!",
1546*4882a593Smuzhiyun 				     lmp_version, project_id[proj_id]);
1547*4882a593Smuzhiyun 				need_download_fw = 0;
1548*4882a593Smuzhiyun 			} else {
1549*4882a593Smuzhiyun 				RTKBT_DBG
1550*4882a593Smuzhiyun 				    ("lmp_version is %x, project_id is %x, match!",
1551*4882a593Smuzhiyun 				     lmp_version, project_id[proj_id]);
1552*4882a593Smuzhiyun 				rtk_get_patch_entry(epatch_buf, &current_entry);
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 				if (current_entry.patch_length == 0)
1555*4882a593Smuzhiyun 					goto fw_fail;
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 				buf_len =
1558*4882a593Smuzhiyun 				    current_entry.patch_length + config_len;
1559*4882a593Smuzhiyun 				RTKBT_DBG("buf_len = 0x%x", buf_len);
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 				if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
1562*4882a593Smuzhiyun 					RTKBT_ERR
1563*4882a593Smuzhiyun 					    ("Can't alloc memory for multi fw&config");
1564*4882a593Smuzhiyun 					buf_len = -1;
1565*4882a593Smuzhiyun 				} else {
1566*4882a593Smuzhiyun 					memcpy(buf,
1567*4882a593Smuzhiyun 					       epatch_buf +
1568*4882a593Smuzhiyun 					       current_entry.start_offset,
1569*4882a593Smuzhiyun 					       current_entry.patch_length);
1570*4882a593Smuzhiyun 					memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4);	/*fw version */
1571*4882a593Smuzhiyun 					if (config_len) {
1572*4882a593Smuzhiyun 						memcpy(&buf
1573*4882a593Smuzhiyun 						       [buf_len - config_len],
1574*4882a593Smuzhiyun 						       config_file_buf,
1575*4882a593Smuzhiyun 						       config_len);
1576*4882a593Smuzhiyun 					}
1577*4882a593Smuzhiyun 				}
1578*4882a593Smuzhiyun 			}
1579*4882a593Smuzhiyun 		}
1580*4882a593Smuzhiyun 	}
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	RTKBT_DBG("fw:%s exists, config file:%s exists",
1583*4882a593Smuzhiyun 		  (buf_len > 0) ? "" : "not", (config_len > 0) ? "" : "not");
1584*4882a593Smuzhiyun 	if (buf && (buf_len > 0) && (need_download_fw)) {
1585*4882a593Smuzhiyun 		fw_len = buf_len;
1586*4882a593Smuzhiyun 		*buff = buf;
1587*4882a593Smuzhiyun 	}
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun 	RTKBT_DBG("load_firmware done");
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun alloc_fail:
1592*4882a593Smuzhiyun 	release_firmware(fw);
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 	if (epatch_buf)
1595*4882a593Smuzhiyun 		kfree(epatch_buf);
1596*4882a593Smuzhiyun 
1597*4882a593Smuzhiyun 	if (config_file_buf)
1598*4882a593Smuzhiyun 		kfree(config_file_buf);
1599*4882a593Smuzhiyun fw_fail:
1600*4882a593Smuzhiyun 	return fw_len;
1601*4882a593Smuzhiyun }
1602*4882a593Smuzhiyun 
init_xdata(xchange_data * xdata,dev_data * dev_entry)1603*4882a593Smuzhiyun void init_xdata(xchange_data * xdata, dev_data * dev_entry)
1604*4882a593Smuzhiyun {
1605*4882a593Smuzhiyun 	memset(xdata, 0, sizeof(xchange_data));
1606*4882a593Smuzhiyun 	xdata->dev_entry = dev_entry;
1607*4882a593Smuzhiyun 	xdata->pipe_in = usb_rcvintpipe(dev_entry->udev, INTR_EP);
1608*4882a593Smuzhiyun 	xdata->pipe_out = usb_sndctrlpipe(dev_entry->udev, CTRL_EP);
1609*4882a593Smuzhiyun 	xdata->send_pkt = kzalloc(PKT_LEN, GFP_KERNEL);
1610*4882a593Smuzhiyun 	xdata->rcv_pkt = kzalloc(PKT_LEN, GFP_KERNEL);
1611*4882a593Smuzhiyun 	xdata->cmd_hdr = (struct hci_command_hdr *)(xdata->send_pkt);
1612*4882a593Smuzhiyun 	xdata->evt_hdr = (struct hci_event_hdr *)(xdata->rcv_pkt);
1613*4882a593Smuzhiyun 	xdata->cmd_cmp =
1614*4882a593Smuzhiyun 	    (struct hci_ev_cmd_complete *)(xdata->rcv_pkt + EVT_HDR_LEN);
1615*4882a593Smuzhiyun 	xdata->req_para = xdata->send_pkt + CMD_HDR_LEN;
1616*4882a593Smuzhiyun 	xdata->rsp_para = xdata->rcv_pkt + EVT_HDR_LEN + CMD_CMP_LEN;
1617*4882a593Smuzhiyun }
1618*4882a593Smuzhiyun 
check_fw_version(xchange_data * xdata)1619*4882a593Smuzhiyun int check_fw_version(xchange_data * xdata)
1620*4882a593Smuzhiyun {
1621*4882a593Smuzhiyun 	struct hci_rp_read_local_version *read_ver_rsp;
1622*4882a593Smuzhiyun 	patch_info *patch_entry;
1623*4882a593Smuzhiyun 	int ret_val;
1624*4882a593Smuzhiyun 	int retry = 0;
1625*4882a593Smuzhiyun 
1626*4882a593Smuzhiyun 	/* Ensure that the first cmd is hci reset after system suspend
1627*4882a593Smuzhiyun 	 * or system reboot */
1628*4882a593Smuzhiyun 	send_reset_command(xdata);
1629*4882a593Smuzhiyun 
1630*4882a593Smuzhiyun get_ver:
1631*4882a593Smuzhiyun 	xdata->cmd_hdr->opcode = cpu_to_le16(HCI_OP_READ_LOCAL_VERSION);
1632*4882a593Smuzhiyun 	xdata->cmd_hdr->plen = 0;
1633*4882a593Smuzhiyun 	xdata->pkt_len = CMD_HDR_LEN;
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	ret_val = send_hci_cmd(xdata);
1636*4882a593Smuzhiyun 	if (ret_val < 0) {
1637*4882a593Smuzhiyun 		RTKBT_ERR("%s: Failed to send HCI command.", __func__);
1638*4882a593Smuzhiyun 		goto version_end;
1639*4882a593Smuzhiyun 	}
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 	ret_val = rcv_hci_evt(xdata);
1642*4882a593Smuzhiyun 	if (ret_val < 0) {
1643*4882a593Smuzhiyun 		RTKBT_ERR("%s: Failed to receive HCI event.", __func__);
1644*4882a593Smuzhiyun 		goto version_end;
1645*4882a593Smuzhiyun 	}
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun 	patch_entry = xdata->dev_entry->patch_entry;
1648*4882a593Smuzhiyun 	read_ver_rsp = (struct hci_rp_read_local_version *)(xdata->rsp_para);
1649*4882a593Smuzhiyun 	read_ver_rsp->lmp_subver = le16_to_cpu(read_ver_rsp->lmp_subver);
1650*4882a593Smuzhiyun 	read_ver_rsp->hci_rev = le16_to_cpu(read_ver_rsp->hci_rev);
1651*4882a593Smuzhiyun 	read_ver_rsp->manufacturer = le16_to_cpu(read_ver_rsp->manufacturer);
1652*4882a593Smuzhiyun 
1653*4882a593Smuzhiyun 	RTKBT_DBG("read_ver_rsp->lmp_subver = 0x%x", read_ver_rsp->lmp_subver);
1654*4882a593Smuzhiyun 	RTKBT_DBG("read_ver_rsp->hci_rev = 0x%x", read_ver_rsp->hci_rev);
1655*4882a593Smuzhiyun 	RTKBT_DBG("patch_entry->lmp_sub = 0x%x", patch_entry->lmp_sub);
1656*4882a593Smuzhiyun 	if (patch_entry->lmp_sub != read_ver_rsp->lmp_subver) {
1657*4882a593Smuzhiyun 		return 1;
1658*4882a593Smuzhiyun 	}
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 	ret_val = 0;
1661*4882a593Smuzhiyun version_end:
1662*4882a593Smuzhiyun 	if (ret_val) {
1663*4882a593Smuzhiyun 		send_reset_command(xdata);
1664*4882a593Smuzhiyun 		retry++;
1665*4882a593Smuzhiyun 		if (retry < 2)
1666*4882a593Smuzhiyun 			goto get_ver;
1667*4882a593Smuzhiyun 	}
1668*4882a593Smuzhiyun 
1669*4882a593Smuzhiyun 	return ret_val;
1670*4882a593Smuzhiyun }
1671*4882a593Smuzhiyun 
rtk_get_eversion(dev_data * dev_entry)1672*4882a593Smuzhiyun uint8_t rtk_get_eversion(dev_data * dev_entry)
1673*4882a593Smuzhiyun {
1674*4882a593Smuzhiyun 	struct rtk_eversion_evt *eversion;
1675*4882a593Smuzhiyun 	patch_info *patch_entry;
1676*4882a593Smuzhiyun 	int ret_val = 0;
1677*4882a593Smuzhiyun 	xchange_data *xdata = NULL;
1678*4882a593Smuzhiyun 
1679*4882a593Smuzhiyun 	RTKBT_DBG("%s: gEVersion %d", __func__, gEVersion);
1680*4882a593Smuzhiyun 	if (gEVersion != 0xFF && gEVersion != 0xFE) {
1681*4882a593Smuzhiyun 		RTKBT_DBG("gEVersion != 0xFF, return it directly!");
1682*4882a593Smuzhiyun 		return gEVersion;
1683*4882a593Smuzhiyun 	}
1684*4882a593Smuzhiyun 
1685*4882a593Smuzhiyun 	xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
1686*4882a593Smuzhiyun 	if (NULL == xdata) {
1687*4882a593Smuzhiyun 		ret_val = 0xFE;
1688*4882a593Smuzhiyun 		RTKBT_DBG("NULL == xdata");
1689*4882a593Smuzhiyun 		return ret_val;
1690*4882a593Smuzhiyun 	}
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun 	init_xdata(xdata, dev_entry);
1693*4882a593Smuzhiyun 
1694*4882a593Smuzhiyun 	xdata->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_READ_RTK_ROM_VERISION);
1695*4882a593Smuzhiyun 	xdata->cmd_hdr->plen = 0;
1696*4882a593Smuzhiyun 	xdata->pkt_len = CMD_HDR_LEN;
1697*4882a593Smuzhiyun 
1698*4882a593Smuzhiyun 	ret_val = send_hci_cmd(xdata);
1699*4882a593Smuzhiyun 	if (ret_val < 0) {
1700*4882a593Smuzhiyun 		RTKBT_ERR("Failed to send read RTK rom version cmd.");
1701*4882a593Smuzhiyun 		ret_val = 0xFE;
1702*4882a593Smuzhiyun 		goto version_end;
1703*4882a593Smuzhiyun 	}
1704*4882a593Smuzhiyun 
1705*4882a593Smuzhiyun 	ret_val = rcv_hci_evt(xdata);
1706*4882a593Smuzhiyun 	if (ret_val < 0) {
1707*4882a593Smuzhiyun 		RTKBT_ERR("Failed to receive HCI event for rom version.");
1708*4882a593Smuzhiyun 		ret_val = 0xFE;
1709*4882a593Smuzhiyun 		goto version_end;
1710*4882a593Smuzhiyun 	}
1711*4882a593Smuzhiyun 
1712*4882a593Smuzhiyun 	patch_entry = xdata->dev_entry->patch_entry;
1713*4882a593Smuzhiyun 	eversion = (struct rtk_eversion_evt *)(xdata->rsp_para);
1714*4882a593Smuzhiyun 	RTKBT_DBG("eversion->status = 0x%x, eversion->version = 0x%x",
1715*4882a593Smuzhiyun 		  eversion->status, eversion->version);
1716*4882a593Smuzhiyun 	if (eversion->status) {
1717*4882a593Smuzhiyun 		ret_val = 0;
1718*4882a593Smuzhiyun 		//global_eversion = 0;
1719*4882a593Smuzhiyun 	} else {
1720*4882a593Smuzhiyun 		ret_val = eversion->version;
1721*4882a593Smuzhiyun 		//global_eversion = eversion->version;
1722*4882a593Smuzhiyun 	}
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun version_end:
1725*4882a593Smuzhiyun 	if (xdata != NULL) {
1726*4882a593Smuzhiyun 		if (xdata->send_pkt)
1727*4882a593Smuzhiyun 			kfree(xdata->send_pkt);
1728*4882a593Smuzhiyun 		if (xdata->rcv_pkt)
1729*4882a593Smuzhiyun 			kfree(xdata->rcv_pkt);
1730*4882a593Smuzhiyun 		kfree(xdata);
1731*4882a593Smuzhiyun 	}
1732*4882a593Smuzhiyun 	return ret_val;
1733*4882a593Smuzhiyun }
1734*4882a593Smuzhiyun 
download_data(xchange_data * xdata)1735*4882a593Smuzhiyun int download_data(xchange_data * xdata)
1736*4882a593Smuzhiyun {
1737*4882a593Smuzhiyun 	download_cp *cmd_para;
1738*4882a593Smuzhiyun 	download_rp *evt_para;
1739*4882a593Smuzhiyun 	uint8_t *pcur;
1740*4882a593Smuzhiyun 	int pkt_len, frag_num, frag_len;
1741*4882a593Smuzhiyun 	int i, ret_val;
1742*4882a593Smuzhiyun 	int j;
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun 	RTKBT_DBG("download_data start");
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun 	cmd_para = (download_cp *) xdata->req_para;
1747*4882a593Smuzhiyun 	evt_para = (download_rp *) xdata->rsp_para;
1748*4882a593Smuzhiyun 	pcur = xdata->fw_data;
1749*4882a593Smuzhiyun 	pkt_len = CMD_HDR_LEN + sizeof(download_cp);
1750*4882a593Smuzhiyun 	frag_num = xdata->fw_len / PATCH_SEG_MAX + 1;
1751*4882a593Smuzhiyun 	frag_len = PATCH_SEG_MAX;
1752*4882a593Smuzhiyun 
1753*4882a593Smuzhiyun 	for (i = 0; i < frag_num; i++) {
1754*4882a593Smuzhiyun 		if (i > 0x7f)
1755*4882a593Smuzhiyun 			j = (i & 0x7f) + 1;
1756*4882a593Smuzhiyun 		else
1757*4882a593Smuzhiyun 			j = i;
1758*4882a593Smuzhiyun 
1759*4882a593Smuzhiyun 		cmd_para->index = j;
1760*4882a593Smuzhiyun 		if (i == (frag_num - 1)) {
1761*4882a593Smuzhiyun 			cmd_para->index |= DATA_END;
1762*4882a593Smuzhiyun 			frag_len = xdata->fw_len % PATCH_SEG_MAX;
1763*4882a593Smuzhiyun 			pkt_len -= (PATCH_SEG_MAX - frag_len);
1764*4882a593Smuzhiyun 		}
1765*4882a593Smuzhiyun 		xdata->cmd_hdr->opcode = cpu_to_le16(DOWNLOAD_OPCODE);
1766*4882a593Smuzhiyun 		xdata->cmd_hdr->plen = sizeof(uint8_t) + frag_len;
1767*4882a593Smuzhiyun 		xdata->pkt_len = pkt_len;
1768*4882a593Smuzhiyun 		memcpy(cmd_para->data, pcur, frag_len);
1769*4882a593Smuzhiyun 
1770*4882a593Smuzhiyun 		ret_val = send_hci_cmd(xdata);
1771*4882a593Smuzhiyun 		if (ret_val < 0) {
1772*4882a593Smuzhiyun 			return ret_val;
1773*4882a593Smuzhiyun 		}
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun 		ret_val = rcv_hci_evt(xdata);
1776*4882a593Smuzhiyun 		if (ret_val < 0) {
1777*4882a593Smuzhiyun 			return ret_val;
1778*4882a593Smuzhiyun 		}
1779*4882a593Smuzhiyun 
1780*4882a593Smuzhiyun 		if (0 != evt_para->status) {
1781*4882a593Smuzhiyun 			return -1;
1782*4882a593Smuzhiyun 		}
1783*4882a593Smuzhiyun 
1784*4882a593Smuzhiyun 		pcur += PATCH_SEG_MAX;
1785*4882a593Smuzhiyun 	}
1786*4882a593Smuzhiyun 
1787*4882a593Smuzhiyun 	RTKBT_DBG("download_data done");
1788*4882a593Smuzhiyun 	return xdata->fw_len;
1789*4882a593Smuzhiyun }
1790*4882a593Smuzhiyun 
send_hci_cmd(xchange_data * xdata)1791*4882a593Smuzhiyun int send_hci_cmd(xchange_data * xdata)
1792*4882a593Smuzhiyun {
1793*4882a593Smuzhiyun 	int ret_val;
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	ret_val = usb_control_msg(xdata->dev_entry->udev, xdata->pipe_out,
1796*4882a593Smuzhiyun 				  0, USB_TYPE_CLASS, 0, 0,
1797*4882a593Smuzhiyun 				  (void *)(xdata->send_pkt),
1798*4882a593Smuzhiyun 				  xdata->pkt_len, MSG_TO);
1799*4882a593Smuzhiyun 
1800*4882a593Smuzhiyun 	if (ret_val < 0)
1801*4882a593Smuzhiyun 		RTKBT_ERR("%s; failed to send ctl msg for hci cmd, err %d",
1802*4882a593Smuzhiyun 			  __func__, ret_val);
1803*4882a593Smuzhiyun 
1804*4882a593Smuzhiyun 	return ret_val;
1805*4882a593Smuzhiyun }
1806*4882a593Smuzhiyun 
rcv_hci_evt(xchange_data * xdata)1807*4882a593Smuzhiyun int rcv_hci_evt(xchange_data * xdata)
1808*4882a593Smuzhiyun {
1809*4882a593Smuzhiyun 	int ret_len = 0, ret_val = 0;
1810*4882a593Smuzhiyun 	int i;			// Added by Realtek
1811*4882a593Smuzhiyun 
1812*4882a593Smuzhiyun 	while (1) {
1813*4882a593Smuzhiyun 		// **************************** Modifed by Realtek (begin)
1814*4882a593Smuzhiyun 		for (i = 0; i < 5; i++)	// Try to send USB interrupt message 5 times.
1815*4882a593Smuzhiyun 		{
1816*4882a593Smuzhiyun 			ret_val =
1817*4882a593Smuzhiyun 			    usb_interrupt_msg(xdata->dev_entry->udev,
1818*4882a593Smuzhiyun 					      xdata->pipe_in,
1819*4882a593Smuzhiyun 					      (void *)(xdata->rcv_pkt), PKT_LEN,
1820*4882a593Smuzhiyun 					      &ret_len, MSG_TO);
1821*4882a593Smuzhiyun 			if (ret_val >= 0)
1822*4882a593Smuzhiyun 				break;
1823*4882a593Smuzhiyun 		}
1824*4882a593Smuzhiyun 		// **************************** Modifed by Realtek (end)
1825*4882a593Smuzhiyun 
1826*4882a593Smuzhiyun 		if (ret_val < 0) {
1827*4882a593Smuzhiyun 			RTKBT_ERR("%s; no usb intr msg for hci event, err %d",
1828*4882a593Smuzhiyun 				  __func__, ret_val);
1829*4882a593Smuzhiyun 			return ret_val;
1830*4882a593Smuzhiyun 		}
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun 		if (CMD_CMP_EVT == xdata->evt_hdr->evt) {
1833*4882a593Smuzhiyun 			if (xdata->cmd_hdr->opcode == xdata->cmd_cmp->opcode)
1834*4882a593Smuzhiyun 				return ret_len;
1835*4882a593Smuzhiyun 		}
1836*4882a593Smuzhiyun 	}
1837*4882a593Smuzhiyun }
1838*4882a593Smuzhiyun 
print_acl(struct sk_buff * skb,int dataOut)1839*4882a593Smuzhiyun void print_acl(struct sk_buff *skb, int dataOut)
1840*4882a593Smuzhiyun {
1841*4882a593Smuzhiyun #if PRINT_ACL_DATA
1842*4882a593Smuzhiyun 	uint wlength = skb->len;
1843*4882a593Smuzhiyun 	uint icount = 0;
1844*4882a593Smuzhiyun 	u16 *handle = (u16 *) (skb->data);
1845*4882a593Smuzhiyun 	u16 dataLen = *(handle + 1);
1846*4882a593Smuzhiyun 	u8 *acl_data = (u8 *) (skb->data);
1847*4882a593Smuzhiyun //if (0==dataOut)
1848*4882a593Smuzhiyun 	printk("%d handle:%04x,len:%d,", dataOut, *handle, dataLen);
1849*4882a593Smuzhiyun //else
1850*4882a593Smuzhiyun //      printk("In handle:%04x,len:%d,",*handle,dataLen);
1851*4882a593Smuzhiyun /*	for(icount=4;(icount<wlength)&&(icount<32);icount++)
1852*4882a593Smuzhiyun 		{
1853*4882a593Smuzhiyun 			printk("%02x ",*(acl_data+icount) );
1854*4882a593Smuzhiyun 		}
1855*4882a593Smuzhiyun 	printk("\n");
1856*4882a593Smuzhiyun */
1857*4882a593Smuzhiyun #endif
1858*4882a593Smuzhiyun }
1859*4882a593Smuzhiyun 
print_command(struct sk_buff * skb)1860*4882a593Smuzhiyun void print_command(struct sk_buff *skb)
1861*4882a593Smuzhiyun {
1862*4882a593Smuzhiyun #if PRINT_CMD_EVENT
1863*4882a593Smuzhiyun 	uint wlength = skb->len;
1864*4882a593Smuzhiyun 	uint icount = 0;
1865*4882a593Smuzhiyun 	u16 *opcode = (u16 *) (skb->data);
1866*4882a593Smuzhiyun 	u8 *cmd_data = (u8 *) (skb->data);
1867*4882a593Smuzhiyun 	u8 paramLen = *(cmd_data + 2);
1868*4882a593Smuzhiyun 
1869*4882a593Smuzhiyun 	switch (*opcode) {
1870*4882a593Smuzhiyun 	case HCI_OP_INQUIRY:
1871*4882a593Smuzhiyun 		printk("HCI_OP_INQUIRY");
1872*4882a593Smuzhiyun 		break;
1873*4882a593Smuzhiyun 	case HCI_OP_INQUIRY_CANCEL:
1874*4882a593Smuzhiyun 		printk("HCI_OP_INQUIRY_CANCEL");
1875*4882a593Smuzhiyun 		break;
1876*4882a593Smuzhiyun 	case HCI_OP_EXIT_PERIODIC_INQ:
1877*4882a593Smuzhiyun 		printk("HCI_OP_EXIT_PERIODIC_INQ");
1878*4882a593Smuzhiyun 		break;
1879*4882a593Smuzhiyun 	case HCI_OP_CREATE_CONN:
1880*4882a593Smuzhiyun 		printk("HCI_OP_CREATE_CONN");
1881*4882a593Smuzhiyun 		break;
1882*4882a593Smuzhiyun 	case HCI_OP_DISCONNECT:
1883*4882a593Smuzhiyun 		printk("HCI_OP_DISCONNECT");
1884*4882a593Smuzhiyun 		break;
1885*4882a593Smuzhiyun 	case HCI_OP_CREATE_CONN_CANCEL:
1886*4882a593Smuzhiyun 		printk("HCI_OP_CREATE_CONN_CANCEL");
1887*4882a593Smuzhiyun 		break;
1888*4882a593Smuzhiyun 	case HCI_OP_ACCEPT_CONN_REQ:
1889*4882a593Smuzhiyun 		printk("HCI_OP_ACCEPT_CONN_REQ");
1890*4882a593Smuzhiyun 		break;
1891*4882a593Smuzhiyun 	case HCI_OP_REJECT_CONN_REQ:
1892*4882a593Smuzhiyun 		printk("HCI_OP_REJECT_CONN_REQ");
1893*4882a593Smuzhiyun 		break;
1894*4882a593Smuzhiyun 	case HCI_OP_AUTH_REQUESTED:
1895*4882a593Smuzhiyun 		printk("HCI_OP_AUTH_REQUESTED");
1896*4882a593Smuzhiyun 		break;
1897*4882a593Smuzhiyun 	case HCI_OP_SET_CONN_ENCRYPT:
1898*4882a593Smuzhiyun 		printk("HCI_OP_SET_CONN_ENCRYPT");
1899*4882a593Smuzhiyun 		break;
1900*4882a593Smuzhiyun 	case HCI_OP_REMOTE_NAME_REQ:
1901*4882a593Smuzhiyun 		printk("HCI_OP_REMOTE_NAME_REQ");
1902*4882a593Smuzhiyun 		break;
1903*4882a593Smuzhiyun 	case HCI_OP_READ_REMOTE_FEATURES:
1904*4882a593Smuzhiyun 		printk("HCI_OP_READ_REMOTE_FEATURES");
1905*4882a593Smuzhiyun 		break;
1906*4882a593Smuzhiyun 	case HCI_OP_SNIFF_MODE:
1907*4882a593Smuzhiyun 		printk("HCI_OP_SNIFF_MODE");
1908*4882a593Smuzhiyun 		break;
1909*4882a593Smuzhiyun 	case HCI_OP_EXIT_SNIFF_MODE:
1910*4882a593Smuzhiyun 		printk("HCI_OP_EXIT_SNIFF_MODE");
1911*4882a593Smuzhiyun 		break;
1912*4882a593Smuzhiyun 	case HCI_OP_SWITCH_ROLE:
1913*4882a593Smuzhiyun 		printk("HCI_OP_SWITCH_ROLE");
1914*4882a593Smuzhiyun 		break;
1915*4882a593Smuzhiyun 	case HCI_OP_SNIFF_SUBRATE:
1916*4882a593Smuzhiyun 		printk("HCI_OP_SNIFF_SUBRATE");
1917*4882a593Smuzhiyun 		break;
1918*4882a593Smuzhiyun 	case HCI_OP_RESET:
1919*4882a593Smuzhiyun 		printk("HCI_OP_RESET");
1920*4882a593Smuzhiyun 		break;
1921*4882a593Smuzhiyun 	default:
1922*4882a593Smuzhiyun 		printk("CMD");
1923*4882a593Smuzhiyun 		break;
1924*4882a593Smuzhiyun 	}
1925*4882a593Smuzhiyun 	printk(":%04x,len:%d,", *opcode, paramLen);
1926*4882a593Smuzhiyun 	for (icount = 3; (icount < wlength) && (icount < 24); icount++) {
1927*4882a593Smuzhiyun 		printk("%02x ", *(cmd_data + icount));
1928*4882a593Smuzhiyun 	}
1929*4882a593Smuzhiyun 	printk("\n");
1930*4882a593Smuzhiyun 
1931*4882a593Smuzhiyun #endif
1932*4882a593Smuzhiyun }
1933*4882a593Smuzhiyun 
print_event(struct sk_buff * skb)1934*4882a593Smuzhiyun void print_event(struct sk_buff *skb)
1935*4882a593Smuzhiyun {
1936*4882a593Smuzhiyun #if PRINT_CMD_EVENT
1937*4882a593Smuzhiyun 	uint wlength = skb->len;
1938*4882a593Smuzhiyun 	uint icount = 0;
1939*4882a593Smuzhiyun 	u8 *opcode = (u8 *) (skb->data);
1940*4882a593Smuzhiyun 	u8 paramLen = *(opcode + 1);
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun 	switch (*opcode) {
1943*4882a593Smuzhiyun 	case HCI_EV_INQUIRY_COMPLETE:
1944*4882a593Smuzhiyun 		printk("HCI_EV_INQUIRY_COMPLETE");
1945*4882a593Smuzhiyun 		break;
1946*4882a593Smuzhiyun 	case HCI_EV_INQUIRY_RESULT:
1947*4882a593Smuzhiyun 		printk("HCI_EV_INQUIRY_RESULT");
1948*4882a593Smuzhiyun 		break;
1949*4882a593Smuzhiyun 	case HCI_EV_CONN_COMPLETE:
1950*4882a593Smuzhiyun 		printk("HCI_EV_CONN_COMPLETE");
1951*4882a593Smuzhiyun 		break;
1952*4882a593Smuzhiyun 	case HCI_EV_CONN_REQUEST:
1953*4882a593Smuzhiyun 		printk("HCI_EV_CONN_REQUEST");
1954*4882a593Smuzhiyun 		break;
1955*4882a593Smuzhiyun 	case HCI_EV_DISCONN_COMPLETE:
1956*4882a593Smuzhiyun 		printk("HCI_EV_DISCONN_COMPLETE");
1957*4882a593Smuzhiyun 		break;
1958*4882a593Smuzhiyun 	case HCI_EV_AUTH_COMPLETE:
1959*4882a593Smuzhiyun 		printk("HCI_EV_AUTH_COMPLETE");
1960*4882a593Smuzhiyun 		break;
1961*4882a593Smuzhiyun 	case HCI_EV_REMOTE_NAME:
1962*4882a593Smuzhiyun 		printk("HCI_EV_REMOTE_NAME");
1963*4882a593Smuzhiyun 		break;
1964*4882a593Smuzhiyun 	case HCI_EV_ENCRYPT_CHANGE:
1965*4882a593Smuzhiyun 		printk("HCI_EV_ENCRYPT_CHANGE");
1966*4882a593Smuzhiyun 		break;
1967*4882a593Smuzhiyun 	case HCI_EV_CHANGE_LINK_KEY_COMPLETE:
1968*4882a593Smuzhiyun 		printk("HCI_EV_CHANGE_LINK_KEY_COMPLETE");
1969*4882a593Smuzhiyun 		break;
1970*4882a593Smuzhiyun 	case HCI_EV_REMOTE_FEATURES:
1971*4882a593Smuzhiyun 		printk("HCI_EV_REMOTE_FEATURES");
1972*4882a593Smuzhiyun 		break;
1973*4882a593Smuzhiyun 	case HCI_EV_REMOTE_VERSION:
1974*4882a593Smuzhiyun 		printk("HCI_EV_REMOTE_VERSION");
1975*4882a593Smuzhiyun 		break;
1976*4882a593Smuzhiyun 	case HCI_EV_QOS_SETUP_COMPLETE:
1977*4882a593Smuzhiyun 		printk("HCI_EV_QOS_SETUP_COMPLETE");
1978*4882a593Smuzhiyun 		break;
1979*4882a593Smuzhiyun 	case HCI_EV_CMD_COMPLETE:
1980*4882a593Smuzhiyun 		printk("HCI_EV_CMD_COMPLETE");
1981*4882a593Smuzhiyun 		break;
1982*4882a593Smuzhiyun 	case HCI_EV_CMD_STATUS:
1983*4882a593Smuzhiyun 		printk("HCI_EV_CMD_STATUS");
1984*4882a593Smuzhiyun 		break;
1985*4882a593Smuzhiyun 	case HCI_EV_ROLE_CHANGE:
1986*4882a593Smuzhiyun 		printk("HCI_EV_ROLE_CHANGE");
1987*4882a593Smuzhiyun 		break;
1988*4882a593Smuzhiyun 	case HCI_EV_NUM_COMP_PKTS:
1989*4882a593Smuzhiyun 		printk("HCI_EV_NUM_COMP_PKTS");
1990*4882a593Smuzhiyun 		break;
1991*4882a593Smuzhiyun 	case HCI_EV_MODE_CHANGE:
1992*4882a593Smuzhiyun 		printk("HCI_EV_MODE_CHANGE");
1993*4882a593Smuzhiyun 		break;
1994*4882a593Smuzhiyun 	case HCI_EV_PIN_CODE_REQ:
1995*4882a593Smuzhiyun 		printk("HCI_EV_PIN_CODE_REQ");
1996*4882a593Smuzhiyun 		break;
1997*4882a593Smuzhiyun 	case HCI_EV_LINK_KEY_REQ:
1998*4882a593Smuzhiyun 		printk("HCI_EV_LINK_KEY_REQ");
1999*4882a593Smuzhiyun 		break;
2000*4882a593Smuzhiyun 	case HCI_EV_LINK_KEY_NOTIFY:
2001*4882a593Smuzhiyun 		printk("HCI_EV_LINK_KEY_NOTIFY");
2002*4882a593Smuzhiyun 		break;
2003*4882a593Smuzhiyun 	case HCI_EV_CLOCK_OFFSET:
2004*4882a593Smuzhiyun 		printk("HCI_EV_CLOCK_OFFSET");
2005*4882a593Smuzhiyun 		break;
2006*4882a593Smuzhiyun 	case HCI_EV_PKT_TYPE_CHANGE:
2007*4882a593Smuzhiyun 		printk("HCI_EV_PKT_TYPE_CHANGE");
2008*4882a593Smuzhiyun 		break;
2009*4882a593Smuzhiyun 	case HCI_EV_PSCAN_REP_MODE:
2010*4882a593Smuzhiyun 		printk("HCI_EV_PSCAN_REP_MODE");
2011*4882a593Smuzhiyun 		break;
2012*4882a593Smuzhiyun 	case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
2013*4882a593Smuzhiyun 		printk("HCI_EV_INQUIRY_RESULT_WITH_RSSI");
2014*4882a593Smuzhiyun 		break;
2015*4882a593Smuzhiyun 	case HCI_EV_REMOTE_EXT_FEATURES:
2016*4882a593Smuzhiyun 		printk("HCI_EV_REMOTE_EXT_FEATURES");
2017*4882a593Smuzhiyun 		break;
2018*4882a593Smuzhiyun 	case HCI_EV_SYNC_CONN_COMPLETE:
2019*4882a593Smuzhiyun 		printk("HCI_EV_SYNC_CONN_COMPLETE");
2020*4882a593Smuzhiyun 		break;
2021*4882a593Smuzhiyun 	case HCI_EV_SYNC_CONN_CHANGED:
2022*4882a593Smuzhiyun 		printk("HCI_EV_SYNC_CONN_CHANGED");
2023*4882a593Smuzhiyun 		break;
2024*4882a593Smuzhiyun 	case HCI_EV_SNIFF_SUBRATE:
2025*4882a593Smuzhiyun 		printk("HCI_EV_SNIFF_SUBRATE");
2026*4882a593Smuzhiyun 		break;
2027*4882a593Smuzhiyun 	case HCI_EV_EXTENDED_INQUIRY_RESULT:
2028*4882a593Smuzhiyun 		printk("HCI_EV_EXTENDED_INQUIRY_RESULT");
2029*4882a593Smuzhiyun 		break;
2030*4882a593Smuzhiyun 	case HCI_EV_IO_CAPA_REQUEST:
2031*4882a593Smuzhiyun 		printk("HCI_EV_IO_CAPA_REQUEST");
2032*4882a593Smuzhiyun 		break;
2033*4882a593Smuzhiyun 	case HCI_EV_SIMPLE_PAIR_COMPLETE:
2034*4882a593Smuzhiyun 		printk("HCI_EV_SIMPLE_PAIR_COMPLETE");
2035*4882a593Smuzhiyun 		break;
2036*4882a593Smuzhiyun 	case HCI_EV_REMOTE_HOST_FEATURES:
2037*4882a593Smuzhiyun 		printk("HCI_EV_REMOTE_HOST_FEATURES");
2038*4882a593Smuzhiyun 		break;
2039*4882a593Smuzhiyun 	default:
2040*4882a593Smuzhiyun 		printk("event");
2041*4882a593Smuzhiyun 		break;
2042*4882a593Smuzhiyun 	}
2043*4882a593Smuzhiyun 	printk(":%02x,len:%d,", *opcode, paramLen);
2044*4882a593Smuzhiyun 	for (icount = 2; (icount < wlength) && (icount < 24); icount++) {
2045*4882a593Smuzhiyun 		printk("%02x ", *(opcode + icount));
2046*4882a593Smuzhiyun 	}
2047*4882a593Smuzhiyun 	printk("\n");
2048*4882a593Smuzhiyun 
2049*4882a593Smuzhiyun #endif
2050*4882a593Smuzhiyun }
2051