Merge tag 'lsk-android-14.02' into develop-3.10
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / dhd_cfg80211.c
1 /*
2  * Linux cfg80211 driver - Dongle Host Driver (DHD) related
3  *
4  * $Copyright Open Broadcom Corporation$
5  *
6  * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
7  */
8
9 #include <net/rtnetlink.h>
10
11 #include <bcmutils.h>
12 #include <wldev_common.h>
13 #include <wl_cfg80211.h>
14 #include <dhd_cfg80211.h>
15
16 #ifdef PKT_FILTER_SUPPORT
17 #include <dngl_stats.h>
18 #include <dhd.h>
19 #endif
20
21 extern struct wl_priv *wlcfg_drv_priv;
22
23 #ifdef PKT_FILTER_SUPPORT
24 extern uint dhd_pkt_filter_enable;
25 extern uint dhd_master_mode;
26 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
27 #endif
28
29 static int dhd_dongle_up = FALSE;
30
31 #include <dngl_stats.h>
32 #include <dhd.h>
33 #include <dhdioctl.h>
34 #include <wlioctl.h>
35 #include <dhd_cfg80211.h>
36
37 static s32 wl_dongle_up(struct net_device *ndev, u32 up);
38
39 /**
40  * Function implementations
41  */
42
43 s32 dhd_cfg80211_init(struct wl_priv *wl)
44 {
45         dhd_dongle_up = FALSE;
46         return 0;
47 }
48
49 s32 dhd_cfg80211_deinit(struct wl_priv *wl)
50 {
51         dhd_dongle_up = FALSE;
52         return 0;
53 }
54
55 s32 dhd_cfg80211_down(struct wl_priv *wl)
56 {
57         dhd_dongle_up = FALSE;
58         return 0;
59 }
60
61 s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val)
62 {
63         dhd_pub_t *dhd =  (dhd_pub_t *)(wl->pub);
64         dhd->op_mode |= val;
65         WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode));
66 #ifdef ARP_OFFLOAD_SUPPORT
67         if (dhd->arp_version == 1) {
68                 /* IF P2P is enabled, disable arpoe */
69                 dhd_arp_offload_set(dhd, 0);
70                 dhd_arp_offload_enable(dhd, false);
71         }
72 #endif /* ARP_OFFLOAD_SUPPORT */
73
74         return 0;
75 }
76
77 s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl)
78 {
79         dhd_pub_t *dhd =  (dhd_pub_t *)(wl->pub);
80         dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE);
81         WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode));
82
83 #ifdef ARP_OFFLOAD_SUPPORT
84         if (dhd->arp_version == 1) {
85                 /* IF P2P is disabled, enable arpoe back for STA mode. */
86                 dhd_arp_offload_set(dhd, dhd_arp_mode);
87                 dhd_arp_offload_enable(dhd, true);
88         }
89 #endif /* ARP_OFFLOAD_SUPPORT */
90
91         return 0;
92 }
93
94 static s32 wl_dongle_up(struct net_device *ndev, u32 up)
95 {
96         s32 err = 0;
97
98         err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
99         if (unlikely(err)) {
100                 WL_ERR(("WLC_UP error (%d)\n", err));
101         }
102         return err;
103 }
104 s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock)
105 {
106 #ifndef DHD_SDALIGN
107 #define DHD_SDALIGN     32
108 #endif
109         struct net_device *ndev;
110         s32 err = 0;
111
112         WL_TRACE(("In\n"));
113         if (dhd_dongle_up) {
114                 WL_ERR(("Dongle is already up\n"));
115                 return err;
116         }
117
118         ndev = wl_to_prmry_ndev(wl);
119
120         if (need_lock)
121                 rtnl_lock();
122
123         err = wl_dongle_up(ndev, 0);
124         if (unlikely(err)) {
125                 WL_ERR(("wl_dongle_up failed\n"));
126                 goto default_conf_out;
127         }
128         dhd_dongle_up = true;
129
130 default_conf_out:
131         if (need_lock)
132                 rtnl_unlock();
133         return err;
134
135 }
136
137 #ifdef CONFIG_NL80211_TESTMODE
138 int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
139 {
140         struct sk_buff *reply;
141         struct wl_priv *wl;
142         dhd_pub_t *dhd;
143         dhd_ioctl_t *ioc = data;
144         int err = 0;
145
146         WL_TRACE(("entry: cmd = %d\n", ioc->cmd));
147         wl = wiphy_priv(wiphy);
148         dhd = wl->pub;
149
150         DHD_OS_WAKE_LOCK(dhd);
151
152         /* send to dongle only if we are not waiting for reload already */
153         if (dhd->hang_was_sent) {
154                 WL_ERR(("HANG was sent up earlier\n"));
155                 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS);
156                 DHD_OS_WAKE_UNLOCK(dhd);
157                 return OSL_ERROR(BCME_DONGLE_DOWN);
158         }
159
160         /* currently there is only one wiphy for ifidx 0 */
161         err = dhd_ioctl_process(dhd, 0, ioc);
162         if (err)
163                 goto done;
164
165         /* response data is in ioc->buf so return ioc here */
166         reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*ioc));
167         nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*ioc), ioc);
168         err = cfg80211_testmode_reply(reply);
169 done:
170         DHD_OS_WAKE_UNLOCK(dhd);
171         return err;
172 }
173 #endif /* CONFIG_NL80211_TESTMODE */
174
175 /* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
176 #define COEX_DHCP
177
178 #if defined(COEX_DHCP)
179
180 /* use New SCO/eSCO smart YG suppression */
181 #define BT_DHCP_eSCO_FIX
182 /* this flag boost wifi pkt priority to max, caution: -not fair to sco */
183 #define BT_DHCP_USE_FLAGS
184 /* T1 start SCO/ESCo priority suppression */
185 #define BT_DHCP_OPPR_WIN_TIME   2500
186 /* T2 turn off SCO/SCO supperesion is (timeout) */
187 #define BT_DHCP_FLAG_FORCE_TIME 5500
188
189 enum wl_cfg80211_btcoex_status {
190         BT_DHCP_IDLE,
191         BT_DHCP_START,
192         BT_DHCP_OPPR_WIN,
193         BT_DHCP_FLAG_FORCE_TIMEOUT
194 };
195
196 /*
197  * get named driver variable to uint register value and return error indication
198  * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
199  */
200 static int
201 dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
202         uint reg, int *retval)
203 {
204         union {
205                 char buf[WLC_IOCTL_SMLEN];
206                 int val;
207         } var;
208         int error;
209
210         bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
211                 (char *)(&var), sizeof(var.buf));
212         error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
213
214         *retval = dtoh32(var.val);
215         return (error);
216 }
217
218 static int
219 dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
220 {
221 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
222         char ioctlbuf_local[1024];
223 #else
224         static char ioctlbuf_local[1024];
225 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
226
227         bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
228
229         return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true));
230 }
231 /*
232 get named driver variable to uint register value and return error indication
233 calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
234 */
235 static int
236 dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
237 {
238         char reg_addr[8];
239
240         memset(reg_addr, 0, sizeof(reg_addr));
241         memcpy((char *)&reg_addr[0], (char *)addr, 4);
242         memcpy((char *)&reg_addr[4], (char *)val, 4);
243
244         return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
245 }
246
247 static bool btcoex_is_sco_active(struct net_device *dev)
248 {
249         int ioc_res = 0;
250         bool res = FALSE;
251         int sco_id_cnt = 0;
252         int param27;
253         int i;
254
255         for (i = 0; i < 12; i++) {
256
257                 ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
258
259                 WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27));
260
261                 if (ioc_res < 0) {
262                         WL_ERR(("ioc read btc params error\n"));
263                         break;
264                 }
265
266                 if ((param27 & 0x6) == 2) { /* count both sco & esco  */
267                         sco_id_cnt++;
268                 }
269
270                 if (sco_id_cnt > 2) {
271                         WL_TRACE(("sco/esco detected, pkt id_cnt:%d  samples:%d\n",
272                                 sco_id_cnt, i));
273                         res = TRUE;
274                         break;
275                 }
276
277                 OSL_SLEEP(5);
278         }
279
280         return res;
281 }
282
283 #if defined(BT_DHCP_eSCO_FIX)
284 /* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
285 static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
286 {
287         static bool saved_status = FALSE;
288
289         char buf_reg50va_dhcp_on[8] =
290                 { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
291         char buf_reg51va_dhcp_on[8] =
292                 { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
293         char buf_reg64va_dhcp_on[8] =
294                 { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
295         char buf_reg65va_dhcp_on[8] =
296                 { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
297         char buf_reg71va_dhcp_on[8] =
298                 { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
299         uint32 regaddr;
300         static uint32 saved_reg50;
301         static uint32 saved_reg51;
302         static uint32 saved_reg64;
303         static uint32 saved_reg65;
304         static uint32 saved_reg71;
305
306         if (trump_sco) {
307                 /* this should reduce eSCO agressive retransmit
308                  * w/o breaking it
309                  */
310
311                 /* 1st save current */
312                 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
313                           "override}\n"));
314                 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
315                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
316                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
317                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
318                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
319                         saved_status = TRUE;
320                         WL_TRACE(("saved bt_params[50,51,64,65,71]:"
321                                   "0x%x 0x%x 0x%x 0x%x 0x%x\n",
322                                   saved_reg50, saved_reg51,
323                                   saved_reg64, saved_reg65, saved_reg71));
324                 } else {
325                         WL_ERR((":%s: save btc_params failed\n",
326                                 __FUNCTION__));
327                         saved_status = FALSE;
328                         return -1;
329                 }
330
331                 WL_TRACE(("override with [50,51,64,65,71]:"
332                           "0x%x 0x%x 0x%x 0x%x 0x%x\n",
333                           *(u32 *)(buf_reg50va_dhcp_on+4),
334                           *(u32 *)(buf_reg51va_dhcp_on+4),
335                           *(u32 *)(buf_reg64va_dhcp_on+4),
336                           *(u32 *)(buf_reg65va_dhcp_on+4),
337                           *(u32 *)(buf_reg71va_dhcp_on+4)));
338
339                 dev_wlc_bufvar_set(dev, "btc_params",
340                         (char *)&buf_reg50va_dhcp_on[0], 8);
341                 dev_wlc_bufvar_set(dev, "btc_params",
342                         (char *)&buf_reg51va_dhcp_on[0], 8);
343                 dev_wlc_bufvar_set(dev, "btc_params",
344                         (char *)&buf_reg64va_dhcp_on[0], 8);
345                 dev_wlc_bufvar_set(dev, "btc_params",
346                         (char *)&buf_reg65va_dhcp_on[0], 8);
347                 dev_wlc_bufvar_set(dev, "btc_params",
348                         (char *)&buf_reg71va_dhcp_on[0], 8);
349
350                 saved_status = TRUE;
351         } else if (saved_status) {
352                 /* restore previously saved bt params */
353                 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
354                           "override}\n"));
355
356                 regaddr = 50;
357                 dev_wlc_intvar_set_reg(dev, "btc_params",
358                         (char *)&regaddr, (char *)&saved_reg50);
359                 regaddr = 51;
360                 dev_wlc_intvar_set_reg(dev, "btc_params",
361                         (char *)&regaddr, (char *)&saved_reg51);
362                 regaddr = 64;
363                 dev_wlc_intvar_set_reg(dev, "btc_params",
364                         (char *)&regaddr, (char *)&saved_reg64);
365                 regaddr = 65;
366                 dev_wlc_intvar_set_reg(dev, "btc_params",
367                         (char *)&regaddr, (char *)&saved_reg65);
368                 regaddr = 71;
369                 dev_wlc_intvar_set_reg(dev, "btc_params",
370                         (char *)&regaddr, (char *)&saved_reg71);
371
372                 WL_TRACE(("restore bt_params[50,51,64,65,71]:"
373                         "0x%x 0x%x 0x%x 0x%x 0x%x\n",
374                         saved_reg50, saved_reg51, saved_reg64,
375                         saved_reg65, saved_reg71));
376
377                 saved_status = FALSE;
378         } else {
379                 WL_ERR((":%s att to restore not saved BTCOEX params\n",
380                         __FUNCTION__));
381                 return -1;
382         }
383         return 0;
384 }
385 #endif /* BT_DHCP_eSCO_FIX */
386
387 static void
388 wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
389 {
390 #if defined(BT_DHCP_USE_FLAGS)
391         char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
392         char buf_flag7_default[8]   = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
393 #endif
394
395
396 #if defined(BT_DHCP_eSCO_FIX)
397         /* set = 1, save & turn on  0 - off & restore prev settings */
398         set_btc_esco_params(dev, set);
399 #endif
400
401 #if defined(BT_DHCP_USE_FLAGS)
402         WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
403         if (set == TRUE)
404                 /* Forcing bt_flag7  */
405                 dev_wlc_bufvar_set(dev, "btc_flags",
406                         (char *)&buf_flag7_dhcp_on[0],
407                         sizeof(buf_flag7_dhcp_on));
408         else
409                 /* Restoring default bt flag7 */
410                 dev_wlc_bufvar_set(dev, "btc_flags",
411                         (char *)&buf_flag7_default[0],
412                         sizeof(buf_flag7_default));
413 #endif
414 }
415
416 static void wl_cfg80211_bt_timerfunc(ulong data)
417 {
418         struct btcoex_info *bt_local = (struct btcoex_info *)data;
419         WL_TRACE(("Enter\n"));
420         bt_local->timer_on = 0;
421         schedule_work(&bt_local->work);
422 }
423
424 static void wl_cfg80211_bt_handler(struct work_struct *work)
425 {
426         struct btcoex_info *btcx_inf;
427
428         btcx_inf = container_of(work, struct btcoex_info, work);
429
430         if (btcx_inf->timer_on) {
431                 btcx_inf->timer_on = 0;
432                 del_timer_sync(&btcx_inf->timer);
433         }
434
435         switch (btcx_inf->bt_state) {
436                 case BT_DHCP_START:
437                         /* DHCP started
438                          * provide OPPORTUNITY window to get DHCP address
439                          */
440                         WL_TRACE(("bt_dhcp stm: started \n"));
441
442                         btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
443                         mod_timer(&btcx_inf->timer,
444                                 jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME));
445                         btcx_inf->timer_on = 1;
446                         break;
447
448                 case BT_DHCP_OPPR_WIN:
449                         if (btcx_inf->dhcp_done) {
450                                 WL_TRACE(("DHCP Done before T1 expiration\n"));
451                                 goto btc_coex_idle;
452                         }
453
454                         /* DHCP is not over yet, start lowering BT priority
455                          * enforce btc_params + flags if necessary
456                          */
457                         WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME));
458                         if (btcx_inf->dev)
459                                 wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
460                         btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
461                         mod_timer(&btcx_inf->timer,
462                                 jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME));
463                         btcx_inf->timer_on = 1;
464                         break;
465
466                 case BT_DHCP_FLAG_FORCE_TIMEOUT:
467                         if (btcx_inf->dhcp_done) {
468                                 WL_TRACE(("DHCP Done before T2 expiration\n"));
469                         } else {
470                                 /* Noo dhcp during T1+T2, restore BT priority */
471                                 WL_TRACE(("DHCP wait interval T2:%d msec expired\n",
472                                         BT_DHCP_FLAG_FORCE_TIME));
473                         }
474
475                         /* Restoring default bt priority */
476                         if (btcx_inf->dev)
477                                 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
478 btc_coex_idle:
479                         btcx_inf->bt_state = BT_DHCP_IDLE;
480                         btcx_inf->timer_on = 0;
481                         break;
482
483                 default:
484                         WL_ERR(("error g_status=%d !!!\n",      btcx_inf->bt_state));
485                         if (btcx_inf->dev)
486                                 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
487                         btcx_inf->bt_state = BT_DHCP_IDLE;
488                         btcx_inf->timer_on = 0;
489                         break;
490         }
491
492         net_os_wake_unlock(btcx_inf->dev);
493 }
494
495 int wl_cfg80211_btcoex_init(struct wl_priv *wl)
496 {
497         struct btcoex_info *btco_inf = NULL;
498
499         btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
500         if (!btco_inf)
501                 return -ENOMEM;
502
503         btco_inf->bt_state = BT_DHCP_IDLE;
504         btco_inf->ts_dhcp_start = 0;
505         btco_inf->ts_dhcp_ok = 0;
506         /* Set up timer for BT  */
507         btco_inf->timer_ms = 10;
508         init_timer(&btco_inf->timer);
509         btco_inf->timer.data = (ulong)btco_inf;
510         btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
511
512         btco_inf->dev = wl->wdev->netdev;
513
514         INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
515
516         wl->btcoex_info = btco_inf;
517         return 0;
518 }
519
520 void wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
521 {
522         if (!wl->btcoex_info)
523                 return;
524
525         if (wl->btcoex_info->timer_on) {
526                 wl->btcoex_info->timer_on = 0;
527                 del_timer_sync(&wl->btcoex_info->timer);
528         }
529
530         cancel_work_sync(&wl->btcoex_info->work);
531
532         kfree(wl->btcoex_info);
533         wl->btcoex_info = NULL;
534 }
535
536 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
537 {
538
539         struct wl_priv *wl = wlcfg_drv_priv;
540         char powermode_val = 0;
541         char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
542         char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
543         char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
544
545         uint32 regaddr;
546         static uint32 saved_reg66;
547         static uint32 saved_reg41;
548         static uint32 saved_reg68;
549         static bool saved_status = FALSE;
550
551 #ifdef COEX_DHCP
552         char buf_flag7_default[8] =   { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
553         struct btcoex_info *btco_inf = wl->btcoex_info;
554 #endif /* COEX_DHCP */
555
556 #ifdef PKT_FILTER_SUPPORT
557         dhd_pub_t *dhd =  (dhd_pub_t *)(wl->pub);
558 #endif
559
560         /* Figure out powermode 1 or o command */
561         strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
562
563         if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
564                 WL_TRACE_HW4(("DHCP session starts\n"));
565
566 #if defined(DHCP_SCAN_SUPPRESS)
567                 /* Suppress scan during the DHCP */
568                 wl_cfg80211_scan_suppress(dev, 1);
569 #endif /* OEM_ANDROID */
570
571 #ifdef PKT_FILTER_SUPPORT
572                 dhd->dhcp_in_progress = 1;
573
574                 if (dhd->early_suspended) {
575                         WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n"));
576                         dhd_enable_packet_filter(0, dhd);
577                 }
578 #endif
579
580                 /* Retrieve and saved orig regs value */
581                 if ((saved_status == FALSE) &&
582                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 66,  &saved_reg66)) &&
583                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 41,  &saved_reg41)) &&
584                         (!dev_wlc_intvar_get_reg(dev, "btc_params", 68,  &saved_reg68)))   {
585                                 saved_status = TRUE;
586                                 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
587                                         saved_reg66, saved_reg41, saved_reg68));
588
589                                 /* Disable PM mode during dhpc session */
590
591                                 /* Disable PM mode during dhpc session */
592 #ifdef COEX_DHCP
593                                 /* Start  BT timer only for SCO connection */
594                                 if (btcoex_is_sco_active(dev)) {
595                                         /* btc_params 66 */
596                                         dev_wlc_bufvar_set(dev, "btc_params",
597                                                 (char *)&buf_reg66va_dhcp_on[0],
598                                                 sizeof(buf_reg66va_dhcp_on));
599                                         /* btc_params 41 0x33 */
600                                         dev_wlc_bufvar_set(dev, "btc_params",
601                                                 (char *)&buf_reg41va_dhcp_on[0],
602                                                 sizeof(buf_reg41va_dhcp_on));
603                                         /* btc_params 68 0x190 */
604                                         dev_wlc_bufvar_set(dev, "btc_params",
605                                                 (char *)&buf_reg68va_dhcp_on[0],
606                                                 sizeof(buf_reg68va_dhcp_on));
607                                         saved_status = TRUE;
608
609                                         btco_inf->bt_state = BT_DHCP_START;
610                                         btco_inf->timer_on = 1;
611                                         mod_timer(&btco_inf->timer, btco_inf->timer.expires);
612                                         WL_TRACE(("enable BT DHCP Timer\n"));
613                                 }
614 #endif /* COEX_DHCP */
615                 }
616                 else if (saved_status == TRUE) {
617                         WL_ERR(("was called w/o DHCP OFF. Continue\n"));
618                 }
619         }
620         else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
621
622
623 #if defined(DHCP_SCAN_SUPPRESS)
624                 /* Since DHCP is complete, enable the scan back */
625                 wl_cfg80211_scan_suppress(dev, 0);
626 #endif /* OEM_ANDROID */
627
628 #ifdef PKT_FILTER_SUPPORT
629                 dhd->dhcp_in_progress = 0;
630                 WL_TRACE_HW4(("DHCP is complete \n"));
631
632                 /* Enable packet filtering */
633                 if (dhd->early_suspended) {
634                         WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n"));
635                         dhd_enable_packet_filter(1, dhd);
636                 }
637 #endif /* PKT_FILTER_SUPPORT */
638
639                 /* Restoring PM mode */
640
641 #ifdef COEX_DHCP
642                 /* Stop any bt timer because DHCP session is done */
643                 WL_TRACE(("disable BT DHCP Timer\n"));
644                 if (btco_inf->timer_on) {
645                         btco_inf->timer_on = 0;
646                         del_timer_sync(&btco_inf->timer);
647
648                         if (btco_inf->bt_state != BT_DHCP_IDLE) {
649                         /* need to restore original btc flags & extra btc params */
650                                 WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state));
651                                 /* wake up btcoex thread to restore btlags+params  */
652                                 schedule_work(&btco_inf->work);
653                         }
654                 }
655
656                 /* Restoring btc_flag paramter anyway */
657                 if (saved_status == TRUE)
658                         dev_wlc_bufvar_set(dev, "btc_flags",
659                                 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
660 #endif /* COEX_DHCP */
661
662                 /* Restore original values */
663                 if (saved_status == TRUE) {
664                         regaddr = 66;
665                         dev_wlc_intvar_set_reg(dev, "btc_params",
666                                 (char *)&regaddr, (char *)&saved_reg66);
667                         regaddr = 41;
668                         dev_wlc_intvar_set_reg(dev, "btc_params",
669                                 (char *)&regaddr, (char *)&saved_reg41);
670                         regaddr = 68;
671                         dev_wlc_intvar_set_reg(dev, "btc_params",
672                                 (char *)&regaddr, (char *)&saved_reg68);
673
674                         WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
675                                 saved_reg66, saved_reg41, saved_reg68));
676                 }
677                 saved_status = FALSE;
678
679         }
680         else {
681                 WL_ERR(("Unkwown yet power setting, ignored\n"));
682         }
683
684         snprintf(command, 3, "OK");
685
686         return (strlen("OK"));
687 }
688 #endif