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