1 /* 2 * Broadcom Dongle Host Driver (DHD), Linux-specific network interface 3 * Basically selected code segments from usb-cdc.c and usb-rndis.c 4 * 5 * Copyright (C) 1999-2010, Broadcom Corporation 6 * 7 * Unless you and Broadcom execute a separate written software license 8 * agreement governing use of this software, this software is licensed to you 9 * under the terms of the GNU General Public License version 2 (the "GPL"), 10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the 11 * following added to such license: 12 * 13 * As a special exception, the copyright holders of this software give you 14 * permission to link this software with independent modules, and to copy and 15 * distribute the resulting executable under terms of your choice, provided that 16 * you also meet, for each linked independent module, the terms and conditions of 17 * the license of that module. An independent module is a module which is not 18 * derived from this software. The special exception does not apply to any 19 * modifications of the software. 20 * 21 * Notwithstanding the above, under no circumstances may you combine this 22 * software in any way with any other Broadcom software provided under a license 23 * other than the GPL, without Broadcom's express prior written consent. 24 * 25 * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.104 2010/08/20 19:15:40 Exp $ 26 */ 27 28 #ifdef CONFIG_WIFI_CONTROL_FUNC 29 #include <linux/platform_device.h> 30 #endif 31 #include <typedefs.h> 32 #include <linuxver.h> 33 #include <osl.h> 34 35 #include <linux/init.h> 36 #include <linux/kernel.h> 37 #include <linux/slab.h> 38 #include <linux/skbuff.h> 39 #include <linux/netdevice.h> 40 #include <linux/etherdevice.h> 41 #include <linux/random.h> 42 #include <linux/spinlock.h> 43 #include <linux/ethtool.h> 44 #include <linux/fcntl.h> 45 #include <linux/fs.h> 46 47 #include <asm/uaccess.h> 48 #include <asm/unaligned.h> 49 50 #include <epivers.h> 51 #include <bcmutils.h> 52 #include <bcmendian.h> 53 54 #include <proto/ethernet.h> 55 #include <dngl_stats.h> 56 #include <dhd.h> 57 #include <dhd_bus.h> 58 #include <dhd_proto.h> 59 #include <dhd_dbg.h> 60 #include <wl_iw.h> 61 #ifdef CONFIG_HAS_WAKELOCK 62 #include <linux/wakelock.h> 63 #endif 64 #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) 65 #include <linux/wlan_plat.h> 66 67 struct semaphore wifi_control_sem; 68 69 struct dhd_bus *g_bus; 70 71 static struct wifi_platform_data *wifi_control_data = NULL; 72 static struct resource *wifi_irqres = NULL; 73 74 int wifi_get_irq_number(unsigned long *irq_flags_ptr) 75 { 76 if (wifi_irqres) { 77 *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; 78 return (int)wifi_irqres->start; 79 } 80 #ifdef CUSTOM_OOB_GPIO_NUM 81 return CUSTOM_OOB_GPIO_NUM; 82 #else 83 return -1; 84 #endif 85 } 86 87 int wifi_set_carddetect(int on) 88 { 89 printk("%s = %d\n", __FUNCTION__, on); 90 if (wifi_control_data && wifi_control_data->set_carddetect) { 91 wifi_control_data->set_carddetect(on); 92 } 93 return 0; 94 } 95 96 int wifi_set_power(int on, unsigned long msec) 97 { 98 printk("%s = %d\n", __FUNCTION__, on); 99 if (wifi_control_data && wifi_control_data->set_power) { 100 wifi_control_data->set_power(on); 101 } 102 if (msec) 103 mdelay(msec); 104 return 0; 105 } 106 107 int wifi_set_reset(int on, unsigned long msec) 108 { 109 printk("%s = %d\n", __FUNCTION__, on); 110 if (wifi_control_data && wifi_control_data->set_reset) { 111 wifi_control_data->set_reset(on); 112 } 113 if (msec) 114 mdelay(msec); 115 return 0; 116 } 117 118 int wifi_get_mac_addr(unsigned char *buf) 119 { 120 printk("%s\n", __FUNCTION__); 121 if (!buf) 122 return -EINVAL; 123 if (wifi_control_data && wifi_control_data->get_mac_addr) { 124 return wifi_control_data->get_mac_addr(buf); 125 } 126 return -EOPNOTSUPP; 127 } 128 129 static int wifi_probe(struct platform_device *pdev) 130 { 131 struct wifi_platform_data *wifi_ctrl = 132 (struct wifi_platform_data *)(pdev->dev.platform_data); 133 134 DHD_TRACE(("## %s\n", __FUNCTION__)); 135 wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); 136 wifi_control_data = wifi_ctrl; 137 138 wifi_set_power(1, 0); /* Power On */ 139 wifi_set_carddetect(1); /* CardDetect (0->1) */ 140 141 up(&wifi_control_sem); 142 return 0; 143 } 144 145 static int wifi_remove(struct platform_device *pdev) 146 { 147 struct wifi_platform_data *wifi_ctrl = 148 (struct wifi_platform_data *)(pdev->dev.platform_data); 149 150 DHD_TRACE(("## %s\n", __FUNCTION__)); 151 wifi_control_data = wifi_ctrl; 152 153 wifi_set_power(0, 0); /* Power Off */ 154 wifi_set_carddetect(0); /* CardDetect (1->0) */ 155 156 up(&wifi_control_sem); 157 return 0; 158 } 159 static int wifi_suspend(struct platform_device *pdev, pm_message_t state) 160 { 161 DHD_TRACE(("##> %s\n", __FUNCTION__)); 162 return 0; 163 } 164 static int wifi_resume(struct platform_device *pdev) 165 { 166 DHD_TRACE(("##> %s\n", __FUNCTION__)); 167 return 0; 168 } 169 170 static struct platform_driver wifi_device = { 171 .probe = wifi_probe, 172 .remove = wifi_remove, 173 .suspend = wifi_suspend, 174 .resume = wifi_resume, 175 .driver = { 176 .name = "bcm4329_wlan", 177 } 178 }; 179 180 int wifi_add_dev(void) 181 { 182 DHD_TRACE(("## Calling platform_driver_register\n")); 183 return platform_driver_register(&wifi_device); 184 } 185 186 void wifi_del_dev(void) 187 { 188 DHD_TRACE(("## Unregister platform_driver_register\n")); 189 platform_driver_unregister(&wifi_device); 190 } 191 #endif /* defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ 192 193 194 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) 195 #include <linux/suspend.h> 196 volatile bool dhd_mmc_suspend = FALSE; 197 DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); 198 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ 199 200 #if defined(OOB_INTR_ONLY) 201 extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); 202 #endif /* defined(OOB_INTR_ONLY) */ 203 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) 204 MODULE_LICENSE("GPL v2"); 205 #endif /* LinuxVer */ 206 207 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) 208 const char * 209 print_tainted() 210 { 211 return ""; 212 } 213 #endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ 214 215 /* Linux wireless extension support */ 216 #if defined(CONFIG_WIRELESS_EXT) 217 #include <wl_iw.h> 218 #endif /* defined(CONFIG_WIRELESS_EXT) */ 219 220 #if defined(CONFIG_HAS_EARLYSUSPEND) 221 #include <linux/earlysuspend.h> 222 extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); 223 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ 224 225 #ifdef PKT_FILTER_SUPPORT 226 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); 227 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); 228 #endif 229 230 /* Interface control information */ 231 typedef struct dhd_if { 232 struct dhd_info *info; /* back pointer to dhd_info */ 233 /* OS/stack specifics */ 234 struct net_device *net; 235 struct net_device_stats stats; 236 int idx; /* iface idx in dongle */ 237 int state; /* interface state */ 238 uint subunit; /* subunit */ 239 uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ 240 bool attached; /* Delayed attachment when unset */ 241 bool txflowcontrol; /* Per interface flow control indicator */ 242 char name[IFNAMSIZ+1]; /* linux interface name */ 243 } dhd_if_t; 244 245 /* Local private structure (extension of pub) */ 246 typedef struct dhd_info { 247 #if defined(CONFIG_WIRELESS_EXT) 248 wl_iw_t iw; /* wireless extensions state (must be first) */ 249 #endif /* defined(CONFIG_WIRELESS_EXT) */ 250 251 dhd_pub_t pub; 252 253 /* OS/stack specifics */ 254 dhd_if_t *iflist[DHD_MAX_IFS]; 255 256 struct semaphore proto_sem; 257 wait_queue_head_t ioctl_resp_wait; 258 struct timer_list timer; 259 bool wd_timer_valid; 260 struct tasklet_struct tasklet; 261 spinlock_t sdlock; 262 spinlock_t txqlock; 263 /* Thread based operation */ 264 bool threads_only; 265 struct semaphore sdsem; 266 long watchdog_pid; 267 struct semaphore watchdog_sem; 268 struct completion watchdog_exited; 269 long dpc_pid; 270 struct semaphore dpc_sem; 271 struct completion dpc_exited; 272 273 /* Wakelocks */ 274 #ifdef CONFIG_HAS_WAKELOCK 275 struct wake_lock wl_wifi; /* Wifi wakelock */ 276 struct wake_lock wl_rxwake; /* Wifi rx wakelock */ 277 #endif 278 spinlock_t wl_lock; 279 int wl_count; 280 int wl_packet; 281 282 int hang_was_sent; 283 284 /* Thread to issue ioctl for multicast */ 285 long sysioc_pid; 286 struct semaphore sysioc_sem; 287 struct completion sysioc_exited; 288 bool set_multicast; 289 bool set_macaddress; 290 struct ether_addr macvalue; 291 wait_queue_head_t ctrl_wait; 292 atomic_t pend_8021x_cnt; 293 294 #ifdef CONFIG_HAS_EARLYSUSPEND 295 struct early_suspend early_suspend; 296 #endif /* CONFIG_HAS_EARLYSUSPEND */ 297 } dhd_info_t; 298 299 /* Definitions to provide path to the firmware and nvram 300 * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" 301 */ 302 char firmware_path[MOD_PARAM_PATHLEN]; 303 char nvram_path[MOD_PARAM_PATHLEN]; 304 305 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 306 struct semaphore dhd_registration_sem; 307 #define DHD_REGISTRATION_TIMEOUT 8000 /* msec : allowed time to finished dhd registration */ 308 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ 309 /* load firmware and/or nvram values from the filesystem */ 310 module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0); 311 module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); 312 313 /* Error bits */ 314 module_param(dhd_msg_level, int, 0); 315 316 /* Spawn a thread for system ioctls (set mac, set mcast) */ 317 uint dhd_sysioc = TRUE; 318 module_param(dhd_sysioc, uint, 0); 319 320 /* Watchdog interval */ 321 uint dhd_watchdog_ms = 10; 322 module_param(dhd_watchdog_ms, uint, 0); 323 324 #ifdef DHD_DEBUG 325 /* Console poll interval */ 326 uint dhd_console_ms = 0; 327 module_param(dhd_console_ms, uint, 0); 328 #endif /* DHD_DEBUG */ 329 330 /* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ 331 uint dhd_arp_mode = 0xb; 332 module_param(dhd_arp_mode, uint, 0); 333 334 /* ARP offload enable */ 335 uint dhd_arp_enable = TRUE; 336 module_param(dhd_arp_enable, uint, 0); 337 338 /* Global Pkt filter enable control */ 339 uint dhd_pkt_filter_enable = TRUE; 340 module_param(dhd_pkt_filter_enable, uint, 0); 341 342 /* Pkt filter init setup */ 343 uint dhd_pkt_filter_init = 0; 344 module_param(dhd_pkt_filter_init, uint, 0); 345 346 /* Pkt filter mode control */ 347 uint dhd_master_mode = TRUE; 348 module_param(dhd_master_mode, uint, 1); 349 350 /* Watchdog thread priority, -1 to use kernel timer */ 351 int dhd_watchdog_prio = 97; 352 module_param(dhd_watchdog_prio, int, 0); 353 354 /* DPC thread priority, -1 to use tasklet */ 355 int dhd_dpc_prio = 98; 356 module_param(dhd_dpc_prio, int, 0); 357 358 /* DPC thread priority, -1 to use tasklet */ 359 extern int dhd_dongle_memsize; 360 module_param(dhd_dongle_memsize, int, 0); 361 362 /* Control fw roaming */ 363 #ifdef CUSTOMER_HW2 364 uint dhd_roam = 0; 365 #else 366 uint dhd_roam = 1; 367 #endif 368 369 /* Control radio state */ 370 uint dhd_radio_up = 1; 371 372 /* Network inteface name */ 373 char iface_name[IFNAMSIZ]; 374 module_param_string(iface_name, iface_name, IFNAMSIZ, 0); 375 376 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) 377 #define DAEMONIZE(a) daemonize(a); \ 378 allow_signal(SIGKILL); \ 379 allow_signal(SIGTERM); 380 #else /* Linux 2.4 (w/o preemption patch) */ 381 #define RAISE_RX_SOFTIRQ() \ 382 cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) 383 #define DAEMONIZE(a) daemonize(); \ 384 do { if (a) \ 385 strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ 386 } while (0); 387 #endif /* LINUX_VERSION_CODE */ 388 389 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) 390 #define BLOCKABLE() (!in_atomic()) 391 #else 392 #define BLOCKABLE() (!in_interrupt()) 393 #endif 394 395 /* The following are specific to the SDIO dongle */ 396 397 /* IOCTL response timeout */ 398 int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; 399 400 /* Idle timeout for backplane clock */ 401 int dhd_idletime = DHD_IDLETIME_TICKS; 402 module_param(dhd_idletime, int, 0); 403 404 /* Use polling */ 405 uint dhd_poll = FALSE; 406 module_param(dhd_poll, uint, 0); 407 408 /* Use interrupts */ 409 uint dhd_intr = TRUE; 410 module_param(dhd_intr, uint, 0); 411 412 /* SDIO Drive Strength (in milliamps) */ 413 uint dhd_sdiod_drive_strength = 6; 414 module_param(dhd_sdiod_drive_strength, uint, 0); 415 416 /* Tx/Rx bounds */ 417 extern uint dhd_txbound; 418 extern uint dhd_rxbound; 419 module_param(dhd_txbound, uint, 0); 420 module_param(dhd_rxbound, uint, 0); 421 422 /* Deferred transmits */ 423 extern uint dhd_deferred_tx; 424 module_param(dhd_deferred_tx, uint, 0); 425 426 427 428 #ifdef SDTEST 429 /* Echo packet generator (pkts/s) */ 430 uint dhd_pktgen = 0; 431 module_param(dhd_pktgen, uint, 0); 432 433 /* Echo packet len (0 => sawtooth, max 2040) */ 434 uint dhd_pktgen_len = 0; 435 module_param(dhd_pktgen_len, uint, 0); 436 #endif 437 438 /* Version string to report */ 439 #ifdef DHD_DEBUG 440 #ifndef SRCBASE 441 #define SRCBASE "drivers/net/wireless/bcm4329" 442 #endif 443 #define DHD_COMPILED "\nCompiled in " SRCBASE 444 #else 445 #define DHD_COMPILED 446 #endif 447 448 static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR 449 #ifdef DHD_DEBUG 450 "\nCompiled in " SRCBASE " on " __DATE__ " at " __TIME__ 451 #endif 452 ; 453 454 455 #if defined(CONFIG_WIRELESS_EXT) 456 struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); 457 #endif /* defined(CONFIG_WIRELESS_EXT) */ 458 459 static void dhd_dpc(ulong data); 460 /* forward decl */ 461 extern int dhd_wait_pend8021x(struct net_device *dev); 462 463 #ifdef TOE 464 #ifndef BDC 465 #error TOE requires BDC 466 #endif /* !BDC */ 467 static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); 468 static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); 469 #endif /* TOE */ 470 471 static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, 472 wl_event_msg_t *event_ptr, void **data_ptr); 473 474 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) 475 static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) 476 { 477 int ret = NOTIFY_DONE; 478 479 switch (action) { 480 case PM_HIBERNATION_PREPARE: 481 case PM_SUSPEND_PREPARE: 482 dhd_mmc_suspend = TRUE; 483 ret = NOTIFY_OK; 484 break; 485 case PM_POST_HIBERNATION: 486 case PM_POST_SUSPEND: 487 dhd_mmc_suspend = FALSE; 488 ret = NOTIFY_OK; 489 break; 490 } 491 smp_mb(); 492 return ret; 493 } 494 495 static struct notifier_block dhd_sleep_pm_notifier = { 496 .notifier_call = dhd_sleep_pm_callback, 497 .priority = 0 498 }; 499 extern int register_pm_notifier(struct notifier_block *nb); 500 extern int unregister_pm_notifier(struct notifier_block *nb); 501 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ 502 503 static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) 504 { 505 #ifdef PKT_FILTER_SUPPORT 506 DHD_TRACE(("%s: %d\n", __FUNCTION__, value)); 507 /* 1 - Enable packet filter, only allow unicast packet to send up */ 508 /* 0 - Disable packet filter */ 509 if (dhd_pkt_filter_enable) { 510 int i; 511 512 for (i = 0; i < dhd->pktfilter_count; i++) { 513 dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); 514 dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], 515 value, dhd_master_mode); 516 } 517 } 518 #endif 519 } 520 521 #if defined(CONFIG_HAS_EARLYSUSPEND) 522 static int dhd_set_suspend(int value, dhd_pub_t *dhd) 523 { 524 int power_mode = PM_MAX; 525 /* wl_pkt_filter_enable_t enable_parm; */ 526 char iovbuf[32]; 527 int bcn_li_dtim = 3; 528 #ifdef CUSTOMER_HW2 529 uint roamvar = 1; 530 #endif /* CUSTOMER_HW2 */ 531 532 DHD_TRACE(("%s: enter, value = %d in_suspend = %d\n", 533 __FUNCTION__, value, dhd->in_suspend)); 534 535 if (dhd && dhd->up) { 536 if (value && dhd->in_suspend) { 537 538 /* Kernel suspended */ 539 DHD_TRACE(("%s: force extra Suspend setting \n", __FUNCTION__)); 540 541 dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, 542 (char *)&power_mode, sizeof(power_mode)); 543 544 /* Enable packet filter, only allow unicast packet to send up */ 545 dhd_set_packet_filter(1, dhd); 546 547 /* if dtim skip setup as default force it to wake each thrid dtim 548 * for better power saving. 549 * Note that side effect is chance to miss BC/MC packet 550 */ 551 if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1)) 552 bcn_li_dtim = 3; 553 else 554 bcn_li_dtim = dhd->dtim_skip; 555 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, 556 4, iovbuf, sizeof(iovbuf)); 557 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 558 #ifdef CUSTOMER_HW2 559 /* Disable build-in roaming to allowed ext supplicant to take of roaming */ 560 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); 561 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 562 #endif /* CUSTOMER_HW2 */ 563 } else { 564 565 /* Kernel resumed */ 566 DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); 567 568 power_mode = PM_FAST; 569 dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, 570 sizeof(power_mode)); 571 572 /* disable pkt filter */ 573 dhd_set_packet_filter(0, dhd); 574 575 /* restore pre-suspend setting for dtim_skip */ 576 bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, 577 4, iovbuf, sizeof(iovbuf)); 578 579 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 580 #ifdef CUSTOMER_HW2 581 roamvar = dhd_roam; 582 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); 583 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); 584 #endif /* CUSTOMER_HW2 */ 585 } 586 } 587 588 return 0; 589 } 590 591 static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val) 592 { 593 dhd_pub_t *dhdp = &dhd->pub; 594 595 dhd_os_wake_lock(dhdp); 596 dhd_os_proto_block(dhdp); 597 /* Set flag when early suspend was called */ 598 dhdp->in_suspend = val; 599 if (!dhdp->suspend_disable_flag) 600 dhd_set_suspend(val, dhdp); 601 dhd_os_proto_unblock(dhdp); 602 dhd_os_wake_unlock(dhdp); 603 } 604 605 static void dhd_early_suspend(struct early_suspend *h) 606 { 607 struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); 608 609 DHD_TRACE(("%s: enter\n", __FUNCTION__)); 610 611 if (dhd) 612 dhd_suspend_resume_helper(dhd, 1); 613 } 614 615 static void dhd_late_resume(struct early_suspend *h) 616 { 617 struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); 618 619 DHD_TRACE(("%s: enter\n", __FUNCTION__)); 620 621 if (dhd) 622 dhd_suspend_resume_helper(dhd, 0); 623 } 624 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ 625 626 /* 627 * Generalized timeout mechanism. Uses spin sleep with exponential back-off until 628 * the sleep time reaches one jiffy, then switches over to task delay. Usage: 629 * 630 * dhd_timeout_start(&tmo, usec); 631 * while (!dhd_timeout_expired(&tmo)) 632 * if (poll_something()) 633 * break; 634 * if (dhd_timeout_expired(&tmo)) 635 * fatal(); 636 */ 637 638 void 639 dhd_timeout_start(dhd_timeout_t *tmo, uint usec) 640 { 641 tmo->limit = usec; 642 tmo->increment = 0; 643 tmo->elapsed = 0; 644 tmo->tick = 1000000 / HZ; 645 } 646 647 int 648 dhd_timeout_expired(dhd_timeout_t *tmo) 649 { 650 /* Does nothing the first call */ 651 if (tmo->increment == 0) { 652 tmo->increment = 1; 653 return 0; 654 } 655 656 if (tmo->elapsed >= tmo->limit) 657 return 1; 658 659 /* Add the delay that's about to take place */ 660 tmo->elapsed += tmo->increment; 661 662 if (tmo->increment < tmo->tick) { 663 OSL_DELAY(tmo->increment); 664 tmo->increment *= 2; 665 if (tmo->increment > tmo->tick) 666 tmo->increment = tmo->tick; 667 } else { 668 wait_queue_head_t delay_wait; 669 DECLARE_WAITQUEUE(wait, current); 670 int pending; 671 init_waitqueue_head(&delay_wait); 672 add_wait_queue(&delay_wait, &wait); 673 set_current_state(TASK_INTERRUPTIBLE); 674 schedule_timeout(1); 675 pending = signal_pending(current); 676 remove_wait_queue(&delay_wait, &wait); 677 set_current_state(TASK_RUNNING); 678 if (pending) 679 return 1; /* Interrupted */ 680 } 681 682 return 0; 683 } 684 685 static int 686 dhd_net2idx(dhd_info_t *dhd, struct net_device *net) 687 { 688 int i = 0; 689 690 ASSERT(dhd); 691 while (i < DHD_MAX_IFS) { 692 if (dhd->iflist[i] && (dhd->iflist[i]->net == net)) 693 return i; 694 i++; 695 } 696 697 return DHD_BAD_IF; 698 } 699 700 int 701 dhd_ifname2idx(dhd_info_t *dhd, char *name) 702 { 703 int i = DHD_MAX_IFS; 704 705 ASSERT(dhd); 706 707 if (name == NULL || *name == '\0') 708 return 0; 709 710 while (--i > 0) 711 if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) 712 break; 713 714 DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); 715 716 return i; /* default - the primary interface */ 717 } 718 719 char * 720 dhd_ifname(dhd_pub_t *dhdp, int ifidx) 721 { 722 dhd_info_t *dhd = (dhd_info_t *)dhdp->info; 723 724 ASSERT(dhd); 725 726 if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { 727 DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); 728 return "<if_bad>"; 729 } 730 731 if (dhd->iflist[ifidx] == NULL) { 732 DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); 733 return "<if_null>"; 734 } 735 736 if (dhd->iflist[ifidx]->net) 737 return dhd->iflist[ifidx]->net->name; 738 739 return "<if_none>"; 740 } 741 742 static void 743 _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) 744 { 745 struct net_device *dev; 746 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) 747 struct netdev_hw_addr *ha; 748 #else 749 struct dev_mc_list *mclist; 750 #endif 751 uint32 allmulti, cnt; 752 753 wl_ioctl_t ioc; 754 char *buf, *bufp; 755 uint buflen; 756 int ret; 757 758 ASSERT(dhd && dhd->iflist[ifidx]); 759 dev = dhd->iflist[ifidx]->net; 760 761 netif_addr_lock_bh(dev); 762 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) 763 cnt = netdev_mc_count(dev); 764 #else 765 cnt = dev->mc_count; 766 #endif 767 netif_addr_unlock_bh(dev); 768 769 /* Determine initial value of allmulti flag */ 770 allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; 771 772 /* Send down the multicast list first. */ 773 buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); 774 if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { 775 DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", 776 dhd_ifname(&dhd->pub, ifidx), cnt)); 777 return; 778 } 779 780 strcpy(bufp, "mcast_list"); 781 bufp += strlen("mcast_list") + 1; 782 783 cnt = htol32(cnt); 784 memcpy(bufp, &cnt, sizeof(cnt)); 785 bufp += sizeof(cnt); 786 787 netif_addr_lock_bh(dev); 788 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) 789 netdev_for_each_mc_addr(ha, dev) { 790 if (!cnt) 791 break; 792 memcpy(bufp, ha->addr, ETHER_ADDR_LEN); 793 bufp += ETHER_ADDR_LEN; 794 cnt--; 795 } 796 #else 797 for (mclist = dev->mc_list;(mclist && (cnt > 0)); cnt--, mclist = mclist->next) { 798 memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); 799 bufp += ETHER_ADDR_LEN; 800 } 801 #endif 802 netif_addr_unlock_bh(dev); 803 804 memset(&ioc, 0, sizeof(ioc)); 805 ioc.cmd = WLC_SET_VAR; 806 ioc.buf = buf; 807 ioc.len = buflen; 808 ioc.set = TRUE; 809 810 ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); 811 if (ret < 0) { 812 DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", 813 dhd_ifname(&dhd->pub, ifidx), cnt)); 814 allmulti = cnt ? TRUE : allmulti; 815 } 816 817 MFREE(dhd->pub.osh, buf, buflen); 818 819 /* Now send the allmulti setting. This is based on the setting in the 820 * net_device flags, but might be modified above to be turned on if we 821 * were trying to set some addresses and dongle rejected it... 822 */ 823 824 buflen = sizeof("allmulti") + sizeof(allmulti); 825 if (!(buf = MALLOC(dhd->pub.osh, buflen))) { 826 DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx))); 827 return; 828 } 829 allmulti = htol32(allmulti); 830 831 if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) { 832 DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n", 833 dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen)); 834 MFREE(dhd->pub.osh, buf, buflen); 835 return; 836 } 837 838 839 memset(&ioc, 0, sizeof(ioc)); 840 ioc.cmd = WLC_SET_VAR; 841 ioc.buf = buf; 842 ioc.len = buflen; 843 ioc.set = TRUE; 844 845 ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); 846 if (ret < 0) { 847 DHD_ERROR(("%s: set allmulti %d failed\n", 848 dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); 849 } 850 851 MFREE(dhd->pub.osh, buf, buflen); 852 853 /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ 854 855 allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; 856 allmulti = htol32(allmulti); 857 858 memset(&ioc, 0, sizeof(ioc)); 859 ioc.cmd = WLC_SET_PROMISC; 860 ioc.buf = &allmulti; 861 ioc.len = sizeof(allmulti); 862 ioc.set = TRUE; 863 864 ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); 865 if (ret < 0) { 866 DHD_ERROR(("%s: set promisc %d failed\n", 867 dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); 868 } 869 } 870 871 static int 872 _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) 873 { 874 char buf[32]; 875 wl_ioctl_t ioc; 876 int ret; 877 878 DHD_TRACE(("%s enter\n", __FUNCTION__)); 879 if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) { 880 DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx))); 881 return -1; 882 } 883 memset(&ioc, 0, sizeof(ioc)); 884 ioc.cmd = WLC_SET_VAR; 885 ioc.buf = buf; 886 ioc.len = 32; 887 ioc.set = TRUE; 888 889 ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); 890 if (ret < 0) { 891 DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); 892 } else { 893 memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); 894 } 895 896 return ret; 897 } 898 899 #ifdef SOFTAP 900 extern struct net_device *ap_net_dev; 901 #endif 902 903 static void 904 dhd_op_if(dhd_if_t *ifp) 905 { 906 dhd_info_t *dhd; 907 int ret = 0, err = 0; 908 909 ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ 910 911 dhd = ifp->info; 912 913 DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state)); 914 915 switch (ifp->state) { 916 case WLC_E_IF_ADD: 917 /* 918 * Delete the existing interface before overwriting it 919 * in case we missed the WLC_E_IF_DEL event. 920 */ 921 if (ifp->net != NULL) { 922 DHD_ERROR(("%s: ERROR: netdev:%s already exists, try free & unregister \n", 923 __FUNCTION__, ifp->net->name)); 924 netif_stop_queue(ifp->net); 925 unregister_netdev(ifp->net); 926 free_netdev(ifp->net); 927 } 928 /* Allocate etherdev, including space for private structure */ 929 if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) { 930 DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); 931 ret = -ENOMEM; 932 } 933 if (ret == 0) { 934 strcpy(ifp->net->name, ifp->name); 935 memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd)); 936 if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) { 937 DHD_ERROR(("%s: dhd_net_attach failed, err %d\n", 938 __FUNCTION__, err)); 939 ret = -EOPNOTSUPP; 940 } else { 941 #ifdef SOFTAP 942 /* semaphore that the soft AP CODE waits on */ 943 extern struct semaphore ap_eth_sema; 944 945 /* save ptr to wl0.1 netdev for use in wl_iw.c */ 946 ap_net_dev = ifp->net; 947 /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */ 948 up(&ap_eth_sema); 949 #endif 950 DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n", 951 current->pid, ifp->net->name)); 952 ifp->state = 0; 953 } 954 } 955 break; 956 case WLC_E_IF_DEL: 957 if (ifp->net != NULL) { 958 DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", __FUNCTION__)); 959 netif_stop_queue(ifp->net); 960 unregister_netdev(ifp->net); 961 ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ 962 } 963 break; 964 default: 965 DHD_ERROR(("%s: bad op %d\n", __FUNCTION__, ifp->state)); 966 ASSERT(!ifp->state); 967 break; 968 } 969 970 if (ret < 0) { 971 if (ifp->net) { 972 free_netdev(ifp->net); 973 } 974 dhd->iflist[ifp->idx] = NULL; 975 MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); 976 #ifdef SOFTAP 977 if (ifp->net == ap_net_dev) 978 ap_net_dev = NULL; /* NULL SOFTAP global as well */ 979 #endif /* SOFTAP */ 980 } 981 } 982 983 static int 984 _dhd_sysioc_thread(void *data) 985 { 986 dhd_info_t *dhd = (dhd_info_t *)data; 987 int i; 988 #ifdef SOFTAP 989 bool in_ap = FALSE; 990 #endif 991 992 DAEMONIZE("dhd_sysioc"); 993 994 while (down_interruptible(&dhd->sysioc_sem) == 0) { 995 dhd_os_wake_lock(&dhd->pub); 996 for (i = 0; i < DHD_MAX_IFS; i++) { 997 if (dhd->iflist[i]) { 998 #ifdef SOFTAP 999 in_ap = (ap_net_dev != NULL); 1000 #endif /* SOFTAP */ 1001 if (dhd->iflist[i]->state) 1002 dhd_op_if(dhd->iflist[i]); 1003 #ifdef SOFTAP 1004 if (dhd->iflist[i] == NULL) { 1005 DHD_TRACE(("%s: interface %d just been removed!\n\n", __FUNCTION__, i)); 1006 continue; 1007 } 1008 1009 if (in_ap && dhd->set_macaddress) { 1010 DHD_TRACE(("attempt to set MAC for %s in AP Mode blocked.\n", dhd->iflist[i]->net->name)); 1011 dhd->set_macaddress = FALSE; 1012 continue; 1013 } 1014 1015 if (in_ap && dhd->set_multicast) { 1016 DHD_TRACE(("attempt to set MULTICAST list for %s in AP Mode blocked.\n", dhd->iflist[i]->net->name)); 1017 dhd->set_multicast = FALSE; 1018 continue; 1019 } 1020 #endif /* SOFTAP */ 1021 if (dhd->set_multicast) { 1022 dhd->set_multicast = FALSE; 1023 _dhd_set_multicast_list(dhd, i); 1024 } 1025 if (dhd->set_macaddress) { 1026 dhd->set_macaddress = FALSE; 1027 _dhd_set_mac_address(dhd, i, &dhd->macvalue); 1028 } 1029 } 1030 } 1031 dhd_os_wake_unlock(&dhd->pub); 1032 } 1033 complete_and_exit(&dhd->sysioc_exited, 0); 1034 } 1035 1036 static int 1037 dhd_set_mac_address(struct net_device *dev, void *addr) 1038 { 1039 int ret = 0; 1040 1041 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 1042 struct sockaddr *sa = (struct sockaddr *)addr; 1043 int ifidx; 1044 1045 ifidx = dhd_net2idx(dhd, dev); 1046 if (ifidx == DHD_BAD_IF) 1047 return -1; 1048 1049 ASSERT(dhd->sysioc_pid >= 0); 1050 memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); 1051 dhd->set_macaddress = TRUE; 1052 up(&dhd->sysioc_sem); 1053 1054 return ret; 1055 } 1056 1057 static void 1058 dhd_set_multicast_list(struct net_device *dev) 1059 { 1060 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 1061 int ifidx; 1062 1063 ifidx = dhd_net2idx(dhd, dev); 1064 if (ifidx == DHD_BAD_IF) 1065 return; 1066 1067 ASSERT(dhd->sysioc_pid >= 0); 1068 dhd->set_multicast = TRUE; 1069 up(&dhd->sysioc_sem); 1070 } 1071 1072 int 1073 dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) 1074 { 1075 int ret; 1076 dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); 1077 1078 /* Reject if down */ 1079 if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { 1080 return -ENODEV; 1081 } 1082 1083 /* Update multicast statistic */ 1084 if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) { 1085 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); 1086 struct ether_header *eh = (struct ether_header *)pktdata; 1087 1088 if (ETHER_ISMULTI(eh->ether_dhost)) 1089 dhdp->tx_multicast++; 1090 if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) 1091 atomic_inc(&dhd->pend_8021x_cnt); 1092 } 1093 1094 /* Look into the packet and update the packet priority */ 1095 if ((PKTPRIO(pktbuf) == 0)) 1096 pktsetprio(pktbuf, FALSE); 1097 1098 /* If the protocol uses a data header, apply it */ 1099 dhd_prot_hdrpush(dhdp, ifidx, pktbuf); 1100 1101 /* Use bus module to send data frame */ 1102 #ifdef BCMDBUS 1103 ret = dbus_send_pkt(dhdp->dbus, pktbuf, NULL /* pktinfo */); 1104 #else 1105 ret = dhd_bus_txdata(dhdp->bus, pktbuf); 1106 #endif /* BCMDBUS */ 1107 1108 return ret; 1109 } 1110 1111 static int 1112 dhd_start_xmit(struct sk_buff *skb, struct net_device *net) 1113 { 1114 int ret; 1115 void *pktbuf; 1116 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); 1117 int ifidx; 1118 1119 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1120 1121 dhd_os_wake_lock(&dhd->pub); 1122 1123 /* Reject if down */ 1124 if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) { 1125 DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d\n", 1126 __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); 1127 netif_stop_queue(net); 1128 /* Send Event when bus down detected during data session */ 1129 if (dhd->pub.busstate == DHD_BUS_DOWN) { 1130 DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__)); 1131 net_os_send_hang_message(net); 1132 } 1133 dhd_os_wake_unlock(&dhd->pub); 1134 return -ENODEV; 1135 } 1136 1137 ifidx = dhd_net2idx(dhd, net); 1138 if (ifidx == DHD_BAD_IF) { 1139 DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); 1140 netif_stop_queue(net); 1141 dhd_os_wake_unlock(&dhd->pub); 1142 return -ENODEV; 1143 } 1144 1145 /* Make sure there's enough room for any header */ 1146 if (skb_headroom(skb) < dhd->pub.hdrlen) { 1147 struct sk_buff *skb2; 1148 1149 DHD_INFO(("%s: insufficient headroom\n", 1150 dhd_ifname(&dhd->pub, ifidx))); 1151 dhd->pub.tx_realloc++; 1152 skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen); 1153 dev_kfree_skb(skb); 1154 if ((skb = skb2) == NULL) { 1155 DHD_ERROR(("%s: skb_realloc_headroom failed\n", 1156 dhd_ifname(&dhd->pub, ifidx))); 1157 ret = -ENOMEM; 1158 goto done; 1159 } 1160 } 1161 1162 /* Convert to packet */ 1163 if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { 1164 DHD_ERROR(("%s: PKTFRMNATIVE failed\n", 1165 dhd_ifname(&dhd->pub, ifidx))); 1166 dev_kfree_skb_any(skb); 1167 ret = -ENOMEM; 1168 goto done; 1169 } 1170 1171 ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); 1172 1173 done: 1174 if (ret) 1175 dhd->pub.dstats.tx_dropped++; 1176 else 1177 dhd->pub.tx_packets++; 1178 1179 dhd_os_wake_unlock(&dhd->pub); 1180 1181 /* Return ok: we always eat the packet */ 1182 return 0; 1183 } 1184 1185 void 1186 dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) 1187 { 1188 struct net_device *net; 1189 dhd_info_t *dhd = dhdp->info; 1190 1191 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1192 1193 dhdp->txoff = state; 1194 ASSERT(dhd && dhd->iflist[ifidx]); 1195 net = dhd->iflist[ifidx]->net; 1196 if (state == ON) 1197 netif_stop_queue(net); 1198 else 1199 netif_wake_queue(net); 1200 } 1201 1202 void 1203 dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) 1204 { 1205 dhd_info_t *dhd = (dhd_info_t *)dhdp->info; 1206 struct sk_buff *skb; 1207 uchar *eth; 1208 uint len; 1209 void * data, *pnext, *save_pktbuf; 1210 int i; 1211 dhd_if_t *ifp; 1212 wl_event_msg_t event; 1213 1214 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1215 1216 save_pktbuf = pktbuf; 1217 1218 for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { 1219 1220 pnext = PKTNEXT(dhdp->osh, pktbuf); 1221 PKTSETNEXT(wl->sh.osh, pktbuf, NULL); 1222 1223 1224 skb = PKTTONATIVE(dhdp->osh, pktbuf); 1225 1226 /* Get the protocol, maintain skb around eth_type_trans() 1227 * The main reason for this hack is for the limitation of 1228 * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' 1229 * to perform skb_pull inside vs ETH_HLEN. Since to avoid 1230 * coping of the packet coming from the network stack to add 1231 * BDC, Hardware header etc, during network interface registration 1232 * we set the 'net->hard_header_len' to ETH_HLEN + extra space required 1233 * for BDC, Hardware header etc. and not just the ETH_HLEN 1234 */ 1235 eth = skb->data; 1236 len = skb->len; 1237 1238 ifp = dhd->iflist[ifidx]; 1239 if (ifp == NULL) 1240 ifp = dhd->iflist[0]; 1241 1242 ASSERT(ifp); 1243 skb->dev = ifp->net; 1244 skb->protocol = eth_type_trans(skb, skb->dev); 1245 1246 if (skb->pkt_type == PACKET_MULTICAST) { 1247 dhd->pub.rx_multicast++; 1248 } 1249 1250 skb->data = eth; 1251 skb->len = len; 1252 1253 /* Strip header, count, deliver upward */ 1254 skb_pull(skb, ETH_HLEN); 1255 1256 /* Process special event packets and then discard them */ 1257 if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) 1258 dhd_wl_host_event(dhd, &ifidx, 1259 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) 1260 skb->mac_header, 1261 #else 1262 skb->mac.raw, 1263 #endif 1264 &event, 1265 &data); 1266 1267 ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); 1268 if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state) 1269 ifp = dhd->iflist[ifidx]; 1270 1271 if (ifp->net) 1272 ifp->net->last_rx = jiffies; 1273 1274 dhdp->dstats.rx_bytes += skb->len; 1275 dhdp->rx_packets++; /* Local count */ 1276 1277 if (in_interrupt()) { 1278 netif_rx(skb); 1279 } else { 1280 /* If the receive is not processed inside an ISR, 1281 * the softirqd must be woken explicitly to service 1282 * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled 1283 * by netif_rx_ni(), but in earlier kernels, we need 1284 * to do it manually. 1285 */ 1286 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) 1287 netif_rx_ni(skb); 1288 #else 1289 ulong flags; 1290 netif_rx(skb); 1291 local_irq_save(flags); 1292 RAISE_RX_SOFTIRQ(); 1293 local_irq_restore(flags); 1294 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ 1295 } 1296 } 1297 dhd_os_wake_lock_timeout_enable(dhdp); 1298 } 1299 1300 void 1301 dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) 1302 { 1303 /* Linux version has nothing to do */ 1304 return; 1305 } 1306 1307 void 1308 dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) 1309 { 1310 uint ifidx; 1311 dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); 1312 struct ether_header *eh; 1313 uint16 type; 1314 1315 dhd_prot_hdrpull(dhdp, &ifidx, txp); 1316 1317 eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); 1318 type = ntoh16(eh->ether_type); 1319 1320 if (type == ETHER_TYPE_802_1X) 1321 atomic_dec(&dhd->pend_8021x_cnt); 1322 1323 } 1324 1325 static struct net_device_stats * 1326 dhd_get_stats(struct net_device *net) 1327 { 1328 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); 1329 dhd_if_t *ifp; 1330 int ifidx; 1331 1332 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1333 1334 ifidx = dhd_net2idx(dhd, net); 1335 if (ifidx == DHD_BAD_IF) 1336 return NULL; 1337 1338 ifp = dhd->iflist[ifidx]; 1339 ASSERT(dhd && ifp); 1340 1341 if (dhd->pub.up) { 1342 /* Use the protocol to get dongle stats */ 1343 dhd_prot_dstats(&dhd->pub); 1344 } 1345 1346 /* Copy dongle stats to net device stats */ 1347 ifp->stats.rx_packets = dhd->pub.dstats.rx_packets; 1348 ifp->stats.tx_packets = dhd->pub.dstats.tx_packets; 1349 ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes; 1350 ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes; 1351 ifp->stats.rx_errors = dhd->pub.dstats.rx_errors; 1352 ifp->stats.tx_errors = dhd->pub.dstats.tx_errors; 1353 ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped; 1354 ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped; 1355 ifp->stats.multicast = dhd->pub.dstats.multicast; 1356 1357 return &ifp->stats; 1358 } 1359 1360 static int 1361 dhd_watchdog_thread(void *data) 1362 { 1363 dhd_info_t *dhd = (dhd_info_t *)data; 1364 1365 /* This thread doesn't need any user-level access, 1366 * so get rid of all our resources 1367 */ 1368 #ifdef DHD_SCHED 1369 if (dhd_watchdog_prio > 0) { 1370 struct sched_param param; 1371 param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? 1372 dhd_watchdog_prio:(MAX_RT_PRIO-1); 1373 setScheduler(current, SCHED_FIFO, ¶m); 1374 } 1375 #endif /* DHD_SCHED */ 1376 1377 DAEMONIZE("dhd_watchdog"); 1378 1379 /* Run until signal received */ 1380 while (1) { 1381 if (down_interruptible (&dhd->watchdog_sem) == 0) { 1382 1383 if (dhd->pub.dongle_reset == FALSE) { 1384 /* Call the bus module watchdog */ 1385 dhd_bus_watchdog(&dhd->pub); 1386 } 1387 /* Count the tick for reference */ 1388 dhd->pub.tickcnt++; 1389 1390 /* Reschedule the watchdog */ 1391 if (dhd->wd_timer_valid) 1392 mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); 1393 1394 dhd_os_wake_unlock(&dhd->pub); 1395 } 1396 else 1397 break; 1398 } 1399 1400 complete_and_exit(&dhd->watchdog_exited, 0); 1401 } 1402 1403 static void 1404 dhd_watchdog(ulong data) 1405 { 1406 dhd_info_t *dhd = (dhd_info_t *)data; 1407 1408 dhd_os_wake_lock(&dhd->pub); 1409 if (dhd->watchdog_pid >= 0) { 1410 up(&dhd->watchdog_sem); 1411 return; 1412 } 1413 1414 /* Call the bus module watchdog */ 1415 dhd_bus_watchdog(&dhd->pub); 1416 1417 /* Count the tick for reference */ 1418 dhd->pub.tickcnt++; 1419 1420 /* Reschedule the watchdog */ 1421 if (dhd->wd_timer_valid) 1422 mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); 1423 dhd_os_wake_unlock(&dhd->pub); 1424 } 1425 1426 static int 1427 dhd_dpc_thread(void *data) 1428 { 1429 dhd_info_t *dhd = (dhd_info_t *)data; 1430 1431 /* This thread doesn't need any user-level access, 1432 * so get rid of all our resources 1433 */ 1434 #ifdef DHD_SCHED 1435 if (dhd_dpc_prio > 0) 1436 { 1437 struct sched_param param; 1438 param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); 1439 setScheduler(current, SCHED_FIFO, ¶m); 1440 } 1441 #endif /* DHD_SCHED */ 1442 1443 DAEMONIZE("dhd_dpc"); 1444 1445 /* Run until signal received */ 1446 while (1) { 1447 if (down_interruptible(&dhd->dpc_sem) == 0) { 1448 /* Call bus dpc unless it indicated down (then clean stop) */ 1449 if (dhd->pub.busstate != DHD_BUS_DOWN) { 1450 if (dhd_bus_dpc(dhd->pub.bus)) { 1451 up(&dhd->dpc_sem); 1452 } 1453 else { 1454 dhd_os_wake_unlock(&dhd->pub); 1455 } 1456 } else { 1457 dhd_bus_stop(dhd->pub.bus, TRUE); 1458 dhd_os_wake_unlock(&dhd->pub); 1459 } 1460 } 1461 else 1462 break; 1463 } 1464 1465 complete_and_exit(&dhd->dpc_exited, 0); 1466 } 1467 1468 static void 1469 dhd_dpc(ulong data) 1470 { 1471 dhd_info_t *dhd; 1472 1473 dhd = (dhd_info_t *)data; 1474 1475 /* Call bus dpc unless it indicated down (then clean stop) */ 1476 if (dhd->pub.busstate != DHD_BUS_DOWN) { 1477 if (dhd_bus_dpc(dhd->pub.bus)) 1478 tasklet_schedule(&dhd->tasklet); 1479 } else { 1480 dhd_bus_stop(dhd->pub.bus, TRUE); 1481 } 1482 } 1483 1484 void 1485 dhd_sched_dpc(dhd_pub_t *dhdp) 1486 { 1487 dhd_info_t *dhd = (dhd_info_t *)dhdp->info; 1488 1489 dhd_os_wake_lock(dhdp); 1490 if (dhd->dpc_pid >= 0) { 1491 up(&dhd->dpc_sem); 1492 return; 1493 } 1494 1495 tasklet_schedule(&dhd->tasklet); 1496 } 1497 1498 #ifdef TOE 1499 /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ 1500 static int 1501 dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) 1502 { 1503 wl_ioctl_t ioc; 1504 char buf[32]; 1505 int ret; 1506 1507 memset(&ioc, 0, sizeof(ioc)); 1508 1509 ioc.cmd = WLC_GET_VAR; 1510 ioc.buf = buf; 1511 ioc.len = (uint)sizeof(buf); 1512 ioc.set = FALSE; 1513 1514 strcpy(buf, "toe_ol"); 1515 if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { 1516 /* Check for older dongle image that doesn't support toe_ol */ 1517 if (ret == -EIO) { 1518 DHD_ERROR(("%s: toe not supported by device\n", 1519 dhd_ifname(&dhd->pub, ifidx))); 1520 return -EOPNOTSUPP; 1521 } 1522 1523 DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); 1524 return ret; 1525 } 1526 1527 memcpy(toe_ol, buf, sizeof(uint32)); 1528 return 0; 1529 } 1530 1531 /* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ 1532 static int 1533 dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) 1534 { 1535 wl_ioctl_t ioc; 1536 char buf[32]; 1537 int toe, ret; 1538 1539 memset(&ioc, 0, sizeof(ioc)); 1540 1541 ioc.cmd = WLC_SET_VAR; 1542 ioc.buf = buf; 1543 ioc.len = (uint)sizeof(buf); 1544 ioc.set = TRUE; 1545 1546 /* Set toe_ol as requested */ 1547 1548 strcpy(buf, "toe_ol"); 1549 memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); 1550 1551 if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { 1552 DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", 1553 dhd_ifname(&dhd->pub, ifidx), ret)); 1554 return ret; 1555 } 1556 1557 /* Enable toe globally only if any components are enabled. */ 1558 1559 toe = (toe_ol != 0); 1560 1561 strcpy(buf, "toe"); 1562 memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32)); 1563 1564 if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { 1565 DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); 1566 return ret; 1567 } 1568 1569 return 0; 1570 } 1571 #endif /* TOE */ 1572 1573 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) 1574 static void dhd_ethtool_get_drvinfo(struct net_device *net, 1575 struct ethtool_drvinfo *info) 1576 { 1577 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); 1578 1579 sprintf(info->driver, "wl"); 1580 sprintf(info->version, "%lu", dhd->pub.drv_version); 1581 } 1582 1583 struct ethtool_ops dhd_ethtool_ops = { 1584 .get_drvinfo = dhd_ethtool_get_drvinfo 1585 }; 1586 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ 1587 1588 1589 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) 1590 static int 1591 dhd_ethtool(dhd_info_t *dhd, void *uaddr) 1592 { 1593 struct ethtool_drvinfo info; 1594 char drvname[sizeof(info.driver)]; 1595 uint32 cmd; 1596 #ifdef TOE 1597 struct ethtool_value edata; 1598 uint32 toe_cmpnt, csum_dir; 1599 int ret; 1600 #endif 1601 1602 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1603 1604 /* all ethtool calls start with a cmd word */ 1605 if (copy_from_user(&cmd, uaddr, sizeof (uint32))) 1606 return -EFAULT; 1607 1608 switch (cmd) { 1609 case ETHTOOL_GDRVINFO: 1610 /* Copy out any request driver name */ 1611 if (copy_from_user(&info, uaddr, sizeof(info))) 1612 return -EFAULT; 1613 strncpy(drvname, info.driver, sizeof(info.driver)); 1614 drvname[sizeof(info.driver)-1] = '\0'; 1615 1616 /* clear struct for return */ 1617 memset(&info, 0, sizeof(info)); 1618 info.cmd = cmd; 1619 1620 /* if dhd requested, identify ourselves */ 1621 if (strcmp(drvname, "?dhd") == 0) { 1622 sprintf(info.driver, "dhd"); 1623 strcpy(info.version, EPI_VERSION_STR); 1624 } 1625 1626 /* otherwise, require dongle to be up */ 1627 else if (!dhd->pub.up) { 1628 DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); 1629 return -ENODEV; 1630 } 1631 1632 /* finally, report dongle driver type */ 1633 else if (dhd->pub.iswl) 1634 sprintf(info.driver, "wl"); 1635 else 1636 sprintf(info.driver, "xx"); 1637 1638 sprintf(info.version, "%lu", dhd->pub.drv_version); 1639 if (copy_to_user(uaddr, &info, sizeof(info))) 1640 return -EFAULT; 1641 DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, 1642 (int)sizeof(drvname), drvname, info.driver)); 1643 break; 1644 1645 #ifdef TOE 1646 /* Get toe offload components from dongle */ 1647 case ETHTOOL_GRXCSUM: 1648 case ETHTOOL_GTXCSUM: 1649 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) 1650 return ret; 1651 1652 csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; 1653 1654 edata.cmd = cmd; 1655 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; 1656 1657 if (copy_to_user(uaddr, &edata, sizeof(edata))) 1658 return -EFAULT; 1659 break; 1660 1661 /* Set toe offload components in dongle */ 1662 case ETHTOOL_SRXCSUM: 1663 case ETHTOOL_STXCSUM: 1664 if (copy_from_user(&edata, uaddr, sizeof(edata))) 1665 return -EFAULT; 1666 1667 /* Read the current settings, update and write back */ 1668 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) 1669 return ret; 1670 1671 csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; 1672 1673 if (edata.data != 0) 1674 toe_cmpnt |= csum_dir; 1675 else 1676 toe_cmpnt &= ~csum_dir; 1677 1678 if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) 1679 return ret; 1680 1681 /* If setting TX checksum mode, tell Linux the new mode */ 1682 if (cmd == ETHTOOL_STXCSUM) { 1683 if (edata.data) 1684 dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; 1685 else 1686 dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; 1687 } 1688 1689 break; 1690 #endif /* TOE */ 1691 1692 default: 1693 return -EOPNOTSUPP; 1694 } 1695 1696 return 0; 1697 } 1698 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ 1699 1700 static int 1701 dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) 1702 { 1703 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); 1704 dhd_ioctl_t ioc; 1705 int bcmerror = 0; 1706 int buflen = 0; 1707 void *buf = NULL; 1708 uint driver = 0; 1709 int ifidx; 1710 bool is_set_key_cmd; 1711 int ret; 1712 1713 dhd_os_wake_lock(&dhd->pub); 1714 1715 ifidx = dhd_net2idx(dhd, net); 1716 DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); 1717 1718 if (ifidx == DHD_BAD_IF) { 1719 dhd_os_wake_unlock(&dhd->pub); 1720 return -1; 1721 } 1722 1723 #if defined(CONFIG_WIRELESS_EXT) 1724 /* linux wireless extensions */ 1725 if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { 1726 /* may recurse, do NOT lock */ 1727 ret = wl_iw_ioctl(net, ifr, cmd); 1728 dhd_os_wake_unlock(&dhd->pub); 1729 return ret; 1730 } 1731 #endif /* defined(CONFIG_WIRELESS_EXT) */ 1732 1733 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) 1734 if (cmd == SIOCETHTOOL) { 1735 ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); 1736 dhd_os_wake_unlock(&dhd->pub); 1737 return ret; 1738 } 1739 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ 1740 1741 if (cmd != SIOCDEVPRIVATE) { 1742 dhd_os_wake_unlock(&dhd->pub); 1743 return -EOPNOTSUPP; 1744 } 1745 1746 memset(&ioc, 0, sizeof(ioc)); 1747 1748 /* Copy the ioc control structure part of ioctl request */ 1749 if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { 1750 bcmerror = -BCME_BADADDR; 1751 goto done; 1752 } 1753 1754 /* Copy out any buffer passed */ 1755 if (ioc.buf) { 1756 buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); 1757 /* optimization for direct ioctl calls from kernel */ 1758 /* 1759 if (segment_eq(get_fs(), KERNEL_DS)) { 1760 buf = ioc.buf; 1761 } else { 1762 */ 1763 { 1764 if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) { 1765 bcmerror = -BCME_NOMEM; 1766 goto done; 1767 } 1768 if (copy_from_user(buf, ioc.buf, buflen)) { 1769 bcmerror = -BCME_BADADDR; 1770 goto done; 1771 } 1772 } 1773 } 1774 1775 /* To differentiate between wl and dhd read 4 more byes */ 1776 if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), 1777 sizeof(uint)) != 0)) { 1778 bcmerror = -BCME_BADADDR; 1779 goto done; 1780 } 1781 1782 if (!capable(CAP_NET_ADMIN)) { 1783 bcmerror = -BCME_EPERM; 1784 goto done; 1785 } 1786 1787 /* check for local dhd ioctl and handle it */ 1788 if (driver == DHD_IOCTL_MAGIC) { 1789 bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen); 1790 if (bcmerror) 1791 dhd->pub.bcmerror = bcmerror; 1792 goto done; 1793 } 1794 1795 /* send to dongle (must be up, and wl) */ 1796 if (dhd->pub.busstate != DHD_BUS_DATA) { 1797 DHD_ERROR(("%s DONGLE_DOWN\n", __FUNCTION__)); 1798 bcmerror = BCME_DONGLE_DOWN; 1799 goto done; 1800 } 1801 1802 if (!dhd->pub.iswl) { 1803 bcmerror = BCME_DONGLE_DOWN; 1804 goto done; 1805 } 1806 1807 /* Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to 1808 * prevent M4 encryption. 1809 */ 1810 is_set_key_cmd = ((ioc.cmd == WLC_SET_KEY) || 1811 ((ioc.cmd == WLC_SET_VAR) && 1812 !(strncmp("wsec_key", ioc.buf, 9))) || 1813 ((ioc.cmd == WLC_SET_VAR) && 1814 !(strncmp("bsscfg:wsec_key", ioc.buf, 15)))); 1815 if (is_set_key_cmd) { 1816 dhd_wait_pend8021x(net); 1817 } 1818 1819 bcmerror = dhd_prot_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); 1820 1821 done: 1822 if ((bcmerror == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) && 1823 (!dhd->pub.dongle_reset))) { 1824 DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__)); 1825 net_os_send_hang_message(net); 1826 } 1827 1828 if (!bcmerror && buf && ioc.buf) { 1829 if (copy_to_user(ioc.buf, buf, buflen)) 1830 bcmerror = -EFAULT; 1831 } 1832 1833 if (buf) 1834 MFREE(dhd->pub.osh, buf, buflen); 1835 1836 dhd_os_wake_unlock(&dhd->pub); 1837 1838 return OSL_ERROR(bcmerror); 1839 } 1840 1841 static int 1842 dhd_stop(struct net_device *net) 1843 { 1844 #if !defined(IGNORE_ETH0_DOWN) 1845 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); 1846 1847 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1848 if (dhd->pub.up == 0) { 1849 return 0; 1850 } 1851 1852 /* Set state and stop OS transmissions */ 1853 dhd->pub.up = 0; 1854 netif_stop_queue(net); 1855 #else 1856 DHD_ERROR(("BYPASS %s:due to BRCM compilation : under investigation ...\n", __FUNCTION__)); 1857 #endif /* !defined(IGNORE_ETH0_DOWN) */ 1858 1859 OLD_MOD_DEC_USE_COUNT; 1860 return 0; 1861 } 1862 1863 static int 1864 dhd_open(struct net_device *net) 1865 { 1866 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); 1867 #ifdef TOE 1868 uint32 toe_ol; 1869 #endif 1870 int ifidx; 1871 1872 wl_control_wl_start(net); /* start if needed */ 1873 1874 ifidx = dhd_net2idx(dhd, net); 1875 DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); 1876 1877 if ((dhd->iflist[ifidx]) && (dhd->iflist[ifidx]->state == WLC_E_IF_DEL)) { 1878 DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); 1879 return -1; 1880 } 1881 1882 1883 if (ifidx == 0) { /* do it only for primary eth0 */ 1884 1885 atomic_set(&dhd->pend_8021x_cnt, 0); 1886 1887 memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); 1888 1889 #ifdef TOE 1890 /* Get current TOE mode from dongle */ 1891 if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) 1892 dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; 1893 else 1894 dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; 1895 #endif 1896 } 1897 /* Allow transmit calls */ 1898 netif_start_queue(net); 1899 dhd->pub.up = 1; 1900 1901 OLD_MOD_INC_USE_COUNT; 1902 return 0; 1903 } 1904 1905 osl_t * 1906 dhd_osl_attach(void *pdev, uint bustype) 1907 { 1908 return osl_attach(pdev, bustype, TRUE); 1909 } 1910 1911 void 1912 dhd_osl_detach(osl_t *osh) 1913 { 1914 if (MALLOCED(osh)) { 1915 DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); 1916 } 1917 osl_detach(osh); 1918 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 1919 up(&dhd_registration_sem); 1920 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ 1921 } 1922 1923 int 1924 dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, 1925 uint8 *mac_addr, uint32 flags, uint8 bssidx) 1926 { 1927 dhd_if_t *ifp; 1928 1929 DHD_TRACE(("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle)); 1930 1931 ASSERT(dhd && (ifidx < DHD_MAX_IFS)); 1932 1933 ifp = dhd->iflist[ifidx]; 1934 if (!ifp && !(ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t)))) { 1935 DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__)); 1936 return -ENOMEM; 1937 } 1938 1939 memset(ifp, 0, sizeof(dhd_if_t)); 1940 ifp->info = dhd; 1941 dhd->iflist[ifidx] = ifp; 1942 strncpy(ifp->name, name, IFNAMSIZ); 1943 ifp->name[IFNAMSIZ] = '\0'; 1944 if (mac_addr != NULL) 1945 memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN); 1946 1947 if (handle == NULL) { 1948 ifp->state = WLC_E_IF_ADD; 1949 ifp->idx = ifidx; 1950 ASSERT(dhd->sysioc_pid >= 0); 1951 up(&dhd->sysioc_sem); 1952 } else 1953 ifp->net = (struct net_device *)handle; 1954 1955 return 0; 1956 } 1957 1958 void 1959 dhd_del_if(dhd_info_t *dhd, int ifidx) 1960 { 1961 dhd_if_t *ifp; 1962 1963 DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx)); 1964 1965 ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS)); 1966 ifp = dhd->iflist[ifidx]; 1967 if (!ifp) { 1968 DHD_ERROR(("%s: Null interface\n", __FUNCTION__)); 1969 return; 1970 } 1971 1972 ifp->state = WLC_E_IF_DEL; 1973 ifp->idx = ifidx; 1974 ASSERT(dhd->sysioc_pid >= 0); 1975 up(&dhd->sysioc_sem); 1976 } 1977 1978 dhd_pub_t * 1979 dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) 1980 { 1981 dhd_info_t *dhd = NULL; 1982 struct net_device *net; 1983 1984 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1985 /* updates firmware nvram path if it was provided as module paramters */ 1986 if ((firmware_path != NULL) && (firmware_path[0] != '\0')) 1987 strcpy(fw_path, firmware_path); 1988 if ((nvram_path != NULL) && (nvram_path[0] != '\0')) 1989 strcpy(nv_path, nvram_path); 1990 1991 /* Allocate etherdev, including space for private structure */ 1992 if (!(net = alloc_etherdev(sizeof(dhd)))) { 1993 DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); 1994 goto fail; 1995 } 1996 1997 /* Allocate primary dhd_info */ 1998 if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { 1999 DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); 2000 goto fail; 2001 } 2002 2003 memset(dhd, 0, sizeof(dhd_info_t)); 2004 2005 /* 2006 * Save the dhd_info into the priv 2007 */ 2008 memcpy(netdev_priv(net), &dhd, sizeof(dhd)); 2009 dhd->pub.osh = osh; 2010 2011 /* Set network interface name if it was provided as module parameter */ 2012 if (iface_name[0]) { 2013 int len; 2014 char ch; 2015 strncpy(net->name, iface_name, IFNAMSIZ); 2016 net->name[IFNAMSIZ - 1] = 0; 2017 len = strlen(net->name); 2018 ch = net->name[len - 1]; 2019 if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) 2020 strcat(net->name, "%d"); 2021 } 2022 2023 if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) 2024 goto fail; 2025 2026 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) 2027 net->open = NULL; 2028 #else 2029 net->netdev_ops = NULL; 2030 #endif 2031 2032 init_MUTEX(&dhd->proto_sem); 2033 /* Initialize other structure content */ 2034 init_waitqueue_head(&dhd->ioctl_resp_wait); 2035 init_waitqueue_head(&dhd->ctrl_wait); 2036 2037 /* Initialize the spinlocks */ 2038 spin_lock_init(&dhd->sdlock); 2039 spin_lock_init(&dhd->txqlock); 2040 2041 /* Initialize Wakelock stuff */ 2042 spin_lock_init(&dhd->wl_lock); 2043 dhd->wl_count = 0; 2044 dhd->wl_packet = 0; 2045 #ifdef CONFIG_HAS_WAKELOCK 2046 wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); 2047 wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); 2048 #endif 2049 2050 /* Link to info module */ 2051 dhd->pub.info = dhd; 2052 2053 /* Link to bus module */ 2054 dhd->pub.bus = bus; 2055 dhd->pub.hdrlen = bus_hdrlen; 2056 2057 /* Attach and link in the protocol */ 2058 if (dhd_prot_attach(&dhd->pub) != 0) { 2059 DHD_ERROR(("dhd_prot_attach failed\n")); 2060 goto fail; 2061 } 2062 #if defined(CONFIG_WIRELESS_EXT) 2063 /* Attach and link in the iw */ 2064 if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { 2065 DHD_ERROR(("wl_iw_attach failed\n")); 2066 goto fail; 2067 } 2068 #endif /* defined(CONFIG_WIRELESS_EXT) */ 2069 2070 /* Set up the watchdog timer */ 2071 init_timer(&dhd->timer); 2072 dhd->timer.data = (ulong)dhd; 2073 dhd->timer.function = dhd_watchdog; 2074 2075 /* Initialize thread based operation and lock */ 2076 init_MUTEX(&dhd->sdsem); 2077 if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) { 2078 dhd->threads_only = TRUE; 2079 } 2080 else { 2081 dhd->threads_only = FALSE; 2082 } 2083 2084 if (dhd_dpc_prio >= 0) { 2085 /* Initialize watchdog thread */ 2086 sema_init(&dhd->watchdog_sem, 0); 2087 init_completion(&dhd->watchdog_exited); 2088 dhd->watchdog_pid = kernel_thread(dhd_watchdog_thread, dhd, 0); 2089 } else { 2090 dhd->watchdog_pid = -1; 2091 } 2092 2093 /* Set up the bottom half handler */ 2094 if (dhd_dpc_prio >= 0) { 2095 /* Initialize DPC thread */ 2096 sema_init(&dhd->dpc_sem, 0); 2097 init_completion(&dhd->dpc_exited); 2098 dhd->dpc_pid = kernel_thread(dhd_dpc_thread, dhd, 0); 2099 } else { 2100 tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); 2101 dhd->dpc_pid = -1; 2102 } 2103 2104 if (dhd_sysioc) { 2105 sema_init(&dhd->sysioc_sem, 0); 2106 init_completion(&dhd->sysioc_exited); 2107 dhd->sysioc_pid = kernel_thread(_dhd_sysioc_thread, dhd, 0); 2108 } else { 2109 dhd->sysioc_pid = -1; 2110 } 2111 2112 /* 2113 * Save the dhd_info into the priv 2114 */ 2115 memcpy(netdev_priv(net), &dhd, sizeof(dhd)); 2116 2117 #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) 2118 g_bus = bus; 2119 #endif 2120 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) 2121 register_pm_notifier(&dhd_sleep_pm_notifier); 2122 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ 2123 2124 #ifdef CONFIG_HAS_EARLYSUSPEND 2125 dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; 2126 dhd->early_suspend.suspend = dhd_early_suspend; 2127 dhd->early_suspend.resume = dhd_late_resume; 2128 register_early_suspend(&dhd->early_suspend); 2129 #endif 2130 2131 return &dhd->pub; 2132 2133 fail: 2134 if (net) 2135 free_netdev(net); 2136 if (dhd) 2137 dhd_detach(&dhd->pub); 2138 2139 return NULL; 2140 } 2141 2142 2143 int 2144 dhd_bus_start(dhd_pub_t *dhdp) 2145 { 2146 int ret = -1; 2147 dhd_info_t *dhd = (dhd_info_t*)dhdp->info; 2148 #ifdef EMBEDDED_PLATFORM 2149 char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ 2150 #endif /* EMBEDDED_PLATFORM */ 2151 2152 ASSERT(dhd); 2153 2154 DHD_TRACE(("%s: \n", __FUNCTION__)); 2155 2156 /* try to download image and nvram to the dongle */ 2157 if (dhd->pub.busstate == DHD_BUS_DOWN) { 2158 if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, 2159 fw_path, nv_path))) { 2160 DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", 2161 __FUNCTION__, fw_path, nv_path)); 2162 return -1; 2163 } 2164 } 2165 2166 /* Start the watchdog timer */ 2167 dhd->pub.tickcnt = 0; 2168 dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); 2169 2170 /* Bring up the bus */ 2171 if ((ret = dhd_bus_init(&dhd->pub, TRUE)) != 0) { 2172 DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); 2173 return ret; 2174 } 2175 #if defined(OOB_INTR_ONLY) 2176 /* Host registration for OOB interrupt */ 2177 if (bcmsdh_register_oob_intr(dhdp)) { 2178 del_timer_sync(&dhd->timer); 2179 dhd->wd_timer_valid = FALSE; 2180 DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__)); 2181 return -ENODEV; 2182 } 2183 2184 /* Enable oob at firmware */ 2185 dhd_enable_oob_intr(dhd->pub.bus, TRUE); 2186 #endif /* defined(OOB_INTR_ONLY) */ 2187 2188 /* If bus is not ready, can't come up */ 2189 if (dhd->pub.busstate != DHD_BUS_DATA) { 2190 del_timer_sync(&dhd->timer); 2191 dhd->wd_timer_valid = FALSE; 2192 DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); 2193 return -ENODEV; 2194 } 2195 2196 #ifdef EMBEDDED_PLATFORM 2197 bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); 2198 dhdcdc_query_ioctl(dhdp, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf)); 2199 bcopy(iovbuf, dhdp->eventmask, WL_EVENTING_MASK_LEN); 2200 2201 setbit(dhdp->eventmask, WLC_E_SET_SSID); 2202 setbit(dhdp->eventmask, WLC_E_PRUNE); 2203 setbit(dhdp->eventmask, WLC_E_AUTH); 2204 setbit(dhdp->eventmask, WLC_E_REASSOC); 2205 setbit(dhdp->eventmask, WLC_E_REASSOC_IND); 2206 setbit(dhdp->eventmask, WLC_E_DEAUTH_IND); 2207 setbit(dhdp->eventmask, WLC_E_DISASSOC_IND); 2208 setbit(dhdp->eventmask, WLC_E_DISASSOC); 2209 setbit(dhdp->eventmask, WLC_E_JOIN); 2210 setbit(dhdp->eventmask, WLC_E_ASSOC_IND); 2211 setbit(dhdp->eventmask, WLC_E_PSK_SUP); 2212 setbit(dhdp->eventmask, WLC_E_LINK); 2213 setbit(dhdp->eventmask, WLC_E_NDIS_LINK); 2214 setbit(dhdp->eventmask, WLC_E_MIC_ERROR); 2215 setbit(dhdp->eventmask, WLC_E_PMKID_CACHE); 2216 setbit(dhdp->eventmask, WLC_E_TXFAIL); 2217 setbit(dhdp->eventmask, WLC_E_JOIN_START); 2218 setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE); 2219 #ifdef PNO_SUPPORT 2220 setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND); 2221 #endif /* PNO_SUPPORT */ 2222 2223 /* enable dongle roaming event */ 2224 setbit(dhdp->eventmask, WLC_E_ROAM); 2225 2226 dhdp->pktfilter_count = 1; 2227 /* Setup filter to allow only unicast */ 2228 dhdp->pktfilter[0] = "100 0 0 0 0x01 0x00"; 2229 #endif /* EMBEDDED_PLATFORM */ 2230 2231 /* Bus is ready, do any protocol initialization */ 2232 if ((ret = dhd_prot_init(&dhd->pub)) < 0) 2233 return ret; 2234 2235 return 0; 2236 } 2237 2238 int 2239 dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set) 2240 { 2241 char buf[strlen(name) + 1 + cmd_len]; 2242 int len = sizeof(buf); 2243 wl_ioctl_t ioc; 2244 int ret; 2245 2246 len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); 2247 2248 memset(&ioc, 0, sizeof(ioc)); 2249 2250 ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; 2251 ioc.buf = buf; 2252 ioc.len = len; 2253 ioc.set = set; 2254 2255 ret = dhd_prot_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); 2256 if (!set && ret >= 0) 2257 memcpy(cmd_buf, buf, cmd_len); 2258 2259 return ret; 2260 } 2261 2262 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) 2263 static struct net_device_ops dhd_ops_pri = { 2264 .ndo_open = dhd_open, 2265 .ndo_stop = dhd_stop, 2266 .ndo_get_stats = dhd_get_stats, 2267 .ndo_do_ioctl = dhd_ioctl_entry, 2268 .ndo_start_xmit = dhd_start_xmit, 2269 .ndo_set_mac_address = dhd_set_mac_address, 2270 .ndo_set_multicast_list = dhd_set_multicast_list, 2271 }; 2272 2273 static struct net_device_ops dhd_ops_virt = { 2274 .ndo_get_stats = dhd_get_stats, 2275 .ndo_do_ioctl = dhd_ioctl_entry, 2276 .ndo_start_xmit = dhd_start_xmit, 2277 .ndo_set_mac_address = dhd_set_mac_address, 2278 .ndo_set_multicast_list = dhd_set_multicast_list, 2279 }; 2280 #endif 2281 2282 int 2283 dhd_net_attach(dhd_pub_t *dhdp, int ifidx) 2284 { 2285 dhd_info_t *dhd = (dhd_info_t *)dhdp->info; 2286 struct net_device *net; 2287 uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; 2288 2289 DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); 2290 2291 ASSERT(dhd && dhd->iflist[ifidx]); 2292 net = dhd->iflist[ifidx]->net; 2293 2294 ASSERT(net); 2295 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) 2296 ASSERT(!net->open); 2297 net->get_stats = dhd_get_stats; 2298 net->do_ioctl = dhd_ioctl_entry; 2299 net->hard_start_xmit = dhd_start_xmit; 2300 net->set_mac_address = dhd_set_mac_address; 2301 net->set_multicast_list = dhd_set_multicast_list; 2302 net->open = net->stop = NULL; 2303 #else 2304 ASSERT(!net->netdev_ops); 2305 net->netdev_ops = &dhd_ops_virt; 2306 #endif 2307 2308 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) 2309 net->open = dhd_open; 2310 net->stop = dhd_stop; 2311 #else 2312 net->netdev_ops = &dhd_ops_pri; 2313 #endif 2314 2315 /* 2316 * We have to use the primary MAC for virtual interfaces 2317 */ 2318 if (ifidx != 0) { 2319 /* for virtual interfaces use the primary MAC */ 2320 memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); 2321 } 2322 2323 if (ifidx == 1) { 2324 DHD_TRACE(("%s ACCESS POINT MAC: \n", __FUNCTION__)); 2325 /* ACCESSPOINT INTERFACE CASE */ 2326 temp_addr[0] |= 0x02; /* set bit 2 , - Locally Administered address */ 2327 } 2328 net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; 2329 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) 2330 net->ethtool_ops = &dhd_ethtool_ops; 2331 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ 2332 2333 #if defined(CONFIG_WIRELESS_EXT) 2334 #if WIRELESS_EXT < 19 2335 net->get_wireless_stats = dhd_get_wireless_stats; 2336 #endif /* WIRELESS_EXT < 19 */ 2337 #if WIRELESS_EXT > 12 2338 net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; 2339 #endif /* WIRELESS_EXT > 12 */ 2340 #endif /* defined(CONFIG_WIRELESS_EXT) */ 2341 2342 dhd->pub.rxsz = net->mtu + net->hard_header_len + dhd->pub.hdrlen; 2343 2344 memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); 2345 2346 if (register_netdev(net) != 0) { 2347 DHD_ERROR(("%s: couldn't register the net device\n", __FUNCTION__)); 2348 goto fail; 2349 } 2350 2351 printf("%s: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", net->name, 2352 dhd->pub.mac.octet[0], dhd->pub.mac.octet[1], dhd->pub.mac.octet[2], 2353 dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]); 2354 2355 #if defined(CONFIG_WIRELESS_EXT) 2356 #ifdef SOFTAP 2357 if (ifidx == 0) 2358 /* Don't call for SOFTAP Interface in SOFTAP MODE */ 2359 wl_iw_iscan_set_scan_broadcast_prep(net, 1); 2360 #else 2361 wl_iw_iscan_set_scan_broadcast_prep(net, 1); 2362 #endif /* SOFTAP */ 2363 #endif /* CONFIG_WIRELESS_EXT */ 2364 2365 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2366 up(&dhd_registration_sem); 2367 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ 2368 return 0; 2369 2370 fail: 2371 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) 2372 net->open = NULL; 2373 #else 2374 net->netdev_ops = NULL; 2375 #endif 2376 return BCME_ERROR; 2377 } 2378 2379 void 2380 dhd_bus_detach(dhd_pub_t *dhdp) 2381 { 2382 dhd_info_t *dhd; 2383 2384 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 2385 2386 if (dhdp) { 2387 dhd = (dhd_info_t *)dhdp->info; 2388 if (dhd) { 2389 /* Stop the protocol module */ 2390 dhd_prot_stop(&dhd->pub); 2391 2392 /* Stop the bus module */ 2393 dhd_bus_stop(dhd->pub.bus, TRUE); 2394 #if defined(OOB_INTR_ONLY) 2395 bcmsdh_unregister_oob_intr(); 2396 #endif /* defined(OOB_INTR_ONLY) */ 2397 2398 /* Clear the watchdog timer */ 2399 del_timer_sync(&dhd->timer); 2400 dhd->wd_timer_valid = FALSE; 2401 } 2402 } 2403 } 2404 2405 void 2406 dhd_detach(dhd_pub_t *dhdp) 2407 { 2408 dhd_info_t *dhd; 2409 2410 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 2411 2412 if (dhdp) { 2413 dhd = (dhd_info_t *)dhdp->info; 2414 if (dhd) { 2415 dhd_if_t *ifp; 2416 int i; 2417 2418 #if defined(CONFIG_HAS_EARLYSUSPEND) 2419 if (dhd->early_suspend.suspend) 2420 unregister_early_suspend(&dhd->early_suspend); 2421 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ 2422 #if defined(CONFIG_WIRELESS_EXT) 2423 /* Attach and link in the iw */ 2424 wl_iw_detach(); 2425 #endif 2426 2427 for (i = 1; i < DHD_MAX_IFS; i++) 2428 if (dhd->iflist[i]) 2429 dhd_del_if(dhd, i); 2430 2431 if (dhd->sysioc_pid >= 0) { 2432 KILL_PROC(dhd->sysioc_pid, SIGTERM); 2433 wait_for_completion(&dhd->sysioc_exited); 2434 } 2435 2436 ifp = dhd->iflist[0]; 2437 ASSERT(ifp); 2438 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) 2439 if (ifp->net->open) { 2440 #else 2441 if (ifp->net->netdev_ops == &dhd_ops_pri) { 2442 #endif 2443 dhd_stop(ifp->net); 2444 unregister_netdev(ifp->net); 2445 } 2446 2447 if (dhd->watchdog_pid >= 0) 2448 { 2449 KILL_PROC(dhd->watchdog_pid, SIGTERM); 2450 wait_for_completion(&dhd->watchdog_exited); 2451 } 2452 2453 if (dhd->dpc_pid >= 0) 2454 { 2455 KILL_PROC(dhd->dpc_pid, SIGTERM); 2456 wait_for_completion(&dhd->dpc_exited); 2457 } 2458 else 2459 tasklet_kill(&dhd->tasklet); 2460 2461 dhd_bus_detach(dhdp); 2462 2463 if (dhdp->prot) 2464 dhd_prot_detach(dhdp); 2465 2466 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) 2467 unregister_pm_notifier(&dhd_sleep_pm_notifier); 2468 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ 2469 free_netdev(ifp->net); 2470 #ifdef CONFIG_HAS_WAKELOCK 2471 wake_lock_destroy(&dhd->wl_wifi); 2472 wake_lock_destroy(&dhd->wl_rxwake); 2473 #endif 2474 MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); 2475 MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); 2476 } 2477 } 2478 } 2479 2480 static void __exit 2481 dhd_module_cleanup(void) 2482 { 2483 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 2484 2485 dhd_bus_unregister(); 2486 #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) 2487 wifi_del_dev(); 2488 #endif 2489 /* Call customer gpio to turn off power with WL_REG_ON signal */ 2490 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); 2491 } 2492 2493 static int __init 2494 dhd_module_init(void) 2495 { 2496 int error; 2497 2498 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 2499 2500 /* Sanity check on the module parameters */ 2501 do { 2502 /* Both watchdog and DPC as tasklets are ok */ 2503 if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0)) 2504 break; 2505 2506 /* If both watchdog and DPC are threads, TX must be deferred */ 2507 if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx) 2508 break; 2509 2510 DHD_ERROR(("Invalid module parameters.\n")); 2511 return -EINVAL; 2512 } while (0); 2513 2514 /* Call customer gpio to turn on power with WL_REG_ON signal */ 2515 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); 2516 2517 #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) 2518 sema_init(&wifi_control_sem, 0); 2519 2520 error = wifi_add_dev(); 2521 if (error) { 2522 DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__)); 2523 goto fail_0; 2524 } 2525 2526 /* Waiting callback after platform_driver_register is done or exit with error */ 2527 if (down_timeout(&wifi_control_sem, msecs_to_jiffies(5000)) != 0) { 2528 error = -EINVAL; 2529 DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__)); 2530 goto fail_1; 2531 } 2532 #endif /* #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ 2533 2534 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2535 sema_init(&dhd_registration_sem, 0); 2536 #endif 2537 2538 error = dhd_bus_register(); 2539 2540 if (!error) 2541 printf("\n%s\n", dhd_version); 2542 else { 2543 DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); 2544 goto fail_1; 2545 } 2546 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2547 /* 2548 * Wait till MMC sdio_register_driver callback called and made driver attach. 2549 * It's needed to make sync up exit from dhd insmod and 2550 * Kernel MMC sdio device callback registration 2551 */ 2552 if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) { 2553 error = -EINVAL; 2554 DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); 2555 goto fail_2; 2556 } 2557 #endif 2558 return error; 2559 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) 2560 fail_2: 2561 dhd_bus_unregister(); 2562 #endif 2563 fail_1: 2564 #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) 2565 wifi_del_dev(); 2566 fail_0: 2567 #endif /* defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ 2568 2569 /* Call customer gpio to turn off power with WL_REG_ON signal */ 2570 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); 2571 2572 return error; 2573 } 2574 2575 module_init(dhd_module_init); 2576 module_exit(dhd_module_cleanup); 2577 2578 /* 2579 * OS specific functions required to implement DHD driver in OS independent way 2580 */ 2581 int 2582 dhd_os_proto_block(dhd_pub_t *pub) 2583 { 2584 dhd_info_t *dhd = (dhd_info_t *)(pub->info); 2585 2586 if (dhd) { 2587 down(&dhd->proto_sem); 2588 return 1; 2589 } 2590 2591 return 0; 2592 } 2593 2594 int 2595 dhd_os_proto_unblock(dhd_pub_t *pub) 2596 { 2597 dhd_info_t *dhd = (dhd_info_t *)(pub->info); 2598 2599 if (dhd) { 2600 up(&dhd->proto_sem); 2601 return 1; 2602 } 2603 2604 return 0; 2605 } 2606 2607 unsigned int 2608 dhd_os_get_ioctl_resp_timeout(void) 2609 { 2610 return ((unsigned int)dhd_ioctl_timeout_msec); 2611 } 2612 2613 void 2614 dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) 2615 { 2616 dhd_ioctl_timeout_msec = (int)timeout_msec; 2617 } 2618 2619 int 2620 dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) 2621 { 2622 dhd_info_t *dhd = (dhd_info_t *)(pub->info); 2623 DECLARE_WAITQUEUE(wait, current); 2624 int timeout = dhd_ioctl_timeout_msec; 2625 2626 /* Convert timeout in millsecond to jiffies */ 2627 /* timeout = timeout * HZ / 1000; */ 2628 timeout = msecs_to_jiffies(timeout); 2629 2630 /* Wait until control frame is available */ 2631 add_wait_queue(&dhd->ioctl_resp_wait, &wait); 2632 set_current_state(TASK_INTERRUPTIBLE); 2633 smp_mb(); 2634 while (!(*condition) && (!signal_pending(current) && timeout)) { 2635 timeout = schedule_timeout(timeout); 2636 smp_mb(); 2637 } 2638 2639 if (signal_pending(current)) 2640 *pending = TRUE; 2641 2642 set_current_state(TASK_RUNNING); 2643 remove_wait_queue(&dhd->ioctl_resp_wait, &wait); 2644 2645 return timeout; 2646 } 2647 2648 int 2649 dhd_os_ioctl_resp_wake(dhd_pub_t *pub) 2650 { 2651 dhd_info_t *dhd = (dhd_info_t *)(pub->info); 2652 2653 if (waitqueue_active(&dhd->ioctl_resp_wait)) { 2654 wake_up_interruptible(&dhd->ioctl_resp_wait); 2655 } 2656 2657 return 0; 2658 } 2659 2660 void 2661 dhd_os_wd_timer(void *bus, uint wdtick) 2662 { 2663 dhd_pub_t *pub = bus; 2664 static uint save_dhd_watchdog_ms = 0; 2665 dhd_info_t *dhd = (dhd_info_t *)pub->info; 2666 2667 /* don't start the wd until fw is loaded */ 2668 if (pub->busstate == DHD_BUS_DOWN) 2669 return; 2670 2671 /* Totally stop the timer */ 2672 if (!wdtick && dhd->wd_timer_valid == TRUE) { 2673 del_timer_sync(&dhd->timer); 2674 dhd->wd_timer_valid = FALSE; 2675 save_dhd_watchdog_ms = wdtick; 2676 return; 2677 } 2678 2679 if (wdtick) { 2680 dhd_watchdog_ms = (uint)wdtick; 2681 2682 /* Re arm the timer, at last watchdog period */ 2683 mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); 2684 2685 dhd->wd_timer_valid = TRUE; 2686 save_dhd_watchdog_ms = wdtick; 2687 } 2688 } 2689 2690 void * 2691 dhd_os_open_image(char *filename) 2692 { 2693 struct file *fp; 2694 2695 fp = filp_open(filename, O_RDONLY, 0); 2696 /* 2697 * 2.6.11 (FC4) supports filp_open() but later revs don't? 2698 * Alternative: 2699 * fp = open_namei(AT_FDCWD, filename, O_RD, 0); 2700 * ??? 2701 */ 2702 if (IS_ERR(fp)) 2703 fp = NULL; 2704 2705 return fp; 2706 } 2707 2708 int 2709 dhd_os_get_image_block(char *buf, int len, void *image) 2710 { 2711 struct file *fp = (struct file *)image; 2712 int rdlen; 2713 2714 if (!image) 2715 return 0; 2716 2717 rdlen = kernel_read(fp, fp->f_pos, buf, len); 2718 if (rdlen > 0) 2719 fp->f_pos += rdlen; 2720 2721 return rdlen; 2722 } 2723 2724 void 2725 dhd_os_close_image(void *image) 2726 { 2727 if (image) 2728 filp_close((struct file *)image, NULL); 2729 } 2730 2731 2732 void 2733 dhd_os_sdlock(dhd_pub_t *pub) 2734 { 2735 dhd_info_t *dhd; 2736 2737 dhd = (dhd_info_t *)(pub->info); 2738 2739 if (dhd->threads_only) 2740 down(&dhd->sdsem); 2741 else 2742 spin_lock_bh(&dhd->sdlock); 2743 } 2744 2745 void 2746 dhd_os_sdunlock(dhd_pub_t *pub) 2747 { 2748 dhd_info_t *dhd; 2749 2750 dhd = (dhd_info_t *)(pub->info); 2751 2752 if (dhd->threads_only) 2753 up(&dhd->sdsem); 2754 else 2755 spin_unlock_bh(&dhd->sdlock); 2756 } 2757 2758 void 2759 dhd_os_sdlock_txq(dhd_pub_t *pub) 2760 { 2761 dhd_info_t *dhd; 2762 2763 dhd = (dhd_info_t *)(pub->info); 2764 spin_lock_bh(&dhd->txqlock); 2765 } 2766 2767 void 2768 dhd_os_sdunlock_txq(dhd_pub_t *pub) 2769 { 2770 dhd_info_t *dhd; 2771 2772 dhd = (dhd_info_t *)(pub->info); 2773 spin_unlock_bh(&dhd->txqlock); 2774 } 2775 void 2776 dhd_os_sdlock_rxq(dhd_pub_t *pub) 2777 { 2778 } 2779 void 2780 dhd_os_sdunlock_rxq(dhd_pub_t *pub) 2781 { 2782 } 2783 2784 void 2785 dhd_os_sdtxlock(dhd_pub_t *pub) 2786 { 2787 dhd_os_sdlock(pub); 2788 } 2789 2790 void 2791 dhd_os_sdtxunlock(dhd_pub_t *pub) 2792 { 2793 dhd_os_sdunlock(pub); 2794 } 2795 2796 #ifdef DHD_USE_STATIC_BUF 2797 void * dhd_os_prealloc(int section, unsigned long size) 2798 { 2799 #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) 2800 void *alloc_ptr = NULL; 2801 if (wifi_control_data && wifi_control_data->mem_prealloc) 2802 { 2803 alloc_ptr = wifi_control_data->mem_prealloc(section, size); 2804 if (alloc_ptr) 2805 { 2806 DHD_INFO(("success alloc section %d\n", section)); 2807 bzero(alloc_ptr, size); 2808 return alloc_ptr; 2809 } 2810 } 2811 2812 DHD_ERROR(("can't alloc section %d\n", section)); 2813 return 0; 2814 #else 2815 return MALLOC(0, size); 2816 #endif /* #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ 2817 } 2818 #endif /* DHD_USE_STATIC_BUF */ 2819 #if defined(CONFIG_WIRELESS_EXT) 2820 struct iw_statistics * 2821 dhd_get_wireless_stats(struct net_device *dev) 2822 { 2823 int res = 0; 2824 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2825 2826 res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); 2827 2828 if (res == 0) 2829 return &dhd->iw.wstats; 2830 else 2831 return NULL; 2832 } 2833 #endif /* defined(CONFIG_WIRELESS_EXT) */ 2834 2835 static int 2836 dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, 2837 wl_event_msg_t *event, void **data) 2838 { 2839 int bcmerror = 0; 2840 2841 ASSERT(dhd != NULL); 2842 2843 bcmerror = wl_host_event(dhd, ifidx, pktdata, event, data); 2844 if (bcmerror != BCME_OK) 2845 return (bcmerror); 2846 2847 #if defined(CONFIG_WIRELESS_EXT) 2848 ASSERT(dhd->iflist[*ifidx] != NULL); 2849 2850 if (ntoh32(event->event_type) == WLC_E_IF) { 2851 DHD_INFO(("<0> interface:%d OP:%d don't pass to wext," 2852 "net_device might not be created yet\n", 2853 *ifidx, ntoh32(event->event_type))); 2854 return bcmerror; 2855 } 2856 2857 ASSERT(dhd->iflist[*ifidx]->net != NULL); 2858 2859 if (dhd->iflist[*ifidx]->net) 2860 wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); 2861 #endif /* defined(CONFIG_WIRELESS_EXT) */ 2862 2863 return (bcmerror); 2864 } 2865 2866 /* send up locally generated event */ 2867 void 2868 dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) 2869 { 2870 switch (ntoh32(event->event_type)) { 2871 default: 2872 break; 2873 } 2874 } 2875 2876 void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) 2877 { 2878 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) 2879 struct dhd_info *dhdinfo = dhd->info; 2880 dhd_os_sdunlock(dhd); 2881 wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2); 2882 dhd_os_sdlock(dhd); 2883 #endif 2884 return; 2885 } 2886 2887 void dhd_wait_event_wakeup(dhd_pub_t *dhd) 2888 { 2889 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) 2890 struct dhd_info *dhdinfo = dhd->info; 2891 if (waitqueue_active(&dhdinfo->ctrl_wait)) 2892 wake_up_interruptible(&dhdinfo->ctrl_wait); 2893 #endif 2894 return; 2895 } 2896 2897 int 2898 dhd_dev_reset(struct net_device *dev, uint8 flag) 2899 { 2900 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2901 2902 /* Turning off watchdog */ 2903 if (flag) 2904 dhd_os_wd_timer(&dhd->pub, 0); 2905 2906 dhd_bus_devreset(&dhd->pub, flag); 2907 2908 /* Turning on watchdog back */ 2909 if (!flag) 2910 dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); 2911 DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); 2912 2913 return 1; 2914 } 2915 2916 int net_os_set_suspend_disable(struct net_device *dev, int val) 2917 { 2918 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2919 int ret = 0; 2920 2921 if (dhd) { 2922 ret = dhd->pub.suspend_disable_flag; 2923 dhd->pub.suspend_disable_flag = val; 2924 } 2925 return ret; 2926 } 2927 2928 int net_os_set_suspend(struct net_device *dev, int val) 2929 { 2930 int ret = 0; 2931 #if defined(CONFIG_HAS_EARLYSUSPEND) 2932 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2933 2934 if (dhd) { 2935 dhd_os_proto_block(&dhd->pub); 2936 ret = dhd_set_suspend(val, &dhd->pub); 2937 dhd_os_proto_unblock(&dhd->pub); 2938 } 2939 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ 2940 return ret; 2941 } 2942 2943 int net_os_set_dtim_skip(struct net_device *dev, int val) 2944 { 2945 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2946 2947 if (dhd) 2948 dhd->pub.dtim_skip = val; 2949 2950 return 0; 2951 } 2952 2953 int net_os_set_packet_filter(struct net_device *dev, int val) 2954 { 2955 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2956 int ret = 0; 2957 2958 /* Packet filtering is set only if we still in early-suspend and 2959 * we need either to turn it ON or turn it OFF 2960 * We can always turn it OFF in case of early-suspend, but we turn it 2961 * back ON only if suspend_disable_flag was not set 2962 */ 2963 if (dhd && dhd->pub.up) { 2964 dhd_os_proto_block(&dhd->pub); 2965 if (dhd->pub.in_suspend) { 2966 if (!val || (val && !dhd->pub.suspend_disable_flag)) 2967 dhd_set_packet_filter(val, &dhd->pub); 2968 } 2969 dhd_os_proto_unblock(&dhd->pub); 2970 } 2971 return ret; 2972 } 2973 2974 2975 void 2976 dhd_dev_init_ioctl(struct net_device *dev) 2977 { 2978 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2979 2980 dhd_preinit_ioctls(&dhd->pub); 2981 } 2982 2983 #ifdef PNO_SUPPORT 2984 /* Linux wrapper to call common dhd_pno_clean */ 2985 int 2986 dhd_dev_pno_reset(struct net_device *dev) 2987 { 2988 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2989 2990 return (dhd_pno_clean(&dhd->pub)); 2991 } 2992 2993 2994 /* Linux wrapper to call common dhd_pno_enable */ 2995 int 2996 dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled) 2997 { 2998 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 2999 3000 return (dhd_pno_enable(&dhd->pub, pfn_enabled)); 3001 } 3002 3003 3004 /* Linux wrapper to call common dhd_pno_set */ 3005 int 3006 dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr) 3007 { 3008 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 3009 3010 return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr)); 3011 } 3012 3013 /* Linux wrapper to get pno status */ 3014 int 3015 dhd_dev_get_pno_status(struct net_device *dev) 3016 { 3017 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 3018 3019 return (dhd_pno_get_status(&dhd->pub)); 3020 } 3021 3022 #endif /* PNO_SUPPORT */ 3023 3024 static int 3025 dhd_get_pend_8021x_cnt(dhd_info_t *dhd) 3026 { 3027 return (atomic_read(&dhd->pend_8021x_cnt)); 3028 } 3029 3030 #define MAX_WAIT_FOR_8021X_TX 10 3031 3032 int 3033 dhd_wait_pend8021x(struct net_device *dev) 3034 { 3035 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 3036 int timeout = 10 * HZ / 1000; 3037 int ntimes = MAX_WAIT_FOR_8021X_TX; 3038 int pend = dhd_get_pend_8021x_cnt(dhd); 3039 3040 while (ntimes && pend) { 3041 if (pend) { 3042 set_current_state(TASK_INTERRUPTIBLE); 3043 schedule_timeout(timeout); 3044 set_current_state(TASK_RUNNING); 3045 ntimes--; 3046 } 3047 pend = dhd_get_pend_8021x_cnt(dhd); 3048 } 3049 return pend; 3050 } 3051 3052 #ifdef DHD_DEBUG 3053 int 3054 write_to_file(dhd_pub_t *dhd, uint8 *buf, int size) 3055 { 3056 int ret = 0; 3057 struct file *fp; 3058 mm_segment_t old_fs; 3059 loff_t pos = 0; 3060 3061 /* change to KERNEL_DS address limit */ 3062 old_fs = get_fs(); 3063 set_fs(KERNEL_DS); 3064 3065 /* open file to write */ 3066 fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640); 3067 if (!fp) { 3068 printf("%s: open file error\n", __FUNCTION__); 3069 ret = -1; 3070 goto exit; 3071 } 3072 3073 /* Write buf to file */ 3074 fp->f_op->write(fp, buf, size, &pos); 3075 3076 exit: 3077 /* free buf before return */ 3078 MFREE(dhd->osh, buf, size); 3079 /* close file before return */ 3080 if (fp) 3081 filp_close(fp, current->files); 3082 /* restore previous address limit */ 3083 set_fs(old_fs); 3084 3085 return ret; 3086 } 3087 #endif /* DHD_DEBUG */ 3088 3089 int dhd_os_wake_lock_timeout(dhd_pub_t *pub) 3090 { 3091 dhd_info_t *dhd = (dhd_info_t *)(pub->info); 3092 unsigned long flags; 3093 int ret = 0; 3094 3095 if (dhd) { 3096 spin_lock_irqsave(&dhd->wl_lock, flags); 3097 ret = dhd->wl_packet; 3098 #ifdef CONFIG_HAS_WAKELOCK 3099 if (dhd->wl_packet) 3100 wake_lock_timeout(&dhd->wl_rxwake, HZ); 3101 #endif 3102 dhd->wl_packet = 0; 3103 spin_unlock_irqrestore(&dhd->wl_lock, flags); 3104 } 3105 /* printk("%s: %d\n", __FUNCTION__, ret); */ 3106 return ret; 3107 } 3108 3109 int net_os_wake_lock_timeout(struct net_device *dev) 3110 { 3111 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 3112 int ret = 0; 3113 3114 if (dhd) 3115 ret = dhd_os_wake_lock_timeout(&dhd->pub); 3116 return ret; 3117 } 3118 3119 int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub) 3120 { 3121 dhd_info_t *dhd = (dhd_info_t *)(pub->info); 3122 unsigned long flags; 3123 3124 if (dhd) { 3125 spin_lock_irqsave(&dhd->wl_lock, flags); 3126 dhd->wl_packet = 1; 3127 spin_unlock_irqrestore(&dhd->wl_lock, flags); 3128 } 3129 /* printk("%s\n",__func__); */ 3130 return 0; 3131 } 3132 3133 int net_os_wake_lock_timeout_enable(struct net_device *dev) 3134 { 3135 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 3136 int ret = 0; 3137 3138 if (dhd) 3139 ret = dhd_os_wake_lock_timeout_enable(&dhd->pub); 3140 return ret; 3141 } 3142 3143 int dhd_os_wake_lock(dhd_pub_t *pub) 3144 { 3145 dhd_info_t *dhd = (dhd_info_t *)(pub->info); 3146 unsigned long flags; 3147 int ret = 0; 3148 3149 if (dhd) { 3150 spin_lock_irqsave(&dhd->wl_lock, flags); 3151 #ifdef CONFIG_HAS_WAKELOCK 3152 if (!dhd->wl_count) 3153 wake_lock(&dhd->wl_wifi); 3154 #endif 3155 dhd->wl_count++; 3156 ret = dhd->wl_count; 3157 spin_unlock_irqrestore(&dhd->wl_lock, flags); 3158 } 3159 /* printk("%s: %d\n", __FUNCTION__, ret); */ 3160 return ret; 3161 } 3162 3163 int net_os_wake_lock(struct net_device *dev) 3164 { 3165 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 3166 int ret = 0; 3167 3168 if (dhd) 3169 ret = dhd_os_wake_lock(&dhd->pub); 3170 return ret; 3171 } 3172 3173 int dhd_os_wake_unlock(dhd_pub_t *pub) 3174 { 3175 dhd_info_t *dhd = (dhd_info_t *)(pub->info); 3176 unsigned long flags; 3177 int ret = 0; 3178 3179 dhd_os_wake_lock_timeout(pub); 3180 if (dhd) { 3181 spin_lock_irqsave(&dhd->wl_lock, flags); 3182 if (dhd->wl_count) { 3183 dhd->wl_count--; 3184 #ifdef CONFIG_HAS_WAKELOCK 3185 if (!dhd->wl_count) 3186 wake_unlock(&dhd->wl_wifi); 3187 #endif 3188 ret = dhd->wl_count; 3189 } 3190 spin_unlock_irqrestore(&dhd->wl_lock, flags); 3191 } 3192 /* printk("%s: %d\n", __FUNCTION__, ret); */ 3193 return ret; 3194 } 3195 3196 int net_os_wake_unlock(struct net_device *dev) 3197 { 3198 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 3199 int ret = 0; 3200 3201 if (dhd) 3202 ret = dhd_os_wake_unlock(&dhd->pub); 3203 return ret; 3204 } 3205 3206 int net_os_send_hang_message(struct net_device *dev) 3207 { 3208 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); 3209 int ret = 0; 3210 3211 if (dhd) { 3212 if (!dhd->hang_was_sent) { 3213 dhd->hang_was_sent = 1; 3214 ret = wl_iw_send_priv_event(dev, "HANG"); 3215 } 3216 } 3217 return ret; 3218 } 3219