Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/wl/dhd/dhdu.c
Views: 3960
/*1* Common code for dhd utility, hacked from wl utility2*3* $Copyright Open Broadcom Corporation$4*5* $Id: dhdu.c 381853 2013-01-30 03:36:11Z $6*/78/* For backwards compatibility, the absence of the define 'BWL_NO_FILESYSTEM_SUPPORT'9* implies that a filesystem is supported.10*/11#if !defined(BWL_NO_FILESYSTEM_SUPPORT)12#define BWL_FILESYSTEM_SUPPORT13#endif1415#ifndef PROP_TXSTATUS16#define PROP_TXSTATUS17#endif1819#include <stdio.h>20#include <stdlib.h>21#include <string.h>22#include <ctype.h>23#include <assert.h>2425#include <typedefs.h>26#include <epivers.h>27#include <proto/ethernet.h>28#include <dhdioctl.h>29#include <sdiovar.h>30#include <bcmutils.h>31#include <bcmendian.h>32#include "dhdu.h"33#include "miniopt.h"34#include <usbrdl.h>35#include <proto/bcmip.h>36#include <hndrte_debug.h>37#include <hndrte_armtrap.h>38#define IPV4_ADDR_LEN 439#ifdef WLBTAMP40#include <proto/bt_amp_hci.h>41#endif4243#define DUMP_INFO_PTR_PTR 0x1808784445#include <errno.h>4647#include <trxhdr.h>48#include "ucode_download.h"4950#define stricmp strcasecmp51#define strnicmp strncasecmp525354static cmd_func_t dhd_var_void;55static cmd_func_t dhd_varint, dhd_varstr;56static cmd_func_t dhd_var_getandprintstr, dhd_var_getint, dhd_var_get, dhd_var_ampak_otpmac;57static cmd_func_t dhd_var_setint;5859static cmd_func_t dhd_version, dhd_list, dhd_msglevel;6061#ifdef SDTEST62static cmd_func_t dhd_pktgen;63#endif64static cmd_func_t dhd_sprom;65static cmd_func_t dhd_sdreg;66static cmd_func_t dhd_sd_msglevel, dhd_sd_blocksize, dhd_sd_mode, dhd_sd_reg;67static cmd_func_t dhd_dma_mode;68static cmd_func_t dhd_membytes, dhd_download, dhd_dldn,69dhd_upload, dhd_coredump, dhd_vars, dhd_idleclock, dhd_idletime;70static cmd_func_t dhd_logstamp;71#ifdef BCMSPI72static cmd_func_t dhd_spierrstats;73#endif /* BCMSPI */7475#ifdef PROP_TXSTATUS76static cmd_func_t dhd_proptxstatusenable;77static cmd_func_t dhd_proptxstatusmode;78#endif79static int dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr);80static int dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len);8182static uint dhd_iovar_mkbuf(char *name, char *data, uint datalen,83char *buf, uint buflen, int *perr);84static int dhd_iovar_getint(void *dhd, char *name, int *var);85static int dhd_iovar_setint(void *dhd, char *name, int var);8687#if defined(BWL_FILESYSTEM_SUPPORT)88static int file_size(char *fname);89static int read_vars(char *fname, char *buf, int buf_maxlen);90#endif9192#ifdef WLBTAMP93static cmd_func_t wl_HCI_cmd;94static cmd_func_t wl_HCI_ACL_data;95#endif9697/* dword align allocation */98static union {99char bufdata[DHD_IOCTL_MAXLEN];100uint32 alignme;101} bufstruct_dhd;102static char *buf = (char*) &bufstruct_dhd.bufdata;103104/* integer output format, default to signed integer */105static uint8 int_fmt;106107typedef struct {108uint value;109char *string;110} dbg_msg_t;111112static int dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg);113114/* Actual command table */115cmd_t dhd_cmds[] = {116{ "cmds", dhd_list, -1, -1,117"generate a short list of available commands"},118{ "version", dhd_version, DHD_GET_VAR, -1,119"get version information" },120{ "hang", dhd_msglevel, DHD_GET_VAR, DHD_SET_VAR,121"set hang event" },122{ "wlmsglevel", dhd_msglevel, DHD_GET_VAR, DHD_SET_VAR,123"get/set message bits" },124{ "msglevel", dhd_msglevel, DHD_GET_VAR, DHD_SET_VAR,125"get/set message bits" },126{ "bcmerrorstr", dhd_var_getandprintstr, DHD_GET_VAR, -1,127"errorstring"},128{ "wdtick", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,129"watchdog tick time (ms units)"},130{ "intr", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,131"use interrupts on the bus"},132{ "pollrate", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,133"number of ticks between bus polls (0 means no polling)"},134{ "idletime", dhd_idletime, DHD_GET_VAR, DHD_SET_VAR,135"number of ticks for activity timeout (-1: immediate, 0: never)"},136{ "idleclock", dhd_idleclock, DHD_GET_VAR, DHD_SET_VAR,137"idleclock active | stopped | <N>\n"138"\tactive (0) - do not request any change to the SD clock\n"139"\tstopped (-1) - request SD clock be stopped on activity timeout\n"140"\t<N> (other) - an sd_divisor value to request on activity timeout\n"},141{ "sd1idle", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,142"change mode to SD1 when turning off clock at idle"},143{ "forceeven", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,144"force SD tx/rx buffers to be even"},145{ "readahead", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,146"enable readahead feature (look for next frame len in headers)"},147{ "sdrxchain", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,148"enable packet chains to SDIO stack for glom receive"},149{ "alignctl", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,150"align control frames"},151{ "sdalign", dhd_varint, DHD_GET_VAR, -1,152"display the (compiled in) alignment target for sd requests"},153{ "txbound", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,154"get/set maximum number of tx frames per scheduling"},155{ "rxbound", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,156"get/set maximum number of rx frames per scheduling"},157{ "txminmax", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,158"get/set maximum number of tx frames per scheduling while rx frames outstanding"},159{ "dconpoll", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,160"g/set dongle console polling interval (ms)"},161{ "dump", dhd_varstr, DHD_GET_VAR, -1,162"dump information"},163{ "cons", dhd_varstr, -1, DHD_SET_VAR,164"send string to device console (sd only)"},165{ "clearcounts", dhd_var_void, -1, DHD_SET_VAR,166"reset the bus stats shown in the dhd dump"},167{ "logdump", dhd_varstr, DHD_GET_VAR, -1,168"dump the timestamp logging buffer"},169{ "logcal", dhd_varint, -1, DHD_SET_VAR,170"logcal <n> -- log around an osl_delay of <n> usecs"},171{ "logstamp", dhd_logstamp, -1, DHD_SET_VAR,172"logstamp [<n1>] [<n2>] -- add a message to the log"},173{ "memsize", dhd_varint, DHD_GET_VAR, -1,174"display size of onchip SOCRAM"},175{ "membytes", dhd_membytes, DHD_GET_VAR, DHD_SET_VAR,176"membytes [-h | -r | -i] <address> <length> [<bytes>]\n"177"\tread or write data in the dongle ram\n"178"\t-h <bytes> is a sequence of hex digits, else a char string\n"179"\t-r output as a raw write rather than hexdump display\n"},180{ "download", dhd_download, -1, DHD_SET_VAR,181"download [-a <address>] [--noreset] [--norun] [--verify] <binfile> [<varsfile>]\n"182"\tdownload file to specified dongle ram address and start CPU\n"183"\toptional vars file will replace vars parsed from the CIS\n"184"\t--noreset do not reset SOCRAM core before download\n"185"\t--norun do not start dongle CPU after download\n"186"\t--verify do readback verify \n"187"\tdefault <address> is 0\n"},188{ "dldn", dhd_dldn, -1, DHD_SET_VAR,189"download <binfile>\n"190"\tdownload file to specified dongle ram address 0\n"},191{ "vars", dhd_vars, DHD_GET_VAR, DHD_SET_VAR,192"vars [<file>]\n"193"\toverride SPROM vars with <file> (before download)\n"},194{ "coredump", dhd_coredump, -1, -1,195"coredump <file>\n"196"\tdump dongle RAM content into a file in dumpfile format\n"197"\tfor use with ELF core generator"},198{ "upload", dhd_upload, -1, -1,199"upload [-a <address> ] <file> [<size>]\n"200"\tupload dongle RAM content into a file\n"201"\tdefault <address> is 0, default <size> is RAM size"},202{ "srdump", dhd_sprom, DHD_GET_VAR, -1,203"display SPROM content" },204{ "srwrite", dhd_sprom, -1, DHD_SET_VAR,205"write data or file content to SPROM\n"206"\tsrwrite <word-offset> <word-value> ...\n"207"\tsrwrite [-c] <srom-file-path>\n"208"\t -c means write regardless of crc"},209{ "sleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,210"enter/exit simulated host sleep (bus powerdown w/OOB wakeup)"},211{ "kso", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,212"keep sdio on"},213{ "devcap", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,214"brcm device capabilities"},215{ "devsleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,216"Sleep CMD14"},217#ifdef SDTEST218{ "extloop", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,219"external loopback: convert all tx data to echo test frames"},220{ "pktgen", dhd_pktgen, DHD_GET_VAR, DHD_SET_VAR,221"configure/report pktgen status (SDIO)\n"222"\t-f N frequency: send/recv a burst every N ticks\n"223"\t-c N count: send/recv N packets each burst\n"224"\t-t N total: stop after a total of N packets\n"225"\t-p N print: display counts on console every N bursts\n"226"\t-m N min: set minimum length of packet data\n"227"\t-M N Max: set maximum length of packet data\n"228"\t-l N len: set fixed length of packet data\n"229"\t-s N stop after N tx failures\n"230"\t-d dir test direction/type:\n"231"\t send -- send packets discarded by dongle\n"232"\t echo -- send packets to be echoed by dongle\n"233"\t burst -- request bursts (of size <-c>) from dongle\n"234"\t one every <-f> ticks, until <-t> total requests\n"235"\t recv -- request dongle enter continuous send mode,\n"236"\t read up to <-c> pkts every <-f> ticks until <-t>\n"237"\t total reads\n"},238#endif /* SDTEST */239{ "dngl_isolation", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,240"g/set dongle isolation, so the dev could be disabled with out effecting the dongle state"},241{ "sdreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR,242"g/set sdpcmdev core register (f1) across SDIO (CMD53)"},243{ "sbreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR,244"g/set any backplane core register (f1) across SDIO (CMD53)"},245{ "magic", dhd_var_ampak_otpmac, DHD_GET_VAR, -1,246"magic"},247{ "sd_cis", dhd_var_getandprintstr, DHD_GET_VAR, -1,248"dump sdio CIS"},249{ "sd_devreg", dhd_sd_reg, DHD_GET_VAR, DHD_SET_VAR,250"g/set device register across SDIO bus (CMD52)"},251{ "sd_hostreg", dhd_sd_reg, DHD_GET_VAR, DHD_SET_VAR,252"g/set local controller register"},253{ "sd_blocksize", dhd_sd_blocksize, DHD_GET_VAR, DHD_SET_VAR,254"g/set block size for a function"},255{ "sd_blockmode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,256"g/set blockmode"},257{ "sd_ints", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,258"g/set client ints"},259{ "sd_dma", dhd_dma_mode, DHD_GET_VAR, DHD_SET_VAR,260"g/set dma usage: [PIO | SDMA | ADMA1 | ADMA2]"},261{ "sd_yieldcpu", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,262"allow blocking (yield of CPU) on data xfer"},263{ "sd_minyield", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,264"minimum xfer size to allow CPU yield"},265{ "sd_forcerb", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,266"force readback when changing local interrupt settings"},267{ "sd_numints", dhd_varint, DHD_GET_VAR, -1,268"number of device interrupts"},269{ "sd_numlocalints", dhd_varint, DHD_GET_VAR, -1,270"number of non-device interrupts"},271{ "sd_divisor", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,272"set the divisor for SDIO clock generation"},273{ "sd_power", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,274"set the SD Card slot power"},275{ "sd_clock", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,276"turn on/off the SD Clock"},277{ "sd_crc", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,278"turn on/off CRC checking in SPI mode"},279{ "sd_mode", dhd_sd_mode, DHD_GET_VAR, DHD_SET_VAR,280"g/set SDIO bus mode (spi, sd1, sd4)"},281{ "sd_highspeed", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,282"set the high-speed clocking mode"},283{ "sd_msglevel", dhd_sd_msglevel, DHD_GET_VAR, DHD_SET_VAR,284"g/set debug message level"},285{ "sd_hciregs", dhd_varstr, DHD_GET_VAR, -1,286"display host-controller interrupt registers"},287{ "sdiod_drive", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,288"SDIO Device drive strength in milliamps. (0=tri-state, 1-12mA)"},289#ifdef BCMSPI290{ "spi_errstats", dhd_spierrstats, DHD_GET_VAR, DHD_SET_VAR,291"SPI device status error statistics."},292{ "spi_respdelay", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,293"g/set response delay flag."},294#endif /* BCMSPI */295{ "devreset", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,296"Move device into or out of reset state (1/reset, or 0/operational)"},297{ "ioctl_timeout", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,298"IOCTL response timeout (milliseconds)."},299#ifdef WLBTAMP300{ "HCI_cmd", wl_HCI_cmd, -1, DHD_SET_VAR,301"carries HCI commands to the driver\n"302"\tusage: dhd HCI_cmd <command> <args>\n" },303{ "HCI_ACL_data", wl_HCI_ACL_data, -1, DHD_SET_VAR,304"carries HCI ACL data packet to the driver\n"305"\tusage: dhd HCI_ACL_data <logical link handle> <data>\n" },306#endif307#ifdef PROP_TXSTATUS308{ "proptx", dhd_proptxstatusenable, DHD_GET_VAR, DHD_SET_VAR,309"enable/disable the proptxtstatus feature\n"310"0 - disabled\n"311"1 - enabled\n"},312{ "ptxmode", dhd_proptxstatusmode, DHD_GET_VAR, DHD_SET_VAR,313"set the proptxtstatus operation mode:\n"314"0 - Unsupported\n"315"1 - Use implied credit from a packet status\n"316"2 - Use explicit credit\n" },317#endif318{ "sd_uhsimode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR,319"g/set UHSI Mode"},320{ NULL, NULL, 0, 0, NULL }321};322323cmd_t dhd_varcmd = {"var", dhd_varint, -1, -1, "unrecognized name, type -h for help"};324char *dhdu_av0;325326#if defined(BWL_FILESYSTEM_SUPPORT)327static int328file_size(char *fname)329{330FILE *fp;331long size = -1;332333/* Can't use stat() because of Win CE */334335if ((fp = fopen(fname, "rb")) == NULL ||336fseek(fp, 0, SEEK_END) < 0 ||337(size = ftell(fp)) < 0)338fprintf(stderr, "Could not determine size of %s: %s\n",339fname, strerror(errno));340341if (fp != NULL)342fclose(fp);343344return (int)size;345}346#endif /* BWL_FILESYSTEM_SUPPORT */347348349/* parse/validate the command line arguments */350/*351* pargv is updated upon return if the first argument is an option.352* It remains intact otherwise.353*/354int355dhd_option(char ***pargv, char **pifname, int *phelp)356{357char *ifname = NULL;358int help = FALSE;359int status = CMD_OPT;360char **argv = *pargv;361362int_fmt = INT_FMT_DEC;363364while (*argv) {365/* select different adapter */366if (!strcmp(*argv, "-a") || !strcmp(*argv, "-i")) {367char *opt = *argv++;368ifname = *argv;369if (!ifname) {370fprintf(stderr,371"error: expected interface name after option %s\n", opt);372status = CMD_ERR;373break;374}375}376377/* integer output format */378else if (!strcmp(*argv, "-d"))379int_fmt = INT_FMT_DEC;380else if (!strcmp(*argv, "-u"))381int_fmt = INT_FMT_UINT;382else if (!strcmp(*argv, "-x"))383int_fmt = INT_FMT_HEX;384385/* command usage */386else if (!strcmp(*argv, "-h"))387help = TRUE;388389/* done with generic options */390else {391status = CMD_DHD;392break;393}394395/* consume the argument */396argv ++;397break;398}399400*phelp = help;401*pifname = ifname;402*pargv = argv;403404return status;405}406407void408dhd_cmd_usage(cmd_t *cmd)409{410if (strlen(cmd->name) >= 8)411fprintf(stderr, "%s\n\t%s\n\n", cmd->name, cmd->help);412else413fprintf(stderr, "%s\t%s\n\n", cmd->name, cmd->help);414}415416/* Dump out short list of commands */417static int418dhd_list(void *dhd, cmd_t *garb, char **argv)419{420cmd_t *cmd;421int nrows, i, len;422char *buf;423int letter, col, row, pad;424425UNUSED_PARAMETER(dhd);426UNUSED_PARAMETER(garb);427UNUSED_PARAMETER(argv);428429for (cmd = dhd_cmds, nrows = 0; cmd->name; cmd++)430nrows++;431432nrows /= 4;433nrows++;434435len = nrows * 80 + 2;436buf = malloc(len);437if (buf == NULL) {438fprintf(stderr, "Failed to allocate buffer of %d bytes\n", len);439return COMMAND_ERROR;440}441for (i = 0; i < len; i++)442*(buf+i) = 0;443444row = col = 0;445for (letter = 'a'; letter < 'z'; letter++) {446for (cmd = dhd_cmds; cmd->name; cmd++) {447if (cmd->name[0] == letter || cmd->name[0] == letter - 0x20) {448strcat(buf+row*80, cmd->name);449pad = 18 * (col + 1) - strlen(buf+row*80);450if (pad < 1)451pad = 1;452for (; pad; pad--)453strcat(buf+row*80, " ");454row++;455if (row == nrows) {456col++; row = 0;457}458}459}460}461for (row = 0; row < nrows; row++)462printf("%s\n", buf+row*80);463464printf("\n");465free(buf);466return (0);467}468469void470dhd_cmds_usage(cmd_t *port_cmds)471{472cmd_t *port_cmd;473cmd_t *cmd;474475/* print usage of port commands */476for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)477/* Check for wc_cmd */478dhd_cmd_usage(port_cmd);479480/* print usage of common commands without port counterparts */481for (cmd = dhd_cmds; cmd->name; cmd++) {482/* search if port counterpart exists */483for (port_cmd = port_cmds; port_cmd && port_cmd->name; port_cmd++)484if (!strcmp(port_cmd->name, cmd->name))485break;486if (!port_cmd || !port_cmd->name)487dhd_cmd_usage(cmd);488}489}490491void492dhd_usage(cmd_t *port_cmds)493{494fprintf(stderr,495"Usage: %s [-a|i <adapter>] [-h] [-d|u|x] <command> [arguments]\n",496dhdu_av0);497498fprintf(stderr, "\n");499fprintf(stderr, " -h this message\n");500fprintf(stderr, " -a, -i adapter name or number\n");501fprintf(stderr, " -d display values as signed integer\n");502fprintf(stderr, " -u display values as unsigned integer\n");503fprintf(stderr, " -x display values as hexdecimal\n");504fprintf(stderr, "\n");505506dhd_cmds_usage(port_cmds);507}508509int510dhd_check(void *dhd)511{512int ret;513int val;514515if ((ret = dhd_get(dhd, DHD_GET_MAGIC, &val, sizeof(int)) < 0))516return ret;517if (val != DHD_IOCTL_MAGIC)518return -1;519if ((ret = dhd_get(dhd, DHD_GET_VERSION, &val, sizeof(int)) < 0))520return ret;521if (val > DHD_IOCTL_VERSION) {522fprintf(stderr, "Version mismatch, please upgrade\n");523return -1;524}525return 0;526}527528void529dhd_printint(int val)530{531switch (int_fmt) {532case INT_FMT_UINT:533printf("%u\n", val);534break;535case INT_FMT_HEX:536printf("0x%x\n", val);537break;538case INT_FMT_DEC:539default:540printf("%d\n", val);541break;542}543}544545/* pretty hex print a contiguous buffer (tweaked from wlu) */546void547dhd_hexdump(uchar *buf, uint nbytes, uint saddr)548{549char line[256];550char* p;551uint i;552553if (nbytes == 0) {554printf("\n");555return;556}557558p = line;559for (i = 0; i < nbytes; i++) {560if (i % 16 == 0) {561p += sprintf(p, "%08x: ", saddr + i); /* line prefix */562}563p += sprintf(p, "%02x ", buf[i]);564if (i % 16 == 15) {565uint j;566p += sprintf(p, " ");567for (j = i-15; j <= i; j++)568p += sprintf(p, "%c",569((buf[j] >= 0x20 && buf[j] <= 0x7f) ? buf[j] : '.'));570printf("%s\n", line); /* flush line */571p = line;572}573}574575/* flush last partial line */576if (p != line)577printf("%s\n", line);578}579580581#ifdef SDTEST582static int583dhd_pktgen(void *dhd, cmd_t *cmd, char **argv)584{585int ret = 0;586void *ptr = NULL;587dhd_pktgen_t pktgen;588char *str;589590UNUSED_PARAMETER(dhd);591UNUSED_PARAMETER(cmd);592593/* Get current settings */594if ((ret = dhd_var_getbuf(dhd, "pktgen", NULL, 0, &ptr)) != 0)595return ret;596memcpy(&pktgen, ptr, sizeof(pktgen));597598if (pktgen.version != DHD_PKTGEN_VERSION) {599fprintf(stderr, "pktgen version mismatch (module %d app %d)\n",600pktgen.version, DHD_PKTGEN_VERSION);601return COMMAND_ERROR;602}603604/* Presence of args implies a set, else a get */605if (*++argv) {606miniopt_t opts;607int opt_err;608609/* Initialize option parser */610miniopt_init(&opts, "pktgen", "", FALSE);611612while ((opt_err = miniopt(&opts, argv)) != -1) {613if (opt_err == 1) {614fprintf(stderr, "pktgen options error\n");615ret = -1;616goto exit;617}618argv += opts.consumed;619620if (!opts.good_int && opts.opt != 'd') {621fprintf(stderr, "invalid integer %s\n", opts.valstr);622ret = -1;623goto exit;624}625626switch (opts.opt) {627case 'f':628pktgen.freq = opts.uval;629break;630case 'c':631pktgen.count = opts.uval;632break;633case 'p':634pktgen.print = opts.uval;635break;636case 't':637pktgen.total = opts.uval;638break;639case 's':640pktgen.stop = opts.uval;641break;642case 'm':643pktgen.minlen = opts.uval;644break;645case 'M':646pktgen.maxlen = opts.uval;647break;648case 'l': case 'L':649pktgen.minlen = pktgen.maxlen = opts.uval;650break;651case 'd':652if (!strcmp(opts.valstr, "send"))653pktgen.mode = DHD_PKTGEN_SEND;654else if (!strcmp(opts.valstr, "echo"))655pktgen.mode = DHD_PKTGEN_ECHO;656else if (!strcmp(opts.valstr, "burst"))657pktgen.mode = DHD_PKTGEN_RXBURST;658else if (!strcmp(opts.valstr, "recv"))659pktgen.mode = DHD_PKTGEN_RECV;660else {661fprintf(stderr, "unrecognized dir mode %s\n",662opts.valstr);663return USAGE_ERROR;664}665break;666667default:668fprintf(stderr, "option parsing error (key %s valstr %s)\n",669opts.key, opts.valstr);670ret = USAGE_ERROR;671goto exit;672}673}674675if (pktgen.maxlen < pktgen.minlen) {676fprintf(stderr, "min/max error (%d/%d)\n", pktgen.minlen, pktgen.maxlen);677ret = -1;678goto exit;679}680681/* Set the new values */682ret = dhd_var_setbuf(dhd, "pktgen", &pktgen, sizeof(pktgen));683} else {684printf("Counts: %d send attempts, %d received, %d tx failures\n",685pktgen.numsent, pktgen.numrcvd, pktgen.numfail);686}687688/* Show configuration in either case */689switch (pktgen.mode) {690case DHD_PKTGEN_ECHO: str = "echo"; break;691case DHD_PKTGEN_SEND: str = "send"; break;692case DHD_PKTGEN_RECV: str = "recv"; break;693case DHD_PKTGEN_RXBURST: str = "burst"; break;694default: str = "UNKNOWN"; break;695}696697printf("Config: mode %s %d pkts (len %d-%d) each %d ticks\n",698str, pktgen.count, pktgen.minlen, pktgen.maxlen, pktgen.freq);699700/* Second config line for optional items */701str = " ";702if (pktgen.total) {703printf("%slimit %d", str, pktgen.total);704str = ", ";705}706if (pktgen.print) {707printf("%sprint every %d ticks", str, (pktgen.freq * pktgen.print));708str = ", ";709}710if (pktgen.stop) {711printf("%sstop after %d tx failures", str, pktgen.stop);712str = ", ";713}714if (str[0] == ',')715printf("\n");716717exit:718return ret;719}720#endif /* SDTEST */721722static dbg_msg_t dhd_sd_msgs[] = {723{SDH_ERROR_VAL, "error"},724{SDH_TRACE_VAL, "trace"},725{SDH_INFO_VAL, "info"},726{SDH_DATA_VAL, "data"},727{SDH_CTRL_VAL, "control"},728{SDH_LOG_VAL, "log"},729{SDH_DMA_VAL, "dma"},730{0, NULL}731};732733static int734dhd_sd_msglevel(void *dhd, cmd_t *cmd, char **argv)735{736return dhd_do_msglevel(dhd, cmd, argv, dhd_sd_msgs);737}738739static int740dhd_sd_blocksize(void *dhd, cmd_t *cmd, char **argv)741{742int ret;743int argc;744char *endptr = NULL;745void *ptr = NULL;746int func, size;747748/* arg count */749for (argc = 0; argv[argc]; argc++);750argc--;751752if (argc < 1 || argc > 2) {753printf("required args: function [size] (size 0 means max)\n");754return USAGE_ERROR;755}756757func = strtol(argv[1], &endptr, 0);758if (*endptr != '\0') {759printf("Invalid function: %s\n", argv[1]);760return USAGE_ERROR;761}762763if (argc > 1) {764size = strtol(argv[2], &endptr, 0);765if (*endptr != '\0') {766printf("Invalid size: %s\n", argv[1]);767return USAGE_ERROR;768}769}770771if (argc == 1) {772if ((ret = dhd_var_getbuf(dhd, cmd->name, &func, sizeof(func), &ptr)) >= 0)773printf("Function %d block size: %d\n", func, *(int*)ptr);774} else {775printf("Setting function %d block size to %d\n", func, size);776size &= 0x0000ffff; size |= (func << 16);777ret = dhd_var_setbuf(dhd, cmd->name, &size, sizeof(size));778}779780return (ret);781}782783static int784dhd_sd_mode(void *wl, cmd_t *cmd, char **argv)785{786int ret;787int argc;788int sdmode;789790/* arg count */791for (argc = 0; argv[argc]; argc++);792argc--;793794if (argv[1]) {795if (!strcmp(argv[1], "spi")) {796strcpy(argv[1], "0");797} else if (!strcmp(argv[1], "sd1")) {798strcpy(argv[1], "1");799} else if (!strcmp(argv[1], "sd4")) {800strcpy(argv[1], "2");801} else {802return USAGE_ERROR;803}804805ret = dhd_var_setint(wl, cmd, argv);806807} else {808if ((ret = dhd_var_get(wl, cmd, argv))) {809return (ret);810} else {811sdmode = *(int32*)buf;812813printf("SD Mode is: %s\n",814sdmode == 0 ? "SPI"815: sdmode == 1 ? "SD1"816: sdmode == 2 ? "SD4" : "Unknown");817}818}819820return (ret);821}822823static int824dhd_dma_mode(void *wl, cmd_t *cmd, char **argv)825{826int ret;827int argc;828int dmamode;829830/* arg count */831for (argc = 0; argv[argc]; argc++);832argc--;833834if (argv[1]) {835if (!stricmp(argv[1], "pio")) {836strcpy(argv[1], "0");837} else if (!strcmp(argv[1], "0")) {838} else if (!stricmp(argv[1], "dma")) {839strcpy(argv[1], "1");840} else if (!stricmp(argv[1], "sdma")) {841strcpy(argv[1], "1");842} else if (!strcmp(argv[1], "1")) {843} else if (!stricmp(argv[1], "adma1")) {844strcpy(argv[1], "2");845} else if (!stricmp(argv[1], "adma")) {846strcpy(argv[1], "3");847} else if (!stricmp(argv[1], "adma2")) {848strcpy(argv[1], "3");849} else {850return USAGE_ERROR;851}852853ret = dhd_var_setint(wl, cmd, argv);854855} else {856if ((ret = dhd_var_get(wl, cmd, argv))) {857return (ret);858} else {859dmamode = *(int32*)buf;860861printf("DMA Mode is: %s\n",862dmamode == 0 ? "PIO"863: dmamode == 1 ? "SDMA"864: dmamode == 2 ? "ADMA1"865: dmamode == 3 ? "ADMA2"866: "Unknown");867}868}869870return (ret);871}872873874static int875dhd_sdreg(void *dhd, cmd_t *cmd, char **argv)876{877int ret;878sdreg_t sdreg;879uint argc;880char *ptr = NULL;881882UNUSED_PARAMETER(cmd);883884bzero(&sdreg, sizeof(sdreg));885886/* arg count */887for (argc = 0; argv[argc]; argc++);888argc--;889890/* required args: offset (will default size) */891if (argc < 1) {892printf("required args: offset[/size] [value]\n");893return USAGE_ERROR;894}895896sdreg.offset = strtoul(argv[1], &ptr, 0);897if (*ptr && *ptr != '/') {898printf("Bad arg: %s\n", argv[1]);899return USAGE_ERROR;900}901902/* read optional /size */903if (*ptr == '/') {904sdreg.func = strtol((ptr+1), &ptr, 0);905if (*ptr || ((sdreg.func != 2) && sdreg.func != 4)) {906printf("Bad size option?\n");907return USAGE_ERROR;908}909}910else {911sdreg.func = 4;912printf("Defaulting to register size 4\n");913}914915if (argc > 1) {916sdreg.value = strtoul(argv[2], &ptr, 0);917if (*ptr) {918printf("Bad value: %s\n", argv[2]);919return USAGE_ERROR;920}921}922923if (argc <= 1) {924ret = dhd_var_getbuf(dhd, argv[0], &sdreg, sizeof(sdreg), (void**)&ptr);925if (ret >= 0)926printf("0x%0*x\n", (2 * sdreg.func), *(int *)ptr);927} else {928ret = dhd_var_setbuf(dhd, argv[0], &sdreg, sizeof(sdreg));929}930931return (ret);932}933934static int935dhd_membytes(void *dhd, cmd_t *cmd, char **argv)936{937int ret = -1;938uint argc;939char *ptr;940int params[2];941uint addr;942uint len;943int align;944945int rawout, hexin;946947miniopt_t opts;948int opt_err;949950/* Parse command-line options */951miniopt_init(&opts, "membytes", "rh", FALSE);952953rawout = hexin = 0;954955argv++;956while ((opt_err = miniopt(&opts, argv)) != -1) {957if (opt_err == 1) {958fprintf(stderr, "membytes options error\n");959ret = -1;960goto exit;961}962963if (opts.positional)964break;965966argv += opts.consumed;967968if (opts.opt == 'h') {969hexin = 1;970} else if (opts.opt == 'r') {971rawout = 1;972} else {973fprintf(stderr, "membytes command error\n");974ret = -1;975goto exit;976}977}978979/* arg count */980for (argc = 0; argv[argc]; argc++);981982/* required args: address size [<bytes>]] */983if (argc < 2) {984fprintf(stderr, "required args: address size [<bytes>]\n");985return USAGE_ERROR;986}987if (argc < 3 && hexin) {988fprintf(stderr, "missing <bytes> arg implies by -h\n");989return USAGE_ERROR;990}991if ((argc > 2) && (rawout)) {992fprintf(stderr, "can't have input <bytes> arg with -r or -i\n");993return USAGE_ERROR;994}995996/* read address */997addr = strtoul(argv[0], &ptr, 0);998if (*ptr) {999fprintf(stderr, "Bad arg: %s\n", argv[0]);1000return USAGE_ERROR;1001}10021003/* read size */1004len = strtoul(argv[1], &ptr, 0);1005if (*ptr) {1006fprintf(stderr, "Bad value: %s\n", argv[1]);1007return USAGE_ERROR;1008}10091010align = addr & 0x03;1011if (align && argc > 2) {1012fprintf(stderr, "Can only write starting at long-aligned addresses.\n");1013return USAGE_ERROR;1014}10151016/* get can just use utility function, set must copy custom buffer */1017if (argc == 2) {1018uint chunk = DHD_IOCTL_MAXLEN;1019for (addr -= align, len += align; len; addr += chunk, len -= chunk, align = 0) {1020chunk = MIN(chunk, len);1021params[0] = addr; params[1] = ROUNDUP(chunk, 4);1022ret = dhd_var_getbuf(dhd, "membytes",1023params, (2 * sizeof(int)), (void**)&ptr);1024if (ret < 0)1025goto exit;10261027if (rawout) {1028fwrite(ptr + align, sizeof(char), chunk - align, stdout);1029} else {1030dhd_hexdump((uchar*)ptr + align, chunk - align, addr + align);1031}1032}1033} else {1034uint patlen = strlen(argv[2]);1035uint chunk, maxchunk;1036char *sptr;10371038if (hexin) {1039char *inptr, *outptr;1040if (patlen & 1) {1041fprintf(stderr, "Hex (-h) must consist of whole bytes\n");1042ret = USAGE_ERROR;1043goto exit;1044}10451046for (inptr = outptr = argv[2]; patlen; patlen -= 2) {1047int n1, n2;10481049n1 = (int)((unsigned char)*inptr++);1050n2 = (int)((unsigned char)*inptr++);1051if (!isxdigit(n1) || !isxdigit(n2)) {1052fprintf(stderr, "invalid hex digit %c\n",1053(isxdigit(n1) ? n2 : n1));1054ret = USAGE_ERROR;1055goto exit;1056}1057n1 = isdigit(n1) ? (n1 - '0')1058: ((islower(n1) ? (toupper(n1)) : n1) - 'A' + 10);1059n2 = isdigit(n2) ? (n2 - '0')1060: ((islower(n2) ? (toupper(n2)) : n2) - 'A' + 10);1061*outptr++ = (n1 * 16) + n2;1062}10631064patlen = outptr - argv[2];1065}10661067sptr = argv[2];1068maxchunk = DHD_IOCTL_MAXLEN - (strlen(cmd->name) + 1 + (2 * sizeof(int)));10691070while (len) {1071chunk = (len > maxchunk) ? (maxchunk & ~0x3) : len;10721073/* build the iovar command */1074memset(buf, 0, DHD_IOCTL_MAXLEN);1075strcpy(buf, cmd->name);1076ptr = buf + strlen(buf) + 1;1077params[0] = addr; params[1] = chunk;1078memcpy(ptr, params, (2 * sizeof(int)));1079ptr += (2 * sizeof(int));1080addr += chunk; len -= chunk;10811082while (chunk--) {1083*ptr++ = *sptr++;1084if (sptr >= (argv[2] + patlen))1085sptr = argv[2];1086}10871088ret = dhd_set(dhd, DHD_SET_VAR, &buf[0], (ptr - buf));1089if (ret < 0)1090goto exit;1091}1092}10931094exit:1095return ret;1096}10971098static int1099dhd_idletime(void *dhd, cmd_t *cmd, char **argv)1100{1101int32 idletime;1102char *endptr = NULL;1103int err = 0;11041105if (argv[1]) {1106if (!strcmp(argv[1], "never")) {1107idletime = 0;1108} else if (!strcmp(argv[1], "immediate") || !strcmp(argv[1], "immed")) {1109idletime = DHD_IDLE_IMMEDIATE;1110} else {1111idletime = strtol(argv[1], &endptr, 0);1112if (*endptr != '\0') {1113fprintf(stderr, "invalid number %s\n", argv[1]);1114err = -1;1115}1116}1117if ((idletime < 0) && (idletime != DHD_IDLE_IMMEDIATE)) {1118fprintf(stderr, "invalid value %s\n", argv[1]);1119err = -1;1120}11211122if (!err) {1123strcpy(buf, "idletime");1124endptr = buf + strlen(buf) + 1;1125memcpy(endptr, &idletime, sizeof(uint32));1126endptr += sizeof(uint32);1127err = dhd_set(dhd, DHD_SET_VAR, &buf[0], (endptr - buf));1128}1129} else {1130if ((err = dhd_var_get(dhd, cmd, argv))) {1131return err;1132} else {1133idletime = *(int32*)buf;11341135if (idletime == 0) {1136printf("0 (never)\n");1137} else if (idletime == DHD_IDLE_IMMEDIATE) {1138printf("-1 (immediate)\n");1139} else if (idletime > 0) {1140printf("%d\n", idletime);1141} else printf("%d (invalid)\n", idletime);1142}1143}1144return err;1145}11461147static int1148dhd_idleclock(void *dhd, cmd_t *cmd, char **argv)1149{1150int32 idleclock;1151char *endptr = NULL;1152int err = 0;11531154if (argv[1]) {1155if (!strcmp(argv[1], "active")) {1156idleclock = DHD_IDLE_ACTIVE;1157} else if (!strcmp(argv[1], "stopped")) {1158idleclock = DHD_IDLE_STOP;1159} else {1160idleclock = strtol(argv[1], &endptr, 0);1161if (*endptr != '\0') {1162fprintf(stderr, "invalid number %s\n", argv[1]);1163err = USAGE_ERROR;1164}1165}11661167if (!err) {1168strcpy(buf, "idleclock");1169endptr = buf + strlen(buf) + 1;1170memcpy(endptr, &idleclock, sizeof(int32));1171endptr += sizeof(int32);1172err = dhd_set(dhd, DHD_SET_VAR, &buf[0], (endptr - buf));1173}1174} else {1175if ((err = dhd_var_get(dhd, cmd, argv))) {1176return err;1177} else {1178idleclock = *(int32*)buf;11791180if (idleclock == DHD_IDLE_ACTIVE)1181printf("Idleclock %d (active)\n", idleclock);1182else if (idleclock == DHD_IDLE_STOP)1183printf("Idleclock %d (stopped)\n", idleclock);1184else1185printf("Idleclock divisor %d\n", idleclock);1186}1187}1188return err;1189}11901191/* Word count for a 4kb SPROM */1192#define SPROM_WORDS 25611931194static int1195dhd_sprom(void *dhd, cmd_t *cmd, char **argv)1196{1197#if !defined(BWL_FILESYSTEM_SUPPORT)1198return (-1);1199#else1200int ret, i;1201uint argc;1202char *endptr;1203char *bufp, *countptr;1204uint16 *wordptr;1205uint offset, words, bytes;1206bool nocrc = FALSE;12071208char *fname;1209FILE *fp;12101211UNUSED_PARAMETER(cmd);12121213/* arg count */1214for (argc = 0; argv[argc]; argc++);1215argc--;12161217/* init buffer */1218bufp = buf;1219memset(bufp, 0, DHD_IOCTL_MAXLEN);1220strcpy(bufp, "sprom");1221bufp += strlen("sprom") + 1;12221223if (strcmp(argv[0], "srdump") == 0) {1224if (argc) {1225fprintf(stderr, "Command srdump doesn't take args\n");1226return USAGE_ERROR;1227}1228offset = 0;1229words = SPROM_WORDS;1230bytes = 2 * words;12311232memcpy(bufp, &offset, sizeof(int));1233bufp += sizeof(int);1234memcpy(bufp, &bytes, sizeof(int));1235bufp += sizeof(int);12361237if (!ISALIGNED(bufp, sizeof(uint16))) {1238fprintf(stderr, "Internal error: unaligned word buffer\n");1239return COMMAND_ERROR;1240}1241} else {1242if (strcmp(argv[0], "srwrite") != 0) {1243fprintf(stderr, "Unimplemented sprom command: %s\n", argv[0]);1244return USAGE_ERROR;1245}12461247if (argc == 0) {1248return USAGE_ERROR;1249} else if ((argc == 1) ||1250((argc == 2) && ((nocrc = !strcmp(argv[1], "-c"))))) {12511252fname = nocrc ? argv[2] : argv[1];12531254/* determine and validate file size */1255if ((ret = file_size(fname)) < 0)1256return COMMAND_ERROR;12571258bytes = ret;1259offset = 0;1260words = bytes / 2;12611262if (bytes != 2 * SPROM_WORDS) {1263fprintf(stderr, "Bad file size\n");1264return COMMAND_ERROR;1265}12661267memcpy(bufp, &offset, sizeof(int));1268bufp += sizeof(int);1269memcpy(bufp, &bytes, sizeof(int));1270bufp += sizeof(int);12711272if (!ISALIGNED(bufp, sizeof(uint16))) {1273fprintf(stderr, "Internal error: unaligned word buffer\n");1274return COMMAND_ERROR;1275}12761277if ((fp = fopen(fname, "rb")) == NULL) {1278fprintf(stderr, "Could not open %s: %s\n",1279fname, strerror(errno));1280return COMMAND_ERROR;1281}12821283if (fread((uint16*)bufp, sizeof(uint16), words, fp) != words) {1284fprintf(stderr, "Could not read %d bytes from %s\n",1285words * 2, fname);1286fclose(fp);1287return COMMAND_ERROR;1288}12891290fclose(fp);12911292if (!nocrc &&1293hndcrc8((uint8*)bufp, bytes, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE) {1294fprintf(stderr, "CRC check failed: 0x%02x, should be 0x%02x.\n",1295((uint8*)bufp)[bytes-1],1296~hndcrc8((uint8*)bufp, bytes - 1, CRC8_INIT_VALUE) & 0xff);1297return COMMAND_ERROR;1298}12991300ltoh16_buf(bufp, bytes);1301} else {1302offset = strtoul(*++argv, &endptr, 0) * 2;1303if (*endptr != '\0') {1304fprintf(stderr, "offset %s is not an integer\n", *argv);1305return USAGE_ERROR;1306}13071308memcpy(bufp, &offset, sizeof(int));1309bufp += sizeof(int);1310countptr = bufp;1311bufp += sizeof(int);13121313if (!ISALIGNED(bufp, sizeof(uint16))) {1314fprintf(stderr, "Internal error: unaligned word buffer\n");1315return COMMAND_ERROR;1316}13171318for (words = 0, wordptr = (uint16*)bufp; *++argv; words++) {1319*wordptr++ = (uint16)strtoul(*argv, &endptr, 0);1320if (*endptr != '\0') {1321fprintf(stderr, "value %s is not an integer\n", *argv);1322return USAGE_ERROR;1323}1324if (words > SPROM_WORDS) {1325fprintf(stderr, "max of %d words\n", SPROM_WORDS);1326return USAGE_ERROR;1327}1328}13291330bytes = 2 * words;1331memcpy(countptr, &bytes, sizeof(int));1332}1333}13341335if (argc) {1336ret = dhd_set(dhd, DHD_SET_VAR, buf,1337(strlen("sprom") + 1) + (2 * sizeof(int)) + bytes);1338return (ret);1339} else {1340ret = dhd_get(dhd, DHD_GET_VAR, buf,1341(strlen("sprom") + 1) + (2 * sizeof(int)) + bytes);1342if (ret < 0) {1343return ret;1344}13451346for (i = 0; i < (int)words; i++) {1347if ((i % 8) == 0)1348printf("\n srom[%03d]: ", i);1349printf("0x%04x ", ((uint16*)buf)[i]);1350}1351printf("\n");1352}13531354return 0;1355#endif /* BWL_FILESYSTEM_SUPPORT */1356}13571358/*1359* read_vars: reads an environment variables file into a buffer,1360* reformatting them and returning the length (-1 on error).1361*1362* The input text file consists of lines of the form "<var>=<value>\n".1363* CRs are ignored, as are blank lines and comments beginning with '#'.1364*1365* The output buffer consists of blocks of the form "<var>=<value>\0"1366* (the newlines have been replaced by NULs)1367*1368* Todo: allow quoted variable names and quoted values.1369*/13701371#if defined(BWL_FILESYSTEM_SUPPORT)1372static int1373read_vars(char *fname, char *buf, int buf_maxlen)1374{1375FILE *fp;1376int buf_len, slen;1377char line[256], *s, *e;1378int line_no = 0;13791380if ((fp = fopen(fname, "rb")) == NULL) {1381fprintf(stderr, "Cannot open NVRAM file %s: %s\n",1382fname, strerror(errno));1383exit(1);1384}13851386buf_len = 0;13871388while (fgets(line, sizeof(line), fp) != NULL) {1389bool found_eq = FALSE;13901391/* Ensure line length is limited */1392line[sizeof(line) - 1] = 0;13931394/* Skip any initial white space */1395for (s = line; *s == ' ' || *s == '\t'; s++)1396;13971398/* Determine end of string */1399for (e = s; *e != 0 && *e != '#' && *e != '\r' && *e != '\n'; e++)1400if (*e == '=')1401found_eq = TRUE;14021403/* Strip any white space from end of string */1404while (e > s && (e[-1] == ' ' || e[-1] == '\t'))1405e--;14061407slen = e - s;14081409/* Skip lines that end up blank */1410if (slen == 0)1411continue;14121413if (!found_eq) {1414fprintf(stderr, "Invalid line %d in NVRAM file %s\n", line_no, fname);1415fclose(fp);1416return -1;1417}14181419if (buf_len + slen + 1 > buf_maxlen) {1420fprintf(stderr, "NVRAM file %s too long\n", fname);1421fclose(fp);1422return -1;1423}14241425memcpy(buf + buf_len, s, slen);1426buf_len += slen;1427buf[buf_len++] = 0;1428}14291430fclose(fp);14311432return buf_len;1433}1434#endif /* BWL_FILESYSTEM_SUPPORT */14351436static int1437dhd_vars(void *dhd, cmd_t *cmd, char **argv)1438{1439int ret;1440uint argc;1441char *bufp;14421443UNUSED_PARAMETER(cmd);14441445/* arg count */1446for (argc = 0; argv[argc]; argc++);1447argc--;14481449switch (argc) {1450case 0: /* get */1451{1452if ((ret = dhd_var_getbuf(dhd, "vars", NULL, 0, (void**)&bufp)))1453break;1454while (*bufp) {1455printf("%s\n", bufp);1456bufp += strlen(bufp) + 1;1457}1458}1459break;14601461#if defined(BWL_FILESYSTEM_SUPPORT)1462case 1: /* set */1463{1464char *vname;1465uint nvram_len;14661467vname = argv[1];14681469bufp = buf;1470strcpy(bufp, "vars");1471bufp += strlen("vars") + 1;14721473if ((ret = read_vars(vname, bufp,1474DHD_IOCTL_MAXLEN - (strlen("vars") + 3))) < 0) {1475ret = -1;1476break;1477}14781479nvram_len = ret;1480bufp += nvram_len;1481*bufp++ = 0;14821483ret = dhd_set(dhd, DHD_SET_VAR, buf, bufp - buf);1484}1485break;1486#endif /* BWL_FILESYSTEM_SUPPORT */14871488default:1489ret = -1;1490break;1491}14921493return ret;1494}14951496#define MEMBLOCK 204814971498/* Check that strlen("membytes")+1 + 2*sizeof(int32) + MEMBLOCK <= DHD_IOCTL_MAXLEN */1499#if (MEMBLOCK + 17 > DHD_IOCTL_MAXLEN)1500#error MEMBLOCK/DHD_IOCTL_MAXLEN sizing1501#endif150215031504#if defined(BWL_FILESYSTEM_SUPPORT)1505static int1506dhd_verify_file_bytes(void *dhd, uint8 *memblock, int start, uint len)1507{1508int ret = 0, i;1509char *ptr;1510int params[2];1511uint8 *src, *dst;15121513params[0] = start;1514params[1] = len;1515ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);1516if (ret) {1517fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",1518__FUNCTION__, len, start);1519return -1;1520}15211522src = (uint8 *)memblock;1523dst = (uint8 *)ptr;1524while (i < len) {1525if (src[i] != dst[i]) {1526fprintf(stderr, " 0x%x: exp[0x%02X] != got[0x%02X]\n",1527start+i, src[i], dst[i]);1528ret = -1;1529}1530i++;1531}15321533return ret;1534}15351536static int1537dhd_load_file_bytes(void *dhd, cmd_t *cmd, FILE *fp, int fsize, int start, uint blk_sz, bool verify)1538{1539int tot_len = 0;1540uint read_len;1541char *bufp;1542uint len;1543uint8 memblock[MEMBLOCK];1544int ret;15451546UNUSED_PARAMETER(cmd);15471548if (!fsize || !fp)1549return -1;15501551assert(blk_sz <= MEMBLOCK);15521553while (tot_len < fsize) {1554read_len = fsize - tot_len;1555if (read_len >= blk_sz) {1556read_len = blk_sz;15571558if (!ISALIGNED(start, MEMBLOCK))1559read_len = ROUNDUP(start, MEMBLOCK) - start;1560}15611562len = fread(memblock, sizeof(uint8), read_len, fp);1563if ((len < read_len) && !feof(fp)) {1564fprintf(stderr, "%s: error reading file\n", __FUNCTION__);1565return -1;15661567}15681569bufp = buf;1570memset(bufp, 0, DHD_IOCTL_MAXLEN);1571strcpy(bufp, "membytes");1572bufp += strlen("membytes") + 1;1573memcpy(bufp, &start, sizeof(int));1574bufp += sizeof(int);1575memcpy(bufp, &len, sizeof(int));1576bufp += sizeof(int);1577memcpy(bufp, memblock, len);15781579ret = dhd_set(dhd, DHD_SET_VAR, &buf[0], (bufp - buf + len));15801581if (ret) {1582fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",1583__FUNCTION__, ret, len, start);1584return -1;1585}15861587if (verify == TRUE) {1588if (len & 1)1589len = ROUNDUP(len, 2);15901591if (dhd_verify_file_bytes(dhd, memblock, start, len) != 0) {1592fprintf(stderr, "%s: verify failed %d membytes "1593"from 0x%08x\n",1594__FUNCTION__, len, start);1595}1596}15971598start += len;1599tot_len += len;1600}1601return 0;1602}1603#endif /* BWL_FILESYSTEM_SUPPORT */16041605#ifdef PROP_TXSTATUS1606static int1607dhd_proptxstatusenable(void *dhd, cmd_t *cmd, char **argv)1608{1609int flag = 0xdead;16101611if (argv[1]) {1612flag = atoi(argv[1]);1613dhd_iovar_setint(dhd, cmd->name, flag);1614}1615else {1616dhd_iovar_getint(dhd, cmd->name, &flag);1617printf("proptxstatus: %d\n", flag);1618}1619return 0;1620}16211622static int1623dhd_proptxstatusmode(void *dhd, cmd_t *cmd, char **argv)1624{1625int mode = 0xdead;16261627if (argv[1]) {1628mode = atoi(argv[1]);1629dhd_iovar_setint(dhd, cmd->name, mode);1630}1631else {1632dhd_iovar_getint(dhd, cmd->name, &mode);1633printf("proptxstatusmode: %d\n", mode);1634}1635return 0;1636}1637#endif /* PROP_TXSTATUS */16381639static int1640dhd_download(void *dhd, cmd_t *cmd, char **argv)1641{1642#if !defined(BWL_FILESYSTEM_SUPPORT)1643return (-1);1644#else1645bool reset = TRUE;1646bool run = TRUE;1647bool verify = FALSE;1648char *fname = NULL;1649char *vname = NULL;1650uint32 start = 0;1651int ret = 0;1652int fsize;1653uint32 bustype;1654long filepos;16551656FILE *fp = NULL;1657uint32 memsize;1658char *memszargs[] = { "memsize", NULL };16591660char *bufp;16611662miniopt_t opts;1663int opt_err;1664uint nvram_len;1665struct trx_header trx_hdr;1666uint32 trx_hdr_len;1667bool trx_file = FALSE;1668uint memblock_sz = MEMBLOCK;1669bool embedded_ucode = FALSE;16701671UNUSED_PARAMETER(cmd);16721673/* Parse command-line options */1674miniopt_init(&opts, "download", "", TRUE);16751676argv++;1677while ((opt_err = miniopt(&opts, argv)) != -1) {1678if (opt_err == 1) {1679fprintf(stderr, "download options error\n");1680ret = -1;1681goto exit;1682}1683argv += opts.consumed;16841685if (opts.opt == 'a') {1686if (!opts.good_int) {1687fprintf(stderr, "invalid address %s\n", opts.valstr);1688ret = -1;1689goto exit;1690}1691start = (uint32)opts.uval;1692} else if (opts.positional) {1693if (fname && vname) {1694fprintf(stderr, "extra positional arg, %s\n",1695opts.valstr);1696ret = -1;1697goto exit;1698}1699if (fname)1700vname = opts.valstr;1701else1702fname = opts.valstr;1703} else if (!opts.opt) {1704if (!strcmp(opts.key, "noreset")) {1705reset = FALSE;1706} else if (!strcmp(opts.key, "norun")) {1707run = FALSE;1708} else if (!strcmp(opts.key, "verify")) {1709verify = TRUE;1710} else {1711fprintf(stderr, "unrecognized option %s\n", opts.valstr);1712ret = -1;1713goto exit;1714}1715} else {1716fprintf(stderr, "unrecognized option %c\n", opts.opt);1717ret = -1;1718goto exit;1719}1720}17211722/* validate arguments */1723if (!fname) {1724fprintf(stderr, "filename required\n");1725ret = -1;1726goto exit;1727}17281729/* validate file size compared to memory size */1730if ((fsize = file_size(fname)) < 0) {1731ret = -1;1732goto exit;1733}1734/* read the file and push blocks down to memory */1735if ((fp = fopen(fname, "rb")) == NULL) {1736fprintf(stderr, "%s: unable to open %s: %s\n",1737__FUNCTION__, fname, strerror(errno));1738ret = -1;1739goto exit;1740}1741/* Verify the file is a regular bin file or trx file */1742{1743uint32 tmp_len;1744trx_hdr_len = sizeof(struct trx_header);1745tmp_len = fread(&trx_hdr, sizeof(uint8), trx_hdr_len, fp);1746if (tmp_len == trx_hdr_len) {1747if (trx_hdr.magic == TRX_MAGIC) {1748trx_file = TRUE;1749if (trx_hdr.flag_version & TRX_EMBED_UCODE)1750embedded_ucode = TRUE;1751}1752else1753fseek(fp, 0, SEEK_SET);1754}1755else1756fseek(fp, 0, SEEK_SET);1757}17581759/* Check on which bus the dhd driver is sitting. Downloading methodology differs from1760* USB to SDIO.1761*/1762{1763char* bustype_args[] = {"bustype", NULL};17641765/* Read the bus type the DHD driver is associated to */1766if ((ret = dhd_var_get(dhd, NULL, bustype_args))) {1767fprintf(stderr, "%s: error obtaining bustype\n", __FUNCTION__);1768goto exit;1769}17701771bustype = *(uint32*)buf;1772}17731774if (trx_file)1775fsize = (int)(trx_hdr.offsets[0]);17761777if (BUS_TYPE_SDIO == bustype) {1778if ((ret = dhd_var_get(dhd, NULL, memszargs))) {1779fprintf(stderr, "%s: error obtaining memsize\n", __FUNCTION__);1780goto exit;1781}1782memsize = *(uint32*)buf;1783}178417851786BCM_REFERENCE(memsize);17871788/* do the download reset if not suppressed */1789if (reset) {1790if ((ret = dhd_iovar_setint(dhd, "dwnldstate", TRUE))) {1791fprintf(stderr, "%s: failed to put dongle in download mode\n",1792__FUNCTION__);1793goto exit;1794}1795}17961797if (BUS_TYPE_USB == bustype) {1798/* store the cur pos pointing to base image which should be written */1799filepos = ftell(fp);1800if (filepos == -1) {1801fprintf(stderr, "%s: ftell failed.\n", __FUNCTION__);1802}18031804/* In case of USB, we need to write header information also to dongle. */1805fseek(fp, 0, SEEK_SET);18061807/* The file size is "base_image + TRX_Header_size" */1808fsize = (int)(trx_hdr.offsets[0] + sizeof(struct trx_header));18091810memblock_sz = RDL_CHUNK;1811}181218131814/* Load the ram image */1815if (dhd_load_file_bytes(dhd, cmd, fp, fsize, start, memblock_sz, verify)) {1816fprintf(stderr, "%s: error loading the ramimage at addr 0x%x\n",1817__FUNCTION__, start);1818ret = -1;1819goto exit;1820}18211822if (trx_file) {18231824filepos = ftell(fp);1825if (filepos == -1) {1826fprintf(stderr, "%s: ftell failed.\n", __FUNCTION__);1827}18281829if (BUS_TYPE_SDIO == bustype) {18301831}1832}18331834fclose(fp);1835fp = NULL;18361837/* download the vars file if specified */1838if (vname) {1839bufp = buf;1840strcpy(bufp, "vars");1841bufp += strlen("vars") + 1;18421843if ((ret = read_vars(vname, bufp,1844DHD_IOCTL_MAXLEN - (strlen("vars") + 3))) < 0) {1845ret = -1;1846goto exit;1847}18481849nvram_len = ret;1850bufp += nvram_len;1851*bufp++ = 0;18521853ret = dhd_set(dhd, DHD_SET_VAR, buf, (bufp - buf));1854if (ret) {1855fprintf(stderr, "%s: error %d on delivering vars\n",1856__FUNCTION__, ret);1857goto exit;1858}1859}18601861/* start running the downloaded code if not suppressed */1862if (run) {1863if ((ret = dhd_iovar_setint(dhd, "dwnldstate", FALSE))) {18641865fprintf(stderr, "%s: failed to take dongle out of download mode\n",1866__FUNCTION__);1867/* USB Error return values */1868if (BUS_TYPE_USB == bustype) {1869if (ret == -1)1870fprintf(stderr, "%s: CPU is not in RUNNABLE State\n",1871__FUNCTION__);1872else1873fprintf(stderr, "%s: Error in setting CPU to RUN mode.\n",1874__FUNCTION__);1875}1876goto exit;1877}1878}1879if (embedded_ucode) {1880int retval;1881/* download the embedded ucode now */1882retval = proc_ucode_download(fname, dhd);1883if (retval != 0)1884printf("ucode & initvals download has failed\n");1885}18861887exit:1888if (fp)1889fclose(fp);18901891return ret;1892#endif /* BWL_FILESYSTEM_SUPPORT */1893}18941895static int1896dhd_dldn(void *dhd, cmd_t *cmd, char **argv)1897{1898#if !defined(BWL_FILESYSTEM_SUPPORT)1899return (-1);1900#else1901char *fname = NULL;1902uint32 start = 0;1903int ret = 0;1904int fsize;1905int fd = 0;19061907FILE *fp = NULL;1908uint32 memsize;19091910uint len;1911uint8 memblock[MEMBLOCK];19121913miniopt_t opts;1914int opt_err;19151916UNUSED_PARAMETER(cmd);19171918/* Parse command-line options */1919miniopt_init(&opts, "download", "", TRUE);1920argv++;19211922while ((opt_err = miniopt(&opts, argv)) != -1) {1923if (opt_err == 1) {1924fprintf(stderr, "download options error\n");1925ret = -1;1926goto exit;1927}1928argv += opts.consumed;19291930if (opts.positional) {1931if (fname) {1932fprintf(stderr, "extra positional arg, %s\n",1933opts.valstr);1934ret = -1;1935goto exit;1936}1937if (!fname)1938fname = opts.valstr;1939} else {1940fprintf(stderr, "unrecognized option %c\n", opts.opt);1941ret = -1;1942goto exit;1943}1944}19451946fd = dhd_set(dhd, DHD_DLDN_ST, NULL, 0);1947if (fd < 0) {1948ret = -1;1949goto exit;1950}19511952/* validate arguments */1953if (!fname) {1954fprintf(stderr, "filename required\n");1955ret = -1;1956goto exit;1957}19581959/* validate file size compared to memory size */1960if ((fsize = file_size(fname)) < 0) {1961ret = -1;1962goto exit;1963}19641965memsize = 393216;19661967if (memsize && ((uint32)fsize > memsize)) {1968fprintf(stderr, "%s: file %s too large (%d > %d)\n",1969__FUNCTION__, fname, fsize, memsize);1970ret = -1;1971goto exit;1972}19731974/* read the file and push blocks down to memory */1975if ((fp = fopen(fname, "rb")) == NULL) {1976fprintf(stderr, "%s: unable to open %s: %s\n",1977__FUNCTION__, fname, strerror(errno));1978ret = -1;1979goto exit;1980}19811982while ((len = fread(memblock, sizeof(uint8), MEMBLOCK, fp))) {1983if (len < MEMBLOCK && !feof(fp)) {1984fprintf(stderr, "%s: error reading file %s\n", __FUNCTION__, fname);1985ret = -1;1986goto exit;1987}19881989ret = dhd_set(dhd, DHD_DLDN_WRITE, memblock, len);1990if (ret) {1991fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n",1992__FUNCTION__, ret, len, start);1993goto exit;1994}19951996start += len;1997}19981999if (!feof(fp)) {2000fprintf(stderr, "%s: error reading file %s\n", __FUNCTION__, fname);2001ret = -1;2002goto exit;2003}2004fclose(fp);2005fp = NULL;20062007exit:2008if (fp)2009fclose(fp);20102011if (fd)2012dhd_set(dhd, DHD_DLDN_END, NULL, 0);20132014return ret;2015#endif /* BWL_FILESYSTEM_SUPPORT */2016}20172018static int2019dhd_upload(void *dhd, cmd_t *cmd, char **argv)2020{2021#if !defined(BWL_FILESYSTEM_SUPPORT)2022return (-1);2023#else2024char *fname = NULL;2025uint32 start = 0;2026uint32 size = 0;2027int ret = 0;20282029FILE *fp;2030uint32 memsize;2031char *memszargs[] = { "memsize", NULL };20322033uint len;20342035miniopt_t opts;2036int opt_err;20372038UNUSED_PARAMETER(cmd);2039UNUSED_PARAMETER(argv);20402041/* Parse command-line options */2042miniopt_init(&opts, "upload", "", TRUE);20432044argv++;2045while ((opt_err = miniopt(&opts, argv)) != -1) {2046if (opt_err == 1) {2047fprintf(stderr, "upload options error\n");2048ret = -1;2049goto exit;2050}2051argv += opts.consumed;20522053if (opts.opt == 'a') {2054if (!opts.good_int) {2055fprintf(stderr, "invalid address %s\n", opts.valstr);2056ret = -1;2057goto exit;2058}2059start = (uint32)opts.uval;2060} else if (opts.positional) {2061if (!fname) {2062fname = opts.valstr;2063} else if (opts.good_int) {2064size = (uint32)opts.uval;2065} else {2066fprintf(stderr, "upload options error\n");2067ret = -1;2068goto exit;2069}2070} else if (!opts.opt) {2071fprintf(stderr, "unrecognized option %s\n", opts.valstr);2072ret = -1;2073goto exit;2074} else {2075fprintf(stderr, "unrecognized option %c\n", opts.opt);2076ret = -1;2077goto exit;2078}2079}20802081/* validate arguments */2082if (!fname) {2083fprintf(stderr, "filename required\n");2084ret = -1;2085goto exit;2086}20872088if ((ret = dhd_var_get(dhd, NULL, memszargs))) {2089fprintf(stderr, "%s: error obtaining memsize\n", __FUNCTION__);2090goto exit;2091}2092memsize = *(uint32*)buf;20932094if (!memsize)2095memsize = start + size;20962097if (start + size > memsize) {2098fprintf(stderr, "%s: %d bytes at 0x%x exceeds ramsize 0x%x\n",2099__FUNCTION__, size, start, memsize);2100ret = -1;2101goto exit;2102}21032104if ((fp = fopen(fname, "wb")) == NULL) {2105fprintf(stderr, "%s: Could not open %s: %s\n",2106__FUNCTION__, fname, strerror(errno));2107ret = -1;2108goto exit;2109}21102111/* default size to full RAM */2112if (!size)2113size = memsize - start;21142115/* read memory and write to file */2116while (size) {2117char *ptr;2118int params[2];21192120len = MIN(MEMBLOCK, size);21212122params[0] = start;2123params[1] = len;2124ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);2125if (ret) {2126fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",2127__FUNCTION__, len, start);2128break;2129}21302131if (fwrite(ptr, sizeof(char), len, fp) != len) {2132fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);2133ret = -1;2134break;2135}21362137start += len;2138size -= len;2139}21402141fclose(fp);2142exit:2143return ret;2144#endif /* BWL_FILESYSTEM_SUPPORT */2145}21462147static int2148dhd_coredump(void *dhd, cmd_t *cmd, char **argv)2149{2150#if !defined(BWL_FILESYSTEM_SUPPORT)2151return (-1);2152#else2153char *fname = NULL;2154int ret = 0;21552156FILE *fp;21572158uint32 dumpInfoAddr;2159hndrte_debug_t debugInfo;21602161miniopt_t opts;2162int opt_err;21632164int params[2];2165char *ptr;2166uint32 *iptr;21672168unsigned int start;2169unsigned int size;21702171prstatus_t prstatus;21722173UNUSED_PARAMETER(cmd);2174UNUSED_PARAMETER(argv);21752176/* Parse command-line options */2177miniopt_init(&opts, "dump", "", TRUE);21782179argv++;2180while ((opt_err = miniopt(&opts, argv)) != -1) {2181if (opt_err == 1) {2182fprintf(stderr, "dump options error\n");2183ret = -1;2184goto exit;2185}2186argv += opts.consumed;21872188if (opts.positional) {2189if (!fname) {2190fname = opts.valstr;2191} else {2192fprintf(stderr, "dump options error\n");2193ret = -1;2194goto exit;2195}2196} else if (!opts.opt) {2197fprintf(stderr, "unrecognized option %s\n", opts.valstr);2198ret = -1;2199goto exit;2200} else {2201fprintf(stderr, "unrecognized option %c\n", opts.opt);2202ret = -1;2203goto exit;2204}2205}22062207/* validate arguments */2208if (!fname) {2209fprintf(stderr, "filename required\n");2210ret = -1;2211goto exit;2212}22132214params[0] = DUMP_INFO_PTR_PTR;2215params[1] = 8;2216ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&iptr);2217if (ret) {2218fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",2219__FUNCTION__, 8, DUMP_INFO_PTR_PTR);2220ret = -1;2221goto exit;2222}22232224if (*iptr != HNDRTE_DEBUG_PTR_PTR_MAGIC) { /* Sanity check */2225fprintf(stderr, "Error: cannot find dumpinfo area\n");2226ret = -1;2227goto exit;2228}22292230dumpInfoAddr = *(iptr + 1);2231if (dumpInfoAddr == 0) {2232fprintf(stderr, "Error: Dump info pointer is zero\n");2233ret = -1;2234goto exit;2235}22362237/* Read the area the debuginfoptr points at */2238params[0] = dumpInfoAddr;2239params[1] = sizeof(hndrte_debug_t);2240ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);2241if (ret) {2242fprintf(stderr, "%s: failed reading %lu membytes from 0x%08lx\n",2243__FUNCTION__, (long unsigned) sizeof(hndrte_debug_t),2244(long unsigned) dumpInfoAddr);2245ret = -1;2246goto exit;2247}22482249memcpy((char *) &debugInfo, ptr, sizeof(hndrte_debug_t));2250/* Sanity check the area */2251if ((debugInfo.magic != HNDRTE_DEBUG_MAGIC) ||2252(debugInfo.version != HNDRTE_DEBUG_VERSION)) {2253fprintf(stderr, "Error: Invalid debug info area\n");2254ret = -1;2255goto exit;2256}225722582259/* Get the base and size to dump */2260start = debugInfo.ram_base;2261size = debugInfo.ram_size;22622263/* Get the arm trap area */2264bzero(&prstatus, sizeof(prstatus_t));2265if (debugInfo.trap_ptr != 0) {2266int i;2267trap_t armtrap;2268uint32 *reg;22692270params[0] = debugInfo.trap_ptr;2271params[1] = sizeof(trap_t);2272ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);2273if (ret) {2274fprintf(stderr, "%s: failed reading %lu membytes from 0x%08lx\n",2275__FUNCTION__, (long unsigned) sizeof(hndrte_debug_t),2276(long unsigned) dumpInfoAddr);2277ret = -1;2278goto exit;2279}22802281memcpy((char *) &armtrap, ptr, sizeof(trap_t));22822283/* Populate the prstatus */2284prstatus.si_signo = armtrap.type;2285reg = &armtrap.r0;2286for (i = 0; i < 15; i++, reg++) {2287prstatus.uregs[i] = *reg;2288}2289prstatus.uregs[15] = armtrap.epc;2290}22912292if ((fp = fopen(fname, "wb")) == NULL) {2293fprintf(stderr, "%s: Could not open %s: %s\n",2294__FUNCTION__, fname, strerror(errno));2295ret = -1;2296goto exit;2297}22982299/* Write the preamble and debug header */2300fprintf(fp, "Dump starts for version %s FWID 01-%x\n", debugInfo.epivers, debugInfo.fwid);2301fprintf(fp, "XXXXXXXXXXXXXXXXXXXX");2302fprintf(fp, "%8.8lX", (long unsigned) sizeof(debugInfo));2303if (fwrite(&debugInfo, sizeof(unsigned char), sizeof(debugInfo), fp) != sizeof(debugInfo)) {2304fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);2305ret = -1;2306goto exit;2307}23082309/* Write the prstatus */2310if (fwrite(&prstatus, sizeof(unsigned char), sizeof(prstatus), fp) != sizeof(prstatus)) {2311fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);2312ret = -1;2313goto exit;2314}23152316/* Write the ram size as another sanity check */2317fprintf(fp, "%8.8X", size);23182319/* read memory and write to file */2320while (size) {2321int len;2322len = MIN(MEMBLOCK, size);23232324params[0] = start;2325params[1] = len;2326ret = dhd_var_getbuf(dhd, "membytes", params, 2 * sizeof(int), (void**)&ptr);2327if (ret) {2328fprintf(stderr, "%s: failed reading %d membytes from 0x%08x\n",2329__FUNCTION__, len, start);2330break;2331}23322333if (fwrite(ptr, sizeof(*ptr), len, fp) != (uint) len) {2334fprintf(stderr, "%s: error writing to file %s\n", __FUNCTION__, fname);2335ret = -1;2336break;2337}23382339start += len;2340size -= len;2341}23422343fclose(fp);2344exit:2345return ret;2346#endif /* BWL_FILESYSTEM_SUPPORT */2347}23482349static int2350dhd_logstamp(void *dhd, cmd_t *cmd, char **argv)2351{2352int ret;2353char *endptr = NULL;2354uint argc;2355int valn[2] = {0, 0};23562357/* arg count */2358for (argc = 0; argv[argc]; argc++);2359argc--; argv++;23602361if (argc > 2)2362return USAGE_ERROR;23632364if (argc) {2365valn[0] = strtol(argv[0], &endptr, 0);2366if (*endptr != '\0') {2367printf("bad val1: %s\n", argv[0]);2368return USAGE_ERROR;2369}2370}23712372if (argc > 1) {2373valn[1] = strtol(argv[1], &endptr, 0);2374if (*endptr != '\0') {2375printf("bad val2: %s\n", argv[1]);2376return USAGE_ERROR;2377}2378}23792380ret = dhd_var_setbuf(dhd, cmd->name, valn, argc * sizeof(int));23812382return (ret);2383}23842385static int2386dhd_sd_reg(void *dhd, cmd_t *cmd, char **argv)2387{2388int ret;2389sdreg_t sdreg;2390char *endptr = NULL;2391uint argc;2392void *ptr = NULL;23932394bzero(&sdreg, sizeof(sdreg));23952396/* arg count */2397for (argc = 0; argv[argc]; argc++);2398argc--;23992400/* hostreg: offset [value]; devreg: func offset [value] */2401if (!strcmp(cmd->name, "sd_hostreg")) {2402argv++;2403if (argc < 1) {2404printf("required args: offset [value]\n");2405return USAGE_ERROR;2406}24072408} else if (!strcmp(cmd->name, "sd_devreg")) {2409argv++;2410if (argc < 2) {2411printf("required args: func offset [value]\n");2412return USAGE_ERROR;2413}24142415sdreg.func = strtoul(*argv++, &endptr, 0);2416if (*endptr != '\0') {2417printf("Invalid function number\n");2418return USAGE_ERROR;2419}2420} else {2421return USAGE_ERROR;2422}24232424sdreg.offset = strtoul(*argv++, &endptr, 0);2425if (*endptr != '\0') {2426printf("Invalid offset value\n");2427return USAGE_ERROR;2428}24292430/* third arg: value */2431if (*argv) {2432sdreg.value = strtoul(*argv, &endptr, 0);2433if (*endptr != '\0') {2434printf("Invalid value\n");2435return USAGE_ERROR;2436}2437}24382439/* no third arg means get, otherwise set */2440if (!*argv) {2441if ((ret = dhd_var_getbuf(dhd, cmd->name, &sdreg, sizeof(sdreg), &ptr)) >= 0)2442printf("0x%x\n", *(int *)ptr);2443} else {2444ret = dhd_var_setbuf(dhd, cmd->name, &sdreg, sizeof(sdreg));2445}24462447return (ret);2448}24492450static dbg_msg_t dhd_msgs[] = {2451{DHD_ERROR_VAL, "error"},2452{DHD_ERROR_VAL, "err"},2453{DHD_TRACE_VAL, "trace"},2454{DHD_INFO_VAL, "inform"},2455{DHD_INFO_VAL, "info"},2456{DHD_INFO_VAL, "inf"},2457{DHD_DATA_VAL, "data"},2458{DHD_CTL_VAL, "ctl"},2459{DHD_TIMER_VAL, "timer"},2460{DHD_HDRS_VAL, "hdrs"},2461{DHD_BYTES_VAL, "bytes"},2462{DHD_INTR_VAL, "intr"},2463{DHD_LOG_VAL, "log"},2464{DHD_GLOM_VAL, "glom"},2465{DHD_EVENT_VAL, "event"},2466{DHD_BTA_VAL, "bta"},2467{0, NULL}2468};24692470static int2471dhd_msglevel(void *dhd, cmd_t *cmd, char **argv)2472{2473return dhd_do_msglevel(dhd, cmd, argv, dhd_msgs);2474}24752476static int2477dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg)2478{2479int ret, i;2480uint val, last_val = 0, msglevel = 0, msglevel_add = 0, msglevel_del = 0;2481char *endptr = NULL;24822483if ((ret = dhd_iovar_getint(dhd, cmd->name, (int*)&msglevel)) < 0)2484return (ret);24852486if (!*++argv) {2487printf("0x%x ", msglevel);2488for (i = 0; (val = dbg_msg[i].value); i++) {2489if ((msglevel & val) && (val != last_val))2490printf(" %s", dbg_msg[i].string);2491last_val = val;2492}2493printf("\n");2494return (0);2495}24962497while (*argv) {2498char *s = *argv;2499if (*s == '+' || *s == '-')2500s++;2501else2502msglevel_del = ~0; /* make the whole list absolute */2503val = strtoul(s, &endptr, 0);2504/* not a plain integer if not all the string was parsed by strtoul */2505if (*endptr != '\0') {2506for (i = 0; (val = dbg_msg[i].value); i++)2507if (stricmp(dbg_msg[i].string, s) == 0)2508break;2509if (!val)2510goto usage;2511}2512if (**argv == '-')2513msglevel_del |= val;2514else2515msglevel_add |= val;2516++argv;2517}25182519msglevel &= ~msglevel_del;2520msglevel |= msglevel_add;25212522return (dhd_iovar_setint(dhd, cmd->name, msglevel));25232524usage:2525fprintf(stderr, "msg values may be a list of numbers or names from the following set.\n");2526fprintf(stderr, "Use a + or - prefix to make an incremental change.");25272528for (i = 0; (val = dbg_msg[i].value); i++) {2529if (val != last_val)2530fprintf(stderr, "\n0x%04x %s", val, dbg_msg[i].string);2531else2532fprintf(stderr, ", %s", dbg_msg[i].string);2533last_val = val;2534}2535fprintf(stderr, "\n");25362537return 0;2538}25392540static char *2541ver2str(unsigned int vms, unsigned int vls)2542{2543static char verstr[100];2544unsigned int maj, year, month, day, build;25452546maj = (vms >> 16) & 0xFFFF;2547if (maj > 1000) {2548/* it is probably a date... */2549year = (vms >> 16) & 0xFFFF;2550month = vms & 0xFFFF;2551day = (vls >> 16) & 0xFFFF;2552build = vls & 0xFFFF;2553sprintf(verstr, "%d/%d/%d build %d",2554month, day, year, build);2555} else {2556/* it is a tagged release. */2557sprintf(verstr, "%d.%d RC%d.%d",2558(vms>>16)&0xFFFF, vms&0xFFFF,2559(vls>>16)&0xFFFF, vls&0xFFFF);2560}2561return verstr;2562}25632564static int2565dhd_version(void *dhd, cmd_t *cmd, char **argv)2566{2567int ret;2568char *ptr;25692570UNUSED_PARAMETER(cmd);2571UNUSED_PARAMETER(argv);25722573/* Display the application version info */2574printf("%s: %s\n", dhdu_av0,2575ver2str((EPI_MAJOR_VERSION << 16)| EPI_MINOR_VERSION,2576(EPI_RC_NUMBER << 16) | EPI_INCREMENTAL_NUMBER));25772578if ((ret = dhd_var_getbuf(dhd, cmd->name, NULL, 0, (void**)&ptr)) < 0)2579return ret;25802581/* Display the returned string */2582printf("%s\n", ptr);25832584return 0;2585}25862587static int2588dhd_var_setint(void *dhd, cmd_t *cmd, char **argv)2589{2590int32 val;2591int len;2592char *varname;2593char *endptr = NULL;2594char *p;25952596if (cmd->set == -1) {2597printf("set not defined for %s\n", cmd->name);2598return COMMAND_ERROR;2599}26002601if (!*argv) {2602printf("set: missing arguments\n");2603return USAGE_ERROR;2604}26052606varname = *argv++;26072608if (!*argv) {2609printf("set: missing value argument for set of \"%s\"\n", varname);2610return USAGE_ERROR;2611}26122613val = strtol(*argv, &endptr, 0);2614if (*endptr != '\0') {2615/* not all the value string was parsed by strtol */2616printf("set: error parsing value \"%s\" as an integer for set of \"%s\"\n",2617*argv, varname);2618return USAGE_ERROR;2619}26202621strcpy(buf, varname);2622p = buf;2623while (*p != '\0') {2624*p = tolower(*p);2625p++;2626}26272628/* skip the NUL */2629p++;26302631memcpy(p, &val, sizeof(uint));2632len = (p - buf) + sizeof(uint);26332634return (dhd_set(dhd, DHD_SET_VAR, &buf[0], len));2635}26362637static int2638dhd_var_get(void *dhd, cmd_t *cmd, char **argv)2639{2640char *varname;2641char *p;26422643UNUSED_PARAMETER(cmd);26442645if (!*argv) {2646printf("get: missing arguments\n");2647return USAGE_ERROR;2648}26492650varname = *argv++;26512652if (*argv) {2653printf("get: error, extra arg \"%s\"\n", *argv);2654return USAGE_ERROR;2655}26562657strcpy(buf, varname);2658p = buf;2659while (*p != '\0') {2660*p = tolower(*p);2661p++;2662}2663return (dhd_get(dhd, DHD_GET_VAR, &buf[0], DHD_IOCTL_MAXLEN));2664}26652666static int2667dhd_var_getint(void *dhd, cmd_t *cmd, char **argv)2668{2669int err;2670int32 val;2671if (cmd->get == -1) {2672printf("get not defined for %s\n", cmd->name);2673return COMMAND_ERROR;2674}26752676if ((err = dhd_var_get(dhd, cmd, argv)))2677return (err);26782679val = *(int32*)buf;26802681if (val < 10)2682printf("%d\n", val);2683else2684printf("%d (0x%x)\n", val, val);26852686return (0);2687}26882689static int2690dhd_var_ampak_otpmac(void *dhd, cmd_t *cmd, char **argv)2691{2692int err, i, j;2693char *pmacstr[] = {"sd_cis", NULL};2694char tpl[] = "80 07 19 ";2695char mac[2][8] = {{"98 3b 16"}, {"00 22 f4"}};2696char *pch;26972698if ((err = dhd_var_get(dhd, cmd, pmacstr)))2699return (err);27002701pch = strstr(buf, tpl);2702if (!pch) {2703printf("Empty\n");2704return -1;2705}2706pch += strlen(tpl);27072708for (j=0; j<2; j++) {2709if (!strncmp(pch, &mac[j][0], 8)) {2710return 0;2711}2712}2713for (i=0; i<18; i++) {2714if (i%3 == 2)2715continue;2716printf("%c", pch[i]);2717}2718printf("\n");2719return -1;2720}27212722static int2723dhd_var_getandprintstr(void *dhd, cmd_t *cmd, char **argv)2724{2725int err;27262727if ((err = dhd_var_get(dhd, cmd, argv)))2728return (err);27292730printf("%s\n", buf);2731return (0);2732}273327342735void2736dhd_printlasterror(void *dhd)2737{2738char *cmd[2] = {"bcmerrorstr"};27392740if (dhd_var_get(dhd, NULL, cmd) != 0) {2741fprintf(stderr, "%s: \nError getting the last error\n", dhdu_av0);2742} else {2743fprintf(stderr, "%s: %s\n", dhdu_av0, buf);2744}2745}27462747static int2748dhd_varint(void *dhd, cmd_t *cmd, char *argv[])2749{2750if (argv[1])2751return (dhd_var_setint(dhd, cmd, argv));2752else2753return (dhd_var_getint(dhd, cmd, argv));2754}27552756static int2757dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr)2758{2759int len;27602761memset(buf, 0, DHD_IOCTL_MAXLEN);2762strcpy(buf, iovar);27632764/* include the NUL */2765len = strlen(iovar) + 1;27662767if (param_len)2768memcpy(&buf[len], param, param_len);27692770*bufptr = buf;27712772return dhd_get(dhd, DHD_GET_VAR, &buf[0], DHD_IOCTL_MAXLEN);2773}27742775static int2776dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len)2777{2778int len;27792780memset(buf, 0, DHD_IOCTL_MAXLEN);2781strcpy(buf, iovar);27822783/* include the NUL */2784len = strlen(iovar) + 1;27852786if (param_len)2787memcpy(&buf[len], param, param_len);27882789len += param_len;27902791return dhd_set(dhd, DHD_SET_VAR, &buf[0], len);2792}27932794static int2795dhd_var_void(void *dhd, cmd_t *cmd, char **argv)2796{2797UNUSED_PARAMETER(argv);27982799if (cmd->set < 0)2800return USAGE_ERROR;28012802return dhd_var_setbuf(dhd, cmd->name, NULL, 0);2803}28042805/*2806* format an iovar buffer2807*/2808static uint2809dhd_iovar_mkbuf(char *name, char *data, uint datalen, char *buf, uint buflen, int *perr)2810{2811uint len;28122813len = strlen(name) + 1;28142815/* check for overflow */2816if ((len + datalen) > buflen) {2817*perr = BCME_BUFTOOSHORT;2818return 0;2819}28202821strcpy(buf, name);28222823/* append data onto the end of the name string */2824if (datalen > 0)2825memcpy(&buf[len], data, datalen);28262827len += datalen;28282829*perr = 0;2830return len;2831}28322833static int2834dhd_iovar_getint(void *dhd, char *name, int *var)2835{2836char ibuf[DHD_IOCTL_SMLEN];2837int error;28382839dhd_iovar_mkbuf(name, NULL, 0, ibuf, sizeof(ibuf), &error);2840if (error)2841return error;28422843if ((error = dhd_get(dhd, DHD_GET_VAR, &ibuf, sizeof(ibuf))) < 0)2844return error;28452846memcpy(var, ibuf, sizeof(int));28472848return 0;2849}28502851static int2852dhd_iovar_setint(void *dhd, char *name, int var)2853{2854int len;2855char ibuf[DHD_IOCTL_SMLEN];2856int error;28572858len = dhd_iovar_mkbuf(name, (char *)&var, sizeof(var), ibuf, sizeof(ibuf), &error);2859if (error)2860return error;28612862if ((error = dhd_set(dhd, DHD_SET_VAR, &ibuf, len)) < 0)2863return error;28642865return 0;2866}28672868static int2869dhd_varstr(void *dhd, cmd_t *cmd, char **argv)2870{2871int error;2872char *str;28732874if (!*++argv) {2875void *ptr;28762877if ((error = dhd_var_getbuf(dhd, cmd->name, NULL, 0, &ptr)) < 0)2878return (error);28792880str = (char *)ptr;2881printf("%s\n", str);2882return (0);2883} else {2884str = *argv;2885/* iovar buffer length includes NUL */2886return dhd_var_setbuf(dhd, cmd->name, str, strlen(str) + 1);2887}2888}28892890#ifdef BCMSPI2891static int2892dhd_spierrstats(void *dhd, cmd_t *cmd, char **argv)2893{2894int ret, i;2895struct spierrstats_t spierrstats, *p;2896uint argc;2897void *ptr = NULL;28982899bzero(&spierrstats, sizeof(spierrstats));29002901/* arg count */2902for (argc = 0; argv[argc]; argc++);2903argc--;29042905if (strcmp(cmd->name, "spi_errstats")) {2906printf("Supported only for SPI. Required cmd name missing\n");2907return COMMAND_ERROR;2908}29092910/* Check 3rd argument */2911argv++;29122913/* no third arg means get, otherwise set */2914if (!*argv) {2915if ((ret = dhd_var_getbuf(dhd, cmd->name, NULL, 0, &ptr)) < 0)2916return ret;29172918p = (struct spierrstats_t *)ptr;29192920printf("Last %d device-status-bits\n", NUM_PREV_TRANSACTIONS);29212922for (i = 0; i < NUM_PREV_TRANSACTIONS; i++)2923printf("dstatus[%d] = 0x%x, spicmd[%d] = 0x%x\n", i, p->dstatus[i],2924i, p->spicmd[i]);29252926printf("The requested data was not available = %d\n",2927p->dna);2928printf("FIFO underflow happened due to F2 rd command = %d\n",2929p->rdunderflow);2930printf("FIFO overflow happened due to F1/F2 wr command = %d\n",2931p->wroverflow);2932printf("F2 interrupt (OR of all F2 related intr status bits) = %d\n",2933p->f2interrupt);2934printf("F2 FIFO is not ready to receive data = %d\n",2935p->f2rxnotready);2936printf("Error in command or host data, detected by checksum = %d\n",2937p->hostcmddataerr);2938printf("Packet is available in F2 TX FIFO = %d\n",2939p->f2pktavailable);29402941} else {2942ret = dhd_var_setbuf(dhd, cmd->name, &spierrstats, sizeof(spierrstats));2943}29442945return (ret);2946}2947#endif /* BCMSPI */29482949#ifdef WLBTAMP29502951#define MATCH_OP(op, opstr) (strlen(op) == strlen(opstr) && strncmp(op, opstr, strlen(op)) == 0)29522953static int2954wl_HCI_cmd(void *wl, cmd_t *cmd, char **argv)2955{2956union {2957char buf[HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE];2958uint32 alignme;2959} cbuf;2960amp_hci_cmd_t *cpkt = (amp_hci_cmd_t *)&cbuf.buf[0];29612962char *op;2963uint8 plen;29642965UNUSED_PARAMETER(cmd);29662967if (!*++argv)2968return USAGE_ERROR;29692970/* recognize and encode operations */2971op = *argv++;2972if (MATCH_OP(op, "Read_Link_Quality")) {2973cpkt->opcode = HCI_Read_Link_Quality;2974} else if (MATCH_OP(op, "Read_Local_AMP_Info")) {2975cpkt->opcode = HCI_Read_Local_AMP_Info;2976} else if (MATCH_OP(op, "Read_Local_AMP_ASSOC")) {2977cpkt->opcode = HCI_Read_Local_AMP_ASSOC;2978} else if (MATCH_OP(op, "Write_Remote_AMP_ASSOC")) {2979cpkt->opcode = HCI_Write_Remote_AMP_ASSOC;2980} else if (MATCH_OP(op, "Create_Physical_Link")) {2981cpkt->opcode = HCI_Create_Physical_Link;2982} else if (MATCH_OP(op, "Accept_Physical_Link_Request")) {2983cpkt->opcode = HCI_Accept_Physical_Link_Request;2984} else if (MATCH_OP(op, "Disconnect_Physical_Link")) {2985cpkt->opcode = HCI_Disconnect_Physical_Link;2986} else if (MATCH_OP(op, "Create_Logical_Link")) {2987cpkt->opcode = HCI_Create_Logical_Link;2988} else if (MATCH_OP(op, "Accept_Logical_Link")) {2989cpkt->opcode = HCI_Accept_Logical_Link;2990} else if (MATCH_OP(op, "Disconnect_Logical_Link")) {2991cpkt->opcode = HCI_Disconnect_Logical_Link;2992} else if (MATCH_OP(op, "Logical_Link_Cancel")) {2993cpkt->opcode = HCI_Logical_Link_Cancel;2994} else if (MATCH_OP(op, "Short_Range_Mode")) {2995cpkt->opcode = HCI_Short_Range_Mode;2996} else if (MATCH_OP(op, "Read_Connection_Accept_Timeout")) {2997cpkt->opcode = HCI_Read_Connection_Accept_Timeout;2998} else if (MATCH_OP(op, "Write_Connection_Accept_Timeout")) {2999cpkt->opcode = HCI_Write_Connection_Accept_Timeout;3000} else if (MATCH_OP(op, "Read_Link_Supervision_Timeout")) {3001cpkt->opcode = HCI_Read_Link_Supervision_Timeout;3002} else if (MATCH_OP(op, "Write_Link_Supervision_Timeout")) {3003cpkt->opcode = HCI_Write_Link_Supervision_Timeout;3004} else if (MATCH_OP(op, "Reset")) {3005cpkt->opcode = HCI_Reset;3006} else if (MATCH_OP(op, "Enhanced_Flush")) {3007cpkt->opcode = HCI_Enhanced_Flush;3008} else if (MATCH_OP(op, "Read_Best_Effort_Flush_Timeout")) {3009cpkt->opcode = HCI_Read_Best_Effort_Flush_Timeout;3010} else if (MATCH_OP(op, "Write_Best_Effort_Flush_Timeout")) {3011cpkt->opcode = HCI_Write_Best_Effort_Flush_Timeout;3012} else if (MATCH_OP(op, "Read_Logical_Link_Accept_Timeout")) {3013cpkt->opcode = HCI_Read_Logical_Link_Accept_Timeout;3014} else if (MATCH_OP(op, "Write_Logical_Link_Accept_Timeout")) {3015cpkt->opcode = HCI_Write_Logical_Link_Accept_Timeout;3016} else if (MATCH_OP(op, "Read_Buffer_Size")) {3017cpkt->opcode = HCI_Read_Buffer_Size;3018} else if (MATCH_OP(op, "Read_Data_Block_Size")) {3019cpkt->opcode = HCI_Read_Data_Block_Size;3020} else if (MATCH_OP(op, "Set_Event_Mask_Page_2")) {3021cpkt->opcode = HCI_Set_Event_Mask_Page_2;3022} else {3023printf("unsupported HCI command: %s\n", op);3024return (-1);3025}30263027plen = 0;3028while (*argv && (plen < HCI_CMD_DATA_SIZE)) {3029cpkt->parms[plen++] = (uint8)strtol(*argv++, NULL, 0);3030}3031cpkt->plen = plen;30323033return dhd_var_setbuf(wl, cmd->name, cpkt, HCI_CMD_PREAMBLE_SIZE + plen);3034}30353036typedef union {3037uint8 buf[HCI_ACL_DATA_PREAMBLE_SIZE + 2048];3038uint32 alignme;3039} g_hci_dbuf_t;30403041static int3042wl_HCI_ACL_data(void *wl, cmd_t *cmd, char **argv)3043{3044/* Align struct. Also declare static so that large array isn't allocated3045* from the stack.3046*/3047static g_hci_dbuf_t g_hci_dbuf;30483049amp_hci_ACL_data_t *dpkt = (amp_hci_ACL_data_t *)&g_hci_dbuf.buf[0];3050uint16 dlen;30513052if (!*++argv)3053return USAGE_ERROR;30543055/* get logical link handle */3056dpkt->handle = (HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS);3057dpkt->handle |= (uint16)strtol(*argv++, NULL, 0);30583059/* get data */3060dlen = 0;3061while (*argv && (dlen < 2048)) {3062dpkt->data[dlen++] = (uint8)strtol(*argv++, NULL, 0);3063}3064dpkt->dlen = dlen;30653066return dhd_var_setbuf(wl, cmd->name, dpkt, HCI_ACL_DATA_PREAMBLE_SIZE + dlen);3067}3068#endif /* WLBTAMP */30693070/* These two utility functions are used by dhdu_linux.c3071* The code is taken from wlu.c.3072*/3073int3074dhd_atoip(const char *a, struct ipv4_addr *n)3075{3076char *c;3077int i = 0;30783079for (;;) {3080n->addr[i++] = (uint8)strtoul(a, &c, 0);3081if (*c++ != '.' || i == IPV4_ADDR_LEN)3082break;3083a = c;3084}3085return (i == IPV4_ADDR_LEN);3086}30873088int3089dhd_ether_atoe(const char *a, struct ether_addr *n)3090{3091char *c;3092int i = 0;30933094memset(n, 0, ETHER_ADDR_LEN);3095for (;;) {3096n->octet[i++] = (uint8)strtoul(a, &c, 16);3097if (!*c++ || i == ETHER_ADDR_LEN)3098break;3099a = c;3100}3101return (i == ETHER_ADDR_LEN);3102}310331043105