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