upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / net / wireless / bcm4330 / src / dhd / sys / dhd_cdc.c
1 /*
2  * DHD Protocol Module for CDC and BDC.
3  *
4  * Copyright (C) 1999-2011, Broadcom Corporation
5  * 
6  *         Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  * 
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  * 
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  * $Id: dhd_cdc.c,v 1.51.6.28.4.1 2011-02-01 19:36:23 $
25  *
26  * BDC is like CDC, except it includes a header for data packets to convey
27  * packet priority over the bus, and flags (e.g. to indicate checksum status
28  * for dongle offload.)
29  */
30
31 #include <typedefs.h>
32 #include <osl.h>
33
34 #include <bcmutils.h>
35 #include <bcmcdc.h>
36 #include <bcmendian.h>
37
38 #include <dngl_stats.h>
39 #include <dhd.h>
40 #include <dhd_proto.h>
41 #include <dhd_bus.h>
42 #include <dhd_dbg.h>
43
44
45
46 /* Packet alignment for most efficient SDIO (can change based on platform) */
47 #ifndef DHD_SDALIGN
48 #define DHD_SDALIGN     32
49 #endif
50 #if !ISPOWEROF2(DHD_SDALIGN)
51 #error DHD_SDALIGN is not a power of 2!
52 #endif
53
54 #define RETRIES 2               /* # of retries to retrieve matching ioctl response */
55 #define BUS_HEADER_LEN  (16+DHD_SDALIGN)        /* Must be at least SDPCM_RESERVE
56                                  * defined in dhd_sdio.c (amount of header tha might be added)
57                                  * plus any space that might be needed for alignment padding.
58                                  */
59 #define ROUND_UP_MARGIN 2048    /* Biggest SDIO block size possible for
60                                  * round off at the end of buffer
61                                  */
62
63 typedef struct dhd_prot {
64         uint16 reqid;
65         uint8 pending;
66         uint32 lastcmd;
67         uint8 bus_header[BUS_HEADER_LEN];
68         cdc_ioctl_t msg;
69         unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
70 } dhd_prot_t;
71
72 static int
73 dhdcdc_msg(dhd_pub_t *dhd)
74 {
75         int err = 0;
76         dhd_prot_t *prot = dhd->prot;
77         int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
78
79         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
80
81         DHD_OS_WAKE_LOCK(dhd);
82
83         /* NOTE : cdc->msg.len holds the desired length of the buffer to be
84          *        returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
85          *        is actually sent to the dongle
86          */
87         if (len > CDC_MAX_MSG_SIZE)
88                 len = CDC_MAX_MSG_SIZE;
89
90         /* Send request */
91         err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
92
93         DHD_OS_WAKE_UNLOCK(dhd);
94         return err;
95 }
96
97 static int
98 dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
99 {
100         int ret;
101         int cdc_len = len+sizeof(cdc_ioctl_t);
102         dhd_prot_t *prot = dhd->prot;
103
104         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
105
106         do {
107                 ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
108                 if (ret < 0)
109                         break;
110         } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
111
112         return ret;
113 }
114
115 static int
116 dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
117 {
118         dhd_prot_t *prot = dhd->prot;
119         cdc_ioctl_t *msg = &prot->msg;
120         void *info;
121         int ret = 0, retries = 0;
122         uint32 id, flags = 0;
123
124         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
125         DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
126
127
128         /* Respond "bcmerror" and "bcmerrorstr" with local cache */
129         if (cmd == WLC_GET_VAR && buf)
130         {
131                 if (!strcmp((char *)buf, "bcmerrorstr"))
132                 {
133                         strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN);
134                         goto done;
135                 }
136                 else if (!strcmp((char *)buf, "bcmerror"))
137                 {
138                         *(int *)buf = dhd->dongle_error;
139                         goto done;
140                 }
141         }
142
143         memset(msg, 0, sizeof(cdc_ioctl_t));
144
145 #ifdef BCMSPI
146         /* 11bit gSPI bus allows 2048bytes of max-data.  We restrict 'len'
147          * value which is 8Kbytes for various 'get' commands to 2000.  48 bytes are
148          * left for sw headers and misc.
149          */
150         len = (len > 2000) ? 2000 : len;
151 #endif /* BCMSPI */
152         msg->cmd = htol32(cmd);
153         msg->len = htol32(len);
154         msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
155         CDC_SET_IF_IDX(msg, ifidx);
156         /* add additional action bits */
157         action &= WL_IOCTL_ACTION_MASK;
158         msg->flags |= (action << CDCF_IOC_ACTION_SHIFT);
159         msg->flags = htol32(msg->flags);
160
161         if (buf)
162                 memcpy((void *)(&msg[1]), buf, len);
163
164         if ((ret = dhdcdc_msg(dhd)) < 0) {
165                 DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
166                 goto done;
167         }
168
169 retry:
170         /* wait for interrupt and get first fragment */
171         if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
172                 goto done;
173
174         flags = ltoh32(msg->flags);
175         id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
176
177         if ((id < prot->reqid) && (++retries < RETRIES))
178                 goto retry;
179         if (id != prot->reqid) {
180                 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
181                            dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
182                 ret = -EINVAL;
183                 goto done;
184         }
185
186         /* Check info buffer */
187         info = (void*)&msg[1];
188
189         /* Copy info buffer */
190         if (buf)
191         {
192                 if (ret < (int)len)
193                         len = ret;
194                 memcpy(buf, info, len);
195         }
196
197         /* Check the ERROR flag */
198         if (flags & CDCF_IOC_ERROR)
199         {
200                 ret = ltoh32(msg->status);
201                 /* Cache error from dongle */
202                 dhd->dongle_error = ret;
203         }
204
205 done:
206         return ret;
207 }
208
209 static int
210 dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
211 {
212         dhd_prot_t *prot = dhd->prot;
213         cdc_ioctl_t *msg = &prot->msg;
214         int ret = 0;
215         uint32 flags, id;
216
217         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
218         DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
219
220         memset(msg, 0, sizeof(cdc_ioctl_t));
221
222         msg->cmd = htol32(cmd);
223         msg->len = htol32(len);
224         msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
225         CDC_SET_IF_IDX(msg, ifidx);
226         /* add additional action bits */
227         action &= WL_IOCTL_ACTION_MASK;
228         msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET;
229         msg->flags = htol32(msg->flags);
230
231         if (buf)
232                 memcpy((void *)(&msg[1]), buf, len);
233
234         if ((ret = dhdcdc_msg(dhd)) < 0) {
235                 DHD_ERROR(("dhdcdc_set_ioctl: dhdcdc_msg failed w/status %d\n", ret));
236                 goto done;
237         }
238
239         if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
240                 goto done;
241
242         flags = ltoh32(msg->flags);
243         id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
244
245         if (id != prot->reqid) {
246                 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
247                            dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
248                 ret = -EINVAL;
249                 goto done;
250         }
251
252         /* Check the ERROR flag */
253         if (flags & CDCF_IOC_ERROR)
254         {
255                 ret = ltoh32(msg->status);
256                 /* Cache error from dongle */
257                 dhd->dongle_error = ret;
258         }
259
260 done:
261         return ret;
262 }
263
264
265 int
266 dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
267 {
268         dhd_prot_t *prot = dhd->prot;
269         int ret = -1;
270         uint8 action;
271
272         if (dhd->busstate == DHD_BUS_DOWN) {
273                 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
274                 goto done;
275         }
276
277         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
278
279         ASSERT(len <= WLC_IOCTL_MAXLEN);
280
281         if (len > WLC_IOCTL_MAXLEN)
282                 goto done;
283
284         if (prot->pending == TRUE) {
285                 DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
286                         ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
287                         (unsigned long)prot->lastcmd));
288                 if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) {
289                         DHD_TRACE(("iovar cmd=%s\n", (char*)buf));
290                 }
291                 goto done;
292         }
293
294         prot->pending = TRUE;
295         prot->lastcmd = ioc->cmd;
296         action = ioc->set;
297         if (action & WL_IOCTL_ACTION_SET)
298                 ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
299         else {
300                 ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
301                 if (ret > 0)
302                         ioc->used = ret - sizeof(cdc_ioctl_t);
303         }
304
305         /* Too many programs assume ioctl() returns 0 on success */
306         if (ret >= 0)
307                 ret = 0;
308         else {
309                 cdc_ioctl_t *msg = &prot->msg;
310                 ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */
311         }
312
313         /* Intercept the wme_dp ioctl here */
314         if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) {
315                 int slen, val = 0;
316
317                 slen = strlen("wme_dp") + 1;
318                 if (len >= (int)(slen + sizeof(int)))
319                         bcopy(((char *)buf + slen), &val, sizeof(int));
320                 dhd->wme_dp = (uint8) ltoh32(val);
321         }
322
323         prot->pending = FALSE;
324
325 done:
326         return ret;
327 }
328
329 int
330 dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
331                   void *params, int plen, void *arg, int len, bool set)
332 {
333         return BCME_UNSUPPORTED;
334 }
335
336
337 void
338 dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
339 {
340         bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
341 }
342
343 void
344 dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
345 {
346 #ifdef BDC
347         struct bdc_header *h;
348 #endif /* BDC */
349
350         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
351
352 #ifdef BDC
353         /* Push BDC header used to convey priority for buses that don't */
354
355         PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN);
356
357         h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
358
359         h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
360         if (PKTSUMNEEDED(pktbuf))
361                 h->flags |= BDC_FLAG_SUM_NEEDED;
362
363
364         h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK);
365         h->flags2 = 0;
366         h->dataOffset = 0;
367 #endif /* BDC */
368         BDC_SET_IF_IDX(h, ifidx);
369 }
370
371 int
372 dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
373 {
374 #ifdef BDC
375         struct bdc_header *h;
376 #endif
377
378         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
379
380 #ifdef BDC
381         /* Pop BDC header used to convey priority for buses that don't */
382
383         if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
384                 DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
385                            PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
386                 return BCME_ERROR;
387         }
388
389         h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
390
391         if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) {
392                 DHD_ERROR(("%s: rx data ifnum out of range (%d)\n",
393                            __FUNCTION__, *ifidx));
394                 return BCME_ERROR;
395         }
396
397         if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) {
398                 DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n",
399                            dhd_ifname(dhd, *ifidx), h->flags));
400                 if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1)
401                         h->dataOffset = 0;
402                 else
403                         return BCME_ERROR;
404         }
405
406         if (h->flags & BDC_FLAG_SUM_GOOD) {
407                 DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n",
408                           dhd_ifname(dhd, *ifidx), h->flags));
409                 PKTSETSUMGOOD(pktbuf, TRUE);
410         }
411
412         PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK));
413         PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
414 #endif /* BDC */
415
416         if (PKTLEN(dhd->osh, pktbuf) < (uint32) (h->dataOffset << 2)) {
417                 DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
418                            PKTLEN(dhd->osh, pktbuf), (h->dataOffset * 4)));
419                 return BCME_ERROR;
420         }
421
422         PKTPULL(dhd->osh, pktbuf, (h->dataOffset << 2));
423         return 0;
424 }
425
426 int
427 dhd_prot_attach(dhd_pub_t *dhd)
428 {
429         dhd_prot_t *cdc;
430
431 #ifndef DHD_USE_STATIC_BUF
432         if (!(cdc = (dhd_prot_t *)MALLOC(dhd->osh, sizeof(dhd_prot_t)))) {
433                 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
434                 goto fail;
435         }
436 #else
437         if (!(cdc = (dhd_prot_t *)dhd_os_prealloc(DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) {
438                 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
439                 goto fail;
440         }
441 #endif /* DHD_USE_STATIC_BUF */
442         memset(cdc, 0, sizeof(dhd_prot_t));
443
444         /* ensure that the msg buf directly follows the cdc msg struct */
445         if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) {
446                 DHD_ERROR(("dhd_prot_t is not correctly defined\n"));
447                 goto fail;
448         }
449
450         dhd->prot = cdc;
451 #ifdef BDC
452         dhd->hdrlen += BDC_HEADER_LEN;
453 #endif
454         dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN;
455         return 0;
456
457 fail:
458 #ifndef DHD_USE_STATIC_BUF
459         if (cdc != NULL)
460                 MFREE(dhd->osh, cdc, sizeof(dhd_prot_t));
461 #endif
462         return BCME_NOMEM;
463 }
464
465 /* ~NOTE~ What if another thread is waiting on the semaphore?  Holding it? */
466 void
467 dhd_prot_detach(dhd_pub_t *dhd)
468 {
469 #ifndef DHD_USE_STATIC_BUF
470         MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
471 #endif
472         dhd->prot = NULL;
473 }
474
475 void
476 dhd_prot_dstats(dhd_pub_t *dhd)
477 {
478         /* No stats from dongle added yet, copy bus stats */
479         dhd->dstats.tx_packets = dhd->tx_packets;
480         dhd->dstats.tx_errors = dhd->tx_errors;
481         dhd->dstats.rx_packets = dhd->rx_packets;
482         dhd->dstats.rx_errors = dhd->rx_errors;
483         dhd->dstats.rx_dropped = dhd->rx_dropped;
484         dhd->dstats.multicast = dhd->rx_multicast;
485         return;
486 }
487
488 int dhd_set_suspend(int value, dhd_pub_t *dhd)
489 {
490         int power_mode = PM_MAX;
491         wl_pkt_filter_enable_t  enable_parm;
492         char iovbuf[32];
493         int bcn_li_dtim = 3;
494 #ifdef CUSTOMER_HW2
495         uint roamvar = 1;
496 #endif /* CUSTOMER_HW2 */
497
498 #define htod32(i) i
499
500         if (dhd && dhd->up) {
501                 if (value) {
502                         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM,
503                                 (char *)&power_mode, sizeof(power_mode), TRUE, 0);
504                         /* Enable packet filter, only allow unicast packet to send up */
505                         enable_parm.id = htod32(100);
506                         enable_parm.enable = htod32(1);
507                         bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm,
508                                 sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf));
509                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
510                         /* set bcn_li_dtim */
511                         bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
512                                 4, iovbuf, sizeof(iovbuf));
513                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
514 #ifdef CUSTOMER_HW2
515                         /* Disable build-in roaming to allowed ext supplicant to take of romaing */
516                         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
517                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
518 #endif /* CUSTOMER_HW2 */
519                 } else {
520                         power_mode = PM_FAST;
521                         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
522                                 sizeof(power_mode), TRUE, 0);
523                         /* disable pkt filter */
524                         enable_parm.id = htod32(100);
525                         enable_parm.enable = htod32(0);
526                         bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm,
527                                 sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf));
528                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
529                         /* set bcn_li_dtim */
530                         bcn_li_dtim = 0;
531                         bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
532                                 4, iovbuf, sizeof(iovbuf));
533                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
534 #ifdef CUSTOMER_HW2
535                         roamvar = 0;
536                         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
537                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
538 #endif /* CUSTOMER_HW2 */
539                 }
540         }
541
542         return 0;
543 }
544
545 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
546
547 extern void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode);
548 extern void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable);
549 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
550 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
551
552 int
553 dhd_preinit_ioctls(dhd_pub_t *dhd)
554 {
555         int ret = 0;
556         char eventmask[WL_EVENTING_MASK_LEN];
557         char iovbuf[WL_EVENTING_MASK_LEN + 12]; /*  Room for "event_msgs" + '\0' + bitvec  */
558         int up = 1;
559         int power_mode = PM_FAST;
560         int dongle_align = DHD_SDALIGN;
561         int glom = 0;
562         int bcn_timeout = 3;
563         int dhd_roam = 1;
564         int scan_assoc_time = 40;
565         int scan_unassoc_time = 80;
566         char buf[256] = {0};
567 #ifdef GET_CUSTOM_MAC_ENABLE
568         struct ether_addr ea_addr;
569 #endif /* GET_CUSTOM_MAC_ENABLE */
570 #ifdef USE_WIFI_DIRECT
571         int apsta = 1;
572 #endif
573         static int isup = 0;
574
575         if (!isup) {
576            /* query for 'ver' to get version info from firmware */
577            strcpy(buf, "ver");
578            if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) {
579                   DHD_ERROR(("%s: can't get F/W version , error=%d\n", __FUNCTION__, ret));
580                   return BCME_NOTUP;
581            }
582            /* Print fw version info */
583            DHD_ERROR(("Firmware version = %s\n", buf));
584
585            /* Get the device MAC address */
586            strcpy(iovbuf, "cur_etheraddr");
587            if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
588                   DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
589                   return BCME_NOTUP;
590            }
591            memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
592
593            /* Set Country code */
594            if (dhd->country_code[0] != 0) {
595                   if (dhd_wl_ioctl_cmd(dhd, WLC_SET_COUNTRY,
596                                    dhd->country_code, sizeof(dhd->country_code), TRUE, 0) < 0) {
597                          DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
598                   }
599            }
600
601            /* Set PowerSave mode */
602            ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
603
604            /* Match Host and Dongle rx alignment */
605            bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
606            ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
607
608            /* disable glom option per default */
609            bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
610            ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
611
612            /* Setup timeout if Beacons are lost and roam is off to report link down */
613            bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
614            ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
615
616            /* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */
617            bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf));
618            ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
619
620 #ifdef USE_WIFI_DIRECT
621                    /* Enable APSTA mode */
622                 bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
623                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
624 #endif
625
626
627            /* Force STA UP */
628            //   if (dhd_radio_up)
629            ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
630            if (ret < 0)
631                   goto done;
632            isup = 1;
633
634         /* Setup event_msgs */
635         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
636         dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
637         if (ret < 0)
638                 goto done;
639         bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
640
641         /* Setup event_msgs */
642         setbit(eventmask, WLC_E_SET_SSID);
643         setbit(eventmask, WLC_E_PRUNE);
644         setbit(eventmask, WLC_E_AUTH);
645         setbit(eventmask, WLC_E_REASSOC);
646         setbit(eventmask, WLC_E_REASSOC_IND);
647         setbit(eventmask, WLC_E_DEAUTH_IND);
648         setbit(eventmask, WLC_E_DISASSOC_IND);
649         setbit(eventmask, WLC_E_DISASSOC);
650         setbit(eventmask, WLC_E_JOIN);
651         setbit(eventmask, WLC_E_ASSOC_IND);
652         setbit(eventmask, WLC_E_PSK_SUP);
653         setbit(eventmask, WLC_E_LINK);
654         setbit(eventmask, WLC_E_NDIS_LINK);
655         setbit(eventmask, WLC_E_MIC_ERROR);
656         setbit(eventmask, WLC_E_PMKID_CACHE);
657         setbit(eventmask, WLC_E_TXFAIL);
658         setbit(eventmask, WLC_E_JOIN_START);
659         setbit(eventmask, WLC_E_SCAN_COMPLETE);
660 #ifdef WLMEDIA_HTSF
661         setbit(eventmask, WLC_E_HTSFSYNC);
662 #endif
663 #ifdef PNO_SUPPORT
664         setbit(eventmask, WLC_E_PFN_NET_FOUND);
665         setbit(eventmask, WLC_E_PFN_NET_LOST);
666 #endif
667         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
668         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
669
670
671            dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, sizeof(scan_assoc_time), TRUE, 0);
672            dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, sizeof(scan_unassoc_time), TRUE, 0);
673
674 #ifdef ARP_OFFLOAD_SUPPORT
675            /* Set and enable ARP offload feature */
676            if (dhd_arp_enable)
677                   dhd_arp_offload_set(dhd, dhd_arp_mode);
678            dhd_arp_offload_enable(dhd, dhd_arp_enable);
679 #endif /* ARP_OFFLOAD_SUPPORT */
680
681 #ifdef PKT_FILTER_SUPPORT
682            {
683                   int i;
684                   /* Set up pkt filter */
685                   if (dhd_pkt_filter_enable) {
686                          for (i = 0; i < dhd->pktfilter_count; i++) {
687                                 dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
688                                 dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
689                                           dhd_pkt_filter_init, dhd_master_mode);
690                          }
691                   }
692            }
693 #endif /* PKT_FILTER_SUPPORT */
694         }
695 done:
696         return ret;
697 }
698 #ifdef ENABLE_DEEP_SLEEP
699 static dhd_pub_t *dhdpub = NULL;
700 extern void dhd_os_deepsleep_block(void);       /* dhd_linux.c */
701 extern void dhd_os_deepsleep_unblock(void);     /* dhd_linux.c */
702 extern void dhd_os_deepsleep_wait(void);        /* dhd_linux.c */
703
704 #define MAX_TRY_CNT 5
705
706 int dhd_deepsleep(int flag)
707 {
708         char iovbuf[20];
709         uint powervar = 0;
710         int cnt = 0;
711         int ret = 0;
712
713         DHD_ERROR(("[WIFI] %s: Enter.. Flag-> %d \n", __FUNCTION__, flag));
714
715         switch (flag) {
716         case 1 :  /* Deepsleep on */
717                 dhd_os_deepsleep_wait();
718                 printk(KERN_INFO "[WIFI] Deep Sleep ON\n");
719
720                 /* Disable MPC */
721                 powervar = 0;
722                 bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
723                 dhd_wl_ioctl_cmd(dhdpub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
724
725                 /* Enable Deepsleep*/
726                 powervar = 1;
727                 bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
728                 dhd_wl_ioctl_cmd(dhdpub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
729                 break;
730
731         case 0: /* Deepsleep Off */
732                 printk(KERN_INFO "[WIFI] Deep Sleep OFF\n");
733                 dhd_os_deepsleep_block();
734                 /* Disable Deepsleep */
735                 for (cnt = 0; cnt < MAX_TRY_CNT; cnt++) {
736                         powervar = 0;
737                         bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
738                         /* Waiting to settle down after resume. */
739                         msleep(100);
740                         dhd_wl_ioctl_cmd(dhdpub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
741                         memset(iovbuf,0,sizeof(iovbuf));
742                         strcpy(iovbuf, "deepsleep");
743                         ret = dhd_wl_ioctl_cmd(dhdpub, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
744                         if (ret < 0 ) {
745                                 DHD_ERROR(("the error of dhd deepsleep status ret value : %d\n",ret));
746                         } else {
747                                 int status = *(int *)iovbuf;
748                                 if (!status) {
749                                         DHD_ERROR(("deepsleep mode is 0, ok , count : %d\n",cnt));
750                                         break;
751                                 }
752                         }
753                 }
754
755                 /* Enable MPC */
756                 powervar = 1;
757                 memset(iovbuf,0,sizeof(iovbuf));
758                 bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
759                 dhd_wl_ioctl_cmd(dhdpub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
760                 dhd_os_deepsleep_unblock();
761                 break;
762
763         default:
764                 printk("Faulty Input Arg to %s",__FUNCTION__);
765         }
766
767         return 0;
768 }
769 #endif /* ENABLE_DEEP_SLEEP */
770
771 int
772 dhd_prot_init(dhd_pub_t *dhd)
773 {
774         int ret = 0;
775         wlc_rev_info_t revinfo;
776         char buf[128];
777 #ifdef ENABLE_DEEP_SLEEP
778         if (dhd)
779                 dhdpub = dhd;
780 #endif
781         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
782
783         /* Get the device MAC address */
784         strcpy(buf, "cur_etheraddr");
785         ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0);
786         if (ret < 0)
787                 goto done;
788         memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
789
790         /* Get the device rev info */
791         memset(&revinfo, 0, sizeof(revinfo));
792         ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0);
793         if (ret < 0)
794                 goto done;
795
796
797         ret = dhd_preinit_ioctls(dhd);
798
799         /* Always assumes wl for now */
800         dhd->iswl = TRUE;
801
802         goto done;
803
804 done:
805         return ret;
806 }
807
808 void
809 dhd_prot_stop(dhd_pub_t *dhd)
810 {
811         /* Nothing to do for CDC */
812 }