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