• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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