Home | History | Annotate | Download | only in exe
      1 /*
      2  * Common code for dhd utility, hacked from wl utility
      3  *
      4  * Copyright (C) 1999-2010, Broadcom Corporation
      5  *
      6  *      Unless you and Broadcom execute a separate written software license
      7  * agreement governing use of this software, this software is licensed to you
      8  * under the terms of the GNU General Public License version 2 (the "GPL"),
      9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
     10  * following added to such license:
     11  *
     12  *      As a special exception, the copyright holders of this software give you
     13  * permission to link this software with independent modules, and to copy and
     14  * distribute the resulting executable under terms of your choice, provided that
     15  * you also meet, for each linked independent module, the terms and conditions of
     16  * the license of that module.  An independent module is a module which is not
     17  * derived from this software.  The special exception does not apply to any
     18  * modifications of the software.
     19  *
     20  *      Notwithstanding the above, under no circumstances may you combine this
     21  * software in any way with any other Broadcom software provided under a license
     22  * other than the GPL, without Broadcom's express prior written consent.
     23  *
     24  * $Id: dhdu.c,v 1.52.2.10.2.6.2.14 2010/01/19 07:24:15 Exp $
     25  */
     26 
     27 /* For backwards compatibility, the absense of the define 'BWL_NO_FILESYSTEM_SUPPORT'
     28  * implies that a filesystem is supported.
     29  */
     30 #if !defined(BWL_NO_FILESYSTEM_SUPPORT)
     31 #define BWL_FILESYSTEM_SUPPORT
     32 #endif
     33 
     34 
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <string.h>
     38 #include <ctype.h>
     39 #include <assert.h>
     40 
     41 #include <typedefs.h>
     42 #include <epivers.h>
     43 #include <proto/ethernet.h>
     44 #include <dhdioctl.h>
     45 #include <sdiovar.h>
     46 #include <bcmutils.h>
     47 #include <bcmendian.h>
     48 #include "dhdu.h"
     49 
     50 
     51 #include "miniopt.h"
     52 
     53 #include <errno.h>
     54 
     55 #include <trxhdr.h>
     56 
     57 #define stricmp strcasecmp
     58 #define strnicmp strncasecmp
     59 
     60 
     61 static cmd_func_t dhd_var_void;
     62 static cmd_func_t dhd_varint, dhd_varstr;
     63 static cmd_func_t dhd_var_getandprintstr, dhd_var_getint, dhd_var_get;
     64 static cmd_func_t dhd_var_setint;
     65 
     66 static cmd_func_t dhd_version, dhd_list, dhd_msglevel;
     67 
     68 #ifdef SDTEST
     69 static cmd_func_t dhd_pktgen;
     70 #endif
     71 static cmd_func_t dhd_sprom;
     72 static cmd_func_t dhd_sdreg;
     73 static cmd_func_t dhd_sd_msglevel, dhd_sd_blocksize, dhd_sd_mode, dhd_sd_reg;
     74 static cmd_func_t dhd_dma_mode;
     75 static cmd_func_t dhd_membytes, dhd_download, dhd_upload, dhd_vars, dhd_idleclock, dhd_idletime;
     76 static cmd_func_t dhd_logstamp;
     77 
     78 static int dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr);
     79 static int dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len);
     80 
     81 static uint dhd_iovar_mkbuf(char *name, char *data, uint datalen,
     82                             char *buf, uint buflen, int *perr);
     83 static int dhd_iovar_getint(void *dhd, char *name, int *var);
     84 static int dhd_iovar_setint(void *dhd, char *name, int var);
     85 
     86 #if defined(BWL_FILESYSTEM_SUPPORT)
     87 static int file_size(char *fname);
     88 static int read_vars(char *fname, char *buf, int buf_maxlen);
     89 #endif
     90 
     91 
     92 
     93 /* dword align allocation */
     94 static union {
     95 	char bufdata[DHD_IOCTL_MAXLEN];
     96 	uint32 alignme;
     97 } bufstruct_dhd;
     98 static char *buf = (char*) &bufstruct_dhd.bufdata;
     99 
    100 /* integer output format, default to signed integer */
    101 static uint8 int_fmt;
    102 
    103 typedef struct {
    104 	uint value;
    105 	char *string;
    106 } dbg_msg_t;
    107 
    108 static int dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg);
    109 
    110 /* Actual command table */
    111 cmd_t dhd_cmds[] = {
    112 	{ "cmds", dhd_list, -1, -1,
    113 	"generate a short list of available commands"},
    114 	{ "version", dhd_version, DHD_GET_VAR, -1,
    115 	"get version information" },
    116 	{ "msglevel", dhd_msglevel, DHD_GET_VAR, DHD_SET_VAR,
    117 	"get/set message bits" },
    118 	{ "wlmsglevel", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    119 	"get/set wl message(in dhd) bits" },
    120 	{ "bcmerrorstr", dhd_var_getandprintstr, DHD_GET_VAR, -1,
    121 	"errorstring"},
    122 	{ "wdtick", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    123 	"watchdog tick time (ms units)"},
    124 	{ "intr", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    125 	"use interrupts on the bus"},
    126 	{ "pollrate", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    127 	"number of ticks between bus polls (0 means no polling)"},
    128 	{ "idletime", dhd_idletime, DHD_GET_VAR, DHD_SET_VAR,
    129 	"number of ticks for activity timeout (-1: immediate, 0: never)"},
    130 	{ "idleclock", dhd_idleclock, DHD_GET_VAR, DHD_SET_VAR,
    131 	"idleclock active | stopped | <N>\n"
    132 	"\tactive (0)   - do not request any change to the SD clock\n"
    133 	"\tstopped (-1) - request SD clock be stopped on activity timeout\n"
    134 	"\t<N> (other)  - an sd_divisor value to request on activity timeout\n"},
    135 	{ "sd1idle", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    136 	"change mode to SD1 when turning off clock at idle"},
    137 	{ "forceeven", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    138 	"force SD tx/rx buffers to be even"},
    139 	{ "readahead", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    140 	"enable readahead feature (look for next frame len in headers)"},
    141 	{ "sdrxchain", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    142 	"enable packet chains to SDIO stack for glom receive"},
    143 	{ "alignctl", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    144 	"align control frames"},
    145 	{ "sdalign", dhd_varint, DHD_GET_VAR, -1,
    146 	"display the (compiled in) alignment target for sd requests"},
    147 	{ "txbound", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    148 	"get/set maximum number of tx frames per scheduling"},
    149 	{ "rxbound", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    150 	"get/set maximum number of rx frames per scheduling"},
    151 	{ "txminmax", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    152 	"get/set maximum number of tx frames per scheduling while rx frames outstanding"},
    153 	{ "dump", dhd_varstr, DHD_GET_VAR, -1,
    154 	"dump information"},
    155 	{ "clearcounts", dhd_var_void, -1, DHD_SET_VAR,
    156 	"reset the bus stats shown in the dhd dump"},
    157 	{ "logdump", dhd_varstr, DHD_GET_VAR, -1,
    158 	"dump the timestamp logging buffer"},
    159 	{ "logcal", dhd_varint, -1, DHD_SET_VAR,
    160 	"logcal <n>  -- log around an osl_delay of <n> usecs"},
    161 	{ "logstamp", dhd_logstamp, -1, DHD_SET_VAR,
    162 	"logstamp [<n1>] [<n2>]  -- add a message to the log"},
    163 	{ "memsize", dhd_varint, DHD_GET_VAR, -1,
    164 	"display size of onchip SOCRAM"},
    165 	{ "membytes", dhd_membytes, DHD_GET_VAR, DHD_SET_VAR,
    166 	"membytes [-h | -r | -i] <address> <length> [<bytes>]\n"
    167 	"\tread or write data in the dongle ram\n"
    168 	"\t-h   <bytes> is a sequence of hex digits, else a char string\n"
    169 	"\t-r   output as a raw write rather than hexdump display\n"},
    170 	{ "download", dhd_download, -1, DHD_SET_VAR,
    171 	"download [-a <address>] [--noreset] [--norun] <binfile> [<varsfile>]\n"
    172 	"\tdownload file to specified dongle ram address and start CPU\n"
    173 	"\toptional vars file will replace vars parsed from the CIS\n"
    174 	"\t--noreset    do not reset SOCRAM core before download\n"
    175 	"\t--norun      do not start dongle CPU after download\n"
    176 	"\tdefault <address> is 0\n"},
    177 	{ "vars", dhd_vars, DHD_GET_VAR, DHD_SET_VAR,
    178 	"vars [<file>]\n"
    179 	"\toverride SPROM vars with <file> (before download)\n"},
    180 	{ "upload", dhd_upload, -1, -1,
    181 	"upload [-a <address> ] <file> [<size>]\n"
    182 	"\tupload dongle RAM content into a file\n"
    183 	"\tdefault <address> is 0, default <size> is RAM size"},
    184 	{ "srdump", dhd_sprom, DHD_GET_VAR, -1,
    185 	"display SPROM content" },
    186 	{ "srwrite", dhd_sprom, -1, DHD_SET_VAR,
    187 	"write data or file content to SPROM\n"
    188 	"\tsrwrite <word-offset> <word-value> ...\n"
    189 	"\tsrwrite [-c] <srom-file-path>\n"
    190 	"\t  -c means write regardless of crc"},
    191 	{ "sleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    192 	"enter/exit simulated host sleep (bus powerdown w/OOB wakeup)"},
    193 #ifdef SDTEST
    194 	{ "extloop", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    195 	"external loopback: convert all tx data to echo test frames"},
    196 	{ "pktgen", dhd_pktgen, DHD_GET_VAR, DHD_SET_VAR,
    197 	"configure/report pktgen status (SDIO)\n"
    198 	"\t-f N     frequency: send/recv a burst every N ticks\n"
    199 	"\t-c N     count: send/recv N packets each burst\n"
    200 	"\t-t N     total: stop after a total of N packets\n"
    201 	"\t-p N     print: display counts on console every N bursts\n"
    202 	"\t-m N     min: set minimum length of packet data\n"
    203 	"\t-M N     Max: set maximum length of packet data\n"
    204 	"\t-l N     len: set fixed length of packet data\n"
    205 	"\t-s N     stop after N tx failures\n"
    206 	"\t-d dir   test direction/type:\n"
    207 	"\t            send -- send packets discarded by dongle\n"
    208 	"\t            echo -- send packets to be echoed by dongle\n"
    209 	"\t            burst -- request bursts (of size <-c>) from dongle\n"
    210 	"\t              one every <-f> ticks, until <-t> total requests\n"
    211 	"\t            recv -- request dongle enter continuous send mode,\n"
    212 	"\t              read up to <-c> pkts every <-f> ticks until <-t>\n"
    213 	"\t              total reads\n"},
    214 #endif /* SDTEST */
    215 	{ "sdreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR,
    216 	"g/set sdpcmdev core register (f1) across SDIO (CMD53)"},
    217 	{ "sbreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR,
    218 	"g/set any backplane core register (f1) across SDIO (CMD53)"},
    219 	{ "sd_cis", dhd_var_getandprintstr, DHD_GET_VAR, -1,
    220 	"dump sdio CIS"},
    221 	{ "sd_devreg", dhd_sd_reg, DHD_GET_VAR, DHD_SET_VAR,
    222 	"g/set device register across SDIO bus (CMD52)"},
    223 	{ "sd_hostreg", dhd_sd_reg, DHD_GET_VAR, DHD_SET_VAR,
    224 	"g/set local controller register"},
    225 	{ "sd_blocksize", dhd_sd_blocksize, DHD_GET_VAR, DHD_SET_VAR,
    226 	"g/set block size for a function"},
    227 	{ "sd_blockmode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    228 	"g/set blockmode"},
    229 	{ "sd_ints", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    230 	"g/set client ints"},
    231 	{ "sd_dma", dhd_dma_mode, DHD_GET_VAR, DHD_SET_VAR,
    232 	"g/set dma usage: [PIO | SDMA | ADMA1 | ADMA2]"},
    233 	{ "sd_yieldcpu", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    234 	"allow blocking (yield of CPU) on data xfer"},
    235 	{ "sd_minyield", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    236 	"minimum xfer size to allow CPU yield"},
    237 	{ "sd_forcerb", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    238 	"force readback when changing local interrupt settings"},
    239 	{ "sd_numints", dhd_varint, DHD_GET_VAR, -1,
    240 	"number of device interrupts"},
    241 	{ "sd_numlocalints", dhd_varint, DHD_GET_VAR, -1,
    242 	"number of non-device interrupts"},
    243 	{ "sd_divisor", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    244 	"set the divisor for SDIO clock generation"},
    245 	{ "sd_power", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    246 	"set the SD Card slot power"},
    247 	{ "sd_clock", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    248 	"turn on/off the SD Clock"},
    249 	{ "sd_crc", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    250 	"turn on/off CRC checking in SPI mode"},
    251 	{ "sd_mode", dhd_sd_mode, DHD_GET_VAR, DHD_SET_VAR,
    252 	"g/set SDIO bus mode (spi, sd1, sd4)"},
    253 	{ "sd_highspeed", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    254 	"set the high-speed clocking mode"},
    255 	{ "sd_msglevel", dhd_sd_msglevel, DHD_GET_VAR, DHD_SET_VAR,
    256 	"g/set debug message level"},
    257 	{ "sd_hciregs", dhd_varstr, DHD_GET_VAR, -1,
    258 	"display host-controller interrupt registers"},
    259 	{ "sdiod_drive", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    260 	"SDIO Device drive strength in milliamps. (0=tri-state, 1-12mA)"},
    261 	{ "devreset", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    262 	"Move device into or out of reset state (1/reset, or 0/operational)"},
    263 	{ "connstatus", dhd_varstr, DHD_GET_VAR, -1,
    264 	"get status of last connection attempt" },
    265 	{ "ioctl_timeout", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,
    266 	"IOCTL response timeout (milliseconds)."},
    267 	{ NULL, NULL, 0, 0, NULL }
    268 };
    269 
    270 cmd_t dhd_varcmd = {"var", dhd_varint, -1, -1, "unrecognized name, type -h for help"};
    271 char *dhdu_av0;
    272 
    273 #if defined(BWL_FILESYSTEM_SUPPORT)
    274 static int
    275 file_size(char *fname)
    276 {
    277 	FILE *fp;
    278 	long size = -1;
    279 
    280 	/* Can't use stat() because of Win CE */
    281 
    282 	if ((fp = fopen(fname, "rb")) == NULL ||
    283 	    fseek(fp, 0, SEEK_END) < 0 ||
    284 	    (size = ftell(fp)) < 0)
    285 		fprintf(stderr, "Could not determine size of %s: %s\n",
    286 		        fname, strerror(errno));
    287 
    288 	if (fp != NULL)
    289 		fclose(fp);
    290 
    291 	return (int)size;
    292 }
    293 #endif   /* BWL_FILESYSTEM_SUPPORT */
    294 
    295 
    296 /* parse/validate the command line arguments */
    297 /*
    298 * pargv is updated upon return if the first argument is an option.
    299  * It remains intact otherwise.
    300  */
    301 int
    302 dhd_option(char ***pargv, char **pifname, int *phelp)
    303 {
    304 	char *ifname = NULL;
    305 	int help = FALSE;
    306 	int status = CMD_OPT;
    307 	char **argv = *pargv;
    308 
    309 	int_fmt = INT_FMT_DEC;
    310 
    311 	while (*argv) {
    312 		/* select different adapter */
    313 		if (!strcmp(*argv, "-a") || !strcmp(*argv, "-i")) {
    314 			char *opt = *argv++;
    315 			ifname = *argv;
    316 			if (!ifname) {
    317 				fprintf(stderr,
    318 					"error: expected interface name after option %s\n", opt);
    319 				status = CMD_ERR;
    320 				break;
    321 			}
    322 		}
    323 
    324 		/* integer output format */
    325 		else if (!strcmp(*argv, "-d"))
    326 			int_fmt = INT_FMT_DEC;
    327 		else if (!strcmp(*argv, "-u"))
    328 			int_fmt = INT_FMT_UINT;
    329 		else if (!strcmp(*argv, "-x"))
    330 			int_fmt = INT_FMT_HEX;
    331 
    332 		/* command usage */
    333 		else if (!strcmp(*argv, "-h"))
    334 			help = TRUE;
    335 
    336 		/* done with generic options */
    337 		else {
    338 			status = CMD_DHD;
    339 			break;
    340 		}
    341 
    342 		/* consume the argument */
    343 		argv ++;
    344 		break;
    345 	}
    346 
    347 	*phelp = help;
    348 	*pifname = ifname;
    349 	*pargv = argv;
    350 
    351 	return status;
    352 }
    353 
    354 void
    355 dhd_cmd_usage(cmd_t *cmd)
    356 {
    357 	if (strlen(cmd->name) >= 8)
    358 		fprintf(stderr, "%s\n\t%s\n\n", cmd->name, cmd->help);
    359 	else
    360 		fprintf(stderr, "%s\t%s\n\n", cmd->name, cmd->help);
    361 }
    362 
    363 /* Dump out short list of commands */
    364 static int
    365 dhd_list(void *dhd, cmd_t *garb, char **argv)
    366 {
    367 	cmd_t *cmd;
    368 	int nrows, i, len;
    369 	char *buf;
    370 	int letter, col, row, pad;
    371 
    372 	UNUSED_PARAMETER(dhd);
    373 	UNUSED_PARAMETER(garb);
    374 	UNUSED_PARAMETER(argv);
    375 
    376 	for (cmd = dhd_cmds, nrows = 0; cmd->name; cmd++)
    377 		    nrows++;
    378 
    379 	nrows /= 4;
    380 	nrows++;
    381 
    382 	len = nrows * 80 + 2;
    383 	buf = malloc(len);
    384 	if (buf == NULL) {
    385 		fprintf(stderr, "Failed to allocate buffer of %d bytes\n", len);
    386 		return COMMAND_ERROR;
    387 	}
    388 	for (i = 0; i < len; i++)
    389 		*(buf+i) = 0;
    390 
    391 	row = col = 0;
    392 	for (letter = 'a'; letter < 'z'; letter++) {
    393 		for (cmd = dhd_cmds; cmd->name; cmd++) {
    394 			if (cmd->name[0] == letter || cmd->name[0] == letter - 0x20) {
    395 				strcat(buf+row*80, cmd->name);
    396 				pad = 18 * (col + 1) - strlen(buf+row*80);
    397 				if (pad < 1)
    398 					pad = 1;
    399 				for (; pad; pad--)
    400 					strcat(buf+row*80, " ");
    401 				row++;
    402 				if (row == nrows) {
    403 					col++; row = 0;
    404 				}
    405 			}
    406 		}
    407 	}
    408 	for (row = 0; row < nrows; row++)
    409 		printf("%s\n", buf+row*80);
    410 
    411 	printf("\n");
    412 	free(buf);
    413 	return (0);
    414 }
    415 
    416 void
    417 dhd_cmds_usage(cmd_t *port_cmds)
    418 {
    419 	cmd_t *port_cmd;
    420 	cmd_t *cmd;
    421 
    422 	/* print usage of port commands */
    423 	for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)
    424 		/* Check for wc_cmd */
    425 		dhd_cmd_usage(port_cmd);
    426 
    427 	/* print usage of common commands without port counterparts */
    428 	for (cmd = dhd_cmds; cmd->name; cmd++) {
    429 		/* search if port counterpart exists */
    430 		for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)
    431 			if (!strcmp(port_cmd->name, cmd->name))
    432 				break;
    433 		if (!port_cmd || !port_cmd->name)
    434 			dhd_cmd_usage(cmd);
    435 	}
    436 }
    437 
    438 void
    439 dhd_usage(cmd_t *port_cmds)
    440 {
    441 	fprintf(stderr,
    442 	        "Usage: %s [-a|i <adapter>] [-h] [-d|u|x] <command> [arguments]\n",
    443 		dhdu_av0);
    444 
    445 	fprintf(stderr, "\n");
    446 	fprintf(stderr, "  -h		this message\n");
    447 	fprintf(stderr, "  -a, -i	adapter name or number\n");
    448 	fprintf(stderr, "  -d		display values as signed integer\n");
    449 	fprintf(stderr, "  -u		display values as unsigned integer\n");
    450 	fprintf(stderr, "  -x		display values as hexdecimal\n");
    451 	fprintf(stderr, "\n");
    452 
    453 	dhd_cmds_usage(port_cmds);
    454 }
    455 
    456 int
    457 dhd_check(void *dhd)
    458 {
    459 	int ret;
    460 	int val;
    461 
    462 	if ((ret = dhd_get(dhd, DHD_GET_MAGIC, &val, sizeof(int)) < 0))
    463 		return ret;
    464 	if (val != DHD_IOCTL_MAGIC)
    465 		return -1;
    466 	if ((ret = dhd_get(dhd, DHD_GET_VERSION, &val, sizeof(int)) < 0))
    467 		return ret;
    468 	if (val > DHD_IOCTL_VERSION) {
    469 		fprintf(stderr, "Version mismatch, please upgrade\n");
    470 		return -1;
    471 	}
    472 	return 0;
    473 }
    474 
    475 void
    476 dhd_printint(int val)
    477 {
    478 	switch (int_fmt) {
    479 	case INT_FMT_UINT:
    480 		printf("%u\n", val);
    481 		break;
    482 	case INT_FMT_HEX:
    483 		printf("0x%x\n", val);
    484 		break;
    485 	case INT_FMT_DEC:
    486 	default:
    487 		printf("%d\n", val);
    488 		break;
    489 	}
    490 }
    491 
    492 /* pretty hex print a contiguous buffer (tweaked from wlu) */
    493 void
    494 dhd_hexdump(uchar *buf, uint nbytes, uint saddr)
    495 {
    496 	char line[256];
    497 	char* p;
    498 	uint i;
    499 
    500 	if (nbytes == 0) {
    501 		printf("\n");
    502 		return;
    503 	}
    504 
    505 	p = line;
    506 	for (i = 0; i < nbytes; i++) {
    507 		if (i % 16 == 0) {
    508 			p += sprintf(p, "%08x: ", saddr + i);	/* line prefix */
    509 		}
    510 		p += sprintf(p, "%02x ", buf[i]);
    511 		if (i % 16 == 15) {
    512 			uint j;
    513 			p += sprintf(p, "  ");
    514 			for (j = i-15; j <= i; j++)
    515 				p += sprintf(p, "%c",
    516 				             ((buf[j] >= 0x20 && buf[j] <= 0x7f) ? buf[j] : '.'));
    517 			printf("%s\n", line);		/* flush line */
    518 			p = line;
    519 		}
    520 	}
    521 
    522 	/* flush last partial line */
    523 	if (p != line)
    524 		printf("%s\n", line);
    525 }
    526 
    527 
    528 #ifdef SDTEST
    529 static int
    530 dhd_pktgen(void *dhd, cmd_t *cmd, char **argv)
    531 {
    532 	int ret = 0;
    533 	void *ptr = NULL;
    534 	dhd_pktgen_t pktgen;
    535 	char *str;
    536 
    537 	UNUSED_PARAMETER(dhd);
    538 	UNUSED_PARAMETER(cmd);
    539 
    540 	/* Get current settings */
    541 	if ((ret = dhd_var_getbuf(dhd, "pktgen", NULL, 0, &ptr)) != 0)
    542 		return ret;
    543 	memcpy(&pktgen, ptr, sizeof(pktgen));
    544 
    545 	if (pktgen.version != DHD_PKTGEN_VERSION) {
    546 		fprintf(stderr, "pktgen version mismatch (module %d app %d)\n",
    547 		        pktgen.version, DHD_PKTGEN_VERSION);
    548 		return COMMAND_ERROR;
    549 	}
    550 
    551 	/* Presence of args implies a set, else a get */
    552 	if (*++argv) {
    553 		miniopt_t opts;
    554 		int opt_err;
    555 
    556 		/* Initialize option parser */
    557 		miniopt_init(&opts, "pktgen", "", FALSE);
    558 
    559 		while ((opt_err = miniopt(&opts, argv)) != -1) {
    560 			if (opt_err == 1) {
    561 				fprintf(stderr, "pktgen options error\n");
    562 				ret = -1;
    563 				goto exit;
    564 			}
    565 			argv += opts.consumed;
    566 
    567 			if (!opts.good_int && opts.opt != 'd') {
    568 				fprintf(stderr, "invalid integer %s\n", opts.valstr);
    569 				ret = -1;
    570 				goto exit;
    571 			}
    572 
    573 			switch (opts.opt) {
    574 			case 'f':
    575 				pktgen.freq = opts.uval;
    576 				break;
    577 			case 'c':
    578 				pktgen.count = opts.uval;
    579 				break;
    580 			case 'p':
    581 				pktgen.print = opts.uval;
    582 				break;
    583 			case 't':
    584 				pktgen.total = opts.uval;
    585 				break;
    586 			case 's':
    587 				pktgen.stop = opts.uval;
    588 				break;
    589 			case 'm':
    590 				pktgen.minlen = opts.uval;
    591 				break;
    592 			case 'M':
    593 				pktgen.maxlen = opts.uval;
    594 				break;
    595 			case 'l': case 'L':
    596 				pktgen.minlen = pktgen.maxlen = opts.uval;
    597 				break;
    598 			case 'd':
    599 				if (!strcmp(opts.valstr, "send"))
    600 					pktgen.mode = DHD_PKTGEN_SEND;
    601 				else if (!strcmp(opts.valstr, "echo"))
    602 					pktgen.mode = DHD_PKTGEN_ECHO;
    603 				else if (!strcmp(opts.valstr, "burst"))
    604 					pktgen.mode = DHD_PKTGEN_RXBURST;
    605 				else if (!strcmp(opts.valstr, "recv"))
    606 					pktgen.mode = DHD_PKTGEN_RECV;
    607 				else {
    608 					fprintf(stderr, "unrecognized dir mode %s\n",
    609 					        opts.valstr);
    610 					return USAGE_ERROR;
    611 				}
    612 				break;
    613 
    614 			default:
    615 				fprintf(stderr, "option parsing error (key %s valstr %s)\n",
    616 				        opts.key, opts.valstr);
    617 				ret = USAGE_ERROR;
    618 				goto exit;
    619 			}
    620 		}
    621 
    622 		if (pktgen.maxlen < pktgen.minlen) {
    623 			fprintf(stderr, "min/max error (%d/%d)\n", pktgen.minlen, pktgen.maxlen);
    624 			ret = -1;
    625 			goto exit;
    626 		}
    627 
    628 		/* Set the new values */
    629 		ret = dhd_var_setbuf(dhd, "pktgen", &pktgen, sizeof(pktgen));
    630 	} else {
    631 		printf("Counts: %d send attempts, %d received, %d tx failures\n",
    632 		       pktgen.numsent, pktgen.numrcvd, pktgen.numfail);
    633 	}
    634 
    635 	/* Show configuration in either case */
    636 	switch (pktgen.mode) {
    637 	case DHD_PKTGEN_ECHO: str = "echo"; break;
    638 	case DHD_PKTGEN_SEND: str = "send"; break;
    639 	case DHD_PKTGEN_RECV: str = "recv"; break;
    640 	case DHD_PKTGEN_RXBURST: str = "burst"; break;
    641 	default: str = "UNKNOWN"; break;
    642 	}
    643 
    644 	printf("Config: mode %s %d pkts (len %d-%d) each %d ticks\n",
    645 	       str, pktgen.count, pktgen.minlen, pktgen.maxlen, pktgen.freq);
    646 
    647 	/* Second config line for optional items */
    648 	str = "        ";
    649 	if (pktgen.total) {
    650 		printf("%slimit %d", str, pktgen.total);
    651 		str = ", ";
    652 	}
    653 	if (pktgen.print) {
    654 		printf("%sprint every %d ticks", str, (pktgen.freq * pktgen.print));
    655 		str = ", ";
    656 	}
    657 	if (pktgen.stop) {
    658 		printf("%sstop after %d tx failures", str, pktgen.stop);
    659 		str = ", ";
    660 	}
    661 	if (str[0] == ',')
    662 		printf("\n");
    663 
    664 exit:
    665 	return ret;
    666 }
    667 #endif /* SDTEST */
    668 
    669 static dbg_msg_t dhd_sd_msgs[] = {
    670 	{SDH_ERROR_VAL,	"error"},
    671 	{SDH_TRACE_VAL,	"trace"},
    672 	{SDH_INFO_VAL,	"info"},
    673 	{SDH_DATA_VAL,	"data"},
    674 	{SDH_CTRL_VAL,	"control"},
    675 	{SDH_LOG_VAL,	"log"},
    676 	{SDH_DMA_VAL,	"dma"},
    677 	{0,		NULL}
    678 };
    679 
    680 static int
    681 dhd_sd_msglevel(void *dhd, cmd_t *cmd, char **argv)
    682 {
    683 	return dhd_do_msglevel(dhd, cmd, argv, dhd_sd_msgs);
    684 }
    685 
    686 static int
    687 dhd_sd_blocksize(void *dhd, cmd_t *cmd, char **argv)
    688 {
    689 	int ret;
    690 	int argc;
    691 	char *endptr = NULL;
    692 	void *ptr = NULL;
    693 	int func, size;
    694 
    695 	/* arg count */
    696 	for (argc = 0; argv[argc]; argc++);
    697 	argc--;
    698 
    699 	if (argc < 1 || argc > 2) {
    700 		printf("required args: function [size] (size 0 means max)\n");
    701 		return USAGE_ERROR;
    702 	}
    703 
    704 	func = strtol(argv[1], &endptr, 0);
    705 	if (*endptr != '\0') {
    706 		printf("Invaild function: %s\n", argv[1]);
    707 		return USAGE_ERROR;
    708 	}
    709 
    710 	if (argc > 1) {
    711 		size = strtol(argv[2], &endptr, 0);
    712 		if (*endptr != '\0') {
    713 			printf("Invalid size: %s\n", argv[1]);
    714 			return USAGE_ERROR;
    715 		}
    716 	}
    717 
    718 	if (argc == 1) {
    719 		if ((ret = dhd_var_getbuf(dhd, cmd->name, &func, sizeof(func), &ptr)) >= 0)
    720 			printf("Function %d block size: %d\n", func, *(int*)ptr);
    721 	} else {
    722 		printf("Setting function %d block size to %d\n", func, size);
    723 		size &= 0x0000ffff; size |= (func << 16);
    724 		ret = dhd_var_setbuf(dhd, cmd->name, &size, sizeof(size));
    725 	}
    726 
    727 	return (ret);
    728 }
    729 
    730 static int
    731 dhd_sd_mode(void *wl, cmd_t *cmd, char **argv)
    732 {
    733 	int ret;
    734 	int argc;
    735 	int sdmode;
    736 
    737 	/* arg count */
    738 	for (argc = 0; argv[argc]; argc++);
    739 	argc--;
    740 
    741 	if (argv[1]) {
    742 		if (!strcmp(argv[1], "spi")) {
    743 			strcpy(argv[1], "0");
    744 		} else if (!strcmp(argv[1], "sd1")) {
    745 			strcpy(argv[1], "1");
    746 		} else if (!strcmp(argv[1], "sd4")) {
    747 			strcpy(argv[1], "2");
    748 		} else {
    749 			return USAGE_ERROR;
    750 		}
    751 
    752 		ret = dhd_var_setint(wl, cmd, argv);
    753 
    754 	} else {
    755 		if ((ret = dhd_var_get(wl, cmd, argv))) {
    756 			return (ret);
    757 		} else {
    758 			sdmode = *(int32*)buf;
    759 
    760 			printf("SD Mode is: %s\n",
    761 			       sdmode == 0 ? "SPI"
    762 			       : sdmode == 1 ? "SD1"
    763 				   : sdmode == 2 ? "SD4" : "Unknown");
    764 		}
    765 	}
    766 
    767 	return (ret);
    768 }
    769 
    770 static int
    771 dhd_dma_mode(void *wl, cmd_t *cmd, char **argv)
    772 {
    773 	int ret;
    774 	int argc;
    775 	int dmamode;
    776 
    777 	/* arg count */
    778 	for (argc = 0; argv[argc]; argc++);
    779 	argc--;
    780 
    781 	if (argv[1]) {
    782 		if (!stricmp(argv[1], "pio")) {
    783 			strcpy(argv[1], "0");
    784 		} else if (!strcmp(argv[1], "0")) {
    785 		} else if (!stricmp(argv[1], "dma")) {
    786 			strcpy(argv[1], "1");
    787 		} else if (!stricmp(argv[1], "sdma")) {
    788 			strcpy(argv[1], "1");
    789 		} else if (!strcmp(argv[1], "1")) {
    790 		} else if (!stricmp(argv[1], "adma1")) {
    791 			strcpy(argv[1], "2");
    792 		} else if (!stricmp(argv[1], "adma")) {
    793 			strcpy(argv[1], "3");
    794 		} else if (!stricmp(argv[1], "adma2")) {
    795 			strcpy(argv[1], "3");
    796 		} else {
    797 			return USAGE_ERROR;
    798 		}
    799 
    800 		ret = dhd_var_setint(wl, cmd, argv);
    801 
    802 	} else {
    803 		if ((ret = dhd_var_get(wl, cmd, argv))) {
    804 			return (ret);
    805 		} else {
    806 			dmamode = *(int32*)buf;
    807 
    808 			printf("DMA Mode is: %s\n",
    809 			       dmamode == 0 ? "PIO"
    810 			       : dmamode == 1 ? "SDMA"
    811 			       : dmamode == 2 ? "ADMA1"
    812 			       : dmamode == 3 ? "ADMA2"
    813 			       : "Unknown");
    814 		}
    815 	}
    816 
    817 	return (ret);
    818 }
    819 
    820 
    821 static int
    822 dhd_sdreg(void *dhd, cmd_t *cmd, char **argv)
    823 {
    824 	int ret;
    825 	sdreg_t sdreg;
    826 	uint argc;
    827 	char *ptr = NULL;
    828 
    829 	UNUSED_PARAMETER(cmd);
    830 
    831 	bzero(&sdreg, sizeof(sdreg));
    832 
    833 	/* arg count */
    834 	for (argc = 0; argv[argc]; argc++);
    835 	argc--;
    836 
    837 	/* required args: offset (will default size) */
    838 	if (argc < 1) {
    839 		printf("required args: offset[/size] [value]\n");
    840 		return USAGE_ERROR;
    841 	}
    842 
    843 	sdreg.offset = strtoul(argv[1], &ptr, 0);
    844 	if (*ptr && *ptr != '/') {
    845 		printf("Bad arg: %s\n", argv[1]);
    846 		return USAGE_ERROR;
    847 	}
    848 
    849 	/* read optional /size */
    850 	if (*ptr == '/') {
    851 		sdreg.func = strtol((ptr+1), &ptr, 0);
    852 		if (*ptr || ((sdreg.func != 2) && sdreg.func != 4)) {
    853 			printf("Bad size option?\n");
    854 			return USAGE_ERROR;
    855 		}
    856 	}
    857 	else {
    858 		sdreg.func = 4;
    859 		printf("Defaulting to register size 4\n");
    860 	}
    861 
    862 	if (argc > 1) {
    863 		sdreg.value = strtoul(argv[2], &ptr, 0);
    864 		if (*ptr) {
    865 			printf("Bad value: %s\n", argv[2]);
    866 			return USAGE_ERROR;
    867 		}
    868 	}
    869 
    870 	if (argc <= 1) {
    871 		ret = dhd_var_getbuf(dhd, argv[0], &sdreg, sizeof(sdreg), (void**)&ptr);
    872 		if (ret >= 0)
    873 			printf("0x%0*x\n", (2 * sdreg.func), *(int *)ptr);
    874 	} else {
    875 		ret = dhd_var_setbuf(dhd, argv[0], &sdreg, sizeof(sdreg));
    876 	}
    877 
    878 	return (ret);
    879 }
    880 
    881 static int
    882 dhd_membytes(void *dhd, cmd_t *cmd, char **argv)
    883 {
    884 	int ret = -1;
    885 	uint argc;
    886 	char *ptr;
    887 	int params[2];
    888 	uint addr;
    889 	uint len;
    890 	int align;
    891 
    892 	int rawout, hexin;
    893 
    894 	miniopt_t opts;
    895 	int opt_err;
    896 
    897 	/* Parse command-line options */
    898 	miniopt_init(&opts, "membytes", "rh", FALSE);
    899 
    900 	rawout = hexin = 0;
    901 
    902 	argv++;
    903 	while ((opt_err = miniopt(&opts, argv)) != -1) {
    904 		if (opt_err == 1) {
    905 			fprintf(stderr, "membytes options error\n");
    906 			ret = -1;
    907 			goto exit;
    908 		}
    909 
    910 		if (opts.positional)
    911 			break;
    912 
    913 		argv += opts.consumed;
    914 
    915 		if (opts.opt == 'h') {
    916 			hexin = 1;
    917 		} else if (opts.opt == 'r') {
    918 			rawout = 1;
    919 		} else {
    920 			fprintf(stderr, "membytes command error\n");
    921 			ret = -1;
    922 			goto exit;
    923 		}
    924 	}
    925 
    926 	/* arg count */
    927 	for (argc = 0; argv[argc]; argc++);
    928 
    929 	/* required args: address size [<bytes>]] */
    930 	if (argc < 2) {
    931 		fprintf(stderr, "required args: address size [<bytes>]\n");
    932 		return USAGE_ERROR;
    933 	}
    934 	if (argc < 3 && hexin) {
    935 		fprintf(stderr, "missing <bytes> arg implies by -h\n");
    936 		return USAGE_ERROR;
    937 	}
    938 	if ((argc > 2) && (rawout)) {
    939 		fprintf(stderr, "can't have input <bytes> arg with -r or -i\n");
    940 		return USAGE_ERROR;
    941 	}
    942 
    943 	/* read address */
    944 	addr = strtoul(argv[0], &ptr, 0);
    945 	if (*ptr) {
    946 		fprintf(stderr, "Bad arg: %s\n", argv[0]);
    947 		return USAGE_ERROR;
    948 	}
    949 
    950 	/* read size */
    951 	len = strtoul(argv[1], &ptr, 0);
    952 	if (*ptr) {
    953 		fprintf(stderr, "Bad value: %s\n", argv[1]);
    954 		return USAGE_ERROR;
    955 	}
    956 
    957 	align = addr & 0x03;
    958 	if (align && argc > 2) {
    959 		fprintf(stderr, "Can only write starting at long-aligned addresses.\n");
    960 		return USAGE_ERROR;
    961 	}
    962 
    963 	/* get can just use utility function, set must copy custom buffer */
    964 	if (argc == 2) {
    965 		uint chunk = DHD_IOCTL_MAXLEN;
    966 		for (addr -= align, len += align; len; addr += chunk, len -= chunk, align = 0) {
    967 			chunk = MIN(chunk, len);
    968 			params[0] = addr; params[1] = ROUNDUP(chunk, 4);
    969 			ret = dhd_var_getbuf(dhd, "membytes",
    970 			                     params, (2 * sizeof(int)), (void**)&ptr);
    971 			if (ret < 0)
    972 				goto exit;
    973 
    974 			if (rawout) {
    975 				fwrite(ptr + align, sizeof(char), chunk - align, stdout);
    976 			} else {
    977 				dhd_hexdump((uchar*)ptr + align, chunk - align, addr + align);
    978 			}
    979 		}
    980 	} else {
    981 		uint patlen = strlen(argv[2]);
    982 		uint chunk, maxchunk;
    983 		char *sptr;
    984 
    985 		if (hexin) {
    986 			char *inptr, *outptr;
    987 			if (patlen & 1) {
    988 				fprintf(stderr, "Hex (-h) must consist of whole bytes\n");
    989 				ret = USAGE_ERROR;
    990 				goto exit;
    991 			}
    992 
    993 			for (inptr = outptr = argv[2]; patlen; patlen -= 2) {
    994 				int n1, n2;
    995 
    996 				n1 = (int)((unsigned char)*inptr++);
    997 				n2 = (int)((unsigned char)*inptr++);
    998 				if (!isxdigit(n1) || !isxdigit(n2)) {
    999 					fprintf(stderr, "invalid hex digit %c\n",
   1000 					        (isxdigit(n1) ? n2 : n1));
   1001 					ret = USAGE_ERROR;
   1002 					goto exit;
   1003 				}
   1004 				n1 = isdigit(n1) ? (n1 - '0')
   1005 				        : ((islower(n1) ? (toupper(n1)) : n1) - 'A' + 10);
   1006 				n2 = isdigit(n2) ? (n2 - '0')
   1007 				        : ((islower(n2) ? (toupper(n2)) : n2) - 'A' + 10);
   1008 				*outptr++ = (n1 * 16) + n2;
   1009 			}
   1010 
   1011 			patlen = outptr - argv[2];
   1012 		}
   1013 
   1014 		sptr = argv[2];
   1015 		maxchunk = DHD_IOCTL_MAXLEN - (strlen(cmd->name) + 1 + (2 * sizeof(int)));
   1016 
   1017 		while (len) {
   1018 			chunk = (len > maxchunk) ? (maxchunk & ~0x3) : len;
   1019 
   1020 			/* build the iovar command */
   1021 			memset(buf, 0, DHD_IOCTL_MAXLEN);
   1022 			strcpy(buf, cmd->name);
   1023 			ptr = buf + strlen(buf) + 1;
   1024 			params[0] = addr; params[1] = chunk;
   1025 			memcpy(ptr, params, (2 * sizeof(int)));
   1026 			ptr += (2 * sizeof(int));
   1027 			addr += chunk; len -= chunk;
   1028 
   1029 			while (chunk--) {
   1030 				*ptr++ = *sptr++;
   1031 				if (sptr >= (argv[2] + patlen))
   1032 					sptr = argv[2];
   1033 			}
   1034 
   1035 			ret = dhd_set(dhd, DHD_SET_VAR, &buf[0], (ptr - buf));
   1036 			if (ret < 0)
   1037 				goto exit;
   1038 		}
   1039 	}
   1040 
   1041 exit:
   1042 	return ret;
   1043 }
   1044 
   1045 static int
   1046 dhd_idletime(void *dhd, cmd_t *cmd, char **argv)
   1047 {
   1048 	int32 idletime;
   1049 	char *endptr = NULL;
   1050 	int err = 0;
   1051 
   1052 	if (argv[1]) {
   1053 		if (!strcmp(argv[1], "never")) {
   1054 			idletime = 0;
   1055 		} else if (!strcmp(argv[1], "immediate") || !strcmp(argv[1], "immed")) {
   1056 			idletime = DHD_IDLE_IMMEDIATE;
   1057 		} else {
   1058 			idletime = strtol(argv[1], &endptr, 0);
   1059 			if (*endptr != '\0') {
   1060 				fprintf(stderr, "invalid number %s\n", argv[1]);
   1061 				err = -1;
   1062 			}
   1063 		}
   1064 		if ((idletime < 0) && (idletime != DHD_IDLE_IMMEDIATE)) {
   1065 			fprintf(stderr, "invalid value %s\n", argv[1]);
   1066 			err = -1;
   1067 		}
   1068 
   1069 		if (!err) {
   1070 			strcpy(buf, "idletime");
   1071 			endptr = buf + strlen(buf) + 1;
   1072 			memcpy(endptr, &idletime, sizeof(uint32));
   1073 			endptr += sizeof(uint32);
   1074 			err = dhd_set(dhd, DHD_SET_VAR, &buf[0], (endptr - buf));
   1075 		}
   1076 	} else {
   1077 		if ((err = dhd_var_get(dhd, cmd, argv))) {
   1078 			return err;
   1079 		} else {
   1080 			idletime = *(int32*)buf;
   1081 
   1082 			if (idletime == 0) {
   1083 				printf("0 (never)\n");
   1084 			} else if (idletime == DHD_IDLE_IMMEDIATE) {
   1085 				printf("-1 (immediate)\n");
   1086 			} else if (idletime > 0) {
   1087 				printf("%d\n", idletime);
   1088 			} else printf("%d (invalid)\n", idletime);
   1089 		}
   1090 	}
   1091 	return err;
   1092 }
   1093 
   1094 static int
   1095 dhd_idleclock(void *dhd, cmd_t *cmd, char **argv)
   1096 {
   1097 	int32 idleclock;
   1098 	char *endptr = NULL;
   1099 	int err = 0;
   1100 
   1101 	if (argv[1]) {
   1102 		if (!strcmp(argv[1], "active")) {
   1103 			idleclock = DHD_IDLE_ACTIVE;
   1104 		} else if (!strcmp(argv[1], "stopped")) {
   1105 			idleclock = DHD_IDLE_STOP;
   1106 		} else {
   1107 			idleclock = strtol(argv[1], &endptr, 0);
   1108 			if (*endptr != '\0') {
   1109 				fprintf(stderr, "invalid number %s\n", argv[1]);
   1110 				err = USAGE_ERROR;
   1111 			}
   1112 		}
   1113 
   1114 		if (!err) {
   1115 			strcpy(buf, "idleclock");
   1116 			endptr = buf + strlen(buf) + 1;
   1117 			memcpy(endptr, &idleclock, sizeof(int32));
   1118 			endptr += sizeof(int32);
   1119 			err = dhd_set(dhd, DHD_SET_VAR, &buf[0], (endptr - buf));
   1120 		}
   1121 	} else {
   1122 		if ((err = dhd_var_get(dhd, cmd, argv))) {
   1123 			return err;
   1124 		} else {
   1125 			idleclock = *(int32*)buf;
   1126 
   1127 			if (idleclock == DHD_IDLE_ACTIVE)
   1128 				printf("Idleclock %d (active)\n", idleclock);
   1129 			else if (idleclock == DHD_IDLE_STOP)
   1130 				printf("Idleclock %d (stopped)\n", idleclock);
   1131 			else
   1132 				printf("Idleclock divisor %d\n", idleclock);
   1133 		}
   1134 	}
   1135 	return err;
   1136 }
   1137 
   1138 /* Word count for a 4kb SPROM */
   1139 #define SPROM_WORDS 256
   1140 
   1141 static int
   1142 dhd_sprom(void *dhd, cmd_t *cmd, char **argv)
   1143 {
   1144 #if !defined(BWL_FILESYSTEM_SUPPORT)
   1145 	return (-1);
   1146 #else
   1147 	int ret, i;
   1148 	uint argc;
   1149 	char *endptr;
   1150 	char *bufp, *countptr;
   1151 	uint16 *wordptr;
   1152 	uint offset, words, bytes;
   1153 	bool nocrc = FALSE;
   1154 
   1155 	char *fname;
   1156 	FILE *fp;
   1157 
   1158 	UNUSED_PARAMETER(cmd);
   1159 
   1160 	/* arg count */
   1161 	for (argc = 0; argv[argc]; argc++);
   1162 	argc--;
   1163 
   1164 	/* init buffer */
   1165 	bufp = buf;
   1166 	memset(bufp, 0, DHD_IOCTL_MAXLEN);
   1167 	strcpy(bufp, "sprom");
   1168 	bufp += strlen("sprom") + 1;
   1169 
   1170 	if (strcmp(argv[0], "srdump") == 0) {
   1171 		if (argc) {
   1172 			fprintf(stderr, "Command srdump doesn't take args\n");
   1173 			return USAGE_ERROR;
   1174 		}
   1175 		offset = 0;
   1176 		words = SPROM_WORDS;
   1177 		bytes = 2 * words;
   1178 
   1179 		memcpy(bufp, &offset, sizeof(int));
   1180 		bufp += sizeof(int);
   1181 		memcpy(bufp, &bytes, sizeof(int));
   1182 		bufp += sizeof(int);
   1183 
   1184 		if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) {
   1185 			fprintf(stderr, "Internal error: unaligned word buffer\n");
   1186 			return COMMAND_ERROR;
   1187 		}
   1188 	} else {
   1189 		if (strcmp(argv[0], "srwrite") != 0) {
   1190 			fprintf(stderr, "Unimplemented sprom command: %s\n", argv[0]);
   1191 			return USAGE_ERROR;
   1192 		}
   1193 
   1194 		if (argc == 0) {
   1195 			return USAGE_ERROR;
   1196 		} else if ((argc == 1) ||
   1197 		           ((argc == 2) && ((nocrc = !strcmp(argv[1], "-c"))))) {
   1198 
   1199 			fname = nocrc ? argv[2] : argv[1];
   1200 
   1201 			/* determine and validate file size */
   1202 			if ((ret = file_size(fname)) < 0)
   1203 				return COMMAND_ERROR;
   1204 
   1205 			bytes = ret;
   1206 			offset = 0;
   1207 			words = bytes / 2;
   1208 
   1209 			if (bytes != 2 * SPROM_WORDS) {
   1210 				fprintf(stderr, "Bad file size\n");
   1211 				return COMMAND_ERROR;
   1212 			}
   1213 
   1214 			memcpy(bufp, &offset, sizeof(int));
   1215 			bufp += sizeof(int);
   1216 			memcpy(bufp, &bytes, sizeof(int));
   1217 			bufp += sizeof(int);
   1218 
   1219 			if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) {
   1220 				fprintf(stderr, "Internal error: unaligned word buffer\n");
   1221 				return COMMAND_ERROR;
   1222 			}
   1223 
   1224 			if ((fp = fopen(fname, "rb")) == NULL) {
   1225 				fprintf(stderr, "Could not open %s: %s\n",
   1226 				        fname, strerror(errno));
   1227 				return COMMAND_ERROR;
   1228 			}
   1229 
   1230 			if (fread((uint16*)bufp, sizeof(uint16), words, fp) != words) {
   1231 				fprintf(stderr, "Could not read %d bytes from %s\n",
   1232 				        words * 2, fname);
   1233 				fclose(fp);
   1234 				return COMMAND_ERROR;
   1235 			}
   1236 
   1237 			fclose(fp);
   1238 
   1239 			if (!nocrc &&
   1240 			    hndcrc8((uint8*)bufp, bytes, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE) {
   1241 				fprintf(stderr, "CRC check failed: 0x%02x, should be 0x%02x.\n",
   1242 				        ((uint8*)bufp)[bytes-1],
   1243 				        ~hndcrc8((uint8*)bufp, bytes - 1, CRC8_INIT_VALUE) & 0xff);
   1244 				return COMMAND_ERROR;
   1245 			}
   1246 
   1247 			ltoh16_buf(bufp, bytes);
   1248 		} else {
   1249 			offset = strtoul(*++argv, &endptr, 0) * 2;
   1250 			if (*endptr != '\0') {
   1251 				fprintf(stderr, "offset %s is not an integer\n", *argv);
   1252 				return USAGE_ERROR;
   1253 			}
   1254 
   1255 			memcpy(bufp, &offset, sizeof(int));
   1256 			bufp += sizeof(int);
   1257 			countptr = bufp;
   1258 			bufp += sizeof(int);
   1259 
   1260 			if (!ISALIGNED((uintptr)bufp, sizeof(uint16))) {
   1261 				fprintf(stderr, "Internal error: unaligned word buffer\n");
   1262 				return COMMAND_ERROR;
   1263 			}
   1264 
   1265 			for (words = 0, wordptr = (uint16*)bufp; *++argv; words++) {
   1266 				*wordptr++ = (uint16)strtoul(*argv, &endptr, 0);
   1267 				if (*endptr != '\0') {
   1268 					fprintf(stderr, "value %s is not an integer\n", *argv);
   1269 					return USAGE_ERROR;
   1270 				}
   1271 				if (words > SPROM_WORDS) {
   1272 					fprintf(stderr, "max of %d words\n", SPROM_WORDS);
   1273 					return USAGE_ERROR;
   1274 				}
   1275 			}
   1276 
   1277 			bytes = 2 * words;
   1278 			memcpy(countptr, &bytes, sizeof(int));
   1279 		}
   1280 	}
   1281 
   1282 	if (argc) {
   1283 		ret = dhd_set(dhd, DHD_SET_VAR, buf,
   1284 		              (strlen("sprom") + 1) + (2 * sizeof(int)) + bytes);
   1285 		return (ret);
   1286 	} else {
   1287 		ret = dhd_get(dhd, DHD_GET_VAR, buf,
   1288 		              (strlen("sprom") + 1) + (2 * sizeof(int)) + bytes);
   1289 		if (ret < 0) {
   1290 			return ret;
   1291 		}
   1292 
   1293 		for (i = 0; i < (int)words; i++) {
   1294 			if ((i % 8) == 0)
   1295 				printf("\n  srom[%03d]:  ", i);
   1296 			printf("0x%04x  ", ((uint16*)buf)[i]);
   1297 		}
   1298 		printf("\n");
   1299 	}
   1300 
   1301 	return 0;
   1302 #endif /* BWL_FILESYSTEM_SUPPORT */
   1303 }
   1304 
   1305 /*
   1306  * read_vars: reads an environment variables file into a buffer,
   1307  * reformatting them and returning the length (-1 on error).
   1308  *
   1309  * The input text file consists of lines of the form "<var>=<value>\n".
   1310  * CRs are ignored, as are blank lines and comments beginning with '#'.
   1311  *
   1312  * The output buffer consists of blocks of the form "<var>=<value>\0"
   1313  * (the newlines have been replaced by NULs)
   1314  *
   1315  * Todo: allow quoted variable names and quoted values.
   1316 */
   1317 
   1318 #if defined(BWL_FILESYSTEM_SUPPORT)
   1319 static int
   1320 read_vars(char *fname, char *buf, int buf_maxlen)
   1321 {
   1322 	FILE *fp;
   1323 	int buf_len, slen;
   1324 	char line[256], *s, *e;
   1325 	int line_no = 0;
   1326 
   1327 	if ((fp = fopen(fname, "rb")) == NULL) {
   1328 		fprintf(stderr, "Cannot open NVRAM file %s: %s\n",
   1329 		        fname, strerror(errno));
   1330 		exit(1);
   1331 	}
   1332 
   1333 	buf_len = 0;
   1334 
   1335 	while (fgets(line, sizeof(line), fp) != NULL) {
   1336 		bool found_eq = FALSE;
   1337 
   1338 		/* Ensure line length is limited */
   1339 		line[sizeof(line) - 1] = 0;
   1340 
   1341 		/* Skip any initial white space */
   1342 		for (s = line; *s == ' ' || *s == '\t'; s++)
   1343 			;
   1344 
   1345 		/* Determine end of string */
   1346 		for (e = s; *e != 0 && *e != '#' && *e != '\r' && *e != '\n'; e++)
   1347 			if (*e == '=')
   1348 				found_eq = TRUE;
   1349 
   1350 		/* Strip any white space from end of string */
   1351 		while (e > s && (e[-1] == ' ' || e[-1] == '\t'))
   1352 			e--;
   1353 
   1354 		slen = e - s;
   1355 
   1356 		/* Skip lines that end up blank */
   1357 		if (slen == 0)
   1358 			continue;
   1359 
   1360 		if (!found_eq) {
   1361 			fprintf(stderr, "Invalid line %d in NVRAM file %s\n", line_no, fname);
   1362 			fclose(fp);
   1363 			return -1;
   1364 		}
   1365 
   1366 		if (buf_len + slen + 1 > buf_maxlen) {
   1367 			fprintf(stderr, "NVRAM file %s too long\n", fname);
   1368 			fclose(fp);
   1369 			return -1;
   1370 		}
   1371 
   1372 		memcpy(buf + buf_len, s, slen);
   1373 		buf_len += slen;
   1374 		buf[buf_len++] = 0;
   1375 	}
   1376 
   1377 	fclose(fp);
   1378 
   1379 	return buf_len;
   1380 }
   1381 #endif   /* BWL_FILESYSTEM_SUPPORT */
   1382 
   1383 static int
   1384 dhd_vars(void *dhd, cmd_t *cmd, char **argv)
   1385 {
   1386 	int ret;
   1387 	uint argc;
   1388 	char *bufp;
   1389 	char *vname;
   1390 
   1391 	UNUSED_PARAMETER(cmd);
   1392 
   1393 	/* arg count */
   1394 	for (argc = 0; argv[argc]; argc++);
   1395 	argc--;
   1396 
   1397 	switch (argc) {
   1398 	case 0: /* get */
   1399 	{
   1400 		if ((ret = dhd_var_getbuf(dhd, "vars", NULL, 0, (void**)&bufp)))
   1401 			break;
   1402 		while (*bufp) {
   1403 			printf("%s\n", bufp);
   1404 			bufp += strlen(bufp) + 1;
   1405 		}
   1406 	}
   1407 	break;
   1408 
   1409 #if defined(BWL_FILESYSTEM_SUPPORT)
   1410 	case 1: /* set */
   1411 	{
   1412 		uint nvram_len;
   1413 		vname = argv[1];
   1414 
   1415 		bufp = buf;
   1416 		strcpy(bufp, "vars");
   1417 		bufp += strlen("vars") + 1;
   1418 
   1419 		if ((ret = read_vars(vname, bufp,
   1420 		                           DHD_IOCTL_MAXLEN - (strlen("vars") + 3))) < 0) {
   1421 			ret = -1;
   1422 			break;
   1423 		}
   1424 
   1425 		nvram_len = ret;
   1426 		bufp += nvram_len;
   1427 		*bufp++ = 0;
   1428 
   1429 		ret = dhd_set(dhd, DHD_SET_VAR, buf, bufp - buf);
   1430 	}
   1431 	break;
   1432 #endif   /* BWL_FILESYSTEM_SUPPORT */
   1433 
   1434 	default:
   1435 		ret = -1;
   1436 		break;
   1437 	}
   1438 
   1439 	return ret;
   1440 }
   1441 
   1442 #define MEMBLOCK 2048
   1443 
   1444 /* Check that strlen("membytes")+1 + 2*sizeof(int32) + MEMBLOCK <= DHD_IOCTL_MAXLEN */
   1445 #if (MEMBLOCK + 17 > DHD_IOCTL_MAXLEN)
   1446 #error MEMBLOCK/DHD_IOCTL_MAXLEN sizing
   1447 #endif
   1448 
   1449 
   1450 #if defined(BWL_FILESYSTEM_SUPPORT)
   1451 static int
   1452 dhd_load_file_bytes(void *dhd, cmd_t *cmd, FILE *fp, int fsize, int start)
   1453 {
   1454 	int tot_len = 0;
   1455 	uint read_len;
   1456 	char *bufp;
   1457 	uint len;
   1458 	uint8 memblock[MEMBLOCK];
   1459 	int ret;
   1460 
   1461 	UNUSED_PARAMETER(cmd);
   1462 
   1463 	while (tot_len < fsize) {
   1464 		read_len = fsize - tot_len;
   1465 		if (read_len >= MEMBLOCK)
   1466 			read_len = MEMBLOCK;
   1467 		len = fread(memblock, sizeof(uint8), read_len, fp);
   1468 		if ((len < read_len) && !feof(fp)) {
   1469 			fprintf(stderr, "%s: error reading file\n", __FUNCTION__);
   1470 			return -1;
   1471 
   1472 		}
   1473 
   1474 		bufp = buf;
   1475 		memset(bufp, 0, DHD_IOCTL_MAXLEN);
   1476 		strcpy(bufp, "membytes");
   1477 		bufp += strlen("membytes") + 1;
   1478 		memcpy(bufp, &start, sizeof(int));
   1479 		bufp += sizeof(int);
   1480 		memcpy(bufp, &len, sizeof(int));
   1481 		bufp += sizeof(int);
   1482 		memcpy(bufp, memblock, len);
   1483 
   1484 		ret = dhd_set(dhd, DHD_SET_VAR, &buf[0], (bufp - buf + len));
   1485 
   1486 		if (ret) {
   1487 			fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",
   1488 			        __FUNCTION__, ret, len, start);
   1489 			return -1;
   1490 		}
   1491 		start += len;
   1492 		tot_len += len;
   1493 	}
   1494 	return 0;
   1495 }
   1496 #endif   /* BWL_FILESYSTEM_SUPPORT */
   1497 
   1498 static int
   1499 dhd_download(void *dhd, cmd_t *cmd, char **argv)
   1500 {
   1501 #if !defined(BWL_FILESYSTEM_SUPPORT)
   1502 	return (-1);
   1503 #else
   1504 	bool reset = TRUE;
   1505 	bool run = TRUE;
   1506 	char *fname = NULL;
   1507 	char *vname = NULL;
   1508 	uint32 start = 0;
   1509 	int ret = 0;
   1510 	int fsize;
   1511 
   1512 	FILE *fp = NULL;
   1513 	uint32 memsize;
   1514 	char *memszargs[] = { "memsize", NULL };
   1515 
   1516 	char *bufp;
   1517 
   1518 	miniopt_t opts;
   1519 	int opt_err;
   1520 	uint nvram_len;
   1521 	struct trx_header trx_hdr;
   1522 	bool trx_file = FALSE;
   1523 
   1524 	/* Parse command-line options */
   1525 	miniopt_init(&opts, "download", "", TRUE);
   1526 
   1527 	argv++;
   1528 	while ((opt_err = miniopt(&opts, argv)) != -1) {
   1529 		if (opt_err == 1) {
   1530 			fprintf(stderr, "download options error\n");
   1531 			ret = -1;
   1532 			goto exit;
   1533 		}
   1534 		argv += opts.consumed;
   1535 
   1536 		if (opts.opt == 'a') {
   1537 			if (!opts.good_int) {
   1538 				fprintf(stderr, "invalid address %s\n", opts.valstr);
   1539 				ret = -1;
   1540 				goto exit;
   1541 			}
   1542 			start = (uint32)opts.uval;
   1543 		} else if (opts.positional) {
   1544 			if (fname && vname) {
   1545 				fprintf(stderr, "extra positional arg, %s\n",
   1546 				        opts.valstr);
   1547 				ret = -1;
   1548 				goto exit;
   1549 			}
   1550 			if (fname)
   1551 				vname = opts.valstr;
   1552 			else
   1553 				fname = opts.valstr;
   1554 		} else if (!opts.opt) {
   1555 			if (!strcmp(opts.key, "noreset")) {
   1556 				reset = FALSE;
   1557 			} else if (!strcmp(opts.key, "norun")) {
   1558 				run = FALSE;
   1559 			} else {
   1560 				fprintf(stderr, "unrecognized option %s\n", opts.valstr);
   1561 				ret = -1;
   1562 				goto exit;
   1563 			}
   1564 		} else {
   1565 			fprintf(stderr, "unrecognized option %c\n", opts.opt);
   1566 			ret = -1;
   1567 			goto exit;
   1568 		}
   1569 	}
   1570 
   1571 	/* validate arguments */
   1572 	if (!fname) {
   1573 		fprintf(stderr, "filename required\n");
   1574 		ret = -1;
   1575 		goto exit;
   1576 	}
   1577 
   1578 
   1579 	/* validate file size compared to memory size */
   1580 	if ((fsize = file_size(fname)) < 0) {
   1581 		ret = -1;
   1582 		goto exit;
   1583 	}
   1584 	/* read the file and push blocks down to memory */
   1585 	if ((fp = fopen(fname, "rb")) == NULL) {
   1586 		fprintf(stderr, "%s: unable to open %s: %s\n",
   1587 		        __FUNCTION__, fname, strerror(errno));
   1588 		ret = -1;
   1589 		goto exit;
   1590 	}
   1591 	/* Verify the file is a regular bin file or trx file */
   1592 	{
   1593 		uint32 tmp_len;
   1594 		uint32 trx_hdr_len = sizeof(struct trx_header);
   1595 		tmp_len = fread(&trx_hdr, sizeof(uint8), trx_hdr_len, fp);
   1596 		if (tmp_len == trx_hdr_len) {
   1597 			if (trx_hdr.magic == TRX_MAGIC) {
   1598 				fprintf(stderr, "TRX file\n");
   1599 				trx_file = TRUE;
   1600 				/* trx header file format: image_size, rom_img_size, rom_load_adr */
   1601 				fprintf(stderr, "dongle RAM Image size %d\n", trx_hdr.offsets[0]);
   1602 				fprintf(stderr, "dongle ROM Image size %d\n", trx_hdr.offsets[1]);
   1603 				fprintf(stderr, "dongle ROM Loadaddr 0x%x\n", trx_hdr.offsets[2]);
   1604 				fsize = trx_hdr.offsets[0] + trx_hdr.offsets[1];
   1605 				fprintf(stderr, "filesize is %d\n", fsize);
   1606 			}
   1607 			else
   1608 				fseek(fp, 0, SEEK_SET);
   1609 		}
   1610 		else
   1611 			fseek(fp, 0, SEEK_SET);
   1612 	}
   1613 
   1614 	if ((ret = dhd_var_get(dhd, NULL, memszargs))) {
   1615 		fprintf(stderr, "%s: error obtaining memsize\n", __FUNCTION__);
   1616 		goto exit;
   1617 	}
   1618 
   1619 	memsize = *(uint32*)buf;
   1620 
   1621 	if (memsize && ((uint32)fsize > memsize)) {
   1622 		fprintf(stderr, "%s: file %s too large (%d > %d)\n",
   1623 		        __FUNCTION__, fname, fsize, memsize);
   1624 		ret = -1;
   1625 		goto exit;
   1626 	}
   1627 
   1628 	/* do the download reset if not suppressed */
   1629 	if (reset) {
   1630 		if ((ret = dhd_iovar_setint(dhd, "download", TRUE))) {
   1631 			fprintf(stderr, "%s: failed to put dongle in download mode\n",
   1632 			        __FUNCTION__);
   1633 			goto exit;
   1634 		}
   1635 	}
   1636 	if (trx_file)
   1637 		fsize = trx_hdr.offsets[0];
   1638 	/* Load the ram image */
   1639 	if (dhd_load_file_bytes(dhd, cmd, fp, fsize, start)) {
   1640 		fprintf(stderr, "%s: error loading the ramimage at addr 0x%x\n",
   1641 			__FUNCTION__, start);
   1642 			ret = -1;
   1643 			goto exit;
   1644 		}
   1645 	if (trx_file) {
   1646 		/* Load the rom library */
   1647 		start = trx_hdr.offsets[2];
   1648 		fsize = trx_hdr.offsets[1];
   1649 
   1650 		fprintf(stderr, "setting the maxsocram value 0x%x \n", start);
   1651 		if (dhd_iovar_setint(dhd, "maxsocram", start)) {
   1652 			fprintf(stderr, "%s: setting the maxram size to %d failed\n",
   1653 				__FUNCTION__,  start);
   1654 			goto exit;
   1655 		}
   1656 
   1657 		if (dhd_load_file_bytes(dhd, cmd, fp, fsize, start)) {
   1658 			fprintf(stderr, "%s: error loading the rom library at addr 0x%x\n",
   1659 				__FUNCTION__,  start);
   1660 			goto exit;
   1661 		}
   1662 
   1663 	}
   1664 
   1665 	fclose(fp);
   1666 	fp = NULL;
   1667 
   1668 	/* download the vars file if specified */
   1669 	if (vname) {
   1670 		bufp = buf;
   1671 		strcpy(bufp, "vars");
   1672 		bufp += strlen("vars") + 1;
   1673 
   1674 		if ((ret = read_vars(vname, bufp,
   1675 		                           DHD_IOCTL_MAXLEN - (strlen("vars") + 3))) < 0) {
   1676 			ret = -1;
   1677 			goto exit;
   1678 		}
   1679 
   1680 		nvram_len = ret;
   1681 		bufp += nvram_len;
   1682 		*bufp++ = 0;
   1683 
   1684 		ret = dhd_set(dhd, DHD_SET_VAR, buf, (bufp - buf));
   1685 		if (ret) {
   1686 			fprintf(stderr, "%s: error %d on delivering vars\n",
   1687 			        __FUNCTION__, ret);
   1688 			goto exit;
   1689 		}
   1690 	}
   1691 
   1692 	/* start running the downloaded code if not suppressed */
   1693 	if (run) {
   1694 		if ((ret = dhd_iovar_setint(dhd, "download", FALSE))) {
   1695 			fprintf(stderr, "%s: failed to take dongle out of download mode\n",
   1696 			        __FUNCTION__);
   1697 			goto exit;
   1698 		}
   1699 	}
   1700 
   1701 exit:
   1702 	if (fp)
   1703 		fclose(fp);
   1704 
   1705 	return ret;
   1706 #endif /* BWL_FILESYSTEM_SUPPORT */
   1707 }
   1708 
   1709 static int
   1710 dhd_upload(void *dhd, cmd_t *cmd, char **argv)
   1711 {
   1712 #if !defined(BWL_FILESYSTEM_SUPPORT)
   1713 	return (-1);
   1714 #else
   1715 	char *fname = NULL;
   1716 	uint32 start = 0;
   1717 	uint32 size = 0;
   1718 	int ret = 0;
   1719 
   1720 	FILE *fp;
   1721 	uint32 memsize;
   1722 	char *memszargs[] = { "memsize", NULL };
   1723 
   1724 	uint len;
   1725 
   1726 	miniopt_t opts;
   1727 	int opt_err;
   1728 
   1729 	UNUSED_PARAMETER(cmd);
   1730 	UNUSED_PARAMETER(argv);
   1731 
   1732 	/* Parse command-line options */
   1733 	miniopt_init(&opts, "upload", "", TRUE);
   1734 
   1735 	argv++;
   1736 	while ((opt_err = miniopt(&opts, argv)) != -1) {
   1737 		if (opt_err == 1) {
   1738 			fprintf(stderr, "upload options error\n");
   1739 			ret = -1;
   1740 			goto exit;
   1741 		}
   1742 		argv += opts.consumed;
   1743 
   1744 		if (opts.opt == 'a') {
   1745 			if (!opts.good_int) {
   1746 				fprintf(stderr, "invalid address %s\n", opts.valstr);
   1747 				ret = -1;
   1748 				goto exit;
   1749 			}
   1750 			start = (uint32)opts.uval;
   1751 		} else if (opts.positional) {
   1752 			if (!fname) {
   1753 				fname = opts.valstr;
   1754 			} else if (opts.good_int) {
   1755 				size = (uint32)opts.uval;
   1756 			} else {
   1757 				fprintf(stderr, "upload options error\n");
   1758 				ret = -1;
   1759 				goto exit;
   1760 			}
   1761 		} else if (!opts.opt) {
   1762 			fprintf(stderr, "unrecognized option %s\n", opts.valstr);
   1763 			ret = -1;
   1764 			goto exit;
   1765 		} else {
   1766 			fprintf(stderr, "unrecognized option %c\n", opts.opt);
   1767 			ret = -1;
   1768 			goto exit;
   1769 		}
   1770 	}
   1771 
   1772 	/* validate arguments */
   1773 	if (!fname) {
   1774 		fprintf(stderr, "filename required\n");
   1775 		ret = -1;
   1776 		goto exit;
   1777 	}
   1778 
   1779 	if ((ret = dhd_var_get(dhd, NULL, memszargs))) {
   1780 		fprintf(stderr, "%s: error obtaining memsize\n", __FUNCTION__);
   1781 		goto exit;
   1782 	}
   1783 	memsize = *(uint32*)buf;
   1784 
   1785 	if (!memsize)
   1786 		memsize = start + size;
   1787 
   1788 	if (start + size > memsize) {
   1789 		fprintf(stderr, "%s: %d bytes at 0x%x exceeds ramsize 0x%x\n",
   1790 		        __FUNCTION__, size, start, memsize);
   1791 		ret = -1;
   1792 		goto exit;
   1793 	}
   1794 
   1795 	if ((fp = fopen(fname, "wb")) == NULL) {
   1796 		fprintf(stderr, "%s: Could not open %s: %s\n",
   1797 		        __FUNCTION__, fname, strerror(errno));
   1798 		ret = -1;
   1799 		goto exit;
   1800 	}
   1801 
   1802 	/* default size to full RAM */
   1803 	if (!size)
   1804 		size = memsize - start;
   1805 
   1806 	/* read memory and write to file */
   1807 	while (size) {
   1808 		char *ptr;
   1809 		int params[2];
   1810 
   1811 		len = MIN(MEMBLOCK, size);
   1812 
   1813 		params[0] = start;
   1814 		params[1] = len;
   1815 		ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);
   1816 		if (ret) {
   1817 			fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",
   1818 			        __FUNCTION__, len, start);
   1819 			break;
   1820 		}
   1821 
   1822 		if (fwrite(ptr, sizeof(*ptr), len, fp) != len) {
   1823 			fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);
   1824 			ret = -1;
   1825 			break;
   1826 		}
   1827 
   1828 		start += len;
   1829 		size -= len;
   1830 	}
   1831 
   1832 	fclose(fp);
   1833 exit:
   1834 	return ret;
   1835 #endif /* BWL_FILESYSTEM_SUPPORT */
   1836 }
   1837 
   1838 static int
   1839 dhd_logstamp(void *dhd, cmd_t *cmd, char **argv)
   1840 {
   1841 	int ret;
   1842 	char *endptr = NULL;
   1843 	uint argc;
   1844 	int valn[2] = {0, 0};
   1845 
   1846 	/* arg count */
   1847 	for (argc = 0; argv[argc]; argc++);
   1848 	argc--; argv++;
   1849 
   1850 	if (argc > 2)
   1851 		return USAGE_ERROR;
   1852 
   1853 	if (argc) {
   1854 		valn[0] = strtol(argv[0], &endptr, 0);
   1855 		if (*endptr != '\0') {
   1856 			printf("bad val1: %s\n", argv[0]);
   1857 			return USAGE_ERROR;
   1858 		}
   1859 	}
   1860 
   1861 	if (argc > 1) {
   1862 		valn[1] = strtol(argv[1], &endptr, 0);
   1863 		if (*endptr != '\0') {
   1864 			printf("bad val2: %s\n", argv[1]);
   1865 			return USAGE_ERROR;
   1866 		}
   1867 	}
   1868 
   1869 	ret = dhd_var_setbuf(dhd, cmd->name, valn, argc * sizeof(int));
   1870 
   1871 	return (ret);
   1872 }
   1873 
   1874 static int
   1875 dhd_sd_reg(void *dhd, cmd_t *cmd, char **argv)
   1876 {
   1877 	int ret;
   1878 	sdreg_t sdreg;
   1879 	char *endptr = NULL;
   1880 	uint argc;
   1881 	void *ptr = NULL;
   1882 
   1883 	bzero(&sdreg, sizeof(sdreg));
   1884 
   1885 	/* arg count */
   1886 	for (argc = 0; argv[argc]; argc++);
   1887 	argc--;
   1888 
   1889 	/* hostreg: offset [value]; devreg: func offset [value] */
   1890 	if (!strcmp(cmd->name, "sd_hostreg")) {
   1891 		argv++;
   1892 		if (argc < 1) {
   1893 			printf("required args: offset [value]\n");
   1894 			return USAGE_ERROR;
   1895 		}
   1896 
   1897 	} else if (!strcmp(cmd->name, "sd_devreg")) {
   1898 		argv++;
   1899 		if (argc < 2) {
   1900 			printf("required args: func offset [value]\n");
   1901 			return USAGE_ERROR;
   1902 		}
   1903 
   1904 		sdreg.func = strtoul(*argv++, &endptr, 0);
   1905 		if (*endptr != '\0') {
   1906 			printf("Invalid function number\n");
   1907 			return USAGE_ERROR;
   1908 		}
   1909 	} else {
   1910 		return USAGE_ERROR;
   1911 	}
   1912 
   1913 	sdreg.offset = strtoul(*argv++, &endptr, 0);
   1914 	if (*endptr != '\0') {
   1915 		printf("Invalid offset value\n");
   1916 		return USAGE_ERROR;
   1917 	}
   1918 
   1919 	/* third arg: value */
   1920 	if (*argv) {
   1921 		sdreg.value = strtoul(*argv, &endptr, 0);
   1922 		if (*endptr != '\0') {
   1923 			printf("Invalid value\n");
   1924 			return USAGE_ERROR;
   1925 		}
   1926 	}
   1927 
   1928 	/* no third arg means get, otherwise set */
   1929 	if (!*argv) {
   1930 		if ((ret = dhd_var_getbuf(dhd, cmd->name, &sdreg, sizeof(sdreg), &ptr)) >= 0)
   1931 			printf("0x%x\n", *(int *)ptr);
   1932 	} else {
   1933 		ret = dhd_var_setbuf(dhd, cmd->name, &sdreg, sizeof(sdreg));
   1934 	}
   1935 
   1936 	return (ret);
   1937 }
   1938 
   1939 static dbg_msg_t dhd_msgs[] = {
   1940 	{DHD_ERROR_VAL,	"error"},
   1941 	{DHD_ERROR_VAL, "err"},
   1942 	{DHD_TRACE_VAL, "trace"},
   1943 	{DHD_INFO_VAL,	"inform"},
   1944 	{DHD_INFO_VAL,	"info"},
   1945 	{DHD_INFO_VAL,	"inf"},
   1946 	{DHD_DATA_VAL,	"data"},
   1947 	{DHD_CTL_VAL,	"ctl"},
   1948 	{DHD_TIMER_VAL,	"timer"},
   1949 	{DHD_HDRS_VAL,	"hdrs"},
   1950 	{DHD_BYTES_VAL,	"bytes"},
   1951 	{DHD_INTR_VAL,	"intr"},
   1952 	{DHD_LOG_VAL,	"log"},
   1953 	{DHD_GLOM_VAL,	"glom"},
   1954 	{DHD_EVENT_VAL,	"event"},
   1955 	{DHD_BTA_VAL,	"bta"},
   1956 	{0,		NULL}
   1957 };
   1958 
   1959 static int
   1960 dhd_msglevel(void *dhd, cmd_t *cmd, char **argv)
   1961 {
   1962 	return dhd_do_msglevel(dhd, cmd, argv, dhd_msgs);
   1963 }
   1964 
   1965 static int
   1966 dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg)
   1967 {
   1968 	int ret, i;
   1969 	uint val, last_val = 0, msglevel = 0, msglevel_add = 0, msglevel_del = 0;
   1970 	char *endptr = NULL;
   1971 
   1972 	if ((ret = dhd_iovar_getint(dhd, cmd->name, (int*)&msglevel)) < 0)
   1973 		return (ret);
   1974 
   1975 	if (!*++argv) {
   1976 		printf("0x%x ", msglevel);
   1977 		for (i = 0; (val = dbg_msg[i].value); i++) {
   1978 			if ((msglevel & val) && (val != last_val))
   1979 				printf(" %s", dbg_msg[i].string);
   1980 			last_val = val;
   1981 		}
   1982 		printf("\n");
   1983 		return (0);
   1984 	}
   1985 
   1986 	while (*argv) {
   1987 		char *s = *argv;
   1988 		if (*s == '+' || *s == '-')
   1989 			s++;
   1990 		else
   1991 			msglevel_del = ~0;	/* make the whole list absolute */
   1992 		val = strtoul(s, &endptr, 0);
   1993 		/* not a plain integer if not all the string was parsed by strtoul */
   1994 		if (*endptr != '\0') {
   1995 			for (i = 0; (val = dbg_msg[i].value); i++)
   1996 				if (stricmp(dbg_msg[i].string, s) == 0)
   1997 					break;
   1998 			if (!val)
   1999 				goto usage;
   2000 		}
   2001 		if (**argv == '-')
   2002 			msglevel_del |= val;
   2003 		else
   2004 			msglevel_add |= val;
   2005 		++argv;
   2006 	}
   2007 
   2008 	msglevel &= ~msglevel_del;
   2009 	msglevel |= msglevel_add;
   2010 
   2011 	return (dhd_iovar_setint(dhd, cmd->name, msglevel));
   2012 
   2013 usage:
   2014 	fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");
   2015 	fprintf(stderr, "Use a + or - prefix to make an incremental change.");
   2016 
   2017 	for (i = 0; (val = dbg_msg[i].value); i++) {
   2018 		if (val != last_val)
   2019 			fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string);
   2020 		else
   2021 			fprintf(stderr, ", %s", dbg_msg[i].string);
   2022 		last_val = val;
   2023 	}
   2024 	fprintf(stderr, "\n");
   2025 
   2026 	return 0;
   2027 }
   2028 
   2029 static char *
   2030 ver2str(unsigned int vms, unsigned int vls)
   2031 {
   2032 	static char verstr[100];
   2033 	unsigned int maj, year, month, day, build;
   2034 
   2035 	maj = (vms >> 16) & 0xFFFF;
   2036 	if (maj > 1000) {
   2037 		/* it is probably a date... */
   2038 		year = (vms >> 16) & 0xFFFF;
   2039 		month = vms & 0xFFFF;
   2040 		day = (vls >> 16) & 0xFFFF;
   2041 		build = vls & 0xFFFF;
   2042 		sprintf(verstr, "%d/%d/%d build %d",
   2043 			month, day, year, build);
   2044 	} else {
   2045 		/* it is a tagged release. */
   2046 		sprintf(verstr, "%d.%d RC%d.%d",
   2047 			(vms>>16)&0xFFFF, vms&0xFFFF,
   2048 			(vls>>16)&0xFFFF, vls&0xFFFF);
   2049 	}
   2050 	return verstr;
   2051 }
   2052 
   2053 static int
   2054 dhd_version(void *dhd, cmd_t *cmd, char **argv)
   2055 {
   2056 	int ret;
   2057 	char *ptr;
   2058 
   2059 	UNUSED_PARAMETER(cmd);
   2060 	UNUSED_PARAMETER(argv);
   2061 
   2062 	/* Display the application version info */
   2063 	printf("%s: %s\n", dhdu_av0,
   2064 		ver2str((EPI_MAJOR_VERSION << 16)| EPI_MINOR_VERSION,
   2065 		(EPI_RC_NUMBER << 16) | EPI_INCREMENTAL_NUMBER));
   2066 
   2067 	if ((ret = dhd_var_getbuf(dhd, cmd->name, NULL, 0, (void**)&ptr)) < 0)
   2068 		return ret;
   2069 
   2070 	/* Display the returned string */
   2071 	printf("%s\n", ptr);
   2072 
   2073 	return 0;
   2074 }
   2075 
   2076 static int
   2077 dhd_var_setint(void *dhd, cmd_t *cmd, char **argv)
   2078 {
   2079 	int32 val;
   2080 	int len;
   2081 	char *varname;
   2082 	char *endptr = NULL;
   2083 	char *p;
   2084 
   2085 	if (cmd->set == -1) {
   2086 		printf("set not defined for %s\n", cmd->name);
   2087 		return COMMAND_ERROR;
   2088 	}
   2089 
   2090 	if (!*argv) {
   2091 		printf("set: missing arguments\n");
   2092 		return USAGE_ERROR;
   2093 	}
   2094 
   2095 	varname = *argv++;
   2096 
   2097 	if (!*argv) {
   2098 		printf("set: missing value argument for set of \"%s\"\n", varname);
   2099 		return USAGE_ERROR;
   2100 	}
   2101 
   2102 	val = strtol(*argv, &endptr, 0);
   2103 	if (*endptr != '\0') {
   2104 		/* not all the value string was parsed by strtol */
   2105 		printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n",
   2106 			*argv, varname);
   2107 		return USAGE_ERROR;
   2108 	}
   2109 
   2110 	strcpy(buf, varname);
   2111 	p = buf;
   2112 	while (*p != '\0') {
   2113 		*p = tolower(*p);
   2114 		p++;
   2115 	}
   2116 
   2117 	/* skip the NUL */
   2118 	p++;
   2119 
   2120 	memcpy(p, &val, sizeof(uint));
   2121 	len = (p - buf) +  sizeof(uint);
   2122 
   2123 	return (dhd_set(dhd, DHD_SET_VAR, &buf[0], len));
   2124 }
   2125 
   2126 static int
   2127 dhd_var_get(void *dhd, cmd_t *cmd, char **argv)
   2128 {
   2129 	char *varname;
   2130 	char *p;
   2131 
   2132 	UNUSED_PARAMETER(cmd);
   2133 
   2134 	if (!*argv) {
   2135 		printf("get: missing arguments\n");
   2136 		return USAGE_ERROR;
   2137 	}
   2138 
   2139 	varname = *argv++;
   2140 
   2141 	if (*argv) {
   2142 		printf("get: error, extra arg \"%s\"\n", *argv);
   2143 		return USAGE_ERROR;
   2144 	}
   2145 
   2146 	strcpy(buf, varname);
   2147 	p = buf;
   2148 	while (*p != '\0') {
   2149 		*p = tolower(*p);
   2150 		p++;
   2151 	}
   2152 	return (dhd_get(dhd, DHD_GET_VAR, &buf[0], DHD_IOCTL_MAXLEN));
   2153 }
   2154 
   2155 static int
   2156 dhd_var_getint(void *dhd, cmd_t *cmd, char **argv)
   2157 {
   2158 	int err;
   2159 	int32 val;
   2160 
   2161 	if (cmd->get == -1) {
   2162 		printf("get not defined for %s\n", cmd->name);
   2163 		return COMMAND_ERROR;
   2164 	}
   2165 
   2166 	if ((err = dhd_var_get(dhd, cmd, argv)))
   2167 		return (err);
   2168 
   2169 	val = *(int32*)buf;
   2170 
   2171 	if (val < 10)
   2172 		printf("%d\n", val);
   2173 	else
   2174 		printf("%d (0x%x)\n", val, val);
   2175 
   2176 	return (0);
   2177 }
   2178 
   2179 static int
   2180 dhd_var_getandprintstr(void *dhd, cmd_t *cmd, char **argv)
   2181 {
   2182 	int err;
   2183 
   2184 	if ((err = dhd_var_get(dhd, cmd, argv)))
   2185 		return (err);
   2186 
   2187 	printf("%s\n", buf);
   2188 	return (0);
   2189 }
   2190 
   2191 
   2192 void
   2193 dhd_printlasterror(void *dhd)
   2194 {
   2195 	char *cmd[2] = {"bcmerrorstr"};
   2196 
   2197 	if (dhd_var_get(dhd, NULL, cmd) != 0) {
   2198 		fprintf(stderr, "%s: \nError getting the last error\n", dhdu_av0);
   2199 	} else {
   2200 		fprintf(stderr, "%s: %s\n", dhdu_av0, buf);
   2201 	}
   2202 }
   2203 
   2204 static int
   2205 dhd_varint(void *dhd, cmd_t *cmd, char *argv[])
   2206 {
   2207 	if (argv[1])
   2208 		return (dhd_var_setint(dhd, cmd, argv));
   2209 	else
   2210 		return (dhd_var_getint(dhd, cmd, argv));
   2211 }
   2212 
   2213 static int
   2214 dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr)
   2215 {
   2216 	int len;
   2217 
   2218 	memset(buf, 0, DHD_IOCTL_MAXLEN);
   2219 	strcpy(buf, iovar);
   2220 
   2221 	/* include the NUL */
   2222 	len = strlen(iovar) + 1;
   2223 
   2224 	if (param_len)
   2225 		memcpy(&buf[len], param, param_len);
   2226 
   2227 	*bufptr = buf;
   2228 
   2229 	return dhd_get(dhd, DHD_GET_VAR, &buf[0], DHD_IOCTL_MAXLEN);
   2230 }
   2231 
   2232 static int
   2233 dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len)
   2234 {
   2235 	int len;
   2236 
   2237 	memset(buf, 0, DHD_IOCTL_MAXLEN);
   2238 	strcpy(buf, iovar);
   2239 
   2240 	/* include the NUL */
   2241 	len = strlen(iovar) + 1;
   2242 
   2243 	if (param_len)
   2244 		memcpy(&buf[len], param, param_len);
   2245 
   2246 	len += param_len;
   2247 	return dhd_set(dhd, DHD_SET_VAR, &buf[0], len);
   2248 }
   2249 
   2250 static int
   2251 dhd_var_void(void *dhd, cmd_t *cmd, char **argv)
   2252 {
   2253 	UNUSED_PARAMETER(argv);
   2254 
   2255 	if (cmd->set < 0)
   2256 		return USAGE_ERROR;
   2257 
   2258 	return dhd_var_setbuf(dhd, cmd->name, NULL, 0);
   2259 }
   2260 
   2261 /*
   2262  * format an iovar buffer
   2263  */
   2264 static uint
   2265 dhd_iovar_mkbuf(char *name, char *data, uint datalen, char *buf, uint buflen, int *perr)
   2266 {
   2267 	uint len;
   2268 
   2269 	len = strlen(name) + 1;
   2270 
   2271 	/* check for overflow */
   2272 	if ((len + datalen) > buflen) {
   2273 		*perr = BCME_BUFTOOSHORT;
   2274 		return 0;
   2275 	}
   2276 
   2277 	strcpy(buf, name);
   2278 
   2279 	/* append data onto the end of the name string */
   2280 	if (datalen > 0)
   2281 		memcpy(&buf[len], data, datalen);
   2282 
   2283 	len += datalen;
   2284 
   2285 	*perr = 0;
   2286 	return len;
   2287 }
   2288 
   2289 static int
   2290 dhd_iovar_getint(void *dhd, char *name, int *var)
   2291 {
   2292 	char ibuf[DHD_IOCTL_SMLEN];
   2293 	int error;
   2294 
   2295 	dhd_iovar_mkbuf(name, NULL, 0, ibuf, sizeof(ibuf), &error);
   2296 	if (error)
   2297 		return error;
   2298 
   2299 	if ((error = dhd_get(dhd, DHD_GET_VAR, &ibuf, sizeof(ibuf))) < 0)
   2300 		return error;
   2301 
   2302 	memcpy(var, ibuf, sizeof(int));
   2303 
   2304 	return 0;
   2305 }
   2306 
   2307 static int
   2308 dhd_iovar_setint(void *dhd, char *name, int var)
   2309 {
   2310 	int len;
   2311 	char ibuf[DHD_IOCTL_SMLEN];
   2312 	int error;
   2313 
   2314 	len = dhd_iovar_mkbuf(name, (char *)&var, sizeof(var), ibuf, sizeof(ibuf), &error);
   2315 	if (error)
   2316 		return error;
   2317 
   2318 	if ((error = dhd_set(dhd, DHD_SET_VAR, &ibuf, len)) < 0)
   2319 		return error;
   2320 
   2321 	return 0;
   2322 }
   2323 
   2324 static int
   2325 dhd_varstr(void *dhd, cmd_t *cmd, char **argv)
   2326 {
   2327 	int error;
   2328 	char *str;
   2329 
   2330 	if (!*++argv) {
   2331 		void *ptr;
   2332 		if ((error = dhd_var_getbuf(dhd, cmd->name, NULL, 0, &ptr)) < 0)
   2333 			return (error);
   2334 
   2335 		str = (char *)ptr;
   2336 		printf("%s\n", str);
   2337 		return (0);
   2338 	} else {
   2339 		str = *argv;
   2340 		/* iovar buffer length includes NUL */
   2341 		return dhd_var_setbuf(dhd, cmd->name, str, strlen(str) + 1);
   2342 	}
   2343 }
   2344