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