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