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