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