1 /*
2 * Linux cfg80211 driver - Dongle Host Driver (DHD) related
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Dual:>>
22 */
23
24 #include <net/rtnetlink.h>
25
26 #include <bcmutils.h>
27 #include <wldev_common.h>
28 #include <wl_cfg80211.h>
29 #include <dhd_cfg80211.h>
30 #include <dngl_stats.h>
31 #include <dhd.h>
32 #include <dhdioctl.h>
33 #include <wlioctl.h>
34
35 #ifdef PKT_FILTER_SUPPORT
36 extern uint dhd_pkt_filter_enable;
37 extern uint dhd_master_mode;
38 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
39 #endif
40
41 struct btcoex_info {
42 timer_list_compat_t timer;
43 u32 timer_ms;
44 u32 timer_on;
45 u32 ts_dhcp_start; /* ms ts ecord time stats */
46 u32 ts_dhcp_ok; /* ms ts ecord time stats */
47 bool dhcp_done; /* flag, indicates that host done with
48 * dhcp before t1/t2 expiration
49 */
50 s32 bt_state;
51 struct work_struct work;
52 struct net_device *dev;
53 };
54
55 #if defined(OEM_ANDROID)
56 static struct btcoex_info *btcoex_info_loc = NULL;
57
58 /* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
59
60 /* use New SCO/eSCO smart YG suppression */
61 #define BT_DHCP_eSCO_FIX
62 /* this flag boost wifi pkt priority to max, caution: -not fair to sco */
63 #define BT_DHCP_USE_FLAGS
64 /* T1 start SCO/ESCo priority suppression */
65 #define BT_DHCP_OPPR_WIN_TIME 2500
66 /* T2 turn off SCO/SCO supperesion is (timeout) */
67 #define BT_DHCP_FLAG_FORCE_TIME 5500
68
69 #define BTCOEXMODE "BTCOEXMODE"
70 #define POWERMODE "POWERMODE"
71
72 enum wl_cfg80211_btcoex_status {
73 BT_DHCP_IDLE,
74 BT_DHCP_START,
75 BT_DHCP_OPPR_WIN,
76 BT_DHCP_FLAG_FORCE_TIMEOUT
77 };
78
79 /*
80 * get named driver variable to uint register value and return error indication
81 * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value)
82 */
83 static int
dev_wlc_intvar_get_reg(struct net_device * dev,char * name,uint reg,int * retval)84 dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
85 uint reg, int *retval)
86 {
87 union {
88 char buf[WLC_IOCTL_SMLEN];
89 int val;
90 } var;
91 int error;
92
93 bzero(&var, sizeof(var));
94 error = bcm_mkiovar(name, (char *)(®), sizeof(reg), (char *)(&var), sizeof(var.buf));
95 if (error == 0) {
96 return BCME_BUFTOOSHORT;
97 }
98 error = wldev_ioctl_get(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf));
99
100 *retval = dtoh32(var.val);
101 return (error);
102 }
103
104 static int
dev_wlc_bufvar_set(struct net_device * dev,char * name,char * buf,int len)105 dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
106 {
107 char ioctlbuf_local[WLC_IOCTL_SMLEN];
108 int ret;
109
110 ret = bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
111 if (ret == 0)
112 return BCME_BUFTOOSHORT;
113 return (wldev_ioctl_set(dev, WLC_SET_VAR, ioctlbuf_local, ret));
114 }
115
116 /*
117 get named driver variable to uint register value and return error indication
118 calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
119 */
120 static int
dev_wlc_intvar_set_reg(struct net_device * dev,char * name,char * addr,char * val)121 dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
122 {
123 char reg_addr[8];
124
125 bzero(reg_addr, sizeof(reg_addr));
126 memcpy((char *)®_addr[0], (char *)addr, 4);
127 memcpy((char *)®_addr[4], (char *)val, 4);
128
129 return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr)));
130 }
131
132 /* andrey: bt pkt period independant sco/esco session detection algo. */
btcoex_is_sco_active(struct net_device * dev)133 static bool btcoex_is_sco_active(struct net_device *dev)
134 {
135 int ioc_res = 0;
136 bool res = FALSE;
137 int sco_id_cnt = 0;
138 int param27;
139 int i;
140
141 for (i = 0; i < 12; i++) {
142
143 ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27);
144
145 WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27));
146
147 if (ioc_res < 0) {
148 WL_ERR(("ioc read btc params error\n"));
149 break;
150 }
151
152 if ((param27 & 0x6) == 2) { /* count both sco & esco */
153 sco_id_cnt++;
154 }
155
156 if (sco_id_cnt > 2) {
157 WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n",
158 sco_id_cnt, i));
159 res = TRUE;
160 break;
161 }
162
163 OSL_SLEEP(5);
164 }
165
166 return res;
167 }
168
169 #if defined(BT_DHCP_eSCO_FIX)
170 /* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
set_btc_esco_params(struct net_device * dev,bool trump_sco)171 static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
172 {
173 static bool saved_status = FALSE;
174
175 char buf_reg50va_dhcp_on[8] =
176 { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
177 char buf_reg51va_dhcp_on[8] =
178 { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
179 char buf_reg64va_dhcp_on[8] =
180 { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
181 char buf_reg65va_dhcp_on[8] =
182 { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
183 char buf_reg71va_dhcp_on[8] =
184 { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
185 uint32 regaddr;
186 static uint32 saved_reg50;
187 static uint32 saved_reg51;
188 static uint32 saved_reg64;
189 static uint32 saved_reg65;
190 static uint32 saved_reg71;
191
192 if (trump_sco) {
193 /* this should reduce eSCO agressive retransmit
194 * w/o breaking it
195 */
196
197 /* 1st save current */
198 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
199 "override}\n"));
200 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
201 (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
202 (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
203 (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
204 (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
205 saved_status = TRUE;
206 WL_TRACE(("saved bt_params[50,51,64,65,71]:"
207 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
208 saved_reg50, saved_reg51,
209 saved_reg64, saved_reg65, saved_reg71));
210 } else {
211 WL_ERR((":%s: save btc_params failed\n",
212 __FUNCTION__));
213 saved_status = FALSE;
214 return -1;
215 }
216
217 /* pacify the eSco */
218 WL_TRACE(("override with [50,51,64,65,71]:"
219 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
220 *(u32 *)(buf_reg50va_dhcp_on+4),
221 *(u32 *)(buf_reg51va_dhcp_on+4),
222 *(u32 *)(buf_reg64va_dhcp_on+4),
223 *(u32 *)(buf_reg65va_dhcp_on+4),
224 *(u32 *)(buf_reg71va_dhcp_on+4)));
225
226 dev_wlc_bufvar_set(dev, "btc_params",
227 (char *)&buf_reg50va_dhcp_on[0], 8);
228 dev_wlc_bufvar_set(dev, "btc_params",
229 (char *)&buf_reg51va_dhcp_on[0], 8);
230 dev_wlc_bufvar_set(dev, "btc_params",
231 (char *)&buf_reg64va_dhcp_on[0], 8);
232 dev_wlc_bufvar_set(dev, "btc_params",
233 (char *)&buf_reg65va_dhcp_on[0], 8);
234 dev_wlc_bufvar_set(dev, "btc_params",
235 (char *)&buf_reg71va_dhcp_on[0], 8);
236
237 saved_status = TRUE;
238 } else if (saved_status) {
239 /* restore previously saved bt params */
240 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
241 "override}\n"));
242
243 regaddr = 50;
244 dev_wlc_intvar_set_reg(dev, "btc_params",
245 (char *)®addr, (char *)&saved_reg50);
246 regaddr = 51;
247 dev_wlc_intvar_set_reg(dev, "btc_params",
248 (char *)®addr, (char *)&saved_reg51);
249 regaddr = 64;
250 dev_wlc_intvar_set_reg(dev, "btc_params",
251 (char *)®addr, (char *)&saved_reg64);
252 regaddr = 65;
253 dev_wlc_intvar_set_reg(dev, "btc_params",
254 (char *)®addr, (char *)&saved_reg65);
255 regaddr = 71;
256 dev_wlc_intvar_set_reg(dev, "btc_params",
257 (char *)®addr, (char *)&saved_reg71);
258
259 WL_TRACE(("restore bt_params[50,51,64,65,71]:"
260 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
261 saved_reg50, saved_reg51, saved_reg64,
262 saved_reg65, saved_reg71));
263
264 saved_status = FALSE;
265 } else {
266 WL_ERR((":%s att to restore not saved BTCOEX params\n",
267 __FUNCTION__));
268 return -1;
269 }
270 return 0;
271 }
272 #endif /* BT_DHCP_eSCO_FIX */
273
274 static void
wl_cfg80211_bt_setflag(struct net_device * dev,bool set)275 wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
276 {
277 #if defined(BT_DHCP_USE_FLAGS)
278 char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
279 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
280 #endif
281
282 #if defined(BT_DHCP_eSCO_FIX)
283 /* ANREY: New Yury's eSco pacifier */
284 /* set = 1, save & turn on 0 - off & restore prev settings */
285 set_btc_esco_params(dev, set);
286 #endif
287
288 #if defined(BT_DHCP_USE_FLAGS)
289 /* ANdrey: old WI-FI priority boost via flags */
290 WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
291 if (set == TRUE)
292 /* Forcing bt_flag7 */
293 dev_wlc_bufvar_set(dev, "btc_flags",
294 (char *)&buf_flag7_dhcp_on[0],
295 sizeof(buf_flag7_dhcp_on));
296 else
297 /* Restoring default bt flag7 */
298 dev_wlc_bufvar_set(dev, "btc_flags",
299 (char *)&buf_flag7_default[0],
300 sizeof(buf_flag7_default));
301 #endif
302 }
303
wl_cfg80211_bt_timerfunc(ulong data)304 static void wl_cfg80211_bt_timerfunc(ulong data)
305 {
306 struct btcoex_info *bt_local = (struct btcoex_info *)data;
307 WL_TRACE(("Enter\n"));
308 bt_local->timer_on = 0;
309 schedule_work(&bt_local->work);
310 }
311
wl_cfg80211_bt_handler(struct work_struct * work)312 static void wl_cfg80211_bt_handler(struct work_struct *work)
313 {
314 struct btcoex_info *btcx_inf;
315
316 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
317 btcx_inf = container_of(work, struct btcoex_info, work);
318 GCC_DIAGNOSTIC_POP();
319
320 if (btcx_inf->timer_on) {
321 btcx_inf->timer_on = 0;
322 del_timer_sync(&btcx_inf->timer);
323 }
324
325 switch (btcx_inf->bt_state) {
326 case BT_DHCP_START:
327 /* DHCP started
328 * provide OPPORTUNITY window to get DHCP address
329 */
330 WL_TRACE(("bt_dhcp stm: started \n"));
331
332 btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
333 mod_timer(&btcx_inf->timer,
334 jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME));
335 btcx_inf->timer_on = 1;
336 break;
337
338 case BT_DHCP_OPPR_WIN:
339 if (btcx_inf->dhcp_done) {
340 WL_TRACE(("DHCP Done before T1 expiration\n"));
341 goto btc_coex_idle;
342 }
343
344 /* DHCP is not over yet, start lowering BT priority
345 * enforce btc_params + flags if necessary
346 */
347 WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME));
348 if (btcx_inf->dev)
349 wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
350 btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
351 mod_timer(&btcx_inf->timer,
352 jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME));
353 btcx_inf->timer_on = 1;
354 break;
355
356 case BT_DHCP_FLAG_FORCE_TIMEOUT:
357 if (btcx_inf->dhcp_done) {
358 WL_TRACE(("DHCP Done before T2 expiration\n"));
359 } else {
360 /* Noo dhcp during T1+T2, restore BT priority */
361 WL_TRACE(("DHCP wait interval T2:%d msec expired\n",
362 BT_DHCP_FLAG_FORCE_TIME));
363 }
364
365 /* Restoring default bt priority */
366 if (btcx_inf->dev)
367 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
368 btc_coex_idle:
369 btcx_inf->bt_state = BT_DHCP_IDLE;
370 btcx_inf->timer_on = 0;
371 break;
372
373 default:
374 WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state));
375 if (btcx_inf->dev)
376 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
377 btcx_inf->bt_state = BT_DHCP_IDLE;
378 btcx_inf->timer_on = 0;
379 break;
380 }
381
382 /* why we need this? */
383 net_os_wake_unlock(btcx_inf->dev);
384 }
385
wl_cfg80211_btcoex_init(struct net_device * ndev)386 void* wl_cfg80211_btcoex_init(struct net_device *ndev)
387 {
388 struct btcoex_info *btco_inf = NULL;
389
390 btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
391 if (!btco_inf)
392 return NULL;
393
394 btco_inf->bt_state = BT_DHCP_IDLE;
395 btco_inf->ts_dhcp_start = 0;
396 btco_inf->ts_dhcp_ok = 0;
397 /* Set up timer for BT */
398 btco_inf->timer_ms = 10;
399 init_timer_compat(&btco_inf->timer, wl_cfg80211_bt_timerfunc, btco_inf);
400
401 btco_inf->dev = ndev;
402
403 INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
404
405 btcoex_info_loc = btco_inf;
406 return btco_inf;
407 }
408
wl_cfg80211_btcoex_deinit()409 void wl_cfg80211_btcoex_deinit()
410 {
411 if (!btcoex_info_loc)
412 return;
413
414 if (btcoex_info_loc->timer_on) {
415 btcoex_info_loc->timer_on = 0;
416 del_timer_sync(&btcoex_info_loc->timer);
417 }
418
419 cancel_work_sync(&btcoex_info_loc->work);
420
421 kfree(btcoex_info_loc);
422 }
423
wl_cfg80211_set_btcoex_dhcp(struct net_device * dev,dhd_pub_t * dhd,char * command)424 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command)
425 {
426
427 #ifndef OEM_ANDROID
428 static int pm = PM_FAST;
429 int pm_local = PM_OFF;
430 #endif /* OEM_ANDROID */
431 struct btcoex_info *btco_inf = btcoex_info_loc;
432 char powermode_val = 0;
433 uint8 cmd_len = 0;
434 char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
435 char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
436 char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
437
438 uint32 regaddr;
439 static uint32 saved_reg66;
440 static uint32 saved_reg41;
441 static uint32 saved_reg68;
442 static bool saved_status = FALSE;
443
444 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
445
446 /* Figure out powermode 1 or o command */
447 #ifdef OEM_ANDROID
448 cmd_len = sizeof(BTCOEXMODE);
449 #else
450 cmd_len = sizeof(POWERMODE);
451 #endif
452 powermode_val = command[cmd_len];
453
454 WL_INFORM_MEM(("BTCOEX MODE: %c\n", powermode_val));
455 if (powermode_val == '1') {
456 WL_TRACE_HW4(("DHCP session starts\n"));
457
458 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
459 /* Suppress scan during the DHCP */
460 wl_cfg80211_scan_suppress(dev, 1);
461 #endif /* OEM_ANDROID && DHCP_SCAN_SUPPRESS */
462
463 #ifdef PKT_FILTER_SUPPORT
464 dhd->dhcp_in_progress = 1;
465
466 #if defined(APSTA_BLOCK_ARP_DURING_DHCP)
467 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd)) {
468 /* Block ARP frames while DHCP of STA interface is in
469 * progress in case of STA/SoftAP concurrent mode
470 */
471 wl_cfg80211_block_arp(dev, TRUE);
472 } else
473 #endif /* APSTA_BLOCK_ARP_DURING_DHCP */
474 if (dhd->early_suspended) {
475 WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n"));
476 dhd_enable_packet_filter(0, dhd);
477 }
478 #endif /* PKT_FILTER_SUPPORT */
479
480 /* Retrieve and saved orig regs value */
481 if ((saved_status == FALSE) &&
482 #ifndef OEM_ANDROID
483 (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) &&
484 #endif
485 (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
486 (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
487 (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
488 saved_status = TRUE;
489 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
490 saved_reg66, saved_reg41, saved_reg68));
491
492 /* Disable PM mode during dhpc session */
493 #ifndef OEM_ANDROID
494 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
495 #endif
496
497 /* Disable PM mode during dhpc session */
498 /* Start BT timer only for SCO connection */
499 if (btcoex_is_sco_active(dev)) {
500 /* btc_params 66 */
501 dev_wlc_bufvar_set(dev, "btc_params",
502 (char *)&buf_reg66va_dhcp_on[0],
503 sizeof(buf_reg66va_dhcp_on));
504 /* btc_params 41 0x33 */
505 dev_wlc_bufvar_set(dev, "btc_params",
506 (char *)&buf_reg41va_dhcp_on[0],
507 sizeof(buf_reg41va_dhcp_on));
508 /* btc_params 68 0x190 */
509 dev_wlc_bufvar_set(dev, "btc_params",
510 (char *)&buf_reg68va_dhcp_on[0],
511 sizeof(buf_reg68va_dhcp_on));
512 saved_status = TRUE;
513
514 btco_inf->bt_state = BT_DHCP_START;
515 btco_inf->timer_on = 1;
516 mod_timer(&btco_inf->timer,
517 timer_expires(&btco_inf->timer));
518 WL_TRACE(("enable BT DHCP Timer\n"));
519 }
520 }
521 else if (saved_status == TRUE) {
522 WL_ERR(("was called w/o DHCP OFF. Continue\n"));
523 }
524 }
525 #ifdef OEM_ANDROID
526 else if (powermode_val == '2')
527 #else
528 else if (powermode_val == '0')
529 #endif
530 {
531 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
532 /* Since DHCP is complete, enable the scan back */
533 wl_cfg80211_scan_suppress(dev, 0);
534 #endif /* OEM_ANDROID */
535
536 #ifdef PKT_FILTER_SUPPORT
537 dhd->dhcp_in_progress = 0;
538 WL_TRACE_HW4(("DHCP is complete \n"));
539
540 #if defined(APSTA_BLOCK_ARP_DURING_DHCP)
541 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd)) {
542 /* Unblock ARP frames */
543 wl_cfg80211_block_arp(dev, FALSE);
544 } else
545 #endif /* APSTA_BLOCK_ARP_DURING_DHCP */
546 if (dhd->early_suspended) {
547 /* Enable packet filtering */
548 WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n"));
549 dhd_enable_packet_filter(1, dhd);
550 }
551 #endif /* PKT_FILTER_SUPPORT */
552
553 /* Restoring PM mode */
554 #ifndef OEM_ANDROID
555 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
556 #endif
557
558 /* Stop any bt timer because DHCP session is done */
559 WL_TRACE(("disable BT DHCP Timer\n"));
560 if (btco_inf->timer_on) {
561 btco_inf->timer_on = 0;
562 del_timer_sync(&btco_inf->timer);
563
564 if (btco_inf->bt_state != BT_DHCP_IDLE) {
565 /* ANDREY: case when framework signals DHCP end before STM timeout */
566 /* need to restore original btc flags & extra btc params */
567 WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state));
568 /* wake up btcoex thread to restore btlags+params */
569 schedule_work(&btco_inf->work);
570 }
571 }
572
573 /* Restoring btc_flag paramter anyway */
574 if (saved_status == TRUE)
575 dev_wlc_bufvar_set(dev, "btc_flags",
576 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
577
578 /* Restore original values */
579 if (saved_status == TRUE) {
580 regaddr = 66;
581 dev_wlc_intvar_set_reg(dev, "btc_params",
582 (char *)®addr, (char *)&saved_reg66);
583 regaddr = 41;
584 dev_wlc_intvar_set_reg(dev, "btc_params",
585 (char *)®addr, (char *)&saved_reg41);
586 regaddr = 68;
587 dev_wlc_intvar_set_reg(dev, "btc_params",
588 (char *)®addr, (char *)&saved_reg68);
589
590 WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
591 saved_reg66, saved_reg41, saved_reg68));
592 }
593 saved_status = FALSE;
594
595 }
596 else {
597 WL_ERR(("Unknown yet power setting, ignored\n"));
598 }
599 return 0;
600 }
601 #endif /* defined(OEM_ANDROID) */
602