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