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