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