Commit | Line | Data |
---|---|---|
84813812 LJ |
1 | /* |
2 | * Linux cfg80211 driver - Dongle Host Driver (DHD) related | |
3 | * | |
4 | * Copyright (C) 1999-2016, Broadcom Corporation | |
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 | * Notwithstanding the above, under no circumstances may you combine this | |
21 | * software in any way with any other Broadcom software provided under a license | |
22 | * other than the GPL, without Broadcom's express prior written consent. | |
23 | * | |
24 | * | |
25 | * <<Broadcom-WL-IPTag/Open:>> | |
26 | * | |
27 | * $Id: wl_cfg_btcoex.c 514727 2014-11-12 03:02:48Z $ | |
28 | */ | |
29 | ||
30 | #include <net/rtnetlink.h> | |
31 | ||
32 | #include <bcmutils.h> | |
33 | #include <wldev_common.h> | |
34 | #include <wl_cfg80211.h> | |
35 | #include <dhd_cfg80211.h> | |
36 | #include <dngl_stats.h> | |
37 | #include <dhd.h> | |
38 | #include <dhdioctl.h> | |
39 | #include <wlioctl.h> | |
40 | ||
41 | #ifdef PKT_FILTER_SUPPORT | |
42 | extern uint dhd_pkt_filter_enable; | |
43 | extern uint dhd_master_mode; | |
44 | extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); | |
45 | #endif | |
46 | ||
47 | struct btcoex_info { | |
48 | struct timer_list timer; | |
49 | u32 timer_ms; | |
50 | u32 timer_on; | |
51 | u32 ts_dhcp_start; /* ms ts ecord time stats */ | |
52 | u32 ts_dhcp_ok; /* ms ts ecord time stats */ | |
53 | bool dhcp_done; /* flag, indicates that host done with | |
54 | * dhcp before t1/t2 expiration | |
55 | */ | |
56 | s32 bt_state; | |
57 | struct work_struct work; | |
58 | struct net_device *dev; | |
59 | }; | |
60 | ||
61 | #if defined(OEM_ANDROID) | |
62 | static struct btcoex_info *btcoex_info_loc = NULL; | |
63 | ||
64 | /* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ | |
65 | ||
66 | /* use New SCO/eSCO smart YG suppression */ | |
67 | #define BT_DHCP_eSCO_FIX | |
68 | /* this flag boost wifi pkt priority to max, caution: -not fair to sco */ | |
69 | #define BT_DHCP_USE_FLAGS | |
70 | /* T1 start SCO/ESCo priority suppression */ | |
71 | #define BT_DHCP_OPPR_WIN_TIME 2500 | |
72 | /* T2 turn off SCO/SCO supperesion is (timeout) */ | |
73 | #define BT_DHCP_FLAG_FORCE_TIME 5500 | |
74 | ||
75 | enum wl_cfg80211_btcoex_status { | |
76 | BT_DHCP_IDLE, | |
77 | BT_DHCP_START, | |
78 | BT_DHCP_OPPR_WIN, | |
79 | BT_DHCP_FLAG_FORCE_TIMEOUT | |
80 | }; | |
81 | ||
82 | /* | |
83 | * get named driver variable to uint register value and return error indication | |
84 | * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) | |
85 | */ | |
86 | static int | |
87 | dev_wlc_intvar_get_reg(struct net_device *dev, char *name, | |
88 | uint reg, int *retval) | |
89 | { | |
90 | union { | |
91 | char buf[WLC_IOCTL_SMLEN]; | |
92 | int val; | |
93 | } var; | |
94 | int error; | |
95 | ||
96 | bcm_mkiovar(name, (char *)(®), sizeof(reg), | |
97 | (char *)(&var), sizeof(var.buf)); | |
98 | error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); | |
99 | ||
100 | *retval = dtoh32(var.val); | |
101 | return (error); | |
102 | } | |
103 | ||
104 | static int | |
105 | dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) | |
106 | { | |
107 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) | |
108 | char ioctlbuf_local[1024]; | |
109 | #else | |
110 | static char ioctlbuf_local[1024]; | |
111 | #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ | |
112 | ||
113 | bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); | |
114 | ||
115 | return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); | |
116 | } | |
117 | /* | |
118 | get named driver variable to uint register value and return error indication | |
119 | calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) | |
120 | */ | |
121 | static int | |
122 | dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) | |
123 | { | |
124 | char reg_addr[8]; | |
125 | ||
126 | memset(reg_addr, 0, sizeof(reg_addr)); | |
127 | memcpy((char *)®_addr[0], (char *)addr, 4); | |
128 | memcpy((char *)®_addr[4], (char *)val, 4); | |
129 | ||
130 | return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); | |
131 | } | |
132 | ||
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 */ | |
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 | WL_TRACE(("override with [50,51,64,65,71]:" | |
218 | "0x%x 0x%x 0x%x 0x%x 0x%x\n", | |
219 | *(u32 *)(buf_reg50va_dhcp_on+4), | |
220 | *(u32 *)(buf_reg51va_dhcp_on+4), | |
221 | *(u32 *)(buf_reg64va_dhcp_on+4), | |
222 | *(u32 *)(buf_reg65va_dhcp_on+4), | |
223 | *(u32 *)(buf_reg71va_dhcp_on+4))); | |
224 | ||
225 | dev_wlc_bufvar_set(dev, "btc_params", | |
226 | (char *)&buf_reg50va_dhcp_on[0], 8); | |
227 | dev_wlc_bufvar_set(dev, "btc_params", | |
228 | (char *)&buf_reg51va_dhcp_on[0], 8); | |
229 | dev_wlc_bufvar_set(dev, "btc_params", | |
230 | (char *)&buf_reg64va_dhcp_on[0], 8); | |
231 | dev_wlc_bufvar_set(dev, "btc_params", | |
232 | (char *)&buf_reg65va_dhcp_on[0], 8); | |
233 | dev_wlc_bufvar_set(dev, "btc_params", | |
234 | (char *)&buf_reg71va_dhcp_on[0], 8); | |
235 | ||
236 | saved_status = TRUE; | |
237 | } else if (saved_status) { | |
238 | /* restore previously saved bt params */ | |
239 | WL_TRACE(("Do new SCO/eSCO coex algo {save &" | |
240 | "override}\n")); | |
241 | ||
242 | regaddr = 50; | |
243 | dev_wlc_intvar_set_reg(dev, "btc_params", | |
244 | (char *)®addr, (char *)&saved_reg50); | |
245 | regaddr = 51; | |
246 | dev_wlc_intvar_set_reg(dev, "btc_params", | |
247 | (char *)®addr, (char *)&saved_reg51); | |
248 | regaddr = 64; | |
249 | dev_wlc_intvar_set_reg(dev, "btc_params", | |
250 | (char *)®addr, (char *)&saved_reg64); | |
251 | regaddr = 65; | |
252 | dev_wlc_intvar_set_reg(dev, "btc_params", | |
253 | (char *)®addr, (char *)&saved_reg65); | |
254 | regaddr = 71; | |
255 | dev_wlc_intvar_set_reg(dev, "btc_params", | |
256 | (char *)®addr, (char *)&saved_reg71); | |
257 | ||
258 | WL_TRACE(("restore bt_params[50,51,64,65,71]:" | |
259 | "0x%x 0x%x 0x%x 0x%x 0x%x\n", | |
260 | saved_reg50, saved_reg51, saved_reg64, | |
261 | saved_reg65, saved_reg71)); | |
262 | ||
263 | saved_status = FALSE; | |
264 | } else { | |
265 | WL_ERR((":%s att to restore not saved BTCOEX params\n", | |
266 | __FUNCTION__)); | |
267 | return -1; | |
268 | } | |
269 | return 0; | |
270 | } | |
271 | #endif /* BT_DHCP_eSCO_FIX */ | |
272 | ||
273 | static void | |
274 | wl_cfg80211_bt_setflag(struct net_device *dev, bool set) | |
275 | { | |
276 | #if defined(BT_DHCP_USE_FLAGS) | |
277 | char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; | |
278 | char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; | |
279 | #endif | |
280 | ||
281 | ||
282 | #if defined(BT_DHCP_eSCO_FIX) | |
283 | /* set = 1, save & turn on 0 - off & restore prev settings */ | |
284 | set_btc_esco_params(dev, set); | |
285 | #endif | |
286 | ||
287 | #if defined(BT_DHCP_USE_FLAGS) | |
288 | WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); | |
289 | if (set == TRUE) | |
290 | /* Forcing bt_flag7 */ | |
291 | dev_wlc_bufvar_set(dev, "btc_flags", | |
292 | (char *)&buf_flag7_dhcp_on[0], | |
293 | sizeof(buf_flag7_dhcp_on)); | |
294 | else | |
295 | /* Restoring default bt flag7 */ | |
296 | dev_wlc_bufvar_set(dev, "btc_flags", | |
297 | (char *)&buf_flag7_default[0], | |
298 | sizeof(buf_flag7_default)); | |
299 | #endif | |
300 | } | |
301 | ||
302 | static void wl_cfg80211_bt_timerfunc(ulong data) | |
303 | { | |
304 | struct btcoex_info *bt_local = (struct btcoex_info *)data; | |
305 | WL_TRACE(("Enter\n")); | |
306 | bt_local->timer_on = 0; | |
307 | schedule_work(&bt_local->work); | |
308 | } | |
309 | ||
310 | static void wl_cfg80211_bt_handler(struct work_struct *work) | |
311 | { | |
312 | struct btcoex_info *btcx_inf; | |
313 | ||
314 | btcx_inf = container_of(work, struct btcoex_info, work); | |
315 | ||
316 | if (btcx_inf->timer_on) { | |
317 | btcx_inf->timer_on = 0; | |
318 | del_timer_sync(&btcx_inf->timer); | |
319 | } | |
320 | ||
321 | switch (btcx_inf->bt_state) { | |
322 | case BT_DHCP_START: | |
323 | /* DHCP started | |
324 | * provide OPPORTUNITY window to get DHCP address | |
325 | */ | |
326 | WL_TRACE(("bt_dhcp stm: started \n")); | |
327 | ||
328 | btcx_inf->bt_state = BT_DHCP_OPPR_WIN; | |
329 | mod_timer(&btcx_inf->timer, | |
330 | jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); | |
331 | btcx_inf->timer_on = 1; | |
332 | break; | |
333 | ||
334 | case BT_DHCP_OPPR_WIN: | |
335 | if (btcx_inf->dhcp_done) { | |
336 | WL_TRACE(("DHCP Done before T1 expiration\n")); | |
337 | goto btc_coex_idle; | |
338 | } | |
339 | ||
340 | /* DHCP is not over yet, start lowering BT priority | |
341 | * enforce btc_params + flags if necessary | |
342 | */ | |
343 | WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME)); | |
344 | if (btcx_inf->dev) | |
345 | wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); | |
346 | btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; | |
347 | mod_timer(&btcx_inf->timer, | |
348 | jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); | |
349 | btcx_inf->timer_on = 1; | |
350 | break; | |
351 | ||
352 | case BT_DHCP_FLAG_FORCE_TIMEOUT: | |
353 | if (btcx_inf->dhcp_done) { | |
354 | WL_TRACE(("DHCP Done before T2 expiration\n")); | |
355 | } else { | |
356 | /* Noo dhcp during T1+T2, restore BT priority */ | |
357 | WL_TRACE(("DHCP wait interval T2:%d msec expired\n", | |
358 | BT_DHCP_FLAG_FORCE_TIME)); | |
359 | } | |
360 | ||
361 | /* Restoring default bt priority */ | |
362 | if (btcx_inf->dev) | |
363 | wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); | |
364 | btc_coex_idle: | |
365 | btcx_inf->bt_state = BT_DHCP_IDLE; | |
366 | btcx_inf->timer_on = 0; | |
367 | break; | |
368 | ||
369 | default: | |
370 | WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); | |
371 | if (btcx_inf->dev) | |
372 | wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); | |
373 | btcx_inf->bt_state = BT_DHCP_IDLE; | |
374 | btcx_inf->timer_on = 0; | |
375 | break; | |
376 | } | |
377 | ||
378 | net_os_wake_unlock(btcx_inf->dev); | |
379 | } | |
380 | ||
381 | void* wl_cfg80211_btcoex_init(struct net_device *ndev) | |
382 | { | |
383 | struct btcoex_info *btco_inf = NULL; | |
384 | ||
385 | btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); | |
386 | if (!btco_inf) | |
387 | return NULL; | |
388 | ||
389 | btco_inf->bt_state = BT_DHCP_IDLE; | |
390 | btco_inf->ts_dhcp_start = 0; | |
391 | btco_inf->ts_dhcp_ok = 0; | |
392 | /* Set up timer for BT */ | |
393 | btco_inf->timer_ms = 10; | |
394 | init_timer(&btco_inf->timer); | |
395 | btco_inf->timer.data = (ulong)btco_inf; | |
396 | btco_inf->timer.function = wl_cfg80211_bt_timerfunc; | |
397 | ||
398 | btco_inf->dev = ndev; | |
399 | ||
400 | INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); | |
401 | ||
402 | btcoex_info_loc = btco_inf; | |
403 | return btco_inf; | |
404 | } | |
405 | ||
95987a5c | 406 | void wl_cfg80211_btcoex_deinit(void) |
84813812 LJ |
407 | { |
408 | if (!btcoex_info_loc) | |
409 | return; | |
410 | ||
411 | if (btcoex_info_loc->timer_on) { | |
412 | btcoex_info_loc->timer_on = 0; | |
413 | del_timer_sync(&btcoex_info_loc->timer); | |
414 | } | |
415 | ||
416 | cancel_work_sync(&btcoex_info_loc->work); | |
417 | ||
418 | kfree(btcoex_info_loc); | |
419 | } | |
420 | ||
421 | int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command) | |
422 | { | |
423 | ||
424 | #ifndef OEM_ANDROID | |
425 | static int pm = PM_FAST; | |
426 | int pm_local = PM_OFF; | |
427 | #endif /* OEM_ANDROID */ | |
428 | struct btcoex_info *btco_inf = btcoex_info_loc; | |
429 | char powermode_val = 0; | |
430 | char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; | |
431 | char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; | |
432 | char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; | |
433 | ||
434 | uint32 regaddr; | |
435 | static uint32 saved_reg66; | |
436 | static uint32 saved_reg41; | |
437 | static uint32 saved_reg68; | |
438 | static bool saved_status = FALSE; | |
439 | ||
440 | char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; | |
441 | ||
442 | /* Figure out powermode 1 or o command */ | |
443 | #ifdef OEM_ANDROID | |
444 | strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); | |
445 | #else | |
446 | strncpy((char *)&powermode_val, command + strlen("POWERMODE") +1, 1); | |
447 | #endif | |
448 | ||
449 | if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { | |
450 | WL_TRACE_HW4(("DHCP session starts\n")); | |
451 | ||
452 | #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS) | |
453 | /* Suppress scan during the DHCP */ | |
454 | wl_cfg80211_scan_suppress(dev, 1); | |
455 | #endif /* OEM_ANDROID */ | |
456 | ||
457 | #ifdef PKT_FILTER_SUPPORT | |
458 | dhd->dhcp_in_progress = 1; | |
459 | ||
460 | if (dhd->early_suspended) { | |
461 | WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); | |
462 | dhd_enable_packet_filter(0, dhd); | |
463 | } | |
464 | #endif | |
465 | ||
466 | /* Retrieve and saved orig regs value */ | |
467 | if ((saved_status == FALSE) && | |
468 | #ifndef OEM_ANDROID | |
469 | (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) && | |
470 | #endif | |
471 | (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && | |
472 | (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && | |
473 | (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { | |
474 | saved_status = TRUE; | |
475 | WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", | |
476 | saved_reg66, saved_reg41, saved_reg68)); | |
477 | ||
478 | /* Disable PM mode during dhpc session */ | |
479 | #ifndef OEM_ANDROID | |
480 | dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); | |
481 | #endif | |
482 | ||
483 | /* Disable PM mode during dhpc session */ | |
484 | /* Start BT timer only for SCO connection */ | |
485 | if (btcoex_is_sco_active(dev)) { | |
486 | /* btc_params 66 */ | |
487 | dev_wlc_bufvar_set(dev, "btc_params", | |
488 | (char *)&buf_reg66va_dhcp_on[0], | |
489 | sizeof(buf_reg66va_dhcp_on)); | |
490 | /* btc_params 41 0x33 */ | |
491 | dev_wlc_bufvar_set(dev, "btc_params", | |
492 | (char *)&buf_reg41va_dhcp_on[0], | |
493 | sizeof(buf_reg41va_dhcp_on)); | |
494 | /* btc_params 68 0x190 */ | |
495 | dev_wlc_bufvar_set(dev, "btc_params", | |
496 | (char *)&buf_reg68va_dhcp_on[0], | |
497 | sizeof(buf_reg68va_dhcp_on)); | |
498 | saved_status = TRUE; | |
499 | ||
500 | btco_inf->bt_state = BT_DHCP_START; | |
501 | btco_inf->timer_on = 1; | |
502 | mod_timer(&btco_inf->timer, btco_inf->timer.expires); | |
503 | WL_TRACE(("enable BT DHCP Timer\n")); | |
504 | } | |
505 | } | |
506 | else if (saved_status == TRUE) { | |
507 | WL_ERR(("was called w/o DHCP OFF. Continue\n")); | |
508 | } | |
509 | } | |
510 | #ifdef OEM_ANDROID | |
511 | else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) | |
512 | #else | |
513 | else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) | |
514 | #endif | |
515 | { | |
516 | ||
517 | #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS) | |
518 | /* Since DHCP is complete, enable the scan back */ | |
519 | wl_cfg80211_scan_suppress(dev, 0); | |
520 | #endif /* OEM_ANDROID */ | |
521 | ||
522 | #ifdef PKT_FILTER_SUPPORT | |
523 | dhd->dhcp_in_progress = 0; | |
524 | WL_TRACE_HW4(("DHCP is complete \n")); | |
525 | ||
526 | /* Enable packet filtering */ | |
527 | if (dhd->early_suspended) { | |
528 | WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); | |
529 | dhd_enable_packet_filter(1, dhd); | |
530 | } | |
531 | #endif /* PKT_FILTER_SUPPORT */ | |
532 | ||
533 | /* Restoring PM mode */ | |
534 | #ifndef OEM_ANDROID | |
535 | dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); | |
536 | #endif | |
537 | ||
538 | /* Stop any bt timer because DHCP session is done */ | |
539 | WL_TRACE(("disable BT DHCP Timer\n")); | |
540 | if (btco_inf->timer_on) { | |
541 | btco_inf->timer_on = 0; | |
542 | del_timer_sync(&btco_inf->timer); | |
543 | ||
544 | if (btco_inf->bt_state != BT_DHCP_IDLE) { | |
545 | /* need to restore original btc flags & extra btc params */ | |
546 | WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state)); | |
547 | /* wake up btcoex thread to restore btlags+params */ | |
548 | schedule_work(&btco_inf->work); | |
549 | } | |
550 | } | |
551 | ||
552 | /* Restoring btc_flag paramter anyway */ | |
553 | if (saved_status == TRUE) | |
554 | dev_wlc_bufvar_set(dev, "btc_flags", | |
555 | (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); | |
556 | ||
557 | /* Restore original values */ | |
558 | if (saved_status == TRUE) { | |
559 | regaddr = 66; | |
560 | dev_wlc_intvar_set_reg(dev, "btc_params", | |
561 | (char *)®addr, (char *)&saved_reg66); | |
562 | regaddr = 41; | |
563 | dev_wlc_intvar_set_reg(dev, "btc_params", | |
564 | (char *)®addr, (char *)&saved_reg41); | |
565 | regaddr = 68; | |
566 | dev_wlc_intvar_set_reg(dev, "btc_params", | |
567 | (char *)®addr, (char *)&saved_reg68); | |
568 | ||
569 | WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", | |
570 | saved_reg66, saved_reg41, saved_reg68)); | |
571 | } | |
572 | saved_status = FALSE; | |
573 | ||
574 | } | |
575 | else { | |
576 | WL_ERR(("Unkwown yet power setting, ignored\n")); | |
577 | } | |
578 | ||
579 | snprintf(command, 3, "OK"); | |
580 | ||
581 | return (strlen("OK")); | |
582 | } | |
583 | #endif /* defined(OEM_ANDROID) */ |