shared ARM updates
[tomato.git] / release / src-rt-6.x.4708 / shared / dbus_usb.c
blobc7feceee4a1892bfb895dd29da4d7529bc90d384
1 /*
2 * Dongle BUS interface for USB, OS independent
4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: dbus_usb.c 408461 2013-06-19 06:50:14Z $
21 #include <osl.h>
22 #include <bcmdefs.h>
23 #include <bcmutils.h>
24 #include <dbus.h>
25 #include <usbrdl.h>
26 #include <bcmdevs.h>
27 #include <bcmendian.h>
29 #if defined(BCM_DNGL_EMBEDIMAGE)
30 #ifdef EMBED_IMAGE_43236b
31 #include "rtecdc_43236b.h"
32 #endif /* EMBED_IMAGE_43236b */
33 #ifdef EMBED_IMAGE_43238b
34 #include "rtecdc_43238b.h"
35 #endif /* EMBED_IMAGE_43238b */
36 #ifdef EMBED_IMAGE_43526a
37 #include "rtecdc_43526a.h"
38 #endif /* EMBED_IMAGE_43526a */
39 #ifdef EMBED_IMAGE_43526b
40 #include "rtecdc_43526b.h"
41 #endif /* EMBED_IMAGE_43526b */
42 #ifdef EMBED_IMAGE_4360b
43 #include "rtecdc_4360b.h"
44 #endif /* EMBED_IMAGE_4360b */
45 #ifdef EMBED_IMAGE_43242a0
46 #include "rtecdc_43242a0.h"
47 #endif /* EMBED_IMAGE_43242a0 */
48 #ifdef EMBED_IMAGE_43242a1
49 #include "rtecdc_43242a1.h"
50 #endif /* EMBED_IMAGE_43242a1 */
51 #ifdef EMBED_IMAGE_43143a0
52 #include "rtecdc_43143a0.h"
53 #endif /* EMBED_IMAGE_43143a0 */
54 #ifdef EMBED_IMAGE_43143b0
55 #include "rtecdc_43143b0.h"
56 #endif /* EMBED_IMAGE_43143b0 */
57 #ifdef EMBED_IMAGE_4350a0
58 #include "rtecdc_4350a0.h"
59 #endif /* EMBED_IMAGE_4350a0 */
60 #ifdef EMBED_IMAGE_4350b0
61 #include "rtecdc_4350b0.h"
62 #endif /* EMBED_IMAGE_4350b0 */
63 #ifdef EMBED_IMAGE_4350b1
64 #include "rtecdc_4350b1.h"
65 #endif /* EMBED_IMAGE_4350b1 */
66 #ifdef EMBED_IMAGE_GENERIC
67 #include "rtecdc.h"
68 #endif
69 #endif /* BCM_DNGL_EMBEDIMAGE */
71 #define USB_DLIMAGE_SPINWAIT 10 /* in unit of ms */
72 #define USB_DLIMAGE_LIMIT 500 /* spinwait limit (ms) */
73 #define USB_SFLASH_DLIMAGE_SPINWAIT 200 /* in unit of ms */
74 #define USB_SFLASH_DLIMAGE_LIMIT 2000 /* spinwait limit (ms) */
75 #define POSTBOOT_ID 0xA123 /* ID to detect if dongle has boot up */
76 #define USB_RESETCFG_SPINWAIT 1 /* wait after resetcfg (ms) */
77 #define USB_DEV_ISBAD(u) (u->pub->attrib.devid == 0xDEAD)
78 #define USB_DLGO_SPINWAIT 100 /* wait after DL_GO (ms) */
79 #define TEST_CHIP 0x4328
81 typedef struct {
82 dbus_pub_t *pub;
84 void *cbarg;
85 dbus_intf_callbacks_t *cbs;
86 dbus_intf_t *drvintf;
87 void *usbosl_info;
88 uint32 rdlram_base_addr;
89 uint32 rdlram_size;
90 } usb_info_t;
93 * Callbacks common to all USB
95 static void dbus_usb_disconnect(void *handle);
96 static void dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb);
97 static void dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status);
98 static void dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status);
99 static void dbus_usb_errhandler(void *handle, int err);
100 static void dbus_usb_ctl_complete(void *handle, int type, int status);
101 static void dbus_usb_state_change(void *handle, int state);
102 static struct dbus_irb* dbus_usb_getirb(void *handle, bool send);
103 static void dbus_usb_rxerr_indicate(void *handle, bool on);
104 static int dbus_usb_resetcfg(usb_info_t *usbinfo);
105 static int dbus_usb_iovar_op(void *bus, const char *name,
106 void *params, int plen, void *arg, int len, bool set);
107 static int dbus_iovar_process(usb_info_t* usbinfo, const char *name,
108 void *params, int plen, void *arg, int len, bool set);
109 static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid,
110 const char *name, void *params, int plen, void *arg, int len, int val_size);
111 static int dhdusb_downloadvars(usb_info_t *bus, void *arg, int len);
113 static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen);
114 static int dbus_usb_dlstart(void *bus, uint8 *fw, int len);
115 static bool dbus_usb_dlneeded(void *bus);
116 static int dbus_usb_dlrun(void *bus);
117 static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo);
119 #ifdef BCM_DNGL_EMBEDIMAGE
120 static bool dbus_usb_device_exists(void *bus);
121 #endif
123 /* OS specific */
124 extern bool dbus_usbos_dl_cmd(void *info, uint8 cmd, void *buffer, int buflen);
125 extern int dbus_usbos_wait(void *info, uint16 ms);
126 extern int dbus_write_membytes(usb_info_t *usbinfo, bool set, uint32 address,
127 uint8 *data, uint size);
128 extern bool dbus_usbos_dl_send_bulk(void *info, void *buffer, int len);
130 static dbus_intf_callbacks_t dbus_usb_intf_cbs = {
131 dbus_usb_send_irb_timeout,
132 dbus_usb_send_irb_complete,
133 dbus_usb_recv_irb_complete,
134 dbus_usb_errhandler,
135 dbus_usb_ctl_complete,
136 dbus_usb_state_change,
137 NULL, /* isr */
138 NULL, /* dpc */
139 NULL, /* watchdog */
140 NULL, /* dbus_if_pktget */
141 NULL, /* dbus_if_pktfree */
142 dbus_usb_getirb,
143 dbus_usb_rxerr_indicate
146 /* IOVar table */
147 enum {
148 IOV_SET_DOWNLOAD_STATE = 1,
149 IOV_MEMBYTES,
150 IOV_VARS
153 const bcm_iovar_t dhdusb_iovars[] = {
154 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
155 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
156 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
157 {NULL, 0, 0, 0, 0 }
161 * Need global for probe() and disconnect() since
162 * attach() is not called at probe and detach()
163 * can be called inside disconnect()
165 static probe_cb_t probe_cb = NULL;
166 static disconnect_cb_t disconnect_cb = NULL;
167 static void *probe_arg = NULL;
168 static void *disc_arg = NULL;
169 static dbus_intf_t *g_dbusintf = NULL;
170 static dbus_intf_t dbus_usb_intf;
173 * dbus_intf_t common to all USB
174 * These functions override dbus_usb_<os>.c.
176 static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs);
177 static void dbus_usb_detach(dbus_pub_t *pub, void *info);
178 static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint32 hdrlen);
180 /* functions */
183 * As part of DBUS initialization/registration, the higher level DBUS (dbus.c) needs to know what
184 * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c).
186 static void *
187 dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint32 hdrlen)
189 if (probe_cb) {
191 if (g_dbusintf != NULL) {
192 /* First, initialize all lower-level functions as default
193 * so that dbus.c simply calls directly to dbus_usb_os.c.
195 bcopy(g_dbusintf, &dbus_usb_intf, sizeof(dbus_intf_t));
197 /* Second, selectively override functions we need, if any. */
198 dbus_usb_intf.attach = dbus_usb_attach;
199 dbus_usb_intf.detach = dbus_usb_detach;
200 dbus_usb_intf.iovar_op = dbus_usb_iovar_op;
201 dbus_usb_intf.dlstart = dbus_usb_dlstart;
202 dbus_usb_intf.dlneeded = dbus_usb_dlneeded;
203 dbus_usb_intf.dlrun = dbus_usb_dlrun;
204 #ifdef BCM_DNGL_EMBEDIMAGE
205 dbus_usb_intf.device_exists = dbus_usb_device_exists;
206 #endif
209 disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, hdrlen);
210 return disc_arg;
213 return NULL;
217 * On return, *intf contains this or lower-level DBUS functions to be called by higher
218 * level (dbus.c)
221 dbus_bus_register(int vid, int pid, probe_cb_t prcb,
222 disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2)
224 int err;
226 probe_cb = prcb;
227 disconnect_cb = discb;
228 probe_arg = prarg;
230 *intf = &dbus_usb_intf;
232 err = dbus_bus_osl_register(vid, pid, dbus_usb_probe,
233 dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2);
235 ASSERT(g_dbusintf);
236 return err;
240 dbus_bus_deregister()
242 return dbus_bus_osl_deregister();
245 /** initialization consists of registration followed by 'attach'. */
246 void *
247 dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs)
249 usb_info_t *usb_info;
251 if ((g_dbusintf == NULL) || (g_dbusintf->attach == NULL))
252 return NULL;
254 /* Sanity check for BUS_INFO() */
255 ASSERT(OFFSETOF(usb_info_t, pub) == 0);
257 usb_info = MALLOC(pub->osh, sizeof(usb_info_t));
258 if (usb_info == NULL)
259 return NULL;
261 bzero(usb_info, sizeof(usb_info_t));
263 usb_info->pub = pub;
264 usb_info->cbarg = cbarg;
265 usb_info->cbs = cbs;
267 usb_info->usbosl_info = (dbus_pub_t *)g_dbusintf->attach(pub,
268 usb_info, &dbus_usb_intf_cbs);
269 if (usb_info->usbosl_info == NULL) {
270 MFREE(pub->osh, usb_info, sizeof(usb_info_t));
271 return NULL;
274 /* Save USB OS-specific driver entry points */
275 usb_info->drvintf = g_dbusintf;
277 pub->bus = usb_info;
278 #if !defined(BCM_DNGL_EMBEDIMAGE) && !defined(BCM_REQUEST_FW)
280 if (!dbus_usb_resetcfg(usb_info)) {
281 usb_info->pub->busstate = DBUS_STATE_DL_DONE;
283 #endif
284 /* Return Lower layer info */
285 return (void *) usb_info->usbosl_info;
288 void
289 dbus_usb_detach(dbus_pub_t *pub, void *info)
291 usb_info_t *usb_info = (usb_info_t *) pub->bus;
292 osl_t *osh = pub->osh;
294 if (usb_info == NULL)
295 return;
297 if (usb_info->drvintf && usb_info->drvintf->detach)
298 usb_info->drvintf->detach(pub, usb_info->usbosl_info);
300 MFREE(osh, usb_info, sizeof(usb_info_t));
303 void
304 dbus_usb_disconnect(void *handle)
306 if (disconnect_cb)
307 disconnect_cb(disc_arg);
311 * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
312 * notified.
314 static void
315 dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb)
317 usb_info_t *usb_info = (usb_info_t *) handle;
319 DBUSTRACE(("%s\n", __FUNCTION__));
321 if (usb_info == NULL)
322 return;
324 if (usb_info->cbs && usb_info->cbs->send_irb_timeout)
325 usb_info->cbs->send_irb_timeout(usb_info->cbarg, txirb);
329 * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
330 * notified.
332 static void
333 dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status)
335 usb_info_t *usb_info = (usb_info_t *) handle;
337 if (usb_info == NULL)
338 return;
340 if (usb_info->cbs && usb_info->cbs->send_irb_complete)
341 usb_info->cbs->send_irb_complete(usb_info->cbarg, txirb, status);
345 * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
346 * notified.
348 static void
349 dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status)
351 usb_info_t *usb_info = (usb_info_t *) handle;
353 if (usb_info == NULL)
354 return;
356 if (usb_info->cbs && usb_info->cbs->recv_irb_complete)
357 usb_info->cbs->recv_irb_complete(usb_info->cbarg, rxirb, status);
360 /** Lower DBUS level (dbus_usb_os.c) requests a free IRB. Pass this on to the higher DBUS level. */
361 static struct dbus_irb*
362 dbus_usb_getirb(void *handle, bool send)
364 usb_info_t *usb_info = (usb_info_t *) handle;
366 if (usb_info == NULL)
367 return NULL;
369 if (usb_info->cbs && usb_info->cbs->getirb)
370 return usb_info->cbs->getirb(usb_info->cbarg, send);
372 return NULL;
376 * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
377 * notified.
379 static void
380 dbus_usb_rxerr_indicate(void *handle, bool on)
382 usb_info_t *usb_info = (usb_info_t *) handle;
384 if (usb_info == NULL)
385 return;
387 if (usb_info->cbs && usb_info->cbs->rxerr_indicate)
388 usb_info->cbs->rxerr_indicate(usb_info->cbarg, on);
392 * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
393 * notified.
395 static void
396 dbus_usb_errhandler(void *handle, int err)
398 usb_info_t *usb_info = (usb_info_t *) handle;
400 if (usb_info == NULL)
401 return;
403 if (usb_info->cbs && usb_info->cbs->errhandler)
404 usb_info->cbs->errhandler(usb_info->cbarg, err);
408 * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
409 * notified.
411 static void
412 dbus_usb_ctl_complete(void *handle, int type, int status)
414 usb_info_t *usb_info = (usb_info_t *) handle;
416 if (usb_info == NULL)
417 return;
419 if (usb_info->cbs && usb_info->cbs->ctl_complete)
420 usb_info->cbs->ctl_complete(usb_info->cbarg, type, status);
424 * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be
425 * notified.
427 static void
428 dbus_usb_state_change(void *handle, int state)
430 usb_info_t *usb_info = (usb_info_t *) handle;
432 if (usb_info == NULL)
433 return;
435 if (usb_info->cbs && usb_info->cbs->state_change)
436 usb_info->cbs->state_change(usb_info->cbarg, state);
439 /** called by higher DBUS level (dbus.c) */
440 static int
441 dbus_usb_iovar_op(void *bus, const char *name,
442 void *params, int plen, void *arg, int len, bool set)
444 int err = DBUS_OK;
446 err = dbus_iovar_process((usb_info_t*)bus, name, params, plen, arg, len, set);
447 return err;
450 /** process iovar request from higher DBUS level */
451 static int
452 dbus_iovar_process(usb_info_t* usbinfo, const char *name,
453 void *params, int plen, void *arg, int len, bool set)
455 const bcm_iovar_t *vi = NULL;
456 int bcmerror = 0;
457 int val_size;
458 uint32 actionid;
460 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
462 ASSERT(name);
463 ASSERT(len >= 0);
465 /* Get MUST have return space */
466 ASSERT(set || (arg && len));
468 /* Set does NOT take qualifiers */
469 ASSERT(!set || (!params && !plen));
471 /* Look up var locally; if not found pass to host driver */
472 if ((vi = bcm_iovar_lookup(dhdusb_iovars, name)) == NULL) {
473 /* Not Supported */
474 bcmerror = BCME_UNSUPPORTED;
475 DBUSTRACE(("%s: IOVAR %s is not supported\n", name, __FUNCTION__));
476 goto exit;
480 DBUSTRACE(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
481 name, (set ? "set" : "get"), len, plen));
483 /* set up 'params' pointer in case this is a set command so that
484 * the convenience int and bool code can be common to set and get
486 if (params == NULL) {
487 params = arg;
488 plen = len;
491 if (vi->type == IOVT_VOID)
492 val_size = 0;
493 else if (vi->type == IOVT_BUFFER)
494 val_size = len;
495 else
496 /* all other types are integer sized */
497 val_size = sizeof(int);
499 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
500 bcmerror = dbus_usb_doiovar(usbinfo, vi, actionid,
501 name, params, plen, arg, len, val_size);
503 exit:
504 return bcmerror;
507 static int
508 dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
509 void *params, int plen, void *arg, int len, int val_size)
511 int bcmerror = 0;
512 int32 int_val = 0;
513 bool bool_val = 0;
515 DBUSTRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
516 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
518 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
519 goto exit;
521 if (plen >= (int)sizeof(int_val))
522 bcopy(params, &int_val, sizeof(int_val));
524 bool_val = (int_val != 0) ? TRUE : FALSE;
526 switch (actionid) {
528 case IOV_SVAL(IOV_MEMBYTES):
529 case IOV_GVAL(IOV_MEMBYTES):
531 uint32 address;
532 uint size, dsize;
533 uint8 *data;
535 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
537 ASSERT(plen >= 2*sizeof(int));
539 address = (uint32)int_val;
540 BCM_REFERENCE(address);
541 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
542 size = (uint)int_val;
544 /* Do some validation */
545 dsize = set ? plen - (2 * sizeof(int)) : len;
546 if (dsize < size) {
547 DBUSTRACE(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
548 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
549 bcmerror = BCME_BADARG;
550 break;
552 DBUSTRACE(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
553 (set ? "write" : "read"), size, address));
555 /* Generate the actual data pointer */
556 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
558 /* Call to do the transfer */
559 bcmerror = dbus_usb_dl_writeimage(BUS_INFO(bus, usb_info_t), data, size);
561 break;
564 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
566 if (bool_val == TRUE) {
567 bcmerror = dbus_usb_dlneeded(bus);
568 dbus_usb_rdl_dwnld_state(BUS_INFO(bus, usb_info_t));
569 } else {
570 usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
571 bcmerror = dbus_usb_dlrun(bus);
572 usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
574 break;
576 case IOV_SVAL(IOV_VARS):
577 bcmerror = dhdusb_downloadvars(BUS_INFO(bus, usb_info_t), arg, len);
578 break;
580 default:
581 bcmerror = BCME_UNSUPPORTED;
582 break;
585 exit:
586 return bcmerror;
589 /** higher DBUS level (dbus.c) wants to set NVRAM variables in dongle */
590 static int
591 dhdusb_downloadvars(usb_info_t *bus, void *arg, int len)
593 int bcmerror = 0;
594 uint32 varsize;
595 uint32 varaddr;
596 uint32 varsizew;
598 if (!len) {
599 bcmerror = BCME_BUFTOOSHORT;
600 goto err;
603 /* RAM size is not set. Set it at dbus_usb_dlneeded */
604 if (!bus->rdlram_size)
605 bcmerror = BCME_ERROR;
607 /* Even if there are no vars are to be written, we still need to set the ramsize. */
608 varsize = len ? ROUNDUP(len, 4) : 0;
609 varaddr = (bus->rdlram_size - 4) - varsize;
611 /* Write the vars list */
612 DBUSTRACE(("WriteVars: @%x varsize=%d\n", varaddr, varsize));
613 bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, (varaddr + bus->rdlram_base_addr),
614 arg, varsize);
616 /* adjust to the user specified RAM */
617 DBUSTRACE(("Usable memory size: %d\n", bus->rdlram_size));
618 DBUSTRACE(("Vars are at %d, orig varsize is %d\n", varaddr, varsize));
620 varsize = ((bus->rdlram_size - 4) - varaddr);
623 * Determine the length token:
624 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
626 if (bcmerror) {
627 varsizew = 0;
628 } else {
629 varsizew = varsize / 4;
630 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
631 varsizew = htol32(varsizew);
634 DBUSTRACE(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
636 /* Write the length token to the last word */
637 bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, ((bus->rdlram_size - 4) +
638 bus->rdlram_base_addr), (uint8*)&varsizew, 4);
639 err:
640 return bcmerror;
644 * After downloading firmware into dongle and starting it, we need to know if the firmware is
645 * indeed up and running.
647 static int
648 dbus_usb_resetcfg(usb_info_t *usbinfo)
650 void *osinfo;
651 bootrom_id_t id;
652 uint16 wait = 0, wait_time;
654 DBUSTRACE(("%s\n", __FUNCTION__));
656 if (usbinfo == NULL)
657 return DBUS_ERR;
659 osinfo = usbinfo->usbosl_info;
660 ASSERT(osinfo);
662 /* Give dongle chance to boot */
663 wait_time = USB_SFLASH_DLIMAGE_SPINWAIT;
664 while (wait < USB_SFLASH_DLIMAGE_LIMIT) {
665 dbus_usbos_wait(osinfo, wait_time);
667 wait += wait_time;
669 id.chip = 0xDEAD; /* Get the ID */
670 dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t));
671 id.chip = ltoh32(id.chip);
673 if (id.chip == POSTBOOT_ID)
674 break;
677 if (id.chip == POSTBOOT_ID) {
678 DBUSERR(("%s: download done %d ms postboot chip 0x%x/rev 0x%x\n",
679 __FUNCTION__, wait, id.chip, id.chiprev));
681 dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t));
683 dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT);
684 return DBUS_OK;
685 } else {
686 DBUSERR(("%s: Cannot talk to Dongle. Firmware is not UP, %d ms \n",
687 __FUNCTION__, wait));
688 return DBUS_ERR;
691 return DBUS_OK;
694 /** before firmware download, the dongle has to be prepared to receive the fw image */
695 static int
696 dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo)
698 void *osinfo = usbinfo->usbosl_info;
699 rdl_state_t state;
700 int err = DBUS_OK;
702 /* 1) Prepare USB boot loader for runtime image */
703 dbus_usbos_dl_cmd(osinfo, DL_START, &state, sizeof(rdl_state_t));
705 state.state = ltoh32(state.state);
706 state.bytes = ltoh32(state.bytes);
708 /* 2) Check we are in the Waiting state */
709 if (state.state != DL_WAITING) {
710 DBUSERR(("%s: Failed to DL_START\n", __FUNCTION__));
711 err = DBUS_ERR;
712 goto fail;
715 fail:
716 return err;
720 * Dongle contains bootcode in ROM but firmware is (partially) contained in dongle RAM. Therefore,
721 * firmware has to be downloaded into dongle RAM.
723 static int
724 dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen)
726 osl_t *osh = usbinfo->pub->osh;
727 void *osinfo = usbinfo->usbosl_info;
728 unsigned int sendlen, sent, dllen, pktlen;
729 char *bulkchunk = NULL, *dlpos;
730 rdl_state_t state;
731 int err = DBUS_OK;
732 bootrom_id_t id;
733 uint16 wait, wait_time;
735 bulkchunk = MALLOC(osh, RDL_CHUNK);
736 if (bulkchunk == NULL) {
737 err = DBUS_ERR;
738 goto fail;
741 sent = 0;
742 dlpos = fw;
743 dllen = fwlen;
744 pktlen = RDL_CHUNK;
746 #ifdef BCM_USB30
747 /* for SuperSpeed with non-disconnect target, need to make sure */
748 /* bulk out write times can divided by 32 to keep SeqN is 0 */
749 pktlen = (fwlen + RDL_CHUNK - 1)/RDL_CHUNK;
750 if (pktlen%32) {
751 pktlen = (pktlen/32 + 1)*32;
753 pktlen = (dllen + pktlen - 1)/pktlen;
754 #endif /* BCM_USB30 */
756 /* Get chip id and rev */
757 id.chip = usbinfo->pub->attrib.devid;
758 id.chiprev = usbinfo->pub->attrib.chiprev;
760 DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen));
762 dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t));
764 /* 3) Load the image */
765 while ((sent < dllen)) {
766 /* Wait until the usb device reports it received all the bytes we sent */
768 if (sent < dllen) {
769 if ((dllen-sent) < pktlen)
770 sendlen = dllen-sent;
771 else
772 sendlen = pktlen;
774 #ifndef BCM_USB30
775 /* simply avoid having to send a ZLP by ensuring we never have an even
776 * multiple of 64
778 if (!(sendlen % 64))
779 sendlen -= 4;
780 #endif /* BCM_USB30 */
781 /* send data */
782 memcpy(bulkchunk, dlpos, sendlen);
783 if (!dbus_usbos_dl_send_bulk(osinfo, bulkchunk, sendlen)) {
784 err = DBUS_ERR;
785 goto fail;
788 dlpos += sendlen;
789 sent += sendlen;
790 DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen));
793 wait = 0;
794 wait_time = USB_SFLASH_DLIMAGE_SPINWAIT;
795 while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state,
796 sizeof(rdl_state_t))) {
797 if ((id.chip == 43236) && (id.chiprev == 0)) {
798 DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check "
799 "completion!!!\n", __FUNCTION__));
800 dbus_usbos_wait(osinfo, wait_time);
801 wait += wait_time;
802 if (wait >= USB_SFLASH_DLIMAGE_LIMIT) {
803 DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
804 err = DBUS_ERR;
805 goto fail;
806 break;
808 } else {
809 DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
810 err = DBUS_ERR;
811 goto fail;
815 state.state = ltoh32(state.state);
816 state.bytes = ltoh32(state.bytes);
818 /* restart if an error is reported */
819 if ((state.state == DL_BAD_HDR) || (state.state == DL_BAD_CRC)) {
820 DBUSERR(("%s: Bad Hdr or Bad CRC\n", __FUNCTION__));
821 err = DBUS_ERR;
822 goto fail;
826 fail:
827 if (bulkchunk)
828 MFREE(osh, bulkchunk, RDL_CHUNK);
830 return err;
833 /** Higher level DBUS layer (dbus.c) requests this layer to download image into dongle */
834 static int
835 dbus_usb_dlstart(void *bus, uint8 *fw, int len)
837 usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
838 int err;
840 DBUSTRACE(("%s\n", __FUNCTION__));
842 if (usbinfo == NULL)
843 return DBUS_ERR;
845 if (USB_DEV_ISBAD(usbinfo))
846 return DBUS_ERR;
848 err = dbus_usb_rdl_dwnld_state(usbinfo);
850 if (DBUS_OK == err) {
851 err = dbus_usb_dl_writeimage(usbinfo, fw, len);
852 if (err == DBUS_OK)
853 usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
854 else
855 usbinfo->pub->busstate = DBUS_STATE_DL_PENDING;
856 } else
857 usbinfo->pub->busstate = DBUS_STATE_DL_PENDING;
859 return err;
861 static bool
862 dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip)
864 bool retval = TRUE;
865 /* based on the CHIP Id, store the ram size which is needed for NVRAM download. */
866 switch (chip) {
868 case 0x4319:
869 usbinfo->rdlram_size = RDL_RAM_SIZE_4319;
870 usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319;
871 break;
873 case 0x4329:
874 usbinfo->rdlram_size = RDL_RAM_SIZE_4329;
875 usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329;
876 break;
878 case 43234:
879 case 43235:
880 case 43236:
881 case 43238:
882 usbinfo->rdlram_size = RDL_RAM_SIZE_43236;
883 usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236;
884 break;
886 case 0x4328:
887 usbinfo->rdlram_size = RDL_RAM_SIZE_4328;
888 usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328;
889 break;
891 case 0x4322:
892 usbinfo->rdlram_size = RDL_RAM_SIZE_4322;
893 usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322;
894 break;
896 case 0x4360:
897 case 0xAA06:
898 usbinfo->rdlram_size = RDL_RAM_SIZE_4360;
899 usbinfo->rdlram_base_addr = RDL_RAM_BASE_4360;
900 break;
902 case 43242:
903 usbinfo->rdlram_size = RDL_RAM_SIZE_43242;
904 usbinfo->rdlram_base_addr = RDL_RAM_BASE_43242;
905 break;
907 case 43143:
908 usbinfo->rdlram_size = RDL_RAM_SIZE_43143;
909 usbinfo->rdlram_base_addr = RDL_RAM_BASE_43143;
910 break;
912 case 0x4350:
913 usbinfo->rdlram_size = RDL_RAM_SIZE_4350;
914 usbinfo->rdlram_base_addr = RDL_RAM_BASE_4350;
915 break;
917 case POSTBOOT_ID:
918 break;
920 default:
921 DBUSERR(("%s: Chip 0x%x Ram size is not known\n", __FUNCTION__, chip));
922 retval = FALSE;
923 break;
927 return retval;
930 /** higher DBUS level (dbus.c) wants to know if firmware download is required. */
931 static bool
932 dbus_usb_dlneeded(void *bus)
934 usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
935 void *osinfo;
936 bootrom_id_t id;
937 bool dl_needed = TRUE;
939 DBUSTRACE(("%s\n", __FUNCTION__));
941 if (usbinfo == NULL)
942 return FALSE;
944 osinfo = usbinfo->usbosl_info;
945 ASSERT(osinfo);
947 /* Check if firmware downloaded already by querying runtime ID */
948 id.chip = 0xDEAD;
949 dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t));
951 id.chip = ltoh32(id.chip);
952 id.chiprev = ltoh32(id.chiprev);
954 if (FALSE == dbus_usb_update_chipinfo(usbinfo, id.chip)) {
955 dl_needed = FALSE;
956 goto exit;
959 DBUSERR(("%s: chip 0x%x rev 0x%x\n", __FUNCTION__, id.chip, id.chiprev));
960 if (id.chip == POSTBOOT_ID) {
961 /* This code is needed to support two enumerations on USB1.1 scenario */
962 DBUSERR(("%s: Firmware already downloaded\n", __FUNCTION__));
964 dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t));
965 dl_needed = FALSE;
966 if (usbinfo->pub->busstate == DBUS_STATE_DL_PENDING)
967 usbinfo->pub->busstate = DBUS_STATE_DL_DONE;
968 } else {
969 usbinfo->pub->attrib.devid = id.chip;
970 usbinfo->pub->attrib.chiprev = id.chiprev;
973 exit:
974 return dl_needed;
977 /** After issuing firmware download, higher DBUS level (dbus.c) wants to start the firmware. */
978 static int
979 dbus_usb_dlrun(void *bus)
981 usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
982 void *osinfo;
983 rdl_state_t state;
984 int err = DBUS_OK;
986 DBUSTRACE(("%s\n", __FUNCTION__));
988 if (usbinfo == NULL)
989 return DBUS_ERR;
991 if (USB_DEV_ISBAD(usbinfo))
992 return DBUS_ERR;
994 osinfo = usbinfo->usbosl_info;
995 ASSERT(osinfo);
997 /* Check we are runnable */
998 dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t));
1000 state.state = ltoh32(state.state);
1001 state.bytes = ltoh32(state.bytes);
1003 /* Start the image */
1004 if (state.state == DL_RUNNABLE) {
1005 DBUSTRACE(("%s: Issue DL_GO\n", __FUNCTION__));
1006 dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t));
1008 if (usbinfo->pub->attrib.devid == TEST_CHIP)
1009 dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT);
1011 dbus_usb_resetcfg(usbinfo);
1012 /* The Donlge may go for re-enumeration. */
1013 } else {
1014 DBUSERR(("%s: Dongle not runnable\n", __FUNCTION__));
1015 err = DBUS_ERR;
1018 return err;
1022 * As preparation for firmware download, higher DBUS level (dbus.c) requests the firmware image
1023 * to be used for the type of dongle detected. Directly called by dbus.c (so not via a callback
1024 * construction)
1026 void
1027 dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp)
1029 usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
1030 unsigned int devid;
1031 unsigned int crev;
1033 devid = usbinfo->pub->attrib.devid;
1034 crev = usbinfo->pub->attrib.chiprev;
1036 *fw = NULL;
1037 *fwlen = 0;
1039 switch (devid) {
1040 case BCM43236_CHIP_ID:
1041 case BCM43235_CHIP_ID:
1042 case BCM43234_CHIP_ID:
1043 case BCM43238_CHIP_ID: {
1044 if (crev == 3 || crev == 2 || crev == 1) {
1045 #ifdef EMBED_IMAGE_43236b
1046 *fw = (uint8 *)dlarray_43236b;
1047 *fwlen = sizeof(dlarray_43236b);
1048 #endif
1049 #ifdef EMBED_IMAGE_43238b
1050 *fw = (uint8 *)dlarray_43238b;
1051 *fwlen = sizeof(dlarray_43238b);
1052 #endif
1055 } break;
1056 case BCM4360_CHIP_ID:
1057 #ifdef EMBED_IMAGE_4360b
1058 if (crev > 2) {
1059 *fw = (uint8 *)dlarray_4360b;
1060 *fwlen = sizeof(dlarray_4360b);
1062 #endif
1063 break;
1064 case BCM4352_CHIP_ID:
1065 case BCM43526_CHIP_ID:
1066 #ifdef EMBED_IMAGE_43526a
1067 if (crev <= 2) {
1068 *fw = (uint8 *)dlarray_43526a;
1069 *fwlen = sizeof(dlarray_43526a);
1071 #endif
1072 #ifdef EMBED_IMAGE_43526b
1073 if (crev > 2) {
1074 *fw = (uint8 *)dlarray_43526b;
1075 *fwlen = sizeof(dlarray_43526b);
1077 #endif
1078 break;
1080 case BCM43242_CHIP_ID:
1081 #ifdef EMBED_IMAGE_43242a0
1082 *fw = (uint8 *)dlarray_43242a0;
1083 *fwlen = sizeof(dlarray_43242a0);
1084 #elif defined(EMBED_IMAGE_43242a1)
1085 *fw = (uint8 *)dlarray_43242a1;
1086 *fwlen = sizeof(dlarray_43242a1);
1087 #endif
1088 break;
1090 case BCM43143_CHIP_ID:
1091 #ifdef EMBED_IMAGE_43143a0
1092 *fw = (uint8 *)dlarray_43143a0;
1093 *fwlen = sizeof(dlarray_43143a0);
1094 #elif defined(EMBED_IMAGE_43143b0)
1095 *fw = (uint8 *)dlarray_43143b0;
1096 *fwlen = sizeof(dlarray_43143b0);
1097 #endif
1098 break;
1100 case BCM4350_CHIP_ID:
1101 #ifdef EMBED_IMAGE_4350a0
1102 if (crev == 0) {
1103 *fw = (uint8 *)dlarray_4350a0;
1104 *fwlen = sizeof(dlarray_4350a0);
1106 #endif
1107 #ifdef EMBED_IMAGE_4350b0
1108 if (crev == 1) {
1109 *fw = (uint8 *)dlarray_4350b0;
1110 *fwlen = sizeof(dlarray_4350b0);
1112 #endif
1113 #ifdef EMBED_IMAGE_4350b1
1114 if (crev == 2) {
1115 *fw = (uint8 *)dlarray_4350b1;
1116 *fwlen = sizeof(dlarray_4350b1);
1118 #endif
1119 break;
1121 default:
1122 #ifdef EMBED_IMAGE_GENERIC
1123 *fw = (uint8 *)dlarray;
1124 *fwlen = sizeof(dlarray);
1125 #endif
1126 break;
1130 #ifdef BCM_DNGL_EMBEDIMAGE
1131 static bool
1132 dbus_usb_device_exists(void *bus)
1134 usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
1135 void *osinfo;
1136 bootrom_id_t id;
1138 DBUSTRACE(("%s\n", __FUNCTION__));
1140 if (usbinfo == NULL)
1141 return FALSE;
1143 osinfo = usbinfo->usbosl_info;
1144 ASSERT(osinfo);
1146 id.chip = 0xDEAD;
1147 /* Query device to see if we get a response */
1148 dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t));
1150 usbinfo->pub->attrib.devid = id.chip;
1151 if (id.chip == 0xDEAD)
1152 return FALSE;
1153 else
1154 return TRUE;
1156 #endif /* BCM_DNGL_EMBEDIMAGE */