• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Dongle BUS interface for USB, OS independent
4  *
5  * Copyright (C) 1999-2016, Broadcom Corporation
6  *
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  *
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  *
21  *      Notwithstanding the above, under no circumstances may you combine this
22  * software in any way with any other Broadcom software provided under a license
23  * other than the GPL, without Broadcom's express prior written consent.
24  *
25  *
26  * <<Broadcom-WL-IPTag/Open:>>
27  *
28  * $Id: dbus_usb.c 565557 2015-06-22 19:29:44Z $
29  */
30 
31 /**
32  * @file @brief
33  * This file contains DBUS code that is USB, but not OS specific. DBUS is a Broadcom proprietary
34  * host specific abstraction layer.
35  */
36 
37 #include <osl.h>
38 #include <bcmdefs.h>
39 #include <bcmutils.h>
40 #include <dbus.h>
41 #include <usbrdl.h>
42 #include <bcmdevs.h>
43 #include <bcmendian.h>
44 
45 uint dbus_msglevel = DBUS_ERROR_VAL;
46 module_param(dbus_msglevel, int, 0);
47 
48 
49 #define USB_DLIMAGE_RETRY_TIMEOUT    3000    /* retry Timeout */
50 #define USB_SFLASH_DLIMAGE_SPINWAIT  150     /* in unit of ms */
51 #define USB_SFLASH_DLIMAGE_LIMIT     2000    /* spinwait limit (ms) */
52 #define POSTBOOT_ID                  0xA123  /* ID to detect if dongle has boot up */
53 #define USB_RESETCFG_SPINWAIT        1       /* wait after resetcfg (ms) */
54 #define USB_DEV_ISBAD(u)             (u->pub->attrib.devid == 0xDEAD)
55 #define USB_DLGO_SPINWAIT            100     /* wait after DL_GO (ms) */
56 #define TEST_CHIP                    0x4328
57 
58 typedef struct {
59 	dbus_pub_t  *pub;
60 
61 	void        *cbarg;
62 	dbus_intf_callbacks_t *cbs;  /** callbacks into higher DBUS level (dbus.c) */
63 	dbus_intf_t *drvintf;
64 	void        *usbosl_info;
65 	uint32      rdlram_base_addr;
66 	uint32      rdlram_size;
67 } usb_info_t;
68 
69 /*
70  * Callbacks common to all USB
71  */
72 static void dbus_usb_disconnect(void *handle);
73 static void dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb);
74 static void dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status);
75 static void dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status);
76 static void dbus_usb_errhandler(void *handle, int err);
77 static void dbus_usb_ctl_complete(void *handle, int type, int status);
78 static void dbus_usb_state_change(void *handle, int state);
79 static struct dbus_irb* dbus_usb_getirb(void *handle, bool send);
80 static void dbus_usb_rxerr_indicate(void *handle, bool on);
81 #if !defined(BCM_REQUEST_FW)
82 static int dbus_usb_resetcfg(usb_info_t *usbinfo);
83 #endif
84 static int dbus_usb_iovar_op(void *bus, const char *name,
85 	void *params, int plen, void *arg, int len, bool set);
86 static int dbus_iovar_process(usb_info_t* usbinfo, const char *name,
87                  void *params, int plen, void *arg, int len, bool set);
88 static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid,
89 	const char *name, void *params, int plen, void *arg, int len, int val_size);
90 static int dhdusb_downloadvars(usb_info_t *bus, void *arg, int len);
91 
92 static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen);
93 static int dbus_usb_dlstart(void *bus, uint8 *fw, int len);
94 static int dbus_usb_dlneeded(void *bus);
95 static int dbus_usb_dlrun(void *bus);
96 static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo);
97 
98 
99 /* OS specific */
100 extern bool dbus_usbos_dl_cmd(void *info, uint8 cmd, void *buffer, int buflen);
101 extern int dbus_usbos_wait(void *info, uint16 ms);
102 extern int dbus_write_membytes(usb_info_t *usbinfo, bool set, uint32 address,
103 	uint8 *data, uint size);
104 extern bool dbus_usbos_dl_send_bulk(void *info, void *buffer, int len);
105 extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size);
106 
107 /**
108  * These functions are called by the lower DBUS level (dbus_usb_os.c) to notify this DBUS level
109  * (dbus_usb.c) of an event.
110  */
111 static dbus_intf_callbacks_t dbus_usb_intf_cbs = {
112 	dbus_usb_send_irb_timeout,
113 	dbus_usb_send_irb_complete,
114 	dbus_usb_recv_irb_complete,
115 	dbus_usb_errhandler,
116 	dbus_usb_ctl_complete,
117 	dbus_usb_state_change,
118 	NULL,			/* isr */
119 	NULL,			/* dpc */
120 	NULL,			/* watchdog */
121 	NULL,			/* dbus_if_pktget */
122 	NULL, 			/* dbus_if_pktfree */
123 	dbus_usb_getirb,
124 	dbus_usb_rxerr_indicate
125 };
126 
127 /* IOVar table */
128 enum {
129 	IOV_SET_DOWNLOAD_STATE = 1,
130 	IOV_DBUS_MSGLEVEL,
131 	IOV_MEMBYTES,
132 	IOV_VARS,
133 	IOV_LOOPBACK_TX
134 };
135 
136 const bcm_iovar_t dhdusb_iovars[] = {
137 	{"vars",	IOV_VARS,	0,	IOVT_BUFFER,	0 },
138 	{"dbus_msglevel",	IOV_DBUS_MSGLEVEL,	0,	IOVT_UINT32,	0 },
139 	{"dwnldstate",	IOV_SET_DOWNLOAD_STATE,	0,	IOVT_BOOL,	0 },
140 	{"membytes",	IOV_MEMBYTES,	0,	IOVT_BUFFER,	2 * sizeof(int) },
141 	{"usb_lb_txfer", IOV_LOOPBACK_TX, 0,    IOVT_BUFFER,    2 * sizeof(int) },
142 	{NULL, 0, 0, 0, 0 }
143 };
144 
145 /*
146  * Need global for probe() and disconnect() since
147  * attach() is not called at probe and detach()
148  * can be called inside disconnect()
149  */
150 static probe_cb_t	probe_cb = NULL;
151 static disconnect_cb_t	disconnect_cb = NULL;
152 static void		*probe_arg = NULL;
153 static void		*disc_arg = NULL;
154 static dbus_intf_t	*g_dbusintf = NULL;
155 static dbus_intf_t	dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */
156 
157 /*
158  * dbus_intf_t common to all USB
159  * These functions override dbus_usb_<os>.c.
160  */
161 static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs);
162 static void dbus_usb_detach(dbus_pub_t *pub, void *info);
163 static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype,
164 	uint16 bus_no, uint16 slot, uint32 hdrlen);
165 
166 /* functions */
167 
168 /**
169  * As part of DBUS initialization/registration, the higher level DBUS (dbus.c) needs to know what
170  * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c).
171  */
172 static void *
dbus_usb_probe(void * arg,const char * desc,uint32 bustype,uint16 bus_no,uint16 slot,uint32 hdrlen)173 dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no,
174 	uint16 slot, uint32 hdrlen)
175 {
176 	DBUSTRACE(("%s(): \n", __FUNCTION__));
177 	if (probe_cb) {
178 
179 		if (g_dbusintf != NULL) {
180 			/* First, initialize all lower-level functions as default
181 			 * so that dbus.c simply calls directly to dbus_usb_os.c.
182 			 */
183 			bcopy(g_dbusintf, &dbus_usb_intf, sizeof(dbus_intf_t));
184 
185 			/* Second, selectively override functions we need, if any. */
186 			dbus_usb_intf.attach = dbus_usb_attach;
187 			dbus_usb_intf.detach = dbus_usb_detach;
188 			dbus_usb_intf.iovar_op = dbus_usb_iovar_op;
189 			dbus_usb_intf.dlstart = dbus_usb_dlstart;
190 			dbus_usb_intf.dlneeded = dbus_usb_dlneeded;
191 			dbus_usb_intf.dlrun = dbus_usb_dlrun;
192 		}
193 
194 		disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen);
195 		return disc_arg;
196 	}
197 
198 	return NULL;
199 }
200 
201 /**
202  * On return, *intf contains this or lower-level DBUS functions to be called by higher
203  * level (dbus.c)
204  */
205 int
dbus_bus_register(int vid,int pid,probe_cb_t prcb,disconnect_cb_t discb,void * prarg,dbus_intf_t ** intf,void * param1,void * param2)206 dbus_bus_register(int vid, int pid, probe_cb_t prcb,
207 	disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2)
208 {
209 	int err;
210 
211 	DBUSTRACE(("%s(): \n", __FUNCTION__));
212 	probe_cb = prcb;
213 	disconnect_cb = discb;
214 	probe_arg = prarg;
215 
216 	*intf = &dbus_usb_intf;
217 
218 	err = dbus_bus_osl_register(vid, pid, dbus_usb_probe,
219 		dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2);
220 
221 	ASSERT(g_dbusintf);
222 	return err;
223 }
224 
225 int
dbus_bus_deregister()226 dbus_bus_deregister()
227 {
228 	DBUSTRACE(("%s(): \n", __FUNCTION__));
229 	return dbus_bus_osl_deregister();
230 }
231 
232 /** initialization consists of registration followed by 'attach'. */
233 void *
dbus_usb_attach(dbus_pub_t * pub,void * cbarg,dbus_intf_callbacks_t * cbs)234 dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs)
235 {
236 	usb_info_t *usb_info;
237 
238 	DBUSTRACE(("%s(): \n", __FUNCTION__));
239 
240 	if ((g_dbusintf == NULL) || (g_dbusintf->attach == NULL))
241 		return NULL;
242 
243 	/* Sanity check for BUS_INFO() */
244 	ASSERT(OFFSETOF(usb_info_t, pub) == 0);
245 
246 	usb_info = MALLOC(pub->osh, sizeof(usb_info_t));
247 	if (usb_info == NULL)
248 		return NULL;
249 
250 	bzero(usb_info, sizeof(usb_info_t));
251 
252 	usb_info->pub = pub;
253 	usb_info->cbarg = cbarg;
254 	usb_info->cbs = cbs;
255 
256 	usb_info->usbosl_info = (dbus_pub_t *)g_dbusintf->attach(pub,
257 		usb_info, &dbus_usb_intf_cbs);
258 	if (usb_info->usbosl_info == NULL) {
259 		MFREE(pub->osh, usb_info, sizeof(usb_info_t));
260 		return NULL;
261 	}
262 
263 	/* Save USB OS-specific driver entry points */
264 	usb_info->drvintf = g_dbusintf;
265 
266 	pub->bus = usb_info;
267 #if !defined(BCM_REQUEST_FW)
268 	if (!dbus_usb_resetcfg(usb_info)) {
269 		usb_info->pub->busstate = DBUS_STATE_DL_DONE;
270 	}
271 #endif
272 	/* Return Lower layer info */
273 	return (void *) usb_info->usbosl_info;
274 }
275 
276 void
dbus_usb_detach(dbus_pub_t * pub,void * info)277 dbus_usb_detach(dbus_pub_t *pub, void *info)
278 {
279 	usb_info_t *usb_info = (usb_info_t *) pub->bus;
280 	osl_t *osh = pub->osh;
281 
282 	if (usb_info == NULL)
283 		return;
284 
285 	if (usb_info->drvintf && usb_info->drvintf->detach)
286 		usb_info->drvintf->detach(pub, usb_info->usbosl_info);
287 
288 	MFREE(osh, usb_info, sizeof(usb_info_t));
289 }
290 
291 void
dbus_usb_disconnect(void * handle)292 dbus_usb_disconnect(void *handle)
293 {
294 	DBUSTRACE(("%s(): \n", __FUNCTION__));
295 	if (disconnect_cb)
296 		disconnect_cb(disc_arg);
297 }
298 
299 /**
300  * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
301  * notified.
302  */
303 static void
dbus_usb_send_irb_timeout(void * handle,dbus_irb_tx_t * txirb)304 dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb)
305 {
306 	usb_info_t *usb_info = (usb_info_t *) handle;
307 
308 	DBUSTRACE(("%s\n", __FUNCTION__));
309 
310 	if (usb_info == NULL)
311 		return;
312 
313 	if (usb_info->cbs && usb_info->cbs->send_irb_timeout)
314 		usb_info->cbs->send_irb_timeout(usb_info->cbarg, txirb);
315 }
316 
317 /**
318  * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
319  * notified.
320  */
321 static void
dbus_usb_send_irb_complete(void * handle,dbus_irb_tx_t * txirb,int status)322 dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status)
323 {
324 	usb_info_t *usb_info = (usb_info_t *) handle;
325 
326 	if (usb_info == NULL)
327 		return;
328 
329 	if (usb_info->cbs && usb_info->cbs->send_irb_complete)
330 		usb_info->cbs->send_irb_complete(usb_info->cbarg, txirb, status);
331 }
332 
333 /**
334  * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
335  * notified.
336  */
337 static void
dbus_usb_recv_irb_complete(void * handle,dbus_irb_rx_t * rxirb,int status)338 dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status)
339 {
340 	usb_info_t *usb_info = (usb_info_t *) handle;
341 
342 	if (usb_info == NULL)
343 		return;
344 
345 	if (usb_info->cbs && usb_info->cbs->recv_irb_complete)
346 		usb_info->cbs->recv_irb_complete(usb_info->cbarg, rxirb, status);
347 }
348 
349 /** Lower DBUS level (dbus_usb_os.c) requests a free IRB. Pass this on to the higher DBUS level. */
350 static struct dbus_irb*
dbus_usb_getirb(void * handle,bool send)351 dbus_usb_getirb(void *handle, bool send)
352 {
353 	usb_info_t *usb_info = (usb_info_t *) handle;
354 
355 	if (usb_info == NULL)
356 		return NULL;
357 
358 	if (usb_info->cbs && usb_info->cbs->getirb)
359 		return usb_info->cbs->getirb(usb_info->cbarg, send);
360 
361 	return NULL;
362 }
363 
364 /**
365  * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
366  * notified.
367  */
368 static void
dbus_usb_rxerr_indicate(void * handle,bool on)369 dbus_usb_rxerr_indicate(void *handle, bool on)
370 {
371 	usb_info_t *usb_info = (usb_info_t *) handle;
372 
373 	if (usb_info == NULL)
374 		return;
375 
376 	if (usb_info->cbs && usb_info->cbs->rxerr_indicate)
377 		usb_info->cbs->rxerr_indicate(usb_info->cbarg, on);
378 }
379 
380 /**
381  * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
382  * notified.
383  */
384 static void
dbus_usb_errhandler(void * handle,int err)385 dbus_usb_errhandler(void *handle, int err)
386 {
387 	usb_info_t *usb_info = (usb_info_t *) handle;
388 
389 	if (usb_info == NULL)
390 		return;
391 
392 	if (usb_info->cbs && usb_info->cbs->errhandler)
393 		usb_info->cbs->errhandler(usb_info->cbarg, err);
394 }
395 
396 /**
397  * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
398  * notified.
399  */
400 static void
dbus_usb_ctl_complete(void * handle,int type,int status)401 dbus_usb_ctl_complete(void *handle, int type, int status)
402 {
403 	usb_info_t *usb_info = (usb_info_t *) handle;
404 
405 	DBUSTRACE(("%s\n", __FUNCTION__));
406 
407 	if (usb_info == NULL) {
408 		DBUSERR(("%s: usb_info is NULL\n", __FUNCTION__));
409 		return;
410 	}
411 
412 	if (usb_info->cbs && usb_info->cbs->ctl_complete)
413 		usb_info->cbs->ctl_complete(usb_info->cbarg, type, status);
414 }
415 
416 /**
417  * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
418  * notified.
419  */
420 static void
dbus_usb_state_change(void * handle,int state)421 dbus_usb_state_change(void *handle, int state)
422 {
423 	usb_info_t *usb_info = (usb_info_t *) handle;
424 
425 	if (usb_info == NULL)
426 		return;
427 
428 	if (usb_info->cbs && usb_info->cbs->state_change)
429 		usb_info->cbs->state_change(usb_info->cbarg, state);
430 }
431 
432 /** called by higher DBUS level (dbus.c) */
433 static int
dbus_usb_iovar_op(void * bus,const char * name,void * params,int plen,void * arg,int len,bool set)434 dbus_usb_iovar_op(void *bus, const char *name,
435 	void *params, int plen, void *arg, int len, bool set)
436 {
437 	int err = DBUS_OK;
438 
439 	err = dbus_iovar_process((usb_info_t*)bus, name, params, plen, arg, len, set);
440 	return err;
441 }
442 
443 /** process iovar request from higher DBUS level */
444 static int
dbus_iovar_process(usb_info_t * usbinfo,const char * name,void * params,int plen,void * arg,int len,bool set)445 dbus_iovar_process(usb_info_t* usbinfo, const char *name,
446                  void *params, int plen, void *arg, int len, bool set)
447 {
448 	const bcm_iovar_t *vi = NULL;
449 	int bcmerror = 0;
450 	int val_size;
451 	uint32 actionid;
452 
453 	DBUSTRACE(("%s: Enter\n", __FUNCTION__));
454 
455 	ASSERT(name);
456 	ASSERT(len >= 0);
457 
458 	/* Get MUST have return space */
459 	ASSERT(set || (arg && len));
460 
461 	/* Set does NOT take qualifiers */
462 	ASSERT(!set || (!params && !plen));
463 
464 	/* Look up var locally; if not found pass to host driver */
465 	if ((vi = bcm_iovar_lookup(dhdusb_iovars, name)) == NULL) {
466 		/* Not Supported */
467 		bcmerror = BCME_UNSUPPORTED;
468 		DBUSTRACE(("%s: IOVAR %s is not supported\n", name, __FUNCTION__));
469 		goto exit;
470 
471 	}
472 
473 	DBUSTRACE(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
474 	         name, (set ? "set" : "get"), len, plen));
475 
476 	/* set up 'params' pointer in case this is a set command so that
477 	 * the convenience int and bool code can be common to set and get
478 	 */
479 	if (params == NULL) {
480 		params = arg;
481 		plen = len;
482 	}
483 
484 	if (vi->type == IOVT_VOID)
485 		val_size = 0;
486 	else if (vi->type == IOVT_BUFFER)
487 		val_size = len;
488 	else
489 		/* all other types are integer sized */
490 		val_size = sizeof(int);
491 
492 	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
493 	bcmerror = dbus_usb_doiovar(usbinfo, vi, actionid,
494 		name, params, plen, arg, len, val_size);
495 
496 exit:
497 	return bcmerror;
498 } /* dbus_iovar_process */
499 
500 static int
dbus_usb_doiovar(usb_info_t * bus,const bcm_iovar_t * vi,uint32 actionid,const char * name,void * params,int plen,void * arg,int len,int val_size)501 dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
502                 void *params, int plen, void *arg, int len, int val_size)
503 {
504 	int bcmerror = 0;
505 	int32 int_val = 0;
506 	int32 int_val2 = 0;
507 	bool bool_val = 0;
508 
509 	DBUSTRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
510 	           __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
511 
512 	if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
513 		goto exit;
514 
515 	if (plen >= (int)sizeof(int_val))
516 		bcopy(params, &int_val, sizeof(int_val));
517 
518 	if (plen >= (int)sizeof(int_val) * 2)
519 		bcopy((void*)((uintptr)params + sizeof(int_val)), &int_val2, sizeof(int_val2));
520 
521 	bool_val = (int_val != 0) ? TRUE : FALSE;
522 
523 	switch (actionid) {
524 
525 	case IOV_SVAL(IOV_MEMBYTES):
526 	case IOV_GVAL(IOV_MEMBYTES):
527 	{
528 		uint32 address;
529 		uint size, dsize;
530 		uint8 *data;
531 
532 		bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
533 
534 		ASSERT(plen >= 2*sizeof(int));
535 
536 		address = (uint32)int_val;
537 		BCM_REFERENCE(address);
538 		bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
539 		size = (uint)int_val;
540 
541 		/* Do some validation */
542 		dsize = set ? plen - (2 * sizeof(int)) : len;
543 		if (dsize < size) {
544 			DBUSTRACE(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
545 			           __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
546 			bcmerror = BCME_BADARG;
547 			break;
548 		}
549 		DBUSTRACE(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
550 		          (set ? "write" : "read"), size, address));
551 
552 		/* Generate the actual data pointer */
553 		data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
554 
555 		/* Call to do the transfer */
556 		bcmerror = dbus_usb_dl_writeimage(BUS_INFO(bus, usb_info_t), data, size);
557 	}
558 		break;
559 
560 
561 	case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
562 
563 		if (bool_val == TRUE) {
564 			bcmerror = dbus_usb_dlneeded(bus);
565 			dbus_usb_rdl_dwnld_state(BUS_INFO(bus, usb_info_t));
566 		} else {
567 			usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
568 			bcmerror = dbus_usb_dlrun(bus);
569 			usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
570 		}
571 		break;
572 
573 	case IOV_SVAL(IOV_VARS):
574 		bcmerror = dhdusb_downloadvars(BUS_INFO(bus, usb_info_t), arg, len);
575 		break;
576 
577 	case IOV_GVAL(IOV_DBUS_MSGLEVEL):
578 		int_val = (int32)dbus_msglevel;
579 		bcopy(&int_val, arg, val_size);
580 		break;
581 
582 	case IOV_SVAL(IOV_DBUS_MSGLEVEL):
583 		dbus_msglevel = int_val;
584 		break;
585 
586 #ifdef DBUS_USB_LOOPBACK
587 	case IOV_SVAL(IOV_LOOPBACK_TX):
588 			bcmerror = dbus_usbos_loopback_tx(BUS_INFO(bus, usb_info_t), int_val,
589 			  int_val2);
590 			break;
591 #endif
592 	default:
593 		bcmerror = BCME_UNSUPPORTED;
594 		break;
595 	}
596 
597 exit:
598 	return bcmerror;
599 } /* dbus_usb_doiovar */
600 
601 /** higher DBUS level (dbus.c) wants to set NVRAM variables in dongle */
602 static int
dhdusb_downloadvars(usb_info_t * bus,void * arg,int len)603 dhdusb_downloadvars(usb_info_t *bus, void *arg, int len)
604 {
605 	int bcmerror = 0;
606 	uint32 varsize;
607 	uint32 varaddr;
608 	uint32 varsizew;
609 
610 	if (!len) {
611 		bcmerror = BCME_BUFTOOSHORT;
612 		goto err;
613 	}
614 
615 	/* RAM size is not set. Set it at dbus_usb_dlneeded */
616 	if (!bus->rdlram_size)
617 		bcmerror = BCME_ERROR;
618 
619 	/* Even if there are no vars are to be written, we still need to set the ramsize. */
620 	varsize = len ? ROUNDUP(len, 4) : 0;
621 	varaddr = (bus->rdlram_size - 4) - varsize;
622 
623 	/* Write the vars list */
624 	DBUSTRACE(("WriteVars: @%x varsize=%d\n", varaddr, varsize));
625 	bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, (varaddr + bus->rdlram_base_addr),
626 		arg, varsize);
627 
628 	/* adjust to the user specified RAM */
629 	DBUSTRACE(("Usable memory size: %d\n", bus->rdlram_size));
630 	DBUSTRACE(("Vars are at %d, orig varsize is %d\n", varaddr, varsize));
631 
632 	varsize = ((bus->rdlram_size - 4) - varaddr);
633 
634 	/*
635 	 * Determine the length token:
636 	 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
637 	 */
638 	if (bcmerror) {
639 		varsizew = 0;
640 	} else {
641 		varsizew = varsize / 4;
642 		varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
643 		varsizew = htol32(varsizew);
644 	}
645 
646 	DBUSTRACE(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
647 
648 	/* Write the length token to the last word */
649 	bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, ((bus->rdlram_size - 4) +
650 		bus->rdlram_base_addr), (uint8*)&varsizew, 4);
651 err:
652 	return bcmerror;
653 } /* dbus_usb_doiovar */
654 
655 #if !defined(BCM_REQUEST_FW)
656 /**
657  * After downloading firmware into dongle and starting it, we need to know if the firmware is
658  * indeed up and running.
659  */
660 static int
dbus_usb_resetcfg(usb_info_t * usbinfo)661 dbus_usb_resetcfg(usb_info_t *usbinfo)
662 {
663 	void *osinfo;
664 	bootrom_id_t id;
665 	uint16 waittime = 0;
666 
667 	uint32 starttime = 0;
668 	uint32 endtime = 0;
669 
670 	DBUSTRACE(("%s\n", __FUNCTION__));
671 
672 	if (usbinfo == NULL)
673 		return DBUS_ERR;
674 
675 	osinfo = usbinfo->usbosl_info;
676 	ASSERT(osinfo);
677 
678 	/* Give dongle chance to boot */
679 	dbus_usbos_wait(osinfo, USB_SFLASH_DLIMAGE_SPINWAIT);
680 	waittime = USB_SFLASH_DLIMAGE_SPINWAIT;
681 	while (waittime < USB_DLIMAGE_RETRY_TIMEOUT) {
682 
683 		starttime = OSL_SYSUPTIME();
684 
685 		id.chip = 0xDEAD;       /* Get the ID */
686 		dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t));
687 		id.chip = ltoh32(id.chip);
688 
689 		endtime = OSL_SYSUPTIME();
690 		waittime += (endtime - starttime);
691 
692 		if (id.chip == POSTBOOT_ID)
693 			break;
694 	}
695 
696 	if (id.chip == POSTBOOT_ID) {
697 		DBUSERR(("%s: download done. Bootup time = %d ms postboot chip 0x%x/rev 0x%x\n",
698 			__FUNCTION__, waittime, id.chip, id.chiprev));
699 
700 		dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t));
701 
702 		dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT);
703 		return DBUS_OK;
704 	} else {
705 		DBUSERR(("%s: Cannot talk to Dongle. Wait time = %d ms. Firmware is not UP \n",
706 			__FUNCTION__, waittime));
707 		return DBUS_ERR;
708 	}
709 
710 	return DBUS_OK;
711 }
712 #endif
713 
714 /** before firmware download, the dongle has to be prepared to receive the fw image */
715 static int
dbus_usb_rdl_dwnld_state(usb_info_t * usbinfo)716 dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo)
717 {
718 	void *osinfo = usbinfo->usbosl_info;
719 	rdl_state_t state;
720 	int err = DBUS_OK;
721 
722 	/* 1) Prepare USB boot loader for runtime image */
723 	dbus_usbos_dl_cmd(osinfo, DL_START, &state, sizeof(rdl_state_t));
724 
725 	state.state = ltoh32(state.state);
726 	state.bytes = ltoh32(state.bytes);
727 
728 	/* 2) Check we are in the Waiting state */
729 	if (state.state != DL_WAITING) {
730 		DBUSERR(("%s: Failed to DL_START\n", __FUNCTION__));
731 		err = DBUS_ERR;
732 		goto fail;
733 	}
734 
735 fail:
736 	return err;
737 }
738 
739 /**
740  * Dongle contains bootcode in ROM but firmware is (partially) contained in dongle RAM. Therefore,
741  * firmware has to be downloaded into dongle RAM.
742  */
743 static int
dbus_usb_dl_writeimage(usb_info_t * usbinfo,uint8 * fw,int fwlen)744 dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen)
745 {
746 	osl_t *osh = usbinfo->pub->osh;
747 	void *osinfo = usbinfo->usbosl_info;
748 	unsigned int sendlen, sent, dllen;
749 	char *bulkchunk = NULL, *dlpos;
750 	rdl_state_t state;
751 	int err = DBUS_OK;
752 	bootrom_id_t id;
753 	uint16 wait, wait_time;
754 	uint32 dl_trunk_size = RDL_CHUNK;
755 
756 	if (BCM4350_CHIP(usbinfo->pub->attrib.devid))
757 		dl_trunk_size = RDL_CHUNK_MAX;
758 
759 	while (!bulkchunk) {
760 		bulkchunk = MALLOC(osh, dl_trunk_size);
761 		if (dl_trunk_size == RDL_CHUNK)
762 			break;
763 		if (!bulkchunk) {
764 			dl_trunk_size /= 2;
765 			if (dl_trunk_size < RDL_CHUNK)
766 				dl_trunk_size = RDL_CHUNK;
767 		}
768 	}
769 
770 	if (bulkchunk == NULL) {
771 		err = DBUS_ERR;
772 		goto fail;
773 	}
774 
775 	sent = 0;
776 	dlpos = fw;
777 	dllen = fwlen;
778 
779 	/* Get chip id and rev */
780 	id.chip = usbinfo->pub->attrib.devid;
781 	id.chiprev = usbinfo->pub->attrib.chiprev;
782 
783 	DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen));
784 
785 	dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t));
786 
787 	/* 3) Load the image */
788 	while ((sent < dllen)) {
789 		/* Wait until the usb device reports it received all the bytes we sent */
790 
791 		if (sent < dllen) {
792 			if ((dllen-sent) < dl_trunk_size)
793 				sendlen = dllen-sent;
794 			else
795 				sendlen = dl_trunk_size;
796 
797 			/* simply avoid having to send a ZLP by ensuring we never have an even
798 			 * multiple of 64
799 			 */
800 			if (!(sendlen % 64))
801 				sendlen -= 4;
802 
803 			/* send data */
804 			memcpy(bulkchunk, dlpos, sendlen);
805 			if (!dbus_usbos_dl_send_bulk(osinfo, bulkchunk, sendlen)) {
806 				err = DBUS_ERR;
807 				goto fail;
808 			}
809 
810 			dlpos += sendlen;
811 			sent += sendlen;
812 			DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen));
813 		}
814 
815 		wait = 0;
816 		wait_time = USB_SFLASH_DLIMAGE_SPINWAIT;
817 		while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state,
818 			sizeof(rdl_state_t))) {
819 			if ((id.chip == 43236) && (id.chiprev == 0)) {
820 				DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check "
821 					 "completion!!!\n", __FUNCTION__));
822 				dbus_usbos_wait(osinfo, wait_time);
823 				wait += wait_time;
824 				if (wait >= USB_SFLASH_DLIMAGE_LIMIT) {
825 					DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
826 					err = DBUS_ERR;
827 					goto fail;
828 					break;
829 				}
830 			} else {
831 				DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
832 				err = DBUS_ERR;
833 				goto fail;
834 			}
835 		}
836 
837 		state.state = ltoh32(state.state);
838 		state.bytes = ltoh32(state.bytes);
839 
840 		/* restart if an error is reported */
841 		if ((state.state == DL_BAD_HDR) || (state.state == DL_BAD_CRC)) {
842 			DBUSERR(("%s: Bad Hdr or Bad CRC\n", __FUNCTION__));
843 			err = DBUS_ERR;
844 			goto fail;
845 		}
846 
847 	}
848 fail:
849 	if (bulkchunk)
850 		MFREE(osh, bulkchunk, dl_trunk_size);
851 
852 	return err;
853 } /* dbus_usb_dl_writeimage */
854 
855 /** Higher level DBUS layer (dbus.c) requests this layer to download image into dongle */
856 static int
dbus_usb_dlstart(void * bus,uint8 * fw,int len)857 dbus_usb_dlstart(void *bus, uint8 *fw, int len)
858 {
859 	usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
860 	int err;
861 
862 	DBUSTRACE(("%s\n", __FUNCTION__));
863 
864 	if (usbinfo == NULL)
865 		return DBUS_ERR;
866 
867 	if (USB_DEV_ISBAD(usbinfo))
868 		return DBUS_ERR;
869 
870 	err = dbus_usb_rdl_dwnld_state(usbinfo);
871 
872 	if (DBUS_OK == err) {
873 		err = dbus_usb_dl_writeimage(usbinfo, fw, len);
874 		if (err == DBUS_OK)
875 			usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
876 		else
877 			usbinfo->pub->busstate = DBUS_STATE_DL_PENDING;
878 	} else
879 		usbinfo->pub->busstate = DBUS_STATE_DL_PENDING;
880 
881 	return err;
882 }
883 
884 static bool
dbus_usb_update_chipinfo(usb_info_t * usbinfo,uint32 chip)885 dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip)
886 {
887 	bool retval = TRUE;
888 	/* based on the CHIP Id, store the ram size which is needed for NVRAM download. */
889 	switch (chip) {
890 
891 		case 0x4319:
892 			usbinfo->rdlram_size = RDL_RAM_SIZE_4319;
893 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319;
894 			break;
895 
896 		case 0x4329:
897 			usbinfo->rdlram_size = RDL_RAM_SIZE_4329;
898 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329;
899 			break;
900 
901 		case 43234:
902 		case 43235:
903 		case 43236:
904 			usbinfo->rdlram_size = RDL_RAM_SIZE_43236;
905 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236;
906 			break;
907 
908 		case 0x4328:
909 			usbinfo->rdlram_size = RDL_RAM_SIZE_4328;
910 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328;
911 			break;
912 
913 		case 0x4322:
914 			usbinfo->rdlram_size = RDL_RAM_SIZE_4322;
915 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322;
916 			break;
917 
918 		case 0x4360:
919 		case 0xAA06:
920 			usbinfo->rdlram_size = RDL_RAM_SIZE_4360;
921 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4360;
922 			break;
923 
924 		case 43242:
925 		case 43243:
926 			usbinfo->rdlram_size = RDL_RAM_SIZE_43242;
927 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_43242;
928 			break;
929 
930 		case 43143:
931 			usbinfo->rdlram_size = RDL_RAM_SIZE_43143;
932 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_43143;
933 			break;
934 
935 		case 0x4350:
936 		case 43556:
937 		case 43558:
938 		case 43569:
939 			usbinfo->rdlram_size = RDL_RAM_SIZE_4350;
940 			usbinfo->rdlram_base_addr = RDL_RAM_BASE_4350;
941 			break;
942 
943 		case POSTBOOT_ID:
944 			break;
945 
946 		default:
947 			DBUSERR(("%s: Chip 0x%x Ram size is not known\n", __FUNCTION__, chip));
948 			retval = FALSE;
949 			break;
950 
951 	}
952 
953 	return retval;
954 } /* dbus_usb_update_chipinfo */
955 
956 /** higher DBUS level (dbus.c) wants to know if firmware download is required. */
957 static int
dbus_usb_dlneeded(void * bus)958 dbus_usb_dlneeded(void *bus)
959 {
960 	usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
961 	void *osinfo;
962 	bootrom_id_t id;
963 	int dl_needed = 1;
964 
965 	DBUSTRACE(("%s\n", __FUNCTION__));
966 
967 	if (usbinfo == NULL)
968 		return DBUS_ERR;
969 
970 	osinfo = usbinfo->usbosl_info;
971 	ASSERT(osinfo);
972 
973 	/* Check if firmware downloaded already by querying runtime ID */
974 	id.chip = 0xDEAD;
975 	dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t));
976 
977 	id.chip = ltoh32(id.chip);
978 	id.chiprev = ltoh32(id.chiprev);
979 
980 	if (FALSE == dbus_usb_update_chipinfo(usbinfo, id.chip)) {
981 		dl_needed = DBUS_ERR;
982 		goto exit;
983 	}
984 
985 	DBUSERR(("%s: chip 0x%x rev 0x%x\n", __FUNCTION__, id.chip, id.chiprev));
986 	if (id.chip == POSTBOOT_ID) {
987 		/* This code is  needed to support two enumerations on USB1.1 scenario */
988 		DBUSERR(("%s: Firmware already downloaded\n", __FUNCTION__));
989 
990 		dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t));
991 		dl_needed = DBUS_OK;
992 		if (usbinfo->pub->busstate == DBUS_STATE_DL_PENDING)
993 			usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
994 	} else {
995 		usbinfo->pub->attrib.devid = id.chip;
996 		usbinfo->pub->attrib.chiprev = id.chiprev;
997 	}
998 
999 exit:
1000 	return dl_needed;
1001 }
1002 
1003 /** After issuing firmware download, higher DBUS level (dbus.c) wants to start the firmware. */
1004 static int
dbus_usb_dlrun(void * bus)1005 dbus_usb_dlrun(void *bus)
1006 {
1007 	usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
1008 	void *osinfo;
1009 	rdl_state_t state;
1010 	int err = DBUS_OK;
1011 
1012 	DBUSTRACE(("%s\n", __FUNCTION__));
1013 
1014 	if (usbinfo == NULL)
1015 		return DBUS_ERR;
1016 
1017 	if (USB_DEV_ISBAD(usbinfo))
1018 		return DBUS_ERR;
1019 
1020 	osinfo = usbinfo->usbosl_info;
1021 	ASSERT(osinfo);
1022 
1023 	/* Check we are runnable */
1024 	dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t));
1025 
1026 	state.state = ltoh32(state.state);
1027 	state.bytes = ltoh32(state.bytes);
1028 
1029 	/* Start the image */
1030 	if (state.state == DL_RUNNABLE) {
1031 		DBUSTRACE(("%s: Issue DL_GO\n", __FUNCTION__));
1032 		dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t));
1033 
1034 		if (usbinfo->pub->attrib.devid == TEST_CHIP)
1035 			dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT);
1036 
1037 //		dbus_usb_resetcfg(usbinfo);
1038 		/* The Donlge may go for re-enumeration. */
1039 	} else {
1040 		DBUSERR(("%s: Dongle not runnable\n", __FUNCTION__));
1041 		err = DBUS_ERR;
1042 	}
1043 
1044 	return err;
1045 }
1046 
1047 /**
1048  * As preparation for firmware download, higher DBUS level (dbus.c) requests the firmware image
1049  * to be used for the type of dongle detected. Directly called by dbus.c (so not via a callback
1050  * construction)
1051  */
1052 void
dbus_bus_fw_get(void * bus,uint8 ** fw,int * fwlen,int * decomp)1053 dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp)
1054 {
1055 	usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
1056 	unsigned int devid;
1057 	unsigned int crev;
1058 
1059 	devid = usbinfo->pub->attrib.devid;
1060 	crev = usbinfo->pub->attrib.chiprev;
1061 
1062 	*fw = NULL;
1063 	*fwlen = 0;
1064 
1065 	switch (devid) {
1066 	case BCM43236_CHIP_ID:
1067 	case BCM43235_CHIP_ID:
1068 	case BCM43234_CHIP_ID:
1069 	case BCM43238_CHIP_ID: {
1070 		if (crev == 3 || crev == 2 || crev == 1) {
1071 #ifdef EMBED_IMAGE_43236b
1072 			*fw = (uint8 *)dlarray_43236b;
1073 			*fwlen = sizeof(dlarray_43236b);
1074 
1075 #endif
1076 		}
1077 		} break;
1078 	case BCM4360_CHIP_ID:
1079 	case BCM4352_CHIP_ID:
1080 	case BCM43526_CHIP_ID:
1081 #ifdef EMBED_IMAGE_43526a
1082 		if (crev <= 2) {
1083 			*fw = (uint8 *)dlarray_43526a;
1084 			*fwlen = sizeof(dlarray_43526a);
1085 		}
1086 #endif
1087 #ifdef EMBED_IMAGE_43526b
1088 		if (crev > 2) {
1089 			*fw = (uint8 *)dlarray_43526b;
1090 			*fwlen = sizeof(dlarray_43526b);
1091 		}
1092 #endif
1093 		break;
1094 
1095 	case BCM43242_CHIP_ID:
1096 #ifdef EMBED_IMAGE_43242a0
1097 		*fw = (uint8 *)dlarray_43242a0;
1098 		*fwlen = sizeof(dlarray_43242a0);
1099 #endif
1100 		break;
1101 
1102 	case BCM43143_CHIP_ID:
1103 #ifdef EMBED_IMAGE_43143a0
1104 		*fw = (uint8 *)dlarray_43143a0;
1105 		*fwlen = sizeof(dlarray_43143a0);
1106 #endif
1107 #ifdef EMBED_IMAGE_43143b0
1108 		*fw = (uint8 *)dlarray_43143b0;
1109 		*fwlen = sizeof(dlarray_43143b0);
1110 #endif
1111 		break;
1112 
1113 	case BCM4350_CHIP_ID:
1114 	case BCM4354_CHIP_ID:
1115 	case BCM43556_CHIP_ID:
1116 	case BCM43558_CHIP_ID:
1117 	case BCM43566_CHIP_ID:
1118 	case BCM43568_CHIP_ID:
1119 	case BCM43570_CHIP_ID:
1120 	case BCM4358_CHIP_ID:
1121 #ifdef EMBED_IMAGE_4350a0
1122 		if (crev == 0) {
1123 			*fw = (uint8 *)dlarray_4350a0;
1124 			*fwlen = sizeof(dlarray_4350a0);
1125 		}
1126 #endif
1127 #ifdef EMBED_IMAGE_4350b0
1128 		if (crev == 1) {
1129 			*fw = (uint8 *)dlarray_4350b0;
1130 			*fwlen = sizeof(dlarray_4350b0);
1131 		}
1132 #endif
1133 #ifdef EMBED_IMAGE_4350b1
1134 		if (crev == 2) {
1135 			*fw = (uint8 *)dlarray_4350b1;
1136 			*fwlen = sizeof(dlarray_4350b1);
1137 		}
1138 #endif
1139 #ifdef EMBED_IMAGE_43556b1
1140 		if (crev == 2) {
1141 			*fw = (uint8 *)dlarray_43556b1;
1142 			*fwlen = sizeof(dlarray_43556b1);
1143 		}
1144 #endif
1145 #ifdef EMBED_IMAGE_4350c0
1146 		if (crev == 3) {
1147 			*fw = (uint8 *)dlarray_4350c0;
1148 			*fwlen = sizeof(dlarray_4350c0);
1149 		}
1150 #endif /* EMBED_IMAGE_4350c0 */
1151 #ifdef EMBED_IMAGE_4350c1
1152 		if (crev == 4) {
1153 			*fw = (uint8 *)dlarray_4350c1;
1154 			*fwlen = sizeof(dlarray_4350c1);
1155 		}
1156 #endif /* EMBED_IMAGE_4350c1 */
1157 		break;
1158 	case BCM43569_CHIP_ID:
1159 #ifdef EMBED_IMAGE_43569a0
1160 		if (crev == 0) {
1161 			*fw = (uint8 *)dlarray_43569a0;
1162 			*fwlen = sizeof(dlarray_43569a0);
1163 		}
1164 #endif /* EMBED_IMAGE_43569a0 */
1165 		break;
1166 	default:
1167 #ifdef EMBED_IMAGE_GENERIC
1168 		*fw = (uint8 *)dlarray;
1169 		*fwlen = sizeof(dlarray);
1170 #endif
1171 		break;
1172 	}
1173 } /* dbus_bus_fw_get */
1174