staging: brcm80211: removed unused code and definitions from fullmac
[cascardo/linux.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 #include <linux/init.h>
18 #include <linux/kernel.h>
19 #include <linux/kthread.h>
20 #include <linux/slab.h>
21 #include <linux/skbuff.h>
22 #include <linux/netdevice.h>
23 #include <linux/etherdevice.h>
24 #include <linux/mmc/sdio_func.h>
25 #include <linux/random.h>
26 #include <linux/spinlock.h>
27 #include <linux/ethtool.h>
28 #include <linux/fcntl.h>
29 #include <linux/fs.h>
30 #include <linux/uaccess.h>
31 #include <net/cfg80211.h>
32 #if defined(CONFIG_HAS_EARLYSUSPEND)
33 #include <linux/earlysuspend.h>
34 #endif
35 #include <defs.h>
36 #include <brcmu_utils.h>
37 #include <brcmu_wifi.h>
38
39 #include "dngl_stats.h"
40 #include "dhd.h"
41 #include "dhd_bus.h"
42 #include "dhd_proto.h"
43 #include "dhd_dbg.h"
44 #include "wl_cfg80211.h"
45 #include "bcmchip.h"
46
47 /* Global ASSERT type flag */
48 u32 g_assert_type;
49
50 #if defined(CONFIG_PM_SLEEP)
51 #include <linux/suspend.h>
52 atomic_t brcmf_mmc_suspend;
53 DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
54 #endif  /*  defined(CONFIG_PM_SLEEP) */
55
56 MODULE_AUTHOR("Broadcom Corporation");
57 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
58 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");
59 MODULE_LICENSE("Dual BSD/GPL");
60
61
62 /* Interface control information */
63 struct brcmf_if {
64         struct brcmf_info *info;        /* back pointer to brcmf_info */
65         /* OS/stack specifics */
66         struct net_device *net;
67         struct net_device_stats stats;
68         int idx;                /* iface idx in dongle */
69         int state;              /* interface state */
70         uint subunit;           /* subunit */
71         u8 mac_addr[ETH_ALEN];  /* assigned MAC address */
72         bool attached;          /* Delayed attachment when unset */
73         bool txflowcontrol;     /* Per interface flow control indicator */
74         char name[IFNAMSIZ];    /* linux interface name */
75 };
76
77 /* Local private structure (extension of pub) */
78 struct brcmf_info {
79         struct brcmf_pub pub;
80
81         /* OS/stack specifics */
82         struct brcmf_if *iflist[BRCMF_MAX_IFS];
83
84         struct semaphore proto_sem;
85         wait_queue_head_t ioctl_resp_wait;
86
87         /* Thread to issue ioctl for multicast */
88         struct task_struct *sysioc_tsk;
89         struct semaphore sysioc_sem;
90         bool set_multicast;
91         bool set_macaddress;
92         u8 macvalue[ETH_ALEN];
93         atomic_t pend_8021x_cnt;
94
95 #ifdef CONFIG_HAS_EARLYSUSPEND
96         struct early_suspend early_suspend;
97 #endif                          /* CONFIG_HAS_EARLYSUSPEND */
98 };
99
100 /* Error bits */
101 module_param(brcmf_msg_level, int, 0);
102
103 /* Spawn a thread for system ioctls (set mac, set mcast) */
104 uint brcmf_sysioc = true;
105 module_param(brcmf_sysioc, uint, 0);
106
107 /* ARP offload agent mode : Enable ARP Host Auto-Reply
108 and ARP Peer Auto-Reply */
109 uint brcmf_arp_mode = 0xb;
110 module_param(brcmf_arp_mode, uint, 0);
111
112 /* ARP offload enable */
113 uint brcmf_arp_enable = true;
114 module_param(brcmf_arp_enable, uint, 0);
115
116 /* Global Pkt filter enable control */
117 uint brcmf_pkt_filter_enable = true;
118 module_param(brcmf_pkt_filter_enable, uint, 0);
119
120 /*  Pkt filter init setup */
121 uint brcmf_pkt_filter_init;
122 module_param(brcmf_pkt_filter_init, uint, 0);
123
124 /* Pkt filter mode control */
125 uint brcmf_master_mode = true;
126 module_param(brcmf_master_mode, uint, 1);
127
128 extern int brcmf_dongle_memsize;
129 module_param(brcmf_dongle_memsize, int, 0);
130
131 /* Contorl fw roaming */
132 uint brcmf_roam = 1;
133
134 /* Control radio state */
135 uint brcmf_radio_up = 1;
136
137 /* Network inteface name */
138 char iface_name[IFNAMSIZ] = "wlan";
139 module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
140
141 /* The following are specific to the SDIO dongle */
142
143 /* IOCTL response timeout */
144 int brcmf_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
145
146 /* Idle timeout for backplane clock */
147 int brcmf_idletime = BRCMF_IDLETIME_TICKS;
148 module_param(brcmf_idletime, int, 0);
149
150 /* Use polling */
151 uint brcmf_poll;
152 module_param(brcmf_poll, uint, 0);
153
154 /* Use interrupts */
155 uint brcmf_intr = true;
156 module_param(brcmf_intr, uint, 0);
157
158 /* SDIO Drive Strength (in milliamps) */
159 uint brcmf_sdiod_drive_strength = 6;
160 module_param(brcmf_sdiod_drive_strength, uint, 0);
161
162 /* Tx/Rx bounds */
163 extern uint brcmf_txbound;
164 extern uint brcmf_rxbound;
165 module_param(brcmf_txbound, uint, 0);
166 module_param(brcmf_rxbound, uint, 0);
167
168 #ifdef SDTEST
169 /* Echo packet generator (pkts/s) */
170 uint brcmf_pktgen;
171 module_param(brcmf_pktgen, uint, 0);
172
173 /* Echo packet len (0 => sawtooth, max 2040) */
174 uint brcmf_pktgen_len;
175 module_param(brcmf_pktgen_len, uint, 0);
176 #endif
177
178 /* Version string to report */
179 #ifdef BCMDBG
180 #define DHD_COMPILED "\nCompiled in " SRCBASE
181 #else
182 #define DHD_COMPILED
183 #endif
184
185 static int brcmf_toe_get(struct brcmf_info *drvr_priv, int idx, u32 *toe_ol);
186 static int brcmf_toe_set(struct brcmf_info *drvr_priv, int idx, u32 toe_ol);
187 static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
188                             struct brcmf_event_msg *event_ptr,
189                             void **data_ptr);
190
191 #if defined(CONFIG_HAS_EARLYSUSPEND)
192 static int brcmf_set_suspend(int value, struct brcmf_pub *drvr)
193 {
194         int power_mode = PM_MAX;
195         /* struct wl_pkt_filter_enable       enable_parm; */
196         char iovbuf[32];
197         int bcn_li_dtim = 3;
198
199         DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
200                    __func__, value, drvr->in_suspend));
201
202         if (drvr && drvr->up) {
203                 if (value && drvr->in_suspend) {
204
205                         /* Kernel suspended */
206                         DHD_TRACE(("%s: force extra Suspend setting\n",
207                                    __func__));
208
209                         brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_PM,
210                                          (char *)&power_mode,
211                                          sizeof(power_mode));
212
213                         /* Enable packet filter, only allow unicast
214                                  packet to send up */
215                         brcmf_set_packet_filter(1, drvr);
216
217                         /* if dtim skip setup as default force it
218                          * to wake each third dtim
219                          * for better power saving.
220                          * Note that side effect is chance to miss BC/MC
221                          * packet
222                          */
223                         if ((drvr->dtim_skip == 0) || (drvr->dtim_skip == 1))
224                                 bcn_li_dtim = 3;
225                         else
226                                 bcn_li_dtim = drvr->dtim_skip;
227                         brcmu_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
228                                     4, iovbuf, sizeof(iovbuf));
229                         brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR,
230                                                   iovbuf, sizeof(iovbuf));
231                 } else {
232
233                         /* Kernel resumed  */
234                         DHD_TRACE(("%s: Remove extra suspend setting\n",
235                                    __func__));
236
237                         power_mode = PM_FAST;
238                         brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_PM,
239                                                   (char *)&power_mode,
240                                                   sizeof(power_mode));
241
242                         /* disable pkt filter */
243                         brcmf_set_packet_filter(0, drvr);
244
245                         /* restore pre-suspend setting for dtim_skip */
246                         brcmu_mkiovar("bcn_li_dtim", (char *)&drvr->dtim_skip,
247                                     4, iovbuf, sizeof(iovbuf));
248
249                         brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR,
250                                                   iovbuf, sizeof(iovbuf));
251                 }
252         }
253
254         return 0;
255 }
256
257 static void brcmf_suspend_resume_helper(struct brcmf_info *drvr_priv, int val)
258 {
259         struct brcmf_pub *drvr = &drvr_priv->pub;
260
261         brcmf_os_proto_block(drvr);
262         /* Set flag when early suspend was called */
263         drvr->in_suspend = val;
264         if (!drvr->suspend_disable_flag)
265                 brcmf_set_suspend(val, drvr);
266         brcmf_os_proto_unblock(drvr);
267 }
268
269 static void brcmf_early_suspend(struct early_suspend *h)
270 {
271         struct brcmf_info *drvr_priv =
272                         container_of(h, struct brcmf_info, early_suspend);
273
274         DHD_TRACE(("%s: enter\n", __func__));
275
276         if (drvr_priv)
277                 dhd_suspend_resume_helper(drvr_priv, 1);
278
279 }
280
281 static void brcmf_late_resume(struct early_suspend *h)
282 {
283         struct brcmf_info *drvr_priv =
284                         container_of(h, struct brcmf_info, early_suspend);
285
286         DHD_TRACE(("%s: enter\n", __func__));
287
288         if (drvr_priv)
289                 dhd_suspend_resume_helper(drvr_priv, 0);
290 }
291 #endif                          /* defined(CONFIG_HAS_EARLYSUSPEND) */
292
293 /*
294  * Generalized timeout mechanism.  Uses spin sleep with exponential
295  * back-off until
296  * the sleep time reaches one jiffy, then switches over to task delay.  Usage:
297  *
298  *      brcmf_timeout_start(&tmo, usec);
299  *      while (!brcmf_timeout_expired(&tmo))
300  *              if (poll_something())
301  *                      break;
302  *      if (brcmf_timeout_expired(&tmo))
303  *              fatal();
304  */
305
306 void brcmf_timeout_start(struct brcmf_timeout *tmo, uint usec)
307 {
308         tmo->limit = usec;
309         tmo->increment = 0;
310         tmo->elapsed = 0;
311         tmo->tick = 1000000 / HZ;
312 }
313
314 int brcmf_timeout_expired(struct brcmf_timeout *tmo)
315 {
316         /* Does nothing the first call */
317         if (tmo->increment == 0) {
318                 tmo->increment = 1;
319                 return 0;
320         }
321
322         if (tmo->elapsed >= tmo->limit)
323                 return 1;
324
325         /* Add the delay that's about to take place */
326         tmo->elapsed += tmo->increment;
327
328         if (tmo->increment < tmo->tick) {
329                 udelay(tmo->increment);
330                 tmo->increment *= 2;
331                 if (tmo->increment > tmo->tick)
332                         tmo->increment = tmo->tick;
333         } else {
334                 wait_queue_head_t delay_wait;
335                 DECLARE_WAITQUEUE(wait, current);
336                 int pending;
337                 init_waitqueue_head(&delay_wait);
338                 add_wait_queue(&delay_wait, &wait);
339                 set_current_state(TASK_INTERRUPTIBLE);
340                 schedule_timeout(1);
341                 pending = signal_pending(current);
342                 remove_wait_queue(&delay_wait, &wait);
343                 set_current_state(TASK_RUNNING);
344                 if (pending)
345                         return 1;       /* Interrupted */
346         }
347
348         return 0;
349 }
350
351 static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *net)
352 {
353         int i = 0;
354
355         ASSERT(drvr_priv);
356         while (i < BRCMF_MAX_IFS) {
357                 if (drvr_priv->iflist[i] && (drvr_priv->iflist[i]->net == net))
358                         return i;
359                 i++;
360         }
361
362         return BRCMF_BAD_IF;
363 }
364
365 int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
366 {
367         int i = BRCMF_MAX_IFS;
368
369         ASSERT(drvr_priv);
370
371         if (name == NULL || *name == '\0')
372                 return 0;
373
374         while (--i > 0)
375                 if (drvr_priv->iflist[i]
376                     && !strncmp(drvr_priv->iflist[i]->name, name, IFNAMSIZ))
377                         break;
378
379         DHD_TRACE(("%s: return idx %d for \"%s\"\n", __func__, i, name));
380
381         return i;               /* default - the primary interface */
382 }
383
384 char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
385 {
386         struct brcmf_info *drvr_priv = drvr->info;
387
388         ASSERT(drvr_priv);
389
390         if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
391                 DHD_ERROR(("%s: ifidx %d out of range\n", __func__, ifidx));
392                 return "<if_bad>";
393         }
394
395         if (drvr_priv->iflist[ifidx] == NULL) {
396                 DHD_ERROR(("%s: null i/f %d\n", __func__, ifidx));
397                 return "<if_null>";
398         }
399
400         if (drvr_priv->iflist[ifidx]->net)
401                 return drvr_priv->iflist[ifidx]->net->name;
402
403         return "<if_none>";
404 }
405
406 static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
407 {
408         struct net_device *dev;
409         struct netdev_hw_addr *ha;
410         u32 allmulti, cnt;
411
412         struct brcmf_ioctl ioc;
413         char *buf, *bufp;
414         uint buflen;
415         int ret;
416
417         ASSERT(drvr_priv && drvr_priv->iflist[ifidx]);
418         dev = drvr_priv->iflist[ifidx]->net;
419         cnt = netdev_mc_count(dev);
420
421         /* Determine initial value of allmulti flag */
422         allmulti = (dev->flags & IFF_ALLMULTI) ? true : false;
423
424         /* Send down the multicast list first. */
425
426         buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
427         bufp = buf = kmalloc(buflen, GFP_ATOMIC);
428         if (!bufp) {
429                 DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
430                            brcmf_ifname(&drvr_priv->pub, ifidx), cnt));
431                 return;
432         }
433
434         strcpy(bufp, "mcast_list");
435         bufp += strlen("mcast_list") + 1;
436
437         cnt = cpu_to_le32(cnt);
438         memcpy(bufp, &cnt, sizeof(cnt));
439         bufp += sizeof(cnt);
440
441         netdev_for_each_mc_addr(ha, dev) {
442                 if (!cnt)
443                         break;
444                 memcpy(bufp, ha->addr, ETH_ALEN);
445                 bufp += ETH_ALEN;
446                 cnt--;
447         }
448
449         memset(&ioc, 0, sizeof(ioc));
450         ioc.cmd = BRCMF_C_SET_VAR;
451         ioc.buf = buf;
452         ioc.len = buflen;
453         ioc.set = true;
454
455         ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
456         if (ret < 0) {
457                 DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
458                            brcmf_ifname(&drvr_priv->pub, ifidx), cnt));
459                 allmulti = cnt ? true : allmulti;
460         }
461
462         kfree(buf);
463
464         /* Now send the allmulti setting.  This is based on the setting in the
465          * net_device flags, but might be modified above to be turned on if we
466          * were trying to set some addresses and dongle rejected it...
467          */
468
469         buflen = sizeof("allmulti") + sizeof(allmulti);
470         buf = kmalloc(buflen, GFP_ATOMIC);
471         if (!buf) {
472                 DHD_ERROR(("%s: out of memory for allmulti\n",
473                            brcmf_ifname(&drvr_priv->pub, ifidx)));
474                 return;
475         }
476         allmulti = cpu_to_le32(allmulti);
477
478         if (!brcmu_mkiovar
479             ("allmulti", (void *)&allmulti, sizeof(allmulti), buf, buflen)) {
480                 DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d "
481                         "buflen %u\n", brcmf_ifname(&drvr_priv->pub, ifidx),
482                         (int)sizeof(allmulti), buflen));
483                 kfree(buf);
484                 return;
485         }
486
487         memset(&ioc, 0, sizeof(ioc));
488         ioc.cmd = BRCMF_C_SET_VAR;
489         ioc.buf = buf;
490         ioc.len = buflen;
491         ioc.set = true;
492
493         ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
494         if (ret < 0) {
495                 DHD_ERROR(("%s: set allmulti %d failed\n",
496                            brcmf_ifname(&drvr_priv->pub, ifidx),
497                            le32_to_cpu(allmulti)));
498         }
499
500         kfree(buf);
501
502         /* Finally, pick up the PROMISC flag as well, like the NIC
503                  driver does */
504
505         allmulti = (dev->flags & IFF_PROMISC) ? true : false;
506         allmulti = cpu_to_le32(allmulti);
507
508         memset(&ioc, 0, sizeof(ioc));
509         ioc.cmd = BRCMF_C_SET_PROMISC;
510         ioc.buf = &allmulti;
511         ioc.len = sizeof(allmulti);
512         ioc.set = true;
513
514         ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
515         if (ret < 0) {
516                 DHD_ERROR(("%s: set promisc %d failed\n",
517                            brcmf_ifname(&drvr_priv->pub, ifidx),
518                            le32_to_cpu(allmulti)));
519         }
520 }
521
522 static int _brcmf_set_mac_address(struct brcmf_info *drvr_priv, int ifidx, u8 *addr)
523 {
524         char buf[32];
525         struct brcmf_ioctl ioc;
526         int ret;
527
528         DHD_TRACE(("%s enter\n", __func__));
529         if (!brcmu_mkiovar
530             ("cur_etheraddr", (char *)addr, ETH_ALEN, buf, 32)) {
531                 DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n",
532                            brcmf_ifname(&drvr_priv->pub, ifidx)));
533                 return -1;
534         }
535         memset(&ioc, 0, sizeof(ioc));
536         ioc.cmd = BRCMF_C_SET_VAR;
537         ioc.buf = buf;
538         ioc.len = 32;
539         ioc.set = true;
540
541         ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
542         if (ret < 0) {
543                 DHD_ERROR(("%s: set cur_etheraddr failed\n",
544                            brcmf_ifname(&drvr_priv->pub, ifidx)));
545         } else {
546                 memcpy(drvr_priv->iflist[ifidx]->net->dev_addr, addr, ETH_ALEN);
547         }
548
549         return ret;
550 }
551
552 #ifdef SOFTAP
553 extern struct net_device *ap_net_dev;
554 #endif
555
556 static void brcmf_op_if(struct brcmf_if *ifp)
557 {
558         struct brcmf_info *drvr_priv;
559         int ret = 0, err = 0;
560
561         ASSERT(ifp && ifp->info && ifp->idx);   /* Virtual interfaces only */
562
563         drvr_priv = ifp->info;
564
565         DHD_TRACE(("%s: idx %d, state %d\n", __func__, ifp->idx, ifp->state));
566
567         switch (ifp->state) {
568         case BRCMF_E_IF_ADD:
569                 /*
570                  * Delete the existing interface before overwriting it
571                  * in case we missed the BRCMF_E_IF_DEL event.
572                  */
573                 if (ifp->net != NULL) {
574                         DHD_ERROR(("%s: ERROR: netdev:%s already exists, "
575                         "try free & unregister\n",
576                         __func__, ifp->net->name));
577                         netif_stop_queue(ifp->net);
578                         unregister_netdev(ifp->net);
579                         free_netdev(ifp->net);
580                 }
581                 /* Allocate etherdev, including space for private structure */
582                 ifp->net = alloc_etherdev(sizeof(drvr_priv));
583                 if (!ifp->net) {
584                         DHD_ERROR(("%s: OOM - alloc_etherdev\n", __func__));
585                         ret = -ENOMEM;
586                 }
587                 if (ret == 0) {
588                         strcpy(ifp->net->name, ifp->name);
589                         memcpy(netdev_priv(ifp->net), &drvr_priv, sizeof(drvr_priv));
590                         err = brcmf_net_attach(&drvr_priv->pub, ifp->idx);
591                         if (err != 0) {
592                                 DHD_ERROR(("%s: dhd_net_attach failed, "
593                                         "err %d\n",
594                                         __func__, err));
595                                 ret = -EOPNOTSUPP;
596                         } else {
597 #ifdef SOFTAP
598                                 /* semaphore that the soft AP CODE
599                                          waits on */
600                                 extern struct semaphore ap_eth_sema;
601
602                                 /* save ptr to wl0.1 netdev for use
603                                          in wl_iw.c  */
604                                 ap_net_dev = ifp->net;
605                                 /* signal to the SOFTAP 'sleeper' thread,
606                                          wl0.1 is ready */
607                                 up(&ap_eth_sema);
608 #endif
609                                 DHD_TRACE(("\n ==== pid:%x, net_device for "
610                                         "if:%s created ===\n\n",
611                                         current->pid, ifp->net->name));
612                                 ifp->state = 0;
613                         }
614                 }
615                 break;
616         case BRCMF_E_IF_DEL:
617                 if (ifp->net != NULL) {
618                         DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n",
619                                    __func__));
620                         netif_stop_queue(ifp->net);
621                         unregister_netdev(ifp->net);
622                         ret = BRCMF_DEL_IF;     /* Make sure the free_netdev()
623                                                          is called */
624                 }
625                 break;
626         default:
627                 DHD_ERROR(("%s: bad op %d\n", __func__, ifp->state));
628                 ASSERT(!ifp->state);
629                 break;
630         }
631
632         if (ret < 0) {
633                 if (ifp->net)
634                         free_netdev(ifp->net);
635
636                 drvr_priv->iflist[ifp->idx] = NULL;
637                 kfree(ifp);
638 #ifdef SOFTAP
639                 if (ifp->net == ap_net_dev)
640                         ap_net_dev = NULL;      /*  NULL  SOFTAP global
641                                                          wl0.1 as well */
642 #endif                          /*  SOFTAP */
643         }
644 }
645
646 static int _brcmf_sysioc_thread(void *data)
647 {
648         struct brcmf_info *drvr_priv = (struct brcmf_info *) data;
649         int i;
650 #ifdef SOFTAP
651         bool in_ap = false;
652 #endif
653
654         allow_signal(SIGTERM);
655
656         while (down_interruptible(&drvr_priv->sysioc_sem) == 0) {
657                 if (kthread_should_stop())
658                         break;
659                 for (i = 0; i < BRCMF_MAX_IFS; i++) {
660                         if (drvr_priv->iflist[i]) {
661 #ifdef SOFTAP
662                                 in_ap = (ap_net_dev != NULL);
663 #endif                          /* SOFTAP */
664                                 if (drvr_priv->iflist[i]->state)
665                                         brcmf_op_if(drvr_priv->iflist[i]);
666 #ifdef SOFTAP
667                                 if (drvr_priv->iflist[i] == NULL) {
668                                         DHD_TRACE(("\n\n %s: interface %d "
669                                                 "removed!\n", __func__, i));
670                                         continue;
671                                 }
672
673                                 if (in_ap && drvr_priv->set_macaddress) {
674                                         DHD_TRACE(("attempt to set MAC for %s "
675                                                 "in AP Mode," "blocked.\n",
676                                                 drvr_priv->iflist[i]->net->name));
677                                         drvr_priv->set_macaddress = false;
678                                         continue;
679                                 }
680
681                                 if (in_ap && drvr_priv->set_multicast) {
682                                         DHD_TRACE(("attempt to set MULTICAST "
683                                                    "list for %s in AP Mode, "
684                                                    "blocked.\n",
685                                                    drvr_priv->iflist[i]->net->name));
686                                         drvr_priv->set_multicast = false;
687                                         continue;
688                                 }
689 #endif                          /* SOFTAP */
690                                 if (drvr_priv->set_multicast) {
691                                         drvr_priv->set_multicast = false;
692                                         _brcmf_set_multicast_list(drvr_priv, i);
693                                 }
694                                 if (drvr_priv->set_macaddress) {
695                                         drvr_priv->set_macaddress = false;
696                                         _brcmf_set_mac_address(drvr_priv, i,
697                                                              drvr_priv->macvalue);
698                                 }
699                         }
700                 }
701         }
702         return 0;
703 }
704
705 static int brcmf_netdev_set_mac_address(struct net_device *dev, void *addr)
706 {
707         int ret = 0;
708
709         struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(dev);
710         struct sockaddr *sa = (struct sockaddr *)addr;
711         int ifidx;
712
713         ifidx = brcmf_net2idx(drvr_priv, dev);
714         if (ifidx == BRCMF_BAD_IF)
715                 return -1;
716
717         ASSERT(drvr_priv->sysioc_tsk);
718         memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
719         drvr_priv->set_macaddress = true;
720         up(&drvr_priv->sysioc_sem);
721
722         return ret;
723 }
724
725 static void brcmf_netdev_set_multicast_list(struct net_device *dev)
726 {
727         struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(dev);
728         int ifidx;
729
730         ifidx = brcmf_net2idx(drvr_priv, dev);
731         if (ifidx == BRCMF_BAD_IF)
732                 return;
733
734         ASSERT(drvr_priv->sysioc_tsk);
735         drvr_priv->set_multicast = true;
736         up(&drvr_priv->sysioc_sem);
737 }
738
739 int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
740 {
741         struct brcmf_info *drvr_priv = drvr->info;
742
743         /* Reject if down */
744         if (!drvr->up || (drvr->busstate == DHD_BUS_DOWN))
745                 return -ENODEV;
746
747         /* Update multicast statistic */
748         if (pktbuf->len >= ETH_ALEN) {
749                 u8 *pktdata = (u8 *) (pktbuf->data);
750                 struct ethhdr *eh = (struct ethhdr *)pktdata;
751
752                 if (is_multicast_ether_addr(eh->h_dest))
753                         drvr->tx_multicast++;
754                 if (ntohs(eh->h_proto) == ETH_P_PAE)
755                         atomic_inc(&drvr_priv->pend_8021x_cnt);
756         }
757
758         /* If the protocol uses a data header, apply it */
759         brcmf_proto_hdrpush(drvr, ifidx, pktbuf);
760
761         /* Use bus module to send data frame */
762         return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf);
763 }
764
765 static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *net)
766 {
767         int ret;
768         struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
769         int ifidx;
770
771         DHD_TRACE(("%s: Enter\n", __func__));
772
773         /* Reject if down */
774         if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == DHD_BUS_DOWN)) {
775                 DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d\n",
776                            __func__, drvr_priv->pub.up, drvr_priv->pub.busstate));
777                 netif_stop_queue(net);
778                 return -ENODEV;
779         }
780
781         ifidx = brcmf_net2idx(drvr_priv, net);
782         if (ifidx == BRCMF_BAD_IF) {
783                 DHD_ERROR(("%s: bad ifidx %d\n", __func__, ifidx));
784                 netif_stop_queue(net);
785                 return -ENODEV;
786         }
787
788         /* Make sure there's enough room for any header */
789         if (skb_headroom(skb) < drvr_priv->pub.hdrlen) {
790                 struct sk_buff *skb2;
791
792                 DHD_INFO(("%s: insufficient headroom\n",
793                           brcmf_ifname(&drvr_priv->pub, ifidx)));
794                 drvr_priv->pub.tx_realloc++;
795                 skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);
796                 dev_kfree_skb(skb);
797                 skb = skb2;
798                 if (skb == NULL) {
799                         DHD_ERROR(("%s: skb_realloc_headroom failed\n",
800                                    brcmf_ifname(&drvr_priv->pub, ifidx)));
801                         ret = -ENOMEM;
802                         goto done;
803                 }
804         }
805
806         ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb);
807
808 done:
809         if (ret)
810                 drvr_priv->pub.dstats.tx_dropped++;
811         else
812                 drvr_priv->pub.tx_packets++;
813
814         /* Return ok: we always eat the packet */
815         return 0;
816 }
817
818 void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state)
819 {
820         struct net_device *net;
821         struct brcmf_info *drvr_priv = drvr->info;
822
823         DHD_TRACE(("%s: Enter\n", __func__));
824
825         drvr->txoff = state;
826         ASSERT(drvr_priv && drvr_priv->iflist[ifidx]);
827         net = drvr_priv->iflist[ifidx]->net;
828         if (state == ON)
829                 netif_stop_queue(net);
830         else
831                 netif_wake_queue(net);
832 }
833
834 void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
835                   int numpkt)
836 {
837         struct brcmf_info *drvr_priv = drvr->info;
838         unsigned char *eth;
839         uint len;
840         void *data;
841         struct sk_buff *pnext, *save_pktbuf;
842         int i;
843         struct brcmf_if *ifp;
844         struct brcmf_event_msg event;
845
846         DHD_TRACE(("%s: Enter\n", __func__));
847
848         save_pktbuf = skb;
849
850         for (i = 0; skb && i < numpkt; i++, skb = pnext) {
851
852                 pnext = skb->next;
853                 skb->next = NULL;
854
855                 /* Get the protocol, maintain skb around eth_type_trans()
856                  * The main reason for this hack is for the limitation of
857                  * Linux 2.4 where 'eth_type_trans' uses the
858                  * 'net->hard_header_len'
859                  * to perform skb_pull inside vs ETH_HLEN. Since to avoid
860                  * coping of the packet coming from the network stack to add
861                  * BDC, Hardware header etc, during network interface
862                  * registration
863                  * we set the 'net->hard_header_len' to ETH_HLEN + extra space
864                  * required
865                  * for BDC, Hardware header etc. and not just the ETH_HLEN
866                  */
867                 eth = skb->data;
868                 len = skb->len;
869
870                 ifp = drvr_priv->iflist[ifidx];
871                 if (ifp == NULL)
872                         ifp = drvr_priv->iflist[0];
873
874                 ASSERT(ifp);
875                 skb->dev = ifp->net;
876                 skb->protocol = eth_type_trans(skb, skb->dev);
877
878                 if (skb->pkt_type == PACKET_MULTICAST)
879                         drvr_priv->pub.rx_multicast++;
880
881                 skb->data = eth;
882                 skb->len = len;
883
884                 /* Strip header, count, deliver upward */
885                 skb_pull(skb, ETH_HLEN);
886
887                 /* Process special event packets and then discard them */
888                 if (ntohs(skb->protocol) == ETH_P_LINK_CTL)
889                         brcmf_host_event(drvr_priv, &ifidx,
890                                           skb_mac_header(skb),
891                                           &event, &data);
892
893                 ASSERT(ifidx < BRCMF_MAX_IFS && drvr_priv->iflist[ifidx]);
894                 if (drvr_priv->iflist[ifidx] &&
895                     !drvr_priv->iflist[ifidx]->state)
896                         ifp = drvr_priv->iflist[ifidx];
897
898                 if (ifp->net)
899                         ifp->net->last_rx = jiffies;
900
901                 drvr->dstats.rx_bytes += skb->len;
902                 drvr->rx_packets++;     /* Local count */
903
904                 if (in_interrupt()) {
905                         netif_rx(skb);
906                 } else {
907                         /* If the receive is not processed inside an ISR,
908                          * the softirqd must be woken explicitly to service
909                          * the NET_RX_SOFTIRQ.  In 2.6 kernels, this is handled
910                          * by netif_rx_ni(), but in earlier kernels, we need
911                          * to do it manually.
912                          */
913                         netif_rx_ni(skb);
914                 }
915         }
916 }
917
918 void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)
919 {
920         uint ifidx;
921         struct brcmf_info *drvr_priv = drvr->info;
922         struct ethhdr *eh;
923         u16 type;
924
925         brcmf_proto_hdrpull(drvr, &ifidx, txp);
926
927         eh = (struct ethhdr *)(txp->data);
928         type = ntohs(eh->h_proto);
929
930         if (type == ETH_P_PAE)
931                 atomic_dec(&drvr_priv->pend_8021x_cnt);
932
933 }
934
935 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *net)
936 {
937         struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
938         struct brcmf_if *ifp;
939         int ifidx;
940
941         DHD_TRACE(("%s: Enter\n", __func__));
942
943         ifidx = brcmf_net2idx(drvr_priv, net);
944         if (ifidx == BRCMF_BAD_IF)
945                 return NULL;
946
947         ifp = drvr_priv->iflist[ifidx];
948         ASSERT(drvr_priv && ifp);
949
950         if (drvr_priv->pub.up) {
951                 /* Use the protocol to get dongle stats */
952                 brcmf_proto_dstats(&drvr_priv->pub);
953         }
954
955         /* Copy dongle stats to net device stats */
956         ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets;
957         ifp->stats.tx_packets = drvr_priv->pub.dstats.tx_packets;
958         ifp->stats.rx_bytes = drvr_priv->pub.dstats.rx_bytes;
959         ifp->stats.tx_bytes = drvr_priv->pub.dstats.tx_bytes;
960         ifp->stats.rx_errors = drvr_priv->pub.dstats.rx_errors;
961         ifp->stats.tx_errors = drvr_priv->pub.dstats.tx_errors;
962         ifp->stats.rx_dropped = drvr_priv->pub.dstats.rx_dropped;
963         ifp->stats.tx_dropped = drvr_priv->pub.dstats.tx_dropped;
964         ifp->stats.multicast = drvr_priv->pub.dstats.multicast;
965
966         return &ifp->stats;
967 }
968
969 /* Retrieve current toe component enables, which are kept
970          as a bitmap in toe_ol iovar */
971 static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol)
972 {
973         struct brcmf_ioctl ioc;
974         char buf[32];
975         int ret;
976
977         memset(&ioc, 0, sizeof(ioc));
978
979         ioc.cmd = BRCMF_C_GET_VAR;
980         ioc.buf = buf;
981         ioc.len = (uint) sizeof(buf);
982         ioc.set = false;
983
984         strcpy(buf, "toe_ol");
985         ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
986         if (ret < 0) {
987                 /* Check for older dongle image that doesn't support toe_ol */
988                 if (ret == -EIO) {
989                         DHD_ERROR(("%s: toe not supported by device\n",
990                                    brcmf_ifname(&drvr_priv->pub, ifidx)));
991                         return -EOPNOTSUPP;
992                 }
993
994                 DHD_INFO(("%s: could not get toe_ol: ret=%d\n",
995                           brcmf_ifname(&drvr_priv->pub, ifidx), ret));
996                 return ret;
997         }
998
999         memcpy(toe_ol, buf, sizeof(u32));
1000         return 0;
1001 }
1002
1003 /* Set current toe component enables in toe_ol iovar,
1004          and set toe global enable iovar */
1005 static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
1006 {
1007         struct brcmf_ioctl ioc;
1008         char buf[32];
1009         int toe, ret;
1010
1011         memset(&ioc, 0, sizeof(ioc));
1012
1013         ioc.cmd = BRCMF_C_SET_VAR;
1014         ioc.buf = buf;
1015         ioc.len = (uint) sizeof(buf);
1016         ioc.set = true;
1017
1018         /* Set toe_ol as requested */
1019
1020         strcpy(buf, "toe_ol");
1021         memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(u32));
1022
1023         ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
1024         if (ret < 0) {
1025                 DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
1026                            brcmf_ifname(&drvr_priv->pub, ifidx), ret));
1027                 return ret;
1028         }
1029
1030         /* Enable toe globally only if any components are enabled. */
1031
1032         toe = (toe_ol != 0);
1033
1034         strcpy(buf, "toe");
1035         memcpy(&buf[sizeof("toe")], &toe, sizeof(u32));
1036
1037         ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
1038         if (ret < 0) {
1039                 DHD_ERROR(("%s: could not set toe: ret=%d\n",
1040                            brcmf_ifname(&drvr_priv->pub, ifidx), ret));
1041                 return ret;
1042         }
1043
1044         return 0;
1045 }
1046
1047 static void brcmf_ethtool_get_drvinfo(struct net_device *net,
1048                                     struct ethtool_drvinfo *info)
1049 {
1050         struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
1051
1052         sprintf(info->driver, KBUILD_MODNAME);
1053         sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
1054         sprintf(info->fw_version, "%s", BCM4329_FW_NAME);
1055         sprintf(info->bus_info, "%s", dev_name(&wl_cfg80211_get_sdio_func()->dev));
1056 }
1057
1058 struct ethtool_ops brcmf_ethtool_ops = {
1059         .get_drvinfo = brcmf_ethtool_get_drvinfo
1060 };
1061
1062 static int brcmf_ethtool(struct brcmf_info *drvr_priv, void *uaddr)
1063 {
1064         struct ethtool_drvinfo info;
1065         char drvname[sizeof(info.driver)];
1066         u32 cmd;
1067         struct ethtool_value edata;
1068         u32 toe_cmpnt, csum_dir;
1069         int ret;
1070
1071         DHD_TRACE(("%s: Enter\n", __func__));
1072
1073         /* all ethtool calls start with a cmd word */
1074         if (copy_from_user(&cmd, uaddr, sizeof(u32)))
1075                 return -EFAULT;
1076
1077         switch (cmd) {
1078         case ETHTOOL_GDRVINFO:
1079                 /* Copy out any request driver name */
1080                 if (copy_from_user(&info, uaddr, sizeof(info)))
1081                         return -EFAULT;
1082                 strncpy(drvname, info.driver, sizeof(info.driver));
1083                 drvname[sizeof(info.driver) - 1] = '\0';
1084
1085                 /* clear struct for return */
1086                 memset(&info, 0, sizeof(info));
1087                 info.cmd = cmd;
1088
1089                 /* if dhd requested, identify ourselves */
1090                 if (strcmp(drvname, "?dhd") == 0) {
1091                         sprintf(info.driver, "dhd");
1092                         strcpy(info.version, BRCMF_VERSION_STR);
1093                 }
1094
1095                 /* otherwise, require dongle to be up */
1096                 else if (!drvr_priv->pub.up) {
1097                         DHD_ERROR(("%s: dongle is not up\n", __func__));
1098                         return -ENODEV;
1099                 }
1100
1101                 /* finally, report dongle driver type */
1102                 else if (drvr_priv->pub.iswl)
1103                         sprintf(info.driver, "wl");
1104                 else
1105                         sprintf(info.driver, "xx");
1106
1107                 sprintf(info.version, "%lu", drvr_priv->pub.drv_version);
1108                 if (copy_to_user(uaddr, &info, sizeof(info)))
1109                         return -EFAULT;
1110                 DHD_CTL(("%s: given %*s, returning %s\n", __func__,
1111                          (int)sizeof(drvname), drvname, info.driver));
1112                 break;
1113
1114                 /* Get toe offload components from dongle */
1115         case ETHTOOL_GRXCSUM:
1116         case ETHTOOL_GTXCSUM:
1117                 ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt);
1118                 if (ret < 0)
1119                         return ret;
1120
1121                 csum_dir =
1122                     (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
1123
1124                 edata.cmd = cmd;
1125                 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
1126
1127                 if (copy_to_user(uaddr, &edata, sizeof(edata)))
1128                         return -EFAULT;
1129                 break;
1130
1131                 /* Set toe offload components in dongle */
1132         case ETHTOOL_SRXCSUM:
1133         case ETHTOOL_STXCSUM:
1134                 if (copy_from_user(&edata, uaddr, sizeof(edata)))
1135                         return -EFAULT;
1136
1137                 /* Read the current settings, update and write back */
1138                 ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt);
1139                 if (ret < 0)
1140                         return ret;
1141
1142                 csum_dir =
1143                     (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
1144
1145                 if (edata.data != 0)
1146                         toe_cmpnt |= csum_dir;
1147                 else
1148                         toe_cmpnt &= ~csum_dir;
1149
1150                 ret = brcmf_toe_set(drvr_priv, 0, toe_cmpnt);
1151                 if (ret < 0)
1152                         return ret;
1153
1154                 /* If setting TX checksum mode, tell Linux the new mode */
1155                 if (cmd == ETHTOOL_STXCSUM) {
1156                         if (edata.data)
1157                                 drvr_priv->iflist[0]->net->features |=
1158                                     NETIF_F_IP_CSUM;
1159                         else
1160                                 drvr_priv->iflist[0]->net->features &=
1161                                     ~NETIF_F_IP_CSUM;
1162                 }
1163
1164                 break;
1165
1166         default:
1167                 return -EOPNOTSUPP;
1168         }
1169
1170         return 0;
1171 }
1172
1173 static int brcmf_netdev_ioctl_entry(struct net_device *net, struct ifreq *ifr,
1174                                     int cmd)
1175 {
1176         struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
1177         struct brcmf_c_ioctl ioc;
1178         int bcmerror = 0;
1179         int buflen = 0;
1180         void *buf = NULL;
1181         uint driver = 0;
1182         int ifidx;
1183         bool is_set_key_cmd;
1184
1185         ifidx = brcmf_net2idx(drvr_priv, net);
1186         DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __func__, ifidx, cmd));
1187
1188         if (ifidx == BRCMF_BAD_IF)
1189                 return -1;
1190
1191         if (cmd == SIOCETHTOOL)
1192                 return brcmf_ethtool(drvr_priv, (void *)ifr->ifr_data);
1193
1194         if (cmd != SIOCDEVPRIVATE)
1195                 return -EOPNOTSUPP;
1196
1197         memset(&ioc, 0, sizeof(ioc));
1198
1199         /* Copy the ioc control structure part of ioctl request */
1200         if (copy_from_user(&ioc, ifr->ifr_data, sizeof(struct brcmf_ioctl))) {
1201                 bcmerror = -EINVAL;
1202                 goto done;
1203         }
1204
1205         /* Copy out any buffer passed */
1206         if (ioc.buf) {
1207                 buflen = min_t(int, ioc.len, BRCMF_IOCTL_MAXLEN);
1208                 /* optimization for direct ioctl calls from kernel */
1209                 /*
1210                    if (segment_eq(get_fs(), KERNEL_DS)) {
1211                    buf = ioc.buf;
1212                    } else {
1213                  */
1214                 {
1215                         buf = kmalloc(buflen, GFP_ATOMIC);
1216                         if (!buf) {
1217                                 bcmerror = -ENOMEM;
1218                                 goto done;
1219                         }
1220                         if (copy_from_user(buf, ioc.buf, buflen)) {
1221                                 bcmerror = -EINVAL;
1222                                 goto done;
1223                         }
1224                 }
1225         }
1226
1227         /* To differentiate between wl and dhd read 4 more byes */
1228         if ((copy_from_user(&driver, (char *)ifr->ifr_data +
1229                             sizeof(struct brcmf_ioctl), sizeof(uint)) != 0)) {
1230                 bcmerror = -EINVAL;
1231                 goto done;
1232         }
1233
1234         if (!capable(CAP_NET_ADMIN)) {
1235                 bcmerror = -EPERM;
1236                 goto done;
1237         }
1238
1239         /* check for local dhd ioctl and handle it */
1240         if (driver == BRCMF_IOCTL_MAGIC) {
1241                 bcmerror = brcmf_c_ioctl((void *)&drvr_priv->pub, &ioc, buf, buflen);
1242                 if (bcmerror)
1243                         drvr_priv->pub.bcmerror = bcmerror;
1244                 goto done;
1245         }
1246
1247         /* send to dongle (must be up, and wl) */
1248         if ((drvr_priv->pub.busstate != DHD_BUS_DATA)) {
1249                 DHD_ERROR(("%s DONGLE_DOWN,__func__\n", __func__));
1250                 bcmerror = -EIO;
1251                 goto done;
1252         }
1253
1254         if (!drvr_priv->pub.iswl) {
1255                 bcmerror = -EIO;
1256                 goto done;
1257         }
1258
1259         /*
1260          * Intercept BRCMF_C_SET_KEY IOCTL - serialize M4 send and
1261          * set key IOCTL to prevent M4 encryption.
1262          */
1263         is_set_key_cmd = ((ioc.cmd == BRCMF_C_SET_KEY) ||
1264                           ((ioc.cmd == BRCMF_C_SET_VAR) &&
1265                            !(strncmp("wsec_key", ioc.buf, 9))) ||
1266                           ((ioc.cmd == BRCMF_C_SET_VAR) &&
1267                            !(strncmp("bsscfg:wsec_key", ioc.buf, 15))));
1268         if (is_set_key_cmd)
1269                 brcmf_netdev_wait_pend8021x(net);
1270
1271         bcmerror =
1272             brcmf_proto_ioctl(&drvr_priv->pub, ifidx, (struct brcmf_ioctl *)&ioc,
1273                               buf, buflen);
1274
1275 done:
1276         if (!bcmerror && buf && ioc.buf) {
1277                 if (copy_to_user(ioc.buf, buf, buflen))
1278                         bcmerror = -EFAULT;
1279         }
1280
1281         kfree(buf);
1282
1283         if (bcmerror > 0)
1284                 bcmerror = 0;
1285
1286         return bcmerror;
1287 }
1288
1289 static int brcmf_netdev_stop(struct net_device *net)
1290 {
1291 #if !defined(IGNORE_ETH0_DOWN)
1292         struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
1293
1294         DHD_TRACE(("%s: Enter\n", __func__));
1295         wl_cfg80211_down();
1296         if (drvr_priv->pub.up == 0)
1297                 return 0;
1298
1299         /* Set state and stop OS transmissions */
1300         drvr_priv->pub.up = 0;
1301         netif_stop_queue(net);
1302 #else
1303         DHD_ERROR(("BYPASS %s:due to BRCM compilation : under investigation\n",
1304                 __func__));
1305 #endif                          /* !defined(IGNORE_ETH0_DOWN) */
1306
1307         return 0;
1308 }
1309
1310 static int brcmf_netdev_open(struct net_device *net)
1311 {
1312         struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
1313         u32 toe_ol;
1314         int ifidx = brcmf_net2idx(drvr_priv, net);
1315         s32 ret = 0;
1316
1317         DHD_TRACE(("%s: ifidx %d\n", __func__, ifidx));
1318
1319         if (ifidx == 0) {       /* do it only for primary eth0 */
1320
1321                 /* try to bring up bus */
1322                 ret = brcmf_bus_start(&drvr_priv->pub);
1323                 if (ret != 0) {
1324                         DHD_ERROR(("%s: failed with code %d\n", __func__, ret));
1325                         return -1;
1326                 }
1327                 atomic_set(&drvr_priv->pend_8021x_cnt, 0);
1328
1329                 memcpy(net->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
1330
1331                 /* Get current TOE mode from dongle */
1332                 if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0
1333                     && (toe_ol & TOE_TX_CSUM_OL) != 0)
1334                         drvr_priv->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
1335                 else
1336                         drvr_priv->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
1337         }
1338         /* Allow transmit calls */
1339         netif_start_queue(net);
1340         drvr_priv->pub.up = 1;
1341         if (unlikely(wl_cfg80211_up())) {
1342                 DHD_ERROR(("%s: failed to bring up cfg80211\n",
1343                            __func__));
1344                 return -1;
1345         }
1346
1347         return ret;
1348 }
1349
1350 int
1351 brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, void *handle, char *name,
1352            u8 *mac_addr, u32 flags, u8 bssidx)
1353 {
1354         struct brcmf_if *ifp;
1355
1356         DHD_TRACE(("%s: idx %d, handle->%p\n", __func__, ifidx, handle));
1357
1358         ASSERT(drvr_priv && (ifidx < BRCMF_MAX_IFS));
1359
1360         ifp = drvr_priv->iflist[ifidx];
1361         if (!ifp) {
1362                 ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC);
1363                 if (!ifp) {
1364                         DHD_ERROR(("%s: OOM - struct dhd_if\n", __func__));
1365                         return -ENOMEM;
1366                 }
1367         }
1368
1369         memset(ifp, 0, sizeof(struct brcmf_if));
1370         ifp->info = drvr_priv;
1371         drvr_priv->iflist[ifidx] = ifp;
1372         strlcpy(ifp->name, name, IFNAMSIZ);
1373         if (mac_addr != NULL)
1374                 memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
1375
1376         if (handle == NULL) {
1377                 ifp->state = BRCMF_E_IF_ADD;
1378                 ifp->idx = ifidx;
1379                 ASSERT(drvr_priv->sysioc_tsk);
1380                 up(&drvr_priv->sysioc_sem);
1381         } else
1382                 ifp->net = (struct net_device *)handle;
1383
1384         return 0;
1385 }
1386
1387 void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
1388 {
1389         struct brcmf_if *ifp;
1390
1391         DHD_TRACE(("%s: idx %d\n", __func__, ifidx));
1392
1393         ASSERT(drvr_priv && ifidx && (ifidx < BRCMF_MAX_IFS));
1394         ifp = drvr_priv->iflist[ifidx];
1395         if (!ifp) {
1396                 DHD_ERROR(("%s: Null interface\n", __func__));
1397                 return;
1398         }
1399
1400         ifp->state = BRCMF_E_IF_DEL;
1401         ifp->idx = ifidx;
1402         ASSERT(drvr_priv->sysioc_tsk);
1403         up(&drvr_priv->sysioc_sem);
1404 }
1405
1406 struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
1407 {
1408         struct brcmf_info *drvr_priv = NULL;
1409         struct net_device *net;
1410
1411         DHD_TRACE(("%s: Enter\n", __func__));
1412
1413         /* Allocate etherdev, including space for private structure */
1414         net = alloc_etherdev(sizeof(drvr_priv));
1415         if (!net) {
1416                 DHD_ERROR(("%s: OOM - alloc_etherdev\n", __func__));
1417                 goto fail;
1418         }
1419
1420         /* Allocate primary brcmf_info */
1421         drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
1422         if (!drvr_priv) {
1423                 DHD_ERROR(("%s: OOM - alloc dhd_info\n", __func__));
1424                 goto fail;
1425         }
1426
1427         /*
1428          * Save the brcmf_info into the priv
1429          */
1430         memcpy(netdev_priv(net), &drvr_priv, sizeof(drvr_priv));
1431
1432         /* Set network interface name if it was provided as module parameter */
1433         if (iface_name[0]) {
1434                 int len;
1435                 char ch;
1436                 strncpy(net->name, iface_name, IFNAMSIZ);
1437                 net->name[IFNAMSIZ - 1] = 0;
1438                 len = strlen(net->name);
1439                 ch = net->name[len - 1];
1440                 if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
1441                         strcat(net->name, "%d");
1442         }
1443
1444         if (brcmf_add_if(drvr_priv, 0, (void *)net, net->name, NULL, 0, 0) ==
1445             BRCMF_BAD_IF)
1446                 goto fail;
1447
1448         net->netdev_ops = NULL;
1449         sema_init(&drvr_priv->proto_sem, 1);
1450         /* Initialize other structure content */
1451         init_waitqueue_head(&drvr_priv->ioctl_resp_wait);
1452
1453         /* Link to info module */
1454         drvr_priv->pub.info = drvr_priv;
1455
1456         /* Link to bus module */
1457         drvr_priv->pub.bus = bus;
1458         drvr_priv->pub.hdrlen = bus_hdrlen;
1459
1460         /* Attach and link in the protocol */
1461         if (brcmf_proto_attach(&drvr_priv->pub) != 0) {
1462                 DHD_ERROR(("dhd_prot_attach failed\n"));
1463                 goto fail;
1464         }
1465
1466         /* Attach and link in the cfg80211 */
1467         if (unlikely(wl_cfg80211_attach(net, &drvr_priv->pub))) {
1468                 DHD_ERROR(("wl_cfg80211_attach failed\n"));
1469                 goto fail;
1470         }
1471
1472         if (brcmf_sysioc) {
1473                 sema_init(&drvr_priv->sysioc_sem, 0);
1474                 drvr_priv->sysioc_tsk = kthread_run(_brcmf_sysioc_thread, drvr_priv,
1475                                                 "_dhd_sysioc");
1476                 if (IS_ERR(drvr_priv->sysioc_tsk)) {
1477                         printk(KERN_WARNING
1478                                 "_dhd_sysioc thread failed to start\n");
1479                         drvr_priv->sysioc_tsk = NULL;
1480                 }
1481         } else
1482                 drvr_priv->sysioc_tsk = NULL;
1483
1484         /*
1485          * Save the brcmf_info into the priv
1486          */
1487         memcpy(netdev_priv(net), &drvr_priv, sizeof(drvr_priv));
1488
1489 #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
1490         g_bus = bus;
1491 #endif
1492 #if defined(CONFIG_PM_SLEEP)
1493         atomic_set(&brcmf_mmc_suspend, false);
1494 #endif  /* defined(CONFIG_PM_SLEEP) */
1495         /* && defined(DHD_GPL) */
1496         /* Init lock suspend to prevent kernel going to suspend */
1497 #ifdef CONFIG_HAS_EARLYSUSPEND
1498         drvr_priv->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
1499         drvr_priv->early_suspend.suspend = brcmf_early_suspend;
1500         drvr_priv->early_suspend.resume = brcmf_late_resume;
1501         register_early_suspend(&drvr_priv->early_suspend);
1502 #endif
1503
1504         return &drvr_priv->pub;
1505
1506 fail:
1507         if (net)
1508                 free_netdev(net);
1509         if (drvr_priv)
1510                 brcmf_detach(&drvr_priv->pub);
1511
1512         return NULL;
1513 }
1514
1515 int brcmf_bus_start(struct brcmf_pub *drvr)
1516 {
1517         int ret = -1;
1518         struct brcmf_info *drvr_priv = drvr->info;
1519         /* Room for "event_msgs" + '\0' + bitvec */
1520         char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
1521
1522         ASSERT(drvr_priv);
1523
1524         DHD_TRACE(("%s:\n", __func__));
1525
1526         /* Bring up the bus */
1527         ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub, true);
1528         if (ret != 0) {
1529                 DHD_ERROR(("%s, brcmf_sdbrcm_bus_init failed %d\n", __func__,
1530                            ret));
1531                 return ret;
1532         }
1533
1534         /* If bus is not ready, can't come up */
1535         if (drvr_priv->pub.busstate != DHD_BUS_DATA) {
1536                 DHD_ERROR(("%s failed bus is not ready\n", __func__));
1537                 return -ENODEV;
1538         }
1539
1540         brcmu_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
1541                       iovbuf, sizeof(iovbuf));
1542         brcmf_proto_cdc_query_ioctl(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
1543                                     sizeof(iovbuf));
1544         memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
1545
1546         setbit(drvr->eventmask, BRCMF_E_SET_SSID);
1547         setbit(drvr->eventmask, BRCMF_E_PRUNE);
1548         setbit(drvr->eventmask, BRCMF_E_AUTH);
1549         setbit(drvr->eventmask, BRCMF_E_REASSOC);
1550         setbit(drvr->eventmask, BRCMF_E_REASSOC_IND);
1551         setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND);
1552         setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND);
1553         setbit(drvr->eventmask, BRCMF_E_DISASSOC);
1554         setbit(drvr->eventmask, BRCMF_E_JOIN);
1555         setbit(drvr->eventmask, BRCMF_E_ASSOC_IND);
1556         setbit(drvr->eventmask, BRCMF_E_PSK_SUP);
1557         setbit(drvr->eventmask, BRCMF_E_LINK);
1558         setbit(drvr->eventmask, BRCMF_E_NDIS_LINK);
1559         setbit(drvr->eventmask, BRCMF_E_MIC_ERROR);
1560         setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE);
1561         setbit(drvr->eventmask, BRCMF_E_TXFAIL);
1562         setbit(drvr->eventmask, BRCMF_E_JOIN_START);
1563         setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE);
1564
1565 /* enable dongle roaming event */
1566
1567         drvr->pktfilter_count = 1;
1568         /* Setup filter to allow only unicast */
1569         drvr->pktfilter[0] = "100 0 0 0 0x01 0x00";
1570
1571         /* Bus is ready, do any protocol initialization */
1572         ret = brcmf_proto_init(&drvr_priv->pub);
1573         if (ret < 0)
1574                 return ret;
1575
1576         return 0;
1577 }
1578
1579 static struct net_device_ops brcmf_netdev_ops_pri = {
1580         .ndo_open = brcmf_netdev_open,
1581         .ndo_stop = brcmf_netdev_stop,
1582         .ndo_get_stats = brcmf_netdev_get_stats,
1583         .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
1584         .ndo_start_xmit = brcmf_netdev_start_xmit,
1585         .ndo_set_mac_address = brcmf_netdev_set_mac_address,
1586         .ndo_set_multicast_list = brcmf_netdev_set_multicast_list
1587 };
1588
1589 int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
1590 {
1591         struct brcmf_info *drvr_priv = drvr->info;
1592         struct net_device *net;
1593         u8 temp_addr[ETH_ALEN] = {
1594                 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33};
1595
1596         DHD_TRACE(("%s: ifidx %d\n", __func__, ifidx));
1597
1598         ASSERT(drvr_priv && drvr_priv->iflist[ifidx]);
1599
1600         net = drvr_priv->iflist[ifidx]->net;
1601         ASSERT(net);
1602
1603         ASSERT(!net->netdev_ops);
1604         net->netdev_ops = &brcmf_netdev_ops_pri;
1605
1606         /*
1607          * We have to use the primary MAC for virtual interfaces
1608          */
1609         if (ifidx != 0) {
1610                 /* for virtual interfaces use the primary MAC  */
1611                 memcpy(temp_addr, drvr_priv->pub.mac, ETH_ALEN);
1612
1613         }
1614
1615         if (ifidx == 1) {
1616                 DHD_TRACE(("%s ACCESS POINT MAC:\n", __func__));
1617                 /*  ACCESSPOINT INTERFACE CASE */
1618                 temp_addr[0] |= 0X02;   /* set bit 2 ,
1619                          - Locally Administered address  */
1620
1621         }
1622         net->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen;
1623         net->ethtool_ops = &brcmf_ethtool_ops;
1624
1625         drvr_priv->pub.rxsz = net->mtu + net->hard_header_len +
1626                                 drvr_priv->pub.hdrlen;
1627
1628         memcpy(net->dev_addr, temp_addr, ETH_ALEN);
1629
1630         if (register_netdev(net) != 0) {
1631                 DHD_ERROR(("%s: couldn't register the net device\n",
1632                         __func__));
1633                 goto fail;
1634         }
1635
1636         DHD_INFO(("%s: Broadcom Dongle Host Driver\n", net->name));
1637
1638         return 0;
1639
1640 fail:
1641         net->netdev_ops = NULL;
1642         return -EBADE;
1643 }
1644
1645 static void brcmf_bus_detach(struct brcmf_pub *drvr)
1646 {
1647         struct brcmf_info *drvr_priv;
1648
1649         DHD_TRACE(("%s: Enter\n", __func__));
1650
1651         if (drvr) {
1652                 drvr_priv = drvr->info;
1653                 if (drvr_priv) {
1654                         /* Stop the protocol module */
1655                         brcmf_proto_stop(&drvr_priv->pub);
1656
1657                         /* Stop the bus module */
1658                         brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus, true);
1659                 }
1660         }
1661 }
1662
1663 void brcmf_detach(struct brcmf_pub *drvr)
1664 {
1665         struct brcmf_info *drvr_priv;
1666
1667         DHD_TRACE(("%s: Enter\n", __func__));
1668
1669         if (drvr) {
1670                 drvr_priv = drvr->info;
1671                 if (drvr_priv) {
1672                         struct brcmf_if *ifp;
1673                         int i;
1674
1675 #if defined(CONFIG_HAS_EARLYSUSPEND)
1676                         if (drvr_priv->early_suspend.suspend)
1677                                 unregister_early_suspend(
1678                                         &drvr_priv->early_suspend);
1679 #endif                          /* defined(CONFIG_HAS_EARLYSUSPEND) */
1680
1681                         for (i = 1; i < BRCMF_MAX_IFS; i++)
1682                                 if (drvr_priv->iflist[i])
1683                                         brcmf_del_if(drvr_priv, i);
1684
1685                         ifp = drvr_priv->iflist[0];
1686                         ASSERT(ifp);
1687                         if (ifp->net->netdev_ops == &brcmf_netdev_ops_pri) {
1688                                 brcmf_netdev_stop(ifp->net);
1689                                 unregister_netdev(ifp->net);
1690                         }
1691
1692                         if (drvr_priv->sysioc_tsk) {
1693                                 send_sig(SIGTERM, drvr_priv->sysioc_tsk, 1);
1694                                 kthread_stop(drvr_priv->sysioc_tsk);
1695                                 drvr_priv->sysioc_tsk = NULL;
1696                         }
1697
1698                         brcmf_bus_detach(drvr);
1699
1700                         if (drvr->prot)
1701                                 brcmf_proto_detach(drvr);
1702
1703                         wl_cfg80211_detach();
1704
1705                         /* && defined(DHD_GPL) */
1706                         free_netdev(ifp->net);
1707                         kfree(ifp);
1708                         kfree(drvr_priv);
1709                 }
1710         }
1711 }
1712
1713 static void __exit brcmf_module_cleanup(void)
1714 {
1715         DHD_TRACE(("%s: Enter\n", __func__));
1716
1717         brcmf_bus_unregister();
1718 }
1719
1720 static int __init brcmf_module_init(void)
1721 {
1722         int error;
1723
1724         DHD_TRACE(("%s: Enter\n", __func__));
1725
1726         error = brcmf_bus_register();
1727
1728         if (error) {
1729                 DHD_ERROR(("%s: dhd_bus_register failed\n", __func__));
1730                 goto failed;
1731         }
1732         return 0;
1733
1734 failed:
1735         return -EINVAL;
1736 }
1737
1738 module_init(brcmf_module_init);
1739 module_exit(brcmf_module_cleanup);
1740
1741 /*
1742  * OS specific functions required to implement DHD driver in OS independent way
1743  */
1744 int brcmf_os_proto_block(struct brcmf_pub *drvr)
1745 {
1746         struct brcmf_info *drvr_priv = drvr->info;
1747
1748         if (drvr_priv) {
1749                 down(&drvr_priv->proto_sem);
1750                 return 1;
1751         }
1752         return 0;
1753 }
1754
1755 int brcmf_os_proto_unblock(struct brcmf_pub *drvr)
1756 {
1757         struct brcmf_info *drvr_priv = drvr->info;
1758
1759         if (drvr_priv) {
1760                 up(&drvr_priv->proto_sem);
1761                 return 1;
1762         }
1763
1764         return 0;
1765 }
1766
1767 unsigned int brcmf_os_get_ioctl_resp_timeout(void)
1768 {
1769         return (unsigned int)brcmf_ioctl_timeout_msec;
1770 }
1771
1772 void brcmf_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
1773 {
1774         brcmf_ioctl_timeout_msec = (int)timeout_msec;
1775 }
1776
1777 int brcmf_os_ioctl_resp_wait(struct brcmf_pub *drvr, uint *condition,
1778                              bool *pending)
1779 {
1780         struct brcmf_info *drvr_priv = drvr->info;
1781         DECLARE_WAITQUEUE(wait, current);
1782         int timeout = brcmf_ioctl_timeout_msec;
1783
1784         /* Convert timeout in millsecond to jiffies */
1785         timeout = timeout * HZ / 1000;
1786
1787         /* Wait until control frame is available */
1788         add_wait_queue(&drvr_priv->ioctl_resp_wait, &wait);
1789         set_current_state(TASK_INTERRUPTIBLE);
1790
1791         while (!(*condition) && (!signal_pending(current) && timeout))
1792                 timeout = schedule_timeout(timeout);
1793
1794         if (signal_pending(current))
1795                 *pending = true;
1796
1797         set_current_state(TASK_RUNNING);
1798         remove_wait_queue(&drvr_priv->ioctl_resp_wait, &wait);
1799
1800         return timeout;
1801 }
1802
1803 int brcmf_os_ioctl_resp_wake(struct brcmf_pub *drvr)
1804 {
1805         struct brcmf_info *drvr_priv = drvr->info;
1806
1807         if (waitqueue_active(&drvr_priv->ioctl_resp_wait))
1808                 wake_up_interruptible(&drvr_priv->ioctl_resp_wait);
1809
1810         return 0;
1811 }
1812
1813 static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
1814                             struct brcmf_event_msg *event, void **data)
1815 {
1816         int bcmerror = 0;
1817
1818         ASSERT(drvr_priv != NULL);
1819
1820         bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data);
1821         if (bcmerror != 0)
1822                 return bcmerror;
1823
1824         ASSERT(drvr_priv->iflist[*ifidx] != NULL);
1825         ASSERT(drvr_priv->iflist[*ifidx]->net != NULL);
1826         if (drvr_priv->iflist[*ifidx]->net)
1827                 wl_cfg80211_event(drvr_priv->iflist[*ifidx]->net, event, *data);
1828
1829         return bcmerror;
1830 }
1831
1832 int brcmf_netdev_reset(struct net_device *dev, u8 flag)
1833 {
1834         struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(dev);
1835
1836         brcmf_bus_devreset(&drvr_priv->pub, flag);
1837
1838         return 1;
1839 }
1840
1841 static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
1842 {
1843         return atomic_read(&drvr_priv->pend_8021x_cnt);
1844 }
1845
1846 #define MAX_WAIT_FOR_8021X_TX   10
1847
1848 int brcmf_netdev_wait_pend8021x(struct net_device *dev)
1849 {
1850         struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(dev);
1851         int timeout = 10 * HZ / 1000;
1852         int ntimes = MAX_WAIT_FOR_8021X_TX;
1853         int pend = brcmf_get_pend_8021x_cnt(drvr_priv);
1854
1855         while (ntimes && pend) {
1856                 if (pend) {
1857                         set_current_state(TASK_INTERRUPTIBLE);
1858                         schedule_timeout(timeout);
1859                         set_current_state(TASK_RUNNING);
1860                         ntimes--;
1861                 }
1862                 pend = brcmf_get_pend_8021x_cnt(drvr_priv);
1863         }
1864         return pend;
1865 }
1866
1867 #ifdef BCMDBG
1868 int brcmf_write_to_file(struct brcmf_pub *drvr, u8 *buf, int size)
1869 {
1870         int ret = 0;
1871         struct file *fp;
1872         mm_segment_t old_fs;
1873         loff_t pos = 0;
1874
1875         /* change to KERNEL_DS address limit */
1876         old_fs = get_fs();
1877         set_fs(KERNEL_DS);
1878
1879         /* open file to write */
1880         fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640);
1881         if (!fp) {
1882                 DHD_ERROR(("%s: open file error\n", __func__));
1883                 ret = -1;
1884                 goto exit;
1885         }
1886
1887         /* Write buf to file */
1888         fp->f_op->write(fp, buf, size, &pos);
1889
1890 exit:
1891         /* free buf before return */
1892         kfree(buf);
1893         /* close file before return */
1894         if (fp)
1895                 filp_close(fp, current->files);
1896         /* restore previous address limit */
1897         set_fs(old_fs);
1898
1899         return ret;
1900 }
1901 #endif                          /* BCMDBG */
1902
1903 #if defined(BCMDBG)
1904 void osl_assert(char *exp, char *file, int line)
1905 {
1906         char tempbuf[256];
1907         char *basename;
1908
1909         basename = strrchr(file, '/');
1910         /* skip the '/' */
1911         if (basename)
1912                 basename++;
1913
1914         if (!basename)
1915                 basename = file;
1916
1917         snprintf(tempbuf, 256,
1918                  "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
1919                  basename, line);
1920
1921         /*
1922          * Print assert message and give it time to
1923          * be written to /var/log/messages
1924          */
1925         if (!in_interrupt()) {
1926                 const int delay = 3;
1927                 printk(KERN_ERR "%s", tempbuf);
1928                 printk(KERN_ERR "panic in %d seconds\n", delay);
1929                 set_current_state(TASK_INTERRUPTIBLE);
1930                 schedule_timeout(delay * HZ);
1931         }
1932
1933         switch (g_assert_type) {
1934         case 0:
1935                 panic(KERN_ERR "%s", tempbuf);
1936                 break;
1937         case 1:
1938                 printk(KERN_ERR "%s", tempbuf);
1939                 BUG();
1940                 break;
1941         case 2:
1942                 printk(KERN_ERR "%s", tempbuf);
1943                 break;
1944         default:
1945                 break;
1946         }
1947 }
1948 #endif                          /* defined(BCMDBG) */