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