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