1 /*
2 * Common code for DHD command-line utility
3 *
4 * Copyright (C) 1999-2013, Broadcom Corporation
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: dhdu.c 385965 2013-02-19 04:33:34Z $
19 */
20
21 /* For backwards compatibility, the absence of the define 'BWL_NO_FILESYSTEM_SUPPORT'
22 * implies that a filesystem is supported.
23 */
24 #if !defined(BWL_NO_FILESYSTEM_SUPPORT)
25 #define BWL_FILESYSTEM_SUPPORT
26 #endif
27
28 #ifndef PROP_TXSTATUS
29 #define PROP_TXSTATUS
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <assert.h>
37
38 #include <typedefs.h>
39 #include <epivers.h>
40 #include <proto/ethernet.h>
41 #include <dhdioctl.h>
42 #include <sdiovar.h>
43 #include <bcmutils.h>
44 #include <bcmendian.h>
45 #include "dhdu.h"
46 #include "miniopt.h"
47 #include <proto/bcmip.h>
48 #include <hndrte_debug.h>
49 #include <hndrte_armtrap.h>
50 #include <hndrte_cons.h>
51 #define IPV4_ADDR_LEN 4
52
53 #include <errno.h>
54
55 #include <trxhdr.h>
56 #include "ucode_download.h"
57
58 #define stricmp strcasecmp
59 #define strnicmp strncasecmp
60
61
62 static cmd_func_t dhd_var_void;
63 static cmd_func_t dhd_varint, dhd_varstr;
64 static cmd_func_t dhd_var_getandprintstr, dhd_var_getint, dhd_var_get;
65 static cmd_func_t dhd_var_setint;
66
67 static cmd_func_t dhd_version, dhd_list, dhd_msglevel;
68
69 #ifdef SDTEST
70 static cmd_func_t dhd_pktgen;
71 #endif
72 static cmd_func_t dhd_sprom;
73 static cmd_func_t dhd_sdreg;
74 static cmd_func_t dhd_sd_msglevel, dhd_sd_blocksize, dhd_sd_mode, dhd_sd_reg;
75 static cmd_func_t dhd_dma_mode;
76 static cmd_func_t dhd_membytes, dhd_download, dhd_dldn,
77 dhd_upload, dhd_coredump, dhd_consoledump, dhd_vars, dhd_idleclock, dhd_idletime;
78 static cmd_func_t dhd_logstamp;
79
80 static cmd_func_t dhd_hostreorder_flows;
81
82 #ifdef PROP_TXSTATUS
83 static cmd_func_t dhd_proptxstatusenable;
84 static cmd_func_t dhd_proptxstatusmode;
85 static cmd_func_t dhd_proptxopt;
86 #endif
87 static int dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr);
88 static int dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len);
89
90 static uint dhd_iovar_mkbuf(char *name, char *data, uint datalen,
91 char *buf, uint buflen, int *perr);
92 static int dhd_iovar_getint(void *dhd, char *name, int *var);
93 static int dhd_iovar_setint(void *dhd, char *name, int var);
94
95 #if defined(BWL_FILESYSTEM_SUPPORT)
96 static int file_size(char *fname);
97 static int read_vars(char *fname, char *buf, int buf_maxlen);
98 #endif
99
100
101 /* dword align allocation */
102 static union {
103 char bufdata[DHD_IOCTL_MAXLEN];
104 uint32 alignme;
105 } bufstruct_dhd;
106 static char *buf = (char*) &bufstruct_dhd.bufdata;
107
108 /* integer output format, default to signed integer */
109 static uint8 int_fmt;
110
111 #define DEBUG_INFO_PTRS_END 0xffffffff
112 const uint32 debug_info_ptrs[] = {0xf8, 0x878, DEBUG_INFO_PTRS_END};
113
114 typedef struct {
115 uint value;
116 char *string;
117 } dbg_msg_t;
118
119 static int dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg);
120
121 /* Actual command table */
122 cmd_t dhd_cmds[] = {
123 { "cmds", dhd_list, -1, -1,
124 "generate a short list of available commands"},
125 { "version", dhd_version, DHD_GET_VAR, -1,
126 "get version information" },
127 { "msglevel", dhd_msglevel, DHD_GET_VAR, DHD_SET_VAR,
128 "get/set message bits" },
129 { "bcmerrorstr", dhd_var_getandprintstr, DHD_GET_VAR, -1,
130 "errorstring"},
131 { "wdtick", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
132 "watchdog tick time (ms units)"},
133 { "intr", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
134 "use interrupts on the bus"},
135 { "pollrate", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
136 "number of ticks between bus polls (0 means no polling)"},
137 { "idletime", dhd_idletime, DHD_GET_VAR, DHD_SET_VAR,
138 "number of ticks for activity timeout (-1: immediate, 0: never)"},
139 { "idleclock", dhd_idleclock, DHD_GET_VAR, DHD_SET_VAR,
140 "idleclock active | stopped | <N>\n"
141 "\tactive (0) - do not request any change to the SD clock\n"
142 "\tstopped (-1) - request SD clock be stopped on activity timeout\n"
143 "\t<N> (other) - an sd_divisor value to request on activity timeout\n"},
144 { "sd1idle", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
145 "change mode to SD1 when turning off clock at idle"},
146 { "forceeven", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
147 "force SD tx/rx buffers to be even"},
148 { "readahead", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
149 "enable readahead feature (look for next frame len in headers)"},
150 { "sdrxchain", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
151 "enable packet chains to SDIO stack for glom receive"},
152 { "alignctl", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
153 "align control frames"},
154 { "sdalign", dhd_varint, DHD_GET_VAR, -1,
155 "display the (compiled in) alignment target for sd requests"},
156 { "txbound", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
157 "get/set maximum number of tx frames per scheduling"},
158 { "rxbound", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
159 "get/set maximum number of rx frames per scheduling"},
160 { "txminmax", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
161 "get/set maximum number of tx frames per scheduling while rx frames outstanding"},
162 { "dconpoll", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
163 "g/set dongle console polling interval (ms)"},
164 { "dump", dhd_varstr, DHD_GET_VAR, -1,
165 "dump information"},
166 { "cons", dhd_varstr, -1, DHD_SET_VAR,
167 "send string to device console (sd only)"},
168 { "clearcounts", dhd_var_void, -1, DHD_SET_VAR,
169 "reset the bus stats shown in the dhd dump"},
170 { "logdump", dhd_varstr, DHD_GET_VAR, -1,
171 "dump the timestamp logging buffer"},
172 { "logcal", dhd_varint, -1, DHD_SET_VAR,
173 "logcal <n> -- log around an osl_delay of <n> usecs"},
174 { "logstamp", dhd_logstamp, -1, DHD_SET_VAR,
175 "logstamp [<n1>] [<n2>] -- add a message to the log"},
176 { "ramstart", dhd_varint, DHD_GET_VAR, -1,
177 "display start address of onchip SOCRAM"},
178 { "ramsize", dhd_varint, DHD_GET_VAR, -1,
179 "display size of onchip SOCRAM"},
180 { "membytes", dhd_membytes, DHD_GET_VAR, DHD_SET_VAR,
181 "membytes [-h | -r | -i] <address> <length> [<data>]\n"
182 "\tread or write data in the dongle ram\n"
183 "\t-h <data> is a sequence of hex digits rather than a char string\n"
184 "\t-r output binary to stdout rather hex\n"},
185 { "download", dhd_download, -1, DHD_SET_VAR,
186 "download [-a <address>] [--noreset] [--norun] [--verify] <binfile> [<varsfile>]\n"
187 "\tdownload file to specified dongle ram address and start CPU\n"
188 "\toptional vars file will replace vars parsed from the CIS\n"
189 "\t--noreset do not reset SOCRAM core before download\n"
190 "\t--norun do not start dongle CPU after download\n"
191 "\t--verify do readback verify \n"
192 "\tdefault <address> is 0\n"},
193 { "dldn", dhd_dldn, -1, DHD_SET_VAR,
194 "download <binfile>\n"
195 "\tdownload file to specified dongle ram address 0\n"},
196 { "vars", dhd_vars, DHD_GET_VAR, DHD_SET_VAR,
197 "vars [<file>]\n"
198 "\toverride SPROM vars with <file> (before download)\n"},
199 { "coredump", dhd_coredump, -1, -1,
200 "coredump <file>\n"
201 "\tdump dongle RAM content into a file in dumpfile format\n"
202 "\tfor use with ELF core generator"},
203 { "consoledump", dhd_consoledump, -1, -1,
204 "consoledump\n"
205 "\tdump dongle debug console buffer"},
206 { "upload", dhd_upload, -1, -1,
207 "upload [-a <address> ] <file> [<size>]\n"
208 "\tupload dongle RAM content into a file\n"
209 "\tdefault <address> is 0, default <size> is RAM size"},
210 { "srdump", dhd_sprom, DHD_GET_VAR, -1,
211 "display SPROM content" },
212 { "srwrite", dhd_sprom, -1, DHD_SET_VAR,
213 "write data or file content to SPROM\n"
214 "\tsrwrite <word-offset> <word-value> ...\n"
215 "\tsrwrite [-c] <srom-file-path>\n"
216 "\t -c means write regardless of crc"},
217 { "sleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
218 "enter/exit simulated host sleep (bus powerdown w/OOB wakeup)"},
219 { "kso", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
220 "keep sdio on"},
221 { "devcap", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
222 "brcm device capabilities"},
223 { "devsleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
224 "Sleep CMD14"},
225 #ifdef SDTEST
226 { "extloop", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
227 "external loopback: convert all tx data to echo test frames"},
228 { "pktgen", dhd_pktgen, DHD_GET_VAR, DHD_SET_VAR,
229 "configure/report pktgen status (SDIO)\n"
230 "\t-f N frequency: send/recv a burst every N ticks\n"
231 "\t-c N count: send/recv N packets each burst\n"
232 "\t-t N total: stop after a total of N packets\n"
233 "\t-p N print: display counts on console every N bursts\n"
234 "\t-m N min: set minimum length of packet data\n"
235 "\t-M N Max: set maximum length of packet data\n"
236 "\t-l N len: set fixed length of packet data\n"
237 "\t-s N stop after N tx failures\n"
238 "\t-d dir test direction/type:\n"
239 "\t send -- send packets discarded by dongle\n"
240 "\t echo -- send packets to be echoed by dongle\n"
241 "\t burst -- request bursts (of size <-c>) from dongle\n"
242 "\t one every <-f> ticks, until <-t> total requests\n"
243 "\t recv -- request dongle enter continuous send mode,\n"
244 "\t read up to <-c> pkts every <-f> ticks until <-t>\n"
245 "\t total reads\n"},
246 #endif /* SDTEST */
247 { "dngl_isolation", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
248 "g/set dongle isolation, so the dev could be disabled with out effecting the dongle state"},
249 { "sdreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR,
250 "g/set sdpcmdev core register (f1) across SDIO (CMD53)"},
251 { "sbreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR,
252 "g/set any backplane core register (f1) across SDIO (CMD53)"},
253 { "sd_cis", dhd_var_getandprintstr, DHD_GET_VAR, -1,
254 "dump sdio CIS"},
255 { "sd_devreg", dhd_sd_reg, DHD_GET_VAR, DHD_SET_VAR,
256 "g/set device register across SDIO bus (CMD52)"},
257 { "sd_hostreg", dhd_sd_reg, DHD_GET_VAR, DHD_SET_VAR,
258 "g/set local controller register"},
259 { "sd_blocksize", dhd_sd_blocksize, DHD_GET_VAR, DHD_SET_VAR,
260 "g/set block size for a function"},
261 { "sd_blockmode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
262 "g/set blockmode"},
263 { "sd_ints", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
264 "g/set client ints"},
265 { "sd_dma", dhd_dma_mode, DHD_GET_VAR, DHD_SET_VAR,
266 "g/set dma usage: [PIO | SDMA | ADMA1 | ADMA2]"},
267 { "sd_yieldcpu", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
268 "allow blocking (yield of CPU) on data xfer"},
269 { "sd_minyield", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
270 "minimum xfer size to allow CPU yield"},
271 { "sd_forcerb", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
272 "force readback when changing local interrupt settings"},
273 { "sd_numints", dhd_varint, DHD_GET_VAR, -1,
274 "number of device interrupts"},
275 { "sd_numlocalints", dhd_varint, DHD_GET_VAR, -1,
276 "number of non-device interrupts"},
277 { "sd_divisor", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
278 "set the divisor for SDIO clock generation"},
279 { "sd_power", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
280 "set the SD Card slot power"},
281 { "sd_power_save", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
282 "set the SDIO3.0 power save value"},
283 { "sd_clock", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
284 "turn on/off the SD Clock"},
285 { "sd_crc", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
286 "turn on/off CRC checking in SPI mode"},
287 { "sd_mode", dhd_sd_mode, DHD_GET_VAR, DHD_SET_VAR,
288 "g/set SDIO bus mode (spi, sd1, sd4)"},
289 { "sd_highspeed", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
290 "set the high-speed clocking mode"},
291 { "sd_msglevel", dhd_sd_msglevel, DHD_GET_VAR, DHD_SET_VAR,
292 "g/set debug message level"},
293 { "sd_hciregs", dhd_varstr, DHD_GET_VAR, -1,
294 "display host-controller interrupt registers"},
295 { "sdiod_drive", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
296 "SDIO Device drive strength in milliamps. (0=tri-state, 1-12mA)"},
297 { "devreset", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
298 "Move device into or out of reset state (1/reset, or 0/operational)"},
299 { "ioctl_timeout", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
300 "IOCTL response timeout (milliseconds)."},
301 #ifdef PROP_TXSTATUS
302 { "proptx", dhd_proptxstatusenable, DHD_GET_VAR, DHD_SET_VAR,
303 "enable/disable the proptxtstatus feature\n"
304 "0 - disabled\n"
305 "1 - enabled\n"},
306 { "ptxmode", dhd_proptxstatusmode, DHD_GET_VAR, DHD_SET_VAR,
307 "set the proptxtstatus operation mode:\n"
308 "0 - Unsupported\n"
309 "1 - Use implied credit from a packet status\n"
310 "2 - Use explicit credit\n" },
311 { "proptx_opt", dhd_proptxopt, DHD_GET_VAR, DHD_SET_VAR,
312 "enable/disable proptxtstatus optimizations to increase throughput:\n"
313 "0 - Unsupported\n"
314 "1 - Enable proptxstatus optimizations to increase throughput\n" },
315 #endif
316 { "sd_uhsimode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
317 "g/set UHSI Mode"},
318 { "host_reorder_flows", dhd_hostreorder_flows, DHD_GET_VAR, -1,
319 "get host reorder flows "},
320 { "txglomsize", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
321 "max glom size for sdio tx\n"},
322 { "txglommode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
323 "glom mode for sdio tx 0- copy, 1- multidescriptor\n"},
324 { "fw_hang_report", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
325 "enable/disable report firmware hangs for firmware reload\n"
326 "0 - disabled (for testing)\n"
327 "1 - enabled (default)\n"},
328 { NULL, NULL, 0, 0, NULL }
329 };
330
331 cmd_t dhd_varcmd = {"var", dhd_varint, -1, -1, "unrecognized name, type -h for help"};
332 char *dhdu_av0;
333
334 #if defined(BWL_FILESYSTEM_SUPPORT)
335 static int
file_size(char * fname)336 file_size(char *fname)
337 {
338 FILE *fp;
339 long size = -1;
340
341 /* Can't use stat() because of Win CE */
342
343 if ((fp = fopen(fname, "rb")) == NULL ||
344 fseek(fp, 0, SEEK_END) < 0 ||
345 (size = ftell(fp)) < 0)
346 fprintf(stderr, "Could not determine size of %s: %s\n",
347 fname, strerror(errno));
348
349 if (fp != NULL)
350 fclose(fp);
351
352 return (int)size;
353 }
354 #endif /* BWL_FILESYSTEM_SUPPORT */
355
356
357 /* parse/validate the command line arguments */
358 /*
359 * pargv is updated upon return if the first argument is an option.
360 * It remains intact otherwise.
361 */
362 int
dhd_option(char *** pargv,char ** pifname,int * phelp)363 dhd_option(char ***pargv, char **pifname, int *phelp)
364 {
365 char *ifname = NULL;
366 int help = FALSE;
367 int status = CMD_OPT;
368 char **argv = *pargv;
369
370 int_fmt = INT_FMT_DEC;
371
372 while (*argv) {
373 /* select different adapter */
374 if (!strcmp(*argv, "-a") || !strcmp(*argv, "-i")) {
375 char *opt = *argv++;
376 ifname = *argv;
377 if (!ifname) {
378 fprintf(stderr,
379 "error: expected interface name after option %s\n", opt);
380 status = CMD_ERR;
381 break;
382 }
383 }
384
385 /* integer output format */
386 else if (!strcmp(*argv, "-d"))
387 int_fmt = INT_FMT_DEC;
388 else if (!strcmp(*argv, "-u"))
389 int_fmt = INT_FMT_UINT;
390 else if (!strcmp(*argv, "-x"))
391 int_fmt = INT_FMT_HEX;
392
393 /* command usage */
394 else if (!strcmp(*argv, "-h"))
395 help = TRUE;
396
397 /* done with generic options */
398 else {
399 status = CMD_DHD;
400 break;
401 }
402
403 /* consume the argument */
404 argv ++;
405 break;
406 }
407
408 *phelp = help;
409 *pifname = ifname;
410 *pargv = argv;
411
412 return status;
413 }
414
415 void
dhd_cmd_usage(cmd_t * cmd)416 dhd_cmd_usage(cmd_t *cmd)
417 {
418 if (strlen(cmd->name) >= 8)
419 fprintf(stderr, "%s\n\t%s\n\n", cmd->name, cmd->help);
420 else
421 fprintf(stderr, "%s\t%s\n\n", cmd->name, cmd->help);
422 }
423
424 /* Dump out short list of commands */
425 static int
dhd_list(void * dhd,cmd_t * garb,char ** argv)426 dhd_list(void *dhd, cmd_t *garb, char **argv)
427 {
428 cmd_t *cmd;
429 int nrows, i, len;
430 char *buf;
431 int letter, col, row, pad;
432
433 UNUSED_PARAMETER(dhd);
434 UNUSED_PARAMETER(garb);
435 UNUSED_PARAMETER(argv);
436
437 for (cmd = dhd_cmds, nrows = 0; cmd->name; cmd++)
438 nrows++;
439
440 nrows /= 4;
441 nrows++;
442
443 len = nrows * 80 + 2;
444 buf = malloc(len);
445 if (buf == NULL) {
446 fprintf(stderr, "Failed to allocate buffer of %d bytes\n", len);
447 return BCME_NOMEM;
448 }
449 for (i = 0; i < len; i++)
450 *(buf+i) = 0;
451
452 row = col = 0;
453 for (letter = 'a'; letter < 'z'; letter++) {
454 for (cmd = dhd_cmds; cmd->name; cmd++) {
455 if (cmd->name[0] == letter || cmd->name[0] == letter - 0x20) {
456 strcat(buf+row*80, cmd->name);
457 pad = 18 * (col + 1) - strlen(buf+row*80);
458 if (pad < 1)
459 pad = 1;
460 for (; pad; pad--)
461 strcat(buf+row*80, " ");
462 row++;
463 if (row == nrows) {
464 col++; row = 0;
465 }
466 }
467 }
468 }
469 for (row = 0; row < nrows; row++)
470 printf("%s\n", buf+row*80);
471
472 printf("\n");
473 free(buf);
474 return (0);
475 }
476
477 void
dhd_cmds_usage(cmd_t * port_cmds)478 dhd_cmds_usage(cmd_t *port_cmds)
479 {
480 cmd_t *port_cmd;
481 cmd_t *cmd;
482
483 /* print usage of port commands */
484 for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)
485 /* Check for wc_cmd */
486 dhd_cmd_usage(port_cmd);
487
488 /* print usage of common commands without port counterparts */
489 for (cmd = dhd_cmds; cmd->name; cmd++) {
490 /* search if port counterpart exists */
491 for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)
492 if (!strcmp(port_cmd->name, cmd->name))
493 break;
494 if (!port_cmd || !port_cmd->name)
495 dhd_cmd_usage(cmd);
496 }
497 }
498
499 void
dhd_usage(cmd_t * port_cmds)500 dhd_usage(cmd_t *port_cmds)
501 {
502 fprintf(stderr,
503 "Usage: %s [-a|i <adapter>] [-h] [-d|u|x] <command> [arguments]\n",
504 dhdu_av0);
505
506 fprintf(stderr, "\n");
507 fprintf(stderr, " -h this message\n");
508 fprintf(stderr, " -a, -i adapter name or number\n");
509 fprintf(stderr, " -d display values as signed integer\n");
510 fprintf(stderr, " -u display values as unsigned integer\n");
511 fprintf(stderr, " -x display values as hexdecimal\n");
512 fprintf(stderr, "\n");
513
514 dhd_cmds_usage(port_cmds);
515 }
516
517 int
dhd_check(void * dhd)518 dhd_check(void *dhd)
519 {
520 int ret;
521 int val;
522
523 if ((ret = dhd_get(dhd, DHD_GET_MAGIC, &val, sizeof(int))) < 0)
524 return ret;
525 if (val != DHD_IOCTL_MAGIC)
526 return -1;
527 if ((ret = dhd_get(dhd, DHD_GET_VERSION, &val, sizeof(int))) < 0)
528 return ret;
529 if (val > DHD_IOCTL_VERSION) {
530 fprintf(stderr, "Version mismatch, please upgrade\n");
531 return -1;
532 }
533 return 0;
534 }
535
536 void
dhd_printint(int val)537 dhd_printint(int val)
538 {
539 switch (int_fmt) {
540 case INT_FMT_UINT:
541 printf("%u\n", val);
542 break;
543 case INT_FMT_HEX:
544 printf("0x%x\n", val);
545 break;
546 case INT_FMT_DEC:
547 default:
548 printf("%d\n", val);
549 break;
550 }
551 }
552
553 /* pretty hex print a contiguous buffer (tweaked from wlu) */
554 void
dhd_hexdump(uchar * buf,uint nbytes,uint saddr)555 dhd_hexdump(uchar *buf, uint nbytes, uint saddr)
556 {
557 char line[256];
558 char* p;
559 uint i;
560
561 if (nbytes == 0) {
562 printf("\n");
563 return;
564 }
565
566 p = line;
567 for (i = 0; i < nbytes; i++) {
568 if (i % 16 == 0) {
569 p += sprintf(p, "%08x: ", saddr + i); /* line prefix */
570 }
571 p += sprintf(p, "%02x ", buf[i]);
572 if (i % 16 == 15) {
573 uint j;
574 p += sprintf(p, " ");
575 for (j = i-15; j <= i; j++)
576 p += sprintf(p, "%c",
577 ((buf[j] >= 0x20 && buf[j] <= 0x7f) ? buf[j] : '.'));
578 printf("%s\n", line); /* flush line */
579 p = line;
580 }
581 }
582
583 /* flush last partial line */
584 if (p != line)
585 printf("%s\n", line);
586 }
587
588
589 #ifdef SDTEST
590 static int
dhd_pktgen(void * dhd,cmd_t * cmd,char ** argv)591 dhd_pktgen(void *dhd, cmd_t *cmd, char **argv)
592 {
593 int ret = 0;
594 void *ptr = NULL;
595 dhd_pktgen_t pktgen;
596 char *str;
597
598 UNUSED_PARAMETER(dhd);
599 UNUSED_PARAMETER(cmd);
600
601 /* Get current settings */
602 if ((ret = dhd_var_getbuf(dhd, "pktgen", NULL, 0, &ptr)) != 0)
603 return ret;
604 memcpy(&pktgen, ptr, sizeof(pktgen));
605
606 if (pktgen.version != DHD_PKTGEN_VERSION) {
607 fprintf(stderr, "pktgen version mismatch (module %d app %d)\n",
608 pktgen.version, DHD_PKTGEN_VERSION);
609 return BCME_ERROR;
610 }
611
612 /* Presence of args implies a set, else a get */
613 if (*++argv) {
614 miniopt_t opts;
615 int opt_err;
616
617 /* Initialize option parser */
618 miniopt_init(&opts, "pktgen", "", FALSE);
619
620 while ((opt_err = miniopt(&opts, argv)) != -1) {
621 if (opt_err == 1) {
622 fprintf(stderr, "pktgen options error\n");
623 ret = -1;
624 goto exit;
625 }
626 argv += opts.consumed;
627
628 if (!opts.good_int && opts.opt != 'd') {
629 fprintf(stderr, "invalid integer %s\n", opts.valstr);
630 ret = -1;
631 goto exit;
632 }
633
634 switch (opts.opt) {
635 case 'f':
636 pktgen.freq = opts.uval;
637 break;
638 case 'c':
639 pktgen.count = opts.uval;
640 break;
641 case 'p':
642 pktgen.print = opts.uval;
643 break;
644 case 't':
645 pktgen.total = opts.uval;
646 break;
647 case 's':
648 pktgen.stop = opts.uval;
649 break;
650 case 'm':
651 pktgen.minlen = opts.uval;
652 break;
653 case 'M':
654 pktgen.maxlen = opts.uval;
655 break;
656 case 'l': case 'L':
657 pktgen.minlen = pktgen.maxlen = opts.uval;
658 break;
659 case 'd':
660 if (!strcmp(opts.valstr, "send"))
661 pktgen.mode = DHD_PKTGEN_SEND;
662 else if (!strcmp(opts.valstr, "echo"))
663 pktgen.mode = DHD_PKTGEN_ECHO;
664 else if (!strcmp(opts.valstr, "burst"))
665 pktgen.mode = DHD_PKTGEN_RXBURST;
666 else if (!strcmp(opts.valstr, "recv"))
667 pktgen.mode = DHD_PKTGEN_RECV;
668 else {
669 fprintf(stderr, "unrecognized dir mode %s\n",
670 opts.valstr);
671 return BCME_USAGE_ERROR;
672 }
673 break;
674
675 default:
676 fprintf(stderr, "option parsing error (key %s valstr %s)\n",
677 opts.key, opts.valstr);
678 ret = BCME_USAGE_ERROR;
679 goto exit;
680 }
681 }
682
683 if (pktgen.maxlen < pktgen.minlen) {
684 fprintf(stderr, "min/max error (%d/%d)\n", pktgen.minlen, pktgen.maxlen);
685 ret = -1;
686 goto exit;
687 }
688
689 /* Set the new values */
690 ret = dhd_var_setbuf(dhd, "pktgen", &pktgen, sizeof(pktgen));
691 } else {
692 printf("Counts: %d send attempts, %d received, %d tx failures\n",
693 pktgen.numsent, pktgen.numrcvd, pktgen.numfail);
694 }
695
696 /* Show configuration in either case */
697 switch (pktgen.mode) {
698 case DHD_PKTGEN_ECHO: str = "echo"; break;
699 case DHD_PKTGEN_SEND: str = "send"; break;
700 case DHD_PKTGEN_RECV: str = "recv"; break;
701 case DHD_PKTGEN_RXBURST: str = "burst"; break;
702 default: str = "UNKNOWN"; break;
703 }
704
705 printf("Config: mode %s %d pkts (len %d-%d) each %d ticks\n",
706 str, pktgen.count, pktgen.minlen, pktgen.maxlen, pktgen.freq);
707
708 /* Second config line for optional items */
709 str = " ";
710 if (pktgen.total) {
711 printf("%slimit %d", str, pktgen.total);
712 str = ", ";
713 }
714 if (pktgen.print) {
715 printf("%sprint every %d ticks", str, (pktgen.freq * pktgen.print));
716 str = ", ";
717 }
718 if (pktgen.stop) {
719 printf("%sstop after %d tx failures", str, pktgen.stop);
720 str = ", ";
721 }
722 if (str[0] == ',')
723 printf("\n");
724
725 exit:
726 return ret;
727 }
728 #endif /* SDTEST */
729
730 static dbg_msg_t dhd_sd_msgs[] = {
731 {SDH_ERROR_VAL, "error"},
732 {SDH_TRACE_VAL, "trace"},
733 {SDH_INFO_VAL, "info"},
734 {SDH_DATA_VAL, "data"},
735 {SDH_CTRL_VAL, "control"},
736 {SDH_LOG_VAL, "log"},
737 {SDH_DMA_VAL, "dma"},
738 {0, NULL}
739 };
740
741 static int
dhd_sd_msglevel(void * dhd,cmd_t * cmd,char ** argv)742 dhd_sd_msglevel(void *dhd, cmd_t *cmd, char **argv)
743 {
744 return dhd_do_msglevel(dhd, cmd, argv, dhd_sd_msgs);
745 }
746
747 static int
dhd_sd_blocksize(void * dhd,cmd_t * cmd,char ** argv)748 dhd_sd_blocksize(void *dhd, cmd_t *cmd, char **argv)
749 {
750 int ret;
751 int argc;
752 char *endptr = NULL;
753 void *ptr = NULL;
754 int func, size;
755
756 /* arg count */
757 for (argc = 0; argv[argc]; argc++);
758 argc--;
759
760 if (argc < 1 || argc > 2) {
761 printf("required args: function [size] (size 0 means max)\n");
762 return BCME_USAGE_ERROR;
763 }
764
765 func = strtol(argv[1], &endptr, 0);
766 if (*endptr != '\0') {
767 printf("Invalid function: %s\n", argv[1]);
768 return BCME_USAGE_ERROR;
769 }
770
771 if (argc > 1) {
772 size = strtol(argv[2], &endptr, 0);
773 if (*endptr != '\0') {
774 printf("Invalid size: %s\n", argv[1]);
775 return BCME_USAGE_ERROR;
776 }
777 }
778
779 if (argc == 1) {
780 if ((ret = dhd_var_getbuf(dhd, cmd->name, &func, sizeof(func), &ptr)) >= 0)
781 printf("Function %d block size: %d\n", func, *(int*)ptr);
782 } else {
783 printf("Setting function %d block size to %d\n", func, size);
784 size &= 0x0000ffff; size |= (func << 16);
785 ret = dhd_var_setbuf(dhd, cmd->name, &size, sizeof(size));
786 }
787
788 return (ret);
789 }
790
791 static int
dhd_sd_mode(void * wl,cmd_t * cmd,char ** argv)792 dhd_sd_mode(void *wl, cmd_t *cmd, char **argv)
793 {
794 int ret;
795 int argc;
796 int sdmode;
797
798 /* arg count */
799 for (argc = 0; argv[argc]; argc++);
800 argc--;
801
802 if (argv[1]) {
803 if (!strcmp(argv[1], "spi")) {
804 strcpy(argv[1], "0");
805 } else if (!strcmp(argv[1], "sd1")) {
806 strcpy(argv[1], "1");
807 } else if (!strcmp(argv[1], "sd4")) {
808 strcpy(argv[1], "2");
809 } else {
810 return BCME_USAGE_ERROR;
811 }
812
813 ret = dhd_var_setint(wl, cmd, argv);
814
815 } else {
816 if ((ret = dhd_var_get(wl, cmd, argv))) {
817 return (ret);
818 } else {
819 sdmode = *(int32*)buf;
820
821 printf("SD Mode is: %s\n",
822 sdmode == 0 ? "SPI"
823 : sdmode == 1 ? "SD1"
824 : sdmode == 2 ? "SD4" : "Unknown");
825 }
826 }
827
828 return (ret);
829 }
830
831 static int
dhd_dma_mode(void * wl,cmd_t * cmd,char ** argv)832 dhd_dma_mode(void *wl, cmd_t *cmd, char **argv)
833 {
834 int ret;
835 int argc;
836 int dmamode;
837
838 /* arg count */
839 for (argc = 0; argv[argc]; argc++);
840 argc--;
841
842 if (argv[1]) {
843 if (!stricmp(argv[1], "pio")) {
844 strcpy(argv[1], "0");
845 } else if (!strcmp(argv[1], "0")) {
846 } else if (!stricmp(argv[1], "dma")) {
847 strcpy(argv[1], "1");
848 } else if (!stricmp(argv[1], "sdma")) {
849 strcpy(argv[1], "1");
850 } else if (!strcmp(argv[1], "1")) {
851 } else if (!stricmp(argv[1], "adma1")) {
852 strcpy(argv[1], "2");
853 } else if (!stricmp(argv[1], "adma")) {
854 strcpy(argv[1], "3");
855 } else if (!stricmp(argv[1], "adma2")) {
856 strcpy(argv[1], "3");
857 } else {
858 return BCME_USAGE_ERROR;
859 }
860
861 ret = dhd_var_setint(wl, cmd, argv);
862
863 } else {
864 if ((ret = dhd_var_get(wl, cmd, argv))) {
865 return (ret);
866 } else {
867 dmamode = *(int32*)buf;
868
869 printf("DMA Mode is: %s\n",
870 dmamode == 0 ? "PIO"
871 : dmamode == 1 ? "SDMA"
872 : dmamode == 2 ? "ADMA1"
873 : dmamode == 3 ? "ADMA2"
874 : "Unknown");
875 }
876 }
877
878 return (ret);
879 }
880
881
882 static int
dhd_sdreg(void * dhd,cmd_t * cmd,char ** argv)883 dhd_sdreg(void *dhd, cmd_t *cmd, char **argv)
884 {
885 int ret;
886 sdreg_t sdreg;
887 uint argc;
888 char *ptr = NULL;
889
890 UNUSED_PARAMETER(cmd);
891
892 bzero(&sdreg, sizeof(sdreg));
893
894 /* arg count */
895 for (argc = 0; argv[argc]; argc++);
896 argc--;
897
898 /* required args: offset (will default size) */
899 if (argc < 1) {
900 printf("required args: offset[/size] [value]\n");
901 return BCME_USAGE_ERROR;
902 }
903
904 sdreg.offset = strtoul(argv[1], &ptr, 0);
905 if (*ptr && *ptr != '/') {
906 printf("Bad arg: %s\n", argv[1]);
907 return BCME_USAGE_ERROR;
908 }
909
910 /* read optional /size */
911 if (*ptr == '/') {
912 sdreg.func = strtol((ptr+1), &ptr, 0);
913 if (*ptr || ((sdreg.func != 2) && sdreg.func != 4)) {
914 printf("Bad size option?\n");
915 return BCME_USAGE_ERROR;
916 }
917 }
918 else {
919 sdreg.func = 4;
920 printf("Defaulting to register size 4\n");
921 }
922
923 if (argc > 1) {
924 sdreg.value = strtoul(argv[2], &ptr, 0);
925 if (*ptr) {
926 printf("Bad value: %s\n", argv[2]);
927 return BCME_USAGE_ERROR;
928 }
929 }
930
931 if (argc <= 1) {
932 ret = dhd_var_getbuf(dhd, argv[0], &sdreg, sizeof(sdreg), (void**)&ptr);
933 if (ret >= 0)
934 printf("0x%0*x\n", (2 * sdreg.func), *(int *)ptr);
935 } else {
936 ret = dhd_var_setbuf(dhd, argv[0], &sdreg, sizeof(sdreg));
937 }
938
939 return (ret);
940 }
941
942 static int
dhd_membytes(void * dhd,cmd_t * cmd,char ** argv)943 dhd_membytes(void *dhd, cmd_t *cmd, char **argv)
944 {
945 int ret = -1;
946 uint argc;
947 char *ptr;
948 int params[2];
949 uint addr;
950 uint len;
951 int align;
952
953 int rawout, hexin;
954
955 miniopt_t opts;
956 int opt_err;
957
958 /* Parse command-line options */
959 miniopt_init(&opts, "membytes", "rh", FALSE);
960
961 rawout = hexin = 0;
962
963 argv++;
964 while ((opt_err = miniopt(&opts, argv)) != -1) {
965 if (opt_err == 1) {
966 fprintf(stderr, "membytes options error\n");
967 ret = -1;
968 goto exit;
969 }
970
971 if (opts.positional)
972 break;
973
974 argv += opts.consumed;
975
976 if (opts.opt == 'h') {
977 hexin = 1;
978 } else if (opts.opt == 'r') {
979 rawout = 1;
980 } else {
981 fprintf(stderr, "membytes command error\n");
982 ret = -1;
983 goto exit;
984 }
985 }
986
987 /* arg count */
988 for (argc = 0; argv[argc]; argc++);
989
990 /* required args: address size [<data>]] */
991 if (argc < 2) {
992 fprintf(stderr, "required args: address size [<data>]\n");
993 return BCME_USAGE_ERROR;
994 }
995
996 if (argc < 3 && hexin) {
997 fprintf(stderr, "missing <data> required by -h\n");
998 return BCME_USAGE_ERROR;
999 }
1000 if ((argc > 2) && (rawout)) {
1001 fprintf(stderr, "can't have <data> arg with -r\n");
1002 return BCME_USAGE_ERROR;
1003 }
1004
1005 /* read address */
1006 addr = strtoul(argv[0], &ptr, 0);
1007 if (*ptr) {
1008 fprintf(stderr, "Bad arg: %s\n", argv[0]);
1009 return BCME_USAGE_ERROR;
1010 }
1011
1012 /* read size */
1013 len = strtoul(argv[1], &ptr, 0);
1014 if (*ptr) {
1015 fprintf(stderr, "Bad value: %s\n", argv[1]);
1016 return BCME_USAGE_ERROR;
1017 }
1018
1019 align = addr & 0x03;
1020 if (align && argc > 2) {
1021 fprintf(stderr, "Can only write starting at long-aligned addresses.\n");
1022 return BCME_USAGE_ERROR;
1023 }
1024
1025 /* get can just use utility function, set must copy custom buffer */
1026 if (argc == 2) {
1027 /* Read */
1028 uint chunk = DHD_IOCTL_MAXLEN;
1029 for (addr -= align, len += align; len; addr += chunk, len -= chunk, align = 0) {
1030 chunk = MIN(chunk, len);
1031 params[0] = addr;
1032 params[1] = ROUNDUP(chunk, 4);
1033 ret = dhd_var_getbuf(dhd, "membytes",
1034 params, (2 * sizeof(int)), (void**)&ptr);
1035 if (ret < 0)
1036 goto exit;
1037
1038 if (rawout) {
1039 fwrite(ptr + align, sizeof(char), chunk - align, stdout);
1040 } else {
1041 dhd_hexdump((uchar*)ptr + align, chunk - align, addr + align);
1042 }
1043 }
1044 } else {
1045 /* Write */
1046 uint patlen = strlen(argv[2]);
1047 uint chunk, maxchunk;
1048 char *sptr;
1049
1050 if (hexin) {
1051 char *inptr, *outptr;
1052 if (patlen & 1) {
1053 fprintf(stderr, "Hex (-h) must consist of whole bytes\n");
1054 ret = BCME_USAGE_ERROR;
1055 goto exit;
1056 }
1057
1058 for (inptr = outptr = argv[2]; patlen; patlen -= 2) {
1059 int n1, n2;
1060
1061 n1 = (int)((unsigned char)*inptr++);
1062 n2 = (int)((unsigned char)*inptr++);
1063 if (!isxdigit(n1) || !isxdigit(n2)) {
1064 fprintf(stderr, "invalid hex digit %c\n",
1065 (isxdigit(n1) ? n2 : n1));
1066 ret = BCME_USAGE_ERROR;
1067 goto exit;
1068 }
1069 n1 = isdigit(n1) ? (n1 - '0')
1070 : ((islower(n1) ? (toupper(n1)) : n1) - 'A' + 10);
1071 n2 = isdigit(n2) ? (n2 - '0')
1072 : ((islower(n2) ? (toupper(n2)) : n2) - 'A' + 10);
1073 *outptr++ = (n1 * 16) + n2;
1074 }
1075
1076 patlen = outptr - argv[2];
1077 }
1078
1079 sptr = argv[2];
1080 maxchunk = DHD_IOCTL_MAXLEN - (strlen(cmd->name) + 1 + (2 * sizeof(int)));
1081
1082 while (len) {
1083 chunk = (len > maxchunk) ? (maxchunk & ~0x3) : len;
1084
1085 /* build the iovar command */
1086 memset(buf, 0, DHD_IOCTL_MAXLEN);
1087 strcpy(buf, cmd->name);
1088 ptr = buf + strlen(buf) + 1;
1089 params[0] = addr; params[1] = chunk;
1090 memcpy(ptr, params, (2 * sizeof(int)));
1091 ptr += (2 * sizeof(int));
1092 addr += chunk; len -= chunk;
1093
1094 while (chunk--) {
1095 *ptr++ = *sptr++;
1096 if (sptr >= (argv[2] + patlen))
1097 sptr = argv[2];
1098 }
1099
1100 ret = dhd_set(dhd, DHD_SET_VAR, &buf[0], (ptr - buf));
1101 if (ret < 0)
1102 goto exit;
1103 }
1104 }
1105
1106 exit:
1107 return ret;
1108 }
1109
1110 static int
dhd_idletime(void * dhd,cmd_t * cmd,char ** argv)1111 dhd_idletime(void *dhd, cmd_t *cmd, char **argv)
1112 {
1113 int32 idletime;
1114 char *endptr = NULL;
1115 int err = 0;
1116
1117 if (argv[1]) {
1118 if (!strcmp(argv[1], "never")) {
1119 idletime = 0;
1120 } else if (!strcmp(argv[1], "immediate") || !strcmp(argv[1], "immed")) {
1121 idletime = DHD_IDLE_IMMEDIATE;
1122 } else {
1123 idletime = strtol(argv[1], &endptr, 0);
1124 if (*endptr != '\0') {
1125 fprintf(stderr, "invalid number %s\n", argv[1]);
1126 err = BCME_USAGE_ERROR;
1127 }
1128 }
1129 if ((idletime < 0) && (idletime != DHD_IDLE_IMMEDIATE)) {
1130 fprintf(stderr, "invalid value %s\n", argv[1]);
1131 err = -1;
1132 }
1133
1134 if (!err) {
1135 strcpy(buf, "idletime");
1136 endptr = buf + strlen(buf) + 1;
1137 memcpy(endptr, &idletime, sizeof(uint32));
1138 endptr += sizeof(uint32);
1139 err = dhd_set(dhd, DHD_SET_VAR, &buf[0], (endptr - buf));
1140 }
1141 } else {
1142 if ((err = dhd_var_get(dhd, cmd, argv))) {
1143 return err;
1144 } else {
1145 idletime = *(int32*)buf;
1146
1147 if (idletime == 0) {
1148 printf("0 (never)\n");
1149 } else if (idletime == DHD_IDLE_IMMEDIATE) {
1150 printf("-1 (immediate)\n");
1151 } else if (idletime > 0) {
1152 printf("%d\n", idletime);
1153 } else printf("%d (invalid)\n", idletime);
1154 }
1155 }
1156 return err;
1157 }
1158
1159 static int
dhd_idleclock(void * dhd,cmd_t * cmd,char ** argv)1160 dhd_idleclock(void *dhd, cmd_t *cmd, char **argv)
1161 {
1162 int32 idleclock;
1163 char *endptr = NULL;
1164 int err = 0;
1165
1166 if (argv[1]) {
1167 if (!strcmp(argv[1], "active")) {
1168 idleclock = DHD_IDLE_ACTIVE;
1169 } else if (!strcmp(argv[1], "stopped")) {
1170 idleclock = DHD_IDLE_STOP;
1171 } else {
1172 idleclock = strtol(argv[1], &endptr, 0);
1173 if (*endptr != '\0') {
1174 fprintf(stderr, "invalid number %s\n", argv[1]);
1175 err = BCME_USAGE_ERROR;
1176 }
1177 }
1178
1179 if (!err) {
1180 strcpy(buf, "idleclock");
1181 endptr = buf + strlen(buf) + 1;
1182 memcpy(endptr, &idleclock, sizeof(int32));
1183 endptr += sizeof(int32);
1184 err = dhd_set(dhd, DHD_SET_VAR, &buf[0], (endptr - buf));
1185 }
1186 } else {
1187 if ((err = dhd_var_get(dhd, cmd, argv))) {
1188 return err;
1189 } else {
1190 idleclock = *(int32*)buf;
1191
1192 if (idleclock == DHD_IDLE_ACTIVE)
1193 printf("Idleclock %d (active)\n", idleclock);
1194 else if (idleclock == DHD_IDLE_STOP)
1195 printf("Idleclock %d (stopped)\n", idleclock);
1196 else
1197 printf("Idleclock divisor %d\n", idleclock);
1198 }
1199 }
1200 return err;
1201 }
1202
1203 /* Word count for a 4kb SPROM */
1204 #define SPROM_WORDS 256
1205
1206 static int
dhd_sprom(void * dhd,cmd_t * cmd,char ** argv)1207 dhd_sprom(void *dhd, cmd_t *cmd, char **argv)
1208 {
1209 #if !defined(BWL_FILESYSTEM_SUPPORT)
1210 return (-1);
1211 #else
1212 int ret, i;
1213 uint argc;
1214 char *endptr;
1215 char *bufp, *countptr;
1216 uint16 *wordptr;
1217 uint offset, words, bytes;
1218 bool nocrc = FALSE;
1219
1220 char *fname;
1221 FILE *fp;
1222
1223 UNUSED_PARAMETER(cmd);
1224
1225 /* arg count */
1226 for (argc = 0; argv[argc]; argc++);
1227 argc--;
1228
1229 /* init buffer */
1230 bufp = buf;
1231 memset(bufp, 0, DHD_IOCTL_MAXLEN);
1232 strcpy(bufp, "sprom");
1233 bufp += strlen("sprom") + 1;
1234
1235 if (strcmp(argv[0], "srdump") == 0) {
1236 if (argc) {
1237 fprintf(stderr, "Command srdump doesn't take args\n");
1238 return BCME_USAGE_ERROR;
1239 }
1240 offset = 0;
1241 words = SPROM_WORDS;
1242 bytes = 2 * words;
1243
1244 memcpy(bufp, &offset, sizeof(int));
1245 bufp += sizeof(int);
1246 memcpy(bufp, &bytes, sizeof(int));
1247 bufp += sizeof(int);
1248
1249 if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) {
1250 fprintf(stderr, "Internal error: unaligned word buffer\n");
1251 return BCME_ERROR;
1252 }
1253 } else {
1254 if (strcmp(argv[0], "srwrite") != 0) {
1255 fprintf(stderr, "Unimplemented sprom command: %s\n", argv[0]);
1256 return BCME_USAGE_ERROR;
1257 }
1258
1259 if (argc == 0) {
1260 return BCME_USAGE_ERROR;
1261 } else if ((argc == 1) ||
1262 ((argc == 2) && ((nocrc = !strcmp(argv[1], "-c"))))) {
1263
1264 fname = nocrc ? argv[2] : argv[1];
1265
1266 /* determine and validate file size */
1267 if ((ret = file_size(fname)) < 0)
1268 return BCME_ERROR;
1269
1270 bytes = ret;
1271 offset = 0;
1272 words = bytes / 2;
1273
1274 if (bytes != 2 * SPROM_WORDS) {
1275 fprintf(stderr, "Bad file size\n");
1276 return BCME_ERROR;
1277 }
1278
1279 memcpy(bufp, &offset, sizeof(int));
1280 bufp += sizeof(int);
1281 memcpy(bufp, &bytes, sizeof(int));
1282 bufp += sizeof(int);
1283
1284 if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) {
1285 fprintf(stderr, "Internal error: unaligned word buffer\n");
1286 return BCME_ERROR;
1287 }
1288
1289 if ((fp = fopen(fname, "rb")) == NULL) {
1290 fprintf(stderr, "Could not open %s: %s\n",
1291 fname, strerror(errno));
1292 return BCME_ERROR;
1293 }
1294
1295 if (fread((uint16*)bufp, sizeof(uint16), words, fp) != words) {
1296 fprintf(stderr, "Could not read %d bytes from %s\n",
1297 words * 2, fname);
1298 fclose(fp);
1299 return BCME_ERROR;
1300 }
1301
1302 fclose(fp);
1303
1304 if (!nocrc &&
1305 hndcrc8((uint8*)bufp, bytes, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE) {
1306 fprintf(stderr, "CRC check failed: 0x%02x, should be 0x%02x.\n",
1307 ((uint8*)bufp)[bytes-1],
1308 ~hndcrc8((uint8*)bufp, bytes - 1, CRC8_INIT_VALUE) & 0xff);
1309 return BCME_ERROR;
1310 }
1311
1312 ltoh16_buf(bufp, bytes);
1313 } else {
1314 offset = strtoul(*++argv, &endptr, 0) * 2;
1315 if (*endptr != '\0') {
1316 fprintf(stderr, "offset %s is not an integer\n", *argv);
1317 return BCME_USAGE_ERROR;
1318 }
1319
1320 memcpy(bufp, &offset, sizeof(int));
1321 bufp += sizeof(int);
1322 countptr = bufp;
1323 bufp += sizeof(int);
1324
1325 if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) {
1326 fprintf(stderr, "Internal error: unaligned word buffer\n");
1327 return BCME_ERROR;
1328 }
1329
1330 for (words = 0, wordptr = (uint16*)bufp; *++argv; words++) {
1331 *wordptr++ = (uint16)strtoul(*argv, &endptr, 0);
1332 if (*endptr != '\0') {
1333 fprintf(stderr, "value %s is not an integer\n", *argv);
1334 return BCME_USAGE_ERROR;
1335 }
1336 if (words > SPROM_WORDS) {
1337 fprintf(stderr, "max of %d words\n", SPROM_WORDS);
1338 return BCME_USAGE_ERROR;
1339 }
1340 }
1341
1342 bytes = 2 * words;
1343 memcpy(countptr, &bytes, sizeof(int));
1344 }
1345 }
1346
1347 if (argc) {
1348 ret = dhd_set(dhd, DHD_SET_VAR, buf,
1349 (strlen("sprom") + 1) + (2 * sizeof(int)) + bytes);
1350 return (ret);
1351 } else {
1352 ret = dhd_get(dhd, DHD_GET_VAR, buf,
1353 (strlen("sprom") + 1) + (2 * sizeof(int)) + bytes);
1354 if (ret < 0) {
1355 return ret;
1356 }
1357
1358 for (i = 0; i < (int)words; i++) {
1359 if ((i % 8) == 0)
1360 printf("\n srom[%03d]: ", i);
1361 printf("0x%04x ", ((uint16*)buf)[i]);
1362 }
1363 printf("\n");
1364 }
1365
1366 return 0;
1367 #endif /* BWL_FILESYSTEM_SUPPORT */
1368 }
1369
1370 /*
1371 * read_vars: reads an environment variables file into a buffer,
1372 * reformatting them and returning the length (-1 on error).
1373 *
1374 * The input text file consists of lines of the form "<var>=<value>\n".
1375 * CRs are ignored, as are blank lines and comments beginning with '#'.
1376 *
1377 * The output buffer consists of blocks of the form "<var>=<value>\0"
1378 * (the newlines have been replaced by NULs)
1379 *
1380 * Todo: allow quoted variable names and quoted values.
1381 */
1382
1383 #if defined(BWL_FILESYSTEM_SUPPORT)
1384 static int
read_vars(char * fname,char * buf,int buf_maxlen)1385 read_vars(char *fname, char *buf, int buf_maxlen)
1386 {
1387 FILE *fp;
1388 int buf_len, slen;
1389 char line[256], *s, *e;
1390 int line_no = 0;
1391
1392 if ((fp = fopen(fname, "rb")) == NULL) {
1393 fprintf(stderr, "Cannot open NVRAM file %s: %s\n",
1394 fname, strerror(errno));
1395 exit(1);
1396 }
1397
1398 buf_len = 0;
1399
1400 while (fgets(line, sizeof(line), fp) != NULL) {
1401 bool found_eq = FALSE;
1402
1403 /* Ensure line length is limited */
1404 line[sizeof(line) - 1] = 0;
1405
1406 /* Skip any initial white space */
1407 for (s = line; *s == ' ' || *s == '\t'; s++)
1408 ;
1409
1410 /* Determine end of string */
1411 for (e = s; *e != 0 && *e != '#' && *e != '\r' && *e != '\n'; e++)
1412 if (*e == '=')
1413 found_eq = TRUE;
1414
1415 /* Strip any white space from end of string */
1416 while (e > s && (e[-1] == ' ' || e[-1] == '\t'))
1417 e--;
1418
1419 slen = e - s;
1420
1421 /* Skip lines that end up blank */
1422 if (slen == 0)
1423 continue;
1424
1425 if (!found_eq) {
1426 fprintf(stderr, "Invalid line %d in NVRAM file %s\n", line_no, fname);
1427 fclose(fp);
1428 return -1;
1429 }
1430
1431 if (buf_len + slen + 1 > buf_maxlen) {
1432 fprintf(stderr, "NVRAM file %s too long\n", fname);
1433 fclose(fp);
1434 return -1;
1435 }
1436
1437 memcpy(buf + buf_len, s, slen);
1438 buf_len += slen;
1439 buf[buf_len++] = 0;
1440 }
1441
1442 fclose(fp);
1443
1444 return buf_len;
1445 }
1446 #endif /* BWL_FILESYSTEM_SUPPORT */
1447
1448 static int
dhd_vars(void * dhd,cmd_t * cmd,char ** argv)1449 dhd_vars(void *dhd, cmd_t *cmd, char **argv)
1450 {
1451 int ret;
1452 uint argc;
1453 char *bufp;
1454
1455 UNUSED_PARAMETER(cmd);
1456
1457 /* arg count */
1458 for (argc = 0; argv[argc]; argc++);
1459 argc--;
1460
1461 switch (argc) {
1462 case 0: /* get */
1463 {
1464 if ((ret = dhd_var_getbuf(dhd, "vars", NULL, 0, (void**)&bufp)))
1465 break;
1466 while (*bufp) {
1467 printf("%s\n", bufp);
1468 bufp += strlen(bufp) + 1;
1469 }
1470 }
1471 break;
1472
1473 #if defined(BWL_FILESYSTEM_SUPPORT)
1474 case 1: /* set */
1475 {
1476 char *vname;
1477 uint nvram_len;
1478
1479 vname = argv[1];
1480
1481 bufp = buf;
1482 strcpy(bufp, "vars");
1483 bufp += strlen("vars") + 1;
1484
1485 if ((ret = read_vars(vname, bufp,
1486 DHD_IOCTL_MAXLEN - (strlen("vars") + 3))) < 0) {
1487 ret = -1;
1488 break;
1489 }
1490
1491 nvram_len = ret;
1492 bufp += nvram_len;
1493 *bufp++ = 0;
1494
1495 ret = dhd_set(dhd, DHD_SET_VAR, buf, bufp - buf);
1496 }
1497 break;
1498 #endif /* BWL_FILESYSTEM_SUPPORT */
1499
1500 default:
1501 ret = -1;
1502 break;
1503 }
1504
1505 return ret;
1506 }
1507
1508 #define MEMBLOCK 2048
1509
1510 /* Check that strlen("membytes")+1 + 2*sizeof(int32) + MEMBLOCK <= DHD_IOCTL_MAXLEN */
1511 #if (MEMBLOCK + 17 > DHD_IOCTL_MAXLEN)
1512 #error MEMBLOCK/DHD_IOCTL_MAXLEN sizing
1513 #endif
1514
1515
1516 #if defined(BWL_FILESYSTEM_SUPPORT)
1517 static int
dhd_verify_file_bytes(void * dhd,uint8 * memblock,int start,uint len)1518 dhd_verify_file_bytes(void *dhd, uint8 *memblock, int start, uint len)
1519 {
1520 int ret = 0;
1521 uint i = 0;
1522 char *ptr;
1523 int params[2];
1524 uint8 *src, *dst;
1525
1526 params[0] = start;
1527 params[1] = len;
1528 ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);
1529 if (ret) {
1530 fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",
1531 __FUNCTION__, len, start);
1532 return ret;
1533 }
1534
1535 src = (uint8 *)memblock;
1536 dst = (uint8 *)ptr;
1537 while (i < len) {
1538 if (src[i] != dst[i]) {
1539 fprintf(stderr, " 0x%x: exp[0x%02X] != got[0x%02X]\n",
1540 start+i, src[i], dst[i]);
1541 ret = -1;
1542 }
1543 i++;
1544 }
1545
1546 return ret;
1547 }
1548
1549 static int
dhd_load_file_bytes(void * dhd,cmd_t * cmd,FILE * fp,int fsize,int start,uint blk_sz,bool verify)1550 dhd_load_file_bytes(void *dhd, cmd_t *cmd, FILE *fp, int fsize, int start, uint blk_sz, bool verify)
1551 {
1552 int tot_len = 0;
1553 uint read_len;
1554 char *bufp;
1555 uint len;
1556 uint8 memblock[MEMBLOCK];
1557 int ret;
1558 int retry;
1559
1560 UNUSED_PARAMETER(cmd);
1561
1562 if (!fsize || !fp)
1563 return -1;
1564
1565 assert(blk_sz <= MEMBLOCK);
1566
1567 while (tot_len < fsize) {
1568 read_len = fsize - tot_len;
1569 if (read_len >= blk_sz) {
1570 read_len = blk_sz;
1571
1572 if (!ISALIGNED(start, MEMBLOCK))
1573 read_len = ROUNDUP(start, MEMBLOCK) - start;
1574 }
1575
1576 len = fread(memblock, sizeof(uint8), read_len, fp);
1577 if ((len < read_len) && !feof(fp)) {
1578 fprintf(stderr, "%s: error reading file\n", __FUNCTION__);
1579 return -1;
1580
1581 }
1582 retry = 0;
1583 failed_retry:
1584
1585 bufp = buf;
1586 memset(bufp, 0, DHD_IOCTL_MAXLEN);
1587 strcpy(bufp, "membytes");
1588 bufp += strlen("membytes") + 1;
1589 memcpy(bufp, &start, sizeof(int));
1590 bufp += sizeof(int);
1591 memcpy(bufp, &len, sizeof(int));
1592 bufp += sizeof(int);
1593 memcpy(bufp, memblock, len);
1594
1595 ret = dhd_set(dhd, DHD_SET_VAR, &buf[0], (bufp - buf + len));
1596
1597 if (ret) {
1598 fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",
1599 __FUNCTION__, ret, len, start);
1600 return ret;
1601 }
1602
1603 if (verify == TRUE) {
1604 if (dhd_verify_file_bytes(dhd, memblock, start, len) != 0) {
1605 if (retry++ < 5000)
1606 {
1607 fprintf(stderr, "%s: verify failed %d membytes "
1608 "from 0x%08x\n", __FUNCTION__, len, start);
1609 goto failed_retry;
1610 }
1611 }
1612 }
1613
1614 start += len;
1615 tot_len += len;
1616 }
1617 return 0;
1618 }
1619 #endif /* BWL_FILESYSTEM_SUPPORT */
1620
1621 #ifdef PROP_TXSTATUS
1622 static int
dhd_proptxstatusenable(void * dhd,cmd_t * cmd,char ** argv)1623 dhd_proptxstatusenable(void *dhd, cmd_t *cmd, char **argv)
1624 {
1625 int flag = 0xdead;
1626 int ret;
1627
1628 if (argv[1]) {
1629 flag = atoi(argv[1]);
1630 ret = dhd_iovar_setint(dhd, cmd->name, flag);
1631 }
1632 else {
1633 ret = dhd_iovar_getint(dhd, cmd->name, &flag);
1634 if (ret >= 0)
1635 printf("proptxstatus: %d\n", flag);
1636 }
1637 return ret;
1638 }
1639
1640 static int
dhd_proptxstatusmode(void * dhd,cmd_t * cmd,char ** argv)1641 dhd_proptxstatusmode(void *dhd, cmd_t *cmd, char **argv)
1642 {
1643 int mode = 0xdead;
1644 int ret;
1645
1646 if (argv[1]) {
1647 mode = atoi(argv[1]);
1648 ret = dhd_iovar_setint(dhd, cmd->name, mode);
1649 }
1650 else {
1651 ret = dhd_iovar_getint(dhd, cmd->name, &mode);
1652 if (ret >= 0)
1653 printf("proptxstatusmode: %d\n", mode);
1654 }
1655 return ret;
1656 }
1657
1658 static int
dhd_proptxopt(void * dhd,cmd_t * cmd,char ** argv)1659 dhd_proptxopt(void *dhd, cmd_t *cmd, char **argv)
1660 {
1661 int flag = 0xdead;
1662 int ret;
1663
1664 if (argv[1]) {
1665 flag = atoi(argv[1]);
1666 ret = dhd_iovar_setint(dhd, cmd->name, flag);
1667 }
1668 else {
1669 ret = dhd_iovar_getint(dhd, cmd->name, &flag);
1670 if (ret >= 0)
1671 printf("proptx_opt: %d\n", flag);
1672 }
1673 return ret;
1674 }
1675
1676 #endif /* PROP_TXSTATUS */
1677
1678 static int
dhd_get_ramstart(void * dhd,uint32 * ramstart)1679 dhd_get_ramstart(void *dhd, uint32 *ramstart)
1680 {
1681 int ret;
1682 char *ramstart_args[] = {"ramstart", NULL};
1683
1684 /* Read the bus type the DHD driver is associated to */
1685 if ((ret = dhd_var_get(dhd, NULL, ramstart_args)) != BCME_OK) {
1686 fprintf(stderr, "%s: error obtaining ramstart\n", __FUNCTION__);
1687
1688 return ret;
1689 }
1690
1691 *ramstart = *(uint32 *)buf;
1692
1693 return BCME_OK;
1694 }
1695
1696 static int
dhd_download(void * dhd,cmd_t * cmd,char ** argv)1697 dhd_download(void *dhd, cmd_t *cmd, char **argv)
1698 {
1699 #if !defined(BWL_FILESYSTEM_SUPPORT)
1700 return (-1);
1701 #else
1702 bool reset = TRUE;
1703 bool run = TRUE;
1704 bool verify = FALSE;
1705 char *fname = NULL;
1706 char *vname = NULL;
1707 uint32 start;
1708 int ret = 0;
1709 int fsize;
1710 uint32 bustype;
1711 long filepos;
1712
1713 FILE *fp = NULL;
1714 uint32 ramsize;
1715 char *memszargs[] = { "ramsize", NULL };
1716
1717 char *bufp;
1718
1719 miniopt_t opts;
1720 int opt_err;
1721 uint nvram_len;
1722 struct trx_header trx_hdr;
1723 uint32 trx_hdr_len;
1724 bool trx_file = FALSE;
1725 uint memblock_sz = MEMBLOCK;
1726 bool embedded_ucode = FALSE;
1727
1728 UNUSED_PARAMETER(cmd);
1729
1730 if ((ret = dhd_get_ramstart(dhd, &start)) != BCME_OK)
1731 goto exit;
1732
1733 /* Parse command-line options */
1734 miniopt_init(&opts, "download", "", TRUE);
1735
1736 argv++;
1737 while ((opt_err = miniopt(&opts, argv)) != -1) {
1738 if (opt_err == 1) {
1739 fprintf(stderr, "download options error\n");
1740 ret = -1;
1741 goto exit;
1742 }
1743 argv += opts.consumed;
1744
1745 if (opts.opt == 'a') {
1746 if (!opts.good_int) {
1747 fprintf(stderr, "invalid address %s\n", opts.valstr);
1748 ret = -1;
1749 goto exit;
1750 }
1751 start = (uint32)opts.uval;
1752 } else if (opts.positional) {
1753 if (fname && vname) {
1754 fprintf(stderr, "extra positional arg, %s\n",
1755 opts.valstr);
1756 ret = -1;
1757 goto exit;
1758 }
1759 if (fname)
1760 vname = opts.valstr;
1761 else
1762 fname = opts.valstr;
1763 } else if (!opts.opt) {
1764 if (!strcmp(opts.key, "noreset")) {
1765 reset = FALSE;
1766 } else if (!strcmp(opts.key, "norun")) {
1767 run = FALSE;
1768 } else if (!strcmp(opts.key, "verify")) {
1769 verify = TRUE;
1770 } else {
1771 fprintf(stderr, "unrecognized option %s\n", opts.valstr);
1772 ret = -1;
1773 goto exit;
1774 }
1775 } else {
1776 fprintf(stderr, "unrecognized option %c\n", opts.opt);
1777 ret = -1;
1778 goto exit;
1779 }
1780 }
1781
1782 /* validate arguments */
1783 if (!fname) {
1784 fprintf(stderr, "filename required\n");
1785 ret = -1;
1786 goto exit;
1787 }
1788
1789 /* validate file size compared to memory size */
1790 if ((fsize = file_size(fname)) < 0) {
1791 ret = -1;
1792 goto exit;
1793 }
1794 /* read the file and push blocks down to memory */
1795 if ((fp = fopen(fname, "rb")) == NULL) {
1796 fprintf(stderr, "%s: unable to open %s: %s\n",
1797 __FUNCTION__, fname, strerror(errno));
1798 ret = -1;
1799 goto exit;
1800 }
1801 /* Verify the file is a regular bin file or trx file */
1802 {
1803 uint32 tmp_len;
1804 trx_hdr_len = sizeof(struct trx_header);
1805 tmp_len = fread(&trx_hdr, sizeof(uint8), trx_hdr_len, fp);
1806 if (tmp_len == trx_hdr_len) {
1807 if (trx_hdr.magic == TRX_MAGIC) {
1808 trx_file = TRUE;
1809 if (trx_hdr.flag_version & TRX_EMBED_UCODE)
1810 embedded_ucode = TRUE;
1811 }
1812 else
1813 fseek(fp, 0, SEEK_SET);
1814 }
1815 else
1816 fseek(fp, 0, SEEK_SET);
1817 }
1818
1819 /* Check on which bus the dhd driver is sitting. Downloading methodology differs from
1820 * USB to SDIO.
1821 */
1822 {
1823 char* bustype_args[] = {"bustype", NULL};
1824
1825 /* Read the bus type the DHD driver is associated to */
1826 if ((ret = dhd_var_get(dhd, NULL, bustype_args))) {
1827 fprintf(stderr, "%s: error obtaining bustype\n", __FUNCTION__);
1828 goto exit;
1829 }
1830
1831 bustype = *(uint32*)buf;
1832 }
1833
1834 if (trx_file)
1835 fsize = (int)(trx_hdr.offsets[0]);
1836
1837 if (bustype == BUS_TYPE_SDIO) {
1838 if ((ret = dhd_var_get(dhd, NULL, memszargs))) {
1839 fprintf(stderr, "%s: error obtaining ramsize\n", __FUNCTION__);
1840 goto exit;
1841 }
1842 ramsize = *(uint32*)buf;
1843 }
1844
1845
1846 BCM_REFERENCE(ramsize);
1847
1848 /* do the download reset if not suppressed */
1849 if (reset) {
1850 if ((ret = dhd_iovar_setint(dhd, "dwnldstate", TRUE))) {
1851 fprintf(stderr, "%s: failed to put dongle in download mode\n",
1852 __FUNCTION__);
1853 goto exit;
1854 }
1855 }
1856
1857 #define RDL_CHUNK 1500 /* size of each dl transfer */
1858
1859 if (BUS_TYPE_USB == bustype) {
1860 /* store the cur pos pointing to base image which should be written */
1861 filepos = ftell(fp);
1862 if (filepos == -1) {
1863 fprintf(stderr, "%s: ftell failed.\n", __FUNCTION__);
1864 }
1865
1866 /* In case of USB, we need to write header information also to dongle. */
1867 fseek(fp, 0, SEEK_SET);
1868
1869 /* The file size is "base_image + TRX_Header_size" */
1870 fsize = (int)(trx_hdr.offsets[0] + sizeof(struct trx_header));
1871
1872 memblock_sz = RDL_CHUNK;
1873 }
1874
1875
1876 /* Load the ram image */
1877 if ((ret = dhd_load_file_bytes(dhd, cmd, fp, fsize, start, memblock_sz, verify))) {
1878 fprintf(stderr, "%s: error loading the ramimage at addr 0x%x\n",
1879 __FUNCTION__, start);
1880 goto exit;
1881 }
1882
1883 if (trx_file) {
1884
1885 filepos = ftell(fp);
1886 if (filepos == -1) {
1887 fprintf(stderr, "%s: ftell failed.\n", __FUNCTION__);
1888 }
1889
1890 if (BUS_TYPE_SDIO == bustype) {
1891
1892 }
1893 }
1894
1895 fclose(fp);
1896 fp = NULL;
1897
1898 /* download the vars file if specified */
1899 if (vname) {
1900 bufp = buf;
1901 strcpy(bufp, "vars");
1902 bufp += strlen("vars") + 1;
1903
1904 if ((ret = read_vars(vname, bufp,
1905 DHD_IOCTL_MAXLEN - (strlen("vars") + 3))) < 0) {
1906 ret = -1;
1907 goto exit;
1908 }
1909
1910 nvram_len = ret;
1911 bufp += nvram_len;
1912 *bufp++ = 0;
1913
1914 ret = dhd_set(dhd, DHD_SET_VAR, buf, (bufp - buf));
1915 if (ret) {
1916 fprintf(stderr, "%s: error %d on delivering vars\n",
1917 __FUNCTION__, ret);
1918 goto exit;
1919 }
1920 }
1921
1922 /* start running the downloaded code if not suppressed */
1923 if (run) {
1924 if ((ret = dhd_iovar_setint(dhd, "dwnldstate", FALSE))) {
1925
1926 fprintf(stderr, "%s: failed to take dongle out of download mode\n",
1927 __FUNCTION__);
1928 /* USB Error return values */
1929 if (BUS_TYPE_USB == bustype) {
1930 if (ret == -1)
1931 fprintf(stderr, "%s: CPU is not in RUNNABLE State\n",
1932 __FUNCTION__);
1933 else
1934 fprintf(stderr, "%s: Error in setting CPU to RUN mode.\n",
1935 __FUNCTION__);
1936 }
1937 goto exit;
1938 }
1939 }
1940 if (embedded_ucode) {
1941 }
1942
1943 exit:
1944 if (fp)
1945 fclose(fp);
1946
1947 return ret;
1948 #endif /* BWL_FILESYSTEM_SUPPORT */
1949 }
1950
1951 static int
dhd_dldn(void * dhd,cmd_t * cmd,char ** argv)1952 dhd_dldn(void *dhd, cmd_t *cmd, char **argv)
1953 {
1954 #if !defined(BWL_FILESYSTEM_SUPPORT)
1955 return (-1);
1956 #else
1957 char *fname = NULL;
1958 uint32 start;
1959 int ret = 0;
1960 int fsize;
1961 int fd = 0;
1962
1963 FILE *fp = NULL;
1964 uint32 ramsize;
1965
1966 uint len;
1967 uint8 memblock[MEMBLOCK];
1968
1969 miniopt_t opts;
1970 int opt_err;
1971
1972 UNUSED_PARAMETER(cmd);
1973
1974 /* Parse command-line options */
1975 miniopt_init(&opts, "download", "", TRUE);
1976 argv++;
1977
1978 while ((opt_err = miniopt(&opts, argv)) != -1) {
1979 if (opt_err == 1) {
1980 fprintf(stderr, "download options error\n");
1981 ret = -1;
1982 goto exit;
1983 }
1984 argv += opts.consumed;
1985
1986 if (opts.positional) {
1987 if (fname) {
1988 fprintf(stderr, "extra positional arg, %s\n",
1989 opts.valstr);
1990 ret = -1;
1991 goto exit;
1992 }
1993 if (!fname)
1994 fname = opts.valstr;
1995 } else {
1996 fprintf(stderr, "unrecognized option %c\n", opts.opt);
1997 ret = -1;
1998 goto exit;
1999 }
2000 }
2001
2002 fd = dhd_set(dhd, DHD_DLDN_ST, NULL, 0);
2003 if (fd < 0) {
2004 ret = -1;
2005 goto exit;
2006 }
2007
2008 /* validate arguments */
2009 if (!fname) {
2010 fprintf(stderr, "filename required\n");
2011 ret = -1;
2012 goto exit;
2013 }
2014
2015 /* validate file size compared to memory size */
2016 if ((fsize = file_size(fname)) < 0) {
2017 ret = -1;
2018 goto exit;
2019 }
2020
2021 ramsize = 393216;
2022
2023 if (ramsize && ((uint32)fsize > ramsize)) {
2024 fprintf(stderr, "%s: file %s too large (%d > %d)\n",
2025 __FUNCTION__, fname, fsize, ramsize);
2026 ret = -1;
2027 goto exit;
2028 }
2029
2030 /* read the file and push blocks down to memory */
2031 if ((fp = fopen(fname, "rb")) == NULL) {
2032 fprintf(stderr, "%s: unable to open %s: %s\n",
2033 __FUNCTION__, fname, strerror(errno));
2034 ret = -1;
2035 goto exit;
2036 }
2037
2038 if ((ret = dhd_get_ramstart(dhd, &start)) != BCME_OK)
2039 goto exit;
2040
2041 while ((len = fread(memblock, sizeof(uint8), MEMBLOCK, fp))) {
2042 if (len < MEMBLOCK && !feof(fp)) {
2043 fprintf(stderr, "%s: error reading file %s\n", __FUNCTION__, fname);
2044 ret = -1;
2045 goto exit;
2046 }
2047
2048 ret = dhd_set(dhd, DHD_DLDN_WRITE, memblock, len);
2049 if (ret) {
2050 fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",
2051 __FUNCTION__, ret, len, start);
2052 goto exit;
2053 }
2054
2055 start += len;
2056 }
2057
2058 if (!feof(fp)) {
2059 fprintf(stderr, "%s: error reading file %s\n", __FUNCTION__, fname);
2060 ret = -1;
2061 goto exit;
2062 }
2063 fclose(fp);
2064 fp = NULL;
2065
2066 exit:
2067 if (fp)
2068 fclose(fp);
2069
2070 if (fd)
2071 ret = dhd_set(dhd, DHD_DLDN_END, NULL, 0);
2072
2073 return ret;
2074 #endif /* BWL_FILESYSTEM_SUPPORT */
2075 }
2076
2077 static int
dhd_upload(void * dhd,cmd_t * cmd,char ** argv)2078 dhd_upload(void *dhd, cmd_t *cmd, char **argv)
2079 {
2080 #if !defined(BWL_FILESYSTEM_SUPPORT)
2081 return (-1);
2082 #else
2083 char *fname = NULL;
2084 uint32 start;
2085 uint32 size = 0;
2086 int ret = 0;
2087
2088 FILE *fp;
2089 uint32 ramsize;
2090 char *memszargs[] = { "ramsize", NULL };
2091
2092 uint len;
2093
2094 miniopt_t opts;
2095 int opt_err;
2096
2097 UNUSED_PARAMETER(cmd);
2098 UNUSED_PARAMETER(argv);
2099
2100 if ((ret = dhd_get_ramstart(dhd, &start)) != BCME_OK)
2101 goto exit;
2102
2103 /* Parse command-line options */
2104 miniopt_init(&opts, "upload", "", TRUE);
2105
2106 argv++;
2107 while ((opt_err = miniopt(&opts, argv)) != -1) {
2108 if (opt_err == 1) {
2109 fprintf(stderr, "upload options error\n");
2110 ret = -1;
2111 goto exit;
2112 }
2113 argv += opts.consumed;
2114
2115 if (opts.opt == 'a') {
2116 if (!opts.good_int) {
2117 fprintf(stderr, "invalid address %s\n", opts.valstr);
2118 ret = -1;
2119 goto exit;
2120 }
2121 start = (uint32)opts.uval;
2122 } else if (opts.positional) {
2123 if (!fname) {
2124 fname = opts.valstr;
2125 } else if (opts.good_int) {
2126 size = (uint32)opts.uval;
2127 } else {
2128 fprintf(stderr, "upload options error\n");
2129 ret = -1;
2130 goto exit;
2131 }
2132 } else if (!opts.opt) {
2133 fprintf(stderr, "unrecognized option %s\n", opts.valstr);
2134 ret = -1;
2135 goto exit;
2136 } else {
2137 fprintf(stderr, "unrecognized option %c\n", opts.opt);
2138 ret = -1;
2139 goto exit;
2140 }
2141 }
2142
2143 /* validate arguments */
2144 if (!fname) {
2145 fprintf(stderr, "filename required\n");
2146 ret = -1;
2147 goto exit;
2148 }
2149
2150 if ((ret = dhd_var_get(dhd, NULL, memszargs))) {
2151 fprintf(stderr, "%s: error obtaining ramsize\n", __FUNCTION__);
2152 goto exit;
2153 }
2154 ramsize = *(uint32*)buf;
2155
2156 if (!ramsize)
2157 ramsize = start + size;
2158
2159 if ((fp = fopen(fname, "wb")) == NULL) {
2160 fprintf(stderr, "%s: Could not open %s: %s\n",
2161 __FUNCTION__, fname, strerror(errno));
2162 ret = -1;
2163 goto exit;
2164 }
2165
2166 /* default size to full RAM */
2167 if (!size)
2168 size = ramsize - start;
2169
2170 /* read memory and write to file */
2171 while (size) {
2172 char *ptr;
2173 int params[2];
2174
2175 len = MIN(MEMBLOCK, size);
2176
2177 params[0] = start;
2178 params[1] = len;
2179 ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);
2180 if (ret) {
2181 fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",
2182 __FUNCTION__, len, start);
2183 break;
2184 }
2185
2186 if (fwrite(ptr, sizeof(char), len, fp) != len) {
2187 fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);
2188 ret = -1;
2189 break;
2190 }
2191
2192 start += len;
2193 size -= len;
2194 }
2195
2196 fclose(fp);
2197 exit:
2198 return ret;
2199 #endif /* BWL_FILESYSTEM_SUPPORT */
2200 }
2201
2202 #ifdef BWL_FILESYSTEM_SUPPORT
2203 static int
dhd_get_debug_info(void * dhd,hndrte_debug_t * debug_info)2204 dhd_get_debug_info(void *dhd, hndrte_debug_t *debug_info)
2205 {
2206 int i;
2207 int ret;
2208 int params[2];
2209
2210 uint32 *buffer;
2211 uint32 debug_info_ptr;
2212 uint32 ramstart;
2213
2214 if ((ret = dhd_get_ramstart(dhd, &ramstart)) != BCME_OK)
2215 return ret;
2216
2217 /*
2218 * Different chips have different fixed debug_info_ptrs
2219 * because of different ROM locations/uses. Try them all looking
2220 * for the magic number.
2221 */
2222 for (i = 0; ; i++) {
2223 if (debug_info_ptrs[i] == DEBUG_INFO_PTRS_END) {
2224 fprintf(stderr, "Error: cannot find pointer to debug_info\n");
2225 return -1;
2226 }
2227
2228 params[0] = debug_info_ptrs[i] + ramstart;
2229 params[1] = 8;
2230 ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&buffer);
2231 if ((ret == 0) &&
2232 (*buffer == HNDRTE_DEBUG_PTR_PTR_MAGIC)) {
2233 break;
2234 }
2235 }
2236
2237 debug_info_ptr = *(buffer + 1);
2238 if (debug_info_ptr == 0) {
2239 fprintf(stderr, "Error: Debug info pointer is zero\n");
2240 return -1;
2241 }
2242
2243 /* Read the area the debuginfoptr points at */
2244 params[0] = debug_info_ptr;
2245 params[1] = sizeof(hndrte_debug_t);
2246 ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&buffer);
2247 if (ret) {
2248 fprintf(stderr, "%s: failed reading %lu membytes from 0x%08lx\n",
2249 __FUNCTION__, (long unsigned) params[1], (long unsigned) params[0]);
2250 return ret;
2251 }
2252
2253 memcpy((char *) debug_info, buffer, sizeof(hndrte_debug_t));
2254
2255 /* Sanity check the area */
2256 if ((debug_info->magic != HNDRTE_DEBUG_MAGIC) ||
2257 (debug_info->version != HNDRTE_DEBUG_VERSION)) {
2258 fprintf(stderr, "Error: Invalid debug info area\n");
2259 return -1;
2260 }
2261
2262 return 0;
2263 }
2264 #endif /* BWL_FILESYSTEM_SUPPORT */
2265
2266 static int
dhd_coredump(void * dhd,cmd_t * cmd,char ** argv)2267 dhd_coredump(void *dhd, cmd_t *cmd, char **argv)
2268 {
2269 #if !defined(BWL_FILESYSTEM_SUPPORT)
2270 return (-1);
2271 #else
2272 char *fname = NULL;
2273 int ret;
2274
2275 FILE *fp;
2276
2277 hndrte_debug_t debugInfo;
2278
2279 miniopt_t opts;
2280 int opt_err;
2281
2282 int params[2];
2283 char *ptr;
2284
2285 unsigned int start;
2286 unsigned int size;
2287
2288 prstatus_t prstatus;
2289
2290 UNUSED_PARAMETER(cmd);
2291 UNUSED_PARAMETER(argv);
2292
2293 /* Parse command-line options */
2294 miniopt_init(&opts, "dump", "", TRUE);
2295
2296 argv++;
2297 while ((opt_err = miniopt(&opts, argv)) != -1) {
2298 if (opt_err == 1) {
2299 fprintf(stderr, "dump options error\n");
2300 ret = -1;
2301 goto exit;
2302 }
2303 argv += opts.consumed;
2304
2305 if (opts.positional) {
2306 if (!fname) {
2307 fname = opts.valstr;
2308 } else {
2309 fprintf(stderr, "dump options error\n");
2310 ret = -1;
2311 goto exit;
2312 }
2313 } else if (!opts.opt) {
2314 fprintf(stderr, "unrecognized option %s\n", opts.valstr);
2315 ret = -1;
2316 goto exit;
2317 } else {
2318 fprintf(stderr, "unrecognized option %c\n", opts.opt);
2319 ret = -1;
2320 goto exit;
2321 }
2322 }
2323
2324 /* validate arguments */
2325 if (!fname) {
2326 fprintf(stderr, "filename required\n");
2327 ret = -1;
2328 goto exit;
2329 }
2330
2331 if ((ret = dhd_get_debug_info(dhd, &debugInfo)) < 0)
2332 goto exit;
2333
2334 /* Get the base and size to dump */
2335 start = debugInfo.ram_base;
2336 size = debugInfo.ram_size;
2337
2338 /* Get the arm trap area */
2339 bzero(&prstatus, sizeof(prstatus_t));
2340 if (debugInfo.trap_ptr != 0) {
2341 int i;
2342 trap_t armtrap;
2343 uint32 *reg;
2344
2345 params[0] = debugInfo.trap_ptr;
2346 params[1] = sizeof(trap_t);
2347 ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);
2348 if (ret) {
2349 fprintf(stderr, "%s: failed reading %lu membytes from 0x%08lx\n",
2350 __FUNCTION__, (long unsigned) params[1], (long unsigned) params[0]);
2351 goto exit;
2352 }
2353
2354 memcpy((char *) &armtrap, ptr, sizeof(trap_t));
2355
2356 /* Populate the prstatus */
2357 prstatus.si_signo = armtrap.type;
2358 reg = &armtrap.r0;
2359 for (i = 0; i < 15; i++, reg++) {
2360 prstatus.uregs[i] = *reg;
2361 }
2362 prstatus.uregs[15] = armtrap.epc;
2363 }
2364
2365 if ((fp = fopen(fname, "wb")) == NULL) {
2366 fprintf(stderr, "%s: Could not open %s: %s\n",
2367 __FUNCTION__, fname, strerror(errno));
2368 ret = -1;
2369 goto exit;
2370 }
2371
2372 /* Write the preamble and debug header */
2373 fprintf(fp, "Dump starts for version %s FWID 01-%x\n", debugInfo.epivers, debugInfo.fwid);
2374 fprintf(fp, "XXXXXXXXXXXXXXXXXXXX");
2375 fprintf(fp, "%8.8lX", (long unsigned) sizeof(debugInfo));
2376 if (fwrite(&debugInfo, sizeof(unsigned char), sizeof(debugInfo), fp) != sizeof(debugInfo)) {
2377 fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);
2378 ret = -1;
2379 fclose(fp);
2380 goto exit;
2381 }
2382
2383 /* Write the prstatus */
2384 if (fwrite(&prstatus, sizeof(unsigned char), sizeof(prstatus), fp) != sizeof(prstatus)) {
2385 fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);
2386 ret = -1;
2387 fclose(fp);
2388 goto exit;
2389 }
2390
2391 /* Write the ram size as another sanity check */
2392 fprintf(fp, "%8.8X", size);
2393
2394 /* read memory and write to file */
2395 while (size) {
2396 int len;
2397 len = MIN(MEMBLOCK, size);
2398
2399 params[0] = start;
2400 params[1] = len;
2401 ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);
2402 if (ret) {
2403 fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",
2404 __FUNCTION__, len, start);
2405 break;
2406 }
2407
2408 if (fwrite(ptr, sizeof(char), len, fp) != (uint) len) {
2409 fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);
2410 ret = -1;
2411 break;
2412 }
2413
2414 start += len;
2415 size -= len;
2416 }
2417
2418 fclose(fp);
2419 exit:
2420 return ret;
2421 #endif /* BWL_FILESYSTEM_SUPPORT */
2422 }
2423
2424 static int
dhd_consoledump(void * dhd,cmd_t * cmd,char ** argv)2425 dhd_consoledump(void *dhd, cmd_t *cmd, char **argv)
2426 {
2427 #if !defined(BWL_FILESYSTEM_SUPPORT)
2428 return (-1);
2429 #else
2430 int ret;
2431
2432 hndrte_debug_t debugInfo;
2433
2434 miniopt_t opts;
2435 int opt_err;
2436
2437 int params[2];
2438 char *ptr;
2439
2440 unsigned int start;
2441 unsigned int size;
2442 int len;
2443
2444 UNUSED_PARAMETER(cmd);
2445 UNUSED_PARAMETER(argv);
2446
2447 /* Parse command-line options */
2448 miniopt_init(&opts, "consoledump", "", TRUE);
2449
2450 argv++;
2451 while ((opt_err = miniopt(&opts, argv)) != -1) {
2452 if (opt_err == 1) {
2453 fprintf(stderr, "dump options error\n");
2454 ret = -1;
2455 goto exit;
2456 }
2457 argv += opts.consumed;
2458
2459 if (!opts.opt) {
2460 fprintf(stderr, "unrecognized option %s\n", opts.valstr);
2461 ret = -1;
2462 goto exit;
2463 } else {
2464 fprintf(stderr, "unrecognized option %c\n", opts.opt);
2465 ret = -1;
2466 goto exit;
2467 }
2468 }
2469
2470 if ((ret = dhd_get_debug_info(dhd, &debugInfo)) < 0)
2471 goto exit;
2472
2473 if (debugInfo.console <= debugInfo.ram_base) {
2474 fprintf(stderr, "%s: console not found\n", __FUNCTION__);
2475 ret = -1;
2476 goto exit;
2477 }
2478
2479 /* Get the debug console area */
2480 params[0] = debugInfo.console;
2481 params[1] = sizeof(hndrte_cons_t);
2482 ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);
2483 if (ret) {
2484 fprintf(stderr, "%s: failed reading %lu membytes from 0x%08lx\n",
2485 __FUNCTION__, (long unsigned) params[1], (long unsigned) params[0]);
2486 goto exit;
2487 }
2488
2489 if (ptr == NULL) {
2490 fprintf(stderr, "%s: console not initialised\n", __FUNCTION__);
2491 ret = -1;
2492 goto exit;
2493 }
2494
2495 start = (unsigned int)((hndrte_cons_t *)ptr)->log.buf;
2496 size = ((hndrte_cons_t *)ptr)->log.buf_size;
2497
2498 if (start <= debugInfo.ram_base) {
2499 fprintf(stderr, "%s: console buffer not initialised\n", __FUNCTION__);
2500 ret = -1;
2501 goto exit;
2502 }
2503
2504 /* read memory and write to file */
2505 while (size > 0) {
2506 len = MIN(MEMBLOCK, size);
2507
2508 params[0] = start;
2509 params[1] = len;
2510 ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);
2511 if (ret) {
2512 fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",
2513 __FUNCTION__, len, start);
2514 break;
2515 }
2516
2517 printf("%s", ptr);
2518
2519 start += len;
2520 size -= len;
2521 }
2522
2523 exit:
2524 return ret;
2525 #endif /* BWL_FILESYSTEM_SUPPORT */
2526 }
2527
2528 static int
dhd_logstamp(void * dhd,cmd_t * cmd,char ** argv)2529 dhd_logstamp(void *dhd, cmd_t *cmd, char **argv)
2530 {
2531 int ret;
2532 char *endptr = NULL;
2533 uint argc;
2534 int valn[2] = {0, 0};
2535
2536 /* arg count */
2537 for (argc = 0; argv[argc]; argc++);
2538 argc--; argv++;
2539
2540 if (argc > 2)
2541 return BCME_USAGE_ERROR;
2542
2543 if (argc) {
2544 valn[0] = strtol(argv[0], &endptr, 0);
2545 if (*endptr != '\0') {
2546 printf("bad val1: %s\n", argv[0]);
2547 return BCME_USAGE_ERROR;
2548 }
2549 }
2550
2551 if (argc > 1) {
2552 valn[1] = strtol(argv[1], &endptr, 0);
2553 if (*endptr != '\0') {
2554 printf("bad val2: %s\n", argv[1]);
2555 return BCME_USAGE_ERROR;
2556 }
2557 }
2558
2559 ret = dhd_var_setbuf(dhd, cmd->name, valn, argc * sizeof(int));
2560
2561 return (ret);
2562 }
2563
2564 static int
dhd_sd_reg(void * dhd,cmd_t * cmd,char ** argv)2565 dhd_sd_reg(void *dhd, cmd_t *cmd, char **argv)
2566 {
2567 int ret;
2568 sdreg_t sdreg;
2569 char *endptr = NULL;
2570 uint argc;
2571 void *ptr = NULL;
2572
2573 bzero(&sdreg, sizeof(sdreg));
2574
2575 /* arg count */
2576 for (argc = 0; argv[argc]; argc++);
2577 argc--;
2578
2579 /* hostreg: offset [value]; devreg: func offset [value] */
2580 if (!strcmp(cmd->name, "sd_hostreg")) {
2581 argv++;
2582 if (argc < 1) {
2583 printf("required args: offset [value]\n");
2584 return BCME_USAGE_ERROR;
2585 }
2586
2587 } else if (!strcmp(cmd->name, "sd_devreg")) {
2588 argv++;
2589 if (argc < 2) {
2590 printf("required args: func offset [value]\n");
2591 return BCME_USAGE_ERROR;
2592 }
2593
2594 sdreg.func = strtoul(*argv++, &endptr, 0);
2595 if (*endptr != '\0') {
2596 printf("Invalid function number\n");
2597 return BCME_USAGE_ERROR;
2598 }
2599 } else {
2600 return BCME_USAGE_ERROR;
2601 }
2602
2603 sdreg.offset = strtoul(*argv++, &endptr, 0);
2604 if (*endptr != '\0') {
2605 printf("Invalid offset value\n");
2606 return BCME_USAGE_ERROR;
2607 }
2608
2609 /* third arg: value */
2610 if (*argv) {
2611 sdreg.value = strtoul(*argv, &endptr, 0);
2612 if (*endptr != '\0') {
2613 printf("Invalid value\n");
2614 return BCME_USAGE_ERROR;
2615 }
2616 }
2617
2618 /* no third arg means get, otherwise set */
2619 if (!*argv) {
2620 if ((ret = dhd_var_getbuf(dhd, cmd->name, &sdreg, sizeof(sdreg), &ptr)) >= 0)
2621 printf("0x%x\n", *(int *)ptr);
2622 } else {
2623 ret = dhd_var_setbuf(dhd, cmd->name, &sdreg, sizeof(sdreg));
2624 }
2625
2626 return (ret);
2627 }
2628
2629 static dbg_msg_t dhd_msgs[] = {
2630 {DHD_ERROR_VAL, "error"},
2631 {DHD_ERROR_VAL, "err"},
2632 {DHD_TRACE_VAL, "trace"},
2633 {DHD_INFO_VAL, "inform"},
2634 {DHD_INFO_VAL, "info"},
2635 {DHD_INFO_VAL, "inf"},
2636 {DHD_DATA_VAL, "data"},
2637 {DHD_CTL_VAL, "ctl"},
2638 {DHD_TIMER_VAL, "timer"},
2639 {DHD_HDRS_VAL, "hdrs"},
2640 {DHD_BYTES_VAL, "bytes"},
2641 {DHD_INTR_VAL, "intr"},
2642 {DHD_LOG_VAL, "log"},
2643 {DHD_GLOM_VAL, "glom"},
2644 {DHD_EVENT_VAL, "event"},
2645 {DHD_BTA_VAL, "bta"},
2646 {DHD_ISCAN_VAL, "iscan"},
2647 {DHD_ARPOE_VAL, "arpoe"},
2648 {DHD_REORDER_VAL, "reorder"},
2649 {0, NULL}
2650 };
2651
2652 static int
dhd_msglevel(void * dhd,cmd_t * cmd,char ** argv)2653 dhd_msglevel(void *dhd, cmd_t *cmd, char **argv)
2654 {
2655 return dhd_do_msglevel(dhd, cmd, argv, dhd_msgs);
2656 }
2657
2658 static int
dhd_do_msglevel(void * dhd,cmd_t * cmd,char ** argv,dbg_msg_t * dbg_msg)2659 dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg)
2660 {
2661 int ret, i;
2662 uint val, last_val = 0, msglevel = 0, msglevel_add = 0, msglevel_del = 0;
2663 char *endptr = NULL;
2664
2665 if ((ret = dhd_iovar_getint(dhd, cmd->name, (int*)&msglevel)) < 0)
2666 return (ret);
2667
2668 if (!*++argv) {
2669 printf("0x%x ", msglevel);
2670 for (i = 0; (val = dbg_msg[i].value); i++) {
2671 if ((msglevel & val) && (val != last_val))
2672 printf(" %s", dbg_msg[i].string);
2673 last_val = val;
2674 }
2675 printf("\n");
2676 return (0);
2677 }
2678
2679 while (*argv) {
2680 char *s = *argv;
2681 if (*s == '+' || *s == '-')
2682 s++;
2683 else
2684 msglevel_del = ~0; /* make the whole list absolute */
2685 val = strtoul(s, &endptr, 0);
2686 /* not a plain integer if not all the string was parsed by strtoul */
2687 if (*endptr != '\0') {
2688 for (i = 0; (val = dbg_msg[i].value); i++)
2689 if (stricmp(dbg_msg[i].string, s) == 0)
2690 break;
2691 if (!val)
2692 goto usage;
2693 }
2694 if (**argv == '-')
2695 msglevel_del |= val;
2696 else
2697 msglevel_add |= val;
2698 ++argv;
2699 }
2700
2701 msglevel &= ~msglevel_del;
2702 msglevel |= msglevel_add;
2703
2704 return (dhd_iovar_setint(dhd, cmd->name, msglevel));
2705
2706 usage:
2707 fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
2708 fprintf(stderr, "Use a + or - prefix to make an incremental change.");
2709
2710 for (i = 0; (val = dbg_msg[i].value); i++) {
2711 if (val != last_val)
2712 fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string);
2713 else
2714 fprintf(stderr, ", %s", dbg_msg[i].string);
2715 last_val = val;
2716 }
2717 fprintf(stderr, "\n");
2718
2719 return 0;
2720 }
2721
2722 static char *
ver2str(unsigned int vms,unsigned int vls)2723 ver2str(unsigned int vms, unsigned int vls)
2724 {
2725 static char verstr[100];
2726 unsigned int maj, year, month, day, build;
2727
2728 maj = (vms >> 16) & 0xFFFF;
2729 if (maj > 1000) {
2730 /* it is probably a date... */
2731 year = (vms >> 16) & 0xFFFF;
2732 month = vms & 0xFFFF;
2733 day = (vls >> 16) & 0xFFFF;
2734 build = vls & 0xFFFF;
2735 sprintf(verstr, "%d/%d/%d build %d",
2736 month, day, year, build);
2737 } else {
2738 /* it is a tagged release. */
2739 sprintf(verstr, "%d.%d RC%d.%d",
2740 (vms>>16)&0xFFFF, vms&0xFFFF,
2741 (vls>>16)&0xFFFF, vls&0xFFFF);
2742 }
2743 return verstr;
2744 }
2745
2746 static int
dhd_version(void * dhd,cmd_t * cmd,char ** argv)2747 dhd_version(void *dhd, cmd_t *cmd, char **argv)
2748 {
2749 int ret;
2750 char *ptr;
2751
2752 UNUSED_PARAMETER(cmd);
2753 UNUSED_PARAMETER(argv);
2754
2755 /* Display the application version info */
2756 printf("%s: %s\n", dhdu_av0,
2757 ver2str((EPI_MAJOR_VERSION << 16)| EPI_MINOR_VERSION,
2758 (EPI_RC_NUMBER << 16) | EPI_INCREMENTAL_NUMBER));
2759
2760 if ((ret = dhd_var_getbuf(dhd, cmd->name, NULL, 0, (void**)&ptr)) < 0)
2761 return ret;
2762
2763 /* Display the returned string */
2764 printf("%s\n", ptr);
2765
2766 return 0;
2767 }
2768
2769 static int
dhd_var_setint(void * dhd,cmd_t * cmd,char ** argv)2770 dhd_var_setint(void *dhd, cmd_t *cmd, char **argv)
2771 {
2772 int32 val;
2773 int len;
2774 char *varname;
2775 char *endptr = NULL;
2776 char *p;
2777
2778 if (cmd->set == -1) {
2779 printf("set not defined for %s\n", cmd->name);
2780 return BCME_ERROR;
2781 }
2782
2783 if (!*argv) {
2784 printf("set: missing arguments\n");
2785 return BCME_USAGE_ERROR;
2786 }
2787
2788 varname = *argv++;
2789
2790 if (!*argv) {
2791 printf("set: missing value argument for set of \"%s\"\n", varname);
2792 return BCME_USAGE_ERROR;
2793 }
2794
2795 val = strtol(*argv, &endptr, 0);
2796 if (*endptr != '\0') {
2797 /* not all the value string was parsed by strtol */
2798 printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n",
2799 *argv, varname);
2800 return BCME_USAGE_ERROR;
2801 }
2802
2803 strcpy(buf, varname);
2804 p = buf;
2805 while (*p != '\0') {
2806 *p = tolower(*p);
2807 p++;
2808 }
2809
2810 /* skip the NUL */
2811 p++;
2812
2813 memcpy(p, &val, sizeof(uint));
2814 len = (p - buf) + sizeof(uint);
2815
2816 return (dhd_set(dhd, DHD_SET_VAR, &buf[0], len));
2817 }
2818
2819 static int
dhd_var_get(void * dhd,cmd_t * cmd,char ** argv)2820 dhd_var_get(void *dhd, cmd_t *cmd, char **argv)
2821 {
2822 char *varname;
2823 char *p;
2824
2825 UNUSED_PARAMETER(cmd);
2826
2827 if (!*argv) {
2828 printf("get: missing arguments\n");
2829 return BCME_USAGE_ERROR;
2830 }
2831
2832 varname = *argv++;
2833
2834 if (*argv) {
2835 printf("get: error, extra arg \"%s\"\n", *argv);
2836 return BCME_USAGE_ERROR;
2837 }
2838
2839 strcpy(buf, varname);
2840 p = buf;
2841 while (*p != '\0') {
2842 *p = tolower(*p);
2843 p++;
2844 }
2845 return (dhd_get(dhd, DHD_GET_VAR, &buf[0], DHD_IOCTL_MAXLEN));
2846 }
2847
2848 static int
dhd_var_getint(void * dhd,cmd_t * cmd,char ** argv)2849 dhd_var_getint(void *dhd, cmd_t *cmd, char **argv)
2850 {
2851 int err;
2852 int32 val;
2853 if (cmd->get == -1) {
2854 printf("get not defined for %s\n", cmd->name);
2855 return BCME_ERROR;
2856 }
2857
2858 if ((err = dhd_var_get(dhd, cmd, argv)))
2859 return (err);
2860
2861 val = *(int32*)buf;
2862
2863 if (val < 10)
2864 printf("%d\n", val);
2865 else
2866 printf("%d (0x%x)\n", val, val);
2867
2868 return (0);
2869 }
2870
2871 static int
dhd_var_getandprintstr(void * dhd,cmd_t * cmd,char ** argv)2872 dhd_var_getandprintstr(void *dhd, cmd_t *cmd, char **argv)
2873 {
2874 int err;
2875
2876 if ((err = dhd_var_get(dhd, cmd, argv)))
2877 return (err);
2878
2879 printf("%s\n", buf);
2880 return (0);
2881 }
2882
2883
2884 void
dhd_printlasterror(void * dhd)2885 dhd_printlasterror(void *dhd)
2886 {
2887 char *cmd[2] = {"bcmerrorstr"};
2888
2889 if (dhd_var_get(dhd, NULL, cmd) != 0) {
2890 fprintf(stderr, "%s: \nError getting the last error\n", dhdu_av0);
2891 } else {
2892 fprintf(stderr, "%s: %s\n", dhdu_av0, buf);
2893 }
2894 }
2895
2896 static int
dhd_varint(void * dhd,cmd_t * cmd,char * argv[])2897 dhd_varint(void *dhd, cmd_t *cmd, char *argv[])
2898 {
2899 if (argv[1])
2900 return (dhd_var_setint(dhd, cmd, argv));
2901 else
2902 return (dhd_var_getint(dhd, cmd, argv));
2903 }
2904
2905 static int
dhd_var_getbuf(void * dhd,char * iovar,void * param,int param_len,void ** bufptr)2906 dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr)
2907 {
2908 int len;
2909
2910 memset(buf, 0, DHD_IOCTL_MAXLEN);
2911 strcpy(buf, iovar);
2912
2913 /* include the NUL */
2914 len = strlen(iovar) + 1;
2915
2916 if (param_len)
2917 memcpy(&buf[len], param, param_len);
2918
2919 *bufptr = buf;
2920
2921 return dhd_get(dhd, DHD_GET_VAR, &buf[0], DHD_IOCTL_MAXLEN);
2922 }
2923
2924 static int
dhd_var_setbuf(void * dhd,char * iovar,void * param,int param_len)2925 dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len)
2926 {
2927 int len;
2928
2929 memset(buf, 0, DHD_IOCTL_MAXLEN);
2930 strcpy(buf, iovar);
2931
2932 /* include the NUL */
2933 len = strlen(iovar) + 1;
2934
2935 if (param_len)
2936 memcpy(&buf[len], param, param_len);
2937
2938 len += param_len;
2939
2940 return dhd_set(dhd, DHD_SET_VAR, &buf[0], len);
2941 }
2942
2943 static int
dhd_var_void(void * dhd,cmd_t * cmd,char ** argv)2944 dhd_var_void(void *dhd, cmd_t *cmd, char **argv)
2945 {
2946 UNUSED_PARAMETER(argv);
2947
2948 if (cmd->set < 0)
2949 return BCME_ERROR;
2950
2951 return dhd_var_setbuf(dhd, cmd->name, NULL, 0);
2952 }
2953
2954 /*
2955 * format an iovar buffer
2956 */
2957 static uint
dhd_iovar_mkbuf(char * name,char * data,uint datalen,char * buf,uint buflen,int * perr)2958 dhd_iovar_mkbuf(char *name, char *data, uint datalen, char *buf, uint buflen, int *perr)
2959 {
2960 uint len;
2961
2962 len = strlen(name) + 1;
2963
2964 /* check for overflow */
2965 if ((len + datalen) > buflen) {
2966 *perr = BCME_BUFTOOSHORT;
2967 return 0;
2968 }
2969
2970 strcpy(buf, name);
2971
2972 /* append data onto the end of the name string */
2973 if (datalen > 0)
2974 memcpy(&buf[len], data, datalen);
2975
2976 len += datalen;
2977
2978 *perr = 0;
2979 return len;
2980 }
2981
2982 static int
dhd_iovar_getint(void * dhd,char * name,int * var)2983 dhd_iovar_getint(void *dhd, char *name, int *var)
2984 {
2985 char ibuf[DHD_IOCTL_SMLEN];
2986 int error;
2987
2988 dhd_iovar_mkbuf(name, NULL, 0, ibuf, sizeof(ibuf), &error);
2989 if (error)
2990 return error;
2991
2992 if ((error = dhd_get(dhd, DHD_GET_VAR, &ibuf, sizeof(ibuf))) < 0)
2993 return error;
2994
2995 memcpy(var, ibuf, sizeof(int));
2996
2997 return 0;
2998 }
2999
3000 static int
dhd_iovar_setint(void * dhd,char * name,int var)3001 dhd_iovar_setint(void *dhd, char *name, int var)
3002 {
3003 int len;
3004 char ibuf[DHD_IOCTL_SMLEN];
3005 int error;
3006
3007 len = dhd_iovar_mkbuf(name, (char *)&var, sizeof(var), ibuf, sizeof(ibuf), &error);
3008 if (error)
3009 return error;
3010
3011 if ((error = dhd_set(dhd, DHD_SET_VAR, &ibuf, len)) < 0)
3012 return error;
3013
3014 return 0;
3015 }
3016
3017 static int
dhd_varstr(void * dhd,cmd_t * cmd,char ** argv)3018 dhd_varstr(void *dhd, cmd_t *cmd, char **argv)
3019 {
3020 int error;
3021 char *str;
3022
3023 if (!*++argv) {
3024 void *ptr;
3025
3026 if ((error = dhd_var_getbuf(dhd, cmd->name, NULL, 0, &ptr)) < 0)
3027 return (error);
3028
3029 str = (char *)ptr;
3030 printf("%s\n", str);
3031 return (0);
3032 } else {
3033 str = *argv;
3034 /* iovar buffer length includes NUL */
3035 return dhd_var_setbuf(dhd, cmd->name, str, strlen(str) + 1);
3036 }
3037 }
3038
3039
3040 static int
dhd_hostreorder_flows(void * dhd,cmd_t * cmd,char ** argv)3041 dhd_hostreorder_flows(void *dhd, cmd_t *cmd, char **argv)
3042 {
3043 int ret, count, i = 0;
3044 void *ptr;
3045 uint8 *flow_id;
3046
3047
3048 if ((ret = dhd_var_getbuf(dhd, cmd->name, NULL, 0, &ptr)) < 0) {
3049 printf("error getting reorder flows from the host\n");
3050 return ret;
3051 }
3052 flow_id = (uint8 *)ptr;
3053 count = *flow_id;
3054 if (!count)
3055 printf("there are no active flows\n");
3056 else {
3057 printf("flows(%d): \t", count);
3058 while (i++ < count)
3059 printf("%d ", *flow_id++);
3060 printf("\n");
3061 }
3062 return 0;
3063 }
3064
3065
3066
3067 /* These two utility functions are used by dhdu_linux.c
3068 * The code is taken from wlu.c.
3069 */
3070 int
dhd_atoip(const char * a,struct ipv4_addr * n)3071 dhd_atoip(const char *a, struct ipv4_addr *n)
3072 {
3073 char *c;
3074 int i = 0;
3075
3076 for (;;) {
3077 n->addr[i++] = (uint8)strtoul(a, &c, 0);
3078 if (*c++ != '.' || i == IPV4_ADDR_LEN)
3079 break;
3080 a = c;
3081 }
3082 return (i == IPV4_ADDR_LEN);
3083 }
3084
3085 int
dhd_ether_atoe(const char * a,struct ether_addr * n)3086 dhd_ether_atoe(const char *a, struct ether_addr *n)
3087 {
3088 char *c;
3089 int i = 0;
3090
3091 memset(n, 0, ETHER_ADDR_LEN);
3092 for (;;) {
3093 n->octet[i++] = (uint8)strtoul(a, &c, 16);
3094 if (!*c++ || i == ETHER_ADDR_LEN)
3095 break;
3096 a = c;
3097 }
3098 return (i == ETHER_ADDR_LEN);
3099 }
3100