dhd: import wifi and bluetooth firmware
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.101.10.240.x / dhd_config.c
1 extern void *get_ukdev(void);
2 extern int key_unify_read(void *ukdev, char *keyname, unsigned char *keydata,
3 unsigned int datalen, unsigned int *reallen);
4 extern int key_unify_size(void *ukdev, char *keyname, unsigned int *reallen);
5
6 #include <typedefs.h>
7 #include <osl.h>
8
9 #include <bcmendian.h>
10 #include <bcmutils.h>
11 #include <hndsoc.h>
12 #include <bcmsdbus.h>
13 #if defined(HW_OOB) || defined(FORCE_WOWLAN)
14 #include <bcmdefs.h>
15 #include <bcmsdh.h>
16 #include <sdio.h>
17 #include <sbchipc.h>
18 #endif
19 #ifdef WL_CFG80211
20 #include <wl_cfg80211.h>
21 #endif
22
23 #include <dhd_config.h>
24 #include <dhd_dbg.h>
25 #include <wl_android.h>
26
27 static int getUnifyKey(char * inKeyName, unsigned char * outValueBuf, unsigned int inValueBufSize);
28 static int askey_dhd_conf_preinit(struct dhd_conf *conf);
29 static int askey_dhd_conf_read_unifykeys_wifi_disable_5g_band(dhd_pub_t *dhd);
30
31 // kzalloc2getUnifyKey() will return a pointer to a memory allocated by kzalloc().
32 // If the returned pointer is not NULL, remember to kfree the memory.
33 static char * kzalloc2getUnifyKey(char * inKeyName);
34 static int askey_dhd_conf_preinit_by_sn(struct dhd_conf *conf);
35
36 /* message levels */
37 #define CONFIG_ERROR_LEVEL (1 << 0)
38 #define CONFIG_TRACE_LEVEL (1 << 1)
39 #define CONFIG_MSG_LEVEL (1 << 0)
40
41 uint config_msg_level = CONFIG_ERROR_LEVEL | CONFIG_MSG_LEVEL;
42 uint dump_msg_level = 0;
43
44 #define CONFIG_MSG(x, args...) \
45 do { \
46 if (config_msg_level & CONFIG_MSG_LEVEL) { \
47 printk(KERN_ERR "[dhd] %s : " x, __func__, ## args); \
48 } \
49 } while (0)
50 #define CONFIG_ERROR(x, args...) \
51 do { \
52 if (config_msg_level & CONFIG_ERROR_LEVEL) { \
53 printk(KERN_ERR "[dhd] CONFIG-ERROR) %s : " x, __func__, ## args); \
54 } \
55 } while (0)
56 #define CONFIG_TRACE(x, args...) \
57 do { \
58 if (config_msg_level & CONFIG_TRACE_LEVEL) { \
59 printk(KERN_INFO "[dhd] CONFIG-TRACE) %s : " x, __func__, ## args); \
60 } \
61 } while (0)
62
63 #define MAXSZ_BUF 4096
64 #define MAXSZ_CONFIG 8192
65
66 #ifndef WL_CFG80211
67 #define htod32(i) i
68 #define htod16(i) i
69 #define dtoh32(i) i
70 #define dtoh16(i) i
71 #define htodchanspec(i) i
72 #define dtohchanspec(i) i
73 #endif
74
75 #if defined(PROP_TXSTATUS)
76 #include <dhd_wlfc.h>
77 #endif /* PROP_TXSTATUS */
78
79 #define MAX_EVENT_BUF_NUM 16
80 typedef struct eventmsg_buf {
81 u16 num;
82 struct {
83 u16 type;
84 bool set;
85 } event [MAX_EVENT_BUF_NUM];
86 } eventmsg_buf_t;
87
88 typedef struct cihp_name_map_t {
89 uint chip;
90 uint chiprev;
91 uint ag_type;
92 char *chip_name;
93 char *module_name;
94 } cihp_name_map_t;
95
96 /* Map of WLC_E events to connection failure strings */
97 #define DONT_CARE 9999
98 const cihp_name_map_t chip_name_map[] = {
99 /* ChipID Chiprev AG ChipName ModuleName */
100 #ifdef BCMSDIO
101 {BCM43362_CHIP_ID, 0, DONT_CARE, "bcm40181a0", ""},
102 {BCM43362_CHIP_ID, 1, DONT_CARE, "bcm40181a2", ""},
103 {BCM4330_CHIP_ID, 4, FW_TYPE_G, "bcm40183b2", ""},
104 {BCM4330_CHIP_ID, 4, FW_TYPE_AG, "bcm40183b2_ag", ""},
105 {BCM43430_CHIP_ID, 0, DONT_CARE, "bcm43438a0", "ap6212"},
106 {BCM43430_CHIP_ID, 1, DONT_CARE, "bcm43438a1", "ap6212a"},
107 {BCM43430_CHIP_ID, 2, DONT_CARE, "bcm43436b0", "ap6236"},
108 {BCM43012_CHIP_ID, 1, FW_TYPE_G, "bcm43013b0", ""},
109 {BCM43012_CHIP_ID, 1, FW_TYPE_AG, "bcm43013c0_ag", ""},
110 {BCM43012_CHIP_ID, 2, DONT_CARE, "bcm43013c1_ag", ""},
111 {BCM4334_CHIP_ID, 3, DONT_CARE, "bcm4334b1_ag", ""},
112 {BCM43340_CHIP_ID, 2, DONT_CARE, "bcm43341b0_ag", ""},
113 {BCM43341_CHIP_ID, 2, DONT_CARE, "bcm43341b0_ag", ""},
114 {BCM4324_CHIP_ID, 5, DONT_CARE, "bcm43241b4_ag", ""},
115 {BCM4335_CHIP_ID, 2, DONT_CARE, "bcm4339a0_ag", ""},
116 {BCM4339_CHIP_ID, 1, DONT_CARE, "bcm4339a0_ag", "ap6335"},
117 {BCM4345_CHIP_ID, 6, DONT_CARE, "bcm43455c0_ag", "ap6255"},
118 {BCM43454_CHIP_ID, 6, DONT_CARE, "bcm43455c0_ag", ""},
119 {BCM4345_CHIP_ID, 9, DONT_CARE, "bcm43456c5_ag", "ap6256"},
120 {BCM43454_CHIP_ID, 9, DONT_CARE, "bcm43456c5_ag", ""},
121 {BCM4354_CHIP_ID, 1, DONT_CARE, "bcm4354a1_ag", ""},
122 {BCM4354_CHIP_ID, 2, DONT_CARE, "bcm4356a2_ag", "ap6356"},
123 {BCM4356_CHIP_ID, 2, DONT_CARE, "bcm4356a2_ag", ""},
124 {BCM4371_CHIP_ID, 2, DONT_CARE, "bcm4356a2_ag", ""},
125 {BCM43569_CHIP_ID, 3, DONT_CARE, "bcm4358a3_ag", ""},
126 {BCM4359_CHIP_ID, 5, DONT_CARE, "bcm4359b1_ag", ""},
127 {BCM4359_CHIP_ID, 9, DONT_CARE, "bcm4359c0_ag", "ap6398s"},
128 {BCM43751_CHIP_ID, 1, DONT_CARE, "bcm43751a1_ag", ""},
129 {BCM43751_CHIP_ID, 2, DONT_CARE, "bcm43751a2_ag", ""},
130 {BCM43752_CHIP_ID, 1, DONT_CARE, "bcm43752a1_ag", ""},
131 {BCM43752_CHIP_ID, 2, DONT_CARE, "bcm43752a2_ag", ""},
132 #endif
133 #ifdef BCMPCIE
134 {BCM4354_CHIP_ID, 2, DONT_CARE, "bcm4356a2_pcie_ag", ""},
135 {BCM4356_CHIP_ID, 2, DONT_CARE, "bcm4356a2_pcie_ag", ""},
136 {BCM4359_CHIP_ID, 9, DONT_CARE, "bcm4359c0_pcie_ag", ""},
137 {BCM43751_CHIP_ID, 1, DONT_CARE, "bcm43751a1_pcie_ag", ""},
138 {BCM43751_CHIP_ID, 2, DONT_CARE, "bcm43751a2_pcie_ag", ""},
139 {BCM43752_CHIP_ID, 1, DONT_CARE, "bcm43752a1_pcie_ag", ""},
140 {BCM43752_CHIP_ID, 2, DONT_CARE, "bcm43752a2_pcie_ag", ""},
141 #endif
142 #ifdef BCMDBUS
143 {BCM43143_CHIP_ID, 2, DONT_CARE, "bcm43143b0", ""},
144 {BCM43242_CHIP_ID, 1, DONT_CARE, "bcm43242a1_ag", ""},
145 {BCM43569_CHIP_ID, 2, DONT_CARE, "bcm4358u_ag", "ap62x8"},
146 #endif
147 };
148
149 void
150 dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t *chip_nv_list)
151 {
152 CONFIG_TRACE("called\n");
153
154 if (chip_nv_list->m_chip_nv_path_head) {
155 CONFIG_TRACE("Free %p\n", chip_nv_list->m_chip_nv_path_head);
156 kfree(chip_nv_list->m_chip_nv_path_head);
157 }
158 chip_nv_list->count = 0;
159 }
160
161 #ifdef BCMSDIO
162 void
163 dhd_conf_free_mac_list(wl_mac_list_ctrl_t *mac_list)
164 {
165 int i;
166
167 CONFIG_TRACE("called\n");
168 if (mac_list->m_mac_list_head) {
169 for (i=0; i<mac_list->count; i++) {
170 if (mac_list->m_mac_list_head[i].mac) {
171 CONFIG_TRACE("Free mac %p\n", mac_list->m_mac_list_head[i].mac);
172 kfree(mac_list->m_mac_list_head[i].mac);
173 }
174 }
175 CONFIG_TRACE("Free m_mac_list_head %p\n", mac_list->m_mac_list_head);
176 kfree(mac_list->m_mac_list_head);
177 }
178 mac_list->count = 0;
179 }
180
181 #if defined(HW_OOB) || defined(FORCE_WOWLAN)
182 void
183 dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, struct si_pub *sih)
184 {
185 uint32 gpiocontrol, addr;
186
187 if (CHIPID(sih->chip) == BCM43362_CHIP_ID) {
188 CONFIG_MSG("Enable HW OOB for 43362\n");
189 addr = SI_ENUM_BASE(sih) + OFFSETOF(chipcregs_t, gpiocontrol);
190 gpiocontrol = bcmsdh_reg_read(sdh, addr, 4);
191 gpiocontrol |= 0x2;
192 bcmsdh_reg_write(sdh, addr, 4, gpiocontrol);
193 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL);
194 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL);
195 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL);
196 }
197 }
198 #endif
199
200 #define SBSDIO_CIS_SIZE_LIMIT 0x200
201 void
202 dhd_conf_get_otp(dhd_pub_t *dhd, bcmsdh_info_t *sdh, si_t *sih)
203 {
204 int i, err = -1;
205 uint8 *ptr = 0, *ptpl_code = NULL;
206 unsigned char tpl_code, tpl_link='\0';
207 uint8 mac_header[3] = {0x80, 0x07, 0x19};
208 uint8 *cis;
209
210 if (!(cis = MALLOC(dhd->osh, SBSDIO_CIS_SIZE_LIMIT))) {
211 CONFIG_ERROR("cis malloc failed\n");
212 }
213 bzero(cis, SBSDIO_CIS_SIZE_LIMIT);
214
215 if ((err = bcmsdh_cis_read(sdh, 0, cis, SBSDIO_CIS_SIZE_LIMIT))) {
216 CONFIG_ERROR("cis read err %d\n", err);
217 MFREE(dhd->osh, cis, SBSDIO_CIS_SIZE_LIMIT);
218 return;
219 }
220 ptr = cis;
221 do {
222 /* 0xff means we're done */
223 tpl_code = *ptr;
224 ptpl_code = ptr;
225 ptr++;
226 if (tpl_code == 0xff)
227 break;
228
229 /* null entries have no link field or data */
230 if (tpl_code == 0x00)
231 continue;
232
233 tpl_link = *ptr;
234 ptr++;
235 /* a size of 0xff also means we're done */
236 if (tpl_link == 0xff)
237 break;
238 if (config_msg_level & CONFIG_TRACE_LEVEL) {
239 prhex("TPL", ptpl_code, tpl_link+2);
240 }
241
242 if (tpl_code == 0x80 && tpl_link == 0x07 && *ptr == 0x19) {
243 memcpy(&dhd->conf->otp_mac, ptr+1, 6);
244 }
245 #ifdef GET_OTP_MODULE_NAME
246 else if (tpl_code == 0x8e && *ptr == 0x41) {
247 int len = tpl_link - 1;
248 if (len <= sizeof(dhd->conf->module_name) - 1) {
249 strncpy(dhd->conf->module_name, ptr+1, len);
250 CONFIG_MSG("module_name=%s\n", dhd->conf->module_name);
251 } else {
252 CONFIG_ERROR("len is too long %d >= %d\n",
253 len, (int)sizeof(dhd->conf->module_name) - 1);
254 }
255 }
256 #endif
257
258 ptr += tpl_link;
259 } while (1);
260
261 if (!memcmp(&ether_null, &dhd->conf->otp_mac, ETHER_ADDR_LEN)) {
262 ptr = cis;
263 /* Special OTP */
264 if (bcmsdh_reg_read(sdh, SI_ENUM_BASE(sih), 4) == 0x16044330) {
265 for (i=0; i<SBSDIO_CIS_SIZE_LIMIT; i++) {
266 if (!memcmp(mac_header, ptr, 3)) {
267 memcpy(&dhd->conf->otp_mac, ptr+3, 6);
268 break;
269 }
270 ptr++;
271 }
272 }
273 }
274
275 ASSERT(cis);
276 MFREE(dhd->osh, cis, SBSDIO_CIS_SIZE_LIMIT);
277 }
278
279 void
280 dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, char *fw_path)
281 {
282 int i, j;
283 uint8 *mac = (uint8 *)&dhd->conf->otp_mac;
284 int fw_num=0, mac_num=0;
285 uint32 oui, nic;
286 wl_mac_list_t *mac_list;
287 wl_mac_range_t *mac_range;
288 int fw_type, fw_type_new;
289 char *name_ptr;
290
291 mac_list = dhd->conf->fw_by_mac.m_mac_list_head;
292 fw_num = dhd->conf->fw_by_mac.count;
293 if (!mac_list || !fw_num)
294 return;
295
296 oui = (mac[0] << 16) | (mac[1] << 8) | (mac[2]);
297 nic = (mac[3] << 16) | (mac[4] << 8) | (mac[5]);
298
299 /* find out the last '/' */
300 i = strlen(fw_path);
301 while (i > 0) {
302 if (fw_path[i] == '/') {
303 i++;
304 break;
305 }
306 i--;
307 }
308 name_ptr = &fw_path[i];
309
310 if (strstr(name_ptr, "_apsta"))
311 fw_type = FW_TYPE_APSTA;
312 else if (strstr(name_ptr, "_p2p"))
313 fw_type = FW_TYPE_P2P;
314 else if (strstr(name_ptr, "_mesh"))
315 fw_type = FW_TYPE_MESH;
316 else if (strstr(name_ptr, "_es"))
317 fw_type = FW_TYPE_ES;
318 else if (strstr(name_ptr, "_mfg"))
319 fw_type = FW_TYPE_MFG;
320 else
321 fw_type = FW_TYPE_STA;
322
323 for (i=0; i<fw_num; i++) {
324 mac_num = mac_list[i].count;
325 mac_range = mac_list[i].mac;
326 if (strstr(mac_list[i].name, "_apsta"))
327 fw_type_new = FW_TYPE_APSTA;
328 else if (strstr(mac_list[i].name, "_p2p"))
329 fw_type_new = FW_TYPE_P2P;
330 else if (strstr(mac_list[i].name, "_mesh"))
331 fw_type_new = FW_TYPE_MESH;
332 else if (strstr(mac_list[i].name, "_es"))
333 fw_type_new = FW_TYPE_ES;
334 else if (strstr(mac_list[i].name, "_mfg"))
335 fw_type_new = FW_TYPE_MFG;
336 else
337 fw_type_new = FW_TYPE_STA;
338 if (fw_type != fw_type_new) {
339 CONFIG_MSG("fw_typ=%d != fw_type_new=%d\n", fw_type, fw_type_new);
340 continue;
341 }
342 for (j=0; j<mac_num; j++) {
343 if (oui == mac_range[j].oui) {
344 if (nic >= mac_range[j].nic_start && nic <= mac_range[j].nic_end) {
345 strcpy(name_ptr, mac_list[i].name);
346 CONFIG_MSG("matched oui=0x%06X, nic=0x%06X\n", oui, nic);
347 CONFIG_MSG("fw_path=%s\n", fw_path);
348 return;
349 }
350 }
351 }
352 }
353 }
354
355 void
356 dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, char *nv_path)
357 {
358 int i, j;
359 uint8 *mac = (uint8 *)&dhd->conf->otp_mac;
360 int nv_num=0, mac_num=0;
361 uint32 oui, nic;
362 wl_mac_list_t *mac_list;
363 wl_mac_range_t *mac_range;
364 char *pnv_name;
365
366 mac_list = dhd->conf->nv_by_mac.m_mac_list_head;
367 nv_num = dhd->conf->nv_by_mac.count;
368 if (!mac_list || !nv_num)
369 return;
370
371 oui = (mac[0] << 16) | (mac[1] << 8) | (mac[2]);
372 nic = (mac[3] << 16) | (mac[4] << 8) | (mac[5]);
373
374 /* find out the last '/' */
375 i = strlen(nv_path);
376 while (i > 0) {
377 if (nv_path[i] == '/') break;
378 i--;
379 }
380 pnv_name = &nv_path[i+1];
381
382 for (i=0; i<nv_num; i++) {
383 mac_num = mac_list[i].count;
384 mac_range = mac_list[i].mac;
385 for (j=0; j<mac_num; j++) {
386 if (oui == mac_range[j].oui) {
387 if (nic >= mac_range[j].nic_start && nic <= mac_range[j].nic_end) {
388 strcpy(pnv_name, mac_list[i].name);
389 CONFIG_MSG("matched oui=0x%06X, nic=0x%06X\n", oui, nic);
390 CONFIG_MSG("nv_path=%s\n", nv_path);
391 return;
392 }
393 }
394 }
395 }
396 }
397 #endif
398
399 void
400 dhd_conf_free_country_list(struct dhd_conf *conf)
401 {
402 country_list_t *country = conf->country_head;
403 int count = 0;
404
405 CONFIG_TRACE("called\n");
406 while (country) {
407 CONFIG_TRACE("Free cspec %s\n", country->cspec.country_abbrev);
408 conf->country_head = country->next;
409 kfree(country);
410 country = conf->country_head;
411 count++;
412 }
413 CONFIG_TRACE("%d country released\n", count);
414 }
415
416 void
417 dhd_conf_free_mchan_list(struct dhd_conf *conf)
418 {
419 mchan_params_t *mchan = conf->mchan;
420 int count = 0;
421
422 CONFIG_TRACE("called\n");
423 while (mchan) {
424 CONFIG_TRACE("Free cspec %p\n", mchan);
425 conf->mchan = mchan->next;
426 kfree(mchan);
427 mchan = conf->mchan;
428 count++;
429 }
430 CONFIG_TRACE("%d mchan released\n", count);
431 }
432
433 int
434 dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
435 {
436 int fw_type, ag_type;
437 uint chip, chiprev;
438 int i;
439 char *name_ptr;
440
441 chip = dhd->conf->chip;
442 chiprev = dhd->conf->chiprev;
443
444 if (fw_path[0] == '\0') {
445 #ifdef CONFIG_BCMDHD_FW_PATH
446 bcm_strncpy_s(fw_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1);
447 if (fw_path[0] == '\0')
448 #endif
449 {
450 CONFIG_MSG("firmware path is null\n");
451 return 0;
452 }
453 }
454 #ifndef FW_PATH_AUTO_SELECT
455 return DONT_CARE;
456 #endif
457
458 /* find out the last '/' */
459 i = strlen(fw_path);
460 while (i > 0) {
461 if (fw_path[i] == '/') {
462 i++;
463 break;
464 }
465 i--;
466 }
467 name_ptr = &fw_path[i];
468 #ifdef BAND_AG
469 ag_type = FW_TYPE_AG;
470 #else
471 ag_type = strstr(name_ptr, "_ag") ? FW_TYPE_AG : FW_TYPE_G;
472 #endif
473 if (strstr(name_ptr, "_apsta"))
474 fw_type = FW_TYPE_APSTA;
475 else if (strstr(name_ptr, "_p2p"))
476 fw_type = FW_TYPE_P2P;
477 else if (strstr(name_ptr, "_mesh"))
478 fw_type = FW_TYPE_MESH;
479 else if (strstr(name_ptr, "_es"))
480 fw_type = FW_TYPE_ES;
481 else if (strstr(name_ptr, "_mfg"))
482 fw_type = FW_TYPE_MFG;
483 else if (strstr(name_ptr, "_minime"))
484 fw_type = FW_TYPE_MINIME;
485 else
486 fw_type = FW_TYPE_STA;
487
488 for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) {
489 const cihp_name_map_t* row = &chip_name_map[i];
490 if (row->chip == chip && row->chiprev == chiprev &&
491 (row->ag_type == ag_type || row->ag_type == DONT_CARE)) {
492 strcpy(name_ptr, "fw_");
493 strcat(fw_path, row->chip_name);
494 #ifdef BCMUSBDEV_COMPOSITE
495 strcat(fw_path, "_cusb");
496 #endif
497 if (fw_type == FW_TYPE_APSTA)
498 strcat(fw_path, "_apsta.bin");
499 else if (fw_type == FW_TYPE_P2P)
500 strcat(fw_path, "_p2p.bin");
501 else if (fw_type == FW_TYPE_MESH)
502 strcat(fw_path, "_mesh.bin");
503 else if (fw_type == FW_TYPE_ES)
504 strcat(fw_path, "_es.bin");
505 else if (fw_type == FW_TYPE_MFG)
506 strcat(fw_path, "_mfg.bin");
507 else if (fw_type == FW_TYPE_MINIME)
508 strcat(fw_path, "_minime.bin");
509 else
510 strcat(fw_path, ".bin");
511 }
512 }
513
514 dhd->conf->fw_type = fw_type;
515
516 #ifndef MINIME
517 if (fw_type == FW_TYPE_MINIME)
518 CONFIG_ERROR("***** Please enable MINIME in Makefile *****\n");
519 #endif
520
521 CONFIG_TRACE("firmware_path=%s\n", fw_path);
522 return ag_type;
523 }
524
525 void
526 dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type)
527 {
528 uint chip, chiprev;
529 int i;
530 char *name_ptr;
531
532 chip = dhd->conf->chip;
533 chiprev = dhd->conf->chiprev;
534
535 if (clm_path[0] == '\0') {
536 CONFIG_MSG("clm path is null\n");
537 return;
538 }
539
540 /* find out the last '/' */
541 i = strlen(clm_path);
542 while (i > 0) {
543 if (clm_path[i] == '/') {
544 i++;
545 break;
546 }
547 i--;
548 }
549 name_ptr = &clm_path[i];
550
551 for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) {
552 const cihp_name_map_t* row = &chip_name_map[i];
553 if (row->chip == chip && row->chiprev == chiprev &&
554 (row->ag_type == ag_type || row->ag_type == DONT_CARE)) {
555 strcpy(name_ptr, "clm_");
556 strcat(clm_path, row->chip_name);
557 strcat(clm_path, ".blob");
558 }
559 }
560
561 CONFIG_TRACE("clm_path=%s\n", clm_path);
562 }
563
564 void
565 dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type)
566 {
567 uint chip, chiprev;
568 int i;
569 char *name_ptr;
570
571 chip = dhd->conf->chip;
572 chiprev = dhd->conf->chiprev;
573
574 if (nv_path[0] == '\0') {
575 #ifdef CONFIG_BCMDHD_NVRAM_PATH
576 bcm_strncpy_s(nv_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
577 if (nv_path[0] == '\0')
578 #endif
579 {
580 CONFIG_MSG("nvram path is null\n");
581 return;
582 }
583 }
584
585 /* find out the last '/' */
586 i = strlen(nv_path);
587 while (i > 0) {
588 if (nv_path[i] == '/') {
589 i++;
590 break;
591 }
592 i--;
593 }
594 name_ptr = &nv_path[i];
595
596 for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) {
597 const cihp_name_map_t* row = &chip_name_map[i];
598 if (row->chip == chip && row->chiprev == chiprev &&
599 (row->ag_type == ag_type || row->ag_type == DONT_CARE)) {
600 #ifdef GET_OTP_MODULE_NAME
601 if (strlen(dhd->conf->module_name)) {
602 strcpy(name_ptr, "nvram_");
603 strcat(name_ptr, dhd->conf->module_name);
604 } else
605 #endif
606 if (strlen(row->module_name)){
607 strcpy(name_ptr, "nvram_");
608 strcat(name_ptr, row->module_name);
609 } else
610 continue;
611 #ifdef BCMUSBDEV_COMPOSITE
612 strcat(name_ptr, "_cusb");
613 #endif
614 strcat(name_ptr, ".txt");
615 }
616 }
617
618 for (i=0; i<dhd->conf->nv_by_chip.count; i++) {
619 if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip &&
620 chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) {
621 strcpy(name_ptr, dhd->conf->nv_by_chip.m_chip_nv_path_head[i].name);
622 break;
623 }
624 }
625
626 CONFIG_TRACE("nvram_path=%s\n", nv_path);
627 }
628
629 void
630 dhd_conf_copy_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path)
631 {
632 int i;
633
634 if (src_path[0] == '\0') {
635 CONFIG_MSG("src_path is null\n");
636 return;
637 } else
638 strcpy(dst_path, src_path);
639
640 /* find out the last '/' */
641 i = strlen(dst_path);
642 while (i > 0) {
643 if (dst_path[i] == '/') {
644 i++;
645 break;
646 }
647 i--;
648 }
649 strcpy(&dst_path[i], dst_name);
650
651 CONFIG_TRACE("dst_path=%s\n", dst_path);
652 }
653
654 #ifdef CONFIG_PATH_AUTO_SELECT
655 void
656 dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
657 {
658 uint chip, chiprev;
659 int i;
660 char *name_ptr;
661
662 chip = dhd->conf->chip;
663 chiprev = dhd->conf->chiprev;
664
665 if (conf_path[0] == '\0') {
666 CONFIG_MSG("config path is null\n");
667 return;
668 }
669
670 /* find out the last '/' */
671 i = strlen(conf_path);
672 while (i > 0) {
673 if (conf_path[i] == '/') {
674 i++;
675 break;
676 }
677 i--;
678 }
679 name_ptr = &conf_path[i];
680
681 for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) {
682 const cihp_name_map_t* row = &chip_name_map[i];
683 if (row->chip == chip && row->chiprev == chiprev) {
684 strcpy(name_ptr, "config_");
685 strcat(conf_path, row->chip_name);
686 strcat(conf_path, ".txt");
687 }
688 }
689
690 CONFIG_TRACE("config_path=%s\n", conf_path);
691 }
692 #endif
693
694 void
695 dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path)
696 {
697 int ag_type;
698
699 /* External conf takes precedence if specified */
700 dhd_conf_preinit(dhd);
701
702 if (dhd->conf_path[0] == '\0') {
703 dhd_conf_copy_path(dhd, "config.txt", dhd->conf_path, nv_path);
704 }
705 if (dhd->clm_path[0] == '\0') {
706 dhd_conf_copy_path(dhd, "clm.blob", dhd->clm_path, fw_path);
707 }
708 #ifdef CONFIG_PATH_AUTO_SELECT
709 dhd_conf_set_conf_name_by_chip(dhd, dhd->conf_path);
710 #endif
711
712 dhd_conf_read_config(dhd, dhd->conf_path);
713
714 ag_type = dhd_conf_set_fw_name_by_chip(dhd, fw_path);
715 dhd_conf_set_nv_name_by_chip(dhd, nv_path, ag_type);
716 dhd_conf_set_clm_name_by_chip(dhd, dhd->clm_path, ag_type);
717 #ifdef BCMSDIO
718 dhd_conf_set_fw_name_by_mac(dhd, fw_path);
719 dhd_conf_set_nv_name_by_mac(dhd, nv_path);
720 #endif
721
722 CONFIG_MSG("Final fw_path=%s\n", fw_path);
723 CONFIG_MSG("Final nv_path=%s\n", nv_path);
724 CONFIG_MSG("Final clm_path=%s\n", dhd->clm_path);
725 CONFIG_MSG("Final conf_path=%s\n", dhd->conf_path);
726 }
727
728 int
729 dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val,
730 int def, bool down)
731 {
732 int ret = -1;
733 char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
734
735 if (val >= def) {
736 if (down) {
737 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
738 CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret);
739 }
740 if (cmd == WLC_SET_VAR) {
741 CONFIG_TRACE("set %s %d\n", name, val);
742 bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf));
743 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
744 CONFIG_ERROR("%s setting failed %d\n", name, ret);
745 } else {
746 CONFIG_TRACE("set %s %d %d\n", name, cmd, val);
747 if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0)
748 CONFIG_ERROR("%s setting failed %d\n", name, ret);
749 }
750 }
751
752 return ret;
753 }
754
755 int
756 dhd_conf_set_bufiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name,
757 char *buf, int len, bool down)
758 {
759 char iovbuf[WLC_IOCTL_SMLEN];
760 s32 iovar_len;
761 int ret = -1;
762
763 if (down) {
764 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, ifidx)) < 0)
765 CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret);
766 }
767
768 if (cmd == WLC_SET_VAR) {
769 iovar_len = bcm_mkiovar(name, buf, len, iovbuf, sizeof(iovbuf));
770 if (iovar_len > 0)
771 ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, iovar_len, TRUE, ifidx);
772 else
773 ret = BCME_BUFTOOSHORT;
774 if (ret < 0)
775 CONFIG_ERROR("%s setting failed %d, len=%d\n", name, ret, len);
776 } else {
777 if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, TRUE, ifidx)) < 0)
778 CONFIG_ERROR("%s setting failed %d\n", name, ret);
779 }
780
781 return ret;
782 }
783
784 int
785 dhd_conf_get_iovar(dhd_pub_t *dhd, int ifidx, int cmd, char *name,
786 char *buf, int len)
787 {
788 char iovbuf[WLC_IOCTL_SMLEN];
789 int ret = -1;
790
791 if (cmd == WLC_GET_VAR) {
792 if (bcm_mkiovar(name, NULL, 0, iovbuf, sizeof(iovbuf))) {
793 ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, sizeof(iovbuf), FALSE, ifidx);
794 if (!ret) {
795 memcpy(buf, iovbuf, len);
796 } else {
797 CONFIG_ERROR("get iovar %s failed %d\n", name, ret);
798 }
799 } else {
800 CONFIG_ERROR("mkiovar %s failed\n", name);
801 }
802 } else {
803 ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, FALSE, 0);
804 if (ret < 0)
805 CONFIG_ERROR("get iovar %s failed %d\n", name, ret);
806 }
807
808 return ret;
809 }
810
811 static int
812 dhd_conf_rsdb_mode(dhd_pub_t *dhd, char *buf)
813 {
814 wl_config_t rsdb_mode_cfg = {1, 0};
815
816 if (buf) {
817 rsdb_mode_cfg.config = (int)simple_strtol(buf, NULL, 0);
818 CONFIG_MSG("rsdb_mode %d\n", rsdb_mode_cfg.config);
819 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "rsdb_mode", (char *)&rsdb_mode_cfg,
820 sizeof(rsdb_mode_cfg), TRUE);
821 }
822
823 return 0;
824 }
825
826 typedef struct sub_cmd_t {
827 char *name;
828 uint16 id; /* id for the dongle f/w switch/case */
829 uint16 type; /* base type of argument IOVT_XXXX */
830 } sub_cmd_t;
831
832 /* wl he sub cmd list */
833 static const sub_cmd_t he_cmd_list[] = {
834 {"enab", WL_HE_CMD_ENAB, IOVT_UINT8},
835 {"features", WL_HE_CMD_FEATURES, IOVT_UINT32},
836 {"bsscolor", WL_HE_CMD_BSSCOLOR, IOVT_UINT8},
837 {"partialbsscolor", WL_HE_CMD_PARTIAL_BSSCOLOR, IOVT_UINT8},
838 {"cap", WL_HE_CMD_CAP, IOVT_UINT8},
839 {"staid", WL_HE_CMD_STAID, IOVT_UINT16},
840 {"rtsdurthresh", WL_HE_CMD_RTSDURTHRESH, IOVT_UINT16},
841 {"peduration", WL_HE_CMD_PEDURATION, IOVT_UINT8},
842 {"testbed_mode", WL_HE_CMD_TESTBED_MODE, IOVT_UINT32},
843 {"omi_ulmu_throttle", WL_HE_CMD_OMI_ULMU_THROTTLE, IOVT_UINT16},
844 {"omi_dlmu_rr_mpf_map", WL_HE_CMD_OMI_DLMU_RSD_RCM_MPF_MAP, IOVT_UINT32},
845 {"ulmu_disable_policy", WL_HE_CMD_ULMU_DISABLE_POLICY, IOVT_UINT8},
846 {"sr_prohibit", WL_HE_CMD_SR_PROHIBIT, IOVT_UINT8},
847 };
848
849 static uint
850 wl_he_iovt2len(uint iovt)
851 {
852 switch (iovt) {
853 case IOVT_BOOL:
854 case IOVT_INT8:
855 case IOVT_UINT8:
856 return sizeof(uint8);
857 case IOVT_INT16:
858 case IOVT_UINT16:
859 return sizeof(uint16);
860 case IOVT_INT32:
861 case IOVT_UINT32:
862 return sizeof(uint32);
863 default:
864 /* ASSERT(0); */
865 return 0;
866 }
867 }
868
869 static int
870 dhd_conf_he_cmd(dhd_pub_t * dhd, char *buf)
871 {
872 int ret = BCME_OK, i;
873 bcm_xtlv_t *pxtlv = NULL;
874 uint8 mybuf[128];
875 uint16 he_id = -1, he_len = 0, mybuf_len = sizeof(mybuf);
876 uint32 he_val;
877 const sub_cmd_t *tpl = he_cmd_list;
878 char sub_cmd[32], he_val_str[10];
879
880 if (buf) {
881 sscanf(buf, "%s %s", sub_cmd, he_val_str);
882 }
883
884 for (i=0; i<ARRAY_SIZE(he_cmd_list); i++, tpl++) {
885 if (!strcmp(tpl->name, sub_cmd)) {
886 he_id = tpl->id;
887 he_len = wl_he_iovt2len(tpl->type);
888 break;
889 }
890 }
891 if (he_id < 0) {
892 CONFIG_ERROR("No he id found for %s\n", sub_cmd);
893 return 0;
894 }
895
896 pxtlv = (bcm_xtlv_t *)mybuf;
897
898 if (strlen(he_val_str)) {
899 he_val = simple_strtol(he_val_str, NULL, 0);
900 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &mybuf_len, he_id,
901 he_len, (uint8 *)&he_val, BCM_XTLV_OPTION_ALIGN32);
902 if (ret != BCME_OK) {
903 CONFIG_ERROR("failed to pack he enab, err: %s\n", bcmerrorstr(ret));
904 return 0;
905 }
906 CONFIG_MSG("he %s 0x%x\n", sub_cmd, he_val);
907 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "he", (char *)&mybuf,
908 sizeof(mybuf), TRUE);
909 }
910
911 return 0;
912 }
913
914 typedef int (tpl_parse_t)(dhd_pub_t *dhd, char *buf);
915
916 typedef struct iovar_tpl_t {
917 int cmd;
918 char *name;
919 tpl_parse_t *parse;
920 } iovar_tpl_t;
921
922 const iovar_tpl_t iovar_tpl_list[] = {
923 {WLC_SET_VAR, "rsdb_mode", dhd_conf_rsdb_mode},
924 {WLC_SET_VAR, "he", dhd_conf_he_cmd},
925 };
926
927 static int iovar_tpl_parse(const iovar_tpl_t *tpl, int tpl_count,
928 dhd_pub_t *dhd, int cmd, char *name, char *buf)
929 {
930 int i, ret = 0;
931
932 /* look for a matching code in the table */
933 for (i = 0; i < tpl_count; i++, tpl++) {
934 if (tpl->cmd == cmd && !strcmp(tpl->name, name))
935 break;
936 }
937 if (i < tpl_count && tpl->parse) {
938 ret = tpl->parse(dhd, buf);
939 } else {
940 ret = -1;
941 }
942
943 return ret;
944 }
945
946 bool
947 dhd_conf_set_wl_cmd(dhd_pub_t *dhd, char *data, bool down)
948 {
949 int cmd, val, ret = 0, len;
950 char name[32], *pch, *pick_tmp, *pick_tmp2, *pdata = NULL;
951
952 /* Process wl_preinit:
953 * wl_preinit=[cmd]=[val], [cmd]=[val]
954 * Ex: wl_preinit=86=0, mpc=0
955 */
956
957 if (data == NULL)
958 return FALSE;
959
960 len = strlen(data);
961 pdata = kmalloc(len+1, GFP_KERNEL);
962 if (pdata == NULL) {
963 CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", len+1);
964 goto exit;
965 }
966 memset(pdata, 0, len+1);
967 strcpy(pdata, data);
968
969 pick_tmp = pdata;
970 while (pick_tmp && (pick_tmp2 = bcmstrtok(&pick_tmp, ",", 0)) != NULL) {
971 pch = bcmstrtok(&pick_tmp2, "=", 0);
972 if (!pch)
973 break;
974 if (*pch == ' ') {
975 pch++;
976 }
977 memset(name, 0 , sizeof (name));
978 cmd = (int)simple_strtol(pch, NULL, 0);
979 if (cmd == 0) {
980 cmd = WLC_SET_VAR;
981 strcpy(name, pch);
982 }
983 pch = bcmstrtok(&pick_tmp2, ",", 0);
984 if (!pch) {
985 break;
986 }
987 ret = iovar_tpl_parse(iovar_tpl_list, ARRAY_SIZE(iovar_tpl_list),
988 dhd, cmd, name, pch);
989 if (ret) {
990 val = (int)simple_strtol(pch, NULL, 0);
991 dhd_conf_set_intiovar(dhd, cmd, name, val, -1, down);
992 }
993 }
994
995 exit:
996 if (pdata)
997 kfree(pdata);
998 return true;
999 }
1000
1001 int
1002 dhd_conf_get_band(dhd_pub_t *dhd)
1003 {
1004 int band = -1;
1005
1006 if (dhd && dhd->conf)
1007 band = dhd->conf->band;
1008 else
1009 CONFIG_ERROR("dhd or conf is NULL\n");
1010
1011 return band;
1012 }
1013
1014 int
1015 dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec)
1016 {
1017 int bcmerror = -1;
1018
1019 memset(cspec, 0, sizeof(wl_country_t));
1020 bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t));
1021 if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t),
1022 FALSE, 0)) < 0)
1023 CONFIG_ERROR("country code getting failed %d\n", bcmerror);
1024
1025 return bcmerror;
1026 }
1027
1028 int
1029 dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec)
1030 {
1031 int bcmerror = -1;
1032 struct dhd_conf *conf = dhd->conf;
1033 country_list_t *country = conf->country_head;
1034
1035 #ifdef CCODE_LIST
1036 bcmerror = dhd_ccode_map_country_list(dhd, cspec);
1037 #endif
1038
1039 while (country != NULL) {
1040 if (!strncmp("**", country->cspec.country_abbrev, 2)) {
1041 memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ);
1042 cspec->rev = country->cspec.rev;
1043 bcmerror = 0;
1044 break;
1045 } else if (!strncmp(cspec->country_abbrev,
1046 country->cspec.country_abbrev, 2)) {
1047 memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ);
1048 cspec->rev = country->cspec.rev;
1049 bcmerror = 0;
1050 break;
1051 }
1052 country = country->next;
1053 }
1054
1055 if (!bcmerror)
1056 CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev);
1057
1058 return bcmerror;
1059 }
1060
1061 int
1062 dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec)
1063 {
1064 int bcmerror = -1;
1065
1066 memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t));
1067
1068 CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev);
1069 bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec,
1070 sizeof(wl_country_t), FALSE);
1071 dhd_conf_get_country(dhd, cspec);
1072 CONFIG_MSG("Country code: %s (%s/%d)\n",
1073 cspec->country_abbrev, cspec->ccode, cspec->rev);
1074
1075 return bcmerror;
1076 }
1077
1078 int
1079 dhd_conf_fix_country(dhd_pub_t *dhd)
1080 {
1081 int bcmerror = -1;
1082 int band;
1083 wl_uint32_list_t *list;
1084 u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
1085 wl_country_t cspec;
1086
1087 if (!(dhd && dhd->conf)) {
1088 return bcmerror;
1089 }
1090
1091 memset(valid_chan_list, 0, sizeof(valid_chan_list));
1092 list = (wl_uint32_list_t *)(void *) valid_chan_list;
1093 list->count = htod32(WL_NUMCHANNELS);
1094 if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list,
1095 sizeof(valid_chan_list), FALSE, 0)) < 0) {
1096 CONFIG_ERROR("get channels failed with %d\n", bcmerror);
1097 }
1098
1099 band = dhd_conf_get_band(dhd);
1100
1101 if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) &&
1102 dtoh32(list->count)<11)) {
1103 CONFIG_ERROR("bcmerror=%d, # of channels %d\n",
1104 bcmerror, dtoh32(list->count));
1105 dhd_conf_map_country_list(dhd, &dhd->conf->cspec);
1106 if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) {
1107 strcpy(cspec.country_abbrev, "US");
1108 cspec.rev = 0;
1109 strcpy(cspec.ccode, "US");
1110 dhd_conf_map_country_list(dhd, &cspec);
1111 dhd_conf_set_country(dhd, &cspec);
1112 }
1113 }
1114
1115 return bcmerror;
1116 }
1117
1118 bool
1119 dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel)
1120 {
1121 int i;
1122 bool match = false;
1123
1124 if (dhd && dhd->conf) {
1125 if (dhd->conf->channels.count == 0)
1126 return true;
1127 for (i=0; i<dhd->conf->channels.count; i++) {
1128 if (channel == dhd->conf->channels.channel[i])
1129 match = true;
1130 }
1131 } else {
1132 match = true;
1133 CONFIG_ERROR("dhd or conf is NULL\n");
1134 }
1135
1136 return match;
1137 }
1138
1139 int
1140 dhd_conf_set_roam(dhd_pub_t *dhd)
1141 {
1142 int bcmerror = -1;
1143 struct dhd_conf *conf = dhd->conf;
1144
1145 dhd_roam_disable = conf->roam_off;
1146 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE);
1147
1148 if (!conf->roam_off || !conf->roam_off_suspend) {
1149 CONFIG_MSG("set roam_trigger %d\n", conf->roam_trigger[0]);
1150 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER",
1151 (char *)conf->roam_trigger, sizeof(conf->roam_trigger), FALSE);
1152
1153 CONFIG_MSG("set roam_scan_period %d\n", conf->roam_scan_period[0]);
1154 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD",
1155 (char *)conf->roam_scan_period, sizeof(conf->roam_scan_period), FALSE);
1156
1157 CONFIG_MSG("set roam_delta %d\n", conf->roam_delta[0]);
1158 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA",
1159 (char *)conf->roam_delta, sizeof(conf->roam_delta), FALSE);
1160
1161 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "fullroamperiod",
1162 dhd->conf->fullroamperiod, 1, FALSE);
1163 }
1164
1165 return bcmerror;
1166 }
1167
1168 void
1169 dhd_conf_add_to_eventbuffer(struct eventmsg_buf *ev, u16 event, bool set)
1170 {
1171 if (!ev || (event > WLC_E_LAST))
1172 return;
1173
1174 if (ev->num < MAX_EVENT_BUF_NUM) {
1175 ev->event[ev->num].type = event;
1176 ev->event[ev->num].set = set;
1177 ev->num++;
1178 } else {
1179 CONFIG_ERROR("evenbuffer doesn't support > %u events. Update"
1180 " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM);
1181 ASSERT(0);
1182 }
1183 }
1184
1185 s32
1186 dhd_conf_apply_eventbuffer(dhd_pub_t *dhd, eventmsg_buf_t *ev)
1187 {
1188 char eventmask[WL_EVENTING_MASK_LEN];
1189 int i, ret = 0;
1190
1191 if (!ev || (!ev->num))
1192 return -EINVAL;
1193
1194 /* Read event_msgs mask */
1195 ret = dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "event_msgs", eventmask,
1196 sizeof(eventmask));
1197 if (unlikely(ret)) {
1198 CONFIG_ERROR("Get event_msgs error (%d)\n", ret);
1199 goto exit;
1200 }
1201
1202 /* apply the set bits */
1203 for (i = 0; i < ev->num; i++) {
1204 if (ev->event[i].set)
1205 setbit(eventmask, ev->event[i].type);
1206 else
1207 clrbit(eventmask, ev->event[i].type);
1208 }
1209
1210 /* Write updated Event mask */
1211 ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs", eventmask,
1212 sizeof(eventmask), FALSE);
1213 if (unlikely(ret)) {
1214 CONFIG_ERROR("Set event_msgs error (%d)\n", ret);
1215 }
1216
1217 exit:
1218 return ret;
1219 }
1220
1221 int
1222 dhd_conf_enable_roam_offload(dhd_pub_t *dhd, int enable)
1223 {
1224 int err;
1225 eventmsg_buf_t ev_buf;
1226
1227 if (dhd->conf->roam_off_suspend)
1228 return 0;
1229
1230 err = dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_offload", enable, 0, FALSE);
1231 if (err)
1232 return err;
1233
1234 bzero(&ev_buf, sizeof(eventmsg_buf_t));
1235 dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
1236 dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
1237 dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
1238 dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
1239 dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
1240 dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
1241 err = dhd_conf_apply_eventbuffer(dhd, &ev_buf);
1242
1243 CONFIG_TRACE("roam_offload %d\n", enable);
1244
1245 return err;
1246 }
1247
1248 void
1249 dhd_conf_set_bw_cap(dhd_pub_t *dhd)
1250 {
1251 struct {
1252 u32 band;
1253 u32 bw_cap;
1254 } param = {0, 0};
1255
1256 if (dhd->conf->bw_cap[0] >= 0) {
1257 memset(&param, 0, sizeof(param));
1258 param.band = WLC_BAND_2G;
1259 param.bw_cap = (uint)dhd->conf->bw_cap[0];
1260 CONFIG_MSG("set bw_cap 2g 0x%x\n", param.bw_cap);
1261 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "bw_cap", (char *)&param,
1262 sizeof(param), TRUE);
1263 }
1264
1265 if (dhd->conf->bw_cap[1] >= 0) {
1266 memset(&param, 0, sizeof(param));
1267 param.band = WLC_BAND_5G;
1268 param.bw_cap = (uint)dhd->conf->bw_cap[1];
1269 CONFIG_MSG("set bw_cap 5g 0x%x\n", param.bw_cap);
1270 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "bw_cap", (char *)&param,
1271 sizeof(param), TRUE);
1272 }
1273 }
1274
1275 void
1276 dhd_conf_get_wme(dhd_pub_t *dhd, int ifidx, int mode, edcf_acparam_t *acp)
1277 {
1278 int bcmerror = -1;
1279 char iovbuf[WLC_IOCTL_SMLEN];
1280 edcf_acparam_t *acparam;
1281
1282 bzero(iovbuf, sizeof(iovbuf));
1283
1284 /*
1285 * Get current acparams, using buf as an input buffer.
1286 * Return data is array of 4 ACs of wme params.
1287 */
1288 if (mode == 0)
1289 bcm_mkiovar("wme_ac_sta", NULL, 0, iovbuf, sizeof(iovbuf));
1290 else
1291 bcm_mkiovar("wme_ac_ap", NULL, 0, iovbuf, sizeof(iovbuf));
1292 if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf),
1293 FALSE, ifidx)) < 0) {
1294 CONFIG_ERROR("wme_ac_sta getting failed %d\n", bcmerror);
1295 return;
1296 }
1297 memcpy((char*)acp, iovbuf, sizeof(edcf_acparam_t)*AC_COUNT);
1298
1299 acparam = &acp[AC_BK];
1300 CONFIG_TRACE("BK: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
1301 acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
1302 acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
1303 acparam->TXOP);
1304 acparam = &acp[AC_BE];
1305 CONFIG_TRACE("BE: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
1306 acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
1307 acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
1308 acparam->TXOP);
1309 acparam = &acp[AC_VI];
1310 CONFIG_TRACE("VI: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
1311 acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
1312 acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
1313 acparam->TXOP);
1314 acparam = &acp[AC_VO];
1315 CONFIG_TRACE("VO: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
1316 acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
1317 acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
1318 acparam->TXOP);
1319
1320 return;
1321 }
1322
1323 void
1324 dhd_conf_update_wme(dhd_pub_t *dhd, int ifidx, int mode,
1325 edcf_acparam_t *acparam_cur, int aci)
1326 {
1327 int aifsn, ecwmin, ecwmax, txop;
1328 edcf_acparam_t *acp;
1329 struct dhd_conf *conf = dhd->conf;
1330 wme_param_t *wme;
1331
1332 if (mode == 0)
1333 wme = &conf->wme_sta;
1334 else
1335 wme = &conf->wme_ap;
1336
1337 /* Default value */
1338 aifsn = acparam_cur->ACI&EDCF_AIFSN_MASK;
1339 ecwmin = acparam_cur->ECW&EDCF_ECWMIN_MASK;
1340 ecwmax = (acparam_cur->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT;
1341 txop = acparam_cur->TXOP;
1342
1343 /* Modified value */
1344 if (wme->aifsn[aci] > 0)
1345 aifsn = wme->aifsn[aci];
1346 if (wme->ecwmin[aci] > 0)
1347 ecwmin = wme->ecwmin[aci];
1348 if (wme->ecwmax[aci] > 0)
1349 ecwmax = wme->ecwmax[aci];
1350 if (wme->txop[aci] > 0)
1351 txop = wme->txop[aci];
1352
1353 if (!(wme->aifsn[aci] || wme->ecwmin[aci] ||
1354 wme->ecwmax[aci] || wme->txop[aci]))
1355 return;
1356
1357 /* Update */
1358 acp = acparam_cur;
1359 acp->ACI = (acp->ACI & ~EDCF_AIFSN_MASK) | (aifsn & EDCF_AIFSN_MASK);
1360 acp->ECW = ((ecwmax << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK) | (acp->ECW & EDCF_ECWMIN_MASK);
1361 acp->ECW = ((acp->ECW & EDCF_ECWMAX_MASK) | (ecwmin & EDCF_ECWMIN_MASK));
1362 acp->TXOP = txop;
1363
1364 CONFIG_MSG("wme_ac %s aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n",
1365 mode?"ap":"sta", acp->ACI, acp->ACI&EDCF_AIFSN_MASK,
1366 acp->ECW&EDCF_ECWMIN_MASK, (acp->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
1367 acp->TXOP);
1368
1369 /*
1370 * Now use buf as an output buffer.
1371 * Put WME acparams after "wme_ac\0" in buf.
1372 * NOTE: only one of the four ACs can be set at a time.
1373 */
1374 if (mode == 0)
1375 dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wme_ac_sta", (char *)acp,
1376 sizeof(edcf_acparam_t), FALSE);
1377 else
1378 dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wme_ac_ap", (char *)acp,
1379 sizeof(edcf_acparam_t), FALSE);
1380
1381 }
1382
1383 void
1384 dhd_conf_set_wme(dhd_pub_t *dhd, int ifidx, int mode)
1385 {
1386 edcf_acparam_t acparam_cur[AC_COUNT];
1387
1388 if (dhd && dhd->conf) {
1389 if (!dhd->conf->force_wme_ac) {
1390 CONFIG_TRACE("force_wme_ac is not enabled %d\n",
1391 dhd->conf->force_wme_ac);
1392 return;
1393 }
1394
1395 CONFIG_TRACE("Before change:\n");
1396 dhd_conf_get_wme(dhd, ifidx, mode, acparam_cur);
1397
1398 dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_BK], AC_BK);
1399 dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_BE], AC_BE);
1400 dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_VI], AC_VI);
1401 dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_VO], AC_VO);
1402
1403 CONFIG_TRACE("After change:\n");
1404 dhd_conf_get_wme(dhd, ifidx, mode, acparam_cur);
1405 } else {
1406 CONFIG_ERROR("dhd or conf is NULL\n");
1407 }
1408
1409 return;
1410 }
1411
1412 void
1413 dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int p2p_mode, int miracast_mode)
1414 {
1415 struct dhd_conf *conf = dhd->conf;
1416 mchan_params_t *mchan = conf->mchan;
1417 bool set = true;
1418
1419 while (mchan != NULL) {
1420 set = true;
1421 set &= (mchan->bw >= 0);
1422 set &= ((mchan->p2p_mode == -1) | (mchan->p2p_mode == p2p_mode));
1423 set &= ((mchan->miracast_mode == -1) | (mchan->miracast_mode == miracast_mode));
1424 if (set) {
1425 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "mchan_bw", mchan->bw, 0, FALSE);
1426 }
1427 mchan = mchan->next;
1428 }
1429
1430 return;
1431 }
1432
1433 #ifdef PKT_FILTER_SUPPORT
1434 void
1435 dhd_conf_add_pkt_filter(dhd_pub_t *dhd)
1436 {
1437 int i, j;
1438 char str[16];
1439 #define MACS "%02x%02x%02x%02x%02x%02x"
1440
1441 /*
1442 * Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E)
1443 * 1) dhd_master_mode=1
1444 * 2) pkt_filter_delete=100, 102, 103, 104, 105, 106, 107
1445 * 3) pkt_filter_add=131 0 0 12 0xFFFF 0x886C, 132 0 0 12 0xFFFF 0x888E
1446 * 4) magic_pkt_filter_add=141 0 1 12
1447 */
1448 for(i=0; i<dhd->conf->pkt_filter_add.count; i++) {
1449 dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i];
1450 CONFIG_MSG("%s\n", dhd->pktfilter[i+dhd->pktfilter_count]);
1451 }
1452 dhd->pktfilter_count += i;
1453
1454 if (dhd->conf->magic_pkt_filter_add) {
1455 strcat(dhd->conf->magic_pkt_filter_add, " 0x");
1456 strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF");
1457 for (j=0; j<16; j++)
1458 strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF");
1459 strcat(dhd->conf->magic_pkt_filter_add, " 0x");
1460 strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF");
1461 sprintf(str, MACS, MAC2STRDBG(dhd->mac.octet));
1462 for (j=0; j<16; j++)
1463 strncat(dhd->conf->magic_pkt_filter_add, str, 12);
1464 dhd->pktfilter[dhd->pktfilter_count] = dhd->conf->magic_pkt_filter_add;
1465 dhd->pktfilter_count += 1;
1466 }
1467 }
1468
1469 bool
1470 dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id)
1471 {
1472 int i;
1473
1474 if (dhd && dhd->conf) {
1475 for (i=0; i<dhd->conf->pkt_filter_del.count; i++) {
1476 if (id == dhd->conf->pkt_filter_del.id[i]) {
1477 CONFIG_MSG("%d\n", dhd->conf->pkt_filter_del.id[i]);
1478 return true;
1479 }
1480 }
1481 return false;
1482 }
1483 return false;
1484 }
1485
1486 void
1487 dhd_conf_discard_pkt_filter(dhd_pub_t *dhd)
1488 {
1489 dhd->pktfilter_count = 6;
1490 dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = NULL;
1491 dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
1492 dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "102 0 0 0 0xFFFFFF 0x01005E";
1493 dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = "103 0 0 0 0xFFFF 0x3333";
1494 dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL;
1495 /* Do not enable ARP to pkt filter if dhd_master_mode is false.*/
1496 dhd->pktfilter[DHD_ARP_FILTER_NUM] = NULL;
1497
1498 /* IPv4 broadcast address XXX.XXX.XXX.255 */
1499 dhd->pktfilter[dhd->pktfilter_count] = "110 0 0 12 0xFFFF00000000000000000000000000000000000000FF 0x080000000000000000000000000000000000000000FF";
1500 dhd->pktfilter_count++;
1501 /* discard IPv4 multicast address 224.0.0.0/4 */
1502 dhd->pktfilter[dhd->pktfilter_count] = "111 0 0 12 0xFFFF00000000000000000000000000000000F0 0x080000000000000000000000000000000000E0";
1503 dhd->pktfilter_count++;
1504 /* discard IPv6 multicast address FF00::/8 */
1505 dhd->pktfilter[dhd->pktfilter_count] = "112 0 0 12 0xFFFF000000000000000000000000000000000000000000000000FF 0x86DD000000000000000000000000000000000000000000000000FF";
1506 dhd->pktfilter_count++;
1507 /* discard Netbios pkt */
1508 dhd->pktfilter[dhd->pktfilter_count] = "121 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089";
1509 dhd->pktfilter_count++;
1510
1511 }
1512 #endif /* PKT_FILTER_SUPPORT */
1513
1514 int
1515 dhd_conf_get_pm(dhd_pub_t *dhd)
1516 {
1517 if (dhd && dhd->conf) {
1518 return dhd->conf->pm;
1519 }
1520 return -1;
1521 }
1522
1523 int
1524 dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len,
1525 int *hostsleep_set, int *hostsleep_val, int *ret)
1526 {
1527 if (dhd->conf->insuspend & (NO_TXCTL_IN_SUSPEND | WOWL_IN_SUSPEND)) {
1528 if (cmd == WLC_SET_VAR) {
1529 char *psleep = NULL;
1530 psleep = strstr(buf, "hostsleep");
1531 if (psleep) {
1532 *hostsleep_set = 1;
1533 memcpy(hostsleep_val, psleep+strlen("hostsleep")+1, sizeof(int));
1534 }
1535 }
1536 if (dhd->hostsleep && (!*hostsleep_set || *hostsleep_val)) {
1537 CONFIG_TRACE("block all none hostsleep clr cmd\n");
1538 *ret = BCME_EPERM;
1539 goto exit;
1540 } else if (*hostsleep_set && *hostsleep_val) {
1541 CONFIG_TRACE("hostsleep %d => %d\n", dhd->hostsleep, *hostsleep_val);
1542 dhd->hostsleep = *hostsleep_val;
1543 if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) {
1544 dhd_txflowcontrol(dhd, ALL_INTERFACES, ON);
1545 }
1546 if (dhd->hostsleep == 2) {
1547 *ret = 0;
1548 goto exit;
1549 }
1550 } else if (dhd->hostsleep == 2 && !*hostsleep_val) {
1551 CONFIG_TRACE("hostsleep %d => %d\n", dhd->hostsleep, *hostsleep_val);
1552 dhd->hostsleep = *hostsleep_val;
1553 if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) {
1554 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
1555 }
1556 *ret = 0;
1557 goto exit;
1558 }
1559 }
1560 #ifdef NO_POWER_SAVE
1561 if (cmd == WLC_SET_PM) {
1562 if (*(const u32*)buf != 0) {
1563 CONFIG_TRACE("skip PM\n");
1564 *ret = BCME_OK;
1565 goto exit;
1566 }
1567 } else if (cmd == WLC_SET_VAR) {
1568 int cmd_len = strlen("mpc");
1569 if (!strncmp(buf, "mpc", cmd_len)) {
1570 if (*((u32 *)((u8*)buf+cmd_len+1)) != 0) {
1571 CONFIG_TRACE("skip mpc\n");
1572 *ret = BCME_OK;
1573 goto exit;
1574 }
1575 }
1576 }
1577 #endif
1578
1579 return 0;
1580 exit:
1581 return -1;
1582 }
1583
1584 void
1585 dhd_conf_get_hostsleep(dhd_pub_t *dhd,
1586 int hostsleep_set, int hostsleep_val, int ret)
1587 {
1588 if (dhd->conf->insuspend & (NO_TXCTL_IN_SUSPEND | WOWL_IN_SUSPEND)) {
1589 if (hostsleep_set) {
1590 if (hostsleep_val && ret) {
1591 CONFIG_TRACE("reset hostsleep %d => 0\n", dhd->hostsleep);
1592 dhd->hostsleep = 0;
1593 if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) {
1594 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
1595 }
1596 } else if (!hostsleep_val && !ret) {
1597 CONFIG_TRACE("set hostsleep %d => 0\n", dhd->hostsleep);
1598 dhd->hostsleep = 0;
1599 if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) {
1600 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
1601 }
1602 }
1603 }
1604 }
1605 }
1606
1607 #ifdef WL_EXT_WOWL
1608 #define WL_WOWL_TCPFIN (1 << 26)
1609 typedef struct wl_wowl_pattern2 {
1610 char cmd[4];
1611 wl_wowl_pattern_t wowl_pattern;
1612 } wl_wowl_pattern2_t;
1613 static int
1614 dhd_conf_wowl_pattern(dhd_pub_t *dhd, bool add, char *data)
1615 {
1616 uint buf_len = 0;
1617 int id, type, polarity, offset;
1618 char cmd[4]="\0", mask[128]="\0", pattern[128]="\0", mask_tmp[128]="\0", *pmask_tmp;
1619 uint32 masksize, patternsize, pad_len = 0;
1620 wl_wowl_pattern2_t *wowl_pattern2 = NULL;
1621 char *mask_and_pattern;
1622 int ret = 0, i, j, v;
1623
1624 if (data) {
1625 if (add)
1626 strcpy(cmd, "add");
1627 else
1628 strcpy(cmd, "clr");
1629 if (!strcmp(cmd, "clr")) {
1630 CONFIG_TRACE("wowl_pattern clr\n");
1631 ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "wowl_pattern", cmd,
1632 sizeof(cmd), FALSE);
1633 goto exit;
1634 }
1635 sscanf(data, "%d %d %d %d %s %s", &id, &type, &polarity, &offset,
1636 mask_tmp, pattern);
1637 masksize = strlen(mask_tmp) -2;
1638 CONFIG_TRACE("0 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
1639
1640 // add pading
1641 if (masksize % 16)
1642 pad_len = (16 - masksize % 16);
1643 for (i=0; i<pad_len; i++)
1644 strcat(mask_tmp, "0");
1645 masksize += pad_len;
1646 CONFIG_TRACE("1 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
1647
1648 // translate 0x00 to 0, others to 1
1649 j = 0;
1650 pmask_tmp = &mask_tmp[2];
1651 for (i=0; i<masksize/2; i++) {
1652 if(strncmp(&pmask_tmp[i*2], "00", 2))
1653 pmask_tmp[j] = '1';
1654 else
1655 pmask_tmp[j] = '0';
1656 j++;
1657 }
1658 pmask_tmp[j] = '\0';
1659 masksize = masksize / 2;
1660 CONFIG_TRACE("2 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
1661
1662 // reorder per 8bits
1663 pmask_tmp = &mask_tmp[2];
1664 for (i=0; i<masksize/8; i++) {
1665 char c;
1666 for (j=0; j<4; j++) {
1667 c = pmask_tmp[i*8+j];
1668 pmask_tmp[i*8+j] = pmask_tmp[(i+1)*8-j-1];
1669 pmask_tmp[(i+1)*8-j-1] = c;
1670 }
1671 }
1672 CONFIG_TRACE("3 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
1673
1674 // translate 8bits to 1byte
1675 j = 0; v = 0;
1676 pmask_tmp = &mask_tmp[2];
1677 strcpy(mask, "0x");
1678 for (i=0; i<masksize; i++) {
1679 v = (v<<1) | (pmask_tmp[i]=='1');
1680 if (((i+1)%4) == 0) {
1681 if (v < 10)
1682 mask[j+2] = v + '0';
1683 else
1684 mask[j+2] = (v-10) + 'a';
1685 j++;
1686 v = 0;
1687 }
1688 }
1689 mask[j+2] = '\0';
1690 masksize = j/2;
1691 CONFIG_TRACE("4 mask=%s, masksize=%d\n", mask, masksize);
1692
1693 patternsize = (strlen(pattern)-2)/2;
1694 buf_len = sizeof(wl_wowl_pattern2_t) + patternsize + masksize;
1695 wowl_pattern2 = kmalloc(buf_len, GFP_KERNEL);
1696 if (wowl_pattern2 == NULL) {
1697 CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", buf_len);
1698 goto exit;
1699 }
1700 memset(wowl_pattern2, 0, sizeof(wl_wowl_pattern2_t));
1701
1702 strncpy(wowl_pattern2->cmd, cmd, sizeof(cmd));
1703 wowl_pattern2->wowl_pattern.id = id;
1704 wowl_pattern2->wowl_pattern.type = 0;
1705 wowl_pattern2->wowl_pattern.offset = offset;
1706 mask_and_pattern = (char*)wowl_pattern2 + sizeof(wl_wowl_pattern2_t);
1707
1708 wowl_pattern2->wowl_pattern.masksize = masksize;
1709 ret = wl_pattern_atoh(mask, mask_and_pattern);
1710 if (ret == -1) {
1711 CONFIG_ERROR("rejecting mask=%s\n", mask);
1712 goto exit;
1713 }
1714
1715 mask_and_pattern += wowl_pattern2->wowl_pattern.masksize;
1716 wowl_pattern2->wowl_pattern.patternoffset = sizeof(wl_wowl_pattern_t) +
1717 wowl_pattern2->wowl_pattern.masksize;
1718
1719 wowl_pattern2->wowl_pattern.patternsize = patternsize;
1720 ret = wl_pattern_atoh(pattern, mask_and_pattern);
1721 if (ret == -1) {
1722 CONFIG_ERROR("rejecting pattern=%s\n", pattern);
1723 goto exit;
1724 }
1725
1726 CONFIG_TRACE("%s %d %s %s\n", cmd, offset, mask, pattern);
1727
1728 ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "wowl_pattern",
1729 (char *)wowl_pattern2, buf_len, FALSE);
1730 }
1731
1732 exit:
1733 if (wowl_pattern2)
1734 kfree(wowl_pattern2);
1735 return ret;
1736 }
1737
1738 static int
1739 dhd_conf_wowl_wakeind(dhd_pub_t *dhd, bool clear)
1740 {
1741 s8 iovar_buf[WLC_IOCTL_SMLEN];
1742 wl_wowl_wakeind_t *wake = NULL;
1743 int ret = -1;
1744 char clr[6]="clear", wakeind_str[32]="\0";
1745
1746 if (clear) {
1747 CONFIG_TRACE("wowl_wakeind clear\n");
1748 ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "wowl_wakeind",
1749 clr, sizeof(clr), 0);
1750 } else {
1751 ret = dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "wowl_wakeind",
1752 iovar_buf, sizeof(iovar_buf));
1753 if (!ret) {
1754 wake = (wl_wowl_wakeind_t *) iovar_buf;
1755 if (wake->ucode_wakeind & WL_WOWL_MAGIC)
1756 strcpy(wakeind_str, "(MAGIC packet)");
1757 if (wake->ucode_wakeind & WL_WOWL_NET)
1758 strcpy(wakeind_str, "(Netpattern)");
1759 if (wake->ucode_wakeind & WL_WOWL_DIS)
1760 strcpy(wakeind_str, "(Disassoc/Deauth)");
1761 if (wake->ucode_wakeind & WL_WOWL_BCN)
1762 strcpy(wakeind_str, "(Loss of beacon)");
1763 if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_TIME)
1764 strcpy(wakeind_str, "(TCPKA timeout)");
1765 if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_DATA)
1766 strcpy(wakeind_str, "(TCPKA data)");
1767 if (wake->ucode_wakeind & WL_WOWL_TCPFIN)
1768 strcpy(wakeind_str, "(TCP FIN)");
1769 CONFIG_MSG("wakeind=0x%x %s\n", wake->ucode_wakeind, wakeind_str);
1770 }
1771 }
1772
1773 return ret;
1774 }
1775 #endif
1776
1777 int
1778 dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period,
1779 char *packet, bool bcast)
1780 {
1781 wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
1782 int ret = 0, len_bytes=0, buf_len=0;
1783 char *buf = NULL, *iovar_buf = NULL;
1784 uint8 *pdata;
1785
1786 CONFIG_TRACE("id=%d, period=%d, packet=%s\n", id, period, packet);
1787 if (period >= 0) {
1788 buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
1789 if (buf == NULL) {
1790 CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
1791 goto exit;
1792 }
1793 iovar_buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
1794 if (iovar_buf == NULL) {
1795 CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
1796 goto exit;
1797 }
1798 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf;
1799 mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION);
1800 mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
1801 mkeep_alive_pktp->keep_alive_id = id;
1802 buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
1803 mkeep_alive_pktp->period_msec = period;
1804 if (packet && strlen(packet)) {
1805 len_bytes = wl_pattern_atoh(packet, (char *)mkeep_alive_pktp->data);
1806 buf_len += len_bytes;
1807 if (bcast) {
1808 memcpy(mkeep_alive_pktp->data, &ether_bcast, ETHER_ADDR_LEN);
1809 }
1810 ret = dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "cur_etheraddr",
1811 iovar_buf, WLC_IOCTL_SMLEN);
1812 if (!ret) {
1813 pdata = mkeep_alive_pktp->data;
1814 memcpy(pdata+6, iovar_buf, ETHER_ADDR_LEN);
1815 }
1816 }
1817 mkeep_alive_pktp->len_bytes = htod16(len_bytes);
1818 ret = dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "mkeep_alive",
1819 buf, buf_len, FALSE);
1820 }
1821
1822 exit:
1823 if (buf)
1824 kfree(buf);
1825 if (iovar_buf)
1826 kfree(iovar_buf);
1827 return ret;
1828 }
1829
1830 #ifdef ARP_OFFLOAD_SUPPORT
1831 void
1832 dhd_conf_set_garp(dhd_pub_t *dhd, int ifidx, uint32 ipa, bool enable)
1833 {
1834 int i, len = 0, total_len = WLC_IOCTL_SMLEN;
1835 char *iovar_buf = NULL, *packet = NULL;
1836
1837 if (!dhd->conf->garp || ifidx != 0 || !(dhd->op_mode & DHD_FLAG_STA_MODE))
1838 return;
1839
1840 CONFIG_TRACE("enable=%d\n", enable);
1841
1842 if (enable) {
1843 iovar_buf = kmalloc(total_len, GFP_KERNEL);
1844 if (iovar_buf == NULL) {
1845 CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", total_len);
1846 goto exit;
1847 }
1848 packet = kmalloc(total_len, GFP_KERNEL);
1849 if (packet == NULL) {
1850 CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", total_len);
1851 goto exit;
1852 }
1853 dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "cur_etheraddr", iovar_buf, total_len);
1854
1855 len += snprintf(packet+len, total_len, "0xffffffffffff");
1856 for (i=0; i<ETHER_ADDR_LEN; i++)
1857 len += snprintf(packet+len, total_len, "%02x", iovar_buf[i]);
1858 len += snprintf(packet+len, total_len, "08060001080006040001");
1859 // Sender Hardware Addr.
1860 for (i=0; i<ETHER_ADDR_LEN; i++)
1861 len += snprintf(packet+len, total_len, "%02x", iovar_buf[i]);
1862 // Sender IP Addr.
1863 len += snprintf(packet+len, total_len, "%02x%02x%02x%02x",
1864 ipa&0xff, (ipa>>8)&0xff, (ipa>>16)&0xff, (ipa>>24)&0xff);
1865 // Target Hardware Addr.
1866 len += snprintf(packet+len, total_len, "ffffffffffff");
1867 // Target IP Addr.
1868 len += snprintf(packet+len, total_len, "%02x%02x%02x%02x",
1869 ipa&0xff, (ipa>>8)&0xff, (ipa>>16)&0xff, (ipa>>24)&0xff);
1870 len += snprintf(packet+len, total_len, "000000000000000000000000000000000000");
1871 }
1872
1873 dhd_conf_mkeep_alive(dhd, ifidx, 0, dhd->conf->keep_alive_period, packet, TRUE);
1874
1875 exit:
1876 if (iovar_buf)
1877 kfree(iovar_buf);
1878 if (packet)
1879 kfree(packet);
1880 return;
1881 }
1882 #endif
1883
1884 uint
1885 dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask)
1886 {
1887 uint insuspend = 0;
1888
1889 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
1890 insuspend = dhd->conf->insuspend &
1891 (NO_EVENT_IN_SUSPEND | NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND |
1892 ROAM_OFFLOAD_IN_SUSPEND | WOWL_IN_SUSPEND);
1893 } else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
1894 insuspend = dhd->conf->insuspend &
1895 (NO_EVENT_IN_SUSPEND | NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND |
1896 AP_DOWN_IN_SUSPEND | AP_FILTER_IN_SUSPEND);
1897 }
1898
1899 return (insuspend & mask);
1900 }
1901
1902 #ifdef SUSPEND_EVENT
1903 void
1904 dhd_conf_set_suspend_event(dhd_pub_t *dhd, int suspend)
1905 {
1906 struct dhd_conf *conf = dhd->conf;
1907 struct ether_addr bssid;
1908 char suspend_eventmask[WL_EVENTING_MASK_LEN];
1909 wl_event_msg_t msg;
1910 int pm;
1911 #ifdef WL_CFG80211
1912 struct net_device *net;
1913 #endif /* defined(WL_CFG80211) */
1914
1915 CONFIG_TRACE("Enter\n");
1916 if (suspend) {
1917 #ifdef PROP_TXSTATUS
1918 #if defined(BCMSDIO) || defined(BCMDBUS)
1919 if (dhd->wlfc_enabled) {
1920 dhd_wlfc_deinit(dhd);
1921 conf->wlfc = TRUE;
1922 } else {
1923 conf->wlfc = FALSE;
1924 }
1925 #endif /* BCMSDIO || BCMDBUS */
1926 #endif /* PROP_TXSTATUS */
1927 dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "event_msgs",
1928 conf->resume_eventmask, sizeof(conf->resume_eventmask));
1929 memset(suspend_eventmask, 0, sizeof(suspend_eventmask));
1930 setbit(suspend_eventmask, WLC_E_ESCAN_RESULT);
1931 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs",
1932 suspend_eventmask, sizeof(suspend_eventmask), FALSE);
1933 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
1934 memset(&bssid, 0, ETHER_ADDR_LEN);
1935 dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, FALSE, 0);
1936 if (memcmp(&ether_null, &bssid, ETHER_ADDR_LEN))
1937 memcpy(&conf->bssid_insuspend, &bssid, ETHER_ADDR_LEN);
1938 else
1939 memset(&conf->bssid_insuspend, 0, ETHER_ADDR_LEN);
1940 }
1941 }
1942 else {
1943 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs",
1944 conf->resume_eventmask, sizeof(conf->resume_eventmask), FALSE);
1945 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
1946 if (memcmp(&ether_null, &conf->bssid_insuspend, ETHER_ADDR_LEN)) {
1947 memset(&bssid, 0, ETHER_ADDR_LEN);
1948 dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN,
1949 FALSE, 0);
1950 if (memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
1951 dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", 0, 0, FALSE);
1952 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "send_nulldata",
1953 (char *)&bssid, ETHER_ADDR_LEN, FALSE);
1954 OSL_SLEEP(100);
1955 if (conf->pm >= 0)
1956 pm = conf->pm;
1957 else
1958 pm = PM_FAST;
1959 dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE);
1960 } else {
1961 CONFIG_TRACE("send WLC_E_DEAUTH_IND event\n");
1962 bzero(&msg, sizeof(wl_event_msg_t));
1963 memcpy(&msg.addr, &conf->bssid_insuspend, ETHER_ADDR_LEN);
1964 msg.event_type = hton32(WLC_E_DEAUTH_IND);
1965 msg.status = 0;
1966 msg.reason = hton32(DOT11_RC_DEAUTH_LEAVING);
1967 #if defined(WL_EXT_IAPSTA) || defined(USE_IW)
1968 wl_ext_event_send(dhd->event_params, &msg, NULL);
1969 #endif
1970 #ifdef WL_CFG80211
1971 net = dhd_idx2net(dhd, 0);
1972 if (net) {
1973 wl_cfg80211_event(net, &msg, NULL);
1974 }
1975 #endif /* defined(WL_CFG80211) */
1976 }
1977 }
1978 #ifdef PROP_TXSTATUS
1979 #if defined(BCMSDIO) || defined(BCMDBUS)
1980 if (conf->wlfc) {
1981 dhd_wlfc_init(dhd);
1982 dhd_conf_set_intiovar(dhd, WLC_UP, "WLC_UP", 0, 0, FALSE);
1983 }
1984 #endif
1985 #endif /* PROP_TXSTATUS */
1986 }
1987 }
1988
1989 }
1990 #endif
1991
1992 #if defined(WL_CFG80211) || defined(WL_ESCAN)
1993 static void
1994 dhd_conf_wait_event_complete(struct dhd_pub *dhd, int ifidx)
1995 {
1996 s32 timeout = -1;
1997
1998 timeout = wait_event_interruptible_timeout(dhd->conf->event_complete,
1999 wl_ext_event_complete(dhd, ifidx), msecs_to_jiffies(10000));
2000 if (timeout <= 0 || !wl_ext_event_complete(dhd, ifidx)) {
2001 wl_ext_event_complete(dhd, ifidx);
2002 CONFIG_ERROR("timeout\n");
2003 }
2004 }
2005 #endif
2006
2007 int
2008 dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend)
2009 {
2010 struct dhd_conf *conf = dhd->conf;
2011 uint insuspend = 0;
2012 int pm;
2013 #ifdef BCMSDIO
2014 uint32 intstatus = 0;
2015 int ret = 0;
2016 #endif
2017 #ifdef WL_EXT_WOWL
2018 int i;
2019 #endif
2020
2021 insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND);
2022 if (insuspend)
2023 CONFIG_MSG("op_mode %d, suspend %d, suspended %d, insuspend 0x%x, suspend_mode=%d\n",
2024 dhd->op_mode, suspend, conf->suspended, insuspend, conf->suspend_mode);
2025
2026 if (conf->suspended == suspend || !dhd->up) {
2027 return 0;
2028 }
2029
2030 if (suspend) {
2031 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
2032 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_off",
2033 dhd->conf->roam_off_suspend, 0, FALSE);
2034 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_li_dtim",
2035 dhd->conf->suspend_bcn_li_dtim, 0, FALSE);
2036 if (insuspend & ROAM_OFFLOAD_IN_SUSPEND)
2037 dhd_conf_enable_roam_offload(dhd, 2);
2038 } else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2039 if (insuspend & AP_DOWN_IN_SUSPEND) {
2040 dhd_conf_set_intiovar(dhd, WLC_DOWN, "WLC_DOWN", 1, 0, FALSE);
2041 }
2042 }
2043 #if defined(WL_CFG80211) || defined(WL_ESCAN)
2044 if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) {
2045 if (conf->suspend_mode == PM_NOTIFIER)
2046 dhd_conf_wait_event_complete(dhd, 0);
2047 }
2048 #endif
2049 if (insuspend & NO_TXDATA_IN_SUSPEND) {
2050 dhd_txflowcontrol(dhd, ALL_INTERFACES, ON);
2051 }
2052 #if defined(WL_CFG80211) || defined(WL_ESCAN)
2053 if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) {
2054 if (conf->suspend_mode == PM_NOTIFIER)
2055 wl_ext_user_sync(dhd, 0, TRUE);
2056 }
2057 #endif
2058 #ifdef SUSPEND_EVENT
2059 if (insuspend & NO_EVENT_IN_SUSPEND) {
2060 dhd_conf_set_suspend_event(dhd, suspend);
2061 }
2062 #endif
2063 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
2064 if (conf->pm_in_suspend >= 0)
2065 pm = conf->pm_in_suspend;
2066 else if (conf->pm >= 0)
2067 pm = conf->pm;
2068 else
2069 pm = PM_FAST;
2070 dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE);
2071 }
2072 dhd_conf_set_wl_cmd(dhd, conf->wl_suspend, FALSE);
2073 #ifdef WL_EXT_WOWL
2074 if ((insuspend & WOWL_IN_SUSPEND) && dhd_master_mode) {
2075 dhd_conf_wowl_pattern(dhd, FALSE, "clr");
2076 for(i=0; i<conf->pkt_filter_add.count; i++) {
2077 dhd_conf_wowl_pattern(dhd, TRUE, conf->pkt_filter_add.filter[i]);
2078 }
2079 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl", conf->wowl, 0, FALSE);
2080 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl_activate", 1, 0, FALSE);
2081 dhd_conf_wowl_wakeind(dhd, TRUE);
2082 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "hostsleep", 1, 0, FALSE);
2083 #ifdef BCMSDIO
2084 ret = dhd_bus_sleep(dhd, TRUE, &intstatus);
2085 CONFIG_TRACE("ret = %d, intstatus = 0x%x\n", ret, intstatus);
2086 #endif
2087 } else
2088 #endif
2089 if (insuspend & NO_TXCTL_IN_SUSPEND) {
2090 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "hostsleep", 2, 0, FALSE);
2091 #ifdef BCMSDIO
2092 ret = dhd_bus_sleep(dhd, TRUE, &intstatus);
2093 CONFIG_TRACE("ret = %d, intstatus = 0x%x\n", ret, intstatus);
2094 #endif
2095 }
2096 conf->suspended = TRUE;
2097 } else {
2098 if (insuspend & (WOWL_IN_SUSPEND | NO_TXCTL_IN_SUSPEND)) {
2099 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "hostsleep", 0, 0, FALSE);
2100 }
2101 #ifdef WL_EXT_WOWL
2102 if (insuspend & WOWL_IN_SUSPEND) {
2103 dhd_conf_wowl_wakeind(dhd, FALSE);
2104 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl_activate", 0, 0, FALSE);
2105 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl", 0, 0, FALSE);
2106 dhd_conf_wowl_pattern(dhd, FALSE, "clr");
2107 }
2108 #endif
2109 dhd_conf_set_wl_cmd(dhd, conf->wl_resume, FALSE);
2110 dhd_conf_get_iovar(dhd, 0, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm));
2111 CONFIG_TRACE("PM in suspend = %d\n", pm);
2112 #ifdef SUSPEND_EVENT
2113 if (insuspend & NO_EVENT_IN_SUSPEND) {
2114 dhd_conf_set_suspend_event(dhd, suspend);
2115 }
2116 #endif
2117 #if defined(WL_CFG80211) || defined(WL_ESCAN)
2118 if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) {
2119 if (conf->suspend_mode == PM_NOTIFIER)
2120 wl_ext_user_sync(dhd, 0, FALSE);
2121 }
2122 #endif
2123 if (insuspend & NO_TXDATA_IN_SUSPEND) {
2124 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2125 }
2126 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
2127 if (insuspend & ROAM_OFFLOAD_IN_SUSPEND)
2128 dhd_conf_enable_roam_offload(dhd, 0);
2129 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_li_dtim", 0, 0, FALSE);
2130 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_off",
2131 dhd->conf->roam_off, 0, FALSE);
2132 } else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2133 if (insuspend & AP_DOWN_IN_SUSPEND) {
2134 dhd_conf_set_intiovar(dhd, WLC_UP, "WLC_UP", 0, 0, FALSE);
2135 }
2136 }
2137 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
2138 if (conf->pm >= 0)
2139 pm = conf->pm;
2140 else
2141 pm = PM_FAST;
2142 dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE);
2143 }
2144 conf->suspended = FALSE;
2145 }
2146
2147 return 0;
2148 }
2149
2150 #ifdef PROP_TXSTATUS
2151 int
2152 dhd_conf_get_disable_proptx(dhd_pub_t *dhd)
2153 {
2154 struct dhd_conf *conf = dhd->conf;
2155 int disable_proptx = -1;
2156 int fw_proptx = 0;
2157
2158 /* check fw proptx priority:
2159 * 1st: check fw support by wl cap
2160 * 2nd: 4334/43340/43341/43241 support proptx but not show in wl cap, so enable it by default
2161 * if you would like to disable it, please set disable_proptx=1 in config.txt
2162 * 3th: disable when proptxstatus not support in wl cap
2163 */
2164 if (FW_SUPPORTED(dhd, proptxstatus)) {
2165 fw_proptx = 1;
2166 } else if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID ||
2167 dhd->conf->chip == BCM43340_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
2168 fw_proptx = 1;
2169 } else {
2170 fw_proptx = 0;
2171 }
2172
2173 /* returned disable_proptx value:
2174 * -1: disable in STA and enable in P2P(follow original dhd settings when PROP_TXSTATUS_VSDB enabled)
2175 * 0: depend on fw support
2176 * 1: always disable proptx
2177 */
2178 if (conf->disable_proptx == 0) {
2179 // check fw support as well
2180 if (fw_proptx)
2181 disable_proptx = 0;
2182 else
2183 disable_proptx = 1;
2184 } else if (conf->disable_proptx >= 1) {
2185 disable_proptx = 1;
2186 } else {
2187 // check fw support as well
2188 if (fw_proptx)
2189 disable_proptx = -1;
2190 else
2191 disable_proptx = 1;
2192 }
2193
2194 CONFIG_MSG("fw_proptx=%d, disable_proptx=%d\n", fw_proptx, disable_proptx);
2195
2196 return disable_proptx;
2197 }
2198 #endif
2199
2200 uint
2201 pick_config_vars(char *varbuf, uint len, uint start_pos, char *pickbuf, int picklen)
2202 {
2203 bool findNewline, changenewline=FALSE, pick=FALSE;
2204 int column;
2205 uint n, pick_column=0;
2206
2207 findNewline = FALSE;
2208 column = 0;
2209
2210 if (start_pos >= len) {
2211 CONFIG_ERROR("wrong start pos\n");
2212 return 0;
2213 }
2214
2215 for (n = start_pos; n < len; n++) {
2216 if (varbuf[n] == '\r')
2217 continue;
2218 if ((findNewline || changenewline) && varbuf[n] != '\n')
2219 continue;
2220 findNewline = FALSE;
2221 if (varbuf[n] == '#') {
2222 findNewline = TRUE;
2223 continue;
2224 }
2225 if (varbuf[n] == '\\') {
2226 changenewline = TRUE;
2227 continue;
2228 }
2229 if (!changenewline && varbuf[n] == '\n') {
2230 if (column == 0)
2231 continue;
2232 column = 0;
2233 continue;
2234 }
2235 if (changenewline && varbuf[n] == '\n') {
2236 changenewline = FALSE;
2237 continue;
2238 }
2239
2240 if (column==0 && !pick) { // start to pick
2241 pick = TRUE;
2242 column++;
2243 pick_column = 0;
2244 } else {
2245 if (pick && column==0) { // stop to pick
2246 pick = FALSE;
2247 break;
2248 } else
2249 column++;
2250 }
2251 if (pick) {
2252 if (varbuf[n] == 0x9)
2253 continue;
2254 if (pick_column >= picklen)
2255 break;
2256 pickbuf[pick_column] = varbuf[n];
2257 pick_column++;
2258 }
2259 }
2260
2261 return n; // return current position
2262 }
2263
2264 bool
2265 dhd_conf_read_chiprev(dhd_pub_t *dhd, int *chip_match,
2266 char *full_param, uint len_param)
2267 {
2268 char *data = full_param+len_param, *pick_tmp, *pch;
2269 uint chip = 0, rev = 0;
2270
2271 /* Process chip, regrev:
2272 * chip=[chipid], rev==[rev]
2273 * Ex: chip=0x4359, rev=9
2274 */
2275 if (!strncmp("chip=", full_param, len_param)) {
2276 chip = (int)simple_strtol(data, NULL, 0);
2277 pick_tmp = data;
2278 pch = bcmstrstr(pick_tmp, "rev=");
2279 if (pch) {
2280 rev = (int)simple_strtol(pch+strlen("rev="), NULL, 0);
2281 }
2282 if (chip == dhd->conf->chip && rev == dhd->conf->chiprev)
2283 *chip_match = 1;
2284 else
2285 *chip_match = 0;
2286 CONFIG_MSG("chip=0x%x, rev=%d, chip_match=%d\n", chip, rev, *chip_match);
2287 }
2288
2289 return TRUE;
2290 }
2291
2292 bool
2293 dhd_conf_read_log_level(dhd_pub_t *dhd, char *full_param, uint len_param)
2294 {
2295 char *data = full_param+len_param;
2296
2297 if (!strncmp("dhd_msg_level=", full_param, len_param)) {
2298 dhd_msg_level = (int)simple_strtol(data, NULL, 0);
2299 CONFIG_MSG("dhd_msg_level = 0x%X\n", dhd_msg_level);
2300 }
2301 else if (!strncmp("dump_msg_level=", full_param, len_param)) {
2302 dump_msg_level = (int)simple_strtol(data, NULL, 0);
2303 CONFIG_MSG("dump_msg_level = 0x%X\n", dump_msg_level);
2304 }
2305 #ifdef BCMSDIO
2306 else if (!strncmp("sd_msglevel=", full_param, len_param)) {
2307 sd_msglevel = (int)simple_strtol(data, NULL, 0);
2308 CONFIG_MSG("sd_msglevel = 0x%X\n", sd_msglevel);
2309 }
2310 #endif
2311 #ifdef BCMDBUS
2312 else if (!strncmp("dbus_msglevel=", full_param, len_param)) {
2313 dbus_msglevel = (int)simple_strtol(data, NULL, 0);
2314 CONFIG_MSG("dbus_msglevel = 0x%X\n", dbus_msglevel);
2315 }
2316 #endif
2317 else if (!strncmp("android_msg_level=", full_param, len_param)) {
2318 android_msg_level = (int)simple_strtol(data, NULL, 0);
2319 CONFIG_MSG("android_msg_level = 0x%X\n", android_msg_level);
2320 }
2321 else if (!strncmp("config_msg_level=", full_param, len_param)) {
2322 config_msg_level = (int)simple_strtol(data, NULL, 0);
2323 CONFIG_MSG("config_msg_level = 0x%X\n", config_msg_level);
2324 }
2325 #ifdef WL_CFG80211
2326 else if (!strncmp("wl_dbg_level=", full_param, len_param)) {
2327 wl_dbg_level = (int)simple_strtol(data, NULL, 0);
2328 CONFIG_MSG("wl_dbg_level = 0x%X\n", wl_dbg_level);
2329 }
2330 #endif
2331 #if defined(WL_WIRELESS_EXT)
2332 else if (!strncmp("iw_msg_level=", full_param, len_param)) {
2333 iw_msg_level = (int)simple_strtol(data, NULL, 0);
2334 CONFIG_MSG("iw_msg_level = 0x%X\n", iw_msg_level);
2335 }
2336 #endif
2337 #if defined(DHD_DEBUG)
2338 else if (!strncmp("dhd_console_ms=", full_param, len_param)) {
2339 dhd->dhd_console_ms = (int)simple_strtol(data, NULL, 0);
2340 CONFIG_MSG("dhd_console_ms = 0x%X\n", dhd->dhd_console_ms);
2341 }
2342 #endif
2343 else
2344 return false;
2345
2346 return true;
2347 }
2348
2349 void
2350 dhd_conf_read_wme_ac_value(wme_param_t *wme, char *pick, int ac_val)
2351 {
2352 char *pick_tmp, *pch;
2353
2354 pick_tmp = pick;
2355 pch = bcmstrstr(pick_tmp, "aifsn ");
2356 if (pch) {
2357 wme->aifsn[ac_val] = (int)simple_strtol(pch+strlen("aifsn "), NULL, 0);
2358 CONFIG_MSG("ac_val=%d, aifsn=%d\n", ac_val, wme->aifsn[ac_val]);
2359 }
2360 pick_tmp = pick;
2361 pch = bcmstrstr(pick_tmp, "ecwmin ");
2362 if (pch) {
2363 wme->ecwmin[ac_val] = (int)simple_strtol(pch+strlen("ecwmin "), NULL, 0);
2364 CONFIG_MSG("ac_val=%d, ecwmin=%d\n", ac_val, wme->ecwmin[ac_val]);
2365 }
2366 pick_tmp = pick;
2367 pch = bcmstrstr(pick_tmp, "ecwmax ");
2368 if (pch) {
2369 wme->ecwmax[ac_val] = (int)simple_strtol(pch+strlen("ecwmax "), NULL, 0);
2370 CONFIG_MSG("ac_val=%d, ecwmax=%d\n", ac_val, wme->ecwmax[ac_val]);
2371 }
2372 pick_tmp = pick;
2373 pch = bcmstrstr(pick_tmp, "txop ");
2374 if (pch) {
2375 wme->txop[ac_val] = (int)simple_strtol(pch+strlen("txop "), NULL, 0);
2376 CONFIG_MSG("ac_val=%d, txop=0x%x\n", ac_val, wme->txop[ac_val]);
2377 }
2378
2379 }
2380
2381 bool
2382 dhd_conf_read_wme_ac_params(dhd_pub_t *dhd, char *full_param, uint len_param)
2383 {
2384 struct dhd_conf *conf = dhd->conf;
2385 char *data = full_param+len_param;
2386
2387 // wme_ac_sta_be=aifsn 1 ecwmin 2 ecwmax 3 txop 0x5e
2388 // wme_ac_sta_vo=aifsn 1 ecwmin 1 ecwmax 1 txop 0x5e
2389
2390 if (!strncmp("force_wme_ac=", full_param, len_param)) {
2391 conf->force_wme_ac = (int)simple_strtol(data, NULL, 10);
2392 CONFIG_MSG("force_wme_ac = %d\n", conf->force_wme_ac);
2393 }
2394 else if (!strncmp("wme_ac_sta_be=", full_param, len_param)) {
2395 dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_BE);
2396 }
2397 else if (!strncmp("wme_ac_sta_bk=", full_param, len_param)) {
2398 dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_BK);
2399 }
2400 else if (!strncmp("wme_ac_sta_vi=", full_param, len_param)) {
2401 dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_VI);
2402 }
2403 else if (!strncmp("wme_ac_sta_vo=", full_param, len_param)) {
2404 dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_VO);
2405 }
2406 else if (!strncmp("wme_ac_ap_be=", full_param, len_param)) {
2407 dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_BE);
2408 }
2409 else if (!strncmp("wme_ac_ap_bk=", full_param, len_param)) {
2410 dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_BK);
2411 }
2412 else if (!strncmp("wme_ac_ap_vi=", full_param, len_param)) {
2413 dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_VI);
2414 }
2415 else if (!strncmp("wme_ac_ap_vo=", full_param, len_param)) {
2416 dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_VO);
2417 }
2418 else
2419 return false;
2420
2421 return true;
2422 }
2423
2424 #ifdef BCMSDIO
2425 bool
2426 dhd_conf_read_fw_by_mac(dhd_pub_t *dhd, char *full_param, uint len_param)
2427 {
2428 int i, j;
2429 char *pch, *pick_tmp;
2430 wl_mac_list_t *mac_list;
2431 wl_mac_range_t *mac_range;
2432 struct dhd_conf *conf = dhd->conf;
2433 char *data = full_param+len_param;
2434
2435 /* Process fw_by_mac:
2436 * fw_by_mac=[fw_mac_num] \
2437 * [fw_name1] [mac_num1] [oui1-1] [nic_start1-1] [nic_end1-1] \
2438 * [oui1-1] [nic_start1-1] [nic_end1-1]... \
2439 * [oui1-n] [nic_start1-n] [nic_end1-n] \
2440 * [fw_name2] [mac_num2] [oui2-1] [nic_start2-1] [nic_end2-1] \
2441 * [oui2-1] [nic_start2-1] [nic_end2-1]... \
2442 * [oui2-n] [nic_start2-n] [nic_end2-n] \
2443 * Ex: fw_by_mac=2 \
2444 * fw_bcmdhd1.bin 2 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \
2445 * fw_bcmdhd2.bin 3 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \
2446 * 0x983B16 0x916157 0x916487
2447 */
2448
2449 if (!strncmp("fw_by_mac=", full_param, len_param)) {
2450 dhd_conf_free_mac_list(&conf->fw_by_mac);
2451 pick_tmp = data;
2452 pch = bcmstrtok(&pick_tmp, " ", 0);
2453 conf->fw_by_mac.count = (uint32)simple_strtol(pch, NULL, 0);
2454 if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->fw_by_mac.count,
2455 GFP_KERNEL))) {
2456 conf->fw_by_mac.count = 0;
2457 CONFIG_ERROR("kmalloc failed\n");
2458 }
2459 CONFIG_MSG("fw_count=%d\n", conf->fw_by_mac.count);
2460 conf->fw_by_mac.m_mac_list_head = mac_list;
2461 for (i=0; i<conf->fw_by_mac.count; i++) {
2462 pch = bcmstrtok(&pick_tmp, " ", 0);
2463 strcpy(mac_list[i].name, pch);
2464 pch = bcmstrtok(&pick_tmp, " ", 0);
2465 mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0);
2466 CONFIG_MSG("name=%s, mac_count=%d\n",
2467 mac_list[i].name, mac_list[i].count);
2468 if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count,
2469 GFP_KERNEL))) {
2470 mac_list[i].count = 0;
2471 CONFIG_ERROR("kmalloc failed\n");
2472 break;
2473 }
2474 mac_list[i].mac = mac_range;
2475 for (j=0; j<mac_list[i].count; j++) {
2476 pch = bcmstrtok(&pick_tmp, " ", 0);
2477 mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0);
2478 pch = bcmstrtok(&pick_tmp, " ", 0);
2479 mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0);
2480 pch = bcmstrtok(&pick_tmp, " ", 0);
2481 mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0);
2482 CONFIG_MSG("oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n",
2483 mac_range[j].oui, mac_range[j].nic_start, mac_range[j].nic_end);
2484 }
2485 }
2486 }
2487 else
2488 return false;
2489
2490 return true;
2491 }
2492
2493 bool
2494 dhd_conf_read_nv_by_mac(dhd_pub_t *dhd, char *full_param, uint len_param)
2495 {
2496 int i, j;
2497 char *pch, *pick_tmp;
2498 wl_mac_list_t *mac_list;
2499 wl_mac_range_t *mac_range;
2500 struct dhd_conf *conf = dhd->conf;
2501 char *data = full_param+len_param;
2502
2503 /* Process nv_by_mac:
2504 * [nv_by_mac]: The same format as fw_by_mac
2505 */
2506 if (!strncmp("nv_by_mac=", full_param, len_param)) {
2507 dhd_conf_free_mac_list(&conf->nv_by_mac);
2508 pick_tmp = data;
2509 pch = bcmstrtok(&pick_tmp, " ", 0);
2510 conf->nv_by_mac.count = (uint32)simple_strtol(pch, NULL, 0);
2511 if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_mac.count,
2512 GFP_KERNEL))) {
2513 conf->nv_by_mac.count = 0;
2514 CONFIG_ERROR("kmalloc failed\n");
2515 }
2516 CONFIG_MSG("nv_count=%d\n", conf->nv_by_mac.count);
2517 conf->nv_by_mac.m_mac_list_head = mac_list;
2518 for (i=0; i<conf->nv_by_mac.count; i++) {
2519 pch = bcmstrtok(&pick_tmp, " ", 0);
2520 strcpy(mac_list[i].name, pch);
2521 pch = bcmstrtok(&pick_tmp, " ", 0);
2522 mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0);
2523 CONFIG_MSG("name=%s, mac_count=%d\n",
2524 mac_list[i].name, mac_list[i].count);
2525 if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count,
2526 GFP_KERNEL))) {
2527 mac_list[i].count = 0;
2528 CONFIG_ERROR("kmalloc failed\n");
2529 break;
2530 }
2531 mac_list[i].mac = mac_range;
2532 for (j=0; j<mac_list[i].count; j++) {
2533 pch = bcmstrtok(&pick_tmp, " ", 0);
2534 mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0);
2535 pch = bcmstrtok(&pick_tmp, " ", 0);
2536 mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0);
2537 pch = bcmstrtok(&pick_tmp, " ", 0);
2538 mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0);
2539 CONFIG_MSG("oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n",
2540 mac_range[j].oui, mac_range[j].nic_start, mac_range[j].nic_end);
2541 }
2542 }
2543 }
2544 else
2545 return false;
2546
2547 return true;
2548 }
2549 #endif
2550
2551 bool
2552 dhd_conf_read_nv_by_chip(dhd_pub_t *dhd, char *full_param, uint len_param)
2553 {
2554 int i;
2555 char *pch, *pick_tmp;
2556 wl_chip_nv_path_t *chip_nv_path;
2557 struct dhd_conf *conf = dhd->conf;
2558 char *data = full_param+len_param;
2559
2560 /* Process nv_by_chip:
2561 * nv_by_chip=[nv_chip_num] \
2562 * [chip1] [chiprev1] [nv_name1] [chip2] [chiprev2] [nv_name2] \
2563 * Ex: nv_by_chip=2 \
2564 * 43430 0 nvram_ap6212.txt 43430 1 nvram_ap6212a.txt \
2565 */
2566 if (!strncmp("nv_by_chip=", full_param, len_param)) {
2567 dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
2568 pick_tmp = data;
2569 pch = bcmstrtok(&pick_tmp, " ", 0);
2570 conf->nv_by_chip.count = (uint32)simple_strtol(pch, NULL, 0);
2571 if (!(chip_nv_path = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_chip.count,
2572 GFP_KERNEL))) {
2573 conf->nv_by_chip.count = 0;
2574 CONFIG_ERROR("kmalloc failed\n");
2575 }
2576 CONFIG_MSG("nv_by_chip_count=%d\n", conf->nv_by_chip.count);
2577 conf->nv_by_chip.m_chip_nv_path_head = chip_nv_path;
2578 for (i=0; i<conf->nv_by_chip.count; i++) {
2579 pch = bcmstrtok(&pick_tmp, " ", 0);
2580 chip_nv_path[i].chip = (uint32)simple_strtol(pch, NULL, 0);
2581 pch = bcmstrtok(&pick_tmp, " ", 0);
2582 chip_nv_path[i].chiprev = (uint32)simple_strtol(pch, NULL, 0);
2583 pch = bcmstrtok(&pick_tmp, " ", 0);
2584 strcpy(chip_nv_path[i].name, pch);
2585 CONFIG_MSG("chip=0x%x, chiprev=%d, name=%s\n",
2586 chip_nv_path[i].chip, chip_nv_path[i].chiprev, chip_nv_path[i].name);
2587 }
2588 }
2589 else
2590 return false;
2591
2592 return true;
2593 }
2594
2595 bool
2596 dhd_conf_read_roam_params(dhd_pub_t *dhd, char *full_param, uint len_param)
2597 {
2598 struct dhd_conf *conf = dhd->conf;
2599 char *data = full_param+len_param;
2600
2601 if (!strncmp("roam_off=", full_param, len_param)) {
2602 if (!strncmp(data, "0", 1))
2603 conf->roam_off = 0;
2604 else
2605 conf->roam_off = 1;
2606 CONFIG_MSG("roam_off = %d\n", conf->roam_off);
2607 }
2608 else if (!strncmp("roam_off_suspend=", full_param, len_param)) {
2609 if (!strncmp(data, "0", 1))
2610 conf->roam_off_suspend = 0;
2611 else
2612 conf->roam_off_suspend = 1;
2613 CONFIG_MSG("roam_off_suspend = %d\n", conf->roam_off_suspend);
2614 }
2615 else if (!strncmp("roam_trigger=", full_param, len_param)) {
2616 conf->roam_trigger[0] = (int)simple_strtol(data, NULL, 10);
2617 CONFIG_MSG("roam_trigger = %d\n", conf->roam_trigger[0]);
2618 }
2619 else if (!strncmp("roam_scan_period=", full_param, len_param)) {
2620 conf->roam_scan_period[0] = (int)simple_strtol(data, NULL, 10);
2621 CONFIG_MSG("roam_scan_period = %d\n", conf->roam_scan_period[0]);
2622 }
2623 else if (!strncmp("roam_delta=", full_param, len_param)) {
2624 conf->roam_delta[0] = (int)simple_strtol(data, NULL, 10);
2625 CONFIG_MSG("roam_delta = %d\n", conf->roam_delta[0]);
2626 }
2627 else if (!strncmp("fullroamperiod=", full_param, len_param)) {
2628 conf->fullroamperiod = (int)simple_strtol(data, NULL, 10);
2629 CONFIG_MSG("fullroamperiod = %d\n", conf->fullroamperiod);
2630 } else
2631 return false;
2632
2633 return true;
2634 }
2635
2636 bool
2637 dhd_conf_read_country(dhd_pub_t *dhd, char *full_param, uint len_param)
2638 {
2639 struct dhd_conf *conf = dhd->conf;
2640 country_list_t *country_next = NULL, *country;
2641 int i, count = 0;
2642 char *pch, *pick_tmp, *pick_tmp2;
2643 char *data = full_param+len_param;
2644 uint len_data = strlen(data);
2645
2646 /* Process country_list:
2647 * country_list=[country1]:[ccode1]/[regrev1],
2648 * [country2]:[ccode2]/[regrev2] \
2649 * Ex: country_list=US:US/0, TW:TW/1
2650 */
2651 if (!strncmp("ccode=", full_param, len_param)) {
2652 len_data = min((uint)WLC_CNTRY_BUF_SZ, len_data);
2653 memset(&conf->cspec, 0, sizeof(wl_country_t));
2654 memcpy(conf->cspec.country_abbrev, data, len_data);
2655 memcpy(conf->cspec.ccode, data, len_data);
2656 CONFIG_MSG("ccode = %s\n", conf->cspec.ccode);
2657 }
2658 else if (!strncmp("regrev=", full_param, len_param)) {
2659 conf->cspec.rev = (int32)simple_strtol(data, NULL, 10);
2660 CONFIG_MSG("regrev = %d\n", conf->cspec.rev);
2661 }
2662 else if (!strncmp("country_list=", full_param, len_param)) {
2663 dhd_conf_free_country_list(conf);
2664 pick_tmp = data;
2665 for (i=0; i<CONFIG_COUNTRY_LIST_SIZE; i++) {
2666 pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0);
2667 if (!pick_tmp2)
2668 break;
2669 pch = bcmstrtok(&pick_tmp2, ":", 0);
2670 if (!pch)
2671 break;
2672 country = NULL;
2673 if (!(country = kmalloc(sizeof(country_list_t), GFP_KERNEL))) {
2674 CONFIG_ERROR("kmalloc failed\n");
2675 break;
2676 }
2677 memset(country, 0, sizeof(country_list_t));
2678
2679 memcpy(country->cspec.country_abbrev, pch, 2);
2680 pch = bcmstrtok(&pick_tmp2, "/", 0);
2681 if (!pch) {
2682 kfree(country);
2683 break;
2684 }
2685 memcpy(country->cspec.ccode, pch, 2);
2686 pch = bcmstrtok(&pick_tmp2, "/", 0);
2687 if (!pch) {
2688 kfree(country);
2689 break;
2690 }
2691 country->cspec.rev = (int32)simple_strtol(pch, NULL, 10);
2692 count++;
2693 if (!conf->country_head) {
2694 conf->country_head = country;
2695 country_next = country;
2696 } else {
2697 country_next->next = country;
2698 country_next = country;
2699 }
2700 CONFIG_TRACE("abbrev=%s, ccode=%s, regrev=%d\n",
2701 country->cspec.country_abbrev, country->cspec.ccode, country->cspec.rev);
2702 }
2703 CONFIG_MSG("%d country in list\n", count);
2704 }
2705 else
2706 return false;
2707
2708 return true;
2709 }
2710
2711 bool
2712 dhd_conf_read_mchan_params(dhd_pub_t *dhd, char *full_param, uint len_param)
2713 {
2714 int i;
2715 char *pch, *pick_tmp, *pick_tmp2;
2716 struct dhd_conf *conf = dhd->conf;
2717 mchan_params_t *mchan_next = NULL, *mchan;
2718 char *data = full_param+len_param;
2719
2720 /* Process mchan_bw:
2721 * mchan_bw=[val]/[any/go/gc]/[any/source/sink]
2722 * Ex: mchan_bw=80/go/source, 30/gc/sink
2723 */
2724 if (!strncmp("mchan_bw=", full_param, len_param)) {
2725 dhd_conf_free_mchan_list(conf);
2726 pick_tmp = data;
2727 for (i=0; i<MCHAN_MAX_NUM; i++) {
2728 pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0);
2729 if (!pick_tmp2)
2730 break;
2731 pch = bcmstrtok(&pick_tmp2, "/", 0);
2732 if (!pch)
2733 break;
2734
2735 mchan = NULL;
2736 if (!(mchan = kmalloc(sizeof(mchan_params_t), GFP_KERNEL))) {
2737 CONFIG_ERROR("kmalloc failed\n");
2738 break;
2739 }
2740 memset(mchan, 0, sizeof(mchan_params_t));
2741
2742 mchan->bw = (int)simple_strtol(pch, NULL, 0);
2743 if (mchan->bw < 0 || mchan->bw > 100) {
2744 CONFIG_ERROR("wrong bw %d\n", mchan->bw);
2745 kfree(mchan);
2746 break;
2747 }
2748
2749 pch = bcmstrtok(&pick_tmp2, "/", 0);
2750 if (!pch) {
2751 kfree(mchan);
2752 break;
2753 } else {
2754 if (bcmstrstr(pch, "any")) {
2755 mchan->p2p_mode = -1;
2756 } else if (bcmstrstr(pch, "go")) {
2757 mchan->p2p_mode = WL_P2P_IF_GO;
2758 } else if (bcmstrstr(pch, "gc")) {
2759 mchan->p2p_mode = WL_P2P_IF_CLIENT;
2760 }
2761 }
2762 pch = bcmstrtok(&pick_tmp2, "/", 0);
2763 if (!pch) {
2764 kfree(mchan);
2765 break;
2766 } else {
2767 if (bcmstrstr(pch, "any")) {
2768 mchan->miracast_mode = -1;
2769 } else if (bcmstrstr(pch, "source")) {
2770 mchan->miracast_mode = MIRACAST_SOURCE;
2771 } else if (bcmstrstr(pch, "sink")) {
2772 mchan->miracast_mode = MIRACAST_SINK;
2773 }
2774 }
2775 if (!conf->mchan) {
2776 conf->mchan = mchan;
2777 mchan_next = mchan;
2778 } else {
2779 mchan_next->next = mchan;
2780 mchan_next = mchan;
2781 }
2782 CONFIG_TRACE("mchan_bw=%d/%d/%d\n", mchan->bw,mchan->p2p_mode,
2783 mchan->miracast_mode);
2784 }
2785 }
2786 else
2787 return false;
2788
2789 return true;
2790 }
2791
2792 #ifdef PKT_FILTER_SUPPORT
2793 bool
2794 dhd_conf_read_pkt_filter(dhd_pub_t *dhd, char *full_param, uint len_param)
2795 {
2796 struct dhd_conf *conf = dhd->conf;
2797 char *data = full_param+len_param;
2798 char *pch, *pick_tmp;
2799 int i;
2800
2801 /* Process pkt filter:
2802 * 1) pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000
2803 * 2) pkt_filter_delete=100, 102, 103, 104, 105
2804 * 3) magic_pkt_filter_add=141 0 1 12
2805 */
2806 if (!strncmp("dhd_master_mode=", full_param, len_param)) {
2807 if (!strncmp(data, "0", 1))
2808 dhd_master_mode = FALSE;
2809 else
2810 dhd_master_mode = TRUE;
2811 CONFIG_MSG("dhd_master_mode = %d\n", dhd_master_mode);
2812 }
2813 else if (!strncmp("pkt_filter_add=", full_param, len_param)) {
2814 pick_tmp = data;
2815 pch = bcmstrtok(&pick_tmp, ",.-", 0);
2816 i=0;
2817 while (pch != NULL && i<DHD_CONF_FILTER_MAX) {
2818 strcpy(&conf->pkt_filter_add.filter[i][0], pch);
2819 CONFIG_MSG("pkt_filter_add[%d][] = %s\n",
2820 i, &conf->pkt_filter_add.filter[i][0]);
2821 pch = bcmstrtok(&pick_tmp, ",.-", 0);
2822 i++;
2823 }
2824 conf->pkt_filter_add.count = i;
2825 }
2826 else if (!strncmp("pkt_filter_delete=", full_param, len_param) ||
2827 !strncmp("pkt_filter_del=", full_param, len_param)) {
2828 pick_tmp = data;
2829 pch = bcmstrtok(&pick_tmp, " ,.-", 0);
2830 i=0;
2831 while (pch != NULL && i<DHD_CONF_FILTER_MAX) {
2832 conf->pkt_filter_del.id[i] = (uint32)simple_strtol(pch, NULL, 10);
2833 pch = bcmstrtok(&pick_tmp, " ,.-", 0);
2834 i++;
2835 }
2836 conf->pkt_filter_del.count = i;
2837 CONFIG_MSG("pkt_filter_del id = ");
2838 for (i=0; i<conf->pkt_filter_del.count; i++)
2839 printf("%d ", conf->pkt_filter_del.id[i]);
2840 printf("\n");
2841 }
2842 else if (!strncmp("magic_pkt_filter_add=", full_param, len_param)) {
2843 if (conf->magic_pkt_filter_add) {
2844 kfree(conf->magic_pkt_filter_add);
2845 conf->magic_pkt_filter_add = NULL;
2846 }
2847 if (!(conf->magic_pkt_filter_add = kmalloc(MAGIC_PKT_FILTER_LEN, GFP_KERNEL))) {
2848 CONFIG_ERROR("kmalloc failed\n");
2849 } else {
2850 memset(conf->magic_pkt_filter_add, 0, MAGIC_PKT_FILTER_LEN);
2851 strcpy(conf->magic_pkt_filter_add, data);
2852 CONFIG_MSG("magic_pkt_filter_add = %s\n", conf->magic_pkt_filter_add);
2853 }
2854 }
2855 else
2856 return false;
2857
2858 return true;
2859 }
2860 #endif
2861
2862 #ifdef ISAM_PREINIT
2863 #if !defined(WL_EXT_IAPSTA)
2864 #error "WL_EXT_IAPSTA should be defined to enable ISAM_PREINIT"
2865 #endif /* !WL_EXT_IAPSTA */
2866 /*
2867 * isam_init=mode [sta|ap|apsta|dualap] vifname [wlan1]
2868 * isam_config=ifname [wlan0|wlan1] ssid [xxx] chan [x]
2869 hidden [y|n] maxassoc [x]
2870 amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]
2871 emode [none|wep|tkip|aes|tkipaes]
2872 key [xxxxx]
2873 * isam_enable=ifname [wlan0|wlan1]
2874 */
2875 bool
2876 dhd_conf_read_isam(dhd_pub_t *dhd, char *full_param, uint len_param)
2877 {
2878 struct dhd_conf *conf = dhd->conf;
2879 char *data = full_param+len_param;
2880
2881 if (!strncmp("isam_init=", full_param, len_param)) {
2882 sprintf(conf->isam_init, "isam_init %s", data);
2883 CONFIG_MSG("isam_init=%s\n", conf->isam_init);
2884 }
2885 else if (!strncmp("isam_config=", full_param, len_param)) {
2886 sprintf(conf->isam_config, "isam_config %s", data);
2887 CONFIG_MSG("isam_config=%s\n", conf->isam_config);
2888 }
2889 else if (!strncmp("isam_enable=", full_param, len_param)) {
2890 sprintf(conf->isam_enable, "isam_enable %s", data);
2891 CONFIG_MSG("isam_enable=%s\n", conf->isam_enable);
2892 }
2893 else
2894 return false;
2895
2896 return true;
2897 }
2898 #endif
2899
2900 #ifdef IDHCP
2901 bool
2902 dhd_conf_read_dhcp_params(dhd_pub_t *dhd, char *full_param, uint len_param)
2903 {
2904 struct dhd_conf *conf = dhd->conf;
2905 char *data = full_param+len_param;
2906 struct ipv4_addr ipa_set;
2907
2908 if (!strncmp("dhcpc_enable=", full_param, len_param)) {
2909 conf->dhcpc_enable = (int)simple_strtol(data, NULL, 10);
2910 CONFIG_MSG("dhcpc_enable = %d\n", conf->dhcpc_enable);
2911 }
2912 else if (!strncmp("dhcpd_enable=", full_param, len_param)) {
2913 conf->dhcpd_enable = (int)simple_strtol(data, NULL, 10);
2914 CONFIG_MSG("dhcpd_enable = %d\n", conf->dhcpd_enable);
2915 }
2916 else if (!strncmp("dhcpd_ip_addr=", full_param, len_param)) {
2917 if (!bcm_atoipv4(data, &ipa_set)) {
2918 CONFIG_ERROR("dhcpd_ip_addr adress setting failed.n");
2919 return false;
2920 }
2921 memcpy(&conf->dhcpd_ip_addr, &ipa_set, sizeof(struct ipv4_addr));
2922 CONFIG_MSG("dhcpd_ip_addr = %s\n", data);
2923 }
2924 else if (!strncmp("dhcpd_ip_mask=", full_param, len_param)) {
2925 if (!bcm_atoipv4(data, &ipa_set)) {
2926 CONFIG_ERROR("dhcpd_ip_mask adress setting failed\n");
2927 return false;
2928 }
2929 memcpy(&conf->dhcpd_ip_mask, &ipa_set, sizeof(struct ipv4_addr));
2930 CONFIG_MSG("dhcpd_ip_mask = %s\n", data);
2931 }
2932 else if (!strncmp("dhcpd_ip_start=", full_param, len_param)) {
2933 if (!bcm_atoipv4(data, &ipa_set)) {
2934 CONFIG_ERROR("dhcpd_ip_start adress setting failed\n");
2935 return false;
2936 }
2937 memcpy(&conf->dhcpd_ip_start, &ipa_set, sizeof(struct ipv4_addr));
2938 CONFIG_MSG("dhcpd_ip_start = %s\n", data);
2939 }
2940 else if (!strncmp("dhcpd_ip_end=", full_param, len_param)) {
2941 if (!bcm_atoipv4(data, &ipa_set)) {
2942 CONFIG_ERROR("dhcpd_ip_end adress setting failed\n");
2943 return false;
2944 }
2945 memcpy(&conf->dhcpd_ip_end, &ipa_set, sizeof(struct ipv4_addr));
2946 CONFIG_MSG("dhcpd_ip_end = %s\n", data);
2947 }
2948 else
2949 return false;
2950
2951 return true;
2952 }
2953 #endif
2954
2955 #ifdef BCMSDIO
2956 bool
2957 dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
2958 {
2959 struct dhd_conf *conf = dhd->conf;
2960 char *data = full_param+len_param;
2961
2962 if (!strncmp("dhd_doflow=", full_param, len_param)) {
2963 if (!strncmp(data, "0", 1))
2964 dhd_doflow = FALSE;
2965 else
2966 dhd_doflow = TRUE;
2967 CONFIG_MSG("dhd_doflow = %d\n", dhd_doflow);
2968 }
2969 else if (!strncmp("dhd_slpauto=", full_param, len_param) ||
2970 !strncmp("kso_enable=", full_param, len_param)) {
2971 if (!strncmp(data, "0", 1))
2972 dhd_slpauto = FALSE;
2973 else
2974 dhd_slpauto = TRUE;
2975 CONFIG_MSG("dhd_slpauto = %d\n", dhd_slpauto);
2976 }
2977 else if (!strncmp("use_rxchain=", full_param, len_param)) {
2978 conf->use_rxchain = (int)simple_strtol(data, NULL, 10);
2979 CONFIG_MSG("use_rxchain = %d\n", conf->use_rxchain);
2980 }
2981 else if (!strncmp("dhd_txminmax=", full_param, len_param)) {
2982 conf->dhd_txminmax = (uint)simple_strtol(data, NULL, 10);
2983 CONFIG_MSG("dhd_txminmax = %d\n", conf->dhd_txminmax);
2984 }
2985 else if (!strncmp("txinrx_thres=", full_param, len_param)) {
2986 conf->txinrx_thres = (int)simple_strtol(data, NULL, 10);
2987 CONFIG_MSG("txinrx_thres = %d\n", conf->txinrx_thres);
2988 }
2989 #if defined(HW_OOB)
2990 else if (!strncmp("oob_enabled_later=", full_param, len_param)) {
2991 if (!strncmp(data, "0", 1))
2992 conf->oob_enabled_later = FALSE;
2993 else
2994 conf->oob_enabled_later = TRUE;
2995 CONFIG_MSG("oob_enabled_later = %d\n", conf->oob_enabled_later);
2996 }
2997 #endif
2998 else if (!strncmp("dpc_cpucore=", full_param, len_param)) {
2999 conf->dpc_cpucore = (int)simple_strtol(data, NULL, 10);
3000 CONFIG_MSG("dpc_cpucore = %d\n", conf->dpc_cpucore);
3001 }
3002 else if (!strncmp("rxf_cpucore=", full_param, len_param)) {
3003 conf->rxf_cpucore = (int)simple_strtol(data, NULL, 10);
3004 CONFIG_MSG("rxf_cpucore = %d\n", conf->rxf_cpucore);
3005 }
3006 #if defined(BCMSDIOH_TXGLOM)
3007 else if (!strncmp("txglomsize=", full_param, len_param)) {
3008 conf->txglomsize = (uint)simple_strtol(data, NULL, 10);
3009 if (conf->txglomsize > SDPCM_MAXGLOM_SIZE)
3010 conf->txglomsize = SDPCM_MAXGLOM_SIZE;
3011 CONFIG_MSG("txglomsize = %d\n", conf->txglomsize);
3012 }
3013 else if (!strncmp("txglom_ext=", full_param, len_param)) {
3014 if (!strncmp(data, "0", 1))
3015 conf->txglom_ext = FALSE;
3016 else
3017 conf->txglom_ext = TRUE;
3018 CONFIG_MSG("txglom_ext = %d\n", conf->txglom_ext);
3019 if (conf->txglom_ext) {
3020 if ((conf->chip == BCM43362_CHIP_ID) || (conf->chip == BCM4330_CHIP_ID))
3021 conf->txglom_bucket_size = 1680;
3022 else if (conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
3023 conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID)
3024 conf->txglom_bucket_size = 1684;
3025 }
3026 CONFIG_MSG("txglom_bucket_size = %d\n", conf->txglom_bucket_size);
3027 }
3028 else if (!strncmp("bus:rxglom=", full_param, len_param)) {
3029 if (!strncmp(data, "0", 1))
3030 conf->bus_rxglom = FALSE;
3031 else
3032 conf->bus_rxglom = TRUE;
3033 CONFIG_MSG("bus:rxglom = %d\n", conf->bus_rxglom);
3034 }
3035 else if (!strncmp("deferred_tx_len=", full_param, len_param)) {
3036 conf->deferred_tx_len = (int)simple_strtol(data, NULL, 10);
3037 CONFIG_MSG("deferred_tx_len = %d\n", conf->deferred_tx_len);
3038 }
3039 else if (!strncmp("txctl_tmo_fix=", full_param, len_param)) {
3040 conf->txctl_tmo_fix = (int)simple_strtol(data, NULL, 0);
3041 CONFIG_MSG("txctl_tmo_fix = %d\n", conf->txctl_tmo_fix);
3042 }
3043 else if (!strncmp("tx_max_offset=", full_param, len_param)) {
3044 conf->tx_max_offset = (int)simple_strtol(data, NULL, 10);
3045 CONFIG_MSG("tx_max_offset = %d\n", conf->tx_max_offset);
3046 }
3047 else if (!strncmp("txglom_mode=", full_param, len_param)) {
3048 if (!strncmp(data, "0", 1))
3049 conf->txglom_mode = FALSE;
3050 else
3051 conf->txglom_mode = TRUE;
3052 CONFIG_MSG("txglom_mode = %d\n", conf->txglom_mode);
3053 }
3054 #if defined(SDIO_ISR_THREAD)
3055 else if (!strncmp("intr_extn=", full_param, len_param)) {
3056 if (!strncmp(data, "0", 1))
3057 conf->intr_extn = FALSE;
3058 else
3059 conf->intr_extn = TRUE;
3060 CONFIG_MSG("intr_extn = %d\n", conf->intr_extn);
3061 }
3062 #endif
3063 #ifdef BCMSDIO_RXLIM_POST
3064 else if (!strncmp("rxlim_en=", full_param, len_param)) {
3065 if (!strncmp(data, "0", 1))
3066 conf->rxlim_en = FALSE;
3067 else
3068 conf->rxlim_en = TRUE;
3069 CONFIG_MSG("rxlim_en = %d\n", conf->rxlim_en);
3070 }
3071 #endif
3072 #endif
3073 #ifdef MINIME
3074 else if (!strncmp("ramsize=", full_param, len_param)) {
3075 conf->ramsize = (uint32)simple_strtol(data, NULL, 0);
3076 CONFIG_MSG("ramsize = %d\n", conf->ramsize);
3077 }
3078 #endif
3079 else
3080 return false;
3081
3082 return true;
3083 }
3084 #endif
3085
3086 #ifdef BCMPCIE
3087 bool
3088 dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param)
3089 {
3090 struct dhd_conf *conf = dhd->conf;
3091 char *data = full_param+len_param;
3092
3093 if (!strncmp("bus:deepsleep_disable=", full_param, len_param)) {
3094 if (!strncmp(data, "0", 1))
3095 conf->bus_deepsleep_disable = 0;
3096 else
3097 conf->bus_deepsleep_disable = 1;
3098 CONFIG_MSG("bus:deepsleep_disable = %d\n", conf->bus_deepsleep_disable);
3099 }
3100 else
3101 return false;
3102
3103 return true;
3104 }
3105 #endif
3106
3107 bool
3108 dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param)
3109 {
3110 struct dhd_conf *conf = dhd->conf;
3111 char *data = full_param+len_param;
3112
3113 if (!strncmp("deepsleep=", full_param, len_param)) {
3114 if (!strncmp(data, "1", 1))
3115 conf->deepsleep = TRUE;
3116 else
3117 conf->deepsleep = FALSE;
3118 CONFIG_MSG("deepsleep = %d\n", conf->deepsleep);
3119 }
3120 else if (!strncmp("PM=", full_param, len_param)) {
3121 conf->pm = (int)simple_strtol(data, NULL, 10);
3122 CONFIG_MSG("PM = %d\n", conf->pm);
3123 }
3124 else if (!strncmp("pm_in_suspend=", full_param, len_param)) {
3125 conf->pm_in_suspend = (int)simple_strtol(data, NULL, 10);
3126 CONFIG_MSG("pm_in_suspend = %d\n", conf->pm_in_suspend);
3127 }
3128 else if (!strncmp("suspend_mode=", full_param, len_param)) {
3129 conf->suspend_mode = (int)simple_strtol(data, NULL, 0);
3130 CONFIG_MSG("suspend_mode = %d\n", conf->suspend_mode);
3131 if (conf->suspend_mode == PM_NOTIFIER)
3132 conf->insuspend |= (NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND);
3133 }
3134 else if (!strncmp("suspend_bcn_li_dtim=", full_param, len_param)) {
3135 conf->suspend_bcn_li_dtim = (int)simple_strtol(data, NULL, 10);
3136 CONFIG_MSG("suspend_bcn_li_dtim = %d\n", conf->suspend_bcn_li_dtim);
3137 }
3138 else if (!strncmp("xmit_in_suspend=", full_param, len_param)) {
3139 if (!strncmp(data, "1", 1))
3140 conf->insuspend &= ~NO_TXDATA_IN_SUSPEND;
3141 else
3142 conf->insuspend |= NO_TXDATA_IN_SUSPEND;
3143 CONFIG_MSG("insuspend = 0x%x\n", conf->insuspend);
3144 }
3145 else if (!strncmp("insuspend=", full_param, len_param)) {
3146 conf->insuspend = (int)simple_strtol(data, NULL, 0);
3147 CONFIG_MSG("insuspend = 0x%x\n", conf->insuspend);
3148 }
3149 #ifdef WL_EXT_WOWL
3150 else if (!strncmp("wowl=", full_param, len_param)) {
3151 conf->wowl = (int)simple_strtol(data, NULL, 0);
3152 CONFIG_MSG("wowl = 0x%x\n", conf->wowl);
3153 }
3154 #endif
3155 else
3156 return false;
3157
3158 return true;
3159 }
3160
3161 #ifdef GET_CUSTOM_MAC_FROM_CONFIG
3162 int
3163 bcm_str2hex(const char *p, char *ea, int size)
3164 {
3165 int i = 0;
3166 char *ep;
3167
3168 for (;;) {
3169 ea[i++] = (char) bcm_strtoul(p, &ep, 16);
3170 p = ep;
3171 if (!*p++ || i == size)
3172 break;
3173 }
3174
3175 return (i == size);
3176 }
3177 #endif
3178
3179 bool
3180 dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
3181 {
3182 struct dhd_conf *conf = dhd->conf;
3183 char *data = full_param+len_param;
3184 char *pch, *pick_tmp;
3185 int i;
3186 #ifdef GET_CUSTOM_MAC_FROM_CONFIG
3187 struct ether_addr ea_addr;
3188 char macpad[56];
3189 #endif
3190
3191 if (!strncmp("dhd_poll=", full_param, len_param)) {
3192 if (!strncmp(data, "0", 1))
3193 conf->dhd_poll = 0;
3194 else
3195 conf->dhd_poll = 1;
3196 CONFIG_MSG("dhd_poll = %d\n", conf->dhd_poll);
3197 }
3198 else if (!strncmp("dhd_watchdog_ms=", full_param, len_param)) {
3199 dhd_watchdog_ms = (int)simple_strtol(data, NULL, 10);
3200 CONFIG_MSG("dhd_watchdog_ms = %d\n", dhd_watchdog_ms);
3201 }
3202 else if (!strncmp("band=", full_param, len_param)) {
3203 /* Process band:
3204 * band=a for 5GHz only and band=b for 2.4GHz only
3205 */
3206 if (!strcmp(data, "b"))
3207 conf->band = WLC_BAND_2G;
3208 else if (!strcmp(data, "a"))
3209 conf->band = WLC_BAND_5G;
3210 else
3211 conf->band = WLC_BAND_AUTO;
3212 CONFIG_MSG("band = %d\n", conf->band);
3213 }
3214 else if (!strncmp("bw_cap_2g=", full_param, len_param)) {
3215 conf->bw_cap[0] = (uint)simple_strtol(data, NULL, 0);
3216 CONFIG_MSG("bw_cap_2g = %d\n", conf->bw_cap[0]);
3217 }
3218 else if (!strncmp("bw_cap_5g=", full_param, len_param)) {
3219 conf->bw_cap[1] = (uint)simple_strtol(data, NULL, 0);
3220 CONFIG_MSG("bw_cap_5g = %d\n", conf->bw_cap[1]);
3221 }
3222 else if (!strncmp("bw_cap=", full_param, len_param)) {
3223 pick_tmp = data;
3224 pch = bcmstrtok(&pick_tmp, " ,.-", 0);
3225 if (pch != NULL) {
3226 conf->bw_cap[0] = (uint32)simple_strtol(pch, NULL, 0);
3227 CONFIG_MSG("bw_cap 2g = %d\n", conf->bw_cap[0]);
3228 }
3229 pch = bcmstrtok(&pick_tmp, " ,.-", 0);
3230 if (pch != NULL) {
3231 conf->bw_cap[1] = (uint32)simple_strtol(pch, NULL, 0);
3232 CONFIG_MSG("bw_cap 5g = %d\n", conf->bw_cap[1]);
3233 }
3234 }
3235 else if (!strncmp("channels=", full_param, len_param)) {
3236 pick_tmp = data;
3237 pch = bcmstrtok(&pick_tmp, " ,.-", 0);
3238 i=0;
3239 while (pch != NULL && i<WL_NUMCHANNELS) {
3240 conf->channels.channel[i] = (uint32)simple_strtol(pch, NULL, 10);
3241 pch = bcmstrtok(&pick_tmp, " ,.-", 0);
3242 i++;
3243 }
3244 conf->channels.count = i;
3245 CONFIG_MSG("channels = ");
3246 for (i=0; i<conf->channels.count; i++)
3247 printf("%d ", conf->channels.channel[i]);
3248 printf("\n");
3249 }
3250 else if (!strncmp("keep_alive_period=", full_param, len_param)) {
3251 conf->keep_alive_period = (uint)simple_strtol(data, NULL, 10);
3252 CONFIG_MSG("keep_alive_period = %d\n", conf->keep_alive_period);
3253 }
3254 #ifdef ARP_OFFLOAD_SUPPORT
3255 else if (!strncmp("garp=", full_param, len_param)) {
3256 if (!strncmp(data, "0", 1))
3257 conf->garp = FALSE;
3258 else
3259 conf->garp = TRUE;
3260 CONFIG_MSG("garp = %d\n", conf->garp);
3261 }
3262 #endif
3263 else if (!strncmp("srl=", full_param, len_param)) {
3264 conf->srl = (int)simple_strtol(data, NULL, 10);
3265 CONFIG_MSG("srl = %d\n", conf->srl);
3266 }
3267 else if (!strncmp("lrl=", full_param, len_param)) {
3268 conf->lrl = (int)simple_strtol(data, NULL, 10);
3269 CONFIG_MSG("lrl = %d\n", conf->lrl);
3270 }
3271 else if (!strncmp("bcn_timeout=", full_param, len_param)) {
3272 conf->bcn_timeout= (uint)simple_strtol(data, NULL, 10);
3273 CONFIG_MSG("bcn_timeout = %d\n", conf->bcn_timeout);
3274 }
3275 else if (!strncmp("frameburst=", full_param, len_param)) {
3276 conf->frameburst = (int)simple_strtol(data, NULL, 10);
3277 CONFIG_MSG("frameburst = %d\n", conf->frameburst);
3278 }
3279 else if (!strncmp("disable_proptx=", full_param, len_param)) {
3280 conf->disable_proptx = (int)simple_strtol(data, NULL, 10);
3281 CONFIG_MSG("disable_proptx = %d\n", conf->disable_proptx);
3282 }
3283 #ifdef DHDTCPACK_SUPPRESS
3284 else if (!strncmp("tcpack_sup_mode=", full_param, len_param)) {
3285 conf->tcpack_sup_mode = (uint)simple_strtol(data, NULL, 10);
3286 CONFIG_MSG("tcpack_sup_mode = %d\n", conf->tcpack_sup_mode);
3287 }
3288 #endif
3289 else if (!strncmp("pktprio8021x=", full_param, len_param)) {
3290 conf->pktprio8021x = (int)simple_strtol(data, NULL, 10);
3291 CONFIG_MSG("pktprio8021x = %d\n", conf->pktprio8021x);
3292 }
3293 #if defined(BCMSDIO) || defined(BCMPCIE)
3294 else if (!strncmp("dhd_txbound=", full_param, len_param)) {
3295 dhd_txbound = (uint)simple_strtol(data, NULL, 10);
3296 CONFIG_MSG("dhd_txbound = %d\n", dhd_txbound);
3297 }
3298 else if (!strncmp("dhd_rxbound=", full_param, len_param)) {
3299 dhd_rxbound = (uint)simple_strtol(data, NULL, 10);
3300 CONFIG_MSG("dhd_rxbound = %d\n", dhd_rxbound);
3301 }
3302 #endif
3303 else if (!strncmp("orphan_move=", full_param, len_param)) {
3304 conf->orphan_move = (int)simple_strtol(data, NULL, 10);
3305 CONFIG_MSG("orphan_move = %d\n", conf->orphan_move);
3306 }
3307 else if (!strncmp("tsq=", full_param, len_param)) {
3308 conf->tsq = (int)simple_strtol(data, NULL, 10);
3309 CONFIG_MSG("tsq = %d\n", conf->tsq);
3310 }
3311 else if (!strncmp("ctrl_resched=", full_param, len_param)) {
3312 conf->ctrl_resched = (int)simple_strtol(data, NULL, 10);
3313 CONFIG_MSG("ctrl_resched = %d\n", conf->ctrl_resched);
3314 }
3315 else if (!strncmp("in4way=", full_param, len_param)) {
3316 conf->in4way = (int)simple_strtol(data, NULL, 0);
3317 CONFIG_MSG("in4way = 0x%x\n", conf->in4way);
3318 }
3319 else if (!strncmp("wl_preinit=", full_param, len_param)) {
3320 if (conf->wl_preinit) {
3321 kfree(conf->wl_preinit);
3322 conf->wl_preinit = NULL;
3323 }
3324 if (!(conf->wl_preinit = kmalloc(len_param+1, GFP_KERNEL))) {
3325 CONFIG_ERROR("kmalloc failed\n");
3326 } else {
3327 memset(conf->wl_preinit, 0, len_param+1);
3328 strcpy(conf->wl_preinit, data);
3329 CONFIG_MSG("wl_preinit = %s\n", conf->wl_preinit);
3330 }
3331 }
3332 else if (!strncmp("wl_suspend=", full_param, len_param)) {
3333 if (conf->wl_suspend) {
3334 kfree(conf->wl_suspend);
3335 conf->wl_suspend = NULL;
3336 }
3337 if (!(conf->wl_suspend = kmalloc(len_param+1, GFP_KERNEL))) {
3338 CONFIG_ERROR("kmalloc failed\n");
3339 } else {
3340 memset(conf->wl_suspend, 0, len_param+1);
3341 strcpy(conf->wl_suspend, data);
3342 CONFIG_MSG("wl_suspend = %s\n", conf->wl_suspend);
3343 }
3344 }
3345 else if (!strncmp("wl_resume=", full_param, len_param)) {
3346 if (conf->wl_resume) {
3347 kfree(conf->wl_resume);
3348 conf->wl_resume = NULL;
3349 }
3350 if (!(conf->wl_resume = kmalloc(len_param+1, GFP_KERNEL))) {
3351 CONFIG_ERROR("kmalloc failed\n");
3352 } else {
3353 memset(conf->wl_resume, 0, len_param+1);
3354 strcpy(conf->wl_resume, data);
3355 CONFIG_MSG("wl_resume = %s\n", conf->wl_resume);
3356 }
3357 }
3358 #ifdef GET_CUSTOM_MAC_FROM_CONFIG
3359 else if (!strncmp("mac=", full_param, len_param)) {
3360 if (!bcm_ether_atoe(data, &ea_addr)) {
3361 CONFIG_ERROR("mac adress read error");
3362 return false;
3363 }
3364 memcpy(&conf->hw_ether, &ea_addr, ETHER_ADDR_LEN);
3365 CONFIG_MSG("mac = %s\n", data);
3366 }
3367 else if (!strncmp("macpad=", full_param, len_param)) {
3368 if (!bcm_str2hex(data, macpad, sizeof(macpad))) {
3369 CONFIG_ERROR("macpad adress read error");
3370 return false;
3371 }
3372 memcpy(&conf->hw_ether[ETHER_ADDR_LEN], macpad, sizeof(macpad));
3373 if (config_msg_level & CONFIG_TRACE_LEVEL) {
3374 printf("macpad =\n");
3375 for (i=0; i<sizeof(macpad); i++) {
3376 printf("0x%02x, ", conf->hw_ether[ETHER_ADDR_LEN+i]);
3377 if ((i+1)%8 == 0)
3378 printf("\n");
3379 }
3380 }
3381 }
3382 #endif
3383 #ifdef PROPTX_MAXCOUNT
3384 else if (!strncmp("proptx_maxcnt_2g=", full_param, len_param)) {
3385 conf->proptx_maxcnt_2g = (int)simple_strtol(data, NULL, 0);
3386 CONFIG_MSG("proptx_maxcnt_2g = 0x%x\n", conf->proptx_maxcnt_2g);
3387 }
3388 else if (!strncmp("proptx_maxcnt_5g=", full_param, len_param)) {
3389 conf->proptx_maxcnt_5g = (int)simple_strtol(data, NULL, 0);
3390 CONFIG_MSG("proptx_maxcnt_5g = 0x%x\n", conf->proptx_maxcnt_5g);
3391 }
3392 #endif
3393 #ifdef HOST_TPUT_TEST
3394 else if (!strncmp("data_drop_mode=", full_param, len_param)) {
3395 conf->data_drop_mode = (int)simple_strtol(data, NULL, 0);
3396 CONFIG_MSG("data_drop_mode = 0x%x\n", conf->data_drop_mode);
3397 }
3398 #endif
3399 else
3400 return false;
3401
3402 return true;
3403 }
3404
3405 static int askey_dhd_conf_read_unifykeys_wifi_disable_5g_band(dhd_pub_t *dhd) {
3406 int state = 0;
3407 char wifi_disable_5g_band[8] = {0};
3408 char * wl_preinit = NULL;
3409 int size = 0;
3410 struct dhd_conf *conf = dhd->conf;
3411
3412 for (state = 1; state > 0;) {
3413 switch (state) {
3414 case 1:
3415 if (0 != getUnifyKey("wifi_disable_5g_band", wifi_disable_5g_band, sizeof(wifi_disable_5g_band))) {
3416 state = -1;
3417 break;
3418 }
3419
3420 if (conf->wl_preinit) {
3421 // There is a setting for wl_preinit in the config file.
3422 if (NULL != strstr(conf->wl_preinit, "disable_5g_band=")) {
3423 /* Skip wifi_disable_5g_band of unifykeys because there
3424 * is a setting for disable_5g_band in wl_preinit in the
3425 * config file.
3426 */
3427 state = 0;
3428 break;
3429 }
3430 // Backup conf->wl_preinit
3431 size = strlen(conf->wl_preinit) + 1;
3432 wl_preinit = kmalloc(size, GFP_KERNEL);
3433 memset(wl_preinit, 0, size);
3434 strcpy(wl_preinit, conf->wl_preinit);
3435 kfree(conf->wl_preinit);
3436 conf->wl_preinit = NULL;
3437 }
3438
3439 // Create new wl_preinit with disable_5g_band and the backup wl_preinit
3440 size = strlen("disable_5g_band=") + strlen("wifi_disable_5g_band");
3441 if (wl_preinit) {
3442 size += strlen(",") + strlen(wl_preinit);
3443 }
3444 size++;
3445 conf->wl_preinit = kmalloc(size, GFP_KERNEL);
3446 memset(conf->wl_preinit, 0, size);
3447 strcpy(conf->wl_preinit, "disable_5g_band=");
3448 strcat(conf->wl_preinit, wifi_disable_5g_band);
3449 if (wl_preinit) {
3450 strcat(conf->wl_preinit, ",");
3451 strcat(conf->wl_preinit, wl_preinit);
3452 kfree(wl_preinit);
3453 wl_preinit = NULL;
3454 }
3455 state = 0;
3456 break;
3457
3458 }
3459 }
3460
3461 return state;
3462 }
3463
3464 int
3465 dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)
3466 {
3467 int bcmerror = -1, chip_match = -1;
3468 uint len = 0, start_pos=0, end_pos=0;
3469 void *image = NULL;
3470 char *memblock = NULL;
3471 char *bufp, *pick = NULL, *pch;
3472 bool conf_file_exists;
3473 uint len_param;
3474
3475 conf_file_exists = ((conf_path != NULL) && (conf_path[0] != '\0'));
3476 if (!conf_file_exists) {
3477 CONFIG_MSG("config path %s\n", conf_path);
3478 askey_dhd_conf_read_unifykeys_wifi_disable_5g_band(dhd);
3479 return (0);
3480 }
3481
3482 if (conf_file_exists) {
3483 image = dhd_os_open_image1(dhd, conf_path);
3484 if (image == NULL) {
3485 CONFIG_MSG("Ignore config file %s\n", conf_path);
3486 goto err;
3487 }
3488 }
3489
3490 memblock = MALLOC(dhd->osh, MAXSZ_CONFIG);
3491 if (memblock == NULL) {
3492 CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_CONFIG);
3493 goto err;
3494 }
3495
3496 pick = MALLOC(dhd->osh, MAXSZ_BUF);
3497 if (!pick) {
3498 CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_BUF);
3499 goto err;
3500 }
3501
3502 /* Read variables */
3503 if (conf_file_exists) {
3504 len = dhd_os_get_image_block(memblock, MAXSZ_CONFIG, image);
3505 }
3506 if (len > 0 && len < MAXSZ_CONFIG) {
3507 bufp = (char *)memblock;
3508 bufp[len] = 0;
3509
3510 while (start_pos < len) {
3511 memset(pick, 0, MAXSZ_BUF);
3512 end_pos = pick_config_vars(bufp, len, start_pos, pick, MAXSZ_BUF);
3513 if (end_pos - start_pos >= MAXSZ_BUF)
3514 CONFIG_ERROR("out of buf to read MAXSIZ_BUF=%d\n", MAXSZ_BUF);
3515 start_pos = end_pos;
3516 pch = strchr(pick, '=');
3517 if (pch != NULL) {
3518 len_param = pch-pick+1;
3519 if (len_param == strlen(pick)) {
3520 CONFIG_ERROR("not a right parameter %s\n", pick);
3521 continue;
3522 }
3523 } else {
3524 CONFIG_ERROR("not a right parameter %s\n", pick);
3525 continue;
3526 }
3527
3528 dhd_conf_read_chiprev(dhd, &chip_match, pick, len_param);
3529 if (!chip_match)
3530 continue;
3531
3532 if (dhd_conf_read_log_level(dhd, pick, len_param))
3533 continue;
3534 else if (dhd_conf_read_roam_params(dhd, pick, len_param))
3535 continue;
3536 else if (dhd_conf_read_wme_ac_params(dhd, pick, len_param))
3537 continue;
3538 #ifdef BCMSDIO
3539 else if (dhd_conf_read_fw_by_mac(dhd, pick, len_param))
3540 continue;
3541 else if (dhd_conf_read_nv_by_mac(dhd, pick, len_param))
3542 continue;
3543 #endif
3544 else if (dhd_conf_read_nv_by_chip(dhd, pick, len_param))
3545 continue;
3546 else if (dhd_conf_read_country(dhd, pick, len_param))
3547 continue;
3548 else if (dhd_conf_read_mchan_params(dhd, pick, len_param))
3549 continue;
3550 #ifdef PKT_FILTER_SUPPORT
3551 else if (dhd_conf_read_pkt_filter(dhd, pick, len_param))
3552 continue;
3553 #endif /* PKT_FILTER_SUPPORT */
3554 #ifdef ISAM_PREINIT
3555 else if (dhd_conf_read_isam(dhd, pick, len_param))
3556 continue;
3557 #endif /* ISAM_PREINIT */
3558 #ifdef IDHCP
3559 else if (dhd_conf_read_dhcp_params(dhd, pick, len_param))
3560 continue;
3561 #endif /* IDHCP */
3562 #ifdef BCMSDIO
3563 else if (dhd_conf_read_sdio_params(dhd, pick, len_param))
3564 continue;
3565 #endif /* BCMSDIO */
3566 #ifdef BCMPCIE
3567 else if (dhd_conf_read_pcie_params(dhd, pick, len_param))
3568 continue;
3569 #endif /* BCMPCIE */
3570 else if (dhd_conf_read_pm_params(dhd, pick, len_param))
3571 continue;
3572 else if (dhd_conf_read_others(dhd, pick, len_param))
3573 continue;
3574 else
3575 continue;
3576 }
3577
3578 bcmerror = 0;
3579 } else {
3580 CONFIG_ERROR("error reading config file: %d\n", len);
3581 bcmerror = BCME_SDIO_ERROR;
3582 }
3583
3584 err:
3585 if (pick)
3586 MFREE(dhd->osh, pick, MAXSZ_BUF);
3587
3588 if (memblock)
3589 MFREE(dhd->osh, memblock, MAXSZ_CONFIG);
3590
3591 if (image)
3592 dhd_os_close_image1(dhd, image);
3593
3594 askey_dhd_conf_read_unifykeys_wifi_disable_5g_band(dhd);
3595
3596 return bcmerror;
3597 }
3598
3599 int
3600 dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev)
3601 {
3602 CONFIG_MSG("chip=0x%x, chiprev=%d\n", chip, chiprev);
3603 dhd->conf->chip = chip;
3604 dhd->conf->chiprev = chiprev;
3605 return 0;
3606 }
3607
3608 uint
3609 dhd_conf_get_chip(void *context)
3610 {
3611 dhd_pub_t *dhd = context;
3612
3613 if (dhd && dhd->conf)
3614 return dhd->conf->chip;
3615 return 0;
3616 }
3617
3618 uint
3619 dhd_conf_get_chiprev(void *context)
3620 {
3621 dhd_pub_t *dhd = context;
3622
3623 if (dhd && dhd->conf)
3624 return dhd->conf->chiprev;
3625 return 0;
3626 }
3627
3628 #ifdef BCMSDIO
3629 void
3630 dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
3631 {
3632 struct dhd_conf *conf = dhd->conf;
3633
3634 if (enable) {
3635 #if defined(BCMSDIOH_TXGLOM_EXT)
3636 if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID ||
3637 conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
3638 conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
3639 conf->txglom_mode = SDPCM_TXGLOM_CPY;
3640 }
3641 #endif
3642 // other parameters set in preinit or config.txt
3643 if (conf->txglom_ext)
3644 CONFIG_MSG("txglom_ext=%d, txglom_bucket_size=%d\n",
3645 conf->txglom_ext, conf->txglom_bucket_size);
3646 CONFIG_MSG("txglom_mode=%s\n",
3647 conf->txglom_mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy");
3648 CONFIG_MSG("txglomsize=%d, deferred_tx_len=%d\n",
3649 conf->txglomsize, conf->deferred_tx_len);
3650 CONFIG_MSG("txinrx_thres=%d, dhd_txminmax=%d\n",
3651 conf->txinrx_thres, conf->dhd_txminmax);
3652 CONFIG_MSG("tx_max_offset=%d, txctl_tmo_fix=%d\n",
3653 conf->tx_max_offset, conf->txctl_tmo_fix);
3654 } else {
3655 // clear txglom parameters
3656 conf->txglom_ext = FALSE;
3657 conf->txglom_bucket_size = 0;
3658 conf->txglomsize = 0;
3659 conf->deferred_tx_len = 0;
3660 }
3661
3662 }
3663 #endif
3664
3665 void
3666 dhd_conf_postinit_ioctls(dhd_pub_t *dhd)
3667 {
3668 struct dhd_conf *conf = dhd->conf;
3669 char wl_preinit[] = "assoc_retry_max=20";
3670 #ifdef NO_POWER_SAVE
3671 char wl_no_power_save[] = "mpc=0, 86=0";
3672 dhd_conf_set_wl_cmd(dhd, wl_no_power_save, FALSE);
3673 #endif
3674
3675 dhd_conf_set_intiovar(dhd, WLC_UP, "WLC_UP", 0, 0, FALSE);
3676 dhd_conf_map_country_list(dhd, &conf->cspec);
3677 dhd_conf_set_country(dhd, &conf->cspec);
3678 dhd_conf_fix_country(dhd);
3679 dhd_conf_get_country(dhd, &dhd->dhd_cspec);
3680
3681 dhd_conf_set_intiovar(dhd, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE);
3682 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE);
3683 dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", conf->pm, 0, FALSE);
3684 dhd_conf_set_intiovar(dhd, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, FALSE);
3685 dhd_conf_set_intiovar(dhd, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE);
3686 dhd_conf_set_bw_cap(dhd);
3687 dhd_conf_set_roam(dhd);
3688
3689 #if defined(BCMPCIE)
3690 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:deepsleep_disable",
3691 conf->bus_deepsleep_disable, 0, FALSE);
3692 #endif /* defined(BCMPCIE) */
3693
3694 #ifdef IDHCP
3695 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpc_enable", conf->dhcpc_enable,
3696 0, FALSE);
3697 if (conf->dhcpd_enable >= 0) {
3698 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_addr",
3699 (char *)&conf->dhcpd_ip_addr, sizeof(conf->dhcpd_ip_addr), FALSE);
3700 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_mask",
3701 (char *)&conf->dhcpd_ip_mask, sizeof(conf->dhcpd_ip_mask), FALSE);
3702 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_start",
3703 (char *)&conf->dhcpd_ip_start, sizeof(conf->dhcpd_ip_start), FALSE);
3704 dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_end",
3705 (char *)&conf->dhcpd_ip_end, sizeof(conf->dhcpd_ip_end), FALSE);
3706 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpd_enable",
3707 conf->dhcpd_enable, 0, FALSE);
3708 }
3709 #endif
3710 dhd_conf_set_intiovar(dhd, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG",
3711 conf->frameburst, 0, FALSE);
3712
3713 dhd_conf_set_wl_cmd(dhd, wl_preinit, TRUE);
3714 #if defined(BCMSDIO)
3715 {
3716 char ampdu_mpdu[] = "ampdu_mpdu=16";
3717 dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE);
3718 }
3719 #endif
3720 if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
3721 conf->chip == BCM4371_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||
3722 conf->chip == BCM43569_CHIP_ID ||
3723 conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID) {
3724 dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "txbf", 1, 0, FALSE);
3725 }
3726 #if defined(WLEASYMESH)
3727 {
3728 char ezmesh[] = "mbss=1, rsdb_mode=0";
3729 dhd_conf_set_wl_cmd(dhd, ezmesh, TRUE);
3730 }
3731 #endif
3732 dhd_conf_set_wl_cmd(dhd, conf->wl_preinit, TRUE);
3733
3734 #ifndef WL_CFG80211
3735 dhd_conf_set_intiovar(dhd, WLC_UP, "WLC_UP", 0, 0, FALSE);
3736 #endif
3737
3738 }
3739
3740 static int getUnifyKey(char * inKeyName, unsigned char * outValueBuf, unsigned int inValueBufSize) {
3741 unsigned int keyLen = 0;
3742 unsigned char * buf = NULL;
3743
3744 if (NULL == inKeyName || NULL == outValueBuf || 0 == inValueBufSize) {
3745 return -1;
3746 }
3747 memset(outValueBuf, 0, inValueBufSize);
3748 if (key_unify_size(get_ukdev(), inKeyName, &keyLen) < 0) {
3749 return -1;
3750 }
3751 if (0 == keyLen) {
3752 return -1;
3753 }
3754 if ((sizeof(unsigned char) * keyLen) > inValueBufSize) {
3755 return -1;
3756 }
3757
3758 if (NULL == (buf = kzalloc((sizeof(unsigned char) * keyLen), GFP_KERNEL))) {
3759 return -1;
3760 }
3761
3762 if (key_unify_read(get_ukdev(), inKeyName, buf, keyLen, &keyLen) < 0) {
3763 kfree(buf);
3764 buf = NULL;
3765 return -1;
3766 }
3767
3768 strcpy(outValueBuf, buf);
3769
3770 if (NULL != buf) {
3771 kfree(buf);
3772 buf = NULL;
3773 }
3774
3775 return 0;
3776 }
3777
3778 char * kzalloc2getUnifyKey(char * inKeyName) {
3779 unsigned int keyLen = 0;
3780 unsigned char * buf = NULL;
3781
3782 if (NULL == inKeyName) {
3783 return NULL;
3784 }
3785
3786 if (key_unify_size(get_ukdev(), inKeyName, &keyLen) < 0) {
3787 return NULL;
3788 }
3789
3790 if (0 == keyLen) {
3791 return NULL;
3792 }
3793
3794 if (NULL == (buf = kzalloc(((sizeof(unsigned char) * keyLen) + 1), GFP_KERNEL))) {
3795 return NULL;
3796 }
3797
3798 if (key_unify_read(get_ukdev(), inKeyName, buf, keyLen, &keyLen) < 0) {
3799 kfree(buf);
3800 buf = NULL;
3801 return NULL;
3802 }
3803
3804 buf[keyLen] = '\0';
3805
3806 return buf;
3807 }
3808
3809 int askey_dhd_conf_preinit_by_sn(struct dhd_conf *conf) {
3810 char * usid = NULL;
3811 int i = 0;
3812 struct {
3813 char * country;
3814 char * ccode;
3815 int regrev;
3816 } tbl[] = {
3817 {"USA", "US", 1}, // the default MUST be put at the first place of this table
3818 {"JPN", "JP", 58},
3819 {"AUS", "AU", 6},
3820 {"NZL", "NZ", 4},
3821 {"HKG", "HK", 2},
3822 {"CAN", "CA", 2},
3823 {"TWN", "TW", 1},
3824 {"CHN", "CN", 38},
3825 {"DEU", "DE", 7},
3826 {"FRA", "FR", 5},
3827 {"NLD", "NL", 4},
3828 {"ITA", "IT", 4},
3829 {"BGR", "BG", 4},
3830 {"HUN", "HU", 4},
3831 {"AUT", "AT", 4},
3832 {"RUS", "RU", 986},
3833 {"GBR", "GB", 6},
3834 {"BRA", "BR", 4},
3835 {"MEX", "MX", 20},
3836 {"IND", "IN", 3},
3837 {"PHL", "PH", 5},
3838 {"SGP", "SG", 0},
3839 {"MYS", "MY", 3},
3840 {"AND", "AD", 0},
3841 {"ARE", "AE", 6},
3842 {"ATG", "AG", 2},
3843 {"AIA", "AI", 1},
3844 {"ALB", "AL", 2},
3845 {"ASM", "AS", 12},
3846 {"ABW", "AW", 2},
3847 {"AZE", "AZ", 2},
3848 {"BIH", "BA", 2},
3849 {"BGD", "BD", 2},
3850 {"BEL", "BE", 4},
3851 {"BHR", "BH", 4},
3852 {"BMU", "BM", 12},
3853 {"BRN", "BN", 4},
3854 {"BRA", "BR", 4},
3855 {"BHS", "BS", 2},
3856 {"BLR", "BY", 3},
3857 {"CAN", "CA", 2},
3858 {"CHE", "CH", 4},
3859 {"COL", "CO", 17},
3860 {"CRI", "CR", 17},
3861 {"CYP", "CY", 4},
3862 {"CZE", "CZ", 4},
3863 {"DEU", "DE", 7},
3864 {"DNK", "DK", 4},
3865 {"ECU", "EC", 21},
3866 {"EST", "EE", 4},
3867 {"EGY", "EG", 0},
3868 {"ESP", "ES", 4},
3869 {"ETH", "ET", 2},
3870 {"FIN", "FI", 4},
3871 {"GRD", "GD", 2},
3872 {"GEO", "GE", 0},
3873 {"PYF", "GF", 2},
3874 {"GRC", "GR", 4},
3875 {"GTM", "GT", 1},
3876 {"GUM", "GU", 12},
3877 {"HRV", "HR", 4},
3878 {"IDN", "ID", 13},
3879 {"IRL", "IE", 5},
3880 {"ISR", "IL", 7},
3881 {"ISL", "IS", 4},
3882 {"ITA", "IT", 4},
3883 {"JOR", "JO", 3},
3884 {"KHM", "KH", 2},
3885 {"KOR", "KR", 57},
3886 {"KWT", "KW", 5},
3887 {"CYM", "KY", 3},
3888 {"LAO", "LA", 2},
3889 {"LBN", "LB", 5},
3890 {"LIE", "LI", 4},
3891 {"LKA", "LK", 1},
3892 {"LSO", "LS", 2},
3893 {"LTU", "LT", 4},
3894 {"LUX", "LU", 3},
3895 {"LVA", "LV", 4},
3896 {"MAR", "MA", 2},
3897 {"MCO", "MC", 1},
3898 {"MDA", "MD", 2},
3899 {"MNE", "ME", 2},
3900 {"MKD", "MK", 2},
3901 {"MNG", "MN", 1},
3902 {"MRT", "MR", 2},
3903 {"MLT", "MT", 4},
3904 {"MUS", "MU", 2},
3905 {"MDV", "MV", 3},
3906 {"MWI", "MW", 1},
3907 {"NIC", "NI", 2},
3908 {"NLD", "NL", 4},
3909 {"NOR", "NO", 4},
3910 {"NZL", "NZ", 4},
3911 {"OMN", "OM", 4},
3912 {"PAN", "PA", 17},
3913 {"PER", "PE", 20},
3914 {"POL", "PL", 4},
3915 {"PRI", "PR", 20},
3916 {"PRT", "PT", 4},
3917 {"PRY", "PY", 2},
3918 {"REU", "RE", 2},
3919 {"ROU", "RO", 4},
3920 {"SRB", "RS", 2},
3921 {"SWE", "SE", 4},
3922 {"SVN", "SI", 4},
3923 {"SVK", "SK", 4},
3924 {"SMR", "SM", 0},
3925 {"SOM", "SV", 19},
3926 {"THA", "TH", 5},
3927 {"TUN", "TN", 999},
3928 {"TUR", "TR", 7},
3929 {"TTO", "TT", 3},
3930 {"UKR", "UA", 16},
3931 {"VAT", "VA", 2},
3932 {"VEN", "VE", 3},
3933 {"VGB", "VG", 2},
3934 {"VNM", "VN", 4},
3935 {"MYT", "YT", 2},
3936 {"ZAF", "ZA", 6},
3937 {NULL, NULL, -1}
3938 };
3939
3940 if (NULL == (usid = kzalloc2getUnifyKey("usid")) || strlen(usid) < 4) {
3941 i = 0; // for using tbl[0] as the default
3942 }else {
3943 for (i = 0; NULL != tbl[i].country; i++) {
3944 if (0 == strncmp(tbl[i].country, &usid[1], 3)) {
3945 break;
3946 }
3947 }
3948 }
3949 if (NULL == tbl[i].country) {
3950 i = 0; // for using tbl[0] as the default
3951 }
3952 strcpy(conf->cspec.country_abbrev, tbl[i].ccode);
3953 strcpy(conf->cspec.ccode, tbl[i].ccode);
3954 conf->cspec.rev = tbl[i].regrev;
3955
3956 if (usid) {
3957 kfree(usid);
3958 usid = NULL;
3959 }
3960
3961 return 0;
3962 }
3963
3964 static int askey_dhd_conf_preinit(struct dhd_conf *conf) {
3965 char * wifi_country_abbrev_ptr = NULL;
3966 char wifi_country_abbrev[4] = {0};
3967 char wifi_ccode[4] = {0};
3968 char wifi_regrev[4] = {0};
3969 long regrev = 0;
3970
3971 if (NULL == conf) {
3972 return -1;
3973 }
3974 if (0 == getUnifyKey("wifi_ccode", wifi_ccode, sizeof(wifi_ccode)) &&
3975 0 == getUnifyKey("wifi_regrev", wifi_regrev, sizeof(wifi_regrev)) &&
3976 0 == kstrtol(wifi_regrev, 10, &regrev)) {
3977 if (0 == getUnifyKey("wifi_country_abbrev", wifi_country_abbrev, sizeof(wifi_country_abbrev))) {
3978 wifi_country_abbrev_ptr = wifi_country_abbrev;
3979 }else {
3980 wifi_country_abbrev_ptr = wifi_ccode;
3981 }
3982 strcpy(conf->cspec.country_abbrev, wifi_country_abbrev_ptr);
3983 strcpy(conf->cspec.ccode, wifi_ccode);
3984 conf->cspec.rev = regrev;
3985 }else {
3986 strcpy(conf->cspec.country_abbrev, "CN");
3987 strcpy(conf->cspec.ccode, "CN");
3988 conf->cspec.rev = 38;
3989 }
3990 return 0;
3991 }
3992
3993 int
3994 dhd_conf_preinit(dhd_pub_t *dhd)
3995 {
3996 struct dhd_conf *conf = dhd->conf;
3997
3998 CONFIG_TRACE("Enter\n");
3999
4000 #ifdef BCMSDIO
4001 dhd_conf_free_mac_list(&conf->fw_by_mac);
4002 dhd_conf_free_mac_list(&conf->nv_by_mac);
4003 #endif
4004 dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
4005 dhd_conf_free_country_list(conf);
4006 dhd_conf_free_mchan_list(conf);
4007 if (conf->magic_pkt_filter_add) {
4008 kfree(conf->magic_pkt_filter_add);
4009 conf->magic_pkt_filter_add = NULL;
4010 }
4011 if (conf->wl_preinit) {
4012 kfree(conf->wl_preinit);
4013 conf->wl_preinit = NULL;
4014 }
4015 if (conf->wl_suspend) {
4016 kfree(conf->wl_suspend);
4017 conf->wl_suspend = NULL;
4018 }
4019 if (conf->wl_resume) {
4020 kfree(conf->wl_resume);
4021 conf->wl_resume = NULL;
4022 }
4023 conf->band = -1;
4024 memset(&conf->bw_cap, -1, sizeof(conf->bw_cap));
4025 if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {
4026 strcpy(conf->cspec.country_abbrev, "ALL");
4027 strcpy(conf->cspec.ccode, "ALL");
4028 conf->cspec.rev = 0;
4029 } else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
4030 conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
4031 conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
4032 conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||
4033 conf->chip == BCM4362_CHIP_ID || conf->chip == BCM43751_CHIP_ID) {
4034 #if 1
4035 askey_dhd_conf_preinit(conf);
4036 askey_dhd_conf_preinit_by_sn(conf);
4037 #else
4038 strcpy(conf->cspec.country_abbrev, "CN");
4039 strcpy(conf->cspec.ccode, "CN");
4040 conf->cspec.rev = 38;
4041 #endif
4042 } else {
4043 strcpy(conf->cspec.country_abbrev, "CN");
4044 strcpy(conf->cspec.ccode, "CN");
4045 conf->cspec.rev = 0;
4046 }
4047 memset(&conf->channels, 0, sizeof(wl_channel_list_t));
4048 conf->roam_off = 1;
4049 conf->roam_off_suspend = 1;
4050 conf->roam_trigger[0] = -65;
4051 conf->roam_trigger[1] = WLC_BAND_ALL;
4052 conf->roam_scan_period[0] = 10;
4053 conf->roam_scan_period[1] = WLC_BAND_ALL;
4054 conf->roam_delta[0] = 10;
4055 conf->roam_delta[1] = WLC_BAND_ALL;
4056 conf->fullroamperiod = 20;
4057 conf->keep_alive_period = 30000;
4058 #ifdef ARP_OFFLOAD_SUPPORT
4059 conf->garp = FALSE;
4060 #endif
4061 conf->force_wme_ac = 0;
4062 memset(&conf->wme_sta, 0, sizeof(wme_param_t));
4063 memset(&conf->wme_ap, 0, sizeof(wme_param_t));
4064 #ifdef PKT_FILTER_SUPPORT
4065 memset(&conf->pkt_filter_add, 0, sizeof(conf_pkt_filter_add_t));
4066 memset(&conf->pkt_filter_del, 0, sizeof(conf_pkt_filter_del_t));
4067 #endif
4068 conf->srl = -1;
4069 conf->lrl = -1;
4070 conf->bcn_timeout = 16;
4071 conf->disable_proptx = -1;
4072 conf->dhd_poll = -1;
4073 #ifdef BCMSDIO
4074 conf->use_rxchain = 0;
4075 conf->bus_rxglom = TRUE;
4076 conf->txglom_ext = FALSE;
4077 conf->tx_max_offset = 0;
4078 conf->txglomsize = SDPCM_DEFGLOM_SIZE;
4079 conf->txctl_tmo_fix = 300;
4080 conf->txglom_mode = SDPCM_TXGLOM_MDESC;
4081 conf->deferred_tx_len = 0;
4082 conf->dhd_txminmax = 1;
4083 conf->txinrx_thres = -1;
4084 #ifdef MINIME
4085 conf->ramsize = 0x80000;
4086 #endif
4087 #if defined(SDIO_ISR_THREAD)
4088 conf->intr_extn = FALSE;
4089 #endif
4090 #ifdef BCMSDIO_RXLIM_POST
4091 conf->rxlim_en = TRUE;
4092 #endif
4093 #if defined(HW_OOB)
4094 conf->oob_enabled_later = FALSE;
4095 #endif
4096 #endif
4097 #ifdef BCMPCIE
4098 conf->bus_deepsleep_disable = 1;
4099 #endif
4100 conf->dpc_cpucore = -1;
4101 conf->rxf_cpucore = -1;
4102 conf->frameburst = -1;
4103 conf->deepsleep = FALSE;
4104 conf->pm = -1;
4105 conf->pm_in_suspend = -1;
4106 conf->insuspend = 0;
4107 conf->suspend_mode = EARLY_SUSPEND;
4108 conf->suspend_bcn_li_dtim = -1;
4109 #ifdef WL_EXT_WOWL
4110 dhd_master_mode = TRUE;
4111 conf->wowl = WL_WOWL_NET|WL_WOWL_DIS|WL_WOWL_BCN;
4112 conf->insuspend |= (WOWL_IN_SUSPEND | NO_TXDATA_IN_SUSPEND);
4113 #endif
4114 if (conf->suspend_mode == PM_NOTIFIER)
4115 conf->insuspend |= (NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND);
4116 conf->suspended = FALSE;
4117 #ifdef SUSPEND_EVENT
4118 memset(&conf->resume_eventmask, 0, sizeof(conf->resume_eventmask));
4119 memset(&conf->bssid_insuspend, 0, ETHER_ADDR_LEN);
4120 conf->wlfc = FALSE;
4121 #endif
4122 #ifdef GET_CUSTOM_MAC_FROM_CONFIG
4123 memset(&conf->hw_ether, 0, sizeof(conf->hw_ether));
4124 #endif
4125 #ifdef IDHCP
4126 conf->dhcpc_enable = -1;
4127 conf->dhcpd_enable = -1;
4128 #endif
4129 conf->orphan_move = 0;
4130 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
4131 conf->tsq = 10;
4132 #else
4133 conf->tsq = 0;
4134 #endif
4135 #ifdef DHDTCPACK_SUPPRESS
4136 #ifdef BCMPCIE
4137 conf->tcpack_sup_mode = TCPACK_SUP_HOLD;
4138 #else
4139 conf->tcpack_sup_mode = TCPACK_SUP_OFF;
4140 #endif
4141 #endif
4142 conf->pktprio8021x = -1;
4143 conf->ctrl_resched = 2;
4144 conf->in4way = NO_SCAN_IN4WAY | DONT_DELETE_GC_AFTER_WPS | WAIT_DISCONNECTED;
4145 #ifdef PROPTX_MAXCOUNT
4146 conf->proptx_maxcnt_2g = 46;
4147 conf->proptx_maxcnt_5g = WL_TXSTATUS_FREERUNCTR_MASK;
4148 #endif /* DYNAMIC_PROPTX_MAXCOUNT */
4149 #ifdef HOST_TPUT_TEST
4150 conf->data_drop_mode = 0;
4151 #endif
4152 #ifdef ISAM_PREINIT
4153 memset(conf->isam_init, 0, sizeof(conf->isam_init));
4154 memset(conf->isam_config, 0, sizeof(conf->isam_config));
4155 memset(conf->isam_enable, 0, sizeof(conf->isam_enable));
4156 #endif
4157 #ifdef CUSTOMER_HW_AMLOGIC
4158 dhd_slpauto = FALSE;
4159 #ifdef BCMSDIO
4160 conf->txglom_mode = SDPCM_TXGLOM_CPY;
4161 #endif
4162 #endif
4163 #if defined(SDIO_ISR_THREAD)
4164 if (conf->chip == BCM43012_CHIP_ID ||
4165 conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
4166 conf->chip == BCM43454_CHIP_ID || conf->chip == BCM4345_CHIP_ID ||
4167 conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
4168 conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
4169 conf->chip == BCM4359_CHIP_ID ||
4170 conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID) {
4171 conf->intr_extn = TRUE;
4172 }
4173 #endif
4174 if ((conf->chip == BCM43430_CHIP_ID && conf->chiprev == 2) ||
4175 conf->chip == BCM43012_CHIP_ID ||
4176 conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
4177 conf->chip == BCM43454_CHIP_ID || conf->chip == BCM4345_CHIP_ID ||
4178 conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
4179 conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
4180 conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||
4181 conf->chip == BCM43751_CHIP_ID || conf->chip == BCM43752_CHIP_ID) {
4182 #ifdef DHDTCPACK_SUPPRESS
4183 #ifdef BCMSDIO
4184 conf->tcpack_sup_mode = TCPACK_SUP_REPLACE;
4185 #endif
4186 #endif
4187 #if defined(BCMSDIO) || defined(BCMPCIE)
4188 dhd_rxbound = 128;
4189 dhd_txbound = 64;
4190 #endif
4191 conf->frameburst = 1;
4192 #ifdef BCMSDIO
4193 conf->dhd_txminmax = -1;
4194 conf->txinrx_thres = 128;
4195 #endif
4196 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
4197 conf->orphan_move = 1;
4198 #else
4199 conf->orphan_move = 0;
4200 #endif
4201 }
4202
4203 #ifdef BCMSDIO
4204 #if defined(BCMSDIOH_TXGLOM_EXT)
4205 if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID ||
4206 conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
4207 conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
4208 conf->txglom_ext = TRUE;
4209 } else {
4210 conf->txglom_ext = FALSE;
4211 }
4212 if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {
4213 conf->txglom_bucket_size = 1680; // fixed value, don't change
4214 conf->txglomsize = 6;
4215 }
4216 if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID ||
4217 conf->chip == BCM43341_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
4218 conf->txglom_bucket_size = 1684; // fixed value, don't change
4219 conf->txglomsize = 16;
4220 }
4221 #endif
4222 if (conf->txglomsize > SDPCM_MAXGLOM_SIZE)
4223 conf->txglomsize = SDPCM_MAXGLOM_SIZE;
4224 #endif
4225 init_waitqueue_head(&conf->event_complete);
4226
4227 return 0;
4228 }
4229
4230 int
4231 dhd_conf_reset(dhd_pub_t *dhd)
4232 {
4233 struct dhd_conf *conf = dhd->conf;
4234
4235 #ifdef BCMSDIO
4236 dhd_conf_free_mac_list(&conf->fw_by_mac);
4237 dhd_conf_free_mac_list(&conf->nv_by_mac);
4238 #endif
4239 dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
4240 dhd_conf_free_country_list(conf);
4241 dhd_conf_free_mchan_list(conf);
4242 if (conf->magic_pkt_filter_add) {
4243 kfree(conf->magic_pkt_filter_add);
4244 conf->magic_pkt_filter_add = NULL;
4245 }
4246 if (conf->wl_preinit) {
4247 kfree(conf->wl_preinit);
4248 conf->wl_preinit = NULL;
4249 }
4250 if (conf->wl_suspend) {
4251 kfree(conf->wl_suspend);
4252 conf->wl_suspend = NULL;
4253 }
4254 if (conf->wl_resume) {
4255 kfree(conf->wl_resume);
4256 conf->wl_resume = NULL;
4257 }
4258 memset(conf, 0, sizeof(dhd_conf_t));
4259 return 0;
4260 }
4261
4262 int
4263 dhd_conf_attach(dhd_pub_t *dhd)
4264 {
4265 dhd_conf_t *conf;
4266
4267 CONFIG_TRACE("Enter\n");
4268
4269 if (dhd->conf != NULL) {
4270 CONFIG_MSG("config is attached before!\n");
4271 return 0;
4272 }
4273 /* Allocate private bus interface state */
4274 if (!(conf = MALLOC(dhd->osh, sizeof(dhd_conf_t)))) {
4275 CONFIG_ERROR("MALLOC failed\n");
4276 goto fail;
4277 }
4278 memset(conf, 0, sizeof(dhd_conf_t));
4279
4280 dhd->conf = conf;
4281
4282 return 0;
4283
4284 fail:
4285 if (conf != NULL)
4286 MFREE(dhd->osh, conf, sizeof(dhd_conf_t));
4287 return BCME_NOMEM;
4288 }
4289
4290 void
4291 dhd_conf_detach(dhd_pub_t *dhd)
4292 {
4293 struct dhd_conf *conf = dhd->conf;
4294
4295 CONFIG_TRACE("Enter\n");
4296 if (dhd->conf) {
4297 #ifdef BCMSDIO
4298 dhd_conf_free_mac_list(&conf->fw_by_mac);
4299 dhd_conf_free_mac_list(&conf->nv_by_mac);
4300 #endif
4301 dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
4302 dhd_conf_free_country_list(conf);
4303 dhd_conf_free_mchan_list(conf);
4304 if (conf->magic_pkt_filter_add) {
4305 kfree(conf->magic_pkt_filter_add);
4306 conf->magic_pkt_filter_add = NULL;
4307 }
4308 if (conf->wl_preinit) {
4309 kfree(conf->wl_preinit);
4310 conf->wl_preinit = NULL;
4311 }
4312 if (conf->wl_suspend) {
4313 kfree(conf->wl_suspend);
4314 conf->wl_suspend = NULL;
4315 }
4316 if (conf->wl_resume) {
4317 kfree(conf->wl_resume);
4318 conf->wl_resume = NULL;
4319 }
4320 MFREE(dhd->osh, conf, sizeof(dhd_conf_t));
4321 }
4322 dhd->conf = NULL;
4323 }