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