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
62static cmd_func_t dhd_var_void;
63static cmd_func_t dhd_varint, dhd_varstr;
64static cmd_func_t dhd_var_getandprintstr, dhd_var_getint, dhd_var_get;
65static cmd_func_t dhd_var_setint;
66
67static cmd_func_t dhd_version, dhd_list, dhd_msglevel;
68
69#ifdef SDTEST
70static cmd_func_t dhd_pktgen;
71#endif
72static cmd_func_t dhd_sprom;
73static cmd_func_t dhd_sdreg;
74static cmd_func_t dhd_sd_msglevel, dhd_sd_blocksize, dhd_sd_mode, dhd_sd_reg;
75static cmd_func_t dhd_dma_mode;
76static cmd_func_t dhd_membytes, dhd_download, dhd_dldn,
77	dhd_upload, dhd_coredump, dhd_consoledump, dhd_vars, dhd_idleclock, dhd_idletime;
78static cmd_func_t dhd_logstamp;
79
80static cmd_func_t dhd_hostreorder_flows;
81
82#ifdef PROP_TXSTATUS
83static cmd_func_t dhd_proptxstatusenable;
84static cmd_func_t dhd_proptxstatusmode;
85static cmd_func_t dhd_proptxopt;
86#endif
87static int dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr);
88static int dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len);
89
90static uint dhd_iovar_mkbuf(char *name, char *data, uint datalen,
91                            char *buf, uint buflen, int *perr);
92static int dhd_iovar_getint(void *dhd, char *name, int *var);
93static int dhd_iovar_setint(void *dhd, char *name, int var);
94
95#if defined(BWL_FILESYSTEM_SUPPORT)
96static int file_size(char *fname);
97static int read_vars(char *fname, char *buf, int buf_maxlen);
98#endif
99
100
101/* dword align allocation */
102static union {
103	char bufdata[DHD_IOCTL_MAXLEN];
104	uint32 alignme;
105} bufstruct_dhd;
106static char *buf = (char*) &bufstruct_dhd.bufdata;
107
108/* integer output format, default to signed integer */
109static uint8 int_fmt;
110
111#define DEBUG_INFO_PTRS_END 0xffffffff
112const uint32 debug_info_ptrs[] = {0xf8, 0x878, DEBUG_INFO_PTRS_END};
113
114typedef struct {
115	uint value;
116	char *string;
117} dbg_msg_t;
118
119static int dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg);
120
121/* Actual command table */
122cmd_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
331cmd_t dhd_varcmd = {"var", dhd_varint, -1, -1, "unrecognized name, type -h for help"};
332char *dhdu_av0;
333
334#if defined(BWL_FILESYSTEM_SUPPORT)
335static int
336file_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 */
362int
363dhd_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
415void
416dhd_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 */
425static int
426dhd_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
477void
478dhd_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
499void
500dhd_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
517int
518dhd_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
536void
537dhd_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) */
554void
555dhd_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
590static int
591dhd_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
725exit:
726	return ret;
727}
728#endif /* SDTEST */
729
730static 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
741static int
742dhd_sd_msglevel(void *dhd, cmd_t *cmd, char **argv)
743{
744	return dhd_do_msglevel(dhd, cmd, argv, dhd_sd_msgs);
745}
746
747static int
748dhd_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
791static int
792dhd_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
831static int
832dhd_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
882static int
883dhd_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
942static int
943dhd_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
1106exit:
1107	return ret;
1108}
1109
1110static int
1111dhd_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
1159static int
1160dhd_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
1206static int
1207dhd_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)
1384static int
1385read_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
1448static int
1449dhd_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)
1517static int
1518dhd_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
1549static int
1550dhd_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;
1583failed_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
1622static int
1623dhd_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
1640static int
1641dhd_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
1658static int
1659dhd_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
1678static int
1679dhd_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
1696static int
1697dhd_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
1943exit:
1944	if (fp)
1945		fclose(fp);
1946
1947	return ret;
1948#endif /* BWL_FILESYSTEM_SUPPORT */
1949}
1950
1951static int
1952dhd_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
2066exit:
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
2077static int
2078dhd_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 = 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;
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);
2197exit:
2198	return ret;
2199#endif /* BWL_FILESYSTEM_SUPPORT */
2200}
2201
2202#ifdef BWL_FILESYSTEM_SUPPORT
2203static int
2204dhd_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
2266static int
2267dhd_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);
2419exit:
2420	return ret;
2421#endif /* BWL_FILESYSTEM_SUPPORT */
2422}
2423
2424static int
2425dhd_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
2523exit:
2524	return ret;
2525#endif /* BWL_FILESYSTEM_SUPPORT */
2526}
2527
2528static int
2529dhd_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
2564static int
2565dhd_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
2629static 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
2652static int
2653dhd_msglevel(void *dhd, cmd_t *cmd, char **argv)
2654{
2655	return dhd_do_msglevel(dhd, cmd, argv, dhd_msgs);
2656}
2657
2658static int
2659dhd_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
2706usage:
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
2722static char *
2723ver2str(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
2746static int
2747dhd_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
2769static int
2770dhd_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
2819static int
2820dhd_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
2848static int
2849dhd_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
2871static int
2872dhd_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
2884void
2885dhd_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
2896static int
2897dhd_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
2905static int
2906dhd_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
2924static int
2925dhd_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
2943static int
2944dhd_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 */
2957static uint
2958dhd_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
2982static int
2983dhd_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
3000static int
3001dhd_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
3017static int
3018dhd_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
3040static int
3041dhd_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 */
3070int
3071dhd_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
3085int
3086dhd_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