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