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