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