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