xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/dbus.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file dbus.c
2  *
3  * Hides details of USB / SDIO / SPI interfaces and OS details. It is intended to shield details and
4  * provide the caller with one common bus interface for all dongle devices. In practice, it is only
5  * used for USB interfaces. DBUS is not a protocol, but an abstraction layer.
6  *
7  * Copyright (C) 1999-2016, Broadcom Corporation
8  *
9  *      Unless you and Broadcom execute a separate written software license
10  * agreement governing use of this software, this software is licensed to you
11  * under the terms of the GNU General Public License version 2 (the "GPL"),
12  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13  * following added to such license:
14  *
15  *      As a special exception, the copyright holders of this software give you
16  * permission to link this software with independent modules, and to copy and
17  * distribute the resulting executable under terms of your choice, provided that
18  * you also meet, for each linked independent module, the terms and conditions of
19  * the license of that module.  An independent module is a module which is not
20  * derived from this software.  The special exception does not apply to any
21  * modifications of the software.
22  *
23  *      Notwithstanding the above, under no circumstances may you combine this
24  * software in any way with any other Broadcom software provided under a license
25  * other than the GPL, without Broadcom's express prior written consent.
26  *
27  *
28  * <<Broadcom-WL-IPTag/Open:>>
29  *
30  * $Id: dbus.c 553311 2015-04-29 10:23:08Z $
31  */
32 
33 
34 #include <linux/usb.h>
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 #ifdef WL_CFG80211
46 #include <wl_cfg80211.h>
47 #include <wl_cfgp2p.h>
48 #endif
49 
50 #include <bcmdevs_legacy.h>
51 #if defined(BCM_REQUEST_FW)
52 #include <bcmsrom_fmt.h>
53 #include <trxhdr.h>
54 #include <usbrdl.h>
55 #include <bcmendian.h>
56 #include <sbpcmcia.h>
57 #include <bcmnvram.h>
58 #include <bcmdevs.h>
59 #endif
60 
61 
62 
63 #if defined(BCM_REQUEST_FW)
64 #ifndef VARS_MAX
65 #define VARS_MAX            8192
66 #endif
67 #endif
68 
69 #ifdef DBUS_USB_LOOPBACK
70 extern bool is_loopback_pkt(void *buf);
71 extern int matches_loopback_pkt(void *buf);
72 #endif
73 
74 /** General info for all BUS types */
75 typedef struct dbus_irbq {
76 	dbus_irb_t *head;
77 	dbus_irb_t *tail;
78 	int cnt;
79 } dbus_irbq_t;
80 
81 /**
82  * This private structure dhd_bus_t is also declared in dbus_usb_linux.c.
83  * All the fields must be consistent in both declarations.
84  */
85 typedef struct dhd_bus {
86 	dbus_pub_t   pub; /* MUST BE FIRST */
87 	dhd_pub_t *dhd;
88 
89 	void        *cbarg;
90 	dbus_callbacks_t *cbs; /* callbacks to higher level, e.g. dhd_linux.c */
91 	void        *bus_info;
92 	dbus_intf_t *drvintf;  /* callbacks to lower level, e.g. dbus_usb.c or dbus_usb_linux.c */
93 	uint8       *fw;
94 	int         fwlen;
95 	uint32      errmask;
96 	int         rx_low_watermark;  /* avoid rx overflow by filling rx with free IRBs */
97 	int         tx_low_watermark;
98 	bool        txoff;
99 	bool        txoverride;   /* flow control related */
100 	bool        rxoff;
101 	bool        tx_timer_ticking;
102 	uint ctl_completed;
103 
104 	dbus_irbq_t *rx_q;
105 	dbus_irbq_t *tx_q;
106 
107 	uint8        *nvram;
108 	int          nvram_len;
109 	uint8        *image;  /* buffer for combine fw and nvram */
110 	int          image_len;
111 	uint8        *orig_fw;
112 	int          origfw_len;
113 	int          decomp_memsize;
114 	dbus_extdl_t extdl;
115 	int          nvram_nontxt;
116 #if defined(BCM_REQUEST_FW)
117 	void         *firmware;
118 	void         *nvfile;
119 #endif
120 	char		*fw_path;		/* module_param: path to firmware image */
121 	char		*nv_path;		/* module_param: path to nvram vars file */
122 	uint64 last_suspend_end_time;
123 } dhd_bus_t;
124 
125 struct exec_parms {
126 	union {
127 		/* Can consolidate same params, if need be, but this shows
128 		 * group of parameters per function
129 		 */
130 		struct {
131 			dbus_irbq_t  *q;
132 			dbus_irb_t   *b;
133 		} qenq;
134 
135 		struct {
136 			dbus_irbq_t  *q;
137 		} qdeq;
138 	};
139 };
140 
141 #define EXEC_RXLOCK(info, fn, a) \
142 	info->drvintf->exec_rxlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a))
143 
144 #define EXEC_TXLOCK(info, fn, a) \
145 	info->drvintf->exec_txlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a))
146 
147 /*
148  * Callbacks common for all BUS
149  */
150 static void dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb);
151 static void dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status);
152 static void dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status);
153 static void dbus_if_errhandler(void *handle, int err);
154 static void dbus_if_ctl_complete(void *handle, int type, int status);
155 static void dbus_if_state_change(void *handle, int state);
156 static void *dbus_if_pktget(void *handle, uint len, bool send);
157 static void dbus_if_pktfree(void *handle, void *p, bool send);
158 static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send);
159 static void dbus_if_rxerr_indicate(void *handle, bool on);
160 
161 static int dbus_suspend(void *context);
162 static int dbus_resume(void *context);
163 static void * dhd_dbus_probe_cb(uint16 bus_no, uint16 slot, uint32 hdrlen);
164 static void dhd_dbus_disconnect_cb(void *arg);
165 static void dbus_detach(dhd_bus_t *pub);
166 
167 /** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c */
168 static dbus_intf_callbacks_t dbus_intf_cbs = {
169 	dbus_if_send_irb_timeout,
170 	dbus_if_send_irb_complete,
171 	dbus_if_recv_irb_complete,
172 	dbus_if_errhandler,
173 	dbus_if_ctl_complete,
174 	dbus_if_state_change,
175 	NULL,			/* isr */
176 	NULL,			/* dpc */
177 	NULL,			/* watchdog */
178 	dbus_if_pktget,
179 	dbus_if_pktfree,
180 	dbus_if_getirb,
181 	dbus_if_rxerr_indicate
182 };
183 
184 /*
185  * Need global for probe() and disconnect() since
186  * attach() is not called at probe and detach()
187  * can be called inside disconnect()
188  */
189 static dbus_intf_t     *g_busintf = NULL;
190 
191 #if defined(BCM_REQUEST_FW)
192 int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */
193 int nonfwnvramlen = 0;
194 #endif /* #if defined(BCM_REQUEST_FW) */
195 
196 static void* q_enq(dbus_irbq_t *q, dbus_irb_t *b);
197 static void* q_enq_exec(struct exec_parms *args);
198 static dbus_irb_t*q_deq(dbus_irbq_t *q);
199 static void* q_deq_exec(struct exec_parms *args);
200 static int   dbus_tx_timer_init(dhd_bus_t *dhd_bus);
201 static int   dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout);
202 static int   dbus_tx_timer_stop(dhd_bus_t *dhd_bus);
203 static int   dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb);
204 static int   dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb);
205 static int   dbus_rxirbs_fill(dhd_bus_t *dhd_bus);
206 static int   dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info);
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)605 dbus_get_fw_nvram(dhd_bus_t *dhd_bus)
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 	char *pfw_path = dhd_bus->fw_path;
621 	char *pnv_path = dhd_bus->nv_path;
622 
623 	/* For Get nvram */
624 	file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
625 	if (file_exists) {
626 		nv_image = dhd_os_open_image1(dhd_bus->dhd, pnv_path);
627 		if (nv_image == NULL) {
628 			printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
629 			goto err;
630 		}
631 	}
632 	nv_memblock = MALLOC(dhd_bus->pub.osh, MAX_NVRAMBUF_SIZE);
633 	if (nv_memblock == NULL) {
634 		DBUSERR(("%s: Failed to allocate memory %d bytes\n",
635 		           __FUNCTION__, MAX_NVRAMBUF_SIZE));
636 		goto err;
637 	}
638 	len = dhd_os_get_image_block(nv_memblock, MAX_NVRAMBUF_SIZE, nv_image);
639 	if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
640 		bufp = (char *)nv_memblock;
641 		bufp[len] = 0;
642 		dhd_bus->nvram_len = process_nvram_vars(bufp, len);
643 		if (dhd_bus->nvram_len % 4)
644 			nvram_words_pad = 4 - dhd_bus->nvram_len % 4;
645 	} else {
646 		DBUSERR(("%s: error reading nvram file: %d\n", __FUNCTION__, len));
647 		bcmerror = DBUS_ERR_NVRAM;
648 		goto err;
649 	}
650 	if (nv_image) {
651 		dhd_os_close_image1(dhd_bus->dhd, nv_image);
652 		nv_image = NULL;
653 	}
654 
655 	/* For Get first block of fw to calculate total_len */
656 	file_exists = ((pfw_path != NULL) && (pfw_path[0] != '\0'));
657 	if (file_exists) {
658 		fw_image = dhd_os_open_image1(dhd_bus->dhd, pfw_path);
659 		if (fw_image == NULL) {
660 			printf("%s: Open fw file failed %s\n", __FUNCTION__, pfw_path);
661 			goto err;
662 		}
663 	}
664 	memptr = fw_memblock = MALLOC(dhd_bus->pub.osh, memblock_size);
665 	if (fw_memblock == NULL) {
666 		DBUSERR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
667 			memblock_size));
668 		goto err;
669 	}
670 	len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image);
671 	if ((actual_fwlen = check_file(dhd_bus->pub.osh, memptr)) <= 0) {
672 		DBUSERR(("%s: bad firmware format!\n", __FUNCTION__));
673 		goto err;
674 	}
675 
676 	total_len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad;
677 #if defined(CONFIG_DHD_USE_STATIC_BUF)
678 	dhd_bus->image = (uint8*)DHD_OS_PREALLOC(dhd_bus->dhd,
679 		DHD_PREALLOC_MEMDUMP_RAM, total_len);
680 #else
681 	dhd_bus->image = MALLOC(dhd_bus->pub.osh, total_len);
682 #endif /* CONFIG_DHD_USE_STATIC_BUF */
683 	dhd_bus->image_len = total_len;
684 	if (dhd_bus->image == NULL) {
685 		DBUSERR(("%s: malloc failed! size=%d\n", __FUNCTION__, total_len));
686 		goto err;
687 	}
688 
689 	/* Step1: Copy trx header + firmwre */
690 	memptr = fw_memblock;
691 	do {
692 		if (len < 0) {
693 			DBUSERR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
694 			bcmerror = BCME_ERROR;
695 			goto err;
696 		}
697 		bcopy(memptr, dhd_bus->image+offset, len);
698 		offset += len;
699 	} while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image)));
700 	/* Step2: Copy NVRAM + pad */
701 	hdr = (struct trx_header *)dhd_bus->image;
702 	img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX];
703 	bcopy(nv_memblock, (uint8 *)(dhd_bus->image + img_offset),
704 		dhd_bus->nvram_len);
705 	img_offset += dhd_bus->nvram_len;
706 	if (nvram_words_pad) {
707 		bzero(&dhd_bus->image[img_offset], nvram_words_pad);
708 		img_offset += nvram_words_pad;
709 	}
710 #ifdef BCMTRXV2
711 	/* Step3: Copy DSG/CFG for V2 */
712 	if (ISTRX_V2(hdr) &&
713 		(hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] ||
714 		hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) {
715 		DBUSERR(("%s: fix me\n", __FUNCTION__));
716 	}
717 #endif /* BCMTRXV2 */
718 	/* Step4: update TRX header for nvram size */
719 	hdr = (struct trx_header *)dhd_bus->image;
720 	hdr->len = htol32(total_len);
721 	/* Pass the actual fw len */
722 	hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] =
723 		htol32(dhd_bus->nvram_len + nvram_words_pad);
724 	/* Calculate CRC over header */
725 	hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version,
726 		SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version),
727 		CRC32_INIT_VALUE);
728 
729 	/* Calculate CRC over data */
730 	for (i = SIZEOF_TRX(hdr); i < total_len; ++i)
731 			hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32);
732 	hdr->crc32 = htol32(hdr->crc32);
733 
734 	bcmerror = DBUS_OK;
735 
736 err:
737 	if (fw_memblock)
738 		MFREE(dhd_bus->pub.osh, fw_memblock, MAX_NVRAMBUF_SIZE);
739 	if (fw_image)
740 		dhd_os_close_image1(dhd_bus->dhd, fw_image);
741 	if (nv_memblock)
742 		MFREE(dhd_bus->pub.osh, nv_memblock, MAX_NVRAMBUF_SIZE);
743 	if (nv_image)
744 		dhd_os_close_image1(dhd_bus->dhd, nv_image);
745 
746 	return bcmerror;
747 }
748 
749 /**
750  * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into
751  * the dongle
752  */
753 static int
dbus_do_download(dhd_bus_t * dhd_bus)754 dbus_do_download(dhd_bus_t *dhd_bus)
755 {
756 	int err = DBUS_OK;
757 
758 	err = dbus_get_fw_nvram(dhd_bus);
759 	if (err) {
760 		DBUSERR(("dbus_do_download: fail to get nvram %d\n", err));
761 		return err;
762 	}
763 
764 	if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) {
765 		err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info,
766 			dhd_bus->image, dhd_bus->image_len);
767 		if (err == DBUS_OK) {
768 			err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info);
769 		}
770 	} else
771 		err = DBUS_ERR;
772 
773 	if (dhd_bus->image) {
774 #if defined(CONFIG_DHD_USE_STATIC_BUF)
775 		DHD_OS_PREFREE(dhd_bus->dhd, dhd_bus->image, dhd_bus->image_len);
776 #else
777 		MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len);
778 #endif /* CONFIG_DHD_USE_STATIC_BUF */
779 		dhd_bus->image = NULL;
780 		dhd_bus->image_len = 0;
781 	}
782 
783 	return err;
784 } /* dbus_do_download */
785 #else
786 
787 /**
788  * It is easy for the user to pass one jumbo nvram file to the driver than a set of smaller files.
789  * The 'jumbo nvram' file format is essentially a set of nvram files. Before commencing firmware
790  * download, the dongle needs to be probed so that the correct nvram contents within the jumbo nvram
791  * file is selected.
792  */
793 static int
dbus_jumbo_nvram(dhd_bus_t * dhd_bus)794 dbus_jumbo_nvram(dhd_bus_t *dhd_bus)
795 {
796 	int8 *nvram = NULL;
797 	int nvram_len = 0;
798 	int ret = DBUS_OK;
799 	uint16 boardrev = 0xFFFF;
800 	uint16 boardtype = 0xFFFF;
801 
802 	/* read the otp for boardrev & boardtype
803 	* if boardtype/rev are present in otp
804 	* select nvram data for that boardtype/rev
805 	*/
806 	dbus_otp(dhd_bus, &boardtype, &boardrev);
807 
808 	ret = dbus_select_nvram(dhd_bus, dhd_bus->extdl.vars, dhd_bus->extdl.varslen,
809 		boardtype, boardrev, &nvram, &nvram_len);
810 
811 	if (ret == DBUS_JUMBO_BAD_FORMAT)
812 			return DBUS_ERR_NVRAM;
813 	else if (ret == DBUS_JUMBO_NOMATCH &&
814 		(boardtype != 0xFFFF || boardrev  != 0xFFFF)) {
815 			DBUSERR(("No matching NVRAM for boardtype 0x%02x boardrev 0x%02x\n",
816 				boardtype, boardrev));
817 			return DBUS_ERR_NVRAM;
818 	}
819 	dhd_bus->nvram = nvram;
820 	dhd_bus->nvram_len =  nvram_len;
821 
822 	return DBUS_OK;
823 }
824 
825 /** before commencing fw download, the correct NVRAM image to download has to be picked */
826 static int
dbus_get_nvram(dhd_bus_t * dhd_bus)827 dbus_get_nvram(dhd_bus_t *dhd_bus)
828 {
829 	int len, i;
830 	struct trx_header *hdr;
831 	int	actual_fwlen;
832 	uint32 img_offset = 0;
833 
834 	dhd_bus->nvram_len = 0;
835 	if (dhd_bus->extdl.varslen) {
836 		if (DBUS_OK != dbus_jumbo_nvram(dhd_bus))
837 			return DBUS_ERR_NVRAM;
838 		DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len));
839 	}
840 #if defined(BCM_REQUEST_FW)
841 	else if (nonfwnvram) {
842 		dhd_bus->nvram = nonfwnvram;
843 		dhd_bus->nvram_len = nonfwnvramlen;
844 		DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len));
845 	}
846 #endif
847 	if (dhd_bus->nvram) {
848 		uint8 nvram_words_pad = 0;
849 		/* Validate the format/length etc of the file */
850 		if ((actual_fwlen = check_file(dhd_bus->pub.osh, dhd_bus->fw)) <= 0) {
851 			DBUSERR(("%s: bad firmware format!\n", __FUNCTION__));
852 			return DBUS_ERR_NVRAM;
853 		}
854 
855 		if (!dhd_bus->nvram_nontxt) {
856 			/* host supplied nvram could be in .txt format
857 			* with all the comments etc...
858 			*/
859 			dhd_bus->nvram_len = process_nvram_vars(dhd_bus->nvram,
860 				dhd_bus->nvram_len);
861 		}
862 		if (dhd_bus->nvram_len % 4)
863 			nvram_words_pad = 4 - dhd_bus->nvram_len % 4;
864 
865 		len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad;
866 #if defined(CONFIG_DHD_USE_STATIC_BUF)
867 		dhd_bus->image = (uint8*)DHD_OS_PREALLOC(dhd_bus->dhd,
868 			DHD_PREALLOC_MEMDUMP_RAM, len);
869 #else
870 		dhd_bus->image = MALLOC(dhd_bus->pub.osh, len);
871 #endif /* CONFIG_DHD_USE_STATIC_BUF */
872 		dhd_bus->image_len = len;
873 		if (dhd_bus->image == NULL) {
874 			DBUSERR(("%s: malloc failed!\n", __FUNCTION__));
875 			return DBUS_ERR_NVRAM;
876 		}
877 		hdr = (struct trx_header *)dhd_bus->fw;
878 		/* Step1: Copy trx header + firmwre */
879 		img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX];
880 		bcopy(dhd_bus->fw, dhd_bus->image, img_offset);
881 		/* Step2: Copy NVRAM + pad */
882 		bcopy(dhd_bus->nvram, (uint8 *)(dhd_bus->image + img_offset),
883 			dhd_bus->nvram_len);
884 		img_offset += dhd_bus->nvram_len;
885 		if (nvram_words_pad) {
886 			bzero(&dhd_bus->image[img_offset],
887 				nvram_words_pad);
888 			img_offset += nvram_words_pad;
889 		}
890 #ifdef BCMTRXV2
891 		/* Step3: Copy DSG/CFG for V2 */
892 		if (ISTRX_V2(hdr) &&
893 			(hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] ||
894 			hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) {
895 
896 			bcopy(dhd_bus->fw + SIZEOF_TRX(hdr) +
897 				hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX] +
898 				hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX],
899 				dhd_bus->image + img_offset,
900 				hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] +
901 				hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]);
902 
903 			img_offset += hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] +
904 				hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX];
905 		}
906 #endif /* BCMTRXV2 */
907 		/* Step4: update TRX header for nvram size */
908 		hdr = (struct trx_header *)dhd_bus->image;
909 		hdr->len = htol32(len);
910 		/* Pass the actual fw len */
911 		hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] =
912 			htol32(dhd_bus->nvram_len + nvram_words_pad);
913 		/* Calculate CRC over header */
914 		hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version,
915 			SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version),
916 			CRC32_INIT_VALUE);
917 
918 		/* Calculate CRC over data */
919 		for (i = SIZEOF_TRX(hdr); i < len; ++i)
920 				hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32);
921 		hdr->crc32 = htol32(hdr->crc32);
922 	} else {
923 		dhd_bus->image = dhd_bus->fw;
924 		dhd_bus->image_len = (uint32)dhd_bus->fwlen;
925 	}
926 
927 	return DBUS_OK;
928 } /* dbus_get_nvram */
929 
930 /**
931  * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into
932  * the dongle
933  */
934 static int
dbus_do_download(dhd_bus_t * dhd_bus)935 dbus_do_download(dhd_bus_t *dhd_bus)
936 {
937 	int err = DBUS_OK;
938 #ifndef BCM_REQUEST_FW
939 	int decomp_override = 0;
940 #endif
941 #ifdef BCM_REQUEST_FW
942 	uint16 boardrev = 0xFFFF, boardtype = 0xFFFF;
943 	int8 *temp_nvram;
944 	int temp_len;
945 #endif
946 
947 #if defined(BCM_REQUEST_FW)
948 	dhd_bus->firmware = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid,
949 		dhd_bus->pub.attrib.chiprev, &dhd_bus->fw, &dhd_bus->fwlen,
950 		DBUS_FIRMWARE, 0, 0, dhd_bus->fw_path);
951 	if (!dhd_bus->firmware)
952 		return DBUS_ERR;
953 #endif
954 
955 	dhd_bus->image = dhd_bus->fw;
956 	dhd_bus->image_len = (uint32)dhd_bus->fwlen;
957 
958 #ifndef BCM_REQUEST_FW
959 	if (UNZIP_ENAB(dhd_bus) && !decomp_override) {
960 		err = dbus_zlib_decomp(dhd_bus);
961 		if (err) {
962 			DBUSERR(("dbus_attach: fw decompress fail %d\n", err));
963 			return err;
964 		}
965 	}
966 #endif
967 
968 #if defined(BCM_REQUEST_FW)
969 	/* check if firmware is appended with nvram file */
970 	err = dbus_otp(dhd_bus, &boardtype, &boardrev);
971 	/* check if nvram is provided as separte file */
972 	nonfwnvram = NULL;
973 	nonfwnvramlen = 0;
974 	dhd_bus->nvfile = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid,
975 		dhd_bus->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len,
976 		DBUS_NVFILE, boardtype, boardrev, dhd_bus->nv_path);
977 	if (dhd_bus->nvfile) {
978 		int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len);
979 		if (tmp) {
980 			bcopy(temp_nvram, tmp, temp_len);
981 			nonfwnvram = tmp;
982 			nonfwnvramlen = temp_len;
983 		} else {
984 			err = DBUS_ERR;
985 			goto fail;
986 		}
987 	}
988 #endif /* defined(BCM_REQUEST_FW) */
989 
990 	err = dbus_get_nvram(dhd_bus);
991 	if (err) {
992 		DBUSERR(("dbus_do_download: fail to get nvram %d\n", err));
993 		return err;
994 	}
995 
996 
997 	if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) {
998 		err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info,
999 			dhd_bus->image, dhd_bus->image_len);
1000 
1001 		if (err == DBUS_OK)
1002 			err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info);
1003 	} else
1004 		err = DBUS_ERR;
1005 
1006 	if (dhd_bus->nvram) {
1007 #if defined(CONFIG_DHD_USE_STATIC_BUF)
1008 		DHD_OS_PREFREE(dhd_bus->dhd, dhd_bus->image, dhd_bus->image_len);
1009 #else
1010 		MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len);
1011 #endif /* CONFIG_DHD_USE_STATIC_BUF */
1012 		dhd_bus->image = dhd_bus->fw;
1013 		dhd_bus->image_len = (uint32)dhd_bus->fwlen;
1014 	}
1015 
1016 #ifndef BCM_REQUEST_FW
1017 	if (UNZIP_ENAB(dhd_bus) && (!decomp_override) && dhd_bus->orig_fw) {
1018 		MFREE(dhd_bus->pub.osh, dhd_bus->fw, dhd_bus->decomp_memsize);
1019 		dhd_bus->image = dhd_bus->fw = dhd_bus->orig_fw;
1020 		dhd_bus->image_len = dhd_bus->fwlen = dhd_bus->origfw_len;
1021 	}
1022 #endif
1023 
1024 #if defined(BCM_REQUEST_FW)
1025 fail:
1026 	if (dhd_bus->firmware) {
1027 		dbus_release_fw_nvfile(dhd_bus->firmware);
1028 		dhd_bus->firmware = NULL;
1029 	}
1030 	if (dhd_bus->nvfile) {
1031 		dbus_release_fw_nvfile(dhd_bus->nvfile);
1032 		dhd_bus->nvfile = NULL;
1033 	}
1034 	if (nonfwnvram) {
1035 		MFREE(dhd_bus->pub.osh, nonfwnvram, nonfwnvramlen);
1036 		nonfwnvram = NULL;
1037 		nonfwnvramlen = 0;
1038 	}
1039 #endif
1040 	return err;
1041 } /* dbus_do_download */
1042 #endif /* EXTERNAL_FW_PATH */
1043 #endif
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 /* Register/Unregister functions are called by the main DHD entry
1377  * point (e.g. module insertion) to link with the bus driver, in
1378  * order to look for or await the device.
1379  */
1380 
1381 static dbus_driver_t dhd_dbus = {
1382 	dhd_dbus_probe_cb,
1383 	dhd_dbus_disconnect_cb,
1384 	dbus_suspend,
1385 	dbus_resume
1386 };
1387 
1388 /**
1389  * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to prepare for
1390  * action.
1391  */
1392 int
dhd_bus_register(void)1393 dhd_bus_register(void)
1394 {
1395 	int err;
1396 
1397 	DBUSTRACE(("%s: Enter\n", __FUNCTION__));
1398 
1399 	err = dbus_bus_register(&dhd_dbus, &g_busintf);
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 bool net_attached = FALSE;
1410 void
dhd_bus_unregister(void)1411 dhd_bus_unregister(void)
1412 {
1413 	DBUSTRACE(("%s\n", __FUNCTION__));
1414 
1415 	DHD_MUTEX_LOCK();
1416 	if (g_pub) {
1417 		g_pub->dhd_remove = TRUE;
1418 		if (!g_pub->bus) {
1419 			dhd_dbus_disconnect_cb(g_pub->bus);
1420 		}
1421 	}
1422 	DHD_MUTEX_UNLOCK();
1423 	dbus_bus_deregister();
1424 }
1425 
1426 /** As part of initialization, data structures have to be allocated and initialized */
1427 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)1428 dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub,
1429 	dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh)
1430 {
1431 	dhd_bus_t *dhd_bus;
1432 	int err;
1433 
1434 	if ((g_busintf == NULL) || (g_busintf->attach == NULL) || (cbs == NULL))
1435 		return NULL;
1436 
1437 	DBUSTRACE(("%s\n", __FUNCTION__));
1438 
1439 	if ((nrxq <= 0) || (ntxq <= 0))
1440 		return NULL;
1441 
1442 	dhd_bus = MALLOC(osh, sizeof(dhd_bus_t));
1443 	if (dhd_bus == NULL) {
1444 		DBUSERR(("%s: malloc failed %zu\n", __FUNCTION__, sizeof(dhd_bus_t)));
1445 		return NULL;
1446 	}
1447 
1448 	bzero(dhd_bus, sizeof(dhd_bus_t));
1449 
1450 	/* BUS-specific driver interface (at a lower DBUS level) */
1451 	dhd_bus->drvintf = g_busintf;
1452 	dhd_bus->cbarg = pub;
1453 	dhd_bus->cbs = cbs;
1454 
1455 	dhd_bus->pub.sh = sh;
1456 	dhd_bus->pub.osh = osh;
1457 	dhd_bus->pub.rxsize = rxsize;
1458 
1459 	dhd_bus->pub.nrxq = nrxq;
1460 	dhd_bus->rx_low_watermark = nrxq / 2;	/* keep enough posted rx urbs */
1461 	dhd_bus->pub.ntxq = ntxq;
1462 	dhd_bus->tx_low_watermark = ntxq / 4;	/* flow control when too many tx urbs posted */
1463 
1464 	dhd_bus->tx_q = MALLOC(osh, sizeof(dbus_irbq_t));
1465 	if (dhd_bus->tx_q == NULL)
1466 		goto error;
1467 	else {
1468 		bzero(dhd_bus->tx_q, sizeof(dbus_irbq_t));
1469 		err = dbus_irbq_init(dhd_bus, dhd_bus->tx_q, ntxq, sizeof(dbus_irb_tx_t));
1470 		if (err != DBUS_OK)
1471 			goto error;
1472 	}
1473 
1474 	dhd_bus->rx_q = MALLOC(osh, sizeof(dbus_irbq_t));
1475 	if (dhd_bus->rx_q == NULL)
1476 		goto error;
1477 	else {
1478 		bzero(dhd_bus->rx_q, sizeof(dbus_irbq_t));
1479 		err = dbus_irbq_init(dhd_bus, dhd_bus->rx_q, nrxq, sizeof(dbus_irb_rx_t));
1480 		if (err != DBUS_OK)
1481 			goto error;
1482 	}
1483 
1484 
1485 	dhd_bus->bus_info = (void *)g_busintf->attach(&dhd_bus->pub,
1486 		dhd_bus, &dbus_intf_cbs);
1487 	if (dhd_bus->bus_info == NULL)
1488 		goto error;
1489 
1490 	dbus_tx_timer_init(dhd_bus);
1491 
1492 #if defined(BCM_REQUEST_FW)
1493 	/* Need to copy external image for re-download */
1494 	if (extdl && extdl->fw && (extdl->fwlen > 0)) {
1495 		dhd_bus->extdl.fw = MALLOC(osh, extdl->fwlen);
1496 		if (dhd_bus->extdl.fw) {
1497 			bcopy(extdl->fw, dhd_bus->extdl.fw, extdl->fwlen);
1498 			dhd_bus->extdl.fwlen = extdl->fwlen;
1499 		}
1500 	}
1501 
1502 	if (extdl && extdl->vars && (extdl->varslen > 0)) {
1503 		dhd_bus->extdl.vars = MALLOC(osh, extdl->varslen);
1504 		if (dhd_bus->extdl.vars) {
1505 			bcopy(extdl->vars, dhd_bus->extdl.vars, extdl->varslen);
1506 			dhd_bus->extdl.varslen = extdl->varslen;
1507 		}
1508 	}
1509 #endif
1510 
1511 	return (dhd_bus_t *)dhd_bus;
1512 
1513 error:
1514 	DBUSERR(("%s: Failed\n", __FUNCTION__));
1515 	dbus_detach(dhd_bus);
1516 	return NULL;
1517 } /* dbus_attach */
1518 
1519 void
dbus_detach(dhd_bus_t * pub)1520 dbus_detach(dhd_bus_t *pub)
1521 {
1522 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1523 	osl_t *osh;
1524 
1525 	DBUSTRACE(("%s\n", __FUNCTION__));
1526 
1527 	if (dhd_bus == NULL)
1528 		return;
1529 
1530 	dbus_tx_timer_stop(dhd_bus);
1531 
1532 	osh = pub->pub.osh;
1533 
1534 	if (dhd_bus->drvintf && dhd_bus->drvintf->detach)
1535 		 dhd_bus->drvintf->detach((dbus_pub_t *)dhd_bus, dhd_bus->bus_info);
1536 
1537 	if (dhd_bus->tx_q) {
1538 		dbus_irbq_deinit(dhd_bus, dhd_bus->tx_q, sizeof(dbus_irb_tx_t));
1539 		MFREE(osh, dhd_bus->tx_q, sizeof(dbus_irbq_t));
1540 		dhd_bus->tx_q = NULL;
1541 	}
1542 
1543 	if (dhd_bus->rx_q) {
1544 		dbus_irbq_deinit(dhd_bus, dhd_bus->rx_q, sizeof(dbus_irb_rx_t));
1545 		MFREE(osh, dhd_bus->rx_q, sizeof(dbus_irbq_t));
1546 		dhd_bus->rx_q = NULL;
1547 	}
1548 
1549 
1550 	if (dhd_bus->extdl.fw && (dhd_bus->extdl.fwlen > 0)) {
1551 		MFREE(osh, dhd_bus->extdl.fw, dhd_bus->extdl.fwlen);
1552 		dhd_bus->extdl.fw = NULL;
1553 		dhd_bus->extdl.fwlen = 0;
1554 	}
1555 
1556 	if (dhd_bus->extdl.vars && (dhd_bus->extdl.varslen > 0)) {
1557 		MFREE(osh, dhd_bus->extdl.vars, dhd_bus->extdl.varslen);
1558 		dhd_bus->extdl.vars = NULL;
1559 		dhd_bus->extdl.varslen = 0;
1560 	}
1561 
1562 	MFREE(osh, dhd_bus, sizeof(dhd_bus_t));
1563 } /* dbus_detach */
1564 
dbus_dlneeded(dhd_bus_t * pub)1565 int dbus_dlneeded(dhd_bus_t *pub)
1566 {
1567 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1568 	int dlneeded = DBUS_ERR;
1569 
1570 	if (!dhd_bus) {
1571 		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1572 		return DBUS_ERR;
1573 	}
1574 
1575 	DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate));
1576 
1577 	if (dhd_bus->drvintf->dlneeded) {
1578 		dlneeded = dhd_bus->drvintf->dlneeded(dhd_bus->bus_info);
1579 	}
1580 	printf("%s: dlneeded=%d\n", __FUNCTION__, dlneeded);
1581 
1582 	/* dlneeded > 0: need to download
1583 	  * dlneeded = 0: downloaded
1584 	  * dlneeded < 0: bus error*/
1585 	return dlneeded;
1586 }
1587 
1588 #if defined(BCM_REQUEST_FW)
dbus_download_firmware(dhd_bus_t * pub)1589 int dbus_download_firmware(dhd_bus_t *pub)
1590 {
1591 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1592 	int err = DBUS_OK;
1593 
1594 	if (!dhd_bus) {
1595 		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1596 		return DBUS_ERR;
1597 	}
1598 
1599 	DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate));
1600 
1601 	dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING;
1602 	err = dbus_do_download(dhd_bus);
1603 	if (err == DBUS_OK) {
1604 		dhd_bus->pub.busstate = DBUS_STATE_DL_DONE;
1605 	} else {
1606 		DBUSERR(("%s: download failed (%d)\n", __FUNCTION__, err));
1607 	}
1608 
1609 	return err;
1610 }
1611 #endif
1612 
1613 /**
1614  * higher layer requests us to 'up' the interface to the dongle. Prerequisite is that firmware (not
1615  * bootloader) must be active in the dongle.
1616  */
1617 int
dbus_up(struct dhd_bus * pub)1618 dbus_up(struct dhd_bus *pub)
1619 {
1620 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1621 	int err = DBUS_OK;
1622 
1623 	DBUSTRACE(("%s\n", __FUNCTION__));
1624 
1625 	if (dhd_bus == NULL) {
1626 		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1627 		return DBUS_ERR;
1628 	}
1629 
1630 	if ((dhd_bus->pub.busstate == DBUS_STATE_DL_DONE) ||
1631 		(dhd_bus->pub.busstate == DBUS_STATE_DOWN) ||
1632 		(dhd_bus->pub.busstate == DBUS_STATE_SLEEP)) {
1633 		if (dhd_bus->drvintf && dhd_bus->drvintf->up) {
1634 			err = dhd_bus->drvintf->up(dhd_bus->bus_info);
1635 
1636 			if (err == DBUS_OK) {
1637 				dbus_rxirbs_fill(dhd_bus);
1638 			}
1639 		}
1640 	} else
1641 		err = DBUS_ERR;
1642 
1643 	return err;
1644 }
1645 
1646 /** higher layer requests us to 'down' the interface to the dongle. */
1647 int
dbus_down(dbus_pub_t * pub)1648 dbus_down(dbus_pub_t *pub)
1649 {
1650 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1651 
1652 	DBUSTRACE(("%s\n", __FUNCTION__));
1653 
1654 	if (dhd_bus == NULL)
1655 		return DBUS_ERR;
1656 
1657 	dbus_tx_timer_stop(dhd_bus);
1658 
1659 	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
1660 		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
1661 		if (dhd_bus->drvintf && dhd_bus->drvintf->down)
1662 			return dhd_bus->drvintf->down(dhd_bus->bus_info);
1663 	}
1664 
1665 	return DBUS_ERR;
1666 }
1667 
1668 int
dbus_shutdown(dbus_pub_t * pub)1669 dbus_shutdown(dbus_pub_t *pub)
1670 {
1671 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1672 
1673 	DBUSTRACE(("%s\n", __FUNCTION__));
1674 
1675 	if (dhd_bus == NULL)
1676 		return DBUS_ERR;
1677 
1678 	if (dhd_bus->drvintf && dhd_bus->drvintf->shutdown)
1679 		return dhd_bus->drvintf->shutdown(dhd_bus->bus_info);
1680 
1681 	return DBUS_OK;
1682 }
1683 
1684 int
dbus_stop(struct dhd_bus * pub)1685 dbus_stop(struct dhd_bus *pub)
1686 {
1687 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1688 
1689 	DBUSTRACE(("%s\n", __FUNCTION__));
1690 
1691 	if (dhd_bus == NULL)
1692 		return DBUS_ERR;
1693 
1694 	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
1695 		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
1696 		if (dhd_bus->drvintf && dhd_bus->drvintf->stop)
1697 			return dhd_bus->drvintf->stop(dhd_bus->bus_info);
1698 	}
1699 
1700 	return DBUS_ERR;
1701 }
1702 
1703 int
dbus_send_buf(dbus_pub_t * pub,uint8 * buf,int len,void * info)1704 dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info)
1705 {
1706 	return dbus_send_irb(pub, buf, len, NULL, info);
1707 }
1708 
1709 static int
dbus_send_pkt(dbus_pub_t * pub,void * pkt,void * info)1710 dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info)
1711 {
1712 	return dbus_send_irb(pub, NULL, 0, pkt, info);
1713 }
1714 
1715 static int
dbus_send_ctl(struct dhd_bus * pub,uint8 * buf,int len)1716 dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len)
1717 {
1718 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1719 
1720 	if (dhd_bus == NULL) {
1721 		DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__));
1722 		return DBUS_ERR;
1723 	}
1724 
1725 	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
1726 		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
1727 		if (dhd_bus->drvintf && dhd_bus->drvintf->send_ctl)
1728 			return dhd_bus->drvintf->send_ctl(dhd_bus->bus_info, buf, len);
1729 	} else {
1730 		DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate));
1731 	}
1732 
1733 	return DBUS_ERR;
1734 }
1735 
1736 static int
dbus_recv_ctl(struct dhd_bus * pub,uint8 * buf,int len)1737 dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len)
1738 {
1739 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1740 
1741 	if ((dhd_bus == NULL) || (buf == NULL))
1742 		return DBUS_ERR;
1743 
1744 	if (dhd_bus->pub.busstate == DBUS_STATE_UP ||
1745 		dhd_bus->pub.busstate == DBUS_STATE_SLEEP) {
1746 		if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl)
1747 			return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len);
1748 	} else {
1749 		DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate));
1750 	}
1751 
1752 	return DBUS_ERR;
1753 }
1754 
1755 /** Only called via RPC (Dec 2012) */
1756 int
dbus_recv_bulk(dbus_pub_t * pub,uint32 ep_idx)1757 dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx)
1758 {
1759 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1760 
1761 	dbus_irb_rx_t *rxirb;
1762 	struct exec_parms args;
1763 	int status;
1764 
1765 
1766 	if (dhd_bus == NULL)
1767 		return DBUS_ERR;
1768 
1769 	args.qdeq.q = dhd_bus->rx_q;
1770 	if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
1771 		if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) {
1772 			if ((rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) {
1773 				status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info,
1774 					rxirb, ep_idx);
1775 				if (status == DBUS_ERR_RXDROP) {
1776 					bzero(rxirb, sizeof(dbus_irb_rx_t));
1777 					args.qenq.q = dhd_bus->rx_q;
1778 					args.qenq.b = (dbus_irb_t *) rxirb;
1779 					EXEC_RXLOCK(dhd_bus, q_enq_exec, &args);
1780 				}
1781 			}
1782 		}
1783 	}
1784 
1785 	return DBUS_ERR;
1786 }
1787 
1788 #ifdef INTR_EP_ENABLE
1789 /** only called by dhd_cdc.c (Dec 2012) */
1790 static int
dbus_poll_intr(dbus_pub_t * pub)1791 dbus_poll_intr(dbus_pub_t *pub)
1792 {
1793 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1794 
1795 	int status = DBUS_ERR;
1796 
1797 	if (dhd_bus == NULL)
1798 		return DBUS_ERR;
1799 
1800 	if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
1801 		if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) {
1802 			status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info,
1803 				NULL, 0xff);
1804 		}
1805 	}
1806 	return status;
1807 }
1808 #endif /* INTR_EP_ENABLE */
1809 
1810 /** called by nobody (Dec 2012) */
1811 void *
dbus_pktget(dbus_pub_t * pub,int len)1812 dbus_pktget(dbus_pub_t *pub, int len)
1813 {
1814 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1815 
1816 	if ((dhd_bus == NULL) || (len < 0))
1817 		return NULL;
1818 
1819 	return PKTGET(dhd_bus->pub.osh, len, TRUE);
1820 }
1821 
1822 /** called by nobody (Dec 2012) */
1823 void
dbus_pktfree(dbus_pub_t * pub,void * pkt)1824 dbus_pktfree(dbus_pub_t *pub, void* pkt)
1825 {
1826 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1827 
1828 	if ((dhd_bus == NULL) || (pkt == NULL))
1829 		return;
1830 
1831 	PKTFREE(dhd_bus->pub.osh, pkt, TRUE);
1832 }
1833 
1834 /** called by nobody (Dec 2012) */
1835 int
dbus_get_stats(dbus_pub_t * pub,dbus_stats_t * stats)1836 dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats)
1837 {
1838 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1839 
1840 	if ((dhd_bus == NULL) || (stats == NULL))
1841 		return DBUS_ERR;
1842 
1843 	bcopy(&dhd_bus->pub.stats, stats, sizeof(dbus_stats_t));
1844 
1845 	return DBUS_OK;
1846 }
1847 
1848 int
dbus_get_attrib(dhd_bus_t * pub,dbus_attrib_t * attrib)1849 dbus_get_attrib(dhd_bus_t *pub, dbus_attrib_t *attrib)
1850 {
1851 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1852 	int err = DBUS_ERR;
1853 
1854 	if ((dhd_bus == NULL) || (attrib == NULL))
1855 		return DBUS_ERR;
1856 
1857 	if (dhd_bus->drvintf && dhd_bus->drvintf->get_attrib) {
1858 		err = dhd_bus->drvintf->get_attrib(dhd_bus->bus_info,
1859 		&dhd_bus->pub.attrib);
1860 	}
1861 
1862 	bcopy(&dhd_bus->pub.attrib, attrib, sizeof(dbus_attrib_t));
1863 	return err;
1864 }
1865 
1866 int
dbus_get_device_speed(dbus_pub_t * pub)1867 dbus_get_device_speed(dbus_pub_t *pub)
1868 {
1869 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1870 
1871 	if (dhd_bus == NULL)
1872 		return INVALID_SPEED;
1873 
1874 	return (dhd_bus->pub.device_speed);
1875 }
1876 
1877 int
dbus_set_config(dbus_pub_t * pub,dbus_config_t * config)1878 dbus_set_config(dbus_pub_t *pub, dbus_config_t *config)
1879 {
1880 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1881 	int err = DBUS_ERR;
1882 
1883 	if ((dhd_bus == NULL) || (config == NULL))
1884 		return DBUS_ERR;
1885 
1886 	if (dhd_bus->drvintf && dhd_bus->drvintf->set_config) {
1887 		err = dhd_bus->drvintf->set_config(dhd_bus->bus_info,
1888 			config);
1889 
1890 		if ((config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) &&
1891 			(!err) &&
1892 			(dhd_bus->pub.busstate == DBUS_STATE_UP)) {
1893 			dbus_rxirbs_fill(dhd_bus);
1894 		}
1895 	}
1896 
1897 	return err;
1898 }
1899 
1900 int
dbus_get_config(dbus_pub_t * pub,dbus_config_t * config)1901 dbus_get_config(dbus_pub_t *pub, dbus_config_t *config)
1902 {
1903 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1904 	int err = DBUS_ERR;
1905 
1906 	if ((dhd_bus == NULL) || (config == NULL))
1907 		return DBUS_ERR;
1908 
1909 	if (dhd_bus->drvintf && dhd_bus->drvintf->get_config) {
1910 		err = dhd_bus->drvintf->get_config(dhd_bus->bus_info,
1911 		config);
1912 	}
1913 
1914 	return err;
1915 }
1916 
1917 int
dbus_set_errmask(dbus_pub_t * pub,uint32 mask)1918 dbus_set_errmask(dbus_pub_t *pub, uint32 mask)
1919 {
1920 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1921 	int err = DBUS_OK;
1922 
1923 	if (dhd_bus == NULL)
1924 		return DBUS_ERR;
1925 
1926 	dhd_bus->errmask = mask;
1927 	return err;
1928 }
1929 
1930 int
dbus_pnp_resume(dbus_pub_t * pub,int * fw_reload)1931 dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload)
1932 {
1933 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1934 	int err = DBUS_ERR;
1935 	bool fwdl = FALSE;
1936 
1937 	DBUSTRACE(("%s\n", __FUNCTION__));
1938 
1939 	if (dhd_bus == NULL)
1940 		return DBUS_ERR;
1941 
1942 	if (dhd_bus->pub.busstate == DBUS_STATE_UP) {
1943 		return DBUS_OK;
1944 	}
1945 
1946 
1947 
1948 	if (dhd_bus->drvintf->pnp) {
1949 		err = dhd_bus->drvintf->pnp(dhd_bus->bus_info,
1950 			DBUS_PNP_RESUME);
1951 	}
1952 
1953 	if (dhd_bus->drvintf->recv_needed) {
1954 		if (dhd_bus->drvintf->recv_needed(dhd_bus->bus_info)) {
1955 			/* Refill after sleep/hibernate */
1956 			dbus_rxirbs_fill(dhd_bus);
1957 		}
1958 	}
1959 
1960 
1961 	if (fw_reload)
1962 		*fw_reload = fwdl;
1963 
1964 	return err;
1965 } /* dbus_pnp_resume */
1966 
1967 int
dbus_pnp_sleep(dbus_pub_t * pub)1968 dbus_pnp_sleep(dbus_pub_t *pub)
1969 {
1970 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1971 	int err = DBUS_ERR;
1972 
1973 	DBUSTRACE(("%s\n", __FUNCTION__));
1974 
1975 	if (dhd_bus == NULL)
1976 		return DBUS_ERR;
1977 
1978 	dbus_tx_timer_stop(dhd_bus);
1979 
1980 	if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) {
1981 		err = dhd_bus->drvintf->pnp(dhd_bus->bus_info,
1982 			DBUS_PNP_SLEEP);
1983 	}
1984 
1985 	return err;
1986 }
1987 
1988 int
dbus_pnp_disconnect(dbus_pub_t * pub)1989 dbus_pnp_disconnect(dbus_pub_t *pub)
1990 {
1991 	dhd_bus_t *dhd_bus = (dhd_bus_t *) pub;
1992 	int err = DBUS_ERR;
1993 
1994 	DBUSTRACE(("%s\n", __FUNCTION__));
1995 
1996 	if (dhd_bus == NULL)
1997 		return DBUS_ERR;
1998 
1999 	dbus_tx_timer_stop(dhd_bus);
2000 
2001 	if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) {
2002 		err = dhd_bus->drvintf->pnp(dhd_bus->bus_info,
2003 			DBUS_PNP_DISCONNECT);
2004 	}
2005 
2006 	return err;
2007 }
2008 
2009 int
dhd_bus_iovar_op(dhd_pub_t * dhdp,const char * name,void * params,int plen,void * arg,int len,bool set)2010 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
2011 	void *params, int plen, void *arg, int len, bool set)
2012 {
2013 	dhd_bus_t *dhd_bus = (dhd_bus_t *) dhdp->bus;
2014 	int err = DBUS_ERR;
2015 
2016 	DBUSTRACE(("%s\n", __FUNCTION__));
2017 
2018 	if (dhd_bus == NULL)
2019 		return DBUS_ERR;
2020 
2021 	if (dhd_bus->drvintf && dhd_bus->drvintf->iovar_op) {
2022 		err = dhd_bus->drvintf->iovar_op(dhd_bus->bus_info,
2023 			name, params, plen, arg, len, set);
2024 	}
2025 
2026 	return err;
2027 }
2028 
2029 
2030 void *
dhd_dbus_txq(const dbus_pub_t * pub)2031 dhd_dbus_txq(const dbus_pub_t *pub)
2032 {
2033 	return NULL;
2034 }
2035 
2036 uint
dhd_dbus_hdrlen(const dbus_pub_t * pub)2037 dhd_dbus_hdrlen(const dbus_pub_t *pub)
2038 {
2039 	return 0;
2040 }
2041 
2042 void *
dbus_get_devinfo(dbus_pub_t * pub)2043 dbus_get_devinfo(dbus_pub_t *pub)
2044 {
2045 	return pub->dev_info;
2046 }
2047 
2048 #if defined(BCM_REQUEST_FW) && !defined(EXTERNAL_FW_PATH)
2049 static int
dbus_otp(dhd_bus_t * dhd_bus,uint16 * boardtype,uint16 * boardrev)2050 dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev)
2051 {
2052 	uint32 value = 0;
2053 	uint8 *cis;
2054 	uint16 *otpinfo;
2055 	uint32 i;
2056 	bool standard_cis = TRUE;
2057 	uint8 tup, tlen;
2058 	bool btype_present = FALSE;
2059 	bool brev_present = FALSE;
2060 	int ret;
2061 	int devid;
2062 	uint16 btype = 0;
2063 	uint16 brev = 0;
2064 	uint32 otp_size = 0, otp_addr = 0, otp_sw_rgn = 0;
2065 
2066 	if (dhd_bus == NULL || dhd_bus->drvintf == NULL ||
2067 		dhd_bus->drvintf->readreg == NULL)
2068 		return DBUS_ERR;
2069 
2070 	devid = dhd_bus->pub.attrib.devid;
2071 
2072 	if ((devid == BCM43234_CHIP_ID) || (devid == BCM43235_CHIP_ID) ||
2073 		(devid == BCM43236_CHIP_ID)) {
2074 
2075 		otp_size = BCM_OTP_SIZE_43236;
2076 		otp_sw_rgn = BCM_OTP_SW_RGN_43236;
2077 		otp_addr = BCM_OTP_ADDR_43236;
2078 
2079 	} else {
2080 		return DBUS_ERR_NVRAM;
2081 	}
2082 
2083 	cis = MALLOC(dhd_bus->pub.osh, otp_size * 2);
2084 	if (cis == NULL)
2085 		return DBUS_ERR;
2086 
2087 	otpinfo = (uint16 *) cis;
2088 
2089 	for (i = 0; i < otp_size; i++) {
2090 
2091 		ret = dhd_bus->drvintf->readreg(dhd_bus->bus_info,
2092 			otp_addr + ((otp_sw_rgn + i) << 1), 2, &value);
2093 
2094 		if (ret != DBUS_OK) {
2095 			MFREE(dhd_bus->pub.osh, cis, otp_size * 2);
2096 			return ret;
2097 		}
2098 		otpinfo[i] = (uint16) value;
2099 	}
2100 
2101 	for (i = 0; i < (otp_size << 1); ) {
2102 
2103 		if (standard_cis) {
2104 			tup = cis[i++];
2105 			if (tup == CISTPL_NULL || tup == CISTPL_END)
2106 				tlen = 0;
2107 			else
2108 				tlen = cis[i++];
2109 		} else {
2110 			if (cis[i] == CISTPL_NULL || cis[i] == CISTPL_END) {
2111 				tlen = 0;
2112 				tup = cis[i];
2113 			} else {
2114 				tlen = cis[i];
2115 				tup = CISTPL_BRCM_HNBU;
2116 			}
2117 			++i;
2118 		}
2119 
2120 		if (tup == CISTPL_END || (i + tlen) >= (otp_size << 1)) {
2121 			break;
2122 		}
2123 
2124 		switch (tup) {
2125 
2126 		case CISTPL_BRCM_HNBU:
2127 
2128 			switch (cis[i]) {
2129 
2130 			case HNBU_BOARDTYPE:
2131 
2132 				btype = (uint16) ((cis[i + 2] << 8) + cis[i + 1]);
2133 				btype_present = TRUE;
2134 				DBUSTRACE(("%s: HNBU_BOARDTYPE = 0x%2x\n", __FUNCTION__,
2135 					(uint32)btype));
2136 				break;
2137 
2138 			case HNBU_BOARDREV:
2139 
2140 				if (tlen == 2)
2141 					brev = (uint16) cis[i + 1];
2142 				else
2143 					brev = (uint16) ((cis[i + 2] << 8) + cis[i + 1]);
2144 				brev_present = TRUE;
2145 				DBUSTRACE(("%s: HNBU_BOARDREV =  0x%2x\n", __FUNCTION__,
2146 					(uint32)*boardrev));
2147 				break;
2148 
2149 			case HNBU_HNBUCIS:
2150 				DBUSTRACE(("%s: HNBU_HNBUCIS\n", __FUNCTION__));
2151 				tlen++;
2152 				standard_cis = FALSE;
2153 				break;
2154 			}
2155 			break;
2156 		}
2157 
2158 		i += tlen;
2159 	}
2160 
2161 	MFREE(dhd_bus->pub.osh, cis, otp_size * 2);
2162 
2163 	if (btype_present == TRUE && brev_present == TRUE) {
2164 		*boardtype = btype;
2165 		*boardrev = brev;
2166 		DBUSERR(("otp boardtype = 0x%2x boardrev = 0x%2x\n",
2167 			*boardtype, *boardrev));
2168 
2169 		return DBUS_OK;
2170 	}
2171 	else
2172 		return DBUS_ERR;
2173 } /* dbus_otp */
2174 
2175 static int
dbus_select_nvram(dhd_bus_t * dhd_bus,int8 * jumbonvram,int jumbolen,uint16 boardtype,uint16 boardrev,int8 ** nvram,int * nvram_len)2176 dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen,
2177 uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len)
2178 {
2179 	/* Multi board nvram file format is contenation of nvram info with \r
2180 	*  The file format for two contatenated set is
2181 	*  \nBroadcom Jumbo Nvram file\nfirst_set\nsecond_set\nthird_set\n
2182 	*/
2183 	uint8 *nvram_start = NULL, *nvram_end = NULL;
2184 	uint8 *nvram_start_prev = NULL, *nvram_end_prev = NULL;
2185 	uint16 btype = 0, brev = 0;
2186 	int len  = 0;
2187 	char *field;
2188 
2189 	*nvram = NULL;
2190 	*nvram_len = 0;
2191 
2192 	if (strncmp(BCM_JUMBO_START, jumbonvram, strlen(BCM_JUMBO_START))) {
2193 		/* single nvram file in the native format */
2194 		DBUSTRACE(("%s: Non-Jumbo NVRAM File \n", __FUNCTION__));
2195 		*nvram = jumbonvram;
2196 		*nvram_len = jumbolen;
2197 		return DBUS_OK;
2198 	} else {
2199 		DBUSTRACE(("%s: Jumbo NVRAM File \n", __FUNCTION__));
2200 	}
2201 
2202 	/* sanity test the end of the config sets for proper ending */
2203 	if (jumbonvram[jumbolen - 1] != BCM_JUMBO_NVRAM_DELIMIT ||
2204 		jumbonvram[jumbolen - 2] != '\0') {
2205 		DBUSERR(("%s: Bad Jumbo NVRAM file format\n", __FUNCTION__));
2206 		return DBUS_JUMBO_BAD_FORMAT;
2207 	}
2208 
2209 	dhd_bus->nvram_nontxt = DBUS_NVRAM_NONTXT;
2210 
2211 	nvram_start = jumbonvram;
2212 
2213 	while (*nvram_start != BCM_JUMBO_NVRAM_DELIMIT && len < jumbolen) {
2214 
2215 		/* consume the  first file info line
2216 		* \nBroadcom Jumbo Nvram file\nfile1\n ...
2217 		*/
2218 		len ++;
2219 		nvram_start ++;
2220 	}
2221 
2222 	nvram_end = nvram_start;
2223 
2224 	/* search for "boardrev=0xabcd" and "boardtype=0x1234" information in
2225 	* the concatenated nvram config files /sets
2226 	*/
2227 
2228 	while (len < jumbolen) {
2229 
2230 		if (*nvram_end == '\0') {
2231 			/* end of a config set is marked by multiple null characters */
2232 			len ++;
2233 			nvram_end ++;
2234 			DBUSTRACE(("%s: NULL chr len = %d char = 0x%x\n", __FUNCTION__,
2235 				len, *nvram_end));
2236 			continue;
2237 
2238 		} else if (*nvram_end == BCM_JUMBO_NVRAM_DELIMIT) {
2239 
2240 			/* config set delimiter is reached */
2241 			/* check if next config set is present or not
2242 			*  return  if next config is not present
2243 			*/
2244 
2245 			/* start search the next config set */
2246 			nvram_start_prev = nvram_start;
2247 			nvram_end_prev = nvram_end;
2248 
2249 			nvram_end ++;
2250 			nvram_start = nvram_end;
2251 			btype = brev = 0;
2252 			DBUSTRACE(("%s: going to next record len = %d "
2253 					"char = 0x%x \n", __FUNCTION__, len, *nvram_end));
2254 			len ++;
2255 			if (len >= jumbolen) {
2256 
2257 				*nvram = nvram_start_prev;
2258 				*nvram_len = (int)(nvram_end_prev - nvram_start_prev);
2259 
2260 				DBUSTRACE(("%s: no more len = %d nvram_end = 0x%p",
2261 					__FUNCTION__, len, nvram_end));
2262 
2263 				return DBUS_JUMBO_NOMATCH;
2264 
2265 			} else {
2266 				continue;
2267 			}
2268 
2269 		} else {
2270 
2271 			DBUSTRACE(("%s: config str = %s\n", __FUNCTION__, nvram_end));
2272 
2273 			if (bcmp(nvram_end, "boardtype", strlen("boardtype")) == 0) {
2274 
2275 				field = strchr(nvram_end, '=');
2276 				field++;
2277 				btype = (uint16)bcm_strtoul(field, NULL, 0);
2278 
2279 				DBUSTRACE(("%s: btype = 0x%x boardtype = 0x%x \n", __FUNCTION__,
2280 					btype, boardtype));
2281 			}
2282 
2283 			if (bcmp(nvram_end, "boardrev", strlen("boardrev")) == 0) {
2284 
2285 				field = strchr(nvram_end, '=');
2286 				field++;
2287 				brev = (uint16)bcm_strtoul(field, NULL, 0);
2288 
2289 				DBUSTRACE(("%s: brev = 0x%x boardrev = 0x%x \n", __FUNCTION__,
2290 					brev, boardrev));
2291 			}
2292 			if (btype == boardtype && brev == boardrev) {
2293 				/* locate nvram config set end - ie.find '\r' char */
2294 				while (*nvram_end != BCM_JUMBO_NVRAM_DELIMIT)
2295 					nvram_end ++;
2296 				*nvram = nvram_start;
2297 				*nvram_len = (int) (nvram_end - nvram_start);
2298 				DBUSTRACE(("found len = %d nvram_start = 0x%p "
2299 					"nvram_end = 0x%p\n", *nvram_len, nvram_start, nvram_end));
2300 				return DBUS_OK;
2301 			}
2302 
2303 			len += (strlen(nvram_end) + 1);
2304 			nvram_end += (strlen(nvram_end) + 1);
2305 		}
2306 	}
2307 	return DBUS_JUMBO_NOMATCH;
2308 } /* dbus_select_nvram */
2309 
2310 #endif
2311 
2312 #define DBUS_NRXQ	50
2313 #define DBUS_NTXQ	100
2314 
2315 static void
dhd_dbus_send_complete(void * handle,void * info,int status)2316 dhd_dbus_send_complete(void *handle, void *info, int status)
2317 {
2318 	dhd_pub_t *dhd = (dhd_pub_t *)handle;
2319 	void *pkt = info;
2320 
2321 	if ((dhd == NULL) || (pkt == NULL)) {
2322 		DBUSERR(("dhd or pkt is NULL\n"));
2323 		return;
2324 	}
2325 
2326 	if (status == DBUS_OK) {
2327 		dhd->dstats.tx_packets++;
2328 	} else {
2329 		DBUSERR(("TX error=%d\n", status));
2330 		dhd->dstats.tx_errors++;
2331 	}
2332 #ifdef PROP_TXSTATUS
2333 	if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) &&
2334 		(dhd_wlfc_txcomplete(dhd, pkt, status == 0) != WLFC_UNSUPPORTED)) {
2335 		return;
2336 	} else
2337 #endif /* PROP_TXSTATUS */
2338 	dhd_txcomplete(dhd, pkt, status == 0);
2339 	PKTFREE(dhd->osh, pkt, TRUE);
2340 }
2341 
2342 static void
dhd_dbus_recv_pkt(void * handle,void * pkt)2343 dhd_dbus_recv_pkt(void *handle, void *pkt)
2344 {
2345 	uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
2346 	uint reorder_info_len;
2347 	uint pkt_count;
2348 	dhd_pub_t *dhd = (dhd_pub_t *)handle;
2349 	int ifidx = 0;
2350 
2351 	if (dhd == NULL) {
2352 		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2353 		return;
2354 	}
2355 
2356 	/* If the protocol uses a data header, check and remove it */
2357 	if (dhd_prot_hdrpull(dhd, &ifidx, pkt, reorder_info_buf,
2358 		&reorder_info_len) != 0) {
2359 		DBUSERR(("rx protocol error\n"));
2360 		PKTFREE(dhd->osh, pkt, FALSE);
2361 		dhd->rx_errors++;
2362 		return;
2363 	}
2364 
2365 	if (reorder_info_len) {
2366 		/* Reordering info from the firmware */
2367 		dhd_process_pkt_reorder_info(dhd, reorder_info_buf, reorder_info_len,
2368 			&pkt, &pkt_count);
2369 		if (pkt_count == 0)
2370 			return;
2371 	}
2372 	else {
2373 		pkt_count = 1;
2374 	}
2375 	dhd_rx_frame(dhd, ifidx, pkt, pkt_count, 0);
2376 }
2377 
2378 static void
dhd_dbus_recv_buf(void * handle,uint8 * buf,int len)2379 dhd_dbus_recv_buf(void *handle, uint8 *buf, int len)
2380 {
2381 	dhd_pub_t *dhd = (dhd_pub_t *)handle;
2382 	void *pkt;
2383 
2384 	if (dhd == NULL) {
2385 		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2386 		return;
2387 	}
2388 
2389 	if ((pkt = PKTGET(dhd->osh, len, FALSE)) == NULL) {
2390 		DBUSERR(("PKTGET (rx) failed=%d\n", len));
2391 		return;
2392 	}
2393 
2394 	bcopy(buf, PKTDATA(dhd->osh, pkt), len);
2395 	dhd_dbus_recv_pkt(dhd, pkt);
2396 }
2397 
2398 static void
dhd_dbus_txflowcontrol(void * handle,bool onoff)2399 dhd_dbus_txflowcontrol(void *handle, bool onoff)
2400 {
2401 	dhd_pub_t *dhd = (dhd_pub_t *)handle;
2402 	bool wlfc_enabled = FALSE;
2403 
2404 	if (dhd == NULL) {
2405 		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2406 		return;
2407 	}
2408 
2409 #ifdef PROP_TXSTATUS
2410 	wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, onoff, !onoff) != WLFC_UNSUPPORTED);
2411 #endif
2412 
2413 	if (!wlfc_enabled) {
2414 		dhd_txflowcontrol(dhd, ALL_INTERFACES, onoff);
2415 	}
2416 }
2417 
2418 static void
dhd_dbus_errhandler(void * handle,int err)2419 dhd_dbus_errhandler(void *handle, int err)
2420 {
2421 }
2422 
2423 static void
dhd_dbus_ctl_complete(void * handle,int type,int status)2424 dhd_dbus_ctl_complete(void *handle, int type, int status)
2425 {
2426 	dhd_pub_t *dhd = (dhd_pub_t *)handle;
2427 
2428 	if (dhd == NULL) {
2429 		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2430 		return;
2431 	}
2432 
2433 	if (type == DBUS_CBCTL_READ) {
2434 		if (status == DBUS_OK)
2435 			dhd->rx_ctlpkts++;
2436 		else
2437 			dhd->rx_ctlerrs++;
2438 	} else if (type == DBUS_CBCTL_WRITE) {
2439 		if (status == DBUS_OK)
2440 			dhd->tx_ctlpkts++;
2441 		else
2442 			dhd->tx_ctlerrs++;
2443 	}
2444 
2445 	dhd->bus->ctl_completed = TRUE;
2446 	dhd_os_ioctl_resp_wake(dhd);
2447 }
2448 
2449 static void
dhd_dbus_state_change(void * handle,int state)2450 dhd_dbus_state_change(void *handle, int state)
2451 {
2452 	dhd_pub_t *dhd = (dhd_pub_t *)handle;
2453 	unsigned long flags;
2454 	wifi_adapter_info_t *adapter;
2455 
2456 	if (dhd == NULL) {
2457 		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2458 		return;
2459 	}
2460 	adapter = (wifi_adapter_info_t *)dhd->adapter;
2461 
2462 	if (dhd->busstate == DHD_BUS_SUSPEND && state == DBUS_STATE_DOWN) {
2463 		DBUSERR(("%s: switch state %d to %d\n", __FUNCTION__, state, DBUS_STATE_SLEEP));
2464 		state = DBUS_STATE_SLEEP;
2465 	}
2466 	switch (state) {
2467 		case DBUS_STATE_DL_NEEDED:
2468 			DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__));
2469 			break;
2470 		case DBUS_STATE_DOWN:
2471 			DHD_LINUX_GENERAL_LOCK(dhd, flags);
2472 			dhd_txflowcontrol(dhd, ALL_INTERFACES, ON);
2473 			DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__));
2474 			dhd->busstate = DHD_BUS_DOWN;
2475 			DHD_LINUX_GENERAL_UNLOCK(dhd, flags);
2476 			break;
2477 		case DBUS_STATE_UP:
2478 			DBUSTRACE(("%s: DBUS is up\n", __FUNCTION__));
2479 			DHD_LINUX_GENERAL_LOCK(dhd, flags);
2480 			dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2481 			dhd->busstate = DHD_BUS_DATA;
2482 			DHD_LINUX_GENERAL_UNLOCK(dhd, flags);
2483 			break;
2484 		default:
2485 			break;
2486 	}
2487 
2488 	DBUSERR(("%s: DBUS current state=%d\n", __FUNCTION__, state));
2489 }
2490 
2491 static void *
dhd_dbus_pktget(void * handle,uint len,bool send)2492 dhd_dbus_pktget(void *handle, uint len, bool send)
2493 {
2494 	dhd_pub_t *dhd = (dhd_pub_t *)handle;
2495 	void *p = NULL;
2496 
2497 	if (dhd == NULL) {
2498 		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2499 		return NULL;
2500 	}
2501 
2502 	if (send == TRUE) {
2503 		dhd_os_sdlock_txq(dhd);
2504 		p = PKTGET(dhd->osh, len, TRUE);
2505 		dhd_os_sdunlock_txq(dhd);
2506 	} else {
2507 		dhd_os_sdlock_rxq(dhd);
2508 		p = PKTGET(dhd->osh, len, FALSE);
2509 		dhd_os_sdunlock_rxq(dhd);
2510 	}
2511 
2512 	return p;
2513 }
2514 
2515 static void
dhd_dbus_pktfree(void * handle,void * p,bool send)2516 dhd_dbus_pktfree(void *handle, void *p, bool send)
2517 {
2518 	dhd_pub_t *dhd = (dhd_pub_t *)handle;
2519 
2520 	if (dhd == NULL) {
2521 		DBUSERR(("%s: dhd is NULL\n", __FUNCTION__));
2522 		return;
2523 	}
2524 
2525 	if (send == TRUE) {
2526 #ifdef PROP_TXSTATUS
2527 		if (DHD_PKTTAG_WLFCPKT(PKTTAG(p)) &&
2528 			(dhd_wlfc_txcomplete(dhd, p, FALSE) != WLFC_UNSUPPORTED)) {
2529 			return;
2530 		}
2531 #endif /* PROP_TXSTATUS */
2532 
2533 		dhd_os_sdlock_txq(dhd);
2534 		PKTFREE(dhd->osh, p, TRUE);
2535 		dhd_os_sdunlock_txq(dhd);
2536 	} else {
2537 		dhd_os_sdlock_rxq(dhd);
2538 		PKTFREE(dhd->osh, p, FALSE);
2539 		dhd_os_sdunlock_rxq(dhd);
2540 	}
2541 }
2542 
2543 
2544 static dbus_callbacks_t dhd_dbus_cbs = {
2545 	dhd_dbus_send_complete,
2546 	dhd_dbus_recv_buf,
2547 	dhd_dbus_recv_pkt,
2548 	dhd_dbus_txflowcontrol,
2549 	dhd_dbus_errhandler,
2550 	dhd_dbus_ctl_complete,
2551 	dhd_dbus_state_change,
2552 	dhd_dbus_pktget,
2553 	dhd_dbus_pktfree
2554 };
2555 
2556 uint
dhd_bus_chip(struct dhd_bus * bus)2557 dhd_bus_chip(struct dhd_bus *bus)
2558 {
2559 	ASSERT(bus != NULL);
2560 	return bus->pub.attrib.devid;
2561 }
2562 
2563 uint
dhd_bus_chiprev(struct dhd_bus * bus)2564 dhd_bus_chiprev(struct dhd_bus *bus)
2565 {
2566 	ASSERT(bus);
2567 	ASSERT(bus != NULL);
2568 	return bus->pub.attrib.chiprev;
2569 }
2570 
2571 struct device *
dhd_bus_to_dev(struct dhd_bus * bus)2572 dhd_bus_to_dev(struct dhd_bus *bus)
2573 {
2574 	return dbus_get_dev();
2575 }
2576 
2577 void
dhd_bus_dump(dhd_pub_t * dhdp,struct bcmstrbuf * strbuf)2578 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2579 {
2580 	bcm_bprintf(strbuf, "Bus USB\n");
2581 }
2582 
2583 void
dhd_bus_clearcounts(dhd_pub_t * dhdp)2584 dhd_bus_clearcounts(dhd_pub_t *dhdp)
2585 {
2586 }
2587 
2588 int
dhd_bus_txdata(struct dhd_bus * bus,void * pktbuf)2589 dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf)
2590 {
2591 	DBUSTRACE(("%s\n", __FUNCTION__));
2592 	if (bus->txoff) {
2593 		DBUSTRACE(("txoff\n"));
2594 		return BCME_EPERM;
2595 	}
2596 	return dbus_send_pkt(&bus->pub, pktbuf, pktbuf);
2597 }
2598 
2599 int
dhd_bus_txctl(struct dhd_bus * bus,uchar * msg,uint msglen)2600 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2601 {
2602 	int timeleft = 0;
2603 	int ret = -1;
2604 
2605 	DBUSTRACE(("%s: Enter\n", __FUNCTION__));
2606 
2607 	if (bus->dhd->dongle_reset)
2608 		return -EIO;
2609 
2610 	bus->ctl_completed = FALSE;
2611 	ret = dbus_send_ctl(bus, (void *)msg, msglen);
2612 	if (ret) {
2613 		DBUSERR(("%s: dbus_send_ctl error %d\n", __FUNCTION__, ret));
2614 		return ret;
2615 	}
2616 
2617 	timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed);
2618 	if ((!timeleft) || (!bus->ctl_completed)) {
2619 		DBUSERR(("%s: Txctl timeleft %d ctl_completed %d\n",
2620 			__FUNCTION__, timeleft, bus->ctl_completed));
2621 		ret = -1;
2622 	}
2623 
2624 #ifdef INTR_EP_ENABLE
2625 	/* If the ctl write is successfully completed, wait for an acknowledgement
2626 	* that indicates that it is now ok to do ctl read from the dongle
2627 	*/
2628 	if (ret != -1) {
2629 		bus->ctl_completed = FALSE;
2630 		if (dbus_poll_intr(bus->pub)) {
2631 			DBUSERR(("%s: dbus_poll_intr not submitted\n", __FUNCTION__));
2632 		} else {
2633 			/* interrupt polling is sucessfully submitted. Wait for dongle to send
2634 			* interrupt
2635 			*/
2636 			timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed);
2637 			if (!timeleft) {
2638 				DBUSERR(("%s: intr poll wait timed out\n", __FUNCTION__));
2639 			}
2640 		}
2641 	}
2642 #endif /* INTR_EP_ENABLE */
2643 
2644 	return ret;
2645 }
2646 
2647 int
dhd_bus_rxctl(struct dhd_bus * bus,uchar * msg,uint msglen)2648 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2649 {
2650 	int timeleft;
2651 	int ret = -1;
2652 
2653 	DBUSTRACE(("%s: Enter\n", __FUNCTION__));
2654 
2655 	if (bus->dhd->dongle_reset)
2656 		return -EIO;
2657 
2658 	bus->ctl_completed = FALSE;
2659 	ret = dbus_recv_ctl(bus, (uchar*)msg, msglen);
2660 	if (ret) {
2661 		DBUSERR(("%s: dbus_recv_ctl error %d\n", __FUNCTION__, ret));
2662 		goto done;
2663 	}
2664 
2665 	timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->ctl_completed);
2666 	if ((!timeleft) || (!bus->ctl_completed)) {
2667 		DBUSERR(("%s: Rxctl timeleft %d ctl_completed %d\n", __FUNCTION__,
2668 			timeleft, bus->ctl_completed));
2669 		ret = -ETIMEDOUT;
2670 		goto done;
2671 	}
2672 
2673 	/* XXX FIX: Must return cdc_len, not len, because after query_ioctl()
2674 	 * it subtracts sizeof(cdc_ioctl_t);  The other approach is
2675 	 * to have dbus_recv_ctl() return actual len.
2676 	 */
2677 	ret = msglen;
2678 
2679 done:
2680 	return ret;
2681 }
2682 
2683 static void
dhd_dbus_advertise_bus_cleanup(dhd_pub_t * dhdp)2684 dhd_dbus_advertise_bus_cleanup(dhd_pub_t *dhdp)
2685 {
2686 	unsigned long flags;
2687 	int timeleft;
2688 
2689 	DHD_LINUX_GENERAL_LOCK(dhdp, flags);
2690 	dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS;
2691 	DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
2692 
2693 	timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
2694 	if ((timeleft == 0) || (timeleft == 1)) {
2695 		DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
2696 				__FUNCTION__, dhdp->dhd_bus_busy_state));
2697 		ASSERT(0);
2698 	}
2699 
2700 	return;
2701 }
2702 
2703 static void
dhd_dbus_advertise_bus_remove(dhd_pub_t * dhdp)2704 dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp)
2705 {
2706 	unsigned long flags;
2707 	int timeleft;
2708 
2709 	DHD_LINUX_GENERAL_LOCK(dhdp, flags);
2710 	if (dhdp->busstate != DHD_BUS_SUSPEND)
2711 		dhdp->busstate = DHD_BUS_REMOVE;
2712 	DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
2713 
2714 	timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
2715 	if ((timeleft == 0) || (timeleft == 1)) {
2716 		DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
2717 				__FUNCTION__, dhdp->dhd_bus_busy_state));
2718 		ASSERT(0);
2719 	}
2720 
2721 	return;
2722 }
2723 
2724 int
dhd_bus_devreset(dhd_pub_t * dhdp,uint8 flag)2725 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
2726 {
2727 	int bcmerror = 0;
2728 	unsigned long flags;
2729 	wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)dhdp->adapter;
2730 
2731 	if (flag == TRUE) {
2732 		if (!dhdp->dongle_reset) {
2733 			DBUSERR(("%s: == Power OFF ==\n", __FUNCTION__));
2734 			dhd_dbus_advertise_bus_cleanup(dhdp);
2735 			dhd_os_wd_timer(dhdp, 0);
2736 #if !defined(IGNORE_ETH0_DOWN)
2737 			/* Force flow control as protection when stop come before ifconfig_down */
2738 			dhd_txflowcontrol(dhdp, ALL_INTERFACES, ON);
2739 #endif /* !defined(IGNORE_ETH0_DOWN) */
2740 			dbus_stop(dhdp->bus);
2741 
2742 			dhdp->dongle_reset = TRUE;
2743 			dhdp->up = FALSE;
2744 
2745 			DHD_LINUX_GENERAL_LOCK(dhdp, flags);
2746 			dhdp->busstate = DHD_BUS_DOWN;
2747 			DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
2748 			wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY);
2749 
2750 			printf("%s:  WLAN OFF DONE\n", __FUNCTION__);
2751 			/* App can now remove power from device */
2752 		} else
2753 			bcmerror = BCME_ERROR;
2754 	} else {
2755 		/* App must have restored power to device before calling */
2756 		printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
2757 		if (dhdp->dongle_reset) {
2758 			/* Turn on WLAN */
2759 			DHD_MUTEX_UNLOCK();
2760 			wait_event_interruptible_timeout(adapter->status_event,
2761 				wifi_get_adapter_status(adapter, WIFI_STATUS_FW_READY),
2762 				msecs_to_jiffies(DHD_FW_READY_TIMEOUT));
2763 			DHD_MUTEX_LOCK();
2764 			bcmerror = dbus_up(dhdp->bus);
2765 			if (bcmerror == BCME_OK) {
2766 				dhdp->dongle_reset = FALSE;
2767 				dhdp->up = TRUE;
2768 #if !defined(IGNORE_ETH0_DOWN)
2769 				/* Restore flow control  */
2770 				dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
2771 #endif
2772 				dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
2773 
2774 				DBUSTRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
2775 			} else {
2776 				DBUSERR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, bcmerror));
2777 			}
2778 		}
2779 	}
2780 
2781 	return bcmerror;
2782 }
2783 
2784 void
dhd_bus_update_fw_nv_path(struct dhd_bus * bus,char * pfw_path,char * pnv_path,char * pclm_path,char * pconf_path)2785 dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path,
2786 	char *pnv_path, char *pclm_path, char *pconf_path)
2787 {
2788 	DBUSTRACE(("%s\n", __FUNCTION__));
2789 
2790 	if (bus == NULL) {
2791 		DBUSERR(("%s: bus is NULL\n", __FUNCTION__));
2792 		return;
2793 	}
2794 
2795 	bus->fw_path = pfw_path;
2796 	bus->nv_path = pnv_path;
2797 	bus->dhd->clm_path = pclm_path;
2798 	bus->dhd->conf_path = pconf_path;
2799 
2800 	dhd_conf_set_path_params(bus->dhd, bus->fw_path, bus->nv_path);
2801 
2802 }
2803 
2804 static int
dhd_dbus_sync_dongle(dhd_pub_t * pub,int dlneeded)2805 dhd_dbus_sync_dongle(dhd_pub_t *pub, int dlneeded)
2806 {
2807 	int ret = 0;
2808 
2809 	if (dlneeded == 0) {
2810 		ret = dbus_up(pub->bus);
2811 		if (ret) {
2812 			DBUSERR(("%s: dbus_up failed!!\n", __FUNCTION__));
2813 			goto exit;
2814 		}
2815 		ret = dhd_sync_with_dongle(pub);
2816 		if (ret < 0) {
2817 			DBUSERR(("%s: failed with code ret=%d\n", __FUNCTION__, ret));
2818 			goto exit;
2819 		}
2820 	}
2821 
2822 exit:
2823 	return ret;
2824 }
2825 
2826 static int
dbus_suspend(void * context)2827 dbus_suspend(void *context)
2828 {
2829 	int ret = 0;
2830 
2831 #if defined(LINUX)
2832 	dhd_bus_t *bus = (dhd_bus_t*)context;
2833 	unsigned long flags;
2834 
2835 	DBUSERR(("%s Enter\n", __FUNCTION__));
2836 	if (bus->dhd == NULL) {
2837 		DBUSERR(("bus not inited\n"));
2838 		return BCME_ERROR;
2839 	}
2840 	if (bus->dhd->prot == NULL) {
2841 		DBUSERR(("prot is not inited\n"));
2842 		return BCME_ERROR;
2843 	}
2844 
2845 	if (bus->dhd->up == FALSE) {
2846 		return BCME_OK;
2847 	}
2848 
2849 	DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
2850 	if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) {
2851 		DBUSERR(("not in a readystate to LPBK  is not inited\n"));
2852 		DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
2853 		return BCME_ERROR;
2854 	}
2855 	DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
2856 	if (bus->dhd->dongle_reset) {
2857 		DBUSERR(("Dongle is in reset state.\n"));
2858 		return -EIO;
2859 	}
2860 
2861 	DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
2862 	/* stop all interface network queue. */
2863 	dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
2864 	bus->dhd->busstate = DHD_BUS_SUSPEND;
2865 #if defined(LINUX) || defined(linux)
2866 	if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) {
2867 		DBUSERR(("Tx Request is not ended\n"));
2868 		bus->dhd->busstate = DHD_BUS_DATA;
2869 		/* resume all interface network queue. */
2870 		dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
2871 		DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
2872 		return -EBUSY;
2873 	}
2874 #endif /* LINUX || linux */
2875 	DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd);
2876 	DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
2877 
2878 	ret = dhd_os_check_wakelock_all(bus->dhd);
2879 
2880 	DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
2881 	if (ret) {
2882 		bus->dhd->busstate = DHD_BUS_DATA;
2883 		/* resume all interface network queue. */
2884 		dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
2885 	} else {
2886 		bus->last_suspend_end_time = OSL_LOCALTIME_NS();
2887 	}
2888 	bus->dhd->hostsleep = 2;
2889 	DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd);
2890 	dhd_os_busbusy_wake(bus->dhd);
2891 	DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
2892 
2893 #endif /* LINUX */
2894 	DBUSERR(("%s Exit ret=%d\n", __FUNCTION__, ret));
2895 	return ret;
2896 }
2897 
2898 static int
dbus_resume(void * context)2899 dbus_resume(void *context)
2900 {
2901 	dhd_bus_t *bus = (dhd_bus_t*)context;
2902 	ulong flags;
2903 	int dlneeded = 0;
2904 	int ret = 0;
2905 
2906 	DBUSERR(("%s Enter\n", __FUNCTION__));
2907 
2908 	if (bus->dhd->up == FALSE) {
2909 		return BCME_OK;
2910 	}
2911 
2912 	dlneeded = dbus_dlneeded(bus);
2913 	if (dlneeded == 0) {
2914 		ret = dbus_up(bus);
2915 		if (ret) {
2916 			DBUSERR(("%s: dbus_up failed!!\n", __FUNCTION__));
2917 		}
2918 	}
2919 
2920 	DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
2921 	DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd);
2922 	DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
2923 
2924 	DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
2925 	DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd);
2926 	bus->dhd->hostsleep = 0;
2927 	bus->dhd->busstate = DHD_BUS_DATA;
2928 	dhd_os_busbusy_wake(bus->dhd);
2929 	/* resume all interface network queue. */
2930 	dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
2931 	DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
2932 //	dhd_conf_set_suspend_resume(bus->dhd, 0);
2933 
2934 	return 0;
2935 }
2936 
2937 /*
2938  * hdrlen is space to reserve in pkt headroom for DBUS
2939  */
2940 static void *
dhd_dbus_probe_cb(uint16 bus_no,uint16 slot,uint32 hdrlen)2941 dhd_dbus_probe_cb(uint16 bus_no, uint16 slot, uint32 hdrlen)
2942 {
2943 	osl_t *osh = NULL;
2944 	dhd_bus_t *bus = NULL;
2945 	dhd_pub_t *pub = NULL;
2946 	uint rxsz;
2947 	int dlneeded = 0, ret = DBUS_OK;
2948 	wifi_adapter_info_t *adapter = NULL;
2949 	bool net_attach_now = TRUE;
2950 
2951 	DBUSTRACE(("%s: Enter\n", __FUNCTION__));
2952 
2953 	adapter = dhd_wifi_platform_get_adapter(USB_BUS, bus_no, slot);
2954 
2955 	if (!g_pub) {
2956 		/* Ask the OS interface part for an OSL handle */
2957 		if (!(osh = osl_attach(NULL, USB_BUS, TRUE))) {
2958 			DBUSERR(("%s: OSL attach failed\n", __FUNCTION__));
2959 			goto fail;
2960 		}
2961 
2962 		/* Attach to the dhd/OS interface */
2963 		if (!(pub = dhd_attach(osh, bus, hdrlen, adapter))) {
2964 			DBUSERR(("%s: dhd_attach failed\n", __FUNCTION__));
2965 			goto fail;
2966 		}
2967 	} else {
2968 		pub = g_pub;
2969 		osh = pub->osh;
2970 	}
2971 
2972 	if (pub->bus) {
2973 		DBUSERR(("%s: wrong probe\n", __FUNCTION__));
2974 		goto fail;
2975 	}
2976 
2977 	rxsz = dhd_get_rxsz(pub);
2978 	bus = dbus_attach(osh, rxsz, DBUS_NRXQ, DBUS_NTXQ, pub, &dhd_dbus_cbs, NULL, NULL);
2979 	if (bus) {
2980 		pub->bus = bus;
2981 		bus->dhd = pub;
2982 
2983 		dlneeded = dbus_dlneeded(bus);
2984 		if (dlneeded >= 0 && !g_pub) {
2985 			dhd_conf_reset(pub);
2986 			dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev);
2987 			dhd_conf_preinit(pub);
2988 		}
2989 
2990 #if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD)
2991 		if (1)
2992 #else
2993 		if (g_pub || dhd_download_fw_on_driverload)
2994 #endif
2995 		{
2996 			if (dlneeded == 0)
2997 				wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY);
2998 #ifdef BCM_REQUEST_FW
2999 			else if (dlneeded > 0) {
3000 				struct dhd_conf *conf = pub->conf;
3001 				unsigned long flags;
3002 				bool suspended;
3003 				wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY);
3004 				suspended = conf->suspended;
3005 				dhd_set_path(bus->dhd);
3006 				conf->suspended = suspended;
3007 				if (dbus_download_firmware(bus) != DBUS_OK)
3008 					goto fail;
3009 				DHD_LINUX_GENERAL_LOCK(pub, flags);
3010 				if (bus->dhd->busstate != DHD_BUS_SUSPEND)
3011 					bus->dhd->busstate = DHD_BUS_LOAD;
3012 				DHD_LINUX_GENERAL_UNLOCK(pub, flags);
3013 			}
3014 #endif
3015 			else {
3016 				goto fail;
3017 			}
3018 		}
3019 	}
3020 	else {
3021 		DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__));
3022 		goto fail;
3023 	}
3024 
3025 #if defined(BCMDHD_MODULAR) && defined(INSMOD_FW_LOAD)
3026 	if (dlneeded > 0)
3027 		net_attach_now = FALSE;
3028 #endif
3029 
3030 	if (!net_attached && (net_attach_now || (dlneeded == 0))) {
3031 		if (dhd_dbus_sync_dongle(pub, dlneeded)) {
3032 			goto fail;
3033 		}
3034 		if (dhd_attach_net(bus->dhd, TRUE) != 0) {
3035 			DBUSERR(("%s: Net attach failed!!\n", __FUNCTION__));
3036 			goto fail;
3037 		}
3038 		pub->hang_report  = TRUE;
3039 #if defined(MULTIPLE_SUPPLICANT)
3040 		wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
3041 #endif
3042 		net_attached = TRUE;
3043 	}
3044 	else if (net_attached && (pub->up == 1) && (dlneeded == 0)) {
3045 		// kernel resume case
3046 		pub->hostsleep = 0;
3047 		ret = dhd_dbus_sync_dongle(pub, dlneeded);
3048 #ifdef WL_CFG80211
3049 		__wl_cfg80211_up_resume(pub);
3050 		wl_cfgp2p_start_p2p_device_resume(pub);
3051 #endif
3052 		dhd_conf_set_suspend_resume(pub, 0);
3053 		if (ret != DBUS_OK)
3054 			goto fail;
3055 	}
3056 
3057 	if (!g_pub) {
3058 		g_pub = pub;
3059 	}
3060 
3061 	DBUSTRACE(("%s: Exit\n", __FUNCTION__));
3062 	if (net_attached) {
3063 		wifi_set_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED);
3064 		wake_up_interruptible(&adapter->status_event);
3065 		/* This is passed to dhd_dbus_disconnect_cb */
3066 	}
3067 	return bus;
3068 
3069 fail:
3070 	if (pub && pub->bus) {
3071 		dbus_detach(pub->bus);
3072 		pub->bus = NULL;
3073 	}
3074 	/* Release resources in reverse order */
3075 	if (!g_pub) {
3076 		if (pub) {
3077 			dhd_detach(pub);
3078 			dhd_free(pub);
3079 		}
3080 		if (osh) {
3081 			osl_detach(osh);
3082 		}
3083 	}
3084 
3085 	printf("%s: Failed\n", __FUNCTION__);
3086 	return NULL;
3087 }
3088 
3089 static void
dhd_dbus_disconnect_cb(void * arg)3090 dhd_dbus_disconnect_cb(void *arg)
3091 {
3092 	dhd_bus_t *bus = (dhd_bus_t *)arg;
3093 	dhd_pub_t *pub = g_pub;
3094 	osl_t *osh;
3095 	wifi_adapter_info_t *adapter = NULL;
3096 
3097 	adapter = (wifi_adapter_info_t *)pub->adapter;
3098 
3099 	if (pub && !pub->dhd_remove && bus == NULL) {
3100 		DBUSERR(("%s: bus is NULL\n", __FUNCTION__));
3101 		return;
3102 	}
3103 	if (!adapter) {
3104 		DBUSERR(("%s: adapter is NULL\n", __FUNCTION__));
3105 		return;
3106 	}
3107 
3108 	printf("%s: Enter dhd_remove=%d on %s\n", __FUNCTION__,
3109 		pub->dhd_remove, adapter->name);
3110 	if (!pub->dhd_remove) {
3111 		/* Advertise bus remove during rmmod */
3112 		dhd_dbus_advertise_bus_remove(bus->dhd);
3113 		dbus_detach(pub->bus);
3114 		pub->bus = NULL;
3115 		wake_up_interruptible(&adapter->status_event);
3116 	} else {
3117 		osh = pub->osh;
3118 		dhd_detach(pub);
3119 		if (pub->bus) {
3120 			dbus_detach(pub->bus);
3121 			pub->bus = NULL;
3122 		}
3123 		dhd_free(pub);
3124 		g_pub = NULL;
3125 		net_attached = FALSE;
3126 		wifi_clr_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED);
3127 		if (MALLOCED(osh)) {
3128 			DBUSERR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
3129 		}
3130 		osl_detach(osh);
3131 	}
3132 
3133 	DBUSTRACE(("%s: Exit\n", __FUNCTION__));
3134 }
3135 
3136 #ifdef LINUX_EXTERNAL_MODULE_DBUS
3137 
3138 static int __init
bcm_dbus_module_init(void)3139 bcm_dbus_module_init(void)
3140 {
3141 	printf("Inserting bcm_dbus module \n");
3142 	return 0;
3143 }
3144 
3145 static void __exit
bcm_dbus_module_exit(void)3146 bcm_dbus_module_exit(void)
3147 {
3148 	printf("Removing bcm_dbus module \n");
3149 	return;
3150 }
3151 
3152 EXPORT_SYMBOL(dbus_pnp_sleep);
3153 EXPORT_SYMBOL(dhd_bus_register);
3154 EXPORT_SYMBOL(dbus_get_devinfo);
3155 EXPORT_SYMBOL(dbus_detach);
3156 EXPORT_SYMBOL(dbus_get_attrib);
3157 EXPORT_SYMBOL(dbus_down);
3158 EXPORT_SYMBOL(dbus_pnp_resume);
3159 EXPORT_SYMBOL(dbus_set_config);
3160 EXPORT_SYMBOL(dbus_flowctrl_rx);
3161 EXPORT_SYMBOL(dbus_up);
3162 EXPORT_SYMBOL(dbus_get_device_speed);
3163 EXPORT_SYMBOL(dbus_send_pkt);
3164 EXPORT_SYMBOL(dbus_recv_ctl);
3165 EXPORT_SYMBOL(dbus_attach);
3166 EXPORT_SYMBOL(dhd_bus_unregister);
3167 
3168 MODULE_LICENSE("GPL");
3169 
3170 module_init(bcm_dbus_module_init);
3171 module_exit(bcm_dbus_module_exit);
3172 
3173 #endif  /* #ifdef LINUX_EXTERNAL_MODULE_DBUS */
3174