• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file dbus.c
2  *
3  * Hides details of USB / SDIO / SPI interfaces and OS details. It is intended
4  * to shield details and provide the caller with one common bus interface for
5  * all dongle devices. In practice, it is only used for USB interfaces. DBUS is
6  * not a protocol, but an abstraction layer.
7  *
8  * Copyright (C) 1999-2016, Broadcom Corporation
9  *
10  *      Unless you and Broadcom execute a separate written software license
11  * agreement governing use of this software, this software is licensed to you
12  * under the terms of the GNU General Public License version 2 (the "GPL"),
13  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
14  * following added to such license:
15  *
16  *      As a special exception, the copyright holders of this software give you
17  * permission to link this software with independent modules, and to copy and
18  * distribute the resulting executable under terms of your choice, provided that
19  * you also meet, for each linked independent module, the terms and conditions
20  * of the license of that module.  An independent module is a module which is
21  * not derived from this software.  The special exception does not apply to any
22  * modifications of the software.
23  *
24  *      Notwithstanding the above, under no circumstances may you combine this
25  * software in any way with any other Broadcom software provided under a license
26  * other than the GPL, without Broadcom's express prior written consent.
27  *
28  *
29  * <<Broadcom-WL-IPTag/Open:>>
30  *
31  * $Id: dbus.c 553311 2015-04-29 10:23:08Z $
32  */
33 
34 #include "osl.h"
35 #include "dbus.h"
36 #include <bcmutils.h>
37 #include <dngl_stats.h>
38 #include <dhd.h>
39 #include <dhd_proto.h>
40 #ifdef PROP_TXSTATUS /* a form of flow control between host and dongle */
41 #include <dhd_wlfc.h>
42 #endif
43 #include <dhd_config.h>
44 
45 #if defined(BCM_REQUEST_FW)
46 #include <bcmsrom_fmt.h>
47 #include <trxhdr.h>
48 #include <usbrdl.h>
49 #include <bcmendian.h>
50 #include <sbpcmcia.h>
51 #include <bcmnvram.h>
52 #include <bcmdevs.h>
53 #endif
54 
55 #if defined(BCM_REQUEST_FW)
56 #ifndef VARS_MAX
57 #define VARS_MAX 8192
58 #endif
59 #endif
60 
61 #ifdef DBUS_USB_LOOPBACK
62 extern bool is_loopback_pkt(void *buf);
63 extern int matches_loopback_pkt(void *buf);
64 #endif
65 
66 /** General info for all BUS types */
67 typedef struct dbus_irbq {
68     dbus_irb_t *head;
69     dbus_irb_t *tail;
70     int cnt;
71 } dbus_irbq_t;
72 
73 /**
74  * This private structure dhd_bus_t is also declared in dbus_usb_linux.c.
75  * All the fields must be consistent in both declarations.
76  */
77 typedef struct dhd_bus {
78     dbus_pub_t pub; /* MUST BE FIRST */
79     dhd_pub_t *dhd;
80 
81     void *cbarg;
82     dbus_callbacks_t *cbs; /* callbacks to higher level, e.g. dhd_linux.c */
83     void *bus_info;
84     dbus_intf_t *drvintf; /* callbacks to lower level, e.g. dbus_usb.c or
85                              dbus_usb_linux.c */
86     uint8 *fw;
87     int fwlen;
88     uint32 errmask;
89     int rx_low_watermark; /* avoid rx overflow by filling rx with free IRBs */
90     int tx_low_watermark;
91     bool txoff;
92     bool txoverride; /* flow control related */
93     bool rxoff;
94     bool tx_timer_ticking;
95 
96     dbus_irbq_t *rx_q;
97     dbus_irbq_t *tx_q;
98 
99     uint8 *nvram;
100     int nvram_len;
101     uint8 *image; /* buffer for combine fw and nvram */
102     int image_len;
103     uint8 *orig_fw;
104     int origfw_len;
105     int decomp_memsize;
106     dbus_extdl_t extdl;
107     int nvram_nontxt;
108 #if defined(BCM_REQUEST_FW)
109     void *firmware;
110     void *nvfile;
111 #endif
112     char *fw_path; /* module_param: path to firmware image */
113     char *nv_path; /* module_param: path to nvram vars file */
114 } dhd_bus_t;
115 
116 struct exec_parms {
117     union {
118         /* Can consolidate same params, if need be, but this shows
119          * group of parameters per function
120          */
121         struct {
122             dbus_irbq_t *q;
123             dbus_irb_t *b;
124         } qenq;
125 
126         struct {
127             dbus_irbq_t *q;
128         } qdeq;
129     };
130 };
131 
132 #define EXEC_RXLOCK(info, fn, a)                                               \
133     info->drvintf->exec_rxlock(dhd_bus->bus_info, ((exec_cb_t)fn),             \
134                                ((struct exec_parms *)a))
135 
136 #define EXEC_TXLOCK(info, fn, a)                                               \
137     info->drvintf->exec_txlock(dhd_bus->bus_info, ((exec_cb_t)fn),             \
138                                ((struct exec_parms *)a))
139 
140 /*
141  * Callbacks common for all BUS
142  */
143 static void dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb);
144 static void dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb,
145                                       int status);
146 static void dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb,
147                                       int status);
148 static void dbus_if_errhandler(void *handle, int err);
149 static void dbus_if_ctl_complete(void *handle, int type, int status);
150 static void dbus_if_state_change(void *handle, int state);
151 static void *dbus_if_pktget(void *handle, uint len, bool send);
152 static void dbus_if_pktfree(void *handle, void *p, bool send);
153 static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send);
154 static void dbus_if_rxerr_indicate(void *handle, bool on);
155 
156 void *dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
157                         uint16 bus_no, uint16 slot, uint32 hdrlen);
158 void dhd_dbus_disconnect_cb(void *arg);
159 void dbus_detach(dhd_bus_t *pub);
160 
161 /** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c
162  */
163 static dbus_intf_callbacks_t dbus_intf_cbs = {dbus_if_send_irb_timeout,
164                                               dbus_if_send_irb_complete,
165                                               dbus_if_recv_irb_complete,
166                                               dbus_if_errhandler,
167                                               dbus_if_ctl_complete,
168                                               dbus_if_state_change,
169                                               NULL, /* isr */
170                                               NULL, /* dpc */
171                                               NULL, /* watchdog */
172                                               dbus_if_pktget,
173                                               dbus_if_pktfree,
174                                               dbus_if_getirb,
175                                               dbus_if_rxerr_indicate};
176 
177 /*
178  * Need global for probe() and disconnect() since
179  * attach() is not called at probe and detach()
180  * can be called inside disconnect()
181  */
182 static dbus_intf_t *g_busintf = NULL;
183 static probe_cb_t probe_cb = NULL;
184 static disconnect_cb_t disconnect_cb = NULL;
185 static void *probe_arg = NULL;
186 static void *disc_arg = NULL;
187 
188 #if defined(BCM_REQUEST_FW)
189 int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */
190 int nonfwnvramlen = 0;
191 #endif /* #if defined(BCM_REQUEST_FW) */
192 
193 static void *q_enq(dbus_irbq_t *q, dbus_irb_t *b);
194 static void *q_enq_exec(struct exec_parms *args);
195 static dbus_irb_t *q_deq(dbus_irbq_t *q);
196 static void *q_deq_exec(struct exec_parms *args);
197 static int dbus_tx_timer_init(dhd_bus_t *dhd_bus);
198 static int dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout);
199 static int dbus_tx_timer_stop(dhd_bus_t *dhd_bus);
200 static int dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq,
201                           int size_irb);
202 static int dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb);
203 static int dbus_rxirbs_fill(dhd_bus_t *dhd_bus);
204 static int dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt,
205                          void *info);
206 static void dbus_disconnect(void *handle);
207 static void *dbus_probe(void *arg, const char *desc, uint32 bustype,
208                         uint16 bus_no, uint16 slot, uint32 hdrlen);
209 
210 #if defined(BCM_REQUEST_FW)
211 extern char *dngl_firmware;
212 extern unsigned int dngl_fwlen;
213 #ifndef EXTERNAL_FW_PATH
214 static int dbus_get_nvram(dhd_bus_t *dhd_bus);
215 static int dbus_jumbo_nvram(dhd_bus_t *dhd_bus);
216 static int dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev);
217 static int dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen,
218                              uint16 boardtype, uint16 boardrev, int8 **nvram,
219                              int *nvram_len);
220 #endif /* !EXTERNAL_FW_PATH */
221 extern int dbus_zlib_decomp(dhd_bus_t *dhd_bus);
222 extern void *dbus_zlib_calloc(int num, int size);
223 extern void dbus_zlib_free(void *ptr);
224 #endif
225 
226 /* function */
dbus_flowctrl_tx(void * dbi,bool on)227 void dbus_flowctrl_tx(void *dbi, bool on)
228 {
229     dhd_bus_t *dhd_bus = dbi;
230 
231     if (dhd_bus == NULL) {
232         return;
233     }
234 
235     DBUSTRACE(("%s on %d\n", __FUNCTION__, on));
236 
237     if (dhd_bus->txoff == on) {
238         return;
239     }
240 
241     dhd_bus->txoff = on;
242 
243     if (dhd_bus->cbs && dhd_bus->cbs->txflowcontrol) {
244         dhd_bus->cbs->txflowcontrol(dhd_bus->cbarg, on);
245     }
246 }
247 
248 /**
249  * if lower level DBUS signaled a rx error, more free rx IRBs should be
250  * allocated or flow control should kick in to make more free rx IRBs available.
251  */
dbus_if_rxerr_indicate(void * handle,bool on)252 static void dbus_if_rxerr_indicate(void *handle, bool on)
253 {
254     dhd_bus_t *dhd_bus = (dhd_bus_t *)handle;
255 
256     DBUSTRACE(("%s, on %d\n", __FUNCTION__, on));
257 
258     if (dhd_bus == NULL) {
259         return;
260     }
261 
262     if (dhd_bus->txoverride == on) {
263         return;
264     }
265 
266     dhd_bus->txoverride = on; /* flow control */
267 
268     if (!on) {
269         dbus_rxirbs_fill(dhd_bus);
270     }
271 }
272 
273 /** q_enq()/q_deq() are executed with protection via exec_rxlock()/exec_txlock()
274  */
q_enq(dbus_irbq_t * q,dbus_irb_t * b)275 static void *q_enq(dbus_irbq_t *q, dbus_irb_t *b)
276 {
277     ASSERT(q->tail != b);
278     ASSERT(b->next == NULL);
279     b->next = NULL;
280     if (q->tail) {
281         q->tail->next = b;
282         q->tail = b;
283     } else {
284         q->head = q->tail = b;
285     }
286 
287     q->cnt++;
288 
289     return b;
290 }
291 
q_enq_exec(struct exec_parms * args)292 static void *q_enq_exec(struct exec_parms *args)
293 {
294     return q_enq(args->qenq.q, args->qenq.b);
295 }
296 
q_deq(dbus_irbq_t * q)297 static dbus_irb_t *q_deq(dbus_irbq_t *q)
298 {
299     dbus_irb_t *b;
300 
301     b = q->head;
302     if (b) {
303         q->head = q->head->next;
304         b->next = NULL;
305 
306         if (q->head == NULL) {
307             q->tail = q->head;
308         }
309 
310         q->cnt--;
311     }
312     return b;
313 }
314 
q_deq_exec(struct exec_parms * args)315 static void *q_deq_exec(struct exec_parms *args)
316 {
317     return q_deq(args->qdeq.q);
318 }
319 
320 /**
321  * called during attach phase. Status @ Dec 2012: this function does nothing
322  * since for all of the lower DBUS levels dhd_bus->drvintf->tx_timer_init is
323  * NULL.
324  */
dbus_tx_timer_init(dhd_bus_t * dhd_bus)325 static int dbus_tx_timer_init(dhd_bus_t *dhd_bus)
326 {
327     if (dhd_bus && dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_init) {
328         return dhd_bus->drvintf->tx_timer_init(dhd_bus->bus_info);
329     } else {
330         return DBUS_ERR;
331     }
332 }
333 
dbus_tx_timer_start(dhd_bus_t * dhd_bus,uint timeout)334 static int dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout)
335 {
336     if (dhd_bus == NULL) {
337         return DBUS_ERR;
338     }
339 
340     if (dhd_bus->tx_timer_ticking) {
341         return DBUS_OK;
342     }
343 
344     if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_start) {
345         if (dhd_bus->drvintf->tx_timer_start(dhd_bus->bus_info, timeout) ==
346             DBUS_OK) {
347             dhd_bus->tx_timer_ticking = TRUE;
348             return DBUS_OK;
349         }
350     }
351 
352     return DBUS_ERR;
353 }
354 
dbus_tx_timer_stop(dhd_bus_t * dhd_bus)355 static int dbus_tx_timer_stop(dhd_bus_t *dhd_bus)
356 {
357     if (dhd_bus == NULL) {
358         return DBUS_ERR;
359     }
360 
361     if (!dhd_bus->tx_timer_ticking) {
362         return DBUS_OK;
363     }
364 
365     if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_stop) {
366         if (dhd_bus->drvintf->tx_timer_stop(dhd_bus->bus_info) == DBUS_OK) {
367             dhd_bus->tx_timer_ticking = FALSE;
368             return DBUS_OK;
369         }
370     }
371 
372     return DBUS_ERR;
373 }
374 
375 /** called during attach phase. */
dbus_irbq_init(dhd_bus_t * dhd_bus,dbus_irbq_t * q,int nq,int size_irb)376 static int dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq,
377                           int size_irb)
378 {
379     int i;
380     dbus_irb_t *irb;
381 
382     ASSERT(q);
383     ASSERT(dhd_bus);
384 
385     for (i = 0; i < nq; i++) {
386         /* MALLOC dbus_irb_tx or dbus_irb_rx, but cast to simple dbus_irb_t
387          * linkedlist */
388         irb = (dbus_irb_t *)MALLOC(dhd_bus->pub.osh, size_irb);
389         if (irb == NULL) {
390             ASSERT(irb);
391             return DBUS_ERR;
392         }
393         bzero(irb, size_irb);
394 
395         /* q_enq() does not need to go through EXEC_xxLOCK() during init() */
396         q_enq(q, irb);
397     }
398 
399     return DBUS_OK;
400 }
401 
402 /** called during detach phase or when attach failed */
dbus_irbq_deinit(dhd_bus_t * dhd_bus,dbus_irbq_t * q,int size_irb)403 static int dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb)
404 {
405     dbus_irb_t *irb;
406 
407     ASSERT(q);
408     ASSERT(dhd_bus);
409 
410     /* q_deq() does not need to go through EXEC_xxLOCK()
411      * during deinit(); all callbacks are stopped by this time
412      */
413     while ((irb = q_deq(q)) != NULL) {
414         MFREE(dhd_bus->pub.osh, irb, size_irb);
415     }
416 
417     if (q->cnt) {
418         DBUSERR(("deinit: q->cnt=%d > 0\n", q->cnt));
419     }
420     return DBUS_OK;
421 }
422 
423 /** multiple code paths require the rx queue to be filled with more free IRBs */
dbus_rxirbs_fill(dhd_bus_t * dhd_bus)424 static int dbus_rxirbs_fill(dhd_bus_t *dhd_bus)
425 {
426     int err = DBUS_OK;
427 
428     dbus_irb_rx_t *rxirb;
429     struct exec_parms args;
430 
431     ASSERT(dhd_bus);
432     if (dhd_bus->pub.busstate != DBUS_STATE_UP) {
433         DBUSERR(("dbus_rxirbs_fill: DBUS not up \n"));
434         return DBUS_ERR;
435     } else if (!dhd_bus->drvintf || (dhd_bus->drvintf->recv_irb == NULL)) {
436         /* Lower edge bus interface does not support recv_irb().
437          * No need to pre-submit IRBs in this case.
438          */
439         return DBUS_ERR;
440     }
441 
442     /* The dongle recv callback is freerunning without lock. So multiple
443      * callbacks(and this refill) can run in parallel. While the rxoff condition
444      * is triggered outside, below while loop has to check and abort posting
445      * more to avoid RPC rxq overflow.
446      */
447     args.qdeq.q = dhd_bus->rx_q;
448     while ((!dhd_bus->rxoff) &&
449            (rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) {
450         err = dhd_bus->drvintf->recv_irb(dhd_bus->bus_info, rxirb);
451         if (err == DBUS_ERR_RXDROP || err == DBUS_ERR_RXFAIL) {
452             /* Add the the free rxirb back to the queue
453              * and wait till later
454              */
455             bzero(rxirb, sizeof(dbus_irb_rx_t));
456             args.qenq.q = dhd_bus->rx_q;
457             args.qenq.b = (dbus_irb_t *)rxirb;
458             EXEC_RXLOCK(dhd_bus, q_enq_exec, &args);
459             break;
460         } else if (err != DBUS_OK) {
461             int i = 0;
462             while (i++ < 0x64) {
463                 DBUSERR(("%s :: memory leak for rxirb note?\n", __FUNCTION__));
464             }
465         }
466     }
467     return err;
468 } /* dbus_rxirbs_fill */
469 
470 /** called when the DBUS interface state changed. */
dbus_flowctrl_rx(dbus_pub_t * pub,bool on)471 void dbus_flowctrl_rx(dbus_pub_t *pub, bool on)
472 {
473     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
474 
475     if (dhd_bus == NULL) {
476         return;
477     }
478 
479     DBUSTRACE(("%s\n", __FUNCTION__));
480 
481     if (dhd_bus->rxoff == on) {
482         return;
483     }
484 
485     dhd_bus->rxoff = on;
486 
487     if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
488         if (!on) {
489             /* post more irbs, resume rx if necessary */
490             dbus_rxirbs_fill(dhd_bus);
491             if (dhd_bus && dhd_bus->drvintf->recv_resume) {
492                 dhd_bus->drvintf->recv_resume(dhd_bus->bus_info);
493             }
494         } else {
495             /* ??? cancell posted irbs first */
496 
497             if (dhd_bus && dhd_bus->drvintf->recv_stop) {
498                 dhd_bus->drvintf->recv_stop(dhd_bus->bus_info);
499             }
500         }
501     }
502 }
503 
504 /**
505  * Several code paths in this file want to send a buffer to the dongle. This
506  * function handles both sending of a buffer or a pkt.
507  */
dbus_send_irb(dbus_pub_t * pub,uint8 * buf,int len,void * pkt,void * info)508 static int dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt,
509                          void *info)
510 {
511     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
512     int err = DBUS_OK;
513     dbus_irb_tx_t *txirb = NULL;
514     int txirb_pending;
515     struct exec_parms args;
516 
517     if (dhd_bus == NULL) {
518         return DBUS_ERR;
519     }
520 
521     DBUSTRACE(("%s\n", __FUNCTION__));
522 
523     if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
524         dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
525         args.qdeq.q = dhd_bus->tx_q;
526         if (dhd_bus->drvintf) {
527             txirb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args);
528         }
529 
530         if (txirb == NULL) {
531             DBUSERR(("Out of tx dbus_bufs\n"));
532             return DBUS_ERR;
533         }
534 
535         if (pkt != NULL) {
536             txirb->pkt = pkt;
537             txirb->buf = NULL;
538             txirb->len = 0;
539         } else if (buf != NULL) {
540             txirb->pkt = NULL;
541             txirb->buf = buf;
542             txirb->len = len;
543         } else {
544             ASSERT(0); /* Should not happen */
545         }
546         txirb->info = info;
547         txirb->arg = NULL;
548         txirb->retry_count = 0;
549 
550         if (dhd_bus->drvintf && dhd_bus->drvintf->send_irb) {
551             /* call lower DBUS level send_irb function */
552             err = dhd_bus->drvintf->send_irb(dhd_bus->bus_info, txirb);
553             if (err == DBUS_ERR_TXDROP) {
554                 /* tx fail and no completion routine to clean up, reclaim irb
555                  * NOW */
556                 DBUSERR(
557                     ("%s: send_irb failed, status = %d\n", __FUNCTION__, err));
558                 bzero(txirb, sizeof(dbus_irb_tx_t));
559                 args.qenq.q = dhd_bus->tx_q;
560                 args.qenq.b = (dbus_irb_t *)txirb;
561                 EXEC_TXLOCK(dhd_bus, q_enq_exec, &args);
562             } else {
563                 dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL);
564                 txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt;
565                 if (txirb_pending > (dhd_bus->tx_low_watermark * 0x3)) {
566                     dbus_flowctrl_tx(dhd_bus, TRUE);
567                 }
568             }
569         }
570     } else {
571         err = DBUS_ERR_TXFAIL;
572         DBUSTRACE(("%s: bus down, send_irb failed\n", __FUNCTION__));
573     }
574 
575     return err;
576 } /* dbus_send_irb */
577 
578 #if defined(BCM_REQUEST_FW)
579 
580 /**
581  * Before downloading a firmware image into the dongle, the validity of the
582  * image must be checked.
583  */
check_file(osl_t * osh,unsigned char * headers)584 static int check_file(osl_t *osh, unsigned char *headers)
585 {
586     struct trx_header *trx;
587     int actual_len = -1;
588 
589     /* Extract trx header */
590     trx = (struct trx_header *)headers;
591     if (ltoh32(trx->magic) != TRX_MAGIC) {
592         printf("Error: trx bad hdr %x\n", ltoh32(trx->magic));
593         return -1;
594     }
595 
596     headers += SIZEOF_TRX(trx);
597 
598     /* TRX V1: get firmware len */
599     /* TRX V2: get firmware len and DSG/CFG lengths */
600     if (ltoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) {
601         actual_len =
602             ltoh32(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]) + SIZEOF_TRX(trx);
603 #ifdef BCMTRXV2
604         if (ISTRX_V2(trx)) {
605             actual_len += ltoh32(trx->offsets[TRX_OFFSETS_DSG_LEN_IDX]) +
606                           ltoh32(trx->offsets[TRX_OFFSETS_CFG_LEN_IDX]);
607         }
608 #endif
609         return actual_len;
610     } else {
611         printf("compressed image\n");
612     }
613 
614     return -1;
615 }
616 
617 #ifdef EXTERNAL_FW_PATH
dbus_get_fw_nvram(dhd_bus_t * dhd_bus,char * pfw_path,char * pnv_path)618 static int dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
619 {
620     int bcmerror = -1, i;
621     uint len, total_len;
622     void *nv_image = NULL, *fw_image = NULL;
623     char *nv_memblock = NULL, *fw_memblock = NULL;
624     char *bufp;
625     bool file_exists;
626     uint8 nvram_words_pad = 0;
627     uint memblock_size = 2048;
628     uint8 *memptr;
629     int actual_fwlen;
630     struct trx_header *hdr;
631     uint32 img_offset = 0;
632     int offset = 0;
633 
634     /* For Get nvram */
635     file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
636     if (file_exists) {
637         nv_image = dhd_os_open_image1(dhd_bus->dhd, pnv_path);
638         if (nv_image == NULL) {
639             printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
640             goto err;
641         }
642     }
643     nv_memblock = MALLOC(dhd_bus->pub.osh, MAX_NVRAMBUF_SIZE);
644     if (nv_memblock == NULL) {
645         DBUSERR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
646                  MAX_NVRAMBUF_SIZE));
647         goto err;
648     }
649     len = dhd_os_get_image_block(nv_memblock, MAX_NVRAMBUF_SIZE, nv_image);
650     if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
651         bufp = (char *)nv_memblock;
652         bufp[len] = 0;
653         dhd_bus->nvram_len = process_nvram_vars(bufp, len);
654         if (dhd_bus->nvram_len % 0x4) {
655             nvram_words_pad = 0x4 - dhd_bus->nvram_len % 0x4;
656         }
657     } else {
658         DBUSERR(("%s: error reading nvram file: %d\n", __FUNCTION__, len));
659         bcmerror = DBUS_ERR_NVRAM;
660         goto err;
661     }
662     if (nv_image) {
663         dhd_os_close_image1(dhd_bus->dhd, nv_image);
664         nv_image = NULL;
665     }
666 
667     /* For Get first block of fw to calculate total_len */
668     file_exists = ((pfw_path != NULL) && (pfw_path[0] != '\0'));
669     if (file_exists) {
670         fw_image = dhd_os_open_image1(dhd_bus->dhd, pfw_path);
671         if (fw_image == NULL) {
672             printf("%s: Open fw file failed %s\n", __FUNCTION__, pfw_path);
673             goto err;
674         }
675     }
676     memptr = fw_memblock = MALLOC(dhd_bus->pub.osh, memblock_size);
677     if (fw_memblock == NULL) {
678         DBUSERR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
679                  memblock_size));
680         goto err;
681     }
682     len = dhd_os_get_image_block((char *)memptr, memblock_size, fw_image);
683     if ((actual_fwlen = check_file(dhd_bus->pub.osh, memptr)) <= 0) {
684         DBUSERR(("%s: bad firmware format!\n", __FUNCTION__));
685         goto err;
686     }
687 
688     total_len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad;
689 #if defined(CONFIG_DHD_USE_STATIC_BUF)
690     dhd_bus->image = (uint8 *)DHD_OS_PREALLOC(
691         dhd_bus->dhd, DHD_PREALLOC_MEMDUMP_RAM, total_len);
692 #else
693     dhd_bus->image = MALLOC(dhd_bus->pub.osh, total_len);
694 #endif /* CONFIG_DHD_USE_STATIC_BUF */
695     dhd_bus->image_len = total_len;
696     if (dhd_bus->image == NULL) {
697         DBUSERR(("%s: malloc failed! size=%d\n", __FUNCTION__, total_len));
698         goto err;
699     }
700 
701     /* Step1: Copy trx header + firmwre */
702     memptr = fw_memblock;
703     do {
704         if (len < 0) {
705             DBUSERR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__,
706                      len));
707             bcmerror = BCME_ERROR;
708             goto err;
709         }
710         bcopy(memptr, dhd_bus->image + offset, len);
711         offset += len;
712     } while ((
713         len = dhd_os_get_image_block((char *)memptr, memblock_size, fw_image)));
714     /* Step2: Copy NVRAM + pad */
715     hdr = (struct trx_header *)dhd_bus->image;
716     img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX];
717     bcopy(nv_memblock, (uint8 *)(dhd_bus->image + img_offset),
718           dhd_bus->nvram_len);
719     img_offset += dhd_bus->nvram_len;
720     if (nvram_words_pad) {
721         bzero(&dhd_bus->image[img_offset], nvram_words_pad);
722         img_offset += nvram_words_pad;
723     }
724 #ifdef BCMTRXV2
725     /* Step3: Copy DSG/CFG for V2 */
726     if (ISTRX_V2(hdr) && (hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] ||
727                           hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) {
728         DBUSERR(("%s: fix me\n", __FUNCTION__));
729     }
730 #endif /* BCMTRXV2 */
731     /* Step4: update TRX header for nvram size */
732     hdr = (struct trx_header *)dhd_bus->image;
733     hdr->len = htol32(total_len);
734     /* Pass the actual fw len */
735     hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] =
736         htol32(dhd_bus->nvram_len + nvram_words_pad);
737     /* Calculate CRC over header */
738     hdr->crc32 =
739         hndcrc32((uint8 *)&hdr->flag_version,
740                  SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version),
741                  CRC32_INIT_VALUE);
742 
743     /* Calculate CRC over data */
744     for (i = SIZEOF_TRX(hdr); i < total_len; ++i) {
745         hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32);
746     }
747     hdr->crc32 = htol32(hdr->crc32);
748 
749     bcmerror = DBUS_OK;
750 
751 err:
752     if (fw_memblock) {
753         MFREE(dhd_bus->pub.osh, fw_memblock, MAX_NVRAMBUF_SIZE);
754     }
755     if (fw_image) {
756         dhd_os_close_image1(dhd_bus->dhd, fw_image);
757     }
758     if (nv_memblock) {
759         MFREE(dhd_bus->pub.osh, nv_memblock, MAX_NVRAMBUF_SIZE);
760     }
761     if (nv_image) {
762         dhd_os_close_image1(dhd_bus->dhd, nv_image);
763     }
764 
765     return bcmerror;
766 }
767 
768 /**
769  * during driver initialization ('attach') or after PnP 'resume', firmware needs
770  * to be loaded into the dongle
771  */
dbus_do_download(dhd_bus_t * dhd_bus,char * pfw_path,char * pnv_path)772 static int dbus_do_download(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
773 {
774     int err = DBUS_OK;
775 
776     err = dbus_get_fw_nvram(dhd_bus, pfw_path, pnv_path);
777     if (err) {
778         DBUSERR(("dbus_do_download: fail to get nvram %d\n", err));
779         return err;
780     }
781 
782     if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) {
783         err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, dhd_bus->image,
784                                         dhd_bus->image_len);
785         if (err == DBUS_OK) {
786             err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info);
787         }
788     } else {
789         err = DBUS_ERR;
790     }
791 
792     if (dhd_bus->image) {
793 #if defined(CONFIG_DHD_USE_STATIC_BUF)
794         DHD_OS_PREFREE(dhd_bus->dhd, dhd_bus->image, dhd_bus->image_len);
795 #else
796         MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len);
797 #endif /* CONFIG_DHD_USE_STATIC_BUF */
798         dhd_bus->image = NULL;
799         dhd_bus->image_len = 0;
800     }
801 
802     return err;
803 } /* dbus_do_download */
804 #else
805 
806 /**
807  * It is easy for the user to pass one jumbo nvram file to the driver than a set
808  * of smaller files. The 'jumbo nvram' file format is essentially a set of nvram
809  * files. Before commencing firmware download, the dongle needs to be probed so
810  * that the correct nvram contents within the jumbo nvram file is selected.
811  */
dbus_jumbo_nvram(dhd_bus_t * dhd_bus)812 static int dbus_jumbo_nvram(dhd_bus_t *dhd_bus)
813 {
814     int8 *nvram = NULL;
815     int nvram_len = 0;
816     int ret = DBUS_OK;
817     uint16 boardrev = 0xFFFF;
818     uint16 boardtype = 0xFFFF;
819 
820     /* read the otp for boardrev & boardtype
821      * if boardtype/rev are present in otp
822      * select nvram data for that boardtype/rev
823      */
824     dbus_otp(dhd_bus, &boardtype, &boardrev);
825 
826     ret =
827         dbus_select_nvram(dhd_bus, dhd_bus->extdl.vars, dhd_bus->extdl.varslen,
828                           boardtype, boardrev, &nvram, &nvram_len);
829     if (ret == DBUS_JUMBO_BAD_FORMAT) {
830         return DBUS_ERR_NVRAM;
831     } else if (ret == DBUS_JUMBO_NOMATCH &&
832                (boardtype != 0xFFFF || boardrev != 0xFFFF)) {
833         DBUSERR(("No matching NVRAM for boardtype 0x%02x boardrev 0x%02x\n",
834                  boardtype, boardrev));
835         return DBUS_ERR_NVRAM;
836     }
837     dhd_bus->nvram = nvram;
838     dhd_bus->nvram_len = nvram_len;
839 
840     return DBUS_OK;
841 }
842 
843 /** before commencing fw download, the correct NVRAM image to download has to be
844  * picked */
dbus_get_nvram(dhd_bus_t * dhd_bus)845 static int dbus_get_nvram(dhd_bus_t *dhd_bus)
846 {
847     int len, i;
848     struct trx_header *hdr;
849     int actual_fwlen;
850     uint32 img_offset = 0;
851 
852     dhd_bus->nvram_len = 0;
853     if (dhd_bus->extdl.varslen) {
854         if (DBUS_OK != dbus_jumbo_nvram(dhd_bus)) {
855             return DBUS_ERR_NVRAM;
856         }
857         DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len));
858     }
859 #if defined(BCM_REQUEST_FW)
860     else if (nonfwnvram) {
861         dhd_bus->nvram = nonfwnvram;
862         dhd_bus->nvram_len = nonfwnvramlen;
863         DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len));
864     }
865 #endif
866     if (dhd_bus->nvram) {
867         uint8 nvram_words_pad = 0;
868         /* Validate the format/length etc of the file */
869         if ((actual_fwlen = check_file(dhd_bus->pub.osh, dhd_bus->fw)) <= 0) {
870             DBUSERR(("%s: bad firmware format!\n", __FUNCTION__));
871             return DBUS_ERR_NVRAM;
872         }
873 
874         if (!dhd_bus->nvram_nontxt) {
875             /* host supplied nvram could be in .txt format
876              * with all the comments etc...
877              */
878             dhd_bus->nvram_len =
879                 process_nvram_vars(dhd_bus->nvram, dhd_bus->nvram_len);
880         }
881         if (dhd_bus->nvram_len % 0x4) {
882             nvram_words_pad = 0x4 - dhd_bus->nvram_len % 0x4;
883         }
884 
885         len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad;
886         dhd_bus->image = MALLOC(dhd_bus->pub.osh, len);
887         dhd_bus->image_len = len;
888         if (dhd_bus->image == NULL) {
889             DBUSERR(("%s: malloc failed!\n", __FUNCTION__));
890             return DBUS_ERR_NVRAM;
891         }
892         hdr = (struct trx_header *)dhd_bus->fw;
893         /* Step1: Copy trx header + firmwre */
894         img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX];
895         bcopy(dhd_bus->fw, dhd_bus->image, img_offset);
896         /* Step2: Copy NVRAM + pad */
897         bcopy(dhd_bus->nvram, (uint8 *)(dhd_bus->image + img_offset),
898               dhd_bus->nvram_len);
899         img_offset += dhd_bus->nvram_len;
900         if (nvram_words_pad) {
901             bzero(&dhd_bus->image[img_offset], nvram_words_pad);
902             img_offset += nvram_words_pad;
903         }
904 #ifdef BCMTRXV2
905         /* Step3: Copy DSG/CFG for V2 */
906         if (ISTRX_V2(hdr) && (hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] ||
907                               hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) {
908             bcopy(dhd_bus->fw + SIZEOF_TRX(hdr) +
909                       hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX] +
910                       hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX],
911                   dhd_bus->image + img_offset,
912                   hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] +
913                       hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]);
914 
915             img_offset += hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] +
916                           hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX];
917         }
918 #endif /* BCMTRXV2 */
919         /* Step4: update TRX header for nvram size */
920         hdr = (struct trx_header *)dhd_bus->image;
921         hdr->len = htol32(len);
922         /* Pass the actual fw len */
923         hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] =
924             htol32(dhd_bus->nvram_len + nvram_words_pad);
925         /* Calculate CRC over header */
926         hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version,
927                               SIZEOF_TRX(hdr) -
928                                   OFFSETOF(struct trx_header, flag_version),
929                               CRC32_INIT_VALUE);
930 
931         /* Calculate CRC over data */
932         for (i = SIZEOF_TRX(hdr); i < len; ++i) {
933             hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32);
934         }
935         hdr->crc32 = htol32(hdr->crc32);
936     } else {
937         dhd_bus->image = dhd_bus->fw;
938         dhd_bus->image_len = (uint32)dhd_bus->fwlen;
939     }
940 
941     return DBUS_OK;
942 } /* dbus_get_nvram */
943 
944 /**
945  * during driver initialization ('attach') or after PnP 'resume', firmware needs
946  * to be loaded into the dongle
947  */
dbus_do_download(dhd_bus_t * dhd_bus)948 static int dbus_do_download(dhd_bus_t *dhd_bus)
949 {
950     int err = DBUS_OK;
951 #ifndef BCM_REQUEST_FW
952     int decomp_override = 0;
953 #endif
954 #ifdef BCM_REQUEST_FW
955     uint16 boardrev = 0xFFFF, boardtype = 0xFFFF;
956     int8 *temp_nvram;
957     int temp_len;
958 #endif
959 
960 #if defined(BCM_REQUEST_FW)
961     dhd_bus->firmware = dbus_get_fw_nvfile(
962         dhd_bus->pub.attrib.devid, dhd_bus->pub.attrib.chiprev, &dhd_bus->fw,
963         &dhd_bus->fwlen, DBUS_FIRMWARE, 0, 0);
964     if (!dhd_bus->firmware) {
965         return DBUS_ERR;
966     }
967 #endif
968 
969     dhd_bus->image = dhd_bus->fw;
970     dhd_bus->image_len = (uint32)dhd_bus->fwlen;
971 
972 #ifndef BCM_REQUEST_FW
973     if (UNZIP_ENAB(dhd_bus) && !decomp_override) {
974         err = dbus_zlib_decomp(dhd_bus);
975         if (err) {
976             DBUSERR(("dbus_attach: fw decompress fail %d\n", err));
977             return err;
978         }
979     }
980 #endif
981 
982 #if defined(BCM_REQUEST_FW)
983     /* check if firmware is appended with nvram file */
984     err = dbus_otp(dhd_bus, &boardtype, &boardrev);
985     /* check if nvram is provided as separte file */
986     nonfwnvram = NULL;
987     nonfwnvramlen = 0;
988     dhd_bus->nvfile = dbus_get_fw_nvfile(
989         dhd_bus->pub.attrib.devid, dhd_bus->pub.attrib.chiprev,
990         (void *)&temp_nvram, &temp_len, DBUS_NVFILE, boardtype, boardrev);
991     if (dhd_bus->nvfile) {
992         int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len);
993         if (tmp) {
994             bcopy(temp_nvram, tmp, temp_len);
995             nonfwnvram = tmp;
996             nonfwnvramlen = temp_len;
997         } else {
998             err = DBUS_ERR;
999             goto fail;
1000         }
1001     }
1002 #endif /* defined(BCM_REQUEST_FW) */
1003 
1004     err = dbus_get_nvram(dhd_bus);
1005     if (err) {
1006         DBUSERR(("dbus_do_download: fail to get nvram %d\n", err));
1007         return err;
1008     }
1009 
1010     if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) {
1011         err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, dhd_bus->image,
1012                                         dhd_bus->image_len);
1013         if (err == DBUS_OK) {
1014             err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info);
1015         }
1016     } else {
1017         err = DBUS_ERR;
1018     }
1019 
1020     if (dhd_bus->nvram) {
1021         MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len);
1022         dhd_bus->image = dhd_bus->fw;
1023         dhd_bus->image_len = (uint32)dhd_bus->fwlen;
1024     }
1025 
1026 #ifndef BCM_REQUEST_FW
1027     if (UNZIP_ENAB(dhd_bus) && (!decomp_override) && dhd_bus->orig_fw) {
1028         MFREE(dhd_bus->pub.osh, dhd_bus->fw, dhd_bus->decomp_memsize);
1029         dhd_bus->image = dhd_bus->fw = dhd_bus->orig_fw;
1030         dhd_bus->image_len = dhd_bus->fwlen = dhd_bus->origfw_len;
1031     }
1032 #endif
1033 
1034 #if defined(BCM_REQUEST_FW)
1035 fail:
1036     if (dhd_bus->firmware) {
1037         dbus_release_fw_nvfile(dhd_bus->firmware);
1038         dhd_bus->firmware = NULL;
1039     }
1040     if (dhd_bus->nvfile) {
1041         dbus_release_fw_nvfile(dhd_bus->nvfile);
1042         dhd_bus->nvfile = NULL;
1043     }
1044     if (nonfwnvram) {
1045         MFREE(dhd_bus->pub.osh, nonfwnvram, nonfwnvramlen);
1046         nonfwnvram = NULL;
1047         nonfwnvramlen = 0;
1048     }
1049 #endif
1050     return err;
1051 } /* dbus_do_download */
1052 #endif /* EXTERNAL_FW_PATH */
1053 #endif
1054 
1055 /** required for DBUS deregistration */
dbus_disconnect(void * handle)1056 static void dbus_disconnect(void *handle)
1057 {
1058     DBUSTRACE(("%s\n", __FUNCTION__));
1059 
1060     if (disconnect_cb) {
1061         disconnect_cb(disc_arg);
1062     }
1063 }
1064 
1065 /**
1066  * This function is called when the sent irb times out without a tx response
1067  * status. DBUS adds reliability by resending timed out IRBs DBUS_TX_RETRY_LIMIT
1068  * times.
1069  */
dbus_if_send_irb_timeout(void * handle,dbus_irb_tx_t * txirb)1070 static void dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb)
1071 {
1072     dhd_bus_t *dhd_bus = (dhd_bus_t *)handle;
1073 
1074     if ((dhd_bus == NULL) || (dhd_bus->drvintf == NULL) || (txirb == NULL)) {
1075         return;
1076     }
1077 
1078     DBUSTRACE(("%s\n", __FUNCTION__));
1079 
1080     return;
1081 } /* dbus_if_send_irb_timeout */
1082 
1083 /**
1084  * When lower DBUS level signals that a send IRB completed, either successful or
1085  * not, the higher level (e.g. dhd_linux.c) has to be notified, and transmit
1086  * flow control has to be evaluated.
1087  */
dbus_if_send_irb_complete(void * handle,dbus_irb_tx_t * txirb,int status)1088 static void BCMFASTPATH dbus_if_send_irb_complete(void *handle,
1089                                                   dbus_irb_tx_t *txirb,
1090                                                   int status)
1091 {
1092     dhd_bus_t *dhd_bus = (dhd_bus_t *)handle;
1093     int txirb_pending;
1094     struct exec_parms args;
1095     void *pktinfo;
1096 
1097     if ((dhd_bus == NULL) || (txirb == NULL)) {
1098         return;
1099     }
1100 
1101     DBUSTRACE(("%s: status = %d\n", __FUNCTION__, status));
1102 
1103     dbus_tx_timer_stop(dhd_bus);
1104 
1105     /* re-queue BEFORE calling send_complete which will assume that this irb
1106        is now available.
1107      */
1108     pktinfo = txirb->info;
1109     bzero(txirb, sizeof(dbus_irb_tx_t));
1110     args.qenq.q = dhd_bus->tx_q;
1111     args.qenq.b = (dbus_irb_t *)txirb;
1112     EXEC_TXLOCK(dhd_bus, q_enq_exec, &args);
1113 
1114     if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) {
1115         if ((status == DBUS_OK) || (status == DBUS_ERR_NODEVICE)) {
1116             if (dhd_bus->cbs && dhd_bus->cbs->send_complete) {
1117                 dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, status);
1118             }
1119 
1120             if (status == DBUS_OK) {
1121                 txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt;
1122                 if (txirb_pending) {
1123                     dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL);
1124                 }
1125                 if ((txirb_pending < dhd_bus->tx_low_watermark) &&
1126                     dhd_bus->txoff && !dhd_bus->txoverride) {
1127                     dbus_flowctrl_tx(dhd_bus, OFF);
1128                 }
1129             }
1130         } else {
1131             DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__,
1132                      __LINE__, pktinfo));
1133 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC)
1134             if (pktinfo) {
1135                 if (dhd_bus->cbs && dhd_bus->cbs->send_complete) {
1136                     dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo,
1137                                                 status);
1138                 }
1139             }
1140 #else
1141             dbus_if_pktfree(dhd_bus, (void *)pktinfo, TRUE);
1142 #endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) ||              \
1143           defined(BCM_RPC_TOC) */
1144         }
1145     } else {
1146         DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__,
1147                  __LINE__, pktinfo));
1148 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC)
1149         if (pktinfo) {
1150             if (dhd_bus->cbs && dhd_bus->cbs->send_complete) {
1151                 dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, status);
1152             }
1153         }
1154 #else
1155         dbus_if_pktfree(dhd_bus, (void *)pktinfo, TRUE);
1156 #endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY)                 \
1157           defined(BCM_RPC_TOC) */
1158     }
1159 } /* dbus_if_send_irb_complete */
1160 
1161 /**
1162  * When lower DBUS level signals that a receive IRB completed, either successful
1163  * or not, the higher level (e.g. dhd_linux.c) has to be notified, and fresh
1164  * free receive IRBs may have to be given to lower levels.
1165  */
dbus_if_recv_irb_complete(void * handle,dbus_irb_rx_t * rxirb,int status)1166 static void BCMFASTPATH dbus_if_recv_irb_complete(void *handle,
1167                                                   dbus_irb_rx_t *rxirb,
1168                                                   int status)
1169 {
1170     dhd_bus_t *dhd_bus = (dhd_bus_t *)handle;
1171     int rxirb_pending;
1172     struct exec_parms args;
1173 
1174     if ((dhd_bus == NULL) || (rxirb == NULL)) {
1175         return;
1176     }
1177     DBUSTRACE(("%s\n", __FUNCTION__));
1178     if (dhd_bus->pub.busstate != DBUS_STATE_DOWN &&
1179         dhd_bus->pub.busstate != DBUS_STATE_SLEEP) {
1180         if (status == DBUS_OK) {
1181             if ((rxirb->buf != NULL) && (rxirb->actual_len > 0)) {
1182 #ifdef DBUS_USB_LOOPBACK
1183                 if (is_loopback_pkt(rxirb->buf)) {
1184                     matches_loopback_pkt(rxirb->buf);
1185                 } else
1186 #endif
1187                     if (dhd_bus->cbs && dhd_bus->cbs->recv_buf) {
1188                     dhd_bus->cbs->recv_buf(dhd_bus->cbarg, rxirb->buf,
1189                                            rxirb->actual_len);
1190                 }
1191             } else if (rxirb->pkt != NULL) {
1192                 if (dhd_bus->cbs && dhd_bus->cbs->recv_pkt) {
1193                     dhd_bus->cbs->recv_pkt(dhd_bus->cbarg, rxirb->pkt);
1194                 }
1195             } else {
1196                 ASSERT(0); /* Should not happen */
1197             }
1198 
1199             rxirb_pending = dhd_bus->pub.nrxq - dhd_bus->rx_q->cnt - 1;
1200             if ((rxirb_pending <= dhd_bus->rx_low_watermark) &&
1201                 !dhd_bus->rxoff) {
1202                 DBUSTRACE(("Low watermark so submit more %d <= %d \n",
1203                            dhd_bus->rx_low_watermark, rxirb_pending));
1204                 dbus_rxirbs_fill(dhd_bus);
1205             } else if (dhd_bus->rxoff) {
1206                 DBUSTRACE(("rx flow controlled. not filling more. cut_rxq=%d\n",
1207                            dhd_bus->rx_q->cnt));
1208             }
1209         } else if (status == DBUS_ERR_NODEVICE) {
1210             DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__,
1211                      status, rxirb->buf));
1212 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
1213             if (rxirb->buf) {
1214                 PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf);
1215                 PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE);
1216             }
1217 #endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */
1218         } else {
1219             if (status != DBUS_ERR_RXZLP) {
1220                 DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__,
1221                          status, rxirb->buf));
1222             }
1223 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
1224             if (rxirb->buf) {
1225                 PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf);
1226                 PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE);
1227             }
1228 #endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */
1229         }
1230     } else {
1231         DBUSTRACE(("%s: DBUS down, ignoring recv callback. buf %p\n",
1232                    __FUNCTION__, rxirb->buf));
1233 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY)
1234         if (rxirb->buf) {
1235             PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf);
1236             PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE);
1237         }
1238 #endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */
1239     }
1240     if (dhd_bus->rx_q != NULL) {
1241         bzero(rxirb, sizeof(dbus_irb_rx_t));
1242         args.qenq.q = dhd_bus->rx_q;
1243         args.qenq.b = (dbus_irb_t *)rxirb;
1244         EXEC_RXLOCK(dhd_bus, q_enq_exec, &args);
1245     } else {
1246         MFREE(dhd_bus->pub.osh, rxirb, sizeof(dbus_irb_tx_t));
1247     }
1248 } /* dbus_if_recv_irb_complete */
1249 
1250 /**
1251  *  Accumulate errors signaled by lower DBUS levels and signal them to higher
1252  * (e.g. dhd_linux.c) level.
1253  */
dbus_if_errhandler(void * handle,int err)1254 static void dbus_if_errhandler(void *handle, int err)
1255 {
1256     dhd_bus_t *dhd_bus = handle;
1257     uint32 mask = 0;
1258 
1259     if (dhd_bus == NULL) {
1260         return;
1261     }
1262 
1263     switch (err) {
1264         case DBUS_ERR_TXFAIL:
1265             dhd_bus->pub.stats.tx_errors++;
1266             mask |= ERR_CBMASK_TXFAIL;
1267             break;
1268         case DBUS_ERR_TXDROP:
1269             dhd_bus->pub.stats.tx_dropped++;
1270             mask |= ERR_CBMASK_TXFAIL;
1271             break;
1272         case DBUS_ERR_RXFAIL:
1273             dhd_bus->pub.stats.rx_errors++;
1274             mask |= ERR_CBMASK_RXFAIL;
1275             break;
1276         case DBUS_ERR_RXDROP:
1277             dhd_bus->pub.stats.rx_dropped++;
1278             mask |= ERR_CBMASK_RXFAIL;
1279             break;
1280         default:
1281             break;
1282     }
1283 
1284     if (dhd_bus->cbs && dhd_bus->cbs->errhandler && (dhd_bus->errmask & mask)) {
1285         dhd_bus->cbs->errhandler(dhd_bus->cbarg, err);
1286     }
1287 }
1288 
1289 /**
1290  * When lower DBUS level signals control IRB completed, higher level (e.g.
1291  * dhd_linux.c) has to be notified.
1292  */
dbus_if_ctl_complete(void * handle,int type,int status)1293 static void dbus_if_ctl_complete(void *handle, int type, int status)
1294 {
1295     dhd_bus_t *dhd_bus = (dhd_bus_t *)handle;
1296 
1297     DBUSTRACE(("%s\n", __FUNCTION__));
1298 
1299     if (dhd_bus == NULL) {
1300         DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1301         return;
1302     }
1303 
1304     if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) {
1305         if (dhd_bus->cbs && dhd_bus->cbs->ctl_complete) {
1306             dhd_bus->cbs->ctl_complete(dhd_bus->cbarg, type, status);
1307         }
1308     }
1309 }
1310 
1311 /**
1312  * Rx related functionality (flow control, posting of free IRBs to rx queue) is
1313  * dependent upon the bus state. When lower DBUS level signals a change in the
1314  * interface state, take appropriate action and forward the signaling to the
1315  * higher (e.g. dhd_linux.c) level.
1316  */
dbus_if_state_change(void * handle,int state)1317 static void dbus_if_state_change(void *handle, int state)
1318 {
1319     dhd_bus_t *dhd_bus = (dhd_bus_t *)handle;
1320     int old_state;
1321 
1322     if (dhd_bus == NULL) {
1323         return;
1324     }
1325 
1326     if (dhd_bus->pub.busstate == state) {
1327         return;
1328     }
1329     old_state = dhd_bus->pub.busstate;
1330     if (state == DBUS_STATE_DISCONNECT) {
1331         DBUSERR(("DBUS disconnected\n"));
1332     }
1333 
1334     /* Ignore USB SUSPEND while not up yet */
1335     if (state == DBUS_STATE_SLEEP && old_state != DBUS_STATE_UP) {
1336         return;
1337     }
1338 
1339     DBUSTRACE(("dbus state change from %d to to %d\n", old_state, state));
1340 
1341     /* Don't update state if it's PnP firmware re-download */
1342     if (state != DBUS_STATE_PNP_FWDL) {
1343         dhd_bus->pub.busstate = state;
1344     } else {
1345         dbus_flowctrl_rx(handle, FALSE);
1346     }
1347     if (state == DBUS_STATE_SLEEP) {
1348         dbus_flowctrl_rx(handle, TRUE);
1349     }
1350     if (state == DBUS_STATE_UP) {
1351         dbus_rxirbs_fill(dhd_bus);
1352         dbus_flowctrl_rx(handle, FALSE);
1353     }
1354 
1355     if (dhd_bus->cbs && dhd_bus->cbs->state_change) {
1356         dhd_bus->cbs->state_change(dhd_bus->cbarg, state);
1357     }
1358 }
1359 
1360 /** Forward request for packet from lower DBUS layer to higher layer (e.g.
1361  * dhd_linux.c) */
dbus_if_pktget(void * handle,uint len,bool send)1362 static void *dbus_if_pktget(void *handle, uint len, bool send)
1363 {
1364     dhd_bus_t *dhd_bus = (dhd_bus_t *)handle;
1365     void *p = NULL;
1366 
1367     if (dhd_bus == NULL) {
1368         return NULL;
1369     }
1370 
1371     if (dhd_bus->cbs && dhd_bus->cbs->pktget) {
1372         p = dhd_bus->cbs->pktget(dhd_bus->cbarg, len, send);
1373     } else {
1374         ASSERT(0);
1375     }
1376 
1377     return p;
1378 }
1379 
1380 /** Forward request to free packet from lower DBUS layer to higher layer (e.g.
1381  * dhd_linux.c) */
dbus_if_pktfree(void * handle,void * p,bool send)1382 static void dbus_if_pktfree(void *handle, void *p, bool send)
1383 {
1384     dhd_bus_t *dhd_bus = (dhd_bus_t *)handle;
1385 
1386     if (dhd_bus == NULL) {
1387         return;
1388     }
1389 
1390     if (dhd_bus->cbs && dhd_bus->cbs->pktfree) {
1391         dhd_bus->cbs->pktfree(dhd_bus->cbarg, p, send);
1392     } else {
1393         ASSERT(0);
1394     }
1395 }
1396 
1397 /** Lower DBUS level requests either a send or receive IRB */
dbus_if_getirb(void * cbarg,bool send)1398 static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send)
1399 {
1400     dhd_bus_t *dhd_bus = (dhd_bus_t *)cbarg;
1401     struct exec_parms args;
1402     struct dbus_irb *irb;
1403 
1404     if ((dhd_bus == NULL) || (dhd_bus->pub.busstate != DBUS_STATE_UP)) {
1405         return NULL;
1406     }
1407 
1408     if (send == TRUE) {
1409         args.qdeq.q = dhd_bus->tx_q;
1410         irb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args);
1411     } else {
1412         args.qdeq.q = dhd_bus->rx_q;
1413         irb = EXEC_RXLOCK(dhd_bus, q_deq_exec, &args);
1414     }
1415 
1416     return irb;
1417 }
1418 
1419 /**
1420  * Called as part of DBUS bus registration. Calls back into higher level (e.g.
1421  * dhd_linux.c) probe function.
1422  */
dbus_probe(void * arg,const char * desc,uint32 bustype,uint16 bus_no,uint16 slot,uint32 hdrlen)1423 static void *dbus_probe(void *arg, const char *desc, uint32 bustype,
1424                         uint16 bus_no, uint16 slot, uint32 hdrlen)
1425 {
1426     DBUSTRACE(("%s\n", __FUNCTION__));
1427     if (probe_cb) {
1428         disc_arg = probe_cb(probe_arg, desc, bustype, bus_no, slot, hdrlen);
1429         return disc_arg;
1430     }
1431 
1432     return (void *)DBUS_ERR;
1433 }
1434 
1435 /**
1436  * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to
1437  * prepare for action.
1438  */
dhd_bus_register(void)1439 int dhd_bus_register(void)
1440 {
1441     int err;
1442 
1443     DBUSTRACE(("%s: Enter\n", __FUNCTION__));
1444 
1445     probe_cb = dhd_dbus_probe_cb;
1446     disconnect_cb = dhd_dbus_disconnect_cb;
1447     probe_arg = NULL;
1448 
1449     err = dbus_bus_register(
1450         0xa5c, 0x48f, dbus_probe, /* call lower DBUS level register function */
1451         dbus_disconnect, NULL, &g_busintf, NULL, NULL);
1452     /* Device not detected */
1453     if (err == DBUS_ERR_NODEVICE) {
1454         err = DBUS_OK;
1455     }
1456 
1457     return err;
1458 }
1459 
1460 dhd_pub_t *g_pub = NULL;
dhd_bus_unregister(void)1461 void dhd_bus_unregister(void)
1462 {
1463     int ret;
1464 
1465     DBUSTRACE(("%s\n", __FUNCTION__));
1466 
1467     DHD_MUTEX_LOCK();
1468     if (g_pub) {
1469         g_pub->dhd_remove = TRUE;
1470         if (!g_pub->bus) {
1471             dhd_dbus_disconnect_cb(g_pub->bus);
1472         }
1473     }
1474     probe_cb = NULL;
1475     DHD_MUTEX_UNLOCK();
1476     ret = dbus_bus_deregister();
1477     disconnect_cb = NULL;
1478     probe_arg = NULL;
1479 }
1480 
1481 /** As part of initialization, data structures have to be allocated and
1482  * initialized */
dbus_attach(osl_t * osh,int rxsize,int nrxq,int ntxq,dhd_pub_t * pub,dbus_callbacks_t * cbs,dbus_extdl_t * extdl,struct shared_info * sh)1483 dhd_bus_t *dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq,
1484                        dhd_pub_t *pub, dbus_callbacks_t *cbs,
1485                        dbus_extdl_t *extdl, struct shared_info *sh)
1486 {
1487     dhd_bus_t *dhd_bus;
1488     int err;
1489 
1490     if ((g_busintf == NULL) || (g_busintf->attach == NULL) || (cbs == NULL)) {
1491         return NULL;
1492     }
1493 
1494     DBUSTRACE(("%s\n", __FUNCTION__));
1495 
1496     if ((nrxq <= 0) || (ntxq <= 0)) {
1497         return NULL;
1498     }
1499 
1500     dhd_bus = MALLOC(osh, sizeof(dhd_bus_t));
1501     if (dhd_bus == NULL) {
1502         DBUSERR(("%s: malloc failed %zu\n", __FUNCTION__, sizeof(dhd_bus_t)));
1503         return NULL;
1504     }
1505 
1506     bzero(dhd_bus, sizeof(dhd_bus_t));
1507 
1508     /* BUS-specific driver interface (at a lower DBUS level) */
1509     dhd_bus->drvintf = g_busintf;
1510     dhd_bus->cbarg = pub;
1511     dhd_bus->cbs = cbs;
1512 
1513     dhd_bus->pub.sh = sh;
1514     dhd_bus->pub.osh = osh;
1515     dhd_bus->pub.rxsize = rxsize;
1516 
1517     dhd_bus->pub.nrxq = nrxq;
1518     dhd_bus->rx_low_watermark = nrxq / 0x2; /* keep enough posted rx urbs */
1519     dhd_bus->pub.ntxq = ntxq;
1520     dhd_bus->tx_low_watermark =
1521         ntxq / 0x4; /* flow control when too many tx urbs posted */
1522 
1523     dhd_bus->tx_q = MALLOC(osh, sizeof(dbus_irbq_t));
1524     if (dhd_bus->tx_q == NULL) {
1525         goto error;
1526     } else {
1527         bzero(dhd_bus->tx_q, sizeof(dbus_irbq_t));
1528         err =
1529             dbus_irbq_init(dhd_bus, dhd_bus->tx_q, ntxq, sizeof(dbus_irb_tx_t));
1530         if (err != DBUS_OK) {
1531             goto error;
1532         }
1533     }
1534 
1535     dhd_bus->rx_q = MALLOC(osh, sizeof(dbus_irbq_t));
1536     if (dhd_bus->rx_q == NULL) {
1537         goto error;
1538     } else {
1539         bzero(dhd_bus->rx_q, sizeof(dbus_irbq_t));
1540         err =
1541             dbus_irbq_init(dhd_bus, dhd_bus->rx_q, nrxq, sizeof(dbus_irb_rx_t));
1542         if (err != DBUS_OK) {
1543             goto error;
1544         }
1545     }
1546 
1547     dhd_bus->bus_info =
1548         (void *)g_busintf->attach(&dhd_bus->pub, dhd_bus, &dbus_intf_cbs);
1549     if (dhd_bus->bus_info == NULL) {
1550         goto error;
1551     }
1552 
1553     dbus_tx_timer_init(dhd_bus);
1554 
1555 #if defined(BCM_REQUEST_FW)
1556     /* Need to copy external image for re-download */
1557     if (extdl && extdl->fw && (extdl->fwlen > 0)) {
1558         dhd_bus->extdl.fw = MALLOC(osh, extdl->fwlen);
1559         if (dhd_bus->extdl.fw) {
1560             bcopy(extdl->fw, dhd_bus->extdl.fw, extdl->fwlen);
1561             dhd_bus->extdl.fwlen = extdl->fwlen;
1562         }
1563     }
1564 
1565     if (extdl && extdl->vars && (extdl->varslen > 0)) {
1566         dhd_bus->extdl.vars = MALLOC(osh, extdl->varslen);
1567         if (dhd_bus->extdl.vars) {
1568             bcopy(extdl->vars, dhd_bus->extdl.vars, extdl->varslen);
1569             dhd_bus->extdl.varslen = extdl->varslen;
1570         }
1571     }
1572 #endif
1573 
1574     return (dhd_bus_t *)dhd_bus;
1575 
1576 error:
1577     DBUSERR(("%s: Failed\n", __FUNCTION__));
1578     dbus_detach(dhd_bus);
1579     return NULL;
1580 } /* dbus_attach */
1581 
dbus_detach(dhd_bus_t * pub)1582 void dbus_detach(dhd_bus_t *pub)
1583 {
1584     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1585     osl_t *osh;
1586 
1587     DBUSTRACE(("%s\n", __FUNCTION__));
1588 
1589     if (dhd_bus == NULL) {
1590         return;
1591     }
1592 
1593     dbus_tx_timer_stop(dhd_bus);
1594 
1595     osh = pub->pub.osh;
1596 
1597     if (dhd_bus->drvintf && dhd_bus->drvintf->detach) {
1598         dhd_bus->drvintf->detach((dbus_pub_t *)dhd_bus, dhd_bus->bus_info);
1599     }
1600 
1601     if (dhd_bus->tx_q) {
1602         dbus_irbq_deinit(dhd_bus, dhd_bus->tx_q, sizeof(dbus_irb_tx_t));
1603         MFREE(osh, dhd_bus->tx_q, sizeof(dbus_irbq_t));
1604         dhd_bus->tx_q = NULL;
1605     }
1606 
1607     if (dhd_bus->rx_q) {
1608         dbus_irbq_deinit(dhd_bus, dhd_bus->rx_q, sizeof(dbus_irb_rx_t));
1609         MFREE(osh, dhd_bus->rx_q, sizeof(dbus_irbq_t));
1610         dhd_bus->rx_q = NULL;
1611     }
1612 
1613     if (dhd_bus->extdl.fw && (dhd_bus->extdl.fwlen > 0)) {
1614         MFREE(osh, dhd_bus->extdl.fw, dhd_bus->extdl.fwlen);
1615         dhd_bus->extdl.fw = NULL;
1616         dhd_bus->extdl.fwlen = 0;
1617     }
1618 
1619     if (dhd_bus->extdl.vars && (dhd_bus->extdl.varslen > 0)) {
1620         MFREE(osh, dhd_bus->extdl.vars, dhd_bus->extdl.varslen);
1621         dhd_bus->extdl.vars = NULL;
1622         dhd_bus->extdl.varslen = 0;
1623     }
1624 
1625     MFREE(osh, dhd_bus, sizeof(dhd_bus_t));
1626 } /* dbus_detach */
1627 
dbus_dlneeded(dhd_bus_t * pub)1628 int dbus_dlneeded(dhd_bus_t *pub)
1629 {
1630     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1631     int dlneeded = DBUS_ERR;
1632 
1633     if (!dhd_bus) {
1634         DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1635         return DBUS_ERR;
1636     }
1637 
1638     DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate));
1639 
1640     if (dhd_bus->drvintf->dlneeded) {
1641         dlneeded = dhd_bus->drvintf->dlneeded(dhd_bus->bus_info);
1642     }
1643     printf("%s: dlneeded=%d\n", __FUNCTION__, dlneeded);
1644 
1645     /* dlneeded > 0: need to download
1646      * dlneeded = 0: downloaded
1647      * dlneeded < 0: bus error */
1648     return dlneeded;
1649 }
1650 
1651 #if defined(BCM_REQUEST_FW)
dbus_download_firmware(dhd_bus_t * pub,char * pfw_path,char * pnv_path)1652 int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path)
1653 {
1654     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1655     int err = DBUS_OK;
1656 
1657     if (!dhd_bus) {
1658         DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1659         return DBUS_ERR;
1660     }
1661 
1662     DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate));
1663 
1664     dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING;
1665 #ifdef EXTERNAL_FW_PATH
1666     err = dbus_do_download(dhd_bus, pfw_path, pnv_path);
1667 #else
1668     err = dbus_do_download(dhd_bus);
1669 #endif /* EXTERNAL_FW_PATH */
1670     if (err == DBUS_OK) {
1671         dhd_bus->pub.busstate = DBUS_STATE_DL_DONE;
1672     } else {
1673         DBUSERR(("%s: download failed (%d)\n", __FUNCTION__, err));
1674     }
1675 
1676     return err;
1677 }
1678 #endif
1679 
1680 /**
1681  * higher layer requests us to 'up' the interface to the dongle. Prerequisite is
1682  * that firmware (not bootloader) must be active in the dongle.
1683  */
dbus_up(struct dhd_bus * pub)1684 int dbus_up(struct dhd_bus *pub)
1685 {
1686     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1687     int err = DBUS_OK;
1688 
1689     DBUSTRACE(("%s\n", __FUNCTION__));
1690 
1691     if (dhd_bus == NULL) {
1692         DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1693         return DBUS_ERR;
1694     }
1695 
1696     if ((dhd_bus->pub.busstate == DBUS_STATE_DL_DONE) ||
1697         (dhd_bus->pub.busstate == DBUS_STATE_DOWN) ||
1698         (dhd_bus->pub.busstate == DBUS_STATE_SLEEP)) {
1699         if (dhd_bus->drvintf && dhd_bus->drvintf->up) {
1700             err = dhd_bus->drvintf->up(dhd_bus->bus_info);
1701             if (err == DBUS_OK) {
1702                 dbus_rxirbs_fill(dhd_bus);
1703             }
1704         }
1705     } else {
1706         err = DBUS_ERR;
1707     }
1708     return err;
1709 }
1710 
1711 /** higher layer requests us to 'down' the interface to the dongle. */
dbus_down(dbus_pub_t * pub)1712 int dbus_down(dbus_pub_t *pub)
1713 {
1714     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1715 
1716     DBUSTRACE(("%s\n", __FUNCTION__));
1717 
1718     if (dhd_bus == NULL) {
1719         return DBUS_ERR;
1720     }
1721 
1722     dbus_tx_timer_stop(dhd_bus);
1723 
1724     if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
1725         dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
1726         if (dhd_bus->drvintf && dhd_bus->drvintf->down) {
1727             return dhd_bus->drvintf->down(dhd_bus->bus_info);
1728         }
1729     }
1730 
1731     return DBUS_ERR;
1732 }
1733 
dbus_shutdown(dbus_pub_t * pub)1734 int dbus_shutdown(dbus_pub_t *pub)
1735 {
1736     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1737 
1738     DBUSTRACE(("%s\n", __FUNCTION__));
1739 
1740     if (dhd_bus == NULL) {
1741         return DBUS_ERR;
1742     }
1743 
1744     if (dhd_bus->drvintf && dhd_bus->drvintf->shutdown) {
1745         return dhd_bus->drvintf->shutdown(dhd_bus->bus_info);
1746     }
1747 
1748     return DBUS_OK;
1749 }
1750 
dbus_stop(struct dhd_bus * pub)1751 int dbus_stop(struct dhd_bus *pub)
1752 {
1753     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1754 
1755     DBUSTRACE(("%s\n", __FUNCTION__));
1756 
1757     if (dhd_bus == NULL) {
1758         return DBUS_ERR;
1759     }
1760 
1761     if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
1762         dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
1763         if (dhd_bus->drvintf && dhd_bus->drvintf->stop) {
1764             return dhd_bus->drvintf->stop(dhd_bus->bus_info);
1765         }
1766     }
1767 
1768     return DBUS_ERR;
1769 }
1770 
dbus_send_txdata(dbus_pub_t * dbus,void * pktbuf)1771 int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf)
1772 {
1773     return dbus_send_pkt(dbus, pktbuf, pktbuf /* pktinfo */);
1774 }
1775 
dbus_send_buf(dbus_pub_t * pub,uint8 * buf,int len,void * info)1776 int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info)
1777 {
1778     return dbus_send_irb(pub, buf, len, NULL, info);
1779 }
1780 
dbus_send_pkt(dbus_pub_t * pub,void * pkt,void * info)1781 int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info)
1782 {
1783     return dbus_send_irb(pub, NULL, 0, pkt, info);
1784 }
1785 
dbus_send_ctl(struct dhd_bus * pub,uint8 * buf,int len)1786 int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len)
1787 {
1788     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1789 
1790     if (dhd_bus == NULL) {
1791         DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1792         return DBUS_ERR;
1793     }
1794 
1795     if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
1796         dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
1797         if (dhd_bus->drvintf && dhd_bus->drvintf->send_ctl) {
1798             return dhd_bus->drvintf->send_ctl(dhd_bus->bus_info, buf, len);
1799         }
1800     } else {
1801         DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate));
1802     }
1803 
1804     return DBUS_ERR;
1805 }
1806 
dbus_recv_ctl(struct dhd_bus * pub,uint8 * buf,int len)1807 int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len)
1808 {
1809     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1810 
1811     if ((dhd_bus == NULL) || (buf == NULL)) {
1812         return DBUS_ERR;
1813     }
1814 
1815     if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
1816         dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
1817         if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl) {
1818             return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len);
1819         }
1820     }
1821 
1822     return DBUS_ERR;
1823 }
1824 
1825 /** Only called via RPC (Dec 2012) */
dbus_recv_bulk(dbus_pub_t * pub,uint32 ep_idx)1826 int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx)
1827 {
1828     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1829 
1830     dbus_irb_rx_t *rxirb;
1831     struct exec_parms args;
1832     int status;
1833 
1834     if (dhd_bus == NULL) {
1835         return DBUS_ERR;
1836     }
1837 
1838     args.qdeq.q = dhd_bus->rx_q;
1839     if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
1840         if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) {
1841             if ((rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) {
1842                 status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info,
1843                                                             rxirb, ep_idx);
1844                 if (status == DBUS_ERR_RXDROP) {
1845                     bzero(rxirb, sizeof(dbus_irb_rx_t));
1846                     args.qenq.q = dhd_bus->rx_q;
1847                     args.qenq.b = (dbus_irb_t *)rxirb;
1848                     EXEC_RXLOCK(dhd_bus, q_enq_exec, &args);
1849                 }
1850             }
1851         }
1852     }
1853 
1854     return DBUS_ERR;
1855 }
1856 
1857 /** only called by dhd_cdc.c (Dec 2012) */
dbus_poll_intr(dbus_pub_t * pub)1858 int dbus_poll_intr(dbus_pub_t *pub)
1859 {
1860     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1861 
1862     int status = DBUS_ERR;
1863 
1864     if (dhd_bus == NULL) {
1865         return DBUS_ERR;
1866     }
1867 
1868     if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
1869         if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) {
1870             status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info, NULL,
1871                                                         0xff);
1872         }
1873     }
1874     return status;
1875 }
1876 
1877 /** called by nobody (Dec 2012) */
dbus_pktget(dbus_pub_t * pub,int len)1878 void *dbus_pktget(dbus_pub_t *pub, int len)
1879 {
1880     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1881 
1882     if ((dhd_bus == NULL) || (len < 0)) {
1883         return NULL;
1884     }
1885 
1886     return PKTGET(dhd_bus->pub.osh, len, TRUE);
1887 }
1888 
1889 /** called by nobody (Dec 2012) */
dbus_pktfree(dbus_pub_t * pub,void * pkt)1890 void dbus_pktfree(dbus_pub_t *pub, void *pkt)
1891 {
1892     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1893 
1894     if ((dhd_bus == NULL) || (pkt == NULL)) {
1895         return;
1896     }
1897 
1898     PKTFREE(dhd_bus->pub.osh, pkt, TRUE);
1899 }
1900 
1901 /** called by nobody (Dec 2012) */
dbus_get_stats(dbus_pub_t * pub,dbus_stats_t * stats)1902 int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats)
1903 {
1904     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1905 
1906     if ((dhd_bus == NULL) || (stats == NULL)) {
1907         return DBUS_ERR;
1908     }
1909 
1910     bcopy(&dhd_bus->pub.stats, stats, sizeof(dbus_stats_t));
1911 
1912     return DBUS_OK;
1913 }
1914 
dbus_get_attrib(dhd_bus_t * pub,dbus_attrib_t * attrib)1915 int dbus_get_attrib(dhd_bus_t *pub, dbus_attrib_t *attrib)
1916 {
1917     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1918     int err = DBUS_ERR;
1919 
1920     if ((dhd_bus == NULL) || (attrib == NULL)) {
1921         return DBUS_ERR;
1922     }
1923 
1924     if (dhd_bus->drvintf && dhd_bus->drvintf->get_attrib) {
1925         err = dhd_bus->drvintf->get_attrib(dhd_bus->bus_info,
1926                                            &dhd_bus->pub.attrib);
1927     }
1928 
1929     bcopy(&dhd_bus->pub.attrib, attrib, sizeof(dbus_attrib_t));
1930     return err;
1931 }
1932 
dbus_get_device_speed(dbus_pub_t * pub)1933 int dbus_get_device_speed(dbus_pub_t *pub)
1934 {
1935     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1936 
1937     if (dhd_bus == NULL) {
1938         return INVALID_SPEED;
1939     }
1940 
1941     return (dhd_bus->pub.device_speed);
1942 }
1943 
dbus_set_config(dbus_pub_t * pub,dbus_config_t * config)1944 int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config)
1945 {
1946     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1947     int err = DBUS_ERR;
1948 
1949     if ((dhd_bus == NULL) || (config == NULL)) {
1950         return DBUS_ERR;
1951     }
1952 
1953     if (dhd_bus->drvintf && dhd_bus->drvintf->set_config) {
1954         err = dhd_bus->drvintf->set_config(dhd_bus->bus_info, config);
1955         if ((config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) && (!err) &&
1956             (dhd_bus->pub.busstate == DBUS_STATE_UP)) {
1957             dbus_rxirbs_fill(dhd_bus);
1958         }
1959     }
1960     return err;
1961 }
1962 
dbus_get_config(dbus_pub_t * pub,dbus_config_t * config)1963 int dbus_get_config(dbus_pub_t *pub, dbus_config_t *config)
1964 {
1965     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1966     int err = DBUS_ERR;
1967 
1968     if ((dhd_bus == NULL) || (config == NULL)) {
1969         return DBUS_ERR;
1970     }
1971 
1972     if (dhd_bus->drvintf && dhd_bus->drvintf->get_config) {
1973         err = dhd_bus->drvintf->get_config(dhd_bus->bus_info, config);
1974     }
1975 
1976     return err;
1977 }
1978 
dbus_set_errmask(dbus_pub_t * pub,uint32 mask)1979 int dbus_set_errmask(dbus_pub_t *pub, uint32 mask)
1980 {
1981     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1982     int err = DBUS_OK;
1983 
1984     if (dhd_bus == NULL) {
1985         return DBUS_ERR;
1986     }
1987 
1988     dhd_bus->errmask = mask;
1989     return err;
1990 }
1991 
dbus_pnp_resume(dbus_pub_t * pub,int * fw_reload)1992 int dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload)
1993 {
1994     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
1995     int err = DBUS_ERR;
1996     bool fwdl = FALSE;
1997 
1998     DBUSTRACE(("%s\n", __FUNCTION__));
1999 
2000     if (dhd_bus == NULL) {
2001         return DBUS_ERR;
2002     }
2003 
2004     if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
2005         return DBUS_OK;
2006     }
2007 
2008     if (dhd_bus->drvintf->pnp) {
2009         err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, DBUS_PNP_RESUME);
2010     }
2011 
2012     if (dhd_bus->drvintf->recv_needed) {
2013         if (dhd_bus->drvintf->recv_needed(dhd_bus->bus_info)) {
2014             /* Refill after sleep/hibernate */
2015             dbus_rxirbs_fill(dhd_bus);
2016         }
2017     }
2018 
2019     if (fw_reload) {
2020         *fw_reload = fwdl;
2021     }
2022 
2023     return err;
2024 } /* dbus_pnp_resume */
2025 
dbus_pnp_sleep(dbus_pub_t * pub)2026 int dbus_pnp_sleep(dbus_pub_t *pub)
2027 {
2028     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
2029     int err = DBUS_ERR;
2030 
2031     DBUSTRACE(("%s\n", __FUNCTION__));
2032 
2033     if (dhd_bus == NULL) {
2034         return DBUS_ERR;
2035     }
2036 
2037     dbus_tx_timer_stop(dhd_bus);
2038 
2039     if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) {
2040         err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, DBUS_PNP_SLEEP);
2041     }
2042 
2043     return err;
2044 }
2045 
dbus_pnp_disconnect(dbus_pub_t * pub)2046 int dbus_pnp_disconnect(dbus_pub_t *pub)
2047 {
2048     dhd_bus_t *dhd_bus = (dhd_bus_t *)pub;
2049     int err = DBUS_ERR;
2050 
2051     DBUSTRACE(("%s\n", __FUNCTION__));
2052 
2053     if (dhd_bus == NULL) {
2054         return DBUS_ERR;
2055     }
2056 
2057     dbus_tx_timer_stop(dhd_bus);
2058 
2059     if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) {
2060         err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, DBUS_PNP_DISCONNECT);
2061     }
2062 
2063     return err;
2064 }
2065 
dhd_bus_iovar_op(dhd_pub_t * dhdp,const char * name,void * params,int plen,void * arg,int len,bool set)2066 int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, void *params, int plen,
2067                      void *arg, int len, bool set)
2068 {
2069     dhd_bus_t *dhd_bus = (dhd_bus_t *)dhdp->bus;
2070     int err = DBUS_ERR;
2071 
2072     DBUSTRACE(("%s\n", __FUNCTION__));
2073 
2074     if (dhd_bus == NULL) {
2075         return DBUS_ERR;
2076     }
2077 
2078     if (dhd_bus->drvintf && dhd_bus->drvintf->iovar_op) {
2079         err = dhd_bus->drvintf->iovar_op(dhd_bus->bus_info, name, params, plen,
2080                                          arg, len, set);
2081     }
2082 
2083     return err;
2084 }
2085 
dhd_dbus_txq(const dbus_pub_t * pub)2086 void *dhd_dbus_txq(const dbus_pub_t *pub)
2087 {
2088     return NULL;
2089 }
2090 
dhd_dbus_hdrlen(const dbus_pub_t * pub)2091 uint dhd_dbus_hdrlen(const dbus_pub_t *pub)
2092 {
2093     return 0;
2094 }
2095 
dbus_get_devinfo(dbus_pub_t * pub)2096 void *dbus_get_devinfo(dbus_pub_t *pub)
2097 {
2098     return pub->dev_info;
2099 }
2100 
2101 #if defined(BCM_REQUEST_FW) && !defined(EXTERNAL_FW_PATH)
dbus_otp(dhd_bus_t * dhd_bus,uint16 * boardtype,uint16 * boardrev)2102 static int dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev)
2103 {
2104     uint32 value = 0;
2105     uint8 *cis;
2106     uint16 *otpinfo;
2107     uint32 i;
2108     bool standard_cis = TRUE;
2109     uint8 tup, tlen;
2110     bool btype_present = FALSE;
2111     bool brev_present = FALSE;
2112     int ret;
2113     int devid;
2114     uint16 btype = 0;
2115     uint16 brev = 0;
2116     uint32 otp_size = 0, otp_addr = 0, otp_sw_rgn = 0;
2117 
2118     if (dhd_bus == NULL || dhd_bus->drvintf == NULL ||
2119         dhd_bus->drvintf->readreg == NULL) {
2120         return DBUS_ERR;
2121     }
2122 
2123     devid = dhd_bus->pub.attrib.devid;
2124 
2125     if ((devid == BCM43234_CHIP_ID) || (devid == BCM43235_CHIP_ID) ||
2126         (devid == BCM43236_CHIP_ID)) {
2127         otp_size = BCM_OTP_SIZE_43236;
2128         otp_sw_rgn = BCM_OTP_SW_RGN_43236;
2129         otp_addr = BCM_OTP_ADDR_43236;
2130     } else {
2131         return DBUS_ERR_NVRAM;
2132     }
2133 
2134     cis = MALLOC(dhd_bus->pub.osh, otp_size * 0x2);
2135     if (cis == NULL) {
2136         return DBUS_ERR;
2137     }
2138 
2139     otpinfo = (uint16 *)cis;
2140 
2141     for (i = 0; i < otp_size; i++) {
2142         ret = dhd_bus->drvintf->readreg(
2143             dhd_bus->bus_info, otp_addr + ((otp_sw_rgn + i) << 1), 0x2, &value);
2144         if (ret != DBUS_OK) {
2145             MFREE(dhd_bus->pub.osh, cis, otp_size * 0x2);
2146             return ret;
2147         }
2148         otpinfo[i] = (uint16)value;
2149     }
2150 
2151     for (i = 0; i < (otp_size << 1);) {
2152         if (standard_cis) {
2153             tup = cis[i++];
2154             if (tup == CISTPL_NULL || tup == CISTPL_END) {
2155                 tlen = 0;
2156             } else {
2157                 tlen = cis[i++];
2158             }
2159         } else {
2160             if (cis[i] == CISTPL_NULL || cis[i] == CISTPL_END) {
2161                 tlen = 0;
2162                 tup = cis[i];
2163             } else {
2164                 tlen = cis[i];
2165                 tup = CISTPL_BRCM_HNBU;
2166             }
2167             ++i;
2168         }
2169 
2170         if (tup == CISTPL_END || (i + tlen) >= (otp_size << 1)) {
2171             break;
2172         }
2173 
2174         if (tup == CISTPL_BRCM_HNBU) {
2175             switch (cis[i]) {
2176                 case HNBU_BOARDTYPE:
2177                     btype = (uint16)((cis[i + 0x2] << 0x8) + cis[i + 1]);
2178                     btype_present = TRUE;
2179                     DBUSTRACE(("%s: HNBU_BOARDTYPE = 0x%2x\n", __FUNCTION__,
2180                                 (uint32)btype));
2181                     break;
2182                 case HNBU_BOARDREV:
2183                     if (tlen == 0x2) {
2184                         brev = (uint16)cis[i + 1];
2185                     } else {
2186                         brev = (uint16)((cis[i + 0x2] << 0x8) + cis[i + 1]);
2187                     }
2188                     brev_present = TRUE;
2189                     DBUSTRACE(("%s: HNBU_BOARDREV =  0x%2x\n", __FUNCTION__,
2190                                 (uint32)*boardrev));
2191                     break;
2192                 case HNBU_HNBUCIS:
2193                     DBUSTRACE(("%s: HNBU_HNBUCIS\n", __FUNCTION__));
2194                     tlen++;
2195                     standard_cis = FALSE;
2196                     break;
2197             }
2198         }
2199         i += tlen;
2200     }
2201 
2202     MFREE(dhd_bus->pub.osh, cis, otp_size * 0x2);
2203 
2204     if (btype_present == TRUE && brev_present == TRUE) {
2205         *boardtype = btype;
2206         *boardrev = brev;
2207         DBUSERR(("otp boardtype = 0x%2x boardrev = 0x%2x\n", *boardtype,
2208                  *boardrev));
2209 
2210         return DBUS_OK;
2211     } else {
2212         return DBUS_ERR;
2213     }
2214 } /* dbus_otp */
2215 
dbus_select_nvram(dhd_bus_t * dhd_bus,int8 * jumbonvram,int jumbolen,uint16 boardtype,uint16 boardrev,int8 ** nvram,int * nvram_len)2216 static int dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen,
2217                              uint16 boardtype, uint16 boardrev, int8 **nvram,
2218                              int *nvram_len)
2219 {
2220     /* Multi board nvram file format is contenation of nvram info with \r
2221      *  The file format for two contatenated set is
2222      *  \nBroadcom Jumbo Nvram file\nfirst_set\nsecond_set\nthird_set\n
2223      */
2224     uint8 *nvram_start = NULL, *nvram_end = NULL;
2225     uint8 *nvram_start_prev = NULL, *nvram_end_prev = NULL;
2226     uint16 btype = 0, brev = 0;
2227     int len = 0;
2228     char *field;
2229 
2230     *nvram = NULL;
2231     *nvram_len = 0;
2232 
2233     if (strncmp(BCM_JUMBO_START, jumbonvram, strlen(BCM_JUMBO_START))) {
2234         /* single nvram file in the native format */
2235         DBUSTRACE(("%s: Non-Jumbo NVRAM File \n", __FUNCTION__));
2236         *nvram = jumbonvram;
2237         *nvram_len = jumbolen;
2238         return DBUS_OK;
2239     } else {
2240         DBUSTRACE(("%s: Jumbo NVRAM File \n", __FUNCTION__));
2241     }
2242 
2243     /* sanity test the end of the config sets for proper ending */
2244     if (jumbonvram[jumbolen - 1] != BCM_JUMBO_NVRAM_DELIMIT ||
2245         jumbonvram[jumbolen - 0x2] != '\0') {
2246         DBUSERR(("%s: Bad Jumbo NVRAM file format\n", __FUNCTION__));
2247         return DBUS_JUMBO_BAD_FORMAT;
2248     }
2249 
2250     dhd_bus->nvram_nontxt = DBUS_NVRAM_NONTXT;
2251 
2252     nvram_start = jumbonvram;
2253 
2254     while (*nvram_start != BCM_JUMBO_NVRAM_DELIMIT && len < jumbolen) {
2255         /* consume the  first file info line
2256          * \nBroadcom Jumbo Nvram file\nfile1\n ...
2257          */
2258         len++;
2259         nvram_start++;
2260     }
2261 
2262     nvram_end = nvram_start;
2263 
2264     /* search for "boardrev=0xabcd" and "boardtype=0x1234" information in
2265      * the concatenated nvram config files /sets
2266      */
2267 
2268     while (len < jumbolen) {
2269         if (*nvram_end == '\0') {
2270             /* end of a config set is marked by multiple null characters */
2271             len++;
2272             nvram_end++;
2273             DBUSTRACE(("%s: NULL chr len = %d char = 0x%x\n", __FUNCTION__, len,
2274                        *nvram_end));
2275             continue;
2276         } else if (*nvram_end == BCM_JUMBO_NVRAM_DELIMIT) {
2277             /* config set delimiter is reached */
2278             /* check if next config set is present or not
2279              *  return  if next config is not present
2280              */
2281 
2282             /* start search the next config set */
2283             nvram_start_prev = nvram_start;
2284             nvram_end_prev = nvram_end;
2285 
2286             nvram_end++;
2287             nvram_start = nvram_end;
2288             btype = brev = 0;
2289             DBUSTRACE(("%s: going to next record len = %d "
2290                        "char = 0x%x \n",
2291                        __FUNCTION__, len, *nvram_end));
2292             len++;
2293             if (len >= jumbolen) {
2294                 *nvram = nvram_start_prev;
2295                 *nvram_len = (int)(nvram_end_prev - nvram_start_prev);
2296 
2297                 DBUSTRACE(("%s: no more len = %d nvram_end = 0x%p",
2298                            __FUNCTION__, len, nvram_end));
2299 
2300                 return DBUS_JUMBO_NOMATCH;
2301             } else {
2302                 continue;
2303             }
2304         } else {
2305             DBUSTRACE(("%s: config str = %s\n", __FUNCTION__, nvram_end));
2306             if (bcmp(nvram_end, "boardtype", strlen("boardtype")) == 0) {
2307                 field = strchr(nvram_end, '=');
2308                 field++;
2309                 btype = (uint16)bcm_strtoul(field, NULL, 0);
2310 
2311                 DBUSTRACE(("%s: btype = 0x%x boardtype = 0x%x \n", __FUNCTION__,
2312                            btype, boardtype));
2313             }
2314 
2315             if (bcmp(nvram_end, "boardrev", strlen("boardrev")) == 0) {
2316                 field = strchr(nvram_end, '=');
2317                 field++;
2318                 brev = (uint16)bcm_strtoul(field, NULL, 0);
2319 
2320                 DBUSTRACE(("%s: brev = 0x%x boardrev = 0x%x \n", __FUNCTION__,
2321                            brev, boardrev));
2322             }
2323             if (btype == boardtype && brev == boardrev) {
2324                 /* locate nvram config set end - ie.find '\r' char */
2325                 while (*nvram_end != BCM_JUMBO_NVRAM_DELIMIT) {
2326                     nvram_end++;
2327                 }
2328                 *nvram = nvram_start;
2329                 *nvram_len = (int)(nvram_end - nvram_start);
2330                 DBUSTRACE(("found len = %d nvram_start = 0x%p "
2331                            "nvram_end = 0x%p\n",
2332                            *nvram_len, nvram_start, nvram_end));
2333                 return DBUS_OK;
2334             }
2335 
2336             len += (strlen(nvram_end) + 1);
2337             nvram_end += (strlen(nvram_end) + 1);
2338         }
2339     }
2340     return DBUS_JUMBO_NOMATCH;
2341 } /* dbus_select_nvram */
2342 
2343 #endif
2344 
2345 #define DBUS_NRXQ 50
2346 #define DBUS_NTXQ 100
2347 
dhd_dbus_send_complete(void * handle,void * info,int status)2348 static void dhd_dbus_send_complete(void *handle, void *info, int status)
2349 {
2350     dhd_pub_t *dhd = (dhd_pub_t *)handle;
2351     void *pkt = info;
2352 
2353     if ((dhd == NULL) || (pkt == NULL)) {
2354         DBUSERR(("dhd or pkt is NULL\n"));
2355         return;
2356     }
2357 
2358     if (status == DBUS_OK) {
2359         dhd->dstats.tx_packets++;
2360     } else {
2361         DBUSERR(("TX error=%d\n", status));
2362         dhd->dstats.tx_errors++;
2363     }
2364 #ifdef PROP_TXSTATUS
2365     if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) &&
2366         (dhd_wlfc_txcomplete(dhd, pkt, status == 0) != WLFC_UNSUPPORTED)) {
2367         return;
2368     }
2369 #endif /* PROP_TXSTATUS */
2370     PKTFREE(dhd->osh, pkt, TRUE);
2371 }
2372 
dhd_dbus_recv_pkt(void * handle,void * pkt)2373 static void dhd_dbus_recv_pkt(void *handle, void *pkt)
2374 {
2375     uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
2376     uint reorder_info_len;
2377     uint pkt_count;
2378     dhd_pub_t *dhd = (dhd_pub_t *)handle;
2379     int ifidx = 0;
2380 
2381     if (dhd == NULL) {
2382         DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2383         return;
2384     }
2385 
2386     /* If the protocol uses a data header, check and remove it */
2387     if (dhd_prot_hdrpull(dhd, &ifidx, pkt, reorder_info_buf,
2388                          &reorder_info_len) != 0) {
2389         DBUSERR(("rx protocol error\n"));
2390         PKTFREE(dhd->osh, pkt, FALSE);
2391         dhd->rx_errors++;
2392         return;
2393     }
2394 
2395     if (reorder_info_len) {
2396         /* Reordering info from the firmware */
2397         dhd_process_pkt_reorder_info(dhd, reorder_info_buf, reorder_info_len,
2398                                      &pkt, &pkt_count);
2399         if (pkt_count == 0) {
2400             return;
2401         }
2402     } else {
2403         pkt_count = 1;
2404     }
2405     dhd_rx_frame(dhd, ifidx, pkt, pkt_count, 0);
2406 }
2407 
dhd_dbus_recv_buf(void * handle,uint8 * buf,int len)2408 static void dhd_dbus_recv_buf(void *handle, uint8 *buf, int len)
2409 {
2410     dhd_pub_t *dhd = (dhd_pub_t *)handle;
2411     void *pkt;
2412 
2413     if (dhd == NULL) {
2414         DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2415         return;
2416     }
2417 
2418     if ((pkt = PKTGET(dhd->osh, len, FALSE)) == NULL) {
2419         DBUSERR(("PKTGET (rx) failed=%d\n", len));
2420         return;
2421     }
2422 
2423     bcopy(buf, PKTDATA(dhd->osh, pkt), len);
2424     dhd_dbus_recv_pkt(dhd, pkt);
2425 }
2426 
dhd_dbus_txflowcontrol(void * handle,bool onoff)2427 static void dhd_dbus_txflowcontrol(void *handle, bool onoff)
2428 {
2429     dhd_pub_t *dhd = (dhd_pub_t *)handle;
2430     bool wlfc_enabled = FALSE;
2431 
2432     if (dhd == NULL) {
2433         DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2434         return;
2435     }
2436 
2437 #ifdef PROP_TXSTATUS
2438     wlfc_enabled =
2439         (dhd_wlfc_flowcontrol(dhd, onoff, !onoff) != WLFC_UNSUPPORTED);
2440 #endif
2441     if (!wlfc_enabled) {
2442         dhd_txflowcontrol(dhd, ALL_INTERFACES, onoff);
2443     }
2444 }
2445 
dhd_dbus_errhandler(void * handle,int err)2446 static void dhd_dbus_errhandler(void *handle, int err)
2447 {
2448 }
2449 
dhd_dbus_ctl_complete(void * handle,int type,int status)2450 static void dhd_dbus_ctl_complete(void *handle, int type, int status)
2451 {
2452     dhd_pub_t *dhd = (dhd_pub_t *)handle;
2453 
2454     if (dhd == NULL) {
2455         DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2456         return;
2457     }
2458 
2459     if (type == DBUS_CBCTL_READ) {
2460         if (status == DBUS_OK) {
2461             dhd->rx_ctlpkts++;
2462         } else {
2463             dhd->rx_ctlerrs++;
2464         }
2465     } else if (type == DBUS_CBCTL_WRITE) {
2466         if (status == DBUS_OK) {
2467             dhd->tx_ctlpkts++;
2468         } else {
2469             dhd->tx_ctlerrs++;
2470         }
2471     }
2472 
2473     dhd_prot_ctl_complete(dhd);
2474 }
2475 
dhd_dbus_state_change(void * handle,int state)2476 static void dhd_dbus_state_change(void *handle, int state)
2477 {
2478     dhd_pub_t *dhd = (dhd_pub_t *)handle;
2479 
2480     if (dhd == NULL) {
2481         DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2482         return;
2483     }
2484 
2485     switch (state) {
2486         case DBUS_STATE_DL_NEEDED:
2487             DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__));
2488             break;
2489         case DBUS_STATE_DOWN:
2490             DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__));
2491             dhd->busstate = DHD_BUS_DOWN;
2492             break;
2493         case DBUS_STATE_UP:
2494             DBUSTRACE(("%s: DBUS is up\n", __FUNCTION__));
2495             dhd->busstate = DHD_BUS_DATA;
2496             break;
2497         default:
2498             break;
2499     }
2500 
2501     DBUSERR(("%s: DBUS current state=%d\n", __FUNCTION__, state));
2502 }
2503 
dhd_dbus_pktget(void * handle,uint len,bool send)2504 static void *dhd_dbus_pktget(void *handle, uint len, bool send)
2505 {
2506     dhd_pub_t *dhd = (dhd_pub_t *)handle;
2507     void *p = NULL;
2508 
2509     if (dhd == NULL) {
2510         DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2511         return NULL;
2512     }
2513 
2514     if (send == TRUE) {
2515         dhd_os_sdlock_txq(dhd);
2516         p = PKTGET(dhd->osh, len, TRUE);
2517         dhd_os_sdunlock_txq(dhd);
2518     } else {
2519         dhd_os_sdlock_rxq(dhd);
2520         p = PKTGET(dhd->osh, len, FALSE);
2521         dhd_os_sdunlock_rxq(dhd);
2522     }
2523 
2524     return p;
2525 }
2526 
dhd_dbus_pktfree(void * handle,void * p,bool send)2527 static void dhd_dbus_pktfree(void *handle, void *p, bool send)
2528 {
2529     dhd_pub_t *dhd = (dhd_pub_t *)handle;
2530 
2531     if (dhd == NULL) {
2532         DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2533         return;
2534     }
2535 
2536     if (send == TRUE) {
2537 #ifdef PROP_TXSTATUS
2538         if (DHD_PKTTAG_WLFCPKT(PKTTAG(p)) &&
2539             (dhd_wlfc_txcomplete(dhd, p, FALSE) != WLFC_UNSUPPORTED)) {
2540             return;
2541         }
2542 #endif /* PROP_TXSTATUS */
2543 
2544         dhd_os_sdlock_txq(dhd);
2545         PKTFREE(dhd->osh, p, TRUE);
2546         dhd_os_sdunlock_txq(dhd);
2547     } else {
2548         dhd_os_sdlock_rxq(dhd);
2549         PKTFREE(dhd->osh, p, FALSE);
2550         dhd_os_sdunlock_rxq(dhd);
2551     }
2552 }
2553 
2554 static dbus_callbacks_t dhd_dbus_cbs = {
2555     dhd_dbus_send_complete, dhd_dbus_recv_buf,   dhd_dbus_recv_pkt,
2556     dhd_dbus_txflowcontrol, dhd_dbus_errhandler, dhd_dbus_ctl_complete,
2557     dhd_dbus_state_change,  dhd_dbus_pktget,     dhd_dbus_pktfree};
2558 
dhd_bus_chip(struct dhd_bus * bus)2559 uint dhd_bus_chip(struct dhd_bus *bus)
2560 {
2561     ASSERT(bus != NULL);
2562     return bus->pub.attrib.devid;
2563 }
2564 
dhd_bus_chiprev(struct dhd_bus * bus)2565 uint dhd_bus_chiprev(struct dhd_bus *bus)
2566 {
2567     ASSERT(bus);
2568     ASSERT(bus != NULL);
2569     return bus->pub.attrib.chiprev;
2570 }
2571 
dhd_bus_dump(dhd_pub_t * dhdp,struct bcmstrbuf * strbuf)2572 void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2573 {
2574     bcm_bprintf(strbuf, "Bus USB\n");
2575 }
2576 
dhd_bus_clearcounts(dhd_pub_t * dhdp)2577 void dhd_bus_clearcounts(dhd_pub_t *dhdp)
2578 {
2579 }
2580 
dhd_bus_txdata(struct dhd_bus * bus,void * pktbuf)2581 int dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf)
2582 {
2583     DBUSTRACE(("%s\n", __FUNCTION__));
2584     if (bus->txoff) {
2585         DBUSTRACE(("txoff\n"));
2586         return BCME_EPERM;
2587     }
2588     return dbus_send_txdata(&bus->pub, pktbuf);
2589 }
2590 
dhd_dbus_advertise_bus_cleanup(dhd_pub_t * dhdp)2591 static void dhd_dbus_advertise_bus_cleanup(dhd_pub_t *dhdp)
2592 {
2593     unsigned long flags;
2594     int timeleft;
2595 
2596     DHD_LINUX_GENERAL_LOCK(dhdp, flags);
2597     dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS;
2598     DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
2599 
2600     timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
2601     if ((timeleft == 0) || (timeleft == 1)) {
2602         DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", __FUNCTION__,
2603                  dhdp->dhd_bus_busy_state));
2604         ASSERT(0);
2605     }
2606 
2607     return;
2608 }
2609 
dhd_dbus_advertise_bus_remove(dhd_pub_t * dhdp)2610 static void dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp)
2611 {
2612     unsigned long flags;
2613     int timeleft;
2614 
2615     DHD_LINUX_GENERAL_LOCK(dhdp, flags);
2616     dhdp->busstate = DHD_BUS_REMOVE;
2617     DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
2618 
2619     timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
2620     if ((timeleft == 0) || (timeleft == 1)) {
2621         DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", __FUNCTION__,
2622                  dhdp->dhd_bus_busy_state));
2623         ASSERT(0);
2624     }
2625 
2626     return;
2627 }
2628 
dhd_bus_devreset(dhd_pub_t * dhdp,uint8 flag)2629 int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
2630 {
2631     int bcmerror = 0;
2632     unsigned long flags;
2633     wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)dhdp->adapter;
2634 
2635     if (flag == TRUE) {
2636         if (!dhdp->dongle_reset) {
2637             DBUSERR(("%s: == Power OFF ==\n", __FUNCTION__));
2638             dhd_dbus_advertise_bus_cleanup(dhdp);
2639             dhd_os_wd_timer(dhdp, 0);
2640 #if !defined(IGNORE_ETH0_DOWN)
2641             /* Force flow control as protection when stop come before
2642              * ifconfig_down */
2643             dhd_txflowcontrol(dhdp, ALL_INTERFACES, ON);
2644 #endif /* !defined(IGNORE_ETH0_DOWN) */
2645             dbus_stop(dhdp->bus);
2646 
2647             dhdp->dongle_reset = TRUE;
2648             dhdp->up = FALSE;
2649 
2650             DHD_LINUX_GENERAL_LOCK(dhdp, flags);
2651             dhdp->busstate = DHD_BUS_DOWN;
2652             DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
2653             wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY);
2654 
2655             printf("%s:  WLAN OFF DONE\n", __FUNCTION__);
2656             /* App can now remove power from device */
2657         } else {
2658             bcmerror = BCME_ERROR;
2659         }
2660     } else {
2661         /* App must have restored power to device before calling */
2662         printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
2663         if (dhdp->dongle_reset) {
2664             /* Turn on WLAN */
2665             DHD_MUTEX_UNLOCK();
2666             wait_event_interruptible_timeout(
2667                 adapter->status_event,
2668                 wifi_get_adapter_status(adapter, WIFI_STATUS_FW_READY),
2669                 msecs_to_jiffies(DHD_FW_READY_TIMEOUT));
2670             DHD_MUTEX_LOCK();
2671             bcmerror = dbus_up(dhdp->bus);
2672             if (bcmerror == BCME_OK) {
2673                 dhdp->dongle_reset = FALSE;
2674                 dhdp->up = TRUE;
2675 #if !defined(IGNORE_ETH0_DOWN)
2676                 /* Restore flow control  */
2677                 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
2678 #endif
2679                 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
2680 
2681                 DBUSTRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
2682             } else {
2683                 DBUSERR(("%s: failed to dbus_up with code %d\n", __FUNCTION__,
2684                          bcmerror));
2685             }
2686         }
2687     }
2688 
2689     return bcmerror;
2690 }
2691 
dhd_bus_update_fw_nv_path(struct dhd_bus * bus,char * pfw_path,char * pnv_path,char * pclm_path,char * pconf_path)2692 void dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path,
2693                                char *pnv_path, char *pclm_path,
2694                                char *pconf_path)
2695 {
2696     DBUSTRACE(("%s\n", __FUNCTION__));
2697 
2698     if (bus == NULL) {
2699         DBUSERR(("%s: bus is NULL\n", __FUNCTION__));
2700         return;
2701     }
2702 
2703     bus->fw_path = pfw_path;
2704     bus->nv_path = pnv_path;
2705     bus->dhd->clm_path = pclm_path;
2706     bus->dhd->conf_path = pconf_path;
2707 
2708     dhd_conf_set_path_params(bus->dhd, bus->fw_path, bus->nv_path);
2709 }
2710 
2711 /*
2712  * hdrlen is space to reserve in pkt headroom for DBUS
2713  */
dhd_dbus_probe_cb(void * arg,const char * desc,uint32 bustype,uint16 bus_no,uint16 slot,uint32 hdrlen)2714 void *dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
2715                         uint16 bus_no, uint16 slot, uint32 hdrlen)
2716 {
2717     osl_t *osh = NULL;
2718     dhd_bus_t *bus = NULL;
2719     dhd_pub_t *pub = NULL;
2720     uint rxsz;
2721     int dlneeded = 0;
2722     wifi_adapter_info_t *adapter = NULL;
2723 
2724     DBUSTRACE(("%s: Enter\n", __FUNCTION__));
2725 
2726     adapter = dhd_wifi_platform_get_adapter(bustype, bus_no, slot);
2727 
2728     if (!g_pub) {
2729         /* Ask the OS interface part for an OSL handle */
2730         if (!(osh = osl_attach(NULL, bustype, TRUE))) {
2731             DBUSERR(("%s: OSL attach failed\n", __FUNCTION__));
2732             goto fail;
2733         }
2734 
2735         /* Attach to the dhd/OS interface */
2736         if (!(pub = dhd_attach(osh, bus, hdrlen, adapter))) {
2737             DBUSERR(("%s: dhd_attach failed\n", __FUNCTION__));
2738             goto fail;
2739         }
2740     } else {
2741         pub = g_pub;
2742         osh = pub->osh;
2743     }
2744 
2745     if (pub->bus) {
2746         DBUSERR(("%s: wrong probe\n", __FUNCTION__));
2747         goto fail;
2748     }
2749 
2750     rxsz = dhd_get_rxsz(pub);
2751     bus = dbus_attach(osh, rxsz, DBUS_NRXQ, DBUS_NTXQ, pub, &dhd_dbus_cbs, NULL,
2752                       NULL);
2753     if (bus) {
2754         pub->bus = bus;
2755         bus->dhd = pub;
2756 
2757         dlneeded = dbus_dlneeded(bus);
2758         if (dlneeded >= 0) {
2759             if (!g_pub) {
2760                 dhd_conf_reset(pub);
2761                 dhd_conf_set_chiprev(pub, bus->pub.attrib.devid,
2762                                      bus->pub.attrib.chiprev);
2763                 dhd_conf_preinit(pub);
2764             }
2765         }
2766 
2767         if (g_pub || dhd_download_fw_on_driverload) {
2768             if (dlneeded == 0) {
2769                 wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY);
2770 #ifdef BCM_REQUEST_FW
2771             } else if (dlneeded > 0) {
2772                 dhd_set_path(bus->dhd);
2773                 if (dbus_download_firmware(bus, bus->fw_path, bus->nv_path) !=
2774                     DBUS_OK) {
2775                     goto fail;
2776                 }
2777 #endif
2778             } else {
2779                 goto fail;
2780             }
2781         }
2782     } else {
2783         DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__));
2784     }
2785 
2786     if (!g_pub) {
2787         /* Ok, have the per-port tell the stack we're open for business */
2788         if (dhd_attach_net(bus->dhd, TRUE) != 0) {
2789             DBUSERR(("%s: Net attach failed!!\n", __FUNCTION__));
2790             goto fail;
2791         }
2792         pub->hang_report = TRUE;
2793 #if defined(MULTIPLE_SUPPLICANT)
2794         wl_android_post_init(); // terence 20120530: fix critical section in
2795                                 // dhd_open and dhdsdio_probe
2796 #endif
2797         g_pub = pub;
2798     }
2799 
2800     DBUSTRACE(("%s: Exit\n", __FUNCTION__));
2801     wifi_clr_adapter_status(adapter, WIFI_STATUS_DETTACH);
2802     wifi_set_adapter_status(adapter, WIFI_STATUS_ATTACH);
2803     wake_up_interruptible(&adapter->status_event);
2804     /* This is passed to dhd_dbus_disconnect_cb */
2805     return bus;
2806 
2807 fail:
2808     if (pub && pub->bus) {
2809         dbus_detach(pub->bus);
2810         pub->bus = NULL;
2811     }
2812     /* Release resources in reverse order */
2813     if (!g_pub) {
2814         if (pub) {
2815             dhd_detach(pub);
2816             dhd_free(pub);
2817         }
2818         if (osh) {
2819             osl_detach(osh);
2820         }
2821     }
2822 
2823     printf("%s: Failed\n", __FUNCTION__);
2824     return NULL;
2825 }
2826 
dhd_dbus_disconnect_cb(void * arg)2827 void dhd_dbus_disconnect_cb(void *arg)
2828 {
2829     dhd_bus_t *bus = (dhd_bus_t *)arg;
2830     dhd_pub_t *pub = g_pub;
2831     osl_t *osh;
2832     wifi_adapter_info_t *adapter = NULL;
2833 
2834     adapter = (wifi_adapter_info_t *)pub->adapter;
2835 
2836     if (pub && !pub->dhd_remove && bus == NULL) {
2837         DBUSERR(("%s: bus is NULL\n", __FUNCTION__));
2838         return;
2839     }
2840     if (!adapter) {
2841         DBUSERR(("%s: adapter is NULL\n", __FUNCTION__));
2842         return;
2843     }
2844 
2845     printf("%s: Enter dhd_remove=%d on %s\n", __FUNCTION__, pub->dhd_remove,
2846            adapter->name);
2847     if (!pub->dhd_remove) {
2848         /* Advertise bus remove during rmmod */
2849         dhd_dbus_advertise_bus_remove(bus->dhd);
2850         dbus_detach(pub->bus);
2851         pub->bus = NULL;
2852         wifi_clr_adapter_status(adapter, WIFI_STATUS_ATTACH);
2853         wifi_set_adapter_status(adapter, WIFI_STATUS_DETTACH);
2854         wake_up_interruptible(&adapter->status_event);
2855     } else {
2856         osh = pub->osh;
2857         dhd_detach(pub);
2858         if (pub->bus) {
2859             dbus_detach(pub->bus);
2860             pub->bus = NULL;
2861         }
2862         dhd_free(pub);
2863         g_pub = NULL;
2864         if (MALLOCED(osh)) {
2865             DBUSERR(
2866                 ("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
2867         }
2868         osl_detach(osh);
2869     }
2870 
2871     DBUSTRACE(("%s: Exit\n", __FUNCTION__));
2872 }
2873 
2874 #ifdef LINUX_EXTERNAL_MODULE_DBUS
2875 
bcm_dbus_module_init(void)2876 static int __init bcm_dbus_module_init(void)
2877 {
2878     printf("Inserting bcm_dbus module \n");
2879     return 0;
2880 }
2881 
bcm_dbus_module_exit(void)2882 static void __exit bcm_dbus_module_exit(void)
2883 {
2884     printf("Removing bcm_dbus module \n");
2885     return;
2886 }
2887 
2888 EXPORT_SYMBOL(dbus_pnp_sleep);
2889 EXPORT_SYMBOL(dbus_get_devinfo);
2890 EXPORT_SYMBOL(dbus_detach);
2891 EXPORT_SYMBOL(dbus_get_attrib);
2892 EXPORT_SYMBOL(dbus_down);
2893 EXPORT_SYMBOL(dbus_pnp_resume);
2894 EXPORT_SYMBOL(dbus_set_config);
2895 EXPORT_SYMBOL(dbus_flowctrl_rx);
2896 EXPORT_SYMBOL(dbus_up);
2897 EXPORT_SYMBOL(dbus_get_device_speed);
2898 EXPORT_SYMBOL(dbus_send_pkt);
2899 EXPORT_SYMBOL(dbus_recv_ctl);
2900 EXPORT_SYMBOL(dbus_attach);
2901 
2902 MODULE_LICENSE("GPL");
2903 
2904 module_init(bcm_dbus_module_init);
2905 module_exit(bcm_dbus_module_exit);
2906 
2907 #endif /* #ifdef LINUX_EXTERNAL_MODULE_DBUS */
2908