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