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