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