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