summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManel Caro <mcaro@iseebcn.com>2019-03-07 20:13:19 +0100
committerManel Caro <mcaro@iseebcn.com>2019-03-07 20:13:19 +0100
commitbf1dec110d517755e66125d4b8699f50b8e6dfcf (patch)
tree11e5e87fd171f33cd9ed0e072dad4eab7c0faf15
downloadcalibrator-bf1dec110d517755e66125d4b8699f50b8e6dfcf.zip
calibrator-bf1dec110d517755e66125d4b8699f50b8e6dfcf.tar.gz
calibrator-bf1dec110d517755e66125d4b8699f50b8e6dfcf.tar.bz2
Calibrator and uim Initial Commit
-rw-r--r--Makefile52
-rw-r--r--calibrator.c539
-rw-r--r--calibrator.h157
-rw-r--r--ini.c1773
-rw-r--r--ini.h359
-rw-r--r--misc_cmds.c323
-rw-r--r--nl80211.h1434
-rw-r--r--nvs.c1283
-rw-r--r--nvs.h31
-rw-r--r--plt.c1431
-rw-r--r--plt.h412
-rw-r--r--uim_rfkill/readme.txt25
-rw-r--r--uim_rfkill/uim.c924
-rw-r--r--uim_rfkill/uim.h154
-rw-r--r--wl18xx_plt.c787
-rw-r--r--wl18xx_plt.h252
16 files changed, 9936 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cd9ab98
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,52 @@
+# Requisites:
+# sudo apt-get install libnl-3-dev:armhf
+# sudo apt install libnl-3-200:armhf
+# sudo apt install libnl-genl-3-200:armhf
+# last check, if linker fails then you should create
+# this link manually:
+# /lib/arm-linux-gnueabihf/libnl-genl-3.so -> libnl-genl-3.so.200.22.0
+
+
+CC = $(CROSS_COMPILE)gcc
+CFLAGS = -O2 -Wall
+CFLAGS += -I/usr/include -I/usr/include/libnl3
+
+ifdef NLROOT
+CFLAGS += -I${NLROOT}
+endif
+
+LDFLAGS += -L/lib/arm-linux-gnueabihf/
+LIBS += -lm
+
+# Ubuntu 16.04
+NLVER = 3
+
+ifeq ($(NLVER),3)
+ CFLAGS+=-DCONFIG_LIBNL32
+ LIBS += -lnl-3 -lnl-genl-3
+else
+ CFLAGS+=-DCONFIG_LIBNL20
+ LIBS += -lnl -lnl-genl
+endif
+
+OBJS = nvs.o misc_cmds.o calibrator.o plt.o wl18xx_plt.o ini.o
+
+%.o: %.c calibrator.h nl80211.h plt.h nvs_dual_band.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+all: $(OBJS)
+ $(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o calibrator
+
+uim:
+ $(CC) $(CFLAGS) $(LDFLAGS) uim_rfkill/$@.c -o $@
+
+static: $(OBJS)
+ $(CC) $(LDFLAGS) --static $(OBJS) $(LIBS) -o calibrator
+
+install:
+ @echo Copy files to $(NFSROOT)/usr/bin
+ @cp -f ./calibrator $(NFSROOT)/usr/bin
+ @chmod 755 $(NFSROOT)/usr/bin/calibrator
+
+clean:
+ @rm -f *.o calibrator uim
diff --git a/calibrator.c b/calibrator.c
new file mode 100644
index 0000000..b8f66fa
--- /dev/null
+++ b/calibrator.c
@@ -0,0 +1,539 @@
+/*
+ * PLT utility for wireless chip supported by TI's driver wl12xx
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#include "nl80211.h"
+#include "calibrator.h"
+#include "plt.h"
+#include "ini.h"
+
+char calibrator_version[] = "0.80";
+#if !defined CONFIG_LIBNL20 && !defined CONFIG_LIBNL32
+/* libnl 2.0 compatibility code */
+static inline struct nl_handle *nl_socket_alloc(void)
+{
+ return nl_handle_alloc();
+}
+
+static inline void nl_socket_free(struct nl_sock *h)
+{
+ nl_handle_destroy(h);
+}
+
+static inline int __genl_ctrl_alloc_cache(struct nl_sock *h,
+ struct nl_cache **cache)
+{
+ struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
+ if (!tmp)
+ return -ENOMEM;
+ *cache = tmp;
+ return 0;
+}
+#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
+#endif /* CONFIG_LIBNL20 */
+
+int calibrator_debug;
+
+static int nl80211_init(struct nl80211_state *state)
+{
+ int err;
+
+ state->nl_sock = nl_socket_alloc();
+ if (!state->nl_sock) {
+ fprintf(stderr, "Failed to allocate netlink socket.\n");
+ return -ENOMEM;
+ }
+
+ if (genl_connect(state->nl_sock)) {
+ fprintf(stderr, "Failed to connect to generic netlink.\n");
+ err = -ENOLINK;
+ goto out_handle_destroy;
+ }
+
+ if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
+ fprintf(stderr, "Failed to allocate generic netlink cache.\n");
+ err = -ENOMEM;
+ goto out_handle_destroy;
+ }
+
+ state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
+ if (!state->nl80211) {
+ fprintf(stderr, "nl80211 not found.\n");
+ err = -ENOENT;
+ goto out_cache_free;
+ }
+
+ return 0;
+
+ out_cache_free:
+ nl_cache_free(state->nl_cache);
+ out_handle_destroy:
+ nl_socket_free(state->nl_sock);
+ return err;
+}
+
+static void nl80211_cleanup(struct nl80211_state *state)
+{
+ genl_family_put(state->nl80211);
+ nl_cache_free(state->nl_cache);
+ nl_socket_free(state->nl_sock);
+}
+
+static int cmd_size;
+
+extern struct cmd __start___cmd;
+extern struct cmd __stop___cmd;
+
+#define for_each_cmd(_cmd) \
+ for (_cmd = &__start___cmd; _cmd < &__stop___cmd; \
+ _cmd = (const struct cmd *)((char *)_cmd + cmd_size))
+
+
+static void __usage_cmd(const struct cmd *cmd, char *indent, bool full)
+{
+ const char *start, *lend, *end;
+
+ printf("%s", indent);
+
+ switch (cmd->idby) {
+ case CIB_NONE:
+ break;
+ case CIB_PHY:
+ printf("phy <phyname> ");
+ break;
+ case CIB_NETDEV:
+ printf("dev <devname> ");
+ break;
+ }
+ if (cmd->parent && cmd->parent->name)
+ printf("%s ", cmd->parent->name);
+ printf("%s", cmd->name);
+ if (cmd->args)
+ printf(" %s", cmd->args);
+ printf("\n");
+
+ if (!full || !cmd->help)
+ return;
+
+ /* hack */
+ if (strlen(indent))
+ indent = "\t\t";
+ else
+ printf("\n");
+
+ /* print line by line */
+ start = cmd->help;
+ end = strchr(start, '\0');
+ do {
+ lend = strchr(start, '\n');
+ if (!lend)
+ lend = end;
+ printf("%s", indent);
+ printf("%.*s\n", (int)(lend - start), start);
+ start = lend + 1;
+ } while (end != lend);
+
+ printf("\n");
+}
+
+static void usage_options(void)
+{
+ printf("Options:\n");
+ printf("\t--debug\t\tenable netlink debugging\n");
+}
+
+static const char *argv0;
+
+static void usage(bool full)
+{
+ const struct cmd *section, *cmd;
+
+ printf("Usage:\t%s [options] command\n", argv0);
+ usage_options();
+ printf("\t--version\tshow version (%s)\n", calibrator_version);
+ printf("Commands:\n");
+ for_each_cmd(section) {
+ if (section->parent)
+ continue;
+
+ if (section->handler && !section->hidden)
+ __usage_cmd(section, "\t", full);
+
+ for_each_cmd(cmd) {
+ if (section != cmd->parent)
+ continue;
+ if (!cmd->handler || cmd->hidden)
+ continue;
+ __usage_cmd(cmd, "\t", full);
+ }
+ }
+#if 0
+ printf("\nYou can omit the 'phy' or 'dev' if "
+ "the identification is unique,\n"
+ "e.g. \"iw wlan0 info\" or \"iw phy0 info\". "
+ "(Don't when scripting.)\n\n"
+ "Do NOT screenscrape this tool, we don't "
+ "consider its output stable.\n\n");
+#endif
+}
+
+static int print_help(struct nl80211_state *state,
+ struct nl_cb *cb,
+ struct nl_msg *msg,
+ int argc, char **argv)
+{
+ exit(3);
+}
+TOPLEVEL(help, NULL, 0, 0, CIB_NONE, print_help,
+ "Print usage for each command.");
+
+static void usage_cmd(const struct cmd *cmd)
+{
+ printf("\nUsage:\t%s [options] ", argv0);
+ __usage_cmd(cmd, "", true);
+ usage_options();
+}
+
+static void version(void)
+{
+ printf("calibrator version %s\n", calibrator_version);
+}
+
+static int phy_lookup(char *name)
+{
+ char buf[200];
+ int fd, pos;
+
+ snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
+
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ return -1;
+ pos = read(fd, buf, sizeof(buf) - 1);
+ if (pos < 0) {
+ close(fd);
+ return -1;
+ }
+ buf[pos] = '\0';
+ close(fd);
+ return atoi(buf);
+}
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+ void *arg)
+{
+ int *ret = arg;
+ *ret = err->error;
+
+ return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+
+ return NL_SKIP;
+}
+
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+
+ return NL_STOP;
+}
+
+static int __handle_cmd(struct nl80211_state *state, enum id_input idby,
+ int argc, char **argv, const struct cmd **cmdout)
+{
+ const struct cmd *cmd, *match = NULL, *sectcmd;
+ struct nl_cb *cb;
+ struct nl_msg *msg;
+ int devidx = 0;
+ int err, o_argc;
+ const char *command, *section;
+ char *tmp, **o_argv;
+ enum command_identify_by command_idby = CIB_NONE;
+#if 0
+ if (file_exist(CURRENT_NVS_NAME) < 0) {
+ fprintf(stderr, "\n\tUnable to find NVS file (%s).\n\t"
+ "Make sure to use reference-nvs.bin instead.\n\n",
+ CURRENT_NVS_NAME);
+ return 2;
+ }
+#endif
+ if (argc <= 1)
+ return 1;
+
+ o_argc = argc;
+ o_argv = argv;
+
+ switch (idby) {
+ case II_PHY_IDX:
+ command_idby = CIB_PHY;
+ devidx = strtoul(*argv + 4, &tmp, 0);
+ if (*tmp != '\0')
+ return 1;
+ argc--;
+ argv++;
+ break;
+ case II_PHY_NAME:
+ command_idby = CIB_PHY;
+ devidx = phy_lookup(*argv);
+ argc--;
+ argv++;
+ break;
+ case II_NETDEV:
+ command_idby = CIB_NETDEV;
+ devidx = if_nametoindex(*argv);
+ if (devidx == 0)
+ devidx = -1;
+ argc--;
+ argv++;
+ break;
+ default:
+ break;
+ }
+
+ if (devidx < 0)
+ return -errno;
+
+ section = *argv;
+ argc--;
+ argv++;
+
+ for_each_cmd(sectcmd) {
+ if (sectcmd->parent)
+ continue;
+ /* ok ... bit of a hack for the dupe 'info' section */
+ if (match && sectcmd->idby != command_idby)
+ continue;
+
+ if (strcmp(sectcmd->name, section) == 0)
+ match = sectcmd;
+ }
+
+ sectcmd = match;
+ match = NULL;
+ if (!sectcmd)
+ return 1;
+
+ if (argc > 0) {
+ command = *argv;
+
+ for_each_cmd(cmd) {
+ if (!cmd->handler)
+ continue;
+ if (cmd->parent != sectcmd)
+ continue;
+ if (cmd->idby != command_idby)
+ continue;
+ if (strcmp(cmd->name, command))
+ continue;
+ if (argc > 1 && !cmd->args)
+ continue;
+ match = cmd;
+ break;
+ }
+
+ if (match) {
+ argc--;
+ argv++;
+ }
+ }
+
+
+ if (match)
+ cmd = match;
+ else {
+ /* Use the section itself, if possible. */
+ cmd = sectcmd;
+ if (argc && !cmd->args)
+ return 1;
+ if (cmd->idby != command_idby)
+ return 1;
+ if (!cmd->handler)
+ return 1;
+ }
+
+ if (cmdout)
+ *cmdout = cmd;
+
+ if (!cmd->cmd) {
+ argc = o_argc;
+ argv = o_argv;
+ return cmd->handler(state, NULL, NULL, argc, argv);
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ fprintf(stderr, "failed to allocate netlink message\n");
+ return 2;
+ }
+
+ cb = nl_cb_alloc(calibrator_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
+ if (!cb) {
+ fprintf(stderr, "failed to allocate netlink callbacks\n");
+ err = 2;
+ goto out_free_msg;
+ }
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
+ cmd->nl_msg_flags, cmd->cmd, 0);
+
+ switch (command_idby) {
+ case CIB_PHY:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
+ break;
+ case CIB_NETDEV:
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
+ break;
+ default:
+ break;
+ }
+
+ err = cmd->handler(state, cb, msg, argc, argv);
+ if (err) {
+ fprintf(stderr, "failed to handle\n");
+ goto out;
+ }
+
+ err = nl_send_auto_complete(state->nl_sock, msg);
+ if (err < 0) {
+ fprintf(stderr, "failed to autocomplete\n");
+ goto out;
+ }
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+
+ while (err > 0)
+ nl_recvmsgs(state->nl_sock, cb);
+
+ out:
+ nl_cb_put(cb);
+ out_free_msg:
+ nlmsg_free(msg);
+ return err;
+
+ nla_put_failure:
+ fprintf(stderr, "building message failed\n");
+ return 2;
+}
+
+int handle_cmd(struct nl80211_state *state, enum id_input idby,
+ int argc, char **argv)
+{
+ return __handle_cmd(state, idby, argc, argv, NULL);
+}
+
+int main(int argc, char **argv)
+{
+ struct nl80211_state nlstate;
+ int err;
+ const struct cmd *cmd = NULL;
+
+ /* calculate command size including padding */
+ cmd_size = abs((long)&__section_set - (long)&__section_get);
+ /* strip off self */
+ argc--;
+ argv0 = *argv++;
+
+ if (argc > 0 && strcmp(*argv, "--debug") == 0) {
+ calibrator_debug = 1;
+ argc--;
+ argv++;
+ }
+
+ if (argc > 0 && ((strcmp(*argv, "--version") == 0) ||
+ (strcmp(*argv, "-v") == 0))) {
+ version();
+ return 0;
+ }
+
+ /* need to treat "help" command specially so it works w/o nl80211 */
+ if (argc == 0 || strcmp(*argv, "help") == 0) {
+ usage(argc != 0);
+ return 0;
+ }
+
+ err = nl80211_init(&nlstate);
+ if (err)
+ return 1;
+
+ if (strcmp(*argv, "dev") == 0 && argc > 1) {
+ argc--;
+ argv++;
+ err = __handle_cmd(&nlstate, II_NETDEV, argc, argv, &cmd);
+ } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) {
+ if (strlen(*argv) == 3) {
+ argc--;
+ argv++;
+ err = __handle_cmd(&nlstate, II_PHY_NAME,
+ argc, argv, &cmd);
+ } else if (*(*argv + 3) == '#')
+ err = __handle_cmd(&nlstate, II_PHY_IDX,
+ argc, argv, &cmd);
+ else
+ goto detect;
+ } else {
+ int idx;
+ enum id_input idby = II_NONE;
+ detect:
+ idx = if_nametoindex(argv[0]);
+ if (idx != 0)
+ idby = II_NETDEV;
+ else {
+ idx = phy_lookup(argv[0]);
+ if (idx >= 0)
+ idby = II_PHY_NAME;
+ }
+
+ err = __handle_cmd(&nlstate, idby, argc, argv, &cmd);
+ }
+
+ if (err == 1) {
+ if (cmd)
+ usage_cmd(cmd);
+ else
+ usage(false);
+ } else if (err < 0)
+ fprintf(stderr, "command failed: %s (%d)\n",
+ strerror(-err), err);
+
+ nl80211_cleanup(&nlstate);
+
+ return err;
+}
+
+void str2mac(unsigned char *pmac, char *pch)
+{
+ int i;
+
+ for (i = 0; i < MAC_ADDR_LEN; i++) {
+ pmac[i] = (unsigned char)strtoul(pch, &pch, 16);
+ pch++;
+ }
+}
diff --git a/calibrator.h b/calibrator.h
new file mode 100644
index 0000000..5daf96a
--- /dev/null
+++ b/calibrator.h
@@ -0,0 +1,157 @@
+#ifndef __CALIBRATOR_H
+#define __CALIBRATOR_H
+
+#include <stdbool.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+
+#include "nl80211.h"
+
+#define ETH_ALEN 6
+
+#if !defined CONFIG_LIBNL20 && !defined CONFIG_LIBNL32
+# define nl_sock nl_handle
+#endif
+
+struct nl80211_state {
+ struct nl_sock *nl_sock;
+ struct nl_cache *nl_cache;
+ struct genl_family *nl80211;
+};
+
+enum command_identify_by {
+ CIB_NONE,
+ CIB_PHY,
+ CIB_NETDEV,
+};
+
+enum id_input {
+ II_NONE,
+ II_NETDEV,
+ II_PHY_NAME,
+ II_PHY_IDX,
+};
+
+struct cmd {
+ const char *name;
+ const char *args;
+ const char *help;
+ const enum nl80211_commands cmd;
+ int nl_msg_flags;
+ int hidden;
+ const enum command_identify_by idby;
+ /*
+ * The handler should return a negative error code,
+ * zero on success, 1 if the arguments were wrong
+ * and the usage message should and 2 otherwise.
+ */
+ int (*handler)(struct nl80211_state *state,
+ struct nl_cb *cb,
+ struct nl_msg *msg,
+ int argc, char **argv);
+ const struct cmd *parent;
+};
+
+#define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
+
+#define __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help)\
+ static struct cmd \
+ __cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden\
+ __attribute__((used)) __attribute__((section("__cmd"))) = { \
+ .name = (_name), \
+ .args = (_args), \
+ .cmd = (_nlcmd), \
+ .nl_msg_flags = (_flags), \
+ .hidden = (_hidden), \
+ .idby = (_idby), \
+ .handler = (_handler), \
+ .help = (_help), \
+ .parent = _section, \
+ }
+#define COMMAND(section, name, args, cmd, flags, idby, handler, help) \
+ __COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 0, idby, handler, help)
+#define HIDDEN(section, name, args, cmd, flags, idby, handler) \
+ __COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 1, idby, handler, NULL)
+
+#define TOPLEVEL(_name, _args, _nlcmd, _flags, _idby, _handler, _help) \
+ struct cmd \
+ __section ## _ ## _name \
+ __attribute__((used)) __attribute__((section("__cmd"))) = { \
+ .name = (#_name), \
+ .args = (_args), \
+ .cmd = (_nlcmd), \
+ .nl_msg_flags = (_flags), \
+ .idby = (_idby), \
+ .handler = (_handler), \
+ .help = (_help), \
+ }
+#define SECTION(_name) \
+ struct cmd __section ## _ ## _name \
+ __attribute__((used)) __attribute__((section("__cmd"))) = { \
+ .name = (#_name), \
+ .hidden = 1, \
+ }
+
+#define DECLARE_SECTION(_name) \
+ extern struct cmd __section ## _ ## _name;
+
+extern int calibrator_debug;
+
+int handle_cmd(struct nl80211_state *state, enum id_input idby,
+ int argc, char **argv);
+
+struct print_event_args {
+ bool frame, time;
+};
+
+__u32 listen_events(struct nl80211_state *state,
+ const int n_waits, const __u32 *waits);
+__u32 __listen_events(struct nl80211_state *state,
+ const int n_waits, const __u32 *waits,
+ struct print_event_args *args);
+
+
+int mac_addr_a2n(unsigned char *mac_addr, char *arg);
+void mac_addr_n2a(char *mac_addr, unsigned char *arg);
+
+int parse_keys(struct nl_msg *msg, char **argv, int argc);
+
+void print_ht_mcs(const __u8 *mcs);
+void print_ampdu_length(__u8 exponent);
+void print_ampdu_spacing(__u8 spacing);
+void print_ht_capability(__u16 cap);
+
+const char *iftype_name(enum nl80211_iftype iftype);
+const char *command_name(enum nl80211_commands cmd);
+int ieee80211_channel_to_frequency(int chan);
+int ieee80211_frequency_to_channel(int freq);
+
+void print_ssid_escaped(const uint8_t len, const uint8_t *data);
+
+int nl_get_multicast_id(struct nl_sock *sock, const char *family,
+ const char *group);
+
+char *reg_initiator_to_string(__u8 initiator);
+
+const char *get_reason_str(uint16_t reason);
+const char *get_status_str(uint16_t status);
+
+enum print_ie_type {
+ PRINT_SCAN,
+ PRINT_LINK,
+};
+
+#define BIT(x) (1ULL<<(x))
+
+void print_ies(unsigned char *ie, int ielen, bool unknown,
+ enum print_ie_type ptype);
+
+void str2mac(unsigned char *pmac, char *pch);
+
+DECLARE_SECTION(set);
+DECLARE_SECTION(get);
+DECLARE_SECTION(plt);
+
+#endif /* __CALIBRATOR_H */
diff --git a/ini.c b/ini.c
new file mode 100644
index 0000000..46cd8c7
--- /dev/null
+++ b/ini.c
@@ -0,0 +1,1773 @@
+
+
+/*
+ * PLT utility for wireless chip supported by TI's driver wl12xx
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <limits.h>
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include <linux/wireless.h>
+#include "nl80211.h"
+
+#include "calibrator.h"
+#include "plt.h"
+#include "ini.h"
+#include "nvs.h"
+
+static char *ini_get_line(char *s, int size, FILE *stream, int *line,
+ char **_pos)
+{
+ char *pos, *end, *sstart;
+
+ while (fgets(s, size, stream)) {
+ s[size - 1] = '\0';
+ pos = s;
+
+ /* Skip white space from the beginning of line. */
+ while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+ pos++;
+
+ /* Skip comment lines and empty lines */
+ if (*pos == '#' || *pos == '\n' || *pos == '\0')
+ continue;
+
+ /*
+ * Remove # comments unless they are within a double quoted
+ * string.
+ */
+ sstart = strchr(pos, '"');
+ if (sstart)
+ sstart = strrchr(sstart + 1, '"');
+ if (!sstart)
+ sstart = pos;
+ end = strchr(sstart, '#');
+ if (end)
+ *end-- = '\0';
+ else
+ end = pos + strlen(pos) - 1;
+
+ /* Remove trailing white space. */
+ while (end > pos &&
+ (*end == '\n' || *end == ' ' || *end == '\t' ||
+ *end == '\r'))
+ *end-- = '\0';
+
+ if (*pos == '\0')
+ continue;
+
+ (*line)++;
+
+ if (_pos)
+ *_pos = pos;
+ return pos;
+ }
+
+ if (_pos)
+ *_pos = NULL;
+
+ return NULL;
+}
+
+static int split_line(char *line, char **name, char **value)
+{
+ char *pos = line;
+
+ *value = strchr(pos, '=');
+ if (!*value) {
+ fprintf(stderr, "Wrong format of line\n");
+ return 1;
+ }
+
+ *name = *value;
+
+ (*name)--;
+ while (**name == ' ' || **name == '\t' || **name == '\r')
+ (*name)--;
+
+ *++(*name) = '\0';
+
+ (*value)++;
+ while (**value == ' ' || **value == '\t' || **value == '\r')
+ (*value)++;
+
+ return 0;
+}
+
+/* Parse array of unsigned chars */
+static int parse_uc_a(char* name, char *val, unsigned char *out, size_t exp_size)
+{
+ size_t i = 0;
+ long v;
+ char *endval;
+
+ while (*val) {
+ /* Advance to next token */
+ while (*val == ' ' || *val == ',')
+ val++;
+
+ if (i >= exp_size) {
+ fprintf(stderr, "Too many params for %s\n", name);
+ return 1;
+ }
+ v = strtol(val, &endval, 16);
+
+ if (endval == val) {
+ fprintf(stderr, "Syntax error parsing %s\n", name);
+ return 1;
+ }
+ if (v > (long) UCHAR_MAX) {
+ fprintf(stderr, "Overflow parsing %s\n", name);
+ return 1;
+ }
+ out[i++] = v;
+ val = endval;
+ }
+
+ if(exp_size != i) {
+ fprintf(stderr, "Too few parameters for %s\n", name);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Parse array of __le16 */
+static int parse_ui_a(char* name, char *val, __le16 *out, size_t exp_size)
+{
+ size_t i = 0;
+ long v;
+ char *endval;
+ unsigned char *ptr = (unsigned char *)out;
+
+ while (*val) {
+ /* Advance to next token */
+ while (*val == ' ' || *val == ',')
+ val++;
+
+ if (i >= exp_size) {
+ fprintf(stderr, "Too many params for %s\n", name);
+ return 1;
+ }
+ v = strtol(val, &endval, 16);
+
+ if (endval == val) {
+ fprintf(stderr, "Syntax error parsing %s\n", name);
+ return 1;
+ }
+ if (v > (long) INT16_MAX) {
+ fprintf(stderr, "Overflow parsing %s\n", name);
+ return 1;
+ }
+ ptr[i*2] = (unsigned char) v;
+ ptr[(i*2)+1] = (unsigned char) (v >> 8);
+ i++;
+
+ val = endval;
+ }
+
+ if(exp_size != i) {
+ fprintf(stderr, "Too few parameters for %s\n", name);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define COMPARE_N_ADD(temp, str, val, ptr) \
+ if (strncmp(temp, str, sizeof(temp)) == 0) { \
+ return parse_uc_a(temp, val, (unsigned char*) ptr, sizeof(*ptr)); \
+ }
+
+#define COMPARE_N_ADD2(temp, str, val, ptr) \
+ if (strncmp(temp, str, sizeof(temp)) == 0) { \
+ return parse_ui_a(temp, val, (__le16*) ptr, sizeof(*ptr)/2); \
+ }
+
+static int parse_general_prms(char *l, struct wl12xx_common *cmn,
+ struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_general_params *gp = &(p->ini1271.general_params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD("TXBiPFEMAutoDetect", l, val,
+ &gp->tx_bip_fem_auto_detect);
+
+ cmn->auto_fem = gp->tx_bip_fem_auto_detect;
+
+ COMPARE_N_ADD("TXBiPFEMManufacturer", l, val,
+ &gp->tx_bip_fem_manufacturer);
+
+ COMPARE_N_ADD("RefClk", l, val, &gp->ref_clock);
+
+ COMPARE_N_ADD("SettlingTime", l, val, &gp->settling_time);
+
+ COMPARE_N_ADD("ClockValidOnWakeup", l, val,
+ &gp->clk_valid_on_wakeup);
+
+ COMPARE_N_ADD("DC2DCMode", l, val, &gp->dc2dc_mode);
+
+ COMPARE_N_ADD("Single_Dual_Band_Solution", l, val,
+ &gp->dual_mode_select);
+
+ COMPARE_N_ADD("Settings", l, val, &gp->general_settings);
+
+ COMPARE_N_ADD("SRState", l, val, &gp->sr_state);
+
+ COMPARE_N_ADD("SRF1", l, val, &gp->srf1);
+
+ COMPARE_N_ADD("SRF2", l, val, &gp->srf2);
+
+ COMPARE_N_ADD("SRF3", l, val, &gp->srf3);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_general_prms_128x(char *l, struct wl12xx_common *cmn,
+ struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_general_params *gp =
+ &(p->ini128x.general_params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+
+ COMPARE_N_ADD("TXBiPFEMAutoDetect", l, val,
+ &gp->tx_bip_fem_auto_detect);
+
+ COMPARE_N_ADD("TXBiPFEMManufacturer", l, val,
+ &gp->tx_bip_fem_manufacturer);
+
+ cmn->auto_fem = gp->tx_bip_fem_auto_detect;
+
+ COMPARE_N_ADD("RefClk", l, val, &gp->ref_clock);
+
+ COMPARE_N_ADD("SettlingTime", l, val, &gp->settling_time);
+
+ COMPARE_N_ADD("ClockValidOnWakeup", l, val, &gp->clk_valid_on_wakeup);
+
+ COMPARE_N_ADD("TCXO_Clk", l, val, &gp->tcxo_ref_clock);
+
+ COMPARE_N_ADD("TCXO_SettlingTime", l, val, &gp->tcxo_settling_time);
+
+ COMPARE_N_ADD("TCXO_ClockValidOnWakeup", l, val,
+ &gp->tcxo_valid_on_wakeup);
+
+ COMPARE_N_ADD("TCXO_LDO_Voltage", l, val, &gp->tcxo_ldo_voltage);
+
+ COMPARE_N_ADD("Platform_configuration", l, val, &gp->platform_conf);
+
+ COMPARE_N_ADD("Single_Dual_Band_Solution", l, val,
+ &gp->dual_mode_select);
+
+ COMPARE_N_ADD("Settings", l, val, &gp->general_settings);
+
+ COMPARE_N_ADD("XTALItrimVal", l, val, &gp->xtal_itrim_val);
+
+ COMPARE_N_ADD("SRState", l, val, &gp->sr_state);
+
+ COMPARE_N_ADD("SRF1", l, val, &gp->srf1);
+
+ COMPARE_N_ADD("SRF2", l, val, &gp->srf2);
+
+ COMPARE_N_ADD("SRF3", l, val, &gp->srf3);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_band2_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_band_params_2 *gp =
+ &(p->ini1271.stat_radio_params_2);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD("RxTraceInsertionLoss_2_4G", l, val,
+ &gp->rx_trace_insertion_loss);
+
+ COMPARE_N_ADD("TXTraceLoss_2_4G", l, val,
+ &gp->tx_trace_loss);
+
+ COMPARE_N_ADD("RxRssiAndProcessCompensation_2_4G", l, val,
+ &gp->rx_rssi_process_compens);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_band2_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_band_params_2 *gp = &(p->ini128x.stat_radio_params_2);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD("RxTraceInsertionLoss_2_4G", l, val,
+ &gp->rx_trace_insertion_loss);
+
+ COMPARE_N_ADD("TxTraceLoss_2_4G", l, val, &gp->tx_trace_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_band5_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_band_params_5 *gp =
+ &(p->ini1271.stat_radio_params_5);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD("RxTraceInsertionLoss_5G", l, val,
+ &gp->rx_trace_insertion_loss);
+
+ COMPARE_N_ADD("TXTraceLoss_5G", l, val,
+ &gp->tx_trace_loss);
+
+ COMPARE_N_ADD("RxRssiAndProcessCompensation_5G", l, val,
+ &gp->rx_rssi_process_compens);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_band5_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_band_params_5 *gp = &(p->ini128x.stat_radio_params_5);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD("RxTraceInsertionLoss_5G", l, val,
+ &gp->rx_trace_insertion_loss);
+
+ COMPARE_N_ADD("TxTraceLoss_5G", l, val,
+ &gp->tx_trace_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem0_band2_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_fem_params_2 *gp =
+ &(p->ini1271.dyn_radio_params_2[0].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM0_TXBiPReferencePDvoltage_2_4G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM0_TxBiPReferencePower_2_4G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM0_TxBiPOffsetdB_2_4G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM0_DegradedLowToNormalThr_2_4G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM0_NormalToDegradedHighThr_2_4G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_11b", l, val,
+ &gp->tx_per_chan_pwr_limits_11b);
+
+ COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM0_TxPDVsRateOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM0_TxIbiasTable_2_4G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM0_RxFemInsertionLoss_2_4G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem0_band2_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_fem_params_2 *gp =
+ &(p->ini128x.dyn_radio_params_2[0].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM0_TxBiPReferencePDvoltage_2_4G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM0_TxBiPReferencePower_2_4G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM0_TxBiPOffsetdB_2_4G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM0_DegradedLowToNormalThr_2_4G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM0_NormalToDegradedHighThr_2_4G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_11b", l, val,
+ &gp->tx_per_chan_pwr_limits_11b);
+
+ COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM0_TxPDVsRateOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM0_TxPDVsChannelOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_chan_offsets);
+
+ COMPARE_N_ADD("FEM0_TxPDVsTemperature_2_4G", l, val,
+ &gp->tx_pd_vs_temperature);
+
+ COMPARE_N_ADD("FEM0_TxIbiasTable_2_4G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM0_RxFemInsertionLoss_2_4G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem1_band2_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_fem_params_2 *gp =
+ &(p->ini1271.dyn_radio_params_2[1].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM1_TXBiPReferencePDvoltage_2_4G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM1_TxBiPReferencePower_2_4G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM1_TxBiPOffsetdB_2_4G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_2_4G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_2_4G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_11b", l, val,
+ &gp->tx_per_chan_pwr_limits_11b);
+
+ COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM1_TxIbiasTable_2_4G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM1_RxFemInsertionLoss_2_4G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem1_band2_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_fem_params_2 *gp =
+ &(p->ini128x.dyn_radio_params_2[1].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM1_TxBiPReferencePDvoltage_2_4G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM1_TxBiPReferencePower_2_4G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM1_TxBiPOffsetdB_2_4G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_2_4G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_2_4G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_11b", l, val,
+ &gp->tx_per_chan_pwr_limits_11b);
+
+ COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM1_TxPDVsChannelOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_chan_offsets);
+
+ COMPARE_N_ADD("FEM1_TxPDVsTemperature_2_4G", l, val,
+ &gp->tx_pd_vs_temperature);
+
+ COMPARE_N_ADD("FEM1_TxIbiasTable_2_4G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM1_RxFemInsertionLoss_2_4G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem2_band2_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_fem_params_2 *gp =
+ &(p->ini1271.dyn_radio_params_2[2].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM2_TXBiPReferencePDvoltage_2_4G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM2_TxBiPReferencePower_2_4G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM2_TxBiPOffsetdB_2_4G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_2_4G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_2_4G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_2_4G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM2_DegradedLowToNormalThr_2_4G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM2_NormalToDegradedHighThr_2_4G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM2_TxPerChannelPowerLimits_2_4G_11b", l, val,
+ &gp->tx_per_chan_pwr_limits_11b);
+
+ COMPARE_N_ADD("FEM2_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM2_TxPDVsRateOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM2_TxIbiasTable_2_4G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM2_RxFemInsertionLoss_2_4G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem2_band2_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_fem_params_2 *gp =
+ &(p->ini128x.dyn_radio_params_2[2].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM2_TxBiPReferencePDvoltage_2_4G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM2_TxBiPReferencePower_2_4G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM2_TxBiPOffsetdB_2_4G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_2_4G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_2_4G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_2_4G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM2_DegradedLowToNormalThr_2_4G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM2_NormalToDegradedHighThr_2_4G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM2_TxPerChannelPowerLimits_2_4G_11b", l, val,
+ &gp->tx_per_chan_pwr_limits_11b);
+
+ COMPARE_N_ADD("FEM2_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM2_TxPDVsRateOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM2_TxPDVsChannelOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_chan_offsets);
+
+ COMPARE_N_ADD("FEM2_TxPDVsTemperature_2_4G", l, val,
+ &gp->tx_pd_vs_temperature);
+
+ COMPARE_N_ADD("FEM2_TxIbiasTable_2_4G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM2_RxFemInsertionLoss_2_4G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem3_band2_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_fem_params_2 *gp =
+ &(p->ini1271.dyn_radio_params_2[3].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM3_TXBiPReferencePDvoltage_2_4G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM3_TxBiPReferencePower_2_4G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM3_TxBiPOffsetdB_2_4G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_2_4G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_2_4G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_2_4G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM3_DegradedLowToNormalThr_2_4G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM3_NormalToDegradedHighThr_2_4G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM3_TxPerChannelPowerLimits_2_4G_11b", l, val,
+ &gp->tx_per_chan_pwr_limits_11b);
+
+ COMPARE_N_ADD("FEM3_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM3_TxPDVsRateOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM3_TxIbiasTable_2_4G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM3_RxFemInsertionLoss_2_4G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem3_band2_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_fem_params_2 *gp =
+ &(p->ini128x.dyn_radio_params_2[3].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM3_TxBiPReferencePDvoltage_2_4G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM3_TxBiPReferencePower_2_4G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM3_TxBiPOffsetdB_2_4G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_2_4G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_2_4G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_2_4G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM3_DegradedLowToNormalThr_2_4G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM3_NormalToDegradedHighThr_2_4G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM3_TxPerChannelPowerLimits_2_4G_11b", l, val,
+ &gp->tx_per_chan_pwr_limits_11b);
+
+ COMPARE_N_ADD("FEM3_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM3_TxPDVsRateOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM3_TxPDVsChannelOffsets_2_4G", l, val,
+ &gp->tx_pd_vs_chan_offsets);
+
+ COMPARE_N_ADD("FEM3_TxPDVsTemperature_2_4G", l, val,
+ &gp->tx_pd_vs_temperature);
+
+ COMPARE_N_ADD("FEM3_TxIbiasTable_2_4G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM3_RxFemInsertionLoss_2_4G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem0_band5_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_fem_params_5 *gp =
+ &(p->ini1271.dyn_radio_params_5[0].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM0_TXBiPReferencePDvoltage_5G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM0_TxBiPReferencePower_5G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM0_TxBiPOffsetdB_5G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_5G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_5G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_5G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM0_DegradedLowToNormalThr_5G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM0_NormalToDegradedHighThr_5G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_5G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM0_TxPDVsRateOffsets_5G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM0_TxIbiasTable_5G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM0_RxFemInsertionLoss_5G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem0_band5_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_fem_params_5 *gp =
+ &(p->ini128x.dyn_radio_params_5[0].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM0_TxBiPReferencePDvoltage_5G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM0_TxBiPReferencePower_5G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM0_TxBiPOffsetdB_5G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_5G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_5G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_5G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM0_DegradedLowToNormalThr_5G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM0_NormalToDegradedHighThr_5G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_5G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM0_TxPDVsRateOffsets_5G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM0_TxPDVsChannelOffsets_5G", l, val,
+ &gp->tx_pd_vs_chan_offsets);
+
+ COMPARE_N_ADD("FEM0_TxPDVsTemperature_5G", l, val,
+ &gp->tx_pd_vs_temperature);
+
+ COMPARE_N_ADD("FEM0_TxIbiasTable_5G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM0_RxFemInsertionLoss_5G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem1_band5_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_fem_params_5 *gp =
+ &(p->ini1271.dyn_radio_params_5[1].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM1_TXBiPReferencePDvoltage_5G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM1_TxBiPReferencePower_5G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM1_TxBiPOffsetdB_5G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_5G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_5G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_5G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_5G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM1_TxIbiasTable_5G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM1_RxFemInsertionLoss_5G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem1_band5_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_fem_params_5 *gp =
+ &(p->ini128x.dyn_radio_params_5[1].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM1_TxBiPReferencePDvoltage_5G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM1_TxBiPReferencePower_5G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM1_TxBiPOffsetdB_5G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_5G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_5G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_5G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_5G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM1_TxPDVsChannelOffsets_5G", l, val,
+ &gp->tx_pd_vs_chan_offsets);
+
+ COMPARE_N_ADD("FEM1_TxPDVsTemperature_5G", l, val,
+ &gp->tx_pd_vs_temperature);
+
+ COMPARE_N_ADD("FEM1_TxIbiasTable_5G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM1_RxFemInsertionLoss_5G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem2_band5_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_fem_params_5 *gp =
+ &(p->ini1271.dyn_radio_params_5[2].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM2_TXBiPReferencePDvoltage_5G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM2_TxBiPReferencePower_5G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM2_TxBiPOffsetdB_5G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_5G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_5G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_5G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM2_DegradedLowToNormalThr_5G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM2_NormalToDegradedHighThr_5G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM2_TxPerChannelPowerLimits_5G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM2_TxPDVsRateOffsets_5G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM2_TxIbiasTable_5G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM2_RxFemInsertionLoss_5G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem2_band5_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_fem_params_5 *gp =
+ &(p->ini128x.dyn_radio_params_5[2].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM2_TxBiPReferencePDvoltage_5G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM2_TxBiPReferencePower_5G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM2_TxBiPOffsetdB_5G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_5G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_5G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM2_TxPerRatePowerLimits_5G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM2_DegradedLowToNormalThr_5G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM2_NormalToDegradedHighThr_5G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM2_TxPerChannelPowerLimits_5G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM2_TxPDVsRateOffsets_5G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM2_TxPDVsChannelOffsets_5G", l, val,
+ &gp->tx_pd_vs_chan_offsets);
+
+ COMPARE_N_ADD("FEM2_TxPDVsTemperature_5G", l, val,
+ &gp->tx_pd_vs_temperature);
+
+ COMPARE_N_ADD("FEM2_TxIbiasTable_5G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM2_RxFemInsertionLoss_5G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem3_band5_prms(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl1271_ini_fem_params_5 *gp =
+ &(p->ini1271.dyn_radio_params_5[3].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM3_TXBiPReferencePDvoltage_5G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM3_TxBiPReferencePower_5G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM3_TxBiPOffsetdB_5G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_5G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_5G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_5G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM3_DegradedLowToNormalThr_5G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM3_NormalToDegradedHighThr_5G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM3_TxPerChannelPowerLimits_5G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM3_TxPDVsRateOffsets_5G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM3_TxIbiasTable_5G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM3_RxFemInsertionLoss_5G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem3_band5_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini_fem_params_5 *gp =
+ &(p->ini128x.dyn_radio_params_5[3].params);
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD2("FEM3_TxBiPReferencePDvoltage_5G", l, val,
+ &gp->tx_bip_ref_pd_voltage);
+
+ COMPARE_N_ADD("FEM3_TxBiPReferencePower_5G", l, val,
+ &gp->tx_bip_ref_power);
+
+ COMPARE_N_ADD("FEM3_TxBiPOffsetdB_5G", l, val,
+ &gp->tx_bip_ref_offset);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_5G_Normal", l, val,
+ &gp->tx_per_rate_pwr_limits_normal);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_5G_Degraded", l, val,
+ &gp->tx_per_rate_pwr_limits_degraded);
+
+ COMPARE_N_ADD("FEM3_TxPerRatePowerLimits_5G_Extreme", l, val,
+ &gp->tx_per_rate_pwr_limits_extreme);
+
+ COMPARE_N_ADD("FEM3_DegradedLowToNormalThr_5G", l, val,
+ &gp->degraded_low_to_normal_thr);
+
+ COMPARE_N_ADD("FEM3_NormalToDegradedHighThr_5G", l, val,
+ &gp->normal_to_degraded_high_thr);
+
+ COMPARE_N_ADD("FEM3_TxPerChannelPowerLimits_5G_OFDM", l, val,
+ &gp->tx_per_chan_pwr_limits_ofdm);
+
+ COMPARE_N_ADD("FEM3_TxPDVsRateOffsets_5G", l, val,
+ &gp->tx_pd_vs_rate_offsets);
+
+ COMPARE_N_ADD("FEM3_TxPDVsChannelOffsets_5G", l, val,
+ &gp->tx_pd_vs_chan_offsets);
+
+ COMPARE_N_ADD("FEM3_TxPDVsTemperature_5G", l, val,
+ &gp->tx_pd_vs_temperature);
+
+ COMPARE_N_ADD("FEM3_TxIbiasTable_5G", l, val,
+ &gp->tx_ibias);
+
+ COMPARE_N_ADD("FEM3_RxFemInsertionLoss_5G", l, val,
+ &gp->rx_fem_insertion_loss);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int parse_fem_prms_128x(char *l, struct wl12xx_ini *p)
+{
+ char *name, *val;
+ struct wl128x_ini *gp = &p->ini128x;
+
+ if (split_line(l, &name, &val))
+ return 1;
+
+ COMPARE_N_ADD("FemVendorAndOptions", l, val,
+ &gp->fem_vendor_and_options);
+
+ fprintf(stderr, "Unable to parse: (%s)\n", l);
+
+ return 1;
+}
+
+static int find_section(const char *l, enum wl1271_ini_section *st, int *cntr,
+ struct wl12xx_common *cmn)
+{
+ enum wl12xx_arch arch = cmn->arch;
+ if (strncmp("TXBiPFEMAutoDetect", l, 18) == 0) {
+ *st = GENERAL_PRMS;
+ if (arch == WL128X_ARCH)
+ *cntr = 17;
+ else
+ *cntr = 12;
+
+ return 0;
+ }
+
+ if (strncmp("RxTraceInsertionLoss_2_4G", l, 25) == 0) {
+ *st = BAND2_PRMS;
+ if (arch == WL128X_ARCH)
+ *cntr = 2;
+ else
+ *cntr = 3;
+
+ return 0;
+ }
+
+ if (strncmp("FemVendorAndOptions", l, 19) == 0) {
+ *st = FEM_PRMS;
+ *cntr = 1;
+ return 0;
+ }
+
+ if (strncmp("RxTraceInsertionLoss_5G", l, 23) == 0) {
+ *st = BAND5_PRMS;
+ if (arch == WL128X_ARCH)
+ *cntr = 2;
+ else
+ *cntr = 3;
+
+ return 0;
+ }
+
+ if (strncmp("FEM0_TXBiPReferencePDvoltage_2_4G", l, 33) == 0 ||
+ strncmp("FEM0_TxBiPReferencePDvoltage_2_4G", l, 33) == 0) {
+ *st = FEM0_BAND2_PRMS;
+ cmn->fem0_bands++;
+ if (arch == WL128X_ARCH)
+ *cntr = 15;
+ else
+ *cntr = 13;
+
+ return 0;
+ }
+
+ if (strncmp("FEM1_TXBiPReferencePDvoltage_2_4G", l, 33) == 0 ||
+ strncmp("FEM1_TxBiPReferencePDvoltage_2_4G", l, 33) == 0) {
+ *st = FEM1_BAND2_PRMS;
+ cmn->fem1_bands++;
+ if (arch == WL128X_ARCH)
+ *cntr = 15;
+ else
+ *cntr = 13;
+
+ return 0;
+ }
+
+ if (strncmp("FEM2_TXBiPReferencePDvoltage_2_4G", l, 33) == 0 ||
+ strncmp("FEM2_TxBiPReferencePDvoltage_2_4G", l, 33) == 0) {
+ *st = FEM2_BAND2_PRMS;
+ cmn->fem2_bands++;
+ if (arch == WL128X_ARCH)
+ *cntr = 15;
+ else
+ *cntr = 13;
+
+ return 0;
+ }
+
+ if (strncmp("FEM3_TXBiPReferencePDvoltage_2_4G", l, 33) == 0 ||
+ strncmp("FEM3_TxBiPReferencePDvoltage_2_4G", l, 33) == 0) {
+ *st = FEM3_BAND2_PRMS;
+ cmn->fem3_bands++;
+ if (arch == WL128X_ARCH)
+ *cntr = 15;
+ else
+ *cntr = 13;
+
+ return 0;
+ }
+
+ if (strncmp("FEM0_TXBiPReferencePDvoltage_5G", l, 31) == 0 ||
+ strncmp("FEM0_TxBiPReferencePDvoltage_5G", l, 31) == 0) {
+ *st = FEM0_BAND5_PRMS;
+ cmn->fem0_bands++;
+ if (arch == WL128X_ARCH)
+ *cntr = 14;
+ else
+ *cntr = 12;
+
+ return 0;
+ }
+
+ if (strncmp("FEM1_TXBiPReferencePDvoltage_5G", l, 31) == 0 ||
+ strncmp("FEM1_TxBiPReferencePDvoltage_5G", l, 31) == 0) {
+ *st = FEM1_BAND5_PRMS;
+ cmn->fem1_bands++;
+ if (arch == WL128X_ARCH)
+ *cntr = 14;
+ else
+ *cntr = 12;
+
+ return 0;
+ }
+
+ if (strncmp("FEM2_TXBiPReferencePDvoltage_5G", l, 31) == 0 ||
+ strncmp("FEM2_TxBiPReferencePDvoltage_5G", l, 31) == 0) {
+ *st = FEM2_BAND5_PRMS;
+ cmn->fem2_bands++;
+ if (arch == WL128X_ARCH)
+ *cntr = 14;
+ else
+ *cntr = 12;
+
+ return 0;
+ }
+
+ if (strncmp("FEM3_TXBiPReferencePDvoltage_5G", l, 31) == 0 ||
+ strncmp("FEM3_TxBiPReferencePDvoltage_5G", l, 31) == 0) {
+ *st = FEM3_BAND5_PRMS;
+ cmn->fem3_bands++;
+ if (arch == WL128X_ARCH)
+ *cntr = 14;
+ else
+ *cntr = 12;
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static const char* ini_section_str(enum wl1271_ini_section section)
+{
+ const char *section_str;
+
+ switch(section) {
+
+ case GENERAL_PRMS:
+ section_str = "GENERAL_PARAMS";
+ break;
+
+ case FEM_PRMS:
+ section_str = "FEM_PARAMS";
+ break;
+
+ case BAND2_PRMS:
+ section_str = "BAND2_PARAMS";
+ break;
+
+ case BAND5_PRMS:
+ section_str = "BAND5_PARAMS";
+ break;
+
+ case FEM0_BAND2_PRMS:
+ section_str = "FEM0_BAND2_PARAMS";
+ break;
+
+ case FEM1_BAND2_PRMS:
+ section_str = "FEM1_BAND2_PARAMS";
+ break;
+
+ case FEM2_BAND2_PRMS:
+ section_str = "FEM2_BAND2_PARAMS";
+ break;
+
+ case FEM3_BAND2_PRMS:
+ section_str = "FEM3_BAND2_PARAMS";
+ break;
+
+ case FEM0_BAND5_PRMS:
+ section_str = "FEM0_BAND5_PARAMS";
+ break;
+
+ case FEM1_BAND5_PRMS:
+ section_str = "FEM1_BAND5_PARAMS";
+ break;
+
+ case FEM2_BAND5_PRMS:
+ section_str = "FEM2_BAND5_PARAMS";
+ break;
+
+ case FEM3_BAND5_PRMS:
+ section_str = "FEM3_BAND5_PARAMS";
+ break;
+
+ case UKNOWN_SECTION:
+ default:
+ section_str = "UNKNOWN_SECTION";
+ break;
+ }
+
+ return section_str;
+}
+
+static int ini_parse_line(char *l, struct wl12xx_common *cmn)
+{
+ static enum wl1271_ini_section status;
+ static int cntr;
+
+ if (cntr) {
+ /*
+ * Recovery mode -
+ * Check if didn't finish current section and we are already in
+ * another one. This can happen in case of optional params in section.
+ */
+ enum wl1271_ini_section curr_section = status;
+ if (!find_section(l, &status, &cntr, cmn)) {
+ printf("Some params missing in ini section %s moving to section %s\n",
+ ini_section_str(curr_section),
+ ini_section_str(status));
+ }
+ }
+
+ if (!cntr && find_section(l, &status, &cntr, cmn)) {
+ fprintf(stderr, "Uknown ini section %s\n", l);
+ return 1;
+ }
+
+ switch (status) {
+ case GENERAL_PRMS: /* general parameters */
+ cntr--;
+ return cmn->parse_ops->prs_general_prms(l, cmn, &cmn->ini);
+ case FEM_PRMS: /* FEM parameters */
+ if (cmn->arch == WL1271_ARCH) {
+ fprintf(stderr, "The parameter not from 127x architecture\n");
+ return 1;
+ }
+ cntr--;
+ return parse_fem_prms_128x(l, &cmn->ini);
+ case BAND2_PRMS: /* band 2.4GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_band2_prms(l, &cmn->ini);
+ case BAND5_PRMS: /* band 5GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_band5_prms(l, &cmn->ini);
+ case FEM0_BAND2_PRMS: /* FEM0 band 2.4GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_fem0_band2_prms(l, &cmn->ini);
+ case FEM1_BAND2_PRMS: /* FEM1 band 2.4GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_fem1_band2_prms(l, &cmn->ini);
+ case FEM2_BAND2_PRMS: /* FEM2 band 2.4GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_fem2_band2_prms(l, &cmn->ini);
+ case FEM3_BAND2_PRMS: /* FEM3 band 2.4GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_fem3_band2_prms(l, &cmn->ini);
+ case FEM0_BAND5_PRMS: /* FEM0 band 5GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_fem0_band5_prms(l, &cmn->ini);
+ case FEM1_BAND5_PRMS: /* FEM1 band 5GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_fem1_band5_prms(l, &cmn->ini);
+ case FEM2_BAND5_PRMS: /* FEM2 band 5GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_fem2_band5_prms(l, &cmn->ini);
+ case FEM3_BAND5_PRMS: /* FEM3 band 5GHz parameters */
+ cntr--;
+ return cmn->parse_ops->prs_fem3_band5_prms(l, &cmn->ini);
+ case UKNOWN_SECTION:
+ /* added because of compilation warning. handeled in find_section() */
+ break;
+ }
+
+ return 1;
+}
+
+#if 0
+static void ini_dump(struct wl1271_ini *ini)
+{
+ int i;
+
+ printf("\n");
+ printf("General params:\n");
+ printf("ref clock: %02X\n",
+ ini->general_params.ref_clock);
+ printf("settling time: %02X\n",
+ ini->general_params.settling_time);
+ printf("clk valid on wakeup: %02X\n",
+ ini->general_params.clk_valid_on_wakeup);
+ printf("dc2dc mode: %02X\n",
+ ini->general_params.dc2dc_mode);
+ printf("dual band mode: %02X\n",
+ ini->general_params.dual_mode_select);
+ printf("tx bip fem auto detect: %02X\n",
+ ini->general_params.tx_bip_fem_auto_detect);
+ printf("tx bip fem manufacturer: %02X\n",
+ ini->general_params.tx_bip_fem_manufacturer);
+ printf("general settings: %02X\n",
+ ini->general_params.general_settings);
+ printf("sr state: %02X\n",
+ ini->general_params.sr_state);
+
+ printf("srf1:");
+ for (i = 0; i < WL1271_INI_MAX_SMART_REFLEX_PARAM; i++)
+ printf(" %02X", ini->general_params.srf1[i]);
+ printf("\n");
+
+ printf("srf2:");
+ for (i = 0; i < WL1271_INI_MAX_SMART_REFLEX_PARAM; i++)
+ printf(" %02X", ini->general_params.srf2[i]);
+ printf("\n");
+
+ printf("srf3:");
+ for (i = 0; i < WL1271_INI_MAX_SMART_REFLEX_PARAM; i++)
+ printf(" %02X", ini->general_params.srf3[i]);
+ printf("\n");
+
+ printf("Static 2.4 band params:\n");
+
+ printf("rx trace insertion loss: %02X\n",
+ ini->stat_radio_params_2.rx_trace_insertion_loss);
+
+ printf("rx rssi n process compensation:");
+ for (i = 0; i < WL1271_INI_RSSI_PROCESS_COMPENS_SIZE; i++)
+ printf(" %02X",
+ ini->stat_radio_params_2.rx_rssi_process_compens[i]);
+ printf("\n");
+
+ printf("tx trace: %02X\n",
+ ini->stat_radio_params_2.tx_trace_loss);
+
+ printf("Dynamic 2.4 band params for FEM\n");
+
+ printf("Static 5 band params:\n");
+
+ printf("rx trace insertion loss:");
+ for (i = 0; i < WL1271_INI_SUB_BAND_COUNT_5; i++)
+ printf(" %02X",
+ ini->stat_radio_params_5.rx_rssi_process_compens[i]);
+ printf("\n");
+
+ printf("rx rssi n process compensation:");
+ for (i = 0; i < WL1271_INI_RSSI_PROCESS_COMPENS_SIZE; i++)
+ printf(" %02X",
+ ini->stat_radio_params_5.rx_rssi_process_compens[i]);
+ printf("\n");
+
+ printf("tx trace:");
+ for (i = 0; i < WL1271_INI_SUB_BAND_COUNT_5; i++)
+ printf(" %02X",
+ ini->stat_radio_params_5.tx_trace_loss[i]);
+ printf("\n");
+
+ printf("Dynamic 5 band params for FEM\n");
+
+}
+#endif
+
+
+static int is_dual_mode(struct wl12xx_ini *p)
+{
+ struct wl1271_ini_general_params *gp = &(p->ini1271.general_params);
+ return gp->dual_mode_select;
+}
+
+static int is_dual_mode_128x(struct wl12xx_ini *p)
+{
+ struct wl128x_ini_general_params *gp = &(p->ini128x.general_params);
+ return gp->dual_mode_select;
+}
+
+
+static struct wl12xx_parse_ops wl1271_parse_ops = {
+ .prs_general_prms = parse_general_prms,
+ .prs_band2_prms = parse_band2_prms,
+ .prs_band5_prms = parse_band5_prms,
+ .prs_fem0_band2_prms = parse_fem0_band2_prms,
+ .prs_fem1_band2_prms = parse_fem1_band2_prms,
+ .prs_fem2_band2_prms = parse_fem2_band2_prms,
+ .prs_fem3_band2_prms = parse_fem3_band2_prms,
+ .prs_fem0_band5_prms = parse_fem0_band5_prms,
+ .prs_fem1_band5_prms = parse_fem1_band5_prms,
+ .prs_fem2_band5_prms = parse_fem2_band5_prms,
+ .prs_fem3_band5_prms = parse_fem3_band5_prms,
+ .is_dual_mode = is_dual_mode,
+};
+
+static struct wl12xx_parse_ops wl128x_parse_ops = {
+ .prs_general_prms = parse_general_prms_128x,
+ .prs_band2_prms = parse_band2_prms_128x,
+ .prs_band5_prms = parse_band5_prms_128x,
+ .prs_fem0_band2_prms = parse_fem0_band2_prms_128x,
+ .prs_fem1_band2_prms = parse_fem1_band2_prms_128x,
+ .prs_fem2_band2_prms = parse_fem2_band2_prms_128x,
+ .prs_fem3_band2_prms = parse_fem3_band2_prms_128x,
+ .prs_fem0_band5_prms = parse_fem0_band5_prms_128x,
+ .prs_fem1_band5_prms = parse_fem1_band5_prms_128x,
+ .prs_fem2_band5_prms = parse_fem2_band5_prms_128x,
+ .prs_fem3_band5_prms = parse_fem3_band5_prms_128x,
+ .is_dual_mode = is_dual_mode_128x,
+};
+
+int ini_get_dual_mode(struct wl12xx_common *cmn)
+{
+ return cmn->parse_ops->is_dual_mode(&cmn->ini);
+}
+
+int nvs_get_arch(int file_size, struct wl12xx_common *cmn)
+{
+ enum wl12xx_arch arch = UNKNOWN_ARCH;
+
+ switch (file_size) {
+ case WL127X_NVS_FILE_SZ:
+ arch = WL1271_ARCH;
+ cmn->parse_ops = &wl1271_parse_ops;
+ break;
+ case WL128X_NVS_FILE_SZ:
+ arch = WL128X_ARCH;
+ cmn->parse_ops = &wl128x_parse_ops;
+ break;
+ }
+
+ if (cmn->arch != UNKNOWN_ARCH && cmn->arch != arch) {
+ cmn->parse_ops = NULL;
+ return 1;
+ }
+
+ cmn->arch = arch;
+
+ return 0;
+}
+
+static int ini_get_arch(FILE *f, struct wl12xx_common *cmn)
+{
+ char buf[1024], *pos;
+ int line = 0;
+ enum wl12xx_arch arch = UNKNOWN_ARCH;
+
+ while (ini_get_line(buf, sizeof(buf), f, &line, &pos)) {
+ if (strncmp("TCXO_Clk", pos, 8) == 0) {
+ arch = WL128X_ARCH;
+ break;
+ }
+ }
+
+ if (arch == UNKNOWN_ARCH)
+ arch = WL1271_ARCH;
+
+ if (cmn->arch != UNKNOWN_ARCH && cmn->arch != arch)
+ return 1;
+
+ cmn->arch = arch;
+
+ if (cmn->arch == WL1271_ARCH)
+ cmn->parse_ops = &wl1271_parse_ops;
+ else
+ cmn->parse_ops = &wl128x_parse_ops;
+
+ fseek(f, 0L, SEEK_SET);
+
+ return 0;
+}
+
+int read_ini(const char *filename, struct wl12xx_common *cmn)
+{
+ FILE *f;
+ char buf[1024], *pos;
+ int ret = 0, line = 0;
+
+ cmn->auto_fem = 0;
+ cmn->fem0_bands = 0;
+ cmn->fem1_bands = 0;
+ cmn->fem2_bands = 0;
+ cmn->fem3_bands = 0;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Unable to open file %s (%s)\n",
+ filename, strerror(errno));
+ return 1;
+ }
+
+ /* check if it 127x or 128x */
+ if (ini_get_arch(f, cmn)) {
+ fprintf(stderr, "Unable to define wireless architecture\n");
+ ret = 1;
+ goto out;
+ }
+
+ /* start parsing */
+ while (ini_get_line(buf, sizeof(buf), f, &line, &pos)) {
+ ret = ini_parse_line(pos, cmn);
+ if (ret) break;
+ }
+
+out:
+ fclose(f);
+#if 0
+ ini_dump(ini);
+#endif
+ return ret;
+}
diff --git a/ini.h b/ini.h
new file mode 100644
index 0000000..27f95a1
--- /dev/null
+++ b/ini.h
@@ -0,0 +1,359 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __INI_H__
+#define __INI_H__
+
+#include <linux/limits.h>
+
+#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
+
+struct wl1271_ini_general_params {
+ unsigned char ref_clock;
+ unsigned char settling_time;
+ unsigned char clk_valid_on_wakeup;
+ unsigned char dc2dc_mode;
+ unsigned char dual_mode_select;
+ unsigned char tx_bip_fem_auto_detect;
+ unsigned char tx_bip_fem_manufacturer;
+ unsigned char general_settings;
+ unsigned char sr_state;
+ unsigned char srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ unsigned char srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ unsigned char srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+} __attribute__((packed));
+
+#define WL128X_INI_MAX_SETTINGS_PARAM 4
+
+struct wl128x_ini_general_params {
+ unsigned char ref_clock;
+ unsigned char settling_time;
+ unsigned char clk_valid_on_wakeup;
+ unsigned char tcxo_ref_clock;
+ unsigned char tcxo_settling_time;
+ unsigned char tcxo_valid_on_wakeup;
+ unsigned char tcxo_ldo_voltage;
+ unsigned char xtal_itrim_val;
+ unsigned char platform_conf;
+ unsigned char dual_mode_select;
+ unsigned char tx_bip_fem_auto_detect;
+ unsigned char tx_bip_fem_manufacturer;
+ unsigned char general_settings[WL128X_INI_MAX_SETTINGS_PARAM];
+ unsigned char sr_state;
+ unsigned char srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ unsigned char srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ unsigned char srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+} __attribute__((packed));
+
+#define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15
+
+struct wl1271_ini_band_params_2 {
+ unsigned char rx_trace_insertion_loss;
+ unsigned char tx_trace_loss;
+ unsigned char
+ rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __attribute__((packed));
+
+#define WL1271_INI_CHANNEL_COUNT_2 14
+
+struct wl128x_ini_band_params_2 {
+ unsigned char rx_trace_insertion_loss;
+ unsigned char tx_trace_loss[WL1271_INI_CHANNEL_COUNT_2];
+ unsigned char
+ rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __attribute__((packed));
+
+#define WL1271_INI_RATE_GROUP_COUNT 6
+
+struct wl1271_ini_fem_params_2 {
+ __le16 tx_bip_ref_pd_voltage;
+ unsigned char tx_bip_ref_power;
+ unsigned char tx_bip_ref_offset;
+ unsigned char
+ tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char
+ tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char
+ tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2];
+ unsigned char tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2];
+ unsigned char tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char rx_fem_insertion_loss;
+ unsigned char degraded_low_to_normal_thr;
+ unsigned char normal_to_degraded_high_thr;
+} __attribute__((packed));
+
+#define WL128X_INI_RATE_GROUP_COUNT 7
+/* low and high temperatures*/
+#define WL128X_INI_PD_VS_TEMPERATURE_RANGES 2
+
+struct wl128x_ini_fem_params_2 {
+ __le16 tx_bip_ref_pd_voltage;
+ unsigned char tx_bip_ref_power;
+ unsigned char tx_bip_ref_offset;
+ unsigned char
+ tx_per_rate_pwr_limits_normal [WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char
+ tx_per_rate_pwr_limits_degraded [WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char
+ tx_per_rate_pwr_limits_extreme [WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2];
+ unsigned char tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2];
+ unsigned char tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char tx_ibias[WL128X_INI_RATE_GROUP_COUNT + 1];
+ unsigned char tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_2];
+ unsigned char tx_pd_vs_temperature[WL128X_INI_PD_VS_TEMPERATURE_RANGES];
+ unsigned char rx_fem_insertion_loss;
+ unsigned char degraded_low_to_normal_thr;
+ unsigned char normal_to_degraded_high_thr;
+} __attribute__((packed));
+
+#define WL1271_INI_CHANNEL_COUNT_5 35
+#define WL1271_INI_SUB_BAND_COUNT_5 7
+
+struct wl1271_ini_band_params_5 {
+ unsigned char rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char tx_trace_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char
+ rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __attribute__((packed));
+
+struct wl128x_ini_band_params_5 {
+ unsigned char rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char tx_trace_loss[WL1271_INI_CHANNEL_COUNT_5];
+ unsigned char
+ rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __attribute__((packed));
+
+struct wl1271_ini_fem_params_5 {
+ __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char
+ tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char
+ tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char
+ tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5];
+ unsigned char tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
+ unsigned char rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char degraded_low_to_normal_thr;
+ unsigned char normal_to_degraded_high_thr;
+} __attribute__((packed));
+
+struct wl128x_ini_fem_params_5 {
+ __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char
+ tx_per_rate_pwr_limits_normal [WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char
+ tx_per_rate_pwr_limits_degraded [WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char
+ tx_per_rate_pwr_limits_extreme [WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5];
+ unsigned char tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char tx_ibias[WL128X_INI_RATE_GROUP_COUNT];
+ unsigned char tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_5];
+ unsigned char tx_pd_vs_temperature[WL1271_INI_SUB_BAND_COUNT_5 *
+ WL128X_INI_PD_VS_TEMPERATURE_RANGES];
+ unsigned char rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ unsigned char degraded_low_to_normal_thr;
+ unsigned char normal_to_degraded_high_thr;
+} __attribute__((packed));
+
+/* NVS data structure */
+#define WL1271_INI_NVS_SECTION_SIZE 468
+
+/* We have four FEM module types: 0-RFMD, 1-TQS, 2-SKW, 3-TQS_HP */
+#define WL1271_INI_FEM_MODULE_COUNT 4
+
+#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
+/*
+ * In NVS we only store two FEM module entries -
+ * FEM modules 0,2,3 are stored in entry 0
+ * FEM module 1 is stored in entry 1
+ */
+#define WL12XX_NVS_FEM_MODULE_COUNT 2
+
+#define WL12XX_FEM_TO_NVS_ENTRY(ini_fem_module) \
+ ((ini_fem_module) == 1 ? 1 : 0)
+
+struct wl1271_nvs_ini {
+ struct wl1271_ini_general_params general_params;
+ unsigned char padding1;
+ struct wl1271_ini_band_params_2 stat_radio_params_2;
+ unsigned char padding2;
+ struct {
+ struct wl1271_ini_fem_params_2 params;
+ unsigned char padding;
+ } dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT];
+ struct wl1271_ini_band_params_5 stat_radio_params_5;
+ unsigned char padding3;
+ struct {
+ struct wl1271_ini_fem_params_5 params;
+ unsigned char padding;
+ } dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
+} __attribute__((packed));
+
+struct wl1271_nvs_file {
+ /* NVS section */
+ unsigned char nvs[WL1271_INI_NVS_SECTION_SIZE];
+ /* INI section */
+ struct wl1271_nvs_ini ini;
+} __attribute__((packed));
+
+struct wl128x_nvs_ini {
+ struct wl128x_ini_general_params general_params;
+ unsigned char fem_vendor_and_options;
+ struct wl128x_ini_band_params_2 stat_radio_params_2;
+ unsigned char padding2;
+ struct {
+ struct wl128x_ini_fem_params_2 params;
+ unsigned char padding;
+ } dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT];
+ struct wl128x_ini_band_params_5 stat_radio_params_5;
+ unsigned char padding3;
+ struct {
+ struct wl128x_ini_fem_params_5 params;
+ unsigned char padding;
+ } dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
+} __attribute__((packed));
+
+struct wl128x_nvs_file {
+ /* NVS section */
+ unsigned char nvs[WL1271_INI_NVS_SECTION_SIZE];
+ /* INI section */
+ struct wl128x_nvs_ini ini;
+} __attribute__((packed));
+
+struct wl1271_ini {
+ struct wl1271_ini_general_params general_params;
+ unsigned char padding1;
+ struct wl1271_ini_band_params_2 stat_radio_params_2;
+ unsigned char padding2;
+ struct {
+ struct wl1271_ini_fem_params_2 params;
+ unsigned char padding;
+ } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+ struct wl1271_ini_band_params_5 stat_radio_params_5;
+ unsigned char padding3;
+ struct {
+ struct wl1271_ini_fem_params_5 params;
+ unsigned char padding;
+ } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+} __attribute__((packed));
+
+struct wl128x_ini {
+ struct wl128x_ini_general_params general_params;
+ unsigned char fem_vendor_and_options;
+ struct wl128x_ini_band_params_2 stat_radio_params_2;
+ unsigned char padding2;
+ struct {
+ struct wl128x_ini_fem_params_2 params;
+ unsigned char padding;
+ } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+ struct wl128x_ini_band_params_5 stat_radio_params_5;
+ unsigned char padding3;
+ struct {
+ struct wl128x_ini_fem_params_5 params;
+ unsigned char padding;
+ } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+} __attribute__((packed));
+
+enum wl1271_ini_section {
+ UKNOWN_SECTION,
+ GENERAL_PRMS,
+ FEM_PRMS,
+ BAND2_PRMS,
+ BAND5_PRMS,
+ FEM0_BAND2_PRMS,
+ FEM1_BAND2_PRMS,
+ FEM2_BAND2_PRMS,
+ FEM3_BAND2_PRMS,
+ FEM0_BAND5_PRMS,
+ FEM1_BAND5_PRMS,
+ FEM2_BAND5_PRMS,
+ FEM3_BAND5_PRMS
+};
+
+enum wl12xx_arch {
+ UNKNOWN_ARCH,
+ WL1271_ARCH = 0x0403,
+ WL128X_ARCH = 0x0503
+};
+
+struct wl12xx_ini {
+ union {
+ struct wl1271_ini ini1271;
+ struct wl128x_ini ini128x;
+ };
+};
+
+#define DUAL_MODE_UNSET 0xff
+
+struct wl12xx_common {
+ enum wl12xx_arch arch;
+ unsigned char auto_fem;
+ unsigned int fem0_bands;
+ unsigned int fem1_bands;
+ unsigned int fem2_bands;
+ unsigned int fem3_bands;
+ struct wl12xx_parse_ops *parse_ops;
+ struct wl12xx_nvs_ops *nvs_ops;
+ struct wl12xx_ini ini;
+ char *nvs_name;
+};
+
+struct wl12xx_parse_ops {
+ int (*prs_general_prms)(char *l, struct wl12xx_common *cmn,
+ struct wl12xx_ini *p);
+ /* int (*prs_fem_prms)(char *l, void *gp); */
+ int (*prs_band2_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_band5_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_fem0_band2_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_fem1_band2_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_fem2_band2_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_fem3_band2_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_fem0_band5_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_fem1_band5_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_fem2_band5_prms)(char *l, struct wl12xx_ini *p);
+ int (*prs_fem3_band5_prms)(char *l, struct wl12xx_ini *p);
+ int (*is_dual_mode)(struct wl12xx_ini *p);
+};
+
+struct wl12xx_nvs_ops {
+ int (*nvs_fill_radio_prms)(int fd, struct wl12xx_ini *p, char *buf);
+ int (*nvs_set_autofem)(int fd, char *buf, unsigned char val);
+ int (*nvs_set_fem_manuf)(int fd, char *buf, unsigned char val);
+};
+
+int nvs_get_arch(int file_size, struct wl12xx_common *cmn);
+
+int read_ini(const char *filename, struct wl12xx_common *cmn);
+
+int ini_get_dual_mode(struct wl12xx_common *cmn);
+#endif
diff --git a/misc_cmds.c b/misc_cmds.c
new file mode 100644
index 0000000..8a2ebd0
--- /dev/null
+++ b/misc_cmds.c
@@ -0,0 +1,323 @@
+#include <stdbool.h>
+#include <errno.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include "calibrator.h"
+#include "plt.h"
+#include "ini.h"
+#include "nvs.h"
+
+SECTION(get);
+SECTION(set);
+
+static int get_nvs_mac(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ unsigned char mac_buff[12];
+ char *fname;
+ int fd;
+
+ argc -= 2;
+ argv += 2;
+
+ fname = get_opt_nvsinfile(argc, argv);
+ if (!fname)
+ return 1;
+
+ fd = open(fname, O_RDONLY);
+ if (fd < 0) {
+ perror("Error opening file for reading");
+ return 1;
+ }
+
+ read(fd, mac_buff, 12);
+
+ printf("MAC addr from NVS: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_buff[11], mac_buff[10], mac_buff[6],
+ mac_buff[5], mac_buff[4], mac_buff[3]);
+
+ close(fd);
+
+ return 0;
+}
+
+COMMAND(get, nvs_mac, "[<nvs filename>]", 0, 0, CIB_NONE, get_nvs_mac,
+ "Get MAC addr from NVS file (offline)");
+
+/*
+ * Sets MAC address in NVS.
+ * The default value for MAC is random where 1 byte zero.
+ */
+static int set_nvs_mac(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ argc -= 2;
+ argv += 2;
+
+ if ((argc != 2) || (strlen(argv[1]) != 17))
+ return 1;
+
+ nvs_set_mac(argv[0], argv[1]);
+ return 0;
+}
+
+COMMAND(set, nvs_mac, "<nvs file> <mac addr>", 0, 0, CIB_NONE, set_nvs_mac,
+ "Set MAC addr in NVS file (offline), like XX:XX:XX:XX:XX:XX");
+
+static int set_ref_nvs(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct wl12xx_common cmn = {
+ .arch = UNKNOWN_ARCH,
+ .parse_ops = NULL
+ };
+
+ argc -= 2;
+ argv += 2;
+
+ if (argc < 1 || argc > 2)
+ return 1;
+
+ if (read_ini(*argv, &cmn)) {
+ fprintf(stderr, "Fail to read ini file\n");
+ return 1;
+ }
+ argv++;
+ argc--;
+
+ cfg_nvs_ops(&cmn);
+
+ cmn.nvs_name = get_opt_nvsoutfile(argc, argv);
+ if (create_nvs_file(&cmn)) {
+ fprintf(stderr, "Fail to create reference NVS file\n");
+ return 1;
+ }
+
+ printf("%04X\n", cmn.arch);
+
+ return 0;
+}
+
+COMMAND(set, ref_nvs, "<ini file> [<nvs file>]", 0, 0, CIB_NONE, set_ref_nvs,
+ "Create reference NVS file");
+
+static int set_upd_nvs(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ char *infname = NULL, *outfname = NULL;
+ struct wl12xx_common cmn = {
+ .arch = UNKNOWN_ARCH,
+ .parse_ops = NULL
+ };
+
+ argc -= 2;
+ argv += 2;
+
+ if (argc < 1)
+ return 1;
+
+ if (read_ini(*argv, &cmn)) {
+ fprintf(stderr, "Fail to read ini file\n");
+ return 1;
+ }
+ argc--;
+ argv++;
+
+ infname = get_opt_nvsinfile(argc, argv);
+ if (!infname)
+ return 1;
+
+ if (argc) {
+ argc--;
+ argv++;
+ }
+ outfname = get_opt_nvsoutfile(argc, argv);
+ if (!outfname)
+ return 1;
+
+ cfg_nvs_ops(&cmn);
+
+ if (update_nvs_file(infname, outfname, &cmn)) {
+ fprintf(stderr, "Fail to update NVS file\n");
+ return 1;
+ }
+#if 0
+ printf("\n\tThe updated NVS file (%s) is ready\n\tCopy it to %s and "
+ "reboot the system\n\n", NEW_NVS_NAME, CURRENT_NVS_NAME);
+#endif
+ return 0;
+}
+
+COMMAND(set, upd_nvs, "<ini file> [<nvs infile>] [<nvs_outfile>]", 0, 0, CIB_NONE, set_upd_nvs,
+ "Update values of a NVS from INI file");
+
+static int get_dump_nvs(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ char *fname = NULL;
+
+ argc -= 2;
+ argv += 2;
+
+ fname = get_opt_nvsinfile(argc, argv);
+ if (!fname)
+ return 1;
+
+ if (dump_nvs_file(fname)) {
+ fprintf(stderr, "Fail to dump NVS file\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+COMMAND(get, dump_nvs, "[<nvs file>]", 0, 0, CIB_NONE, get_dump_nvs,
+ "Dump NVS file, specified by option or current");
+
+static int get_info_nvs(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ char *fname;
+
+ argc -= 2;
+ argv += 2;
+
+ fname = get_opt_nvsinfile(argc, argv);
+ if(!fname)
+ return 1;
+
+ if (info_nvs_file(fname)) {
+ fprintf(stderr, "Fail to read info from NVS file\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+COMMAND(get, info_nvs, "[<nvs file>]", 0, 0, CIB_NONE, get_info_nvs,
+ "Print information from nvs file");
+
+static int set_autofem(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ char *fname = NULL;
+ int res;
+ unsigned int val;
+ struct wl12xx_common cmn = {
+ .arch = UNKNOWN_ARCH,
+ .parse_ops = NULL
+ };
+
+ argc -= 2;
+ argv += 2;
+
+ if (argc < 1) {
+ fprintf(stderr, "Missing argument\n");
+ return 2;
+ }
+
+ res = sscanf(argv[0], "%x", &val);
+ if (res != 1 || val > 1) {
+ fprintf(stderr, "Invalid argument\n");
+ return 1;
+ }
+ argv++;
+ argc--;
+
+ fname = get_opt_nvsinfile(argc, argv);
+
+ if (set_nvs_file_autofem(fname, val, &cmn)) {
+ fprintf(stderr, "Fail to set AutoFEM\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+COMMAND(set, autofem, "<0-manual|1-auto> [<nvs file>]", 0, 0, CIB_NONE, set_autofem,
+ "Set Auto FEM detection, where 0 - manual, 1 - auto detection");
+
+static int set_fem_manuf(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ char *fname = NULL;
+ int res;
+ unsigned int val;
+ struct wl12xx_common cmn = {
+ .arch = UNKNOWN_ARCH,
+ .parse_ops = NULL
+ };
+
+ argc -= 2;
+ argv += 2;
+
+ if (argc < 1) {
+ fprintf(stderr, "Missing argument\n");
+ return 2;
+ }
+ res = sscanf(argv[0], "%x", &val);
+ if(res != 1 || val >= WL1271_INI_FEM_MODULE_COUNT) {
+ fprintf(stderr, "Invalid argument\n");
+ return 1;
+ }
+ argv++;
+ argc--;
+
+ fname = get_opt_nvsinfile(argc, argv);
+
+ if (set_nvs_file_fem_manuf(fname, val, &cmn)) {
+ fprintf(stderr, "Fail to set AutoFEM\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+COMMAND(set, fem_manuf, "<0|1|2|3> [<nvs file>]", 0, 0, CIB_NONE, set_fem_manuf,
+ "Set FEM manufacturer");
+
+static int get_drv_info(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ argc -= 2;
+ argv += 2;
+
+ if (argc < 1) {
+ fprintf(stderr, "Missing argument (device name)\n");
+ return 2;
+ }
+
+ return do_get_drv_info(argv[0], NULL, NULL);
+}
+
+COMMAND(get, drv_info, "<device name>", 0, 0, CIB_NONE, get_drv_info,
+ "Get driver information: PG version");
+
+static int get_hw_version(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ int ret, chip_id = 0;
+
+ argc -= 2;
+ argv += 2;
+
+ if (argc < 1) {
+ fprintf(stderr, "Missing argument (device name)\n");
+ return 2;
+ }
+
+ ret = do_get_drv_info(argv[0], &chip_id, NULL);
+ if (!ret)
+ printf("%08X\n", chip_id);
+
+ return ret;
+}
+
+COMMAND(get, hw_version, "<device name>", 0, 0, CIB_NONE, get_hw_version,
+ "Get HW version (chip id)");
+
diff --git a/nl80211.h b/nl80211.h
new file mode 100644
index 0000000..0096675
--- /dev/null
+++ b/nl80211.h
@@ -0,0 +1,1434 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006, 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
+ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
+ * Copyright 2008 Colin McCabe <colin@cozybit.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
+ * to get a list of all present wiphys.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
+ * or rename notification. Has attributes %NL80211_ATTR_WIPHY and
+ * %NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
+ *
+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
+ * either a dump request on a %NL80211_ATTR_WIPHY or a specific get
+ * on an %NL80211_ATTR_IFINDEX is supported.
+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
+ * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
+ * be sent from userspace to request creation of a new virtual interface,
+ * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
+ * %NL80211_ATTR_IFNAME.
+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
+ * userspace to request deletion of a virtual interface, then requires
+ * attribute %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
+ * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
+ * and %NL80211_ATTR_KEY_SEQ attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ * or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ * %NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ * parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all stations, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all mesh paths, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
+ * %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
+ * regulatory domain.
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ * after being queried by the kernel. CRDA replies by sending a regulatory
+ * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ * current alpha2 if it found a match. It also provides
+ * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * regulatory rule is a nested set of attributes given by
+ * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * store this as a valid request and then query userspace for it.
+ *
+ * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ * interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ * interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
+ * interface is identified with %NL80211_ATTR_IFINDEX and the management
+ * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
+ * added to the end of the specified management frame is specified with
+ * %NL80211_ATTR_IE. If the command succeeds, the requested data will be
+ * added to all specified management frames generated by
+ * kernel/firmware/driver.
+ * Note: This command has been removed and it is only reserved at this
+ * point to avoid re-using existing command number. The functionality this
+ * command was planned for has been provided with cleaner design with the
+ * option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN,
+ * NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE,
+ * NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
+ * NL80211_CMD_GET_SCAN and on the "scan" multicast group)
+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
+ * partial scan results may be available
+ *
+ * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
+ * or noise level
+ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
+ * NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
+ *
+ * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
+ * has been changed and provides details of the request information
+ * that caused the change such as who initiated the regulatory request
+ * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
+ * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
+ * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
+ * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
+ * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
+ * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
+ * to (%NL80211_ATTR_REG_ALPHA2).
+ * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
+ * has been found while world roaming thus enabling active scan or
+ * any mode of operation that initiates TX (beacons) on a channel
+ * where we would not have been able to do either before. As an example
+ * if you are world roaming (regulatory domain set to world or if your
+ * driver is using a custom world roaming regulatory domain) and while
+ * doing a passive scan on the 5 GHz band you find an AP there (if not
+ * on a DFS channel) you will now be able to actively scan for that AP
+ * or use AP mode on your card on that same channel. Note that this will
+ * never be used for channels 1-11 on the 2 GHz band as they are always
+ * enabled world wide. This beacon hint is only sent if your device had
+ * either disabled active scanning or beaconing on a channel. We send to
+ * userspace the wiphy on which we removed a restriction from
+ * (%NL80211_ATTR_WIPHY) and the channel on which this occurred
+ * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
+ * the beacon hint was processed.
+ *
+ * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
+ * This command is used both as a command (request to authenticate) and
+ * as an event on the "mlme" multicast group indicating completion of the
+ * authentication process.
+ * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
+ * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
+ * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
+ * the SSID (mainly for association, but is included in authentication
+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
+ * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
+ * is used to specify the authentication type. %NL80211_ATTR_IE is used to
+ * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
+ * to be added to the frame.
+ * When used as an event, this reports reception of an Authentication
+ * frame in station and IBSS modes when the local MLME processed the
+ * frame, i.e., it was for the local STA and was received in correct
+ * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
+ * MLME SAP interface (kernel providing MLME, userspace SME). The
+ * included %NL80211_ATTR_FRAME attribute contains the management frame
+ * (including both the header and frame body, but not FCS). This event is
+ * also used to indicate if the authentication attempt timed out. In that
+ * case the %NL80211_ATTR_FRAME attribute is replaced with a
+ * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
+ * pending authentication timed out).
+ * @NL80211_CMD_ASSOCIATE: association request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Association and Reassociation
+ * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
+ * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
+ * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
+ * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
+ * primitives).
+ * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
+ * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
+ *
+ * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
+ * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
+ * event includes %NL80211_ATTR_MAC to describe the source MAC address of
+ * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
+ * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
+ * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
+ * event matches with MLME-MICHAELMICFAILURE.indication() primitive
+ *
+ * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
+ * FREQ attribute (for the initial frequency if no peer can be found)
+ * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
+ * should be fixed rather than automatically determined. Can only be
+ * executed on a network interface that is UP, and fixed BSSID/FREQ
+ * may be rejected. Another optional parameter is the beacon interval,
+ * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
+ * given defaults to 100 TU (102.4ms).
+ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
+ * determined by the network interface.
+ *
+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
+ * to identify the device, and the TESTDATA blob attribute to pass through
+ * to the driver.
+ *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ * requests to connect to a specified network but without separating
+ * auth and assoc steps. For this, you need to specify the SSID in a
+ * %NL80211_ATTR_SSID attribute, and can optionally specify the association
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ * It is also sent as an event, with the BSSID and response IEs when the
+ * connection is established or failed to be established. This can be
+ * determined by the STATUS_CODE attribute.
+ * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
+ * sent as an event when the card/driver roamed by itself.
+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+ * userspace that a connection was dropped by the AP or due to other
+ * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
+ * %NL80211_ATTR_REASON_CODE attributes are used.
+ *
+ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
+ * associated with this wiphy must be down and will follow.
+ *
+ * @NL80211_CMD_MAX: highest used command number
+ * @__NL80211_CMD_AFTER_LAST: internal use
+ */
+enum nl80211_commands {
+/* don't change the order or add anything inbetween, this is ABI! */
+ NL80211_CMD_UNSPEC,
+
+ NL80211_CMD_GET_WIPHY, /* can dump */
+ NL80211_CMD_SET_WIPHY,
+ NL80211_CMD_NEW_WIPHY,
+ NL80211_CMD_DEL_WIPHY,
+
+ NL80211_CMD_GET_INTERFACE, /* can dump */
+ NL80211_CMD_SET_INTERFACE,
+ NL80211_CMD_NEW_INTERFACE,
+ NL80211_CMD_DEL_INTERFACE,
+
+ NL80211_CMD_GET_KEY,
+ NL80211_CMD_SET_KEY,
+ NL80211_CMD_NEW_KEY,
+ NL80211_CMD_DEL_KEY,
+
+ NL80211_CMD_GET_BEACON,
+ NL80211_CMD_SET_BEACON,
+ NL80211_CMD_NEW_BEACON,
+ NL80211_CMD_DEL_BEACON,
+
+ NL80211_CMD_GET_STATION,
+ NL80211_CMD_SET_STATION,
+ NL80211_CMD_NEW_STATION,
+ NL80211_CMD_DEL_STATION,
+
+ NL80211_CMD_GET_MPATH,
+ NL80211_CMD_SET_MPATH,
+ NL80211_CMD_NEW_MPATH,
+ NL80211_CMD_DEL_MPATH,
+
+ NL80211_CMD_SET_BSS,
+
+ NL80211_CMD_SET_REG,
+ NL80211_CMD_REQ_SET_REG,
+
+ NL80211_CMD_GET_MESH_PARAMS,
+ NL80211_CMD_SET_MESH_PARAMS,
+
+ NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
+
+ NL80211_CMD_GET_REG,
+
+ NL80211_CMD_GET_SCAN,
+ NL80211_CMD_TRIGGER_SCAN,
+ NL80211_CMD_NEW_SCAN_RESULTS,
+ NL80211_CMD_SCAN_ABORTED,
+
+ NL80211_CMD_REG_CHANGE,
+
+ NL80211_CMD_AUTHENTICATE,
+ NL80211_CMD_ASSOCIATE,
+ NL80211_CMD_DEAUTHENTICATE,
+ NL80211_CMD_DISASSOCIATE,
+
+ NL80211_CMD_MICHAEL_MIC_FAILURE,
+
+ NL80211_CMD_REG_BEACON_HINT,
+
+ NL80211_CMD_JOIN_IBSS,
+ NL80211_CMD_LEAVE_IBSS,
+
+ NL80211_CMD_TESTMODE,
+
+ NL80211_CMD_CONNECT,
+ NL80211_CMD_ROAM,
+ NL80211_CMD_DISCONNECT,
+
+ NL80211_CMD_SET_WIPHY_NETNS,
+
+ NL80211_CMD_GET_SURVEY,
+ NL80211_CMD_NEW_SURVEY_RESULTS,
+
+ /* add new commands above here */
+
+ /* used to define NL80211_CMD_MAX below */
+ __NL80211_CMD_AFTER_LAST,
+ NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+};
+
+/*
+ * Allow user space programs to use #ifdef on new commands by defining them
+ * here
+ */
+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
+#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
+#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
+#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE
+#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
+#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
+#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
+#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
+
+/**
+ * enum nl80211_attrs - nl80211 netlink attributes
+ *
+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
+ * /sys/class/ieee80211/<phyname>/index
+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
+ * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ * this attribute)
+ * NL80211_CHAN_HT20 = HT20 only
+ * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
+ * less than or equal to the RTS threshold; allowed range: 1..255;
+ * dot11ShortRetryLimit; u8
+ * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is
+ * greater than the RTS threshold; allowed range: 1..255;
+ * dot11ShortLongLimit; u8
+ * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum
+ * length in octets for frames; allowed range: 256..8000, disable
+ * fragmentation with (u32)-1; dot11FragmentationThreshold; u32
+ * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
+ * larger than or equal to this use RTS/CTS handshake); allowed range:
+ * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32
+ *
+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
+ * @NL80211_ATTR_IFNAME: network interface name
+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
+ *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ * IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ * rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ * to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
+ * given for %NL80211_CMD_GET_STATION, nested attribute containing
+ * info as possible, see &enum nl80211_sta_info.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ * consisting of a nested array.
+ *
+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
+ * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
+ * info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ * &enum nl80211_mpath_info.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_mntr_flags.
+ *
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ * current regulatory domain should be set to or is already set to.
+ * For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * to query the CRDA to retrieve one regulatory domain. This attribute can
+ * also be used by userspace to query the kernel for the currently set
+ * regulatory domain. We chose an alpha2 as that is also used by the
+ * IEEE-802.11d country information element to identify a country.
+ * Users can also simply ask the wireless core to set regulatory domain
+ * to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ * rules.
+ *
+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
+ * (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
+ * (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ * rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ * supported interface types, each a flag attribute with the number
+ * of the interface mode.
+ *
+ * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE.
+ *
+ * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE).
+ *
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ * a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
+ * that can be added to a scan request
+ *
+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ * scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
+ * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
+ * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
+ * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
+ * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
+ *
+ * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies
+ * an array of command numbers (i.e. a mapping index to command number)
+ * that the driver for the given wiphy supports.
+ *
+ * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
+ * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
+ * NL80211_CMD_ASSOCIATE events
+ * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets)
+ * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type,
+ * represented as a u32
+ * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
+ * %NL80211_CMD_DISASSOCIATE, u16
+ *
+ * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
+ * a u32
+ *
+ * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _before_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _after_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ *
+ * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
+ * cipher suites
+ *
+ * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
+ * for other networks on different channels
+ *
+ * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
+ * is used, e.g., with %NL80211_CMD_AUTHENTICATE event
+ *
+ * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
+ * used for the association (&enum nl80211_mfp, represented as a u32);
+ * this attribute can be used
+ * with %NL80211_CMD_ASSOCIATE request
+ *
+ * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
+ * &struct nl80211_sta_flag_update.
+ *
+ * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls
+ * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in
+ * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE
+ * request, the driver will assume that the port is unauthorized until
+ * authorized by user space. Otherwise, port is marked authorized by
+ * default in station mode.
+ *
+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
+ * We recommend using nested, driver-specific attributes within this.
+ *
+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
+ * event was due to the AP disconnecting the station, and not due to
+ * a local disconnect request.
+ * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
+ * event (u16)
+ * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
+ * that protected APs should be used.
+ *
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
+ * indicate which unicast key ciphers will be used with the connection
+ * (an array of u32).
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
+ * which group key cipher will be used with the connection (a u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
+ * which WPA version(s) the AP we want to associate with is using
+ * (a u32 with flags from &enum nl80211_wpa_versions).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
+ * which key management algorithm(s) to use (an array of u32).
+ *
+ * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
+ * sent out by the card, for ROAM and successful CONNECT events.
+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
+ * sent by peer, for ROAM and successful CONNECT events.
+ *
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+ * commands to specify using a reassociate frame
+ *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ * %NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ * and join_ibss(), key information is in a nested attribute each
+ * with %NL80211_KEY_* sub-attributes
+ *
+ * @NL80211_ATTR_PID: Process ID of a network namespace.
+ *
+ * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
+ * dumps. This number increases whenever the object list being
+ * dumped changes, and as such userspace can verify that it has
+ * obtained a complete and consistent snapshot by verifying that
+ * all dump messages contain the same generation number. If it
+ * changed then the list changed and the dump should be repeated
+ * completely from scratch.
+ *
+ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
+ *
+ * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of
+ * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
+ * containing info as possible, see &enum survey_info.
+ *
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_attrs {
+/* don't change the order or add anything inbetween, this is ABI! */
+ NL80211_ATTR_UNSPEC,
+
+ NL80211_ATTR_WIPHY,
+ NL80211_ATTR_WIPHY_NAME,
+
+ NL80211_ATTR_IFINDEX,
+ NL80211_ATTR_IFNAME,
+ NL80211_ATTR_IFTYPE,
+
+ NL80211_ATTR_MAC,
+
+ NL80211_ATTR_KEY_DATA,
+ NL80211_ATTR_KEY_IDX,
+ NL80211_ATTR_KEY_CIPHER,
+ NL80211_ATTR_KEY_SEQ,
+ NL80211_ATTR_KEY_DEFAULT,
+
+ NL80211_ATTR_BEACON_INTERVAL,
+ NL80211_ATTR_DTIM_PERIOD,
+ NL80211_ATTR_BEACON_HEAD,
+ NL80211_ATTR_BEACON_TAIL,
+
+ NL80211_ATTR_STA_AID,
+ NL80211_ATTR_STA_FLAGS,
+ NL80211_ATTR_STA_LISTEN_INTERVAL,
+ NL80211_ATTR_STA_SUPPORTED_RATES,
+ NL80211_ATTR_STA_VLAN,
+ NL80211_ATTR_STA_INFO,
+
+ NL80211_ATTR_WIPHY_BANDS,
+
+ NL80211_ATTR_MNTR_FLAGS,
+
+ NL80211_ATTR_MESH_ID,
+ NL80211_ATTR_STA_PLINK_ACTION,
+ NL80211_ATTR_MPATH_NEXT_HOP,
+ NL80211_ATTR_MPATH_INFO,
+
+ NL80211_ATTR_BSS_CTS_PROT,
+ NL80211_ATTR_BSS_SHORT_PREAMBLE,
+ NL80211_ATTR_BSS_SHORT_SLOT_TIME,
+
+ NL80211_ATTR_HT_CAPABILITY,
+
+ NL80211_ATTR_SUPPORTED_IFTYPES,
+
+ NL80211_ATTR_REG_ALPHA2,
+ NL80211_ATTR_REG_RULES,
+
+ NL80211_ATTR_MESH_PARAMS,
+
+ NL80211_ATTR_BSS_BASIC_RATES,
+
+ NL80211_ATTR_WIPHY_TXQ_PARAMS,
+ NL80211_ATTR_WIPHY_FREQ,
+ NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+
+ NL80211_ATTR_KEY_DEFAULT_MGMT,
+
+ NL80211_ATTR_MGMT_SUBTYPE,
+ NL80211_ATTR_IE,
+
+ NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+ NL80211_ATTR_SCAN_FREQUENCIES,
+ NL80211_ATTR_SCAN_SSIDS,
+ NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */
+ NL80211_ATTR_BSS,
+
+ NL80211_ATTR_REG_INITIATOR,
+ NL80211_ATTR_REG_TYPE,
+
+ NL80211_ATTR_SUPPORTED_COMMANDS,
+
+ NL80211_ATTR_FRAME,
+ NL80211_ATTR_SSID,
+ NL80211_ATTR_AUTH_TYPE,
+ NL80211_ATTR_REASON_CODE,
+
+ NL80211_ATTR_KEY_TYPE,
+
+ NL80211_ATTR_MAX_SCAN_IE_LEN,
+ NL80211_ATTR_CIPHER_SUITES,
+
+ NL80211_ATTR_FREQ_BEFORE,
+ NL80211_ATTR_FREQ_AFTER,
+
+ NL80211_ATTR_FREQ_FIXED,
+
+
+ NL80211_ATTR_WIPHY_RETRY_SHORT,
+ NL80211_ATTR_WIPHY_RETRY_LONG,
+ NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+
+ NL80211_ATTR_TIMED_OUT,
+
+ NL80211_ATTR_USE_MFP,
+
+ NL80211_ATTR_STA_FLAGS2,
+
+ NL80211_ATTR_CONTROL_PORT,
+
+ NL80211_ATTR_TESTDATA,
+
+ NL80211_ATTR_PRIVACY,
+
+ NL80211_ATTR_DISCONNECTED_BY_AP,
+ NL80211_ATTR_STATUS_CODE,
+
+ NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ NL80211_ATTR_CIPHER_SUITE_GROUP,
+ NL80211_ATTR_WPA_VERSIONS,
+ NL80211_ATTR_AKM_SUITES,
+
+ NL80211_ATTR_REQ_IE,
+ NL80211_ATTR_RESP_IE,
+
+ NL80211_ATTR_PREV_BSSID,
+
+ NL80211_ATTR_KEY,
+ NL80211_ATTR_KEYS,
+
+ NL80211_ATTR_PID,
+
+ NL80211_ATTR_4ADDR,
+
+ NL80211_ATTR_SURVEY_INFO,
+
+ /* add attributes here, update the policy in nl80211.c */
+
+ __NL80211_ATTR_AFTER_LAST,
+ NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+};
+
+/* source-level API compatibility */
+#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+
+/*
+ * Allow user space programs to use #ifdef on new attributes by defining them
+ * here
+ */
+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
+#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
+#define NL80211_ATTR_IE NL80211_ATTR_IE
+#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
+#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
+#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
+#define NL80211_ATTR_SSID NL80211_ATTR_SSID
+#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
+#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
+#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
+#define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+
+#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_REG_RULES 32
+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
+#define NL80211_HT_CAPABILITY_LEN 26
+
+#define NL80211_MAX_NR_CIPHER_SUITES 5
+#define NL80211_MAX_NR_AKM_SUITES 2
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ *
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @NL80211_IFTYPE_ADHOC: independent BSS member
+ * @NL80211_IFTYPE_STATION: managed BSS member
+ * @NL80211_IFTYPE_AP: access point
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined
+ * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+ NL80211_IFTYPE_UNSPECIFIED,
+ NL80211_IFTYPE_ADHOC,
+ NL80211_IFTYPE_STATION,
+ NL80211_IFTYPE_AP,
+ NL80211_IFTYPE_AP_VLAN,
+ NL80211_IFTYPE_WDS,
+ NL80211_IFTYPE_MONITOR,
+ NL80211_IFTYPE_MESH_POINT,
+
+ /* keep last */
+ __NL80211_IFTYPE_AFTER_LAST,
+ NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ * with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ */
+enum nl80211_sta_flags {
+ __NL80211_STA_FLAG_INVALID,
+ NL80211_STA_FLAG_AUTHORIZED,
+ NL80211_STA_FLAG_SHORT_PREAMBLE,
+ NL80211_STA_FLAG_WME,
+ NL80211_STA_FLAG_MFP,
+
+ /* keep last */
+ __NL80211_STA_FLAG_AFTER_LAST,
+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * struct nl80211_sta_flag_update - station flags mask/set
+ * @mask: mask of station flags to set
+ * @set: which values to set them to
+ *
+ * Both mask and set contain bits as per &enum nl80211_sta_flags.
+ */
+struct nl80211_sta_flag_update {
+ __u32 mask;
+ __u32 set;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+ __NL80211_RATE_INFO_INVALID,
+ NL80211_RATE_INFO_BITRATE,
+ NL80211_RATE_INFO_MCS,
+ NL80211_RATE_INFO_40_MHZ_WIDTH,
+ NL80211_RATE_INFO_SHORT_GI,
+
+ /* keep last */
+ __NL80211_RATE_INFO_AFTER_LAST,
+ NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_info - station information
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
+ * containing info as possible, see &enum nl80211_sta_info_txrate.
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
+ * station)
+ */
+enum nl80211_sta_info {
+ __NL80211_STA_INFO_INVALID,
+ NL80211_STA_INFO_INACTIVE_TIME,
+ NL80211_STA_INFO_RX_BYTES,
+ NL80211_STA_INFO_TX_BYTES,
+ NL80211_STA_INFO_LLID,
+ NL80211_STA_INFO_PLID,
+ NL80211_STA_INFO_PLINK_STATE,
+ NL80211_STA_INFO_SIGNAL,
+ NL80211_STA_INFO_TX_BITRATE,
+ NL80211_STA_INFO_RX_PACKETS,
+ NL80211_STA_INFO_TX_PACKETS,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+ NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+ NL80211_MPATH_FLAG_ACTIVE = 1<<0,
+ NL80211_MPATH_FLAG_RESOLVING = 1<<1,
+ NL80211_MPATH_FLAG_SN_VALID = 1<<2,
+ NL80211_MPATH_FLAG_FIXED = 1<<3,
+ NL80211_MPATH_FLAG_RESOLVED = 1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_ATTR_MPATH_SN: destination sequence number
+ * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
+ * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * &enum nl80211_mpath_flags;
+ * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ */
+enum nl80211_mpath_info {
+ __NL80211_MPATH_INFO_INVALID,
+ NL80211_MPATH_INFO_FRAME_QLEN,
+ NL80211_MPATH_INFO_SN,
+ NL80211_MPATH_INFO_METRIC,
+ NL80211_MPATH_INFO_EXPTIME,
+ NL80211_MPATH_INFO_FLAGS,
+ NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+
+ /* keep last */
+ __NL80211_MPATH_INFO_AFTER_LAST,
+ NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ * an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ * an array of nested bitrate attributes
+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
+ * defined in 802.11n
+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ */
+enum nl80211_band_attr {
+ __NL80211_BAND_ATTR_INVALID,
+ NL80211_BAND_ATTR_FREQS,
+ NL80211_BAND_ATTR_RATES,
+
+ NL80211_BAND_ATTR_HT_MCS_SET,
+ NL80211_BAND_ATTR_HT_CAPA,
+ NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+ NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+
+ /* keep last */
+ __NL80211_BAND_ATTR_AFTER_LAST,
+ NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ * regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ * permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ * (100 * dBm).
+ */
+enum nl80211_frequency_attr {
+ __NL80211_FREQUENCY_ATTR_INVALID,
+ NL80211_FREQUENCY_ATTR_FREQ,
+ NL80211_FREQUENCY_ATTR_DISABLED,
+ NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+ NL80211_FREQUENCY_ATTR_NO_IBSS,
+ NL80211_FREQUENCY_ATTR_RADAR,
+ NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+
+ /* keep last */
+ __NL80211_FREQUENCY_ATTR_AFTER_LAST,
+ NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ * in 2.4 GHz band.
+ */
+enum nl80211_bitrate_attr {
+ __NL80211_BITRATE_ATTR_INVALID,
+ NL80211_BITRATE_ATTR_RATE,
+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+ /* keep last */
+ __NL80211_BITRATE_ATTR_AFTER_LAST,
+ NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_initiator - Indicates the initiator of a reg domain request
+ * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
+ * regulatory domain.
+ * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
+ * regulatory domain.
+ * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
+ * wireless core it thinks its knows the regulatory domain we should be in.
+ * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
+ * 802.11 country information element with regulatory information it
+ * thinks we should consider.
+ */
+enum nl80211_reg_initiator {
+ NL80211_REGDOM_SET_BY_CORE,
+ NL80211_REGDOM_SET_BY_USER,
+ NL80211_REGDOM_SET_BY_DRIVER,
+ NL80211_REGDOM_SET_BY_COUNTRY_IE,
+};
+
+/**
+ * enum nl80211_reg_type - specifies the type of regulatory domain
+ * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains
+ * to a specific country. When this is set you can count on the
+ * ISO / IEC 3166 alpha2 country code being valid.
+ * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
+ * domain.
+ * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
+ * driver specific world regulatory domain. These do not apply system-wide
+ * and are only applicable to the individual devices which have requested
+ * them to be applied.
+ * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
+ * of an intersection between two regulatory domains -- the previously
+ * set regulatory domain on the system and the last accepted regulatory
+ * domain request to be processed.
+ */
+enum nl80211_reg_type {
+ NL80211_REGDOM_TYPE_COUNTRY,
+ NL80211_REGDOM_TYPE_WORLD,
+ NL80211_REGDOM_TYPE_CUSTOM_WORLD,
+ NL80211_REGDOM_TYPE_INTERSECTION,
+};
+
+/**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ * considerations for a given frequency range. These are the
+ * &enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ * rule in KHz. This is not a center of frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ * in KHz. This is not a center a frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ * frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ * for a given frequency range. The value is in mBi (100 * dBi).
+ * If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ * a given frequency range. The value is in mBm (100 * dBm).
+ */
+enum nl80211_reg_rule_attr {
+ __NL80211_REG_RULE_ATTR_INVALID,
+ NL80211_ATTR_REG_RULE_FLAGS,
+
+ NL80211_ATTR_FREQ_RANGE_START,
+ NL80211_ATTR_FREQ_RANGE_END,
+ NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+ NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+ NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+ /* keep last */
+ __NL80211_REG_RULE_ATTR_AFTER_LAST,
+ NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+ NL80211_RRF_NO_OFDM = 1<<0,
+ NL80211_RRF_NO_CCK = 1<<1,
+ NL80211_RRF_NO_INDOOR = 1<<2,
+ NL80211_RRF_NO_OUTDOOR = 1<<3,
+ NL80211_RRF_DFS = 1<<4,
+ NL80211_RRF_PTP_ONLY = 1<<5,
+ NL80211_RRF_PTMP_ONLY = 1<<6,
+ NL80211_RRF_PASSIVE_SCAN = 1<<7,
+ NL80211_RRF_NO_IBSS = 1<<8,
+};
+
+/**
+ * enum nl80211_survey_info - survey information
+ *
+ * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
+ * when getting information about a survey.
+ *
+ * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
+ * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ */
+enum nl80211_survey_info {
+ __NL80211_SURVEY_INFO_INVALID,
+ NL80211_SURVEY_INFO_FREQUENCY,
+ NL80211_SURVEY_INFO_NOISE,
+
+ /* keep last */
+ __NL80211_SURVEY_INFO_AFTER_LAST,
+ NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ * overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+ __NL80211_MNTR_FLAG_INVALID,
+ NL80211_MNTR_FLAG_FCSFAIL,
+ NL80211_MNTR_FLAG_PLCPFAIL,
+ NL80211_MNTR_FLAG_CONTROL,
+ NL80211_MNTR_FLAG_OTHER_BSS,
+ NL80211_MNTR_FLAG_COOK_FRAMES,
+
+ /* keep last */
+ __NL80211_MNTR_FLAG_AFTER_LAST,
+ NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_meshconf_params - mesh configuration parameters
+ *
+ * Mesh configuration parameters
+ *
+ * @__NL80211_MESHCONF_INVALID: internal use
+ *
+ * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
+ * millisecond units, used by the Peer Link Open message
+ *
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
+ * millisecond units, used by the peer link management to close a peer link
+ *
+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
+ * millisecond units
+ *
+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
+ * on this mesh interface
+ *
+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
+ * open retries that can be sent to establish a new peer link instance in a
+ * mesh
+ *
+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
+ * point.
+ *
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
+ * open peer links when we detect compatible mesh peers.
+ *
+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
+ * containing a PREQ that an MP can send to a particular destination (path
+ * target)
+ *
+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
+ * (in milliseconds)
+ *
+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
+ * until giving up on a path discovery (in milliseconds)
+ *
+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
+ * points receiving a PREQ shall consider the forwarding information from the
+ * root to be valid. (TU = time unit)
+ *
+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
+ * TUs) during which an MP can send only one action frame containing a PREQ
+ * reference element
+ *
+ * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
+ * that it takes for an HWMP information element to propagate across the mesh
+ *
+ * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_meshconf_params {
+ __NL80211_MESHCONF_INVALID,
+ NL80211_MESHCONF_RETRY_TIMEOUT,
+ NL80211_MESHCONF_CONFIRM_TIMEOUT,
+ NL80211_MESHCONF_HOLDING_TIMEOUT,
+ NL80211_MESHCONF_MAX_PEER_LINKS,
+ NL80211_MESHCONF_MAX_RETRIES,
+ NL80211_MESHCONF_TTL,
+ NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+ NL80211_MESHCONF_PATH_REFRESH_TIME,
+ NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+ NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+ NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+ NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+ NL80211_MESHCONF_HWMP_ROOTMODE,
+
+ /* keep last */
+ __NL80211_MESHCONF_ATTR_AFTER_LAST,
+ NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_txq_attr - TX queue parameter attributes
+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
+ * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ * disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+ __NL80211_TXQ_ATTR_INVALID,
+ NL80211_TXQ_ATTR_QUEUE,
+ NL80211_TXQ_ATTR_TXOP,
+ NL80211_TXQ_ATTR_CWMIN,
+ NL80211_TXQ_ATTR_CWMAX,
+ NL80211_TXQ_ATTR_AIFS,
+
+ /* keep last */
+ __NL80211_TXQ_ATTR_AFTER_LAST,
+ NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_txq_q {
+ NL80211_TXQ_Q_VO,
+ NL80211_TXQ_Q_VI,
+ NL80211_TXQ_Q_BE,
+ NL80211_TXQ_Q_BK
+};
+
+enum nl80211_channel_type {
+ NL80211_CHAN_NO_HT,
+ NL80211_CHAN_HT20,
+ NL80211_CHAN_HT40MINUS,
+ NL80211_CHAN_HT40PLUS
+};
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ * raw information elements from the probe response/beacon (bin)
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ * in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ * in unspecified units, scaled to 0..100 (u8)
+ * @NL80211_BSS_STATUS: status, if this BSS is "used"
+ * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+ __NL80211_BSS_INVALID,
+ NL80211_BSS_BSSID,
+ NL80211_BSS_FREQUENCY,
+ NL80211_BSS_TSF,
+ NL80211_BSS_BEACON_INTERVAL,
+ NL80211_BSS_CAPABILITY,
+ NL80211_BSS_INFORMATION_ELEMENTS,
+ NL80211_BSS_SIGNAL_MBM,
+ NL80211_BSS_SIGNAL_UNSPEC,
+ NL80211_BSS_STATUS,
+ NL80211_BSS_SEEN_MS_AGO,
+
+ /* keep last */
+ __NL80211_BSS_AFTER_LAST,
+ NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bss_status - BSS "status"
+ */
+enum nl80211_bss_status {
+ NL80211_BSS_STATUS_AUTHENTICATED,
+ NL80211_BSS_STATUS_ASSOCIATED,
+ NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
+/**
+ * enum nl80211_auth_type - AuthenticationType
+ *
+ * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
+ * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
+ * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
+ * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @__NL80211_AUTHTYPE_NUM: internal
+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
+ * trying multiple times); this is invalid in netlink -- leave out
+ * the attribute for this on CONNECT commands.
+ */
+enum nl80211_auth_type {
+ NL80211_AUTHTYPE_OPEN_SYSTEM,
+ NL80211_AUTHTYPE_SHARED_KEY,
+ NL80211_AUTHTYPE_FT,
+ NL80211_AUTHTYPE_NETWORK_EAP,
+
+ /* keep last */
+ __NL80211_AUTHTYPE_NUM,
+ NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
+ NL80211_AUTHTYPE_AUTOMATIC
+};
+
+/**
+ * enum nl80211_key_type - Key Type
+ * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
+ * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
+ * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ */
+enum nl80211_key_type {
+ NL80211_KEYTYPE_GROUP,
+ NL80211_KEYTYPE_PAIRWISE,
+ NL80211_KEYTYPE_PEERKEY,
+};
+
+/**
+ * enum nl80211_mfp - Management frame protection state
+ * @NL80211_MFP_NO: Management frame protection not used
+ * @NL80211_MFP_REQUIRED: Management frame protection required
+ */
+enum nl80211_mfp {
+ NL80211_MFP_NO,
+ NL80211_MFP_REQUIRED,
+};
+
+enum nl80211_wpa_versions {
+ NL80211_WPA_VERSION_1 = 1 << 0,
+ NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+ __NL80211_KEY_INVALID,
+ NL80211_KEY_DATA,
+ NL80211_KEY_IDX,
+ NL80211_KEY_CIPHER,
+ NL80211_KEY_SEQ,
+ NL80211_KEY_DEFAULT,
+ NL80211_KEY_DEFAULT_MGMT,
+
+ /* keep last */
+ __NL80211_KEY_AFTER_LAST,
+ NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
+#endif /* __LINUX_NL80211_H */
diff --git a/nvs.c b/nvs.c
new file mode 100644
index 0000000..2e9e146
--- /dev/null
+++ b/nvs.c
@@ -0,0 +1,1283 @@
+/*
+ * PLT utility for wireless chip supported by TI's driver wl12xx
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <time.h>
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include "nl80211.h"
+
+#include "calibrator.h"
+#include "plt.h"
+#include "ini.h"
+/* 2048 - it should be enough for any chip, until... 22dec2010 */
+#define BUF_SIZE_4_NVS_FILE 2048
+
+static const char if_name_fmt[] = "wlan%d";
+
+static char* get_opt_file(int argc, char **argv, char *dir, char *def)
+{
+ char *name = NULL;
+ if (argc < 0)
+ return NULL;
+ else if (argc == 0) {
+ name = def;
+ fprintf(stderr, "\nThe path to input %s file not provided, "
+ "use default (%s)\n", dir, name);
+ }
+ else
+ name = *argv;
+ return name;
+}
+
+
+char *get_opt_nvsinfile(int argc, char **argv)
+{
+ char *name = get_opt_file(argc, argv, "input", CURRENT_NVS_NAME);
+ if (file_exist(name) < 0) {
+ fprintf(stderr, "File not found %s\n", name);
+ return NULL;
+ }
+ return name;
+}
+
+char *get_opt_nvsoutfile(int argc, char **argv)
+{
+ char *name = get_opt_file(argc, argv, "output", NEW_NVS_NAME);
+ return name;
+}
+
+int nvs_set_mac(char *nvsfile, char *mac)
+{
+ unsigned char mac_buff[12];
+ unsigned int in_mac[6];
+ int fd;
+ unsigned int lower;
+
+ if (mac) {
+ int ret =
+ sscanf(mac, "%2x:%2x:%2x:%2x:%2x:%2x",
+ &in_mac[0], &in_mac[1], &in_mac[2],
+ &in_mac[3], &in_mac[4], &in_mac[5]);
+ if (ret != 6) {
+ fprintf(stderr, "MAC address is not valid: %s\n", mac);
+ return -1;
+ }
+ }
+ else {
+ fprintf(stderr, "No MAC address specified\n");
+ return -1;
+ }
+
+ fd = open(nvsfile, O_RDWR);
+ if (fd < 0) {
+ perror("Error opening file for reading");
+ return 1;
+ }
+
+ read(fd, mac_buff, 12);
+ mac_buff[11] = (unsigned char)in_mac[0];
+ mac_buff[10] = (unsigned char)in_mac[1];
+ mac_buff[6] = (unsigned char)in_mac[2];
+ mac_buff[5] = (unsigned char)in_mac[3];
+ mac_buff[4] = (unsigned char)in_mac[4];
+ mac_buff[3] = (unsigned char)in_mac[5];
+
+ lseek(fd, 0L, 0);
+
+ /* we need at least two valid NIC addresses */
+ lower = (in_mac[3] << 16) + (in_mac[4] << 8) + in_mac[5];
+ if (lower + 1 > 0xffffff)
+ fprintf(stderr,
+ "WARNING: NIC part of the MAC address wraps around!\n");
+
+ printf("Writing mac address %s to file %s\n", mac, nvsfile);
+ write(fd, mac_buff, 12);
+
+ close(fd);
+ return 0;
+}
+
+int nvs_fill_radio_params(int fd, struct wl12xx_ini *ini, char *buf)
+{
+ struct wl1271_nvs_ini gp;
+ int fem_idx;
+
+ if (ini) {
+ /* Reset local NVS Radio Params */
+ memset(&gp, 0, sizeof(gp));
+
+ /* Copy from INI to NVS */
+ gp.general_params = ini->ini1271.general_params;
+ gp.stat_radio_params_2 = ini->ini1271.stat_radio_params_2;
+
+ if (gp.general_params.dual_mode_select)
+ gp.stat_radio_params_5 = ini->ini1271.stat_radio_params_5;
+
+ if (gp.general_params.tx_bip_fem_auto_detect) {
+ /* For backward compatibility we fill the first 2 FEM entries */
+ gp.dyn_radio_params_2[0].params =
+ ini->ini1271.dyn_radio_params_2[0].params;
+ gp.dyn_radio_params_2[1].params =
+ ini->ini1271.dyn_radio_params_2[1].params;
+
+ if (gp.general_params.dual_mode_select) {
+ gp.dyn_radio_params_5[0].params =
+ ini->ini1271.dyn_radio_params_5[0].params;
+ gp.dyn_radio_params_5[1].params =
+ ini->ini1271.dyn_radio_params_5[1].params;
+ }
+ }
+ else {
+ /*
+ * Translate to NVS FEM entry
+ * In case of fem manufacturer 1 (TQS) use FEM idx 1 to maintain
+ * backward compatibilty. For all other types use idx 0
+ */
+ fem_idx = WL12XX_FEM_TO_NVS_ENTRY(
+ gp.general_params.tx_bip_fem_manufacturer);
+
+ gp.dyn_radio_params_2[fem_idx].params =
+ ini->ini1271.dyn_radio_params_2
+ [gp.general_params.tx_bip_fem_manufacturer].params;
+
+ if (gp.general_params.dual_mode_select)
+ gp.dyn_radio_params_5[fem_idx].params =
+ ini->ini1271.dyn_radio_params_5
+ [gp.general_params.tx_bip_fem_manufacturer].params;
+ }
+
+ write(fd, (const void *)&gp, sizeof(gp));
+ } else {
+ char *p = buf + 0x1D4;
+ write(fd, (const void *)p, sizeof(gp));
+ }
+
+ return 0;
+}
+
+static int nvs_fill_radio_params_128x(int fd, struct wl12xx_ini *ini, char *buf)
+{
+ struct wl128x_nvs_ini gp;
+ int fem_idx;
+
+ if (ini) {
+ /* Reset local NVS Radio Params */
+ memset(&gp, 0, sizeof(gp));
+
+ /* Copy from INI to NVS */
+ gp.general_params = ini->ini128x.general_params;
+ gp.fem_vendor_and_options = ini->ini128x.fem_vendor_and_options;
+ gp.stat_radio_params_2 = ini->ini128x.stat_radio_params_2;
+
+ if (gp.general_params.dual_mode_select)
+ gp.stat_radio_params_5 = ini->ini128x.stat_radio_params_5;
+
+ if (gp.general_params.tx_bip_fem_auto_detect) {
+ /* For backward compatibility we fill the first 2 FEM entries */
+ gp.dyn_radio_params_2[0].params =
+ ini->ini128x.dyn_radio_params_2[0].params;
+ gp.dyn_radio_params_2[1].params =
+ ini->ini128x.dyn_radio_params_2[1].params;
+
+ if (gp.general_params.dual_mode_select) {
+ gp.dyn_radio_params_5[0].params =
+ ini->ini128x.dyn_radio_params_5[0].params;
+ gp.dyn_radio_params_5[1].params =
+ ini->ini128x.dyn_radio_params_5[1].params;
+ }
+ }
+ else {
+ /*
+ * Translate to NVS FEM entry
+ * In case of fem manufacturer 1 (TQS) use FEM idx 1 to maintain
+ * backward compatibilty. For all other types use idx 0
+ */
+ fem_idx = WL12XX_FEM_TO_NVS_ENTRY(
+ gp.general_params.tx_bip_fem_manufacturer);
+
+ gp.dyn_radio_params_2[fem_idx].params =
+ ini->ini128x.dyn_radio_params_2
+ [gp.general_params.tx_bip_fem_manufacturer].params;
+
+ if (gp.general_params.dual_mode_select)
+ gp.dyn_radio_params_5[fem_idx].params =
+ ini->ini128x.dyn_radio_params_5
+ [gp.general_params.tx_bip_fem_manufacturer].params;
+ }
+
+ write(fd, (const void *)&gp, sizeof(gp));
+ } else {
+ char *p = buf + 0x1D4;
+ write(fd, (const void *)p, sizeof(gp));
+ }
+
+ return 0;
+}
+
+int nvs_set_autofem(int fd, char *buf, unsigned char val)
+{
+ size_t size, i;
+ struct wl1271_ini *gp;
+ unsigned char *c;
+
+ if (buf == NULL)
+ return 1;
+
+ gp = (struct wl1271_ini *)(buf+0x1d4);
+ gp->general_params.tx_bip_fem_auto_detect = val;
+
+ size = sizeof(struct wl1271_ini);
+
+ c = (unsigned char *)gp;
+
+ for (i = 0; i < size; i++)
+ write(fd, c++, 1);
+
+ return 0;
+}
+
+int nvs_set_autofem_128x(int fd, char *buf, unsigned char val)
+{
+ size_t size, i;
+ struct wl128x_ini *gp;
+ unsigned char *c;
+
+ if (buf == NULL)
+ return 1;
+
+ gp = (struct wl128x_ini *)(buf+0x1d4);
+ gp->general_params.tx_bip_fem_auto_detect = val;
+
+ size = sizeof(struct wl128x_ini);
+
+ c = (unsigned char *)gp;
+
+ for (i = 0; i < size; i++)
+ write(fd, c++, 1);
+
+ return 0;
+}
+
+int nvs_set_fem_manuf(int fd, char *buf, unsigned char val)
+{
+ size_t size, i;
+ struct wl1271_ini *gp;
+ unsigned char *c;
+
+ if (buf == NULL)
+ return 1;
+
+ gp = (struct wl1271_ini *)(buf+0x1d4);
+ gp->general_params.tx_bip_fem_manufacturer = val;
+
+ size = sizeof(struct wl1271_ini);
+
+ c = (unsigned char *)gp;
+
+ for (i = 0; i < size; i++)
+ write(fd, c++, 1);
+
+ return 0;
+}
+
+int nvs_set_fem_manuf_128x(int fd, char *buf, unsigned char val)
+{
+ size_t size, i;
+ struct wl128x_ini *gp;
+ unsigned char *c;
+
+ if (buf == NULL)
+ return 1;
+
+ gp = (struct wl128x_ini *)(buf+0x1d4);
+ gp->general_params.tx_bip_fem_manufacturer = val;
+
+ size = sizeof(struct wl128x_ini);
+
+ c = (unsigned char *)gp;
+
+ for (i = 0; i < size; i++)
+ write(fd, c++, 1);
+
+ return 0;
+}
+
+static struct wl12xx_nvs_ops wl1271_nvs_ops = {
+ .nvs_fill_radio_prms = nvs_fill_radio_params,
+ .nvs_set_autofem = nvs_set_autofem,
+ .nvs_set_fem_manuf = nvs_set_fem_manuf,
+};
+
+static struct wl12xx_nvs_ops wl128x_nvs_ops = {
+ .nvs_fill_radio_prms = nvs_fill_radio_params_128x,
+ .nvs_set_autofem = nvs_set_autofem_128x,
+ .nvs_set_fem_manuf = nvs_set_fem_manuf_128x,
+};
+
+int get_mac_addr(int ifc_num, unsigned char *mac_addr)
+{
+ int s;
+ struct ifreq ifr;
+#if 0
+ if (ifc_num < 0 || ifc_num >= ETH_DEV_MAX)
+ return 1;
+#endif
+ s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (s < 0) {
+ fprintf(stderr, "unable to socket (%s)\n", strerror(errno));
+ return 1;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ sprintf(ifr.ifr_name, if_name_fmt, ifc_num) ;
+ if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
+ fprintf(stderr, "unable to ioctl (%s)\n", strerror(errno));
+ close(s);
+ return 1;
+ }
+
+ close(s);
+
+ memcpy(mac_addr, &ifr.ifr_ifru.ifru_hwaddr.sa_data[0], 6);
+
+ return 0;
+}
+
+int file_exist(const char *filename)
+{
+ struct stat buf;
+ int ret;
+
+ if (filename == NULL) {
+ fprintf(stderr, "wrong parameter\n");
+ return -1;
+ }
+
+ ret = stat(filename, &buf);
+ if (ret != 0) {
+ return -1;
+ }
+
+ return (int)buf.st_size;
+}
+
+void cfg_nvs_ops(struct wl12xx_common *cmn)
+{
+ if (cmn->arch == WL1271_ARCH)
+ cmn->nvs_ops = &wl1271_nvs_ops;
+ else
+ cmn->nvs_ops = &wl128x_nvs_ops;
+}
+
+static int read_from_current_nvs(const char *nvs_file,
+ char *buf, int size, int *nvs_sz)
+{
+ int curr_nvs, ret;
+
+ curr_nvs = open(nvs_file, O_RDONLY, S_IRUSR | S_IWUSR);
+ if (curr_nvs < 0) {
+ fprintf(stderr, "%s> Unable to open NVS file for reference "
+ "(%s)\n", __func__, strerror(errno));
+ return 1;
+ }
+
+ ret = read(curr_nvs, buf, size);
+ if (ret < 0) {
+ fprintf(stderr, "Fail to read file %s (%s)\n", nvs_file,
+ strerror(errno));
+ close(curr_nvs);
+ return 1;
+ }
+
+ if (nvs_sz)
+ *nvs_sz = ret;
+
+ close(curr_nvs);
+
+ //printf("Read NVS file (%s) of size %d\n", nvs_file, ret);
+
+ return 0;
+}
+
+static int read_nvs(const char *nvs_file, char *buf,
+ int size, int *nvs_sz)
+{
+ int fl_sz;
+ fl_sz = file_exist(nvs_file);
+ if (fl_sz < 0) {
+ fprintf(stderr, "File %s not exists\n", nvs_file);
+ return 1;
+ }
+
+ return read_from_current_nvs(nvs_file, buf, size, nvs_sz);
+}
+
+static int fill_nvs_def_rx_params(int fd)
+{
+ unsigned char type = eNVS_RADIO_RX_PARAMETERS;
+ unsigned short length = NVS_RX_PARAM_LENGTH;
+ int i;
+
+ /* Rx type */
+ write(fd, &type, 1);
+
+ /* Rx length */
+ write(fd, &length, 2);
+
+ type = DEFAULT_EFUSE_VALUE; /* just reuse of var */
+ for (i = 0; i < NVS_RX_PARAM_LENGTH; i++)
+ write(fd, &type, 1);
+
+ return 0;
+}
+
+static void nvs_parse_data(const unsigned char *buf,
+ struct wl1271_cmd_cal_p2g *pdata, unsigned int *pver)
+{
+#define BUFFER_INDEX (buf_idx + START_PARAM_INDEX + info_idx)
+ unsigned short buf_idx;
+ unsigned char tlv_type;
+ unsigned short tlv_len;
+ unsigned short info_idx;
+ unsigned int nvsTypeInfo = 0;
+ unsigned char nvs_ver_oct_idx;
+ unsigned char shift;
+
+ for (buf_idx = 0; buf_idx < NVS_TOTAL_LENGTH;) {
+ tlv_type = buf[buf_idx];
+
+ /* fill the correct mode to fill the NVS struct buffer */
+ /* if the tlv_type is the last type break from the loop */
+ switch (tlv_type) {
+ case eNVS_RADIO_TX_PARAMETERS:
+ nvsTypeInfo = eNVS_RADIO_TX_TYPE_PARAMETERS_INFO;
+ break;
+ case eNVS_RADIO_RX_PARAMETERS:
+ nvsTypeInfo = eNVS_RADIO_RX_TYPE_PARAMETERS_INFO;
+ break;
+ case eNVS_VERSION:
+ for (*pver = 0, nvs_ver_oct_idx = 0;
+ nvs_ver_oct_idx < NVS_VERSION_PARAMETER_LENGTH;
+ nvs_ver_oct_idx++) {
+ shift = 8 * (NVS_VERSION_PARAMETER_LENGTH -
+ 1 - nvs_ver_oct_idx);
+ *pver += ((buf[buf_idx + START_PARAM_INDEX +
+ nvs_ver_oct_idx]) << shift);
+ }
+ break;
+ case eTLV_LAST:
+ default:
+ return;
+ }
+
+ tlv_len = (buf[buf_idx + START_LENGTH_INDEX + 1] << 8) +
+ buf[buf_idx + START_LENGTH_INDEX];
+
+ /* if TLV type is not NVS ver fill the NVS according */
+ /* to the mode TX/RX */
+ if ((eNVS_RADIO_TX_PARAMETERS == tlv_type) ||
+ (eNVS_RADIO_RX_PARAMETERS == tlv_type)) {
+ pdata[nvsTypeInfo].type = tlv_type;
+ pdata[nvsTypeInfo].len = tlv_len;
+
+ for (info_idx = 0; (info_idx < tlv_len) &&
+ (BUFFER_INDEX < NVS_TOTAL_LENGTH);
+ info_idx++) {
+ pdata[nvsTypeInfo].buf[info_idx] =
+ buf[BUFFER_INDEX];
+ }
+ }
+
+ /* increment to the next TLV */
+ buf_idx += START_PARAM_INDEX + tlv_len;
+ }
+}
+
+static int nvs_fill_version(int fd, unsigned int *pdata)
+{
+ unsigned char tmp = eNVS_VERSION;
+ unsigned short tmp2 = NVS_VERSION_PARAMETER_LENGTH;
+
+ write(fd, &tmp, 1);
+
+ write(fd, &tmp2, 2);
+
+ tmp = (*pdata >> 16) & 0xff;
+ write(fd, &tmp, 1);
+
+ tmp = (*pdata >> 8) & 0xff;
+ write(fd, &tmp, 1);
+
+ tmp = *pdata & 0xff;
+ write(fd, &tmp, 1);
+
+ return 0;
+}
+
+static int nvs_fill_old_rx_data(int fd, const unsigned char *buf,
+ unsigned short len)
+{
+ unsigned short idx;
+ unsigned char rx_type;
+
+ /* RX BiP type */
+ rx_type = eNVS_RADIO_RX_PARAMETERS;
+ write(fd, &rx_type, 1);
+
+ /* RX BIP Length */
+ write(fd, &len, 2);
+
+ for (idx = 0; idx < len; idx++)
+ write(fd, &(buf[idx]), 1);
+
+ return 0;
+}
+
+static int nvs_upd_nvs_part(int fd, char *buf)
+{
+ char *p = buf;
+
+ write(fd, p, 0x1D4);
+
+ return 0;
+}
+
+static int nvs_fill_nvs_part(int fd)
+{
+ int i;
+ unsigned char mac_addr[MAC_ADDR_LEN] = {
+ 0x0b, 0xad, 0xde, 0xad, 0xbe, 0xef
+ };
+ __le16 nvs_tx_sz = NVS_TX_PARAM_LENGTH;
+ __le32 nvs_ver = 0x0;
+ const unsigned char vals[] = {
+ 0x0, 0x1, 0x6d, 0x54, 0x71, eTLV_LAST, eNVS_RADIO_TX_PARAMETERS
+ };
+
+ write(fd, &vals[1], 1);
+ write(fd, &vals[2], 1);
+ write(fd, &vals[3], 1);
+#if 0
+ if (get_mac_addr(0, mac_addr)) {
+ fprintf(stderr, "%s> Fail to get mac address\n", __func__);
+ return 1;
+ }
+#endif
+ /* write down MAC address in new NVS file */
+ write(fd, &mac_addr[5], 1);
+ write(fd, &mac_addr[4], 1);
+ write(fd, &mac_addr[3], 1);
+ write(fd, &mac_addr[2], 1);
+
+ write(fd, &vals[1], 1);
+ write(fd, &vals[4], 1);
+ write(fd, &vals[3], 1);
+
+ write(fd, &mac_addr[1], 1);
+ write(fd, &mac_addr[0], 1);
+
+ write(fd, &vals[0], 1);
+ write(fd, &vals[0], 1);
+
+ /* fill end burst transaction zeros */
+ for (i = 0; i < NVS_END_BURST_TRANSACTION_LENGTH; i++)
+ write(fd, &vals[0], 1);
+
+ /* fill zeros to Align TLV start address */
+ for (i = 0; i < NVS_ALING_TLV_START_ADDRESS_LENGTH; i++)
+ write(fd, &vals[0], 1);
+
+ /* Fill Tx calibration part */
+ write(fd, &vals[6], 1);
+ write(fd, &nvs_tx_sz, 2);
+
+ for (i = 0; i < nvs_tx_sz; i++)
+ write(fd, &vals[0], 1);
+
+ /* Fill Rx calibration part */
+ fill_nvs_def_rx_params(fd);
+
+ /* fill NVS version */
+ if (nvs_fill_version(fd, &nvs_ver))
+ fprintf(stderr, "Fail to fill version\n");
+
+ /* fill end of NVS */
+ write(fd, &vals[5], 1); /* eTLV_LAST */
+ write(fd, &vals[5], 1); /* eTLV_LAST */
+ write(fd, &vals[0], 1);
+ write(fd, &vals[0], 1);
+
+ return 0;
+}
+
+int prepare_nvs_file(void *arg, char *file_name)
+{
+ int new_nvs, i, nvs_size;
+ unsigned char mac_addr[MAC_ADDR_LEN];
+ struct wl1271_cmd_cal_p2g *pdata;
+ struct wl1271_cmd_cal_p2g old_data[eNUMBER_RADIO_TYPE_PARAMETERS_INFO];
+ char buf[2048];
+ unsigned char *p;
+ struct wl12xx_common cmn = {
+ .arch = UNKNOWN_ARCH,
+ .parse_ops = NULL
+ };
+
+ const unsigned char vals[] = {
+ 0x0, 0x1, 0x6d, 0x54, 0x71, eTLV_LAST, eNVS_RADIO_TX_PARAMETERS
+ };
+
+ if (arg == NULL) {
+ fprintf(stderr, "%s> Missing args\n", __func__);
+ return 1;
+ }
+
+ if (read_nvs(file_name, buf, BUF_SIZE_4_NVS_FILE, &nvs_size))
+ return 1;
+
+ switch (nvs_size) {
+ case NVS_FILE_SIZE_127X:
+ cmn.arch = WL1271_ARCH;
+ break;
+ case NVS_FILE_SIZE_128X:
+ cmn.arch = WL128X_ARCH;
+ break;
+ default:
+ fprintf(stderr, "%s> Wrong file size\n", __func__);
+ return 1;
+ }
+
+ cfg_nvs_ops(&cmn);
+
+ /* create new NVS file */
+ new_nvs = open(file_name,
+ O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (new_nvs < 0) {
+ fprintf(stderr, "%s> Unable to open new NVS file\n", __func__);
+ return 1;
+ }
+
+ write(new_nvs, &vals[1], 1);
+ write(new_nvs, &vals[2], 1);
+ write(new_nvs, &vals[3], 1);
+
+ if (get_mac_addr(0, mac_addr)) {
+ fprintf(stderr, "%s> Fail to get mac addr\n", __func__);
+ close(new_nvs);
+ return 1;
+ }
+
+ /* write down MAC address in new NVS file */
+ write(new_nvs, &mac_addr[5], 1);
+ write(new_nvs, &mac_addr[4], 1);
+ write(new_nvs, &mac_addr[3], 1);
+ write(new_nvs, &mac_addr[2], 1);
+
+ write(new_nvs, &vals[1], 1);
+ write(new_nvs, &vals[4], 1);
+ write(new_nvs, &vals[3], 1);
+
+ write(new_nvs, &mac_addr[1], 1);
+ write(new_nvs, &mac_addr[0], 1);
+
+ write(new_nvs, &vals[0], 1);
+ write(new_nvs, &vals[0], 1);
+
+ /* fill end burst transaction zeros */
+ for (i = 0; i < NVS_END_BURST_TRANSACTION_LENGTH; i++)
+ write(new_nvs, &vals[0], 1);
+
+ /* fill zeros to Align TLV start address */
+ for (i = 0; i < NVS_ALING_TLV_START_ADDRESS_LENGTH; i++)
+ write(new_nvs, &vals[0], 1);
+
+ /* Fill TxBip */
+ pdata = (struct wl1271_cmd_cal_p2g *)arg;
+
+ write(new_nvs, &vals[6], 1);
+ write(new_nvs, &pdata->len, 2);
+
+ p = (unsigned char *)&(pdata->buf);
+ for (i = 0; i < pdata->len; i++)
+ write(new_nvs, p++, 1);
+
+ {
+ unsigned int old_ver;
+#if 0
+ {
+ unsigned char *p = (unsigned char *)buf;
+ for (old_ver = 0; old_ver < 1024; old_ver++) {
+ if (old_ver%16 == 0)
+ printf("\n");
+ printf("%02x ", *p++);
+ }
+ }
+#endif
+ memset(old_data, 0,
+ sizeof(struct wl1271_cmd_cal_p2g)*
+ eNUMBER_RADIO_TYPE_PARAMETERS_INFO);
+ nvs_parse_data((const unsigned char *)&buf[NVS_PRE_PARAMETERS_LENGTH],
+ old_data, &old_ver);
+
+ nvs_fill_old_rx_data(new_nvs,
+ old_data[eNVS_RADIO_RX_TYPE_PARAMETERS_INFO].buf,
+ old_data[eNVS_RADIO_RX_TYPE_PARAMETERS_INFO].len);
+ }
+
+ /* fill NVS version */
+ if (nvs_fill_version(new_nvs, &pdata->ver))
+ fprintf(stderr, "Fail to fill version\n");
+
+ /* fill end of NVS */
+ write(new_nvs, &vals[5], 1); /* eTLV_LAST */
+ write(new_nvs, &vals[5], 1); /* eTLV_LAST */
+ write(new_nvs, &vals[0], 1);
+ write(new_nvs, &vals[0], 1);
+
+ /* fill radio params */
+ if (cmn.nvs_ops->nvs_fill_radio_prms(new_nvs, NULL, buf))
+ fprintf(stderr, "Fail to fill radio params\n");
+
+ close(new_nvs);
+
+ return 0;
+}
+
+int create_nvs_file(struct wl12xx_common *cmn)
+{
+ int new_nvs, res = 0;
+ char buf[2048];
+
+ /* create new NVS file */
+ new_nvs = open(cmn->nvs_name,
+ O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (new_nvs < 0) {
+ fprintf(stderr, "%s> Unable to open new NVS file\n", __func__);
+ return 1;
+ }
+
+ /* fill nvs part */
+ if (nvs_fill_nvs_part(new_nvs)) {
+ fprintf(stderr, "Fail to fill NVS part\n");
+ res = 1;
+
+ goto out;
+ }
+
+ /* fill radio params */
+ if (cmn->nvs_ops->nvs_fill_radio_prms(new_nvs, &cmn->ini, buf)) {
+ fprintf(stderr, "Fail to fill radio params\n");
+ res = 1;
+ }
+
+out:
+ close(new_nvs);
+
+ return res;
+}
+
+int update_nvs_file(const char *nvs_infile, const char *nvs_outfile, struct wl12xx_common *cmn)
+{
+ int new_nvs, res = 0;
+ char buf[2048];
+
+ res = read_nvs(nvs_infile, buf, BUF_SIZE_4_NVS_FILE, NULL);
+ if (res)
+ return 1;
+
+ /* create new NVS file */
+ new_nvs = open(nvs_outfile,
+ O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (new_nvs < 0) {
+ fprintf(stderr, "%s> Unable to open new NVS file\n", __func__);
+ return 1;
+ }
+
+ /* fill nvs part */
+ if (nvs_upd_nvs_part(new_nvs, buf)) {
+ fprintf(stderr, "Fail to fill NVS part\n");
+ res = 1;
+
+ goto out;
+ }
+
+ /* fill radio params */
+ if (cmn->nvs_ops->nvs_fill_radio_prms(new_nvs, &cmn->ini, buf)) {
+ printf("Fail to fill radio params\n");
+ res = 1;
+ }
+
+out:
+ close(new_nvs);
+
+ return res;
+}
+
+int dump_nvs_file(const char *nvs_file)
+{
+ int sz=0, size;
+ char buf[2048];
+ unsigned char *p = (unsigned char *)buf;
+
+ if (read_nvs(nvs_file, buf, BUF_SIZE_4_NVS_FILE, &size))
+ return 1;
+
+ printf("\nThe size is %d bytes\n", size);
+
+ for ( ; sz < size; sz++) {
+ if (sz%16 == 0)
+ printf("\n %04X ", sz);
+ printf("%02x ", *p++);
+ }
+ printf("\n");
+
+ return 0;
+}
+
+int set_nvs_file_autofem(const char *nvs_file, unsigned char val,
+ struct wl12xx_common *cmn)
+{
+ int new_nvs, res = 0;
+ char buf[2048];
+ int nvs_file_sz;
+
+ res = read_nvs(nvs_file, buf, BUF_SIZE_4_NVS_FILE, &nvs_file_sz);
+ if (res)
+ return 1;
+
+ if (nvs_get_arch(nvs_file_sz, cmn)) {
+ fprintf(stderr, "Fail to define architecture\n");
+ return 1;
+ }
+
+ cfg_nvs_ops(cmn);
+
+ /* create new NVS file */
+ new_nvs = open(nvs_file,
+ O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (new_nvs < 0) {
+ fprintf(stderr, "%s> Unable to open new NVS file\n", __func__);
+ return 1;
+ }
+
+ /* fill nvs part */
+ if (nvs_upd_nvs_part(new_nvs, buf)) {
+ fprintf(stderr, "Fail to fill NVS part\n");
+ res = 1;
+
+ goto out;
+ }
+
+ /* fill radio params */
+ if (cmn->nvs_ops->nvs_set_autofem(new_nvs, buf, val)) {
+ printf("Fail to fill radio params\n");
+ res = 1;
+ }
+
+out:
+ close(new_nvs);
+
+ return res;
+}
+
+int set_nvs_file_fem_manuf(const char *nvs_file, unsigned char val,
+ struct wl12xx_common *cmn)
+{
+ int new_nvs, res = 0;
+ char buf[2048];
+ int nvs_file_sz;
+
+ res = read_nvs(nvs_file, buf, BUF_SIZE_4_NVS_FILE, &nvs_file_sz);
+ if (res)
+ return 1;
+
+ if (nvs_get_arch(nvs_file_sz, cmn)) {
+ fprintf(stderr, "Fail to define architecture\n");
+ return 1;
+ }
+
+ cfg_nvs_ops(cmn);
+
+ /* create new NVS file */
+ new_nvs = open(nvs_file,
+ O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (new_nvs < 0) {
+ fprintf(stderr, "%s> Unable to open new NVS file\n", __func__);
+ return 1;
+ }
+
+ /* fill nvs part */
+ if (nvs_upd_nvs_part(new_nvs, buf)) {
+ fprintf(stderr, "Fail to fill NVS part\n");
+ res = 1;
+
+ goto out;
+ }
+
+ /* fill radio params */
+ if (cmn->nvs_ops->nvs_set_fem_manuf(new_nvs, buf, val)) {
+ printf("Fail to fill radio params\n");
+ res = 1;
+ }
+
+out:
+ close(new_nvs);
+
+ return res;
+}
+
+static void _print_hexa(char *name, unsigned char *data, size_t len)
+{
+ size_t i;
+
+ printf("%s = ", name);
+ for (i = 0; i < len; i++) {
+ printf("%02X ", *data++);
+ }
+ printf("\n");
+}
+
+#define print_hexa(name, data) _print_hexa(name, data, sizeof(data))
+
+
+static void print_128x_general_params(struct wl128x_ini_general_params *p)
+{
+ printf("# SECTION 1.1: General parameters\n");
+ printf("TXBiPFEMAutoDetect = %02X\n", p->tx_bip_fem_auto_detect);
+ printf("TXBiPFEMManufacturer = %02X\n", p->tx_bip_fem_manufacturer);
+ printf("RefClk = %02X\n", p->ref_clock);
+ printf("SettlingTime = %02X\n", p->settling_time);
+ printf("ClockValidOnWakeup = %02X\n", p->clk_valid_on_wakeup);
+ printf("TCXO_Clk = %02X\n", p->tcxo_ref_clock);
+ printf("TCXO_SettlingTime = %02X\n", p->tcxo_settling_time);
+ printf("TCXO_ClockValidOnWakeup = %02X\n", p->tcxo_valid_on_wakeup);
+ printf("TCXO_LDO_Voltage = %02X\n", p->tcxo_ldo_voltage);
+ printf("Platform_configuration = %02X\n", p->platform_conf);
+ printf("Single_Dual_Band_Solution = %02X\n", p->dual_mode_select);
+ print_hexa("Settings", p->general_settings);
+ printf("XTALItrimVal = %02X\n", p->xtal_itrim_val);
+ printf("SRState = %02X\n", p->sr_state);
+ print_hexa("SRF1", p->srf1);
+ print_hexa("SRF2", p->srf2);
+ print_hexa("SRF3", p->srf3);
+ printf("\n");
+}
+
+static void print_127x_general_params(struct wl1271_ini_general_params *p)
+{
+ printf("# SECTION 1.1: General parameters\n");
+ printf("TXBiPFEMAutoDetect = %02X\n", p->tx_bip_fem_auto_detect);
+ printf("TXBiPFEMManufacturer = %02X\n", p->tx_bip_fem_manufacturer);
+ printf("RefClk = %02X\n", p->ref_clock);
+ printf("SettlingTime = %02X\n", p->settling_time);
+ printf("ClockValidOnWakeup = %02X\n", p->clk_valid_on_wakeup);
+ printf("DC2DCMode = %02X\n", p->dc2dc_mode);
+ printf("Single_Dual_Band_Solution = %02X\n", p->dual_mode_select);
+ printf("Settings = %02X\n", p->general_settings);
+ printf("SRState = %02X\n", p->sr_state);
+ print_hexa("SRF1", p->srf1);
+ print_hexa("SRF2", p->srf2);
+ print_hexa("SRF3", p->srf3);
+ printf("\n");
+}
+
+static void print_127x_band2_params(struct wl1271_ini_band_params_2 *p)
+{
+ printf("# SECTION 1.2.1: 2.4G parameters\n");
+ printf("RxTraceInsertionLoss_2_4G = %02X\n", p->rx_trace_insertion_loss);
+ printf("TXTraceLoss_2_4G = %02X\n", p->tx_trace_loss);
+ print_hexa("RxRssiAndProcessCompensation_2_4G", p->rx_rssi_process_compens);
+ printf("\n");
+}
+
+static void print_128x_band2_params(struct wl128x_ini_band_params_2 *p)
+{
+ printf("# SECTION 1.2.1: 2.4G parameters\n");
+ printf("RxTraceInsertionLoss_2_4G = %02X\n", p->rx_trace_insertion_loss);
+ print_hexa("TXTraceLoss_2_4G", p->tx_trace_loss);
+ printf("\n");
+}
+
+static void print_127x_band5_params(struct wl1271_ini_band_params_5 *p)
+{
+ printf("# SECTION 1.2.2: 5G parameters\n");
+
+ print_hexa("RxTraceInsertionLoss_5G", p->rx_trace_insertion_loss);
+ print_hexa("TXTraceLoss_5G", p->tx_trace_loss);
+ print_hexa("RxRssiAndProcessCompensation_5G", p->rx_rssi_process_compens);
+ printf("\n");
+}
+
+static void print_128x_band5_params(struct wl128x_ini_band_params_5 *p)
+{
+ printf("# SECTION 1.2.2: 5G parameters\n");
+
+ print_hexa("RxTraceInsertionLoss_5G", p->rx_trace_insertion_loss);
+ print_hexa("TXTraceLoss_5G", p->tx_trace_loss);
+ printf("\n");
+}
+
+static void _print_femhexa(char *fem ,char *name, unsigned char *data, int size)
+{
+ printf("%s", fem);
+ _print_hexa(name, data, size);
+}
+
+static void _print_femle16a(char *fem, char *name, __le16 *data, int len)
+{
+ int i;
+ unsigned char *ptr = (unsigned char *)data;
+
+ printf("%s%s = ", fem, name);
+ for (i = 0; i < len; i++) {
+ printf("%02X%02X ", *(ptr+1), *ptr);
+ ptr += 2;
+ }
+ printf("\n");
+}
+
+
+#define print_femhexa(fem, name, data) _print_femhexa(fem, name, data, sizeof(data))
+#define print_femle16a(fem, name, data) _print_femle16a(fem, name, data, sizeof(data) / 2)
+
+static void print_127x_fem_param2(int femnr, struct wl1271_ini_fem_params_2 *p)
+{
+ char fem[6];
+ int ret;
+
+ printf("# SECTION 2.1.1: 2.4G parameters\n");
+
+ ret = snprintf(fem, sizeof(fem), "FEM%d_", femnr);
+ if (ret < 0 || ret >= ((int) sizeof(fem))) {
+ printf("# Invalid FEM numer %d\n", femnr);
+ return;
+ }
+
+ printf("%sTXBiPReferencePDvoltage_2_4G = %04X\n", fem, p->tx_bip_ref_pd_voltage);
+ printf("%sTxBiPReferencePower_2_4G = %02X\n", fem, p->tx_bip_ref_power);
+ printf("%sTxBiPOffsetdB_2_4G = %02X\n", fem, p->tx_bip_ref_offset);
+
+ print_femhexa(fem, "TxPerRatePowerLimits_2_4G_Normal", p->tx_per_rate_pwr_limits_normal);
+ print_femhexa(fem, "TxPerRatePowerLimits_2_4G_Degraded", p->tx_per_rate_pwr_limits_degraded);
+ print_femhexa(fem, "TxPerRatePowerLimits_2_4G_Extreme", p->tx_per_rate_pwr_limits_extreme);
+
+ printf("%sDegradedLowToNormalThr_2_4G = %02X\n", fem, p->degraded_low_to_normal_thr);
+ printf("%sNormalToDegradedHighThr_2_4G = %02X\n", fem, p->normal_to_degraded_high_thr);
+
+ print_femhexa(fem, "TxPerChannelPowerLimits_2_4G_11b", p->tx_per_chan_pwr_limits_11b);
+ print_femhexa(fem, "TxPerChannelPowerLimits_2_4G_OFDM", p->tx_per_chan_pwr_limits_ofdm);
+ print_femhexa(fem, "TxPDVsRateOffsets_2_4G", p->tx_pd_vs_rate_offsets);
+ print_femhexa(fem, "TxIbiasTable_2_4G", p->tx_ibias);
+
+ printf("%sRxFemInsertionLoss_2_4G = %02X\n", fem, p->rx_fem_insertion_loss);
+}
+
+static void print_128x_fem_param2(int femnr, struct wl128x_ini_fem_params_2 *p)
+{
+ char fem[6];
+ sprintf(fem, "FEM%d_", femnr);
+
+ printf("# SECTION 2.1.1: 2.4G parameters\n");
+
+ printf("%sTXBiPReferencePDvoltage_2_4G = %04X\n", fem, p->tx_bip_ref_pd_voltage);
+ printf("%sTxBiPReferencePower_2_4G = %02X\n", fem, p->tx_bip_ref_power);
+ printf("%sTxBiPOffsetdB_2_4G = %02X\n", fem, p->tx_bip_ref_offset);
+
+ print_femhexa(fem, "TxPerRatePowerLimits_2_4G_Normal", p->tx_per_rate_pwr_limits_normal);
+ print_femhexa(fem, "TxPerRatePowerLimits_2_4G_Degraded", p->tx_per_rate_pwr_limits_degraded);
+ print_femhexa(fem, "TxPerRatePowerLimits_2_4G_Extreme", p->tx_per_rate_pwr_limits_extreme);
+
+ printf("%sDegradedLowToNormalThr_2_4G = %02X\n", fem, p->degraded_low_to_normal_thr);
+ printf("%sNormalToDegradedHighThr_2_4G = %02X\n", fem, p->normal_to_degraded_high_thr);
+
+ print_femhexa(fem, "TxPerChannelPowerLimits_2_4G_11b", p->tx_per_chan_pwr_limits_11b);
+ print_femhexa(fem, "TxPerChannelPowerLimits_2_4G_OFDM", p->tx_per_chan_pwr_limits_ofdm);
+ print_femhexa(fem, "TxPDVsRateOffsets_2_4G", p->tx_pd_vs_rate_offsets);
+ print_femhexa(fem, "TxPDVsChannelOffsets_2_4G", p->tx_pd_vs_chan_offsets);
+ print_femhexa(fem, "TxPDVsTemperature_2_4G", p->tx_pd_vs_temperature);
+ print_femhexa(fem, "TxIbiasTable_2_4G", p->tx_ibias);
+
+ printf("%sRxFemInsertionLoss_2_4G = %02X\n", fem, p->rx_fem_insertion_loss);
+}
+
+static void print_127x_fem_param5(int femnr, struct wl1271_ini_fem_params_5 *p)
+{
+ char fem[6];
+ sprintf(fem, "FEM%d_", femnr);
+
+ printf("# SECTION 2.1.2: 5G parameters\n");
+
+ print_femle16a(fem, "TxBiPReferencePDvoltage_5G", p->tx_bip_ref_pd_voltage);
+
+ print_femhexa(fem, "TxBiPReferencePower_5G", p->tx_bip_ref_power);
+ print_femhexa(fem, "TxBiPOffsetdB_5G", p->tx_bip_ref_offset);
+
+ print_femhexa(fem, "TxPerRatePowerLimits_5G_Normal", p->tx_per_rate_pwr_limits_normal);
+ print_femhexa(fem, "TxPerRatePowerLimits_5G_Degraded", p->tx_per_rate_pwr_limits_degraded);
+ print_femhexa(fem, "TxPerRatePowerLimits_5G_Extreme", p->tx_per_rate_pwr_limits_extreme);
+
+ printf("%sDegradedLowToNormalThr_5G = %02X\n", fem, p->degraded_low_to_normal_thr);
+ printf("%sNormalToDegradedHighThr_5G = %02X\n", fem, p->normal_to_degraded_high_thr);
+
+ print_femhexa(fem, "TxPerChannelPowerLimits_5G_OFDM", p->tx_per_chan_pwr_limits_ofdm);
+ print_femhexa(fem, "TxPDVsRateOffsets_5G", p->tx_pd_vs_rate_offsets);
+ print_femhexa(fem, "TxIbiasTable_5G", p->tx_ibias);
+ print_femhexa(fem, "RxFemInsertionLoss_5G", p->rx_fem_insertion_loss);
+}
+
+static void print_128x_fem_param5(int femnr, struct wl128x_ini_fem_params_5 *p)
+{
+ char fem[6];
+ sprintf(fem, "FEM%d_", femnr);
+
+ printf("# SECTION 2.1.2: 5G parameters\n");
+
+ print_femle16a(fem, "TxBiPReferencePDvoltage_5G", p->tx_bip_ref_pd_voltage);
+
+ print_femhexa(fem, "TxBiPReferencePower_5G", p->tx_bip_ref_power);
+ print_femhexa(fem, "TxBiPOffsetdB_5G", p->tx_bip_ref_offset);
+
+ print_femhexa(fem, "TxPerRatePowerLimits_5G_Normal", p->tx_per_rate_pwr_limits_normal);
+ print_femhexa(fem, "TxPerRatePowerLimits_5G_Degraded", p->tx_per_rate_pwr_limits_degraded);
+ print_femhexa(fem, "TxPerRatePowerLimits_5G_Extreme", p->tx_per_rate_pwr_limits_extreme);
+
+ printf("%sDegradedLowToNormalThr_5G = %02X\n", fem, p->degraded_low_to_normal_thr);
+ printf("%sNormalToDegradedHighThr_5G = %02X\n", fem, p->normal_to_degraded_high_thr);
+
+ print_femhexa(fem, "TxPerChannelPowerLimits_5G_OFDM", p->tx_per_chan_pwr_limits_ofdm);
+ print_femhexa(fem, "TxPDVsRateOffsets_5G", p->tx_pd_vs_rate_offsets);
+ print_femhexa(fem, "TxPDVsChannelOffsets_5G", p->tx_pd_vs_chan_offsets);
+ print_femhexa(fem, "TxPDVsTemperature_5G", p->tx_pd_vs_temperature);
+ print_femhexa(fem, "TxIbiasTable_5G", p->tx_ibias);
+ print_femhexa(fem, "RxFemInsertionLoss_5G", p->rx_fem_insertion_loss);
+}
+
+int get_fem_nr(int autodetect, int manuf, int *femcnt, int *femi)
+{
+ if (autodetect) {
+ printf("#Fem autodetect is on. Showing both FEM datas\n");
+ *femcnt = 2;
+ *femi = 0;
+ }
+ else {
+ *femcnt = 1;
+ if(manuf >= WL1271_INI_FEM_MODULE_COUNT) {
+ fprintf(stderr, "FEM index out of bounds (%d > %d)\n", manuf,
+ WL1271_INI_FEM_MODULE_COUNT);
+ return 1;
+ }
+
+ *femi = manuf;
+ printf("#Fem autodetect is off. FEM manufacturer=%d "
+ "Fem entry used is %d\n",
+ manuf, WL12XX_FEM_TO_NVS_ENTRY(manuf));
+ }
+ return 0;
+}
+
+
+
+int info_nvs_file(const char *nvs_file)
+{
+ char buf[BUF_SIZE_4_NVS_FILE];
+ int ret, i, femi, femcnt, maxfem, fem_idx;
+
+ int fd = open(nvs_file, O_RDONLY, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open NVS %s\n", nvs_file);
+ return 1;
+ }
+
+ ret = read(fd, buf, BUF_SIZE_4_NVS_FILE);
+ if (ret < 0) {
+ fprintf(stderr, "Fail to read file %s (%s)\n", nvs_file,
+ strerror(errno));
+ close(fd);
+ return 1;
+ }
+ close(fd);
+
+ if (ret == sizeof(struct wl1271_nvs_file)) {
+ struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *) &buf;
+ printf("#Chip is 127x\n");
+ print_127x_general_params(&nvs->ini.general_params);
+ print_127x_band2_params(&nvs->ini.stat_radio_params_2);
+ if (nvs->ini.general_params.dual_mode_select)
+ print_127x_band5_params(&nvs->ini.stat_radio_params_5);
+
+ if( get_fem_nr(nvs->ini.general_params.tx_bip_fem_auto_detect,
+ nvs->ini.general_params.tx_bip_fem_manufacturer,
+ &femcnt, &femi))
+ return 1;
+
+ maxfem = femcnt + femi;
+ for (i = femi; i < maxfem; i++) {
+ fem_idx = WL12XX_FEM_TO_NVS_ENTRY(i);
+
+ print_127x_fem_param2(i, &nvs->ini.
+ dyn_radio_params_2[fem_idx].params);
+ printf("\n");
+
+ if (nvs->ini.general_params.dual_mode_select == 1) {
+ print_127x_fem_param5(femi, &nvs->ini.
+ dyn_radio_params_5[fem_idx].params);
+ printf("\n");
+ }
+ femi++;
+ }
+ }
+ else if (ret == sizeof(struct wl128x_nvs_file)) {
+ struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *) &buf;
+ printf("#Chip is 128x\n");
+ print_128x_general_params(&nvs->ini.general_params);
+ print_128x_band2_params(&nvs->ini.stat_radio_params_2);
+ if (nvs->ini.general_params.dual_mode_select)
+ print_128x_band5_params(&nvs->ini.stat_radio_params_5);
+
+ printf("# SECTION 2.1: FEM parameters\n");
+ printf("FemVendorAndOptions = %02X\n\n", nvs->ini.fem_vendor_and_options);
+
+ if( get_fem_nr(nvs->ini.general_params.tx_bip_fem_auto_detect,
+ nvs->ini.general_params.tx_bip_fem_manufacturer,
+ &femcnt, &femi))
+ return 1;
+
+ maxfem = femcnt + femi;
+ for (i = femi; i < maxfem; i++) {
+ fem_idx = WL12XX_FEM_TO_NVS_ENTRY(i);
+
+ print_128x_fem_param2(femi, &nvs->ini.
+ dyn_radio_params_2[fem_idx].params);
+ printf("\n");
+ if (nvs->ini.general_params.dual_mode_select == 1) {
+ print_128x_fem_param5(femi, &nvs->ini.
+ dyn_radio_params_5[fem_idx].params);
+ printf("\n");
+ }
+ femi++;
+ }
+ }
+ else {
+ fprintf(stderr, "Invalid file size %d. Unable to detect chip type\n", ret);
+ return 0;
+ }
+
+ return 0;
+}
+
diff --git a/nvs.h b/nvs.h
new file mode 100644
index 0000000..481fbe2
--- /dev/null
+++ b/nvs.h
@@ -0,0 +1,31 @@
+#ifndef __NVS_H
+#define __NVS_H
+
+#define WL127X_NVS_FILE_SZ 912
+#define WL128X_NVS_FILE_SZ 1113
+
+char *get_opt_nvsinfile(int argc, char **argv);
+char *get_opt_nvsoutfile(int argc, char **argv);
+
+int prepare_nvs_file(void *arg, char *file_name);
+
+int nvs_set_mac(char *nvsfile, char *mac);
+
+void cfg_nvs_ops(struct wl12xx_common *cmn);
+
+int create_nvs_file(struct wl12xx_common *cmn);
+
+int update_nvs_file(const char *nvs_infile, const char *nvs_outfile,
+ struct wl12xx_common *cmn);
+
+int dump_nvs_file(const char *nvs_file);
+
+int set_nvs_file_autofem(const char *nvs_file, unsigned char val,
+ struct wl12xx_common *cmn);
+
+int set_nvs_file_fem_manuf(const char *nvs_file, unsigned char val,
+ struct wl12xx_common *cmn);
+
+int info_nvs_file(const char *nvs_file);
+
+#endif /* __NVS_H */
diff --git a/plt.c b/plt.c
new file mode 100644
index 0000000..1964b9d
--- /dev/null
+++ b/plt.c
@@ -0,0 +1,1431 @@
+/*
+ * PLT utility for wireless chip supported by TI's driver wl12xx
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <net/if.h>
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include <linux/ethtool.h>
+#include "nl80211.h"
+
+#include "calibrator.h"
+#include "plt.h"
+#include "ini.h"
+#include "nvs.h"
+
+#define ZERO_MAC "00:00:00:00:00:00"
+
+#ifndef SIOCETHTOOL
+#define SIOCETHTOOL 0x8946
+#endif
+
+SECTION(plt);
+
+#define CMDBUF_SIZE 200
+static int insmod(char *filename)
+{
+ int ret;
+ char cmd[CMDBUF_SIZE];
+ snprintf(cmd, CMDBUF_SIZE, "%s %s", INSMOD_PATH, filename);
+ ret = system(cmd);
+ if (ret)
+ fprintf(stderr, "Failed to load kernel module using command %s\n", cmd);
+ return ret;
+}
+
+static int rmmod(char *name)
+{
+ char cmd[CMDBUF_SIZE];
+ char *tmp;
+ int i, ret;
+
+ /* "basename" */
+ tmp = strrchr(name, '/');
+ if (!tmp)
+ tmp = name;
+ else
+ tmp++;
+
+ tmp = strdup(tmp);
+ if (!tmp)
+ return -ENOMEM;
+
+ /* strip trailing .ko if there */
+ i = strlen(tmp);
+ if (i < 4) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!strcmp(tmp + i - 3, ".ko"))
+ tmp[i-3] = 0;
+
+ snprintf(cmd, CMDBUF_SIZE, "%s %s", RMMOD_PATH, tmp);
+ ret = system(cmd);
+ if (ret)
+ fprintf(stderr, "Failed to remove kernel module using command %s\n", cmd);
+out:
+ free(tmp);
+ return ret;
+}
+
+static int fem_detect_valid_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
+ unsigned char *fem_manuf;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_TESTDATA]) {
+ fprintf(stderr, "no data!\n");
+ return NL_SKIP;
+ }
+
+ nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
+ nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);
+
+ fem_manuf = (unsigned char*) nla_data(td[WL1271_TM_ATTR_DATA]);
+
+ printf("Firmware detect FEM type=%d\n", *fem_manuf);
+
+ return NL_SKIP;
+}
+
+static int plt_power_mode(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ unsigned int pmode;
+
+ if (argc != 1) {
+ fprintf(stderr, "%s> Missing arguments\n", __func__);
+ return 2;
+ }
+
+ if (strcmp(argv[0], "on") == 0)
+ pmode = PLT_ON;
+ else if (strcmp(argv[0], "off") == 0)
+ pmode = PLT_OFF;
+ else if (strcmp(argv[0], "fem_detect") == 0)
+ pmode = PLT_FEM_DETECT;
+ else if (strcmp(argv[0], "chip_awake") == 0)
+ pmode = PLT_CHIP_AWAKE;
+ else {
+ fprintf(stderr, "%s> Invalid parameter\n", __func__);
+ return 2;
+ }
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__);
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_SET_PLT_MODE);
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_PLT_MODE, pmode);
+
+ nla_nest_end(msg, key);
+
+ if (pmode == PLT_FEM_DETECT)
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, fem_detect_valid_handler, NULL);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, power_mode, "<on|off|fem_detect|chip_awake>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_power_mode,
+ "Set PLT power mode\n");
+
+static int plt_tune_channel(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_cal_channel_tune prms;
+
+ if (argc < 1 || argc > 2)
+ return 1;
+
+ prms.test.id = TEST_CMD_CHANNEL_TUNE;
+ prms.band = (unsigned char)atoi(argv[0]);
+ prms.channel = (unsigned char)atoi(argv[1]);
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA,
+ sizeof(struct wl1271_cmd_cal_channel_tune),
+ &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, tune_channel, "<band> <channel>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tune_channel,
+ "Set band and channel for PLT\n");
+
+static int plt_ref_point(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_cal_update_ref_point prms;
+
+ if (argc < 1 || argc > 3)
+ return 1;
+
+ prms.test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT;
+ prms.ref_detector = atoi(argv[0]);
+ prms.ref_power = atoi(argv[1]);
+ prms.sub_band = atoi(argv[2]);
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, ref_point, "<voltage> <power> <subband>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_ref_point,
+ "Set reference point for PLT\n");
+
+static int calib_valid_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
+ struct wl1271_cmd_cal_p2g *prms;
+#if 0
+ int i; unsigned char *pc;
+#endif
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_TESTDATA]) {
+ fprintf(stderr, "no data!\n");
+ return NL_SKIP;
+ }
+
+ nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
+ nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);
+
+ prms = (struct wl1271_cmd_cal_p2g *)nla_data(td[WL1271_TM_ATTR_DATA]);
+
+ if (prms->radio_status) {
+ fprintf(stderr, "Fail to calibrate with radio status (%d)\n",
+ (signed short)prms->radio_status);
+ return 2;
+ }
+#if 0
+ printf("%s> id %04x status %04x\ntest id %02x ver %08x len %04x=%d\n",
+ __func__,
+ prms->header.id, prms->header.status, prms->test.id,
+ prms->ver, prms->len, prms->len);
+
+ pc = (unsigned char *)prms->buf;
+ printf("++++++++++++++++++++++++\n");
+ for (i = 0; i < prms->len; i++) {
+ if (i%0xf == 0)
+ printf("\n");
+
+ printf("%02x ", *(unsigned char *)pc);
+ pc += 1;
+ }
+ printf("++++++++++++++++++++++++\n");
+#endif
+ printf("Writing calibration data to %s\n", (char*) arg);
+ if (prepare_nvs_file(prms, arg)) {
+ fprintf(stderr, "Fail to prepare calibrated NVS file\n");
+ return 2;
+ }
+#if 0
+ printf("\n\tThe NVS file (%s) is ready\n\tCopy it to %s and "
+ "reboot the system\n\n",
+ NEW_NVS_NAME, CURRENT_NVS_NAME);
+#endif
+ return NL_SKIP;
+}
+
+static void dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+ printf("\n\tDriver %s\n\t"
+ "version %s\n\t"
+ "FW version %s\n\t"
+ "Bus info %s\n\t"
+ "HW version 0x%X\n",
+ info->driver, info->version,
+ info->fw_version, info->bus_info, regs->version);
+}
+
+
+int do_get_drv_info(char *dev_name, int *hw_ver,
+ struct ethtool_drvinfo *out_drvinfo)
+{
+ struct ifreq ifr;
+ int fd, err;
+ struct ethtool_drvinfo drvinfo;
+ struct ethtool_regs *regs;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, dev_name);
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot get control socket\n");
+ return 1;
+ }
+
+ drvinfo.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t)&drvinfo;
+ err = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (err < 0) {
+ fprintf(stderr, "Cannot get driver information\n");
+ goto error_out;
+ }
+
+ regs = calloc(1, sizeof(*regs)+drvinfo.regdump_len);
+ if (!regs) {
+ fprintf(stderr, "Cannot allocate memory for register dump\n");
+ goto error_out;
+ }
+
+ regs->cmd = ETHTOOL_GREGS;
+ regs->len = drvinfo.regdump_len;
+ ifr.ifr_data = (caddr_t)regs;
+ err = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (err < 0) {
+ fprintf(stderr, "Cannot get register dump\n");
+ goto error_out2;
+ }
+
+ if (hw_ver)
+ *hw_ver = regs->version;
+ if (out_drvinfo)
+ *out_drvinfo=drvinfo;
+ if (!hw_ver && !out_drvinfo)
+ dump_regs(&drvinfo, regs);
+ free(regs);
+
+ return 0;
+
+error_out2:
+ free(regs);
+
+error_out:
+ close(fd);
+
+ return 1;
+}
+
+int is_fw_ver_valid(char *dev_name, struct fw_version *fw_ver_valid)
+{
+ char *str, *tmp_str;
+ struct ethtool_drvinfo drvinfo;
+ int i=0, ret=0;
+ struct fw_version fw_ver_crnt;
+
+ ret = do_get_drv_info(dev_name, NULL, &drvinfo);
+ if(ret) {
+ printf("\tFailed to get FW version.\n");
+ goto error;
+ }
+
+ str=drvinfo.fw_version;
+
+ /* Looking for the last space in the version.*/
+ /* Usually version starting with text and value after spacing.*/
+ tmp_str = strrchr (str,' ');
+ while((tmp_str != NULL) &&
+ (i < (int) (sizeof(fw_ver_valid->ver)/sizeof(int))))
+ {
+ tmp_str++;
+ fw_ver_crnt.ver[i]=atoi(tmp_str);
+ if (fw_ver_crnt.ver[i] < fw_ver_valid->ver[i]) {
+ ret=1;
+ break;
+ } else if (fw_ver_crnt.ver[i] > fw_ver_valid->ver[i]) {
+ ret=0;
+ break;
+ }
+ tmp_str = strchr (tmp_str, '.');
+ i++;
+ }
+
+error:
+ return ret;
+}
+
+static int get_chip_arch(char *dev_name, enum wl12xx_arch *arch)
+{
+ int hw_ver, ret;
+
+ ret = do_get_drv_info(dev_name, &hw_ver, NULL);
+ if (ret)
+ return 1;
+
+ *arch = hw_ver >> 16;
+
+ return 0;
+}
+
+static int do_nvs_ver21(struct nl_msg *msg, enum wl12xx_arch arch)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_set_nvs_ver prms;
+
+ memset(&prms, 0, sizeof(struct wl1271_cmd_set_nvs_ver));
+
+ if (arch == WL1271_ARCH)
+ prms.test.id = TEST_CMD_SET_NVS_VERSION;
+ else if(arch == WL128X_ARCH)
+ prms.test.id = TEST_CMD_SET_NVS_VERSION - 1;
+ else {
+ fprintf(stderr, "Unkown arch %x\n", arch);
+ return 1;
+ }
+
+ prms.nvs_ver = NVS_VERSION_2_1;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+
+static int plt_nvs_ver(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ enum wl12xx_arch arch = UNKNOWN_ARCH;
+ int ret;
+
+ if (argc < 1) {
+ fprintf(stderr, "Missing device name\n");
+ return 2;
+ }
+
+ ret = get_chip_arch(argv[0], &arch);
+ if (ret || (arch == UNKNOWN_ARCH)) {
+ fprintf(stderr, "Unknown chip arch\n");
+ return 2;
+ }
+
+ return do_nvs_ver21(msg, arch);
+}
+
+COMMAND(plt, nvs_ver, "<device name>",
+ NL80211_CMD_TESTMODE, 0, CIB_PHY, plt_nvs_ver,
+ "Set NVS version\n");
+
+
+static int plt_nvs_ver2(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ enum wl12xx_arch arch = UNKNOWN_ARCH;
+ int ret;
+
+ if (argc < 1) {
+ fprintf(stderr, "Missing device name\n");
+ return 2;
+ }
+
+ ret = sscanf(argv[0], "%x", &arch);
+ if(ret != 1) {
+ fprintf(stderr, "Unknown chip arch\n");
+ return 2;
+ }
+
+ return do_nvs_ver21(msg, arch);
+}
+
+COMMAND(plt, nvs_ver, "<arch>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_nvs_ver2,
+ "Set NVS version\n");
+
+static int plt_tx_bip(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_cal_p2g prms;
+ int i;
+ char *nvs_path;
+ static char void_path[] = {'\0'};
+
+ if (argc < 8) {
+ fprintf(stderr, "%s> Missing arguments\n", __func__);
+ return 2;
+ }
+
+ if (argc > 8)
+ nvs_path = argv[8];
+ else
+ nvs_path = void_path;
+
+ memset(&prms, 0, sizeof(struct wl1271_cmd_cal_p2g));
+
+ prms.test.id = TEST_CMD_P2G_CAL;
+ for (i = 0; i < 8; i++)
+ prms.sub_band_mask |= (atoi(argv[i]) & 0x1)<<i;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+ NLA_PUT_U8(msg, WL1271_TM_ATTR_ANSWER, 1);
+
+ nla_nest_end(msg, key);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, calib_valid_handler, nvs_path);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, tx_bip,
+ "<0|1> <0|1> <0|1> <0|1> <0|1> <0|1> <0|1> <0|1> [<nvs file>]",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tx_bip,
+ "Do calibrate\n");
+
+static int plt_tx_tone(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_cal_tx_tone prms;
+
+ if (argc < 2) {
+ fprintf(stderr, "%s> Missing arguments\n", __func__);
+ return 2;
+ }
+
+ memset(&prms, 0, sizeof(struct wl1271_cmd_cal_tx_tone));
+
+ prms.test.id = TEST_CMD_TELEC;
+
+ prms.tone_type = atoi(argv[0]);
+ if (prms.tone_type < 1 || prms.tone_type > 2) {
+ fprintf(stderr, "%s> Invalit tone type parameter %d\n",
+ __func__, prms.tone_type);
+ return 2;
+ }
+
+ prms.power = atoi(argv[1]);
+ if (prms.power > 10000) {
+ fprintf(stderr, "%s> Invalit power parameter %d\n",
+ __func__, prms.power);
+ return 2;
+ }
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, tx_tone, "<tone type 1|2> <power 0 - 10000>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tx_tone,
+ "Do command tx_tone to transmit a tone\n");
+
+static int plt_tx_cont(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_pkt_params prms = {
+ .src_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ };
+
+ if (argc != 15)
+ return 1;
+#if 0
+ printf("%s> delay (%d) rate (%08x) size (%d) amount (%d) power (%d) "
+ "seed (%d) pkt_mode (%d) DCF (%d) GI (%d) preamble (%d) type "
+ "(%d) scramble (%d) CLPC (%d), SeqNbrMode (%d) DestMAC (%s)\n",
+ __func__,
+ atoi(argv[0]), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]),
+ atoi(argv[4]), atoi(argv[5]), atoi(argv[6]), atoi(argv[7]),
+ atoi(argv[8]), atoi(argv[9]), atoi(argv[10]), atoi(argv[11]),
+ atoi(argv[12]), atoi(argv[13]), argv[14]
+ );
+#endif
+ memset((void *)&prms, 0, sizeof(struct wl1271_cmd_pkt_params));
+
+ prms.test.id = TEST_CMD_FCC;
+ prms.delay = atoi(argv[0]);
+ prms.rate = strtol(argv[1], NULL, 0);
+ prms.size = (unsigned short)atoi(argv[2]);
+ prms.amount = (unsigned short)atoi(argv[3]);
+ prms.power = atoi(argv[4]);
+ prms.seed = (unsigned short)atoi(argv[5]);
+ prms.pkt_mode = (unsigned char)atoi(argv[6]);
+ prms.dcf_enable = (unsigned char)atoi(argv[7]);
+ prms.g_interval = (unsigned char)atoi(argv[8]);
+ prms.preamble = (unsigned char)atoi(argv[9]);
+ prms.type = (unsigned char)atoi(argv[10]);
+ prms.scramble = (unsigned char)atoi(argv[11]);
+ prms.clpc_enable = (unsigned char)atoi(argv[12]);
+ prms.seq_nbr_mode = (unsigned char)atoi(argv[13]);
+ str2mac(prms.dst_mac, argv[14]);
+
+ if (get_mac_addr(0, prms.src_mac))
+ fprintf(stderr, "fail to get MAC addr\n");
+
+ printf("%02X:%02X:%02X:%02X:%02X:%02X\n",
+ prms.src_mac[0], prms.src_mac[1], prms.src_mac[2],
+ prms.src_mac[3], prms.src_mac[4], prms.src_mac[5]);
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, tx_cont, "<delay> <rate> <size> <amount> <power>\n\t\t<seed> "
+ "<pkt mode> <DC on/off> <gi> <preamble>\n\t\t<type> <scramble> "
+ "<clpc> <seq nbr mode> <dest mac>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tx_cont,
+ "Start Tx Cont\n");
+
+static int plt_tx_stop(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_pkt_params prms;
+
+ prms.test.id = TEST_CMD_STOP_TX;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, tx_stop, NULL,
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_tx_stop,
+ "Stop Tx Cont\n");
+
+static int plt_start_rx_statcs(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_pkt_params prms;
+
+ prms.test.id = TEST_CMD_RX_STAT_START;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__);
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, start_rx_statcs, NULL,
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_start_rx_statcs,
+ "Start Rx statistics collection\n");
+
+static int plt_stop_rx_statcs(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_pkt_params prms;
+
+ prms.test.id = TEST_CMD_RX_STAT_STOP;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__);
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, stop_rx_statcs, NULL,
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_stop_rx_statcs,
+ "Stop Rx statistics collection\n");
+
+static int plt_reset_rx_statcs(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_cmd_pkt_params prms;
+
+ prms.test.id = TEST_CMD_RX_STAT_RESET;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__);
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, reset_rx_statcs, NULL,
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_reset_rx_statcs,
+ "Reset Rx statistics collection\n");
+
+static int display_rx_statcs(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
+ struct wl1271_radio_rx_statcs *prms;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_TESTDATA]) {
+ fprintf(stderr, "no data!\n");
+ return NL_SKIP;
+ }
+
+ nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
+ nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);
+
+ prms =
+ (struct wl1271_radio_rx_statcs *)
+ nla_data(td[WL1271_TM_ATTR_DATA]);
+
+ printf("\n\tTotal number of pkts\t- %d\n\tAccepted pkts\t\t- %d\n\t"
+ "FCS error pkts\t\t- %d\n\tAddress mismatch pkts\t- %d\n\t"
+ "Average SNR\t\t- % d dBm\n\tAverage RSSI\t\t- % d dBm\n\n",
+ prms->base_pkt_id, prms->rx_path_statcs.nbr_rx_valid_pkts,
+ prms->rx_path_statcs.nbr_rx_fcs_err_pkts,
+ prms->rx_path_statcs.nbr_rx_plcp_err_pkts,
+ (signed short)prms->rx_path_statcs.ave_snr/8,
+ (signed short)prms->rx_path_statcs.ave_rssi/8);
+
+ return NL_SKIP;
+}
+
+static int plt_get_rx_statcs(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl1271_radio_rx_statcs prms;
+
+ prms.test.id = TEST_CMD_RX_STAT_GET;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__);
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+ NLA_PUT_U8(msg, WL1271_TM_ATTR_ANSWER, 1);
+
+ nla_nest_end(msg, key);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, display_rx_statcs, NULL);
+
+ /* Important: needed gap between tx_start and tx_get */
+ sleep(2);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(plt, get_rx_statcs, NULL,
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_get_rx_statcs,
+ "Get Rx statistics\n");
+
+static int plt_rx_statistics(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ int ret;
+
+ /* power mode on */
+ {
+ char *prms[4] = { "wlan0", "plt", "power_mode", "on" };
+
+ ret = handle_cmd(state, II_NETDEV, 4, prms);
+ if (ret < 0) {
+ fprintf(stderr, "Fail to set PLT power mode on\n");
+ return 1;
+ }
+ }
+
+ /* start_rx_statcs */
+ {
+ char *prms[3] = { "wlan0", "plt", "start_rx_statcs" };
+
+ ret = handle_cmd(state, II_NETDEV, 3, prms);
+ if (ret < 0) {
+ fprintf(stderr, "Fail to start Rx statistics\n");
+ goto fail_out;
+ }
+ }
+
+ /* get_rx_statcs */
+ {
+ int err;
+ char *prms[3] = { "wlan0", "plt", "get_rx_statcs" };
+
+ err = handle_cmd(state, II_NETDEV, 3, prms);
+ if (err < 0) {
+ fprintf(stderr, "Fail to get Rx statistics\n");
+ ret = err;
+ }
+ }
+
+
+ /* stop_rx_statcs */
+ {
+ int err;
+ char *prms[3] = { "wlan0", "plt", "stop_rx_statcs" };
+
+ err = handle_cmd(state, II_NETDEV, 3, prms);
+ if (err < 0) {
+ fprintf(stderr, "Fail to stop Rx statistics\n");
+ ret = err;
+ }
+ }
+
+fail_out:
+ /* power mode off */
+ {
+ int err;
+ char *prms[4] = { "wlan0", "plt", "power_mode", "off"};
+
+ err = handle_cmd(state, II_NETDEV, 4, prms);
+ if (err < 0) {
+ fprintf(stderr, "Fail to set PLT power mode on\n");
+ return 1;
+ }
+ }
+
+ if (ret < 0)
+ return 1;
+
+ return 0;
+}
+
+COMMAND(plt, rx_statistics, NULL, 0, 0, CIB_NONE, plt_rx_statistics,
+ "Get Rx statistics\n");
+
+static int plt_do_power_on(struct nl80211_state *state, char *devname)
+{
+ int err;
+ char *pm_on[4] = { devname, "plt", "power_mode", "on" };
+
+ err = handle_cmd(state, II_NETDEV, ARRAY_SIZE(pm_on), pm_on);
+ if (err < 0)
+ fprintf(stderr, "Fail to set PLT power mode on\n");
+
+ return err;
+}
+
+static int plt_do_power_off(struct nl80211_state *state, char *devname)
+{
+ int err;
+ char *prms[4] = { devname, "plt", "power_mode", "off"};
+
+ err = handle_cmd(state, II_NETDEV, ARRAY_SIZE(prms), prms);
+ if (err < 0)
+ fprintf(stderr, "Failed to set PLT power mode on\n");
+
+ return err;
+}
+
+
+static int plt_do_calibrate(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int single_dual, char *nvs_file,
+ char *devname, enum wl12xx_arch arch)
+{
+ int ret = 0, err;
+
+ /* tune channel */
+ {
+ char *tune[5] = {
+ devname, "plt", "tune_channel", "0", "7"
+ };
+
+ err = handle_cmd(state, II_NETDEV, ARRAY_SIZE(tune), tune);
+ if (err < 0) {
+ fprintf(stderr, "Fail to tune channel\n");
+ ret = err;
+ goto fail_out;
+ }
+ }
+
+ /* Set nvs version 2.1 */
+ if (arch == UNKNOWN_ARCH) {
+ fprintf(stderr, "Unknown arch. Not setting nvs ver 2.1\n");
+ }
+ else {
+ size_t ret;
+ char archstr[5] = "";
+ char *prms[4] = {
+ "wlan0", "plt", "nvs_ver", archstr
+ };
+
+ ret = snprintf(archstr, sizeof(archstr), "%x", arch);
+ if (ret > sizeof(archstr)) {
+ fprintf(stderr, "Bad arch\n");
+ goto fail_out;
+ }
+
+ printf("Using nvs version 2.1\n");
+ err = handle_cmd(state, II_NETDEV, 4, prms);
+ if (err < 0) {
+ fprintf(stderr, "Fail to set nvs ver 2.1\n");
+ ret = err;
+ }
+ }
+
+ /* calibrate it */
+ {
+ char *prms[12] = {
+ devname, "plt", "tx_bip", "1", "0", "0", "0",
+ "0", "0", "0", "0", nvs_file
+ };
+ printf("Calibrate %s\n", nvs_file);
+
+ /* set flags in case of dual band */
+ if (single_dual) {
+ prms[4] = prms[5] = prms[6] = prms[7] = prms[8] =
+ prms[9] = prms[10] = "1";
+ }
+
+ err = handle_cmd(state, II_NETDEV, ARRAY_SIZE(prms), prms);
+ if (err < 0) {
+ fprintf(stderr, "Failed to calibrate\n");
+ ret = err;
+ }
+ }
+
+fail_out:
+ if (ret < 0)
+ return 1;
+
+ return 0;
+}
+
+static int plt_calibrate(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ int ret, err;
+ int single_dual = 0;
+
+ if (argc > 2 && (strncmp(argv[2], "dual", 4) == 0))
+ single_dual = 1; /* going for dual band calibration */
+ else
+ single_dual = 0; /* going for single band calibration */
+
+
+ err = plt_do_power_on(state, "wlan0");
+ if (err < 0)
+ goto out;
+
+ err = plt_do_calibrate(state, cb, msg, single_dual, NEW_NVS_NAME,
+ "wlan0", UNKNOWN_ARCH);
+
+ ret = plt_do_power_off(state, "wlan0");
+ if (ret < 0)
+ err = ret;
+out:
+ return err;
+}
+
+COMMAND(plt, calibrate, "[<single|dual>]", 0, 0, CIB_NONE,
+ plt_calibrate, "Do calibrate for single or dual band chip\n");
+
+
+static int plt_autocalibrate(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct wl12xx_common cmn = {
+ .auto_fem = 0,
+ .arch = UNKNOWN_ARCH,
+ .parse_ops = NULL,
+ };
+
+ char *devname, *modpath, *inifile1, *macaddr;
+ char *set_mac_prms[5];
+ int single_dual = 0, res, fems_parsed;
+
+ argc -= 2;
+ argv += 2;
+
+ if (argc < 4 || argc > 5) {
+ return 1;
+ }
+
+ devname = *argv++;
+ argc--;
+
+ modpath = *argv++;
+ argc--;
+
+ inifile1 = *argv++;
+ argc--;
+
+ cmn.nvs_name = get_opt_nvsoutfile(argc--, argv++);
+
+ if (argc) {
+ macaddr = *argv++;
+ argc--;
+ } else {
+ macaddr = NULL;
+ }
+
+ if (file_exist(cmn.nvs_name) >= 0) {
+ fprintf(stderr, "nvs file %s. File already exists. Won't overwrite.\n", cmn.nvs_name);
+ return 0;
+ }
+
+ /* Create ref nvs */
+ if (read_ini(inifile1, &cmn)) {
+ fprintf(stderr, "Failed to read ini file %s\n", inifile1);
+ goto out_removenvs;
+ }
+
+ fems_parsed = cmn.fem0_bands + cmn.fem1_bands + cmn.fem2_bands + cmn.fem3_bands;
+
+ /* Get nr bands from parsed ini */
+ single_dual = ini_get_dual_mode(&cmn);
+
+ if (single_dual == 0) {
+ if (fems_parsed < 1 || fems_parsed > 4) {
+ fprintf(stderr, "Incorrect number of FEM sections %d for single mode\n",
+ fems_parsed);
+ return 1;
+ }
+ }
+ else if (single_dual == 1) {
+ if (fems_parsed < 2 && fems_parsed > 8) {
+ fprintf(stderr, "Incorrect number of FEM sections %d for dual mode\n",
+ fems_parsed);
+ return 1;
+ }
+ }
+ else {
+ fprintf(stderr, "Invalid value for TXBiPFEMAutoDetect %d\n",
+ single_dual);
+ return 1;
+ }
+
+ /* I suppose you can have one FEM with 2.4 only and one in dual band
+ but it's more likely a mistake.
+
+ In normal situation we have:
+ ----------------------------
+ Single Band Manual - 1 FEM
+ Dual Band Manual - 2 FEMs
+ Single Band Auto Fem - 4 FEMs
+ Dual Band Auto Fem - 8 FEMs */
+ if ((single_dual + 1) * (cmn.auto_fem * 3 + 1) != fems_parsed) {
+ printf("WARNING: %d FEMS for %d bands with autofem %s looks "
+ "like a strange configuration\n",
+ fems_parsed, single_dual + 1,
+ cmn.auto_fem ? "on" : "off");
+ }
+
+ cfg_nvs_ops(&cmn);
+
+ if (create_nvs_file(&cmn)) {
+ fprintf(stderr, "Failed to create reference NVS file\n");
+ return 1;
+ }
+
+ /* Load module */
+ res = insmod(modpath);
+ if (res) {
+ goto out_removenvs;
+ }
+
+ res = plt_do_power_on(state, devname);
+ if (res < 0)
+ goto out_rmmod;
+
+ res = plt_do_calibrate(state, cb, msg, single_dual,
+ cmn.nvs_name, devname, cmn.arch);
+ if (res) {
+ goto out_power_off;
+ }
+
+ set_mac_prms[0] = devname;
+ set_mac_prms[1] = "plt";
+ set_mac_prms[2] = "set_mac";
+ set_mac_prms[3] = cmn.nvs_name;
+ set_mac_prms[4] = macaddr;
+
+ res = handle_cmd(state, II_NETDEV,
+ ARRAY_SIZE(set_mac_prms) - (!macaddr),
+ set_mac_prms);
+ if (res) {
+ goto out_power_off;
+ }
+
+ /* we can ignore the return value, because we rmmod anyway */
+ plt_do_power_off(state, devname);
+ rmmod(modpath);
+
+ printf("Calibration done. ");
+ if (cmn.fem0_bands) {
+ printf("FEM0 has %d bands. ", cmn.fem0_bands);
+ }
+ if (cmn.fem1_bands) {
+ printf("FEM1 has %d bands. ", cmn.fem1_bands);
+ }
+ if (cmn.fem2_bands) {
+ printf("FEM2 has %d bands. ", cmn.fem2_bands);
+ }
+ if (cmn.fem3_bands) {
+ printf("FEM3 has %d bands. ", cmn.fem3_bands);
+ }
+
+ printf("AutoFEM is %s. ", cmn.auto_fem ? "on" : "off");
+
+ printf("Resulting nvs is %s\n",
+ cmn.nvs_name);
+ return 0;
+
+out_power_off:
+ /* we can ignore the return value, because we rmmod anyway */
+ plt_do_power_off(state, devname);
+out_rmmod:
+ rmmod(modpath);
+
+out_removenvs:
+ fprintf(stderr, "Calibration not complete. Removing half-baked nvs\n");
+ unlink(cmn.nvs_name);
+ return 0;
+
+}
+COMMAND(plt, autocalibrate, "<dev> <module path> <ini file1> <nvs file> "
+ "[<MAC address>|from_fuse|default]", 0, 0, CIB_NONE, plt_autocalibrate,
+ "Do automatic calibration.\n"
+ "The MAC address value can be:\n"
+ "from_fuse\ttry to read from the fuse ROM, if not available the command fails\n"
+ "default\t\twrite 00:00:00:00:00:00 to have the driver read from the fuse ROM,\n"
+ "\t\t\tfails if not available\n"
+ "00:00:00:00:00:00\tforce use of a zeroed MAC address (use with caution!)\n");
+
+static int plt_get_mac_cb(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
+ char *addr;
+ int lower;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_TESTDATA]) {
+ fprintf(stderr, "no data!\n");
+ return NL_SKIP;
+ }
+
+ nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
+ nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);
+
+ addr = (char *) nla_data(td[WL1271_TM_ATTR_DATA]);
+
+ printf("BD_ADDR from fuse:\t0x%0x:0x%0x:0x%0x:0x%0x:0x%0x:0x%0x\n",
+ addr[0], addr[1], addr[2],
+ addr[3], addr[4], addr[5]);
+
+ lower = (addr[3] << 16) + (addr[4] << 8) + addr[5];
+
+ lower++;
+ printf("First WLAN MAC:\t\t0x%0x:0x%0x:0x%0x:0x%0x:0x%0x:0x%0x\n",
+ addr[0], addr[1], addr[2],
+ (lower & 0xff0000) >> 16,
+ (lower & 0xff00) >> 8,
+ (lower & 0xff));
+
+ lower++;
+ printf("Second WLAN MAC:\t0x%0x:0x%0x:0x%0x:0x%0x:0x%0x:0x%0x\n",
+ addr[0], addr[1], addr[2],
+ (lower & 0xff0000) >> 16,
+ (lower & 0xff00) >> 8,
+ (lower & 0xff));
+
+ return NL_SKIP;
+}
+
+static int plt_get_mac_from_fuse(struct nl_msg *msg, struct nl_cb *cb,
+ nl_recvmsg_msg_cb_t callback, void *arg)
+{
+ struct nlattr *key;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "%s> fail to nla_nest_start()\n", __func__);
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_GET_MAC);
+
+ nla_nest_end(msg, key);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback, arg);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+static int plt_get_mac(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ if (argc != 0)
+ return 1;
+
+ return plt_get_mac_from_fuse(msg, cb, plt_get_mac_cb, NULL);
+}
+COMMAND(plt, get_mac, "",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_get_mac,
+ "Read MAC address from the Fuse ROM.\n");
+
+static int plt_set_mac_from_fuse_cb(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
+ char mac[sizeof(ZERO_MAC)];
+ char *addr;
+ char *nvs_file = (char *) arg;
+ int lower;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_TESTDATA]) {
+ fprintf(stderr, "no data!\n");
+ return NL_SKIP;
+ }
+
+ nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
+ nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);
+
+ addr = (char *) nla_data(td[WL1271_TM_ATTR_DATA]);
+
+ /*
+ * The first address is the BD_ADDR, the next is the first
+ * MAC. Increment only the lower part, so we don't overflow
+ * to the OUI */
+ lower = (addr[3] << 16) + (addr[4] << 8) + addr[5] + 1;
+
+ snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+ addr[0], addr[1], addr[2], (lower & 0xff0000) >> 16,
+ (lower & 0xff00) >> 8, (lower & 0xff));
+
+ /* ignore the return value, since a message was already printed out */
+ nvs_set_mac(nvs_file, mac);
+
+ return NL_SKIP;
+}
+
+static int plt_set_mac_default_cb(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ char *nvs_file = (char *) arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_TESTDATA]) {
+ fprintf(stderr, "no data!\n");
+ return NL_SKIP;
+ }
+
+ /*
+ * No need to parse, we just need to know if the command
+ * worked (ie. the hardware supports MAC from fuse) so the
+ * driver can fetch it by itself.
+ */
+
+ /* ignore the return value, since a message was already printed out */
+ nvs_set_mac(nvs_file, ZERO_MAC);
+
+ return NL_SKIP;
+}
+
+static int plt_set_mac_from_fuse(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ return plt_get_mac_from_fuse(msg, cb, plt_set_mac_from_fuse_cb, argv[0]);
+}
+HIDDEN(plt, set_mac_from_fuse, "<nvs file>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_set_mac_from_fuse);
+
+static int plt_set_mac_default(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ return plt_get_mac_from_fuse(msg, cb, plt_set_mac_default_cb, argv[0]);
+}
+HIDDEN(plt, set_mac_default, "<nvs file>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_set_mac_default);
+
+static int plt_set_mac(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ char *nvs_file;
+
+ if (argc < 4 || argc > 5)
+ return 1;
+
+ nvs_file = argv[3];
+
+ if (argc == 4 || !strcmp(argv[4], "default")) {
+ char *prms[] = { argv[0], argv[1], "set_mac_default",
+ nvs_file };
+
+ return handle_cmd(state, II_NETDEV, ARRAY_SIZE(prms), prms);
+ }
+
+ if (!strcmp(argv[4], "from_fuse")) {
+ char *prms[] = { argv[0], argv[1], "set_mac_from_fuse",
+ nvs_file };
+
+ return handle_cmd(state, II_NETDEV, ARRAY_SIZE(prms), prms);
+ }
+
+ if (nvs_set_mac(nvs_file, argv[4]) != 0)
+ return 1;
+
+ return 0;
+}
+COMMAND(plt, set_mac, "<nvs file> [<MAC address>|from_fuse|default]",
+ 0, 0, CIB_NETDEV, plt_set_mac,
+ "Set a MAC address to the NVS file.\n\n"
+ "<MAC address>\tspecific address to use (XX:XX:XX:XX:XX:XX)\n"
+ "from_fuse\ttry to read from the fuse ROM, if not available the command fails\n"
+ "default\t\twrite 00:00:00:00:00:00 to have the driver read from the fuse ROM,\n"
+ "\t\t\tfails if not available\n"
+ "00:00:00:00:00:00\tforce use of a zeroed MAC address (use with caution!)\n");
diff --git a/plt.h b/plt.h
new file mode 100644
index 0000000..8b534a9
--- /dev/null
+++ b/plt.h
@@ -0,0 +1,412 @@
+#ifndef __PLT_H
+#define __PLT_H
+
+#include <linux/ethtool.h>
+
+#ifdef ANDROID
+#define CURRENT_NVS_NAME "/system/etc/firmware/ti-connectivity/wl12xx-nvs.bin"
+#define INSMOD_PATH "/system/bin/insmod"
+#define RMMOD_PATH "/system/bin/rmmod"
+#else
+#define CURRENT_NVS_NAME "/lib/firmware/ti-connectivity/wl12xx-nvs.bin"
+#define INSMOD_PATH "/sbin/insmod"
+#define RMMOD_PATH "/sbin/rmmod"
+#endif
+#define NEW_NVS_NAME "./new-nvs.bin"
+#define NVS_FILE_SIZE_127X 0x390
+#define NVS_FILE_SIZE_128X 0x459
+
+/* NVS definition start here */
+
+#define NVS_TX_TYPE_INDEX 0
+
+#define START_TYPE_INDEX_IN_TLV 0
+#define TLV_TYPE_LENGTH 1
+#define START_LENGTH_INDEX \
+(START_TYPE_INDEX_IN_TLV + TLV_TYPE_LENGTH) /* 1 */
+#define TLV_LENGTH_LENGTH 2
+#define START_PARAM_INDEX \
+(START_LENGTH_INDEX + TLV_LENGTH_LENGTH) /* 3 */
+
+#define NVS_MAC_FIRST_LENGTH_INDEX 0
+#define NVS_MAC_FIRST_LENGHT_VALUE 1
+
+#define NVS_MAC_L_ADDRESS_INDEX \
+((NVS_MAC_FIRST_LENGTH_INDEX) + 1) /* 1*/
+#define NVS_MAC_L_ADDRESS_LENGTH 2
+
+#define NVS_MAC_L_VALUE_INDEX \
+((NVS_MAC_L_ADDRESS_INDEX) + (NVS_MAC_L_ADDRESS_LENGTH)) /* 3 */
+
+#define NVS_MAC_L_VALUE_LENGTH 4
+
+#define NVS_MAC_SECONDE_LENGTH_INDEX \
+((NVS_MAC_L_VALUE_INDEX) + 4) /* 7 */
+#define NVS_MAC_SECONDE_LENGHT_VALUE 1
+
+#define NVS_MAC_H_ADDRESS_INDEX \
+((NVS_MAC_SECONDE_LENGTH_INDEX) + 1) /* 8*/
+#define NVS_MAC_H_ADDRESS_LENGTH 2
+
+#define NVS_MAC_H_VALUE_INDEX \
+((NVS_MAC_H_ADDRESS_INDEX) + (NVS_MAC_H_ADDRESS_LENGTH)) /* 10 */
+#define NVS_MAC_H_VALUE_LENGTH 4
+
+#define NVS_END_BURST_TRANSACTION_INDEX \
+((NVS_MAC_H_VALUE_INDEX) + (NVS_MAC_H_VALUE_LENGTH)) /* 14 */
+#define NVS_END_BURST_TRANSACTION_VALUE 0
+#define NVS_END_BURST_TRANSACTION_LENGTH 7
+
+#define NVS_ALING_TLV_START_ADDRESS_INDEX \
+((NVS_END_BURST_TRANSACTION_INDEX) + \
+(NVS_END_BURST_TRANSACTION_LENGTH)) /* 21 */
+#define NVS_ALING_TLV_START_ADDRESS_VALUE 0
+#define NVS_ALING_TLV_START_ADDRESS_LENGTH 3
+
+
+/* NVS pre TLV length */
+#define NVS_PRE_PARAMETERS_LENGTH \
+((NVS_ALING_TLV_START_ADDRESS_INDEX) + \
+(NVS_ALING_TLV_START_ADDRESS_LENGTH)) /* 24 */
+
+/* NVS P2G table */
+#define NVS_TX_P2G_TABLE_LENGTH \
+((NUMBER_OF_SUB_BANDS_E) * 1 /* byte */) /* 8 */
+
+/* NVS PPA table */
+#define NVS_TX_PPA_STEPS_TABLE_LENGTH \
+((NUMBER_OF_SUB_BANDS_E) * ((TXPWR_CFG0__VGA_STEP__NUMBER_OF_STEPS_E) \
+- 1) * 1 /* byte */) /* 32 */
+
+/* NVS version 1 TX PD curve table length */
+#define NVS_TX_PD_TABLE_LENGTH_NVS_V1 (1 /* byte to set size of table */ + \
+((NUMBER_OF_SUB_BANDS_E) * (2 /* 1 byte offset, 1 byte low range */ + \
+2 /* first index in table */ + (((SIZE_OF_POWER_DETECTOR_TABLE) - 1) * \
+1 /* 1 byte */)))) /* 233 */
+
+/* NVS version 2 TX PD curve table length */
+#define NVS_TX_PD_TABLE_LENGTH_NVS_V2 \
+((NUMBER_OF_SUB_BANDS_E) * (12 /* 12index of one byte -2 dBm - 9dBm */ +\
+28 /* 14 indexes of 2 byte -3dBm, 10dBm - 22 dBm */)) /* 320 */
+
+/* NVS version 1 TX parameters Length */
+#define NVS_TX_PARAM_LENGTH_NVS_V1 \
+((NVS_TX_P2G_TABLE_LENGTH) + (NVS_TX_PPA_STEPS_TABLE_LENGTH) +\
+(NVS_TX_PD_TABLE_LENGTH_NVS_V1)) /* 273 */
+
+/* NVS version 2 TX parameters Length */
+#define NVS_TX_PARAM_LENGTH_NVS_V2 \
+((NVS_TX_P2G_TABLE_LENGTH) + (NVS_TX_PPA_STEPS_TABLE_LENGTH) +\
+(NVS_TX_PD_TABLE_LENGTH_NVS_V2) +\
+(NUMBER_OF_RADIO_CHANNEL_INDEXS_E /* for Per Channel power Gain Offset tabl */))
+
+/* NVS TX version */
+/* #define NVS_TX_PARAM_LENGTH NVS_TX_PARAM_LENGTH_NVS_V2 */
+#define NVS_TX_PARAM_LENGTH 0x199
+
+/* NVS RX version */
+#define NVS_RX_PARAM_LENGTH NUMBER_OF_RX_BIP_EFUSE_PARAMETERS_E /* 19 */
+
+/* NVS version parameter length */
+#define NVS_VERSION_PARAMETER_LENGTH 3
+
+/* NVS max length */
+/* original ((NVS_TOTAL_LENGTH) + 4 - ((NVS_TOTAL_LENGTH) % 4)) */
+#define NVS_TOTAL_LENGTH 500
+
+/* TLV max length */
+#define MAX_TLV_LENGTH NVS_TOTAL_LENGTH
+
+#define MAX_NVS_VERSION_LENGTH 12
+
+enum wl1271_tm_commands {
+ WL1271_TM_CMD_UNSPEC,
+ WL1271_TM_CMD_TEST,
+ WL1271_TM_CMD_INTERROGATE,
+ WL1271_TM_CMD_CONFIGURE,
+ WL1271_TM_CMD_NVS_PUSH,
+ WL1271_TM_CMD_SET_PLT_MODE,
+ WL1271_TM_CMD_RECOVER,
+ WL1271_TM_CMD_GET_MAC,
+
+ __WL1271_TM_CMD_AFTER_LAST
+};
+
+enum wl1271_tm_attrs {
+ WL1271_TM_ATTR_UNSPEC,
+ WL1271_TM_ATTR_CMD_ID,
+ WL1271_TM_ATTR_ANSWER,
+ WL1271_TM_ATTR_DATA,
+ WL1271_TM_ATTR_IE_ID,
+ WL1271_TM_ATTR_PLT_MODE,
+ __WL1271_TM_ATTR_AFTER_LAST
+};
+
+#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1)
+
+enum wl1271_test_cmds {
+ TEST_CMD_PD_BUFFER_CAL = 0x1, /* TX PLT */
+ TEST_CMD_P2G_CAL, /* TX BiP */
+ TEST_CMD_RX_PLT_ENTER,
+ TEST_CMD_RX_PLT_CAL, /* RSSI Cal */
+ TEST_CMD_RX_PLT_EXIT,
+ TEST_CMD_RX_PLT_GET,
+ TEST_CMD_FCC, /* Continuous TX */
+ TEST_CMD_TELEC, /* Carrier wave in a specific channel and band */
+ TEST_CMD_STOP_TX, /* Stop FCC or TELEC */
+ TEST_CMD_PLT_TEMPLATE, /* define Template for TX */
+ TEST_CMD_PLT_GAIN_ADJUST,
+ TEST_CMD_PLT_GAIN_GET,
+ TEST_CMD_CHANNEL_TUNE,
+ TEST_CMD_FREE_RUN_RSSI, /* Free running RSSI measurement */
+ TEST_CMD_DEBUG, /* test command for debug using the struct: */
+ TEST_CMD_CLPC_COMMANDS,
+ RESERVED_4,
+ TEST_CMD_RX_STAT_STOP,
+ TEST_CMD_RX_STAT_START,
+ TEST_CMD_RX_STAT_RESET,
+ TEST_CMD_RX_STAT_GET,
+ TEST_CMD_LOOPBACK_START, /* for FW Test Debug */
+ TEST_CMD_LOOPBACK_STOP, /* for FW Test Debug */
+ TEST_CMD_GET_FW_VERSIONS,
+ TEST_CMD_INI_FILE_RADIO_PARAM,
+ TEST_CMD_RUN_CALIBRATION_TYPE,
+ TEST_CMD_TX_GAIN_ADJUST,
+ TEST_CMD_UPDATE_PD_BUFFER_ERRORS,
+ TEST_CMD_UPDATE_PD_REFERENCE_POINT,
+ TEST_CMD_INI_FILE_GENERAL_PARAM,
+ TEST_CMD_SET_EFUSE,
+ TEST_CMD_GET_EFUSE,
+ TEST_CMD_TEST_TONE,
+ TEST_CMD_POWER_MODE,
+ TEST_CMD_SMART_REFLEX,
+ TEST_CMD_CHANNEL_RESPONSE,
+ TEST_CMD_DCO_ITRIM_FEATURE,
+ TEST_CMD_INI_FILE_RF_EXTENDED_PARAM, /* !!! Not exists in 128x */
+ TEST_CMD_SET_NVS_VERSION, /* For wl128x, the value is minus 1 */
+ MAX_TEST_CMD_ID = 0xFF
+};
+
+enum plt_mode {
+ PLT_OFF = 0,
+ PLT_ON = 1,
+ PLT_FEM_DETECT = 2,
+ PLT_CHIP_AWAKE = 3,
+};
+
+struct wl1271_cmd_header {
+ __u16 id;
+ __u16 status;
+ /* payload */
+ unsigned char data[0];
+} __attribute__((packed));
+
+struct wl1271_cmd_test_header {
+ unsigned char id;
+ unsigned char padding[3];
+} __attribute__((packed));
+
+struct wl1271_cmd_cal_channel_tune {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ unsigned char band;
+ unsigned char channel;
+
+ __le16 radio_status;
+} __attribute__((packed));
+
+struct wl1271_cmd_cal_update_ref_point {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ __le32 ref_power;
+ __le32 ref_detector;
+ unsigned char sub_band;
+ unsigned char padding[3];
+} __attribute__((packed));
+
+struct wl1271_cmd_cal_tx_tone {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ __le16 radio_status;
+ unsigned char padding[2];
+ __le32 power;
+ unsigned char tone_type;
+ unsigned char unused[11];
+} __attribute__((packed));
+
+#define NVS_VERSION_2 2
+#define NVS_VERSION_2_1 21
+
+struct wl1271_cmd_set_nvs_ver {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ __le16 radio_status;
+
+ unsigned char nvs_ver;
+ unsigned char padding;
+} __attribute__((packed));
+
+struct wl1271_cmd_cal_p2g {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ __le32 ver;
+ __le16 len;
+ unsigned char buf[MAX_TLV_LENGTH];
+ unsigned char type;
+ unsigned char padding;
+
+ __le16 radio_status;
+
+ unsigned char sub_band_mask;
+ unsigned char padding2;
+} __attribute__((packed));
+
+#define MAC_ADDR_LEN 6
+
+struct wl1271_cmd_pkt_params {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ __le16 radio_status;
+ unsigned char padding[2];
+ __le32 delay;
+ __le32 rate;
+ __le16 size;
+ __le16 amount;
+ __le32 power;
+ __le16 seed;
+ unsigned char pkt_mode;
+ unsigned char dcf_enable;
+ unsigned char g_interval;
+ unsigned char preamble;
+ unsigned char type;
+ unsigned char scramble;
+ unsigned char clpc_enable;
+ unsigned char seq_nbr_mode;
+ unsigned char src_mac[MAC_ADDR_LEN];
+ unsigned char dst_mac[MAC_ADDR_LEN];
+ unsigned char padding1[2];
+} __attribute__((packed));
+
+struct wl1271_rx_path_statcs {
+ __le32 nbr_rx_valid_pkts;
+ __le32 nbr_rx_fcs_err_pkts;
+ __le32 nbr_rx_plcp_err_pkts;
+ __le32 seq_nbr_miss_cnt; /* For PER calculation */
+ __le16 ave_snr; /* average SNR */
+ __le16 ave_rssi; /* average RSSI */
+ __le16 ave_evm;
+ unsigned char padding[2];
+} __attribute__((packed));
+
+struct wl1271_rx_pkt_statcs {
+ __le32 length;
+ __le32 evm;
+ __le32 rssi;
+ __le16 freq_delta;
+ __le16 flags;
+ char type;
+ unsigned char rate;
+ unsigned char noise;
+ unsigned char agc_gain;
+ unsigned char padding[2];
+} __attribute__((packed));
+
+#define RX_STAT_PACKETS_PER_MESSAGE (20)
+
+struct wl1271_radio_rx_statcs {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ struct wl1271_rx_path_statcs rx_path_statcs;
+ __le32 base_pkt_id;
+ __le32 nbr_pkts; /* input/output: number of following packets */
+ __le32 nbr_miss_pkts;
+ __le16 radio_status;
+ unsigned char padding[2];
+} __attribute__((packed));
+
+struct fw_version {
+ int ver[5];
+} __attribute__((packed));
+
+enum wl1271_nvs_type {
+ eNVS_VERSION = 0xaa,
+ eNVS_RADIO_TX_PARAMETERS = 1,
+ eNVS_RADIO_RX_PARAMETERS = 2,
+ eNVS_RADIO_INI = 16,
+ eNVS_NON_FILE = 0xFE,
+ eTLV_LAST = 0xFF /* last TLV type */
+};
+
+#define DEFAULT_EFUSE_VALUE (0)
+
+enum wl1271_nvs_type_info {
+ eFIRST_RADIO_TYPE_PARAMETERS_INFO,
+ eNVS_RADIO_TX_TYPE_PARAMETERS_INFO = eFIRST_RADIO_TYPE_PARAMETERS_INFO,
+ eNVS_RADIO_RX_TYPE_PARAMETERS_INFO,
+ eLAST_RADIO_TYPE_PARAMETERS_INFO = eNVS_RADIO_RX_TYPE_PARAMETERS_INFO,
+ UNUSED_RADIO_TYPE_PARAMETERS_INFO,
+ eNUMBER_RADIO_TYPE_PARAMETERS_INFO = UNUSED_RADIO_TYPE_PARAMETERS_INFO,
+ LAST_RADIO_TYPE_PARAMETERS_INFO =
+ (eNUMBER_RADIO_TYPE_PARAMETERS_INFO - 1)
+};
+
+enum EFUSE_PARAMETER_TYPE_ENMT {
+ EFUSE_FIRST_PARAMETER_E,
+ /* RX PARAMETERS */
+ EFUSE_FIRST_RX_PARAMETER_E = EFUSE_FIRST_PARAMETER_E,
+ RX_BIP_MAX_GAIN_ERROR_BAND_B_E = EFUSE_FIRST_RX_PARAMETER_E,
+
+ RX_BIP_MAX_GAIN_ERROR_J_LOW_MID_E,
+ RX_BIP_MAX_GAIN_ERROR_J_HIGH_E,
+
+ RX_BIP_MAX_GAIN_ERROR_5G_1ST_E,
+ RX_BIP_MAX_GAIN_ERROR_5G_2ND_E,
+ RX_BIP_MAX_GAIN_ERROR_5G_3RD_E,
+ RX_BIP_MAX_GAIN_ERROR_5G_4TH_E,
+
+ RX_BIP_LNA_STEP_CORR_BAND_B_4TO3_E,
+ RX_BIP_LNA_STEP_CORR_BAND_B_3TO2_E,
+ RX_BIP_LNA_STEP_CORR_BAND_B_2TO1_E,
+ RX_BIP_LNA_STEP_CORR_BAND_B_1TO0_E,
+
+ RX_BIP_LNA_STEP_CORR_BAND_A_4TO3_E,
+ RX_BIP_LNA_STEP_CORR_BAND_A_3TO2_E,
+ RX_BIP_LNA_STEP_CORR_BAND_A_2TO1_E,
+ RX_BIP_LNA_STEP_CORR_BAND_A_1TO0_E,
+
+ RX_BIP_TA_STEP_CORR_BAND_B_2TO1_E,
+ RX_BIP_TA_STEP_CORR_BAND_B_1TO0_E,
+ RX_BIP_TA_STEP_CORR_BAND_A_2TO1_E,
+ RX_BIP_TA_STEP_CORR_BAND_A_1TO0_E,
+ NUMBER_OF_RX_BIP_EFUSE_PARAMETERS_E,
+
+ /* TX PARAMETERS */
+ TX_BIP_PD_BUFFER_GAIN_ERROR_E = NUMBER_OF_RX_BIP_EFUSE_PARAMETERS_E,
+ TX_BIP_PD_BUFFER_VBIAS_ERROR_E,
+ EFUSE_NUMBER_OF_PARAMETERS_E,
+ EFUSE_LAST_PARAMETER_E = (EFUSE_NUMBER_OF_PARAMETERS_E - 1)
+} EFUSE_PARAMETER_TYPE_ENM;
+
+int get_mac_addr(int ifc_num, unsigned char *mac_addr);
+
+int file_exist(const char *filename);
+int do_get_drv_info(char *dev_name, int *hw_ver,
+ struct ethtool_drvinfo *out_drvinfo);
+int is_fw_ver_valid(char *dev_name, struct fw_version *fw_ver_valid);
+
+
+#endif /* __PLT_H */
diff --git a/uim_rfkill/readme.txt b/uim_rfkill/readme.txt
new file mode 100644
index 0000000..9d108a3
--- /dev/null
+++ b/uim_rfkill/readme.txt
@@ -0,0 +1,25 @@
+This is UIM utility required for TI's shared transport driver in order
+to open UART and to deliver the control of it to the driver.
+
+The author of the utility is Pavan Savoy <pavan_savoy@ti.com>
+
+--- Running UIM utility
+
+It needs to be run at boot, Since linux flavors might require Bluetooth or
+GPS to be turned on at boot. For this have the UIM entry in your either one
+of your rc.S files or you can have special udev rule based on the platform
+driver addition of device "kim".
+
+For Android, the following entry in init.rc should suffice,
+service uim /system/bin/uim-sysfs
+ user root
+ group media bluetooth
+ oneshot
+[edit]
+
+For Angstrom, the following command should be done,
+./uim /dev/ttyO1 3686400 none 22 &
+
+--- Building UIM utility
+make uim
+
diff --git a/uim_rfkill/uim.c b/uim_rfkill/uim.c
new file mode 100644
index 0000000..9fd42bf
--- /dev/null
+++ b/uim_rfkill/uim.c
@@ -0,0 +1,924 @@
+/*
+ * User Mode Init manager - For TI shared transport
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <poll.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#ifdef ANDROID
+#include <private/android_filesystem_config.h>
+#include <cutils/log.h>
+#endif
+
+#ifdef ANDROID
+#include <common/ppoll.h> /* for ppoll */
+#endif
+#include "uim.h"
+
+#ifndef ANDROID
+#define INCLUDE_FM 0
+#endif
+
+/* Maintains the exit state of UIM*/
+static int exiting;
+
+/* UART configuration parameters*/
+int uart_flow_control;
+int cust_baud_rate;
+char uart_dev_name[15];
+unsigned int uart_baud_rate;
+struct termios ti;
+int line_discipline;
+
+/* BD address as string and a pointer to array of hex bytes */
+char uim_bd_address[17];
+bdaddr_t *bd_addr;
+
+/* File descriptor for the UART device*/
+int dev_fd;
+
+/* Maintains the state of N_TI_WL line discipline installation*/
+unsigned char st_state = UNINSTALL_N_TI_WL;
+unsigned char prev_st_state = UNINSTALL_N_TI_WL;
+
+/* from kernel's include/linux/rfkill.h
+ * the header in itself not included because of the
+ * version mismatch of android kernel headers project
+ */
+
+/**
+ * enum rfkill_operation - operation types
+ * @RFKILL_OP_ADD: a device was added
+ * @RFKILL_OP_DEL: a device was removed
+ * @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device
+ * @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all)
+ */
+enum rfkill_operation {
+ RFKILL_OP_ADD = 0,
+ RFKILL_OP_DEL,
+ RFKILL_OP_CHANGE,
+ RFKILL_OP_CHANGE_ALL,
+};
+
+/**
+ * struct rfkill_event - events for userspace on /dev/rfkill
+ * @idx: index of dev rfkill
+ * @type: type of the rfkill struct
+ * @op: operation code
+ * @hard: hard state (0/1)
+ * @soft: soft state (0/1)
+ *
+ * Structure used for userspace communication on /dev/rfkill,
+ * used for events from the kernel and control to the kernel.
+ */
+#ifdef ANDROID
+struct rfkill_event {
+ __u32 idx;
+ __u8 type;
+ __u8 op;
+ __u8 soft, hard;
+} __packed;
+#else
+struct rfkill_event {
+ uint32_t idx;
+ uint8_t type;
+ uint8_t op;
+ uint8_t soft, hard;
+} __packed;
+#endif /* ANDROID */
+
+/* to read events and filter notifications for us */
+struct rfkill_event rf_event;
+unsigned int rfkill_idx;
+
+/*****************************************************************************/
+#ifdef UIM_DEBUG
+/* Function to Read the firmware version
+ * module into the system. Currently used for
+ * debugging purpose, whenever the baud rate is changed
+ */
+void read_firmware_version()
+{
+ int index = 0;
+ char resp_buffer[20] = { 0 };
+ unsigned char buffer[] = { 0x01, 0x01, 0x10, 0x00 };
+
+ UIM_START_FUNC();
+ UIM_VER(" wrote %d bytes", (int)write(dev_fd, buffer, 4));
+ UIM_VER(" reading %d bytes", (int)read(dev_fd, resp_buffer, 15));
+
+ for (index = 0; index < 15; index++)
+ UIM_VER(" %x ", resp_buffer[index]);
+
+ printf("\n");
+}
+#endif
+
+/*****************************************************************************/
+#ifdef ANDROID /* library for android to do insmod/rmmod */
+
+/* Function to insert the kernel module into the system*/
+static int insmod(const char *filename, const char *args)
+{
+ void *module;
+ unsigned int size;
+ int ret = -1;
+
+ UIM_START_FUNC();
+
+ module = (void *)load_file(filename, &size);
+ if (!module)
+ return ret;
+
+ ret = init_module(module, size, args);
+ free(module);
+
+ return ret;
+}
+
+/* Function to remove the kernel module from the system*/
+static int rmmod(const char *modname)
+{
+ int ret = -1;
+ int maxtry = MAX_TRY;
+
+ UIM_START_FUNC();
+
+ /* Retry MAX_TRY number of times in case of
+ * failure
+ */
+ while (maxtry-- > 0) {
+ ret = delete_module(modname, O_NONBLOCK | O_EXCL);
+ if (ret < 0 && errno == EAGAIN)
+ sleep(1);
+ else
+ break;
+ }
+
+ /* Failed to remove the module
+ */
+ if (ret != 0)
+ UIM_ERR("Unable to unload driver module \"%s\": %s",
+ modname, strerror(errno));
+ return ret;
+}
+#endif /*ANDROID*/
+
+/*****************************************************************************/
+/* Function to read the HCI event from the given file descriptor
+ *
+ * This will parse the response received and returns error
+ * if the required response is not received
+ */
+int read_hci_event(int fd, unsigned char *buf, int size)
+{
+ int remain, rd;
+ int count = 0;
+ int reading = 1;
+ int rd_retry_count = 0;
+ struct timespec tm = {0, 50*1000*1000};
+
+ UIM_START_FUNC();
+
+ UIM_VER(" read_hci_event");
+ if (size <= 0)
+ return -1;
+
+ /* The first byte identifies the packet type. For HCI event packets, it
+ * should be 0x04, so we read until we get to the 0x04. */
+ while (reading) {
+ rd = read(fd, buf, 1);
+ if (rd <= 0 && rd_retry_count++ < 4) {
+ nanosleep(&tm, NULL);
+ continue;
+ } else if (rd_retry_count >= 4) {
+ return -1;
+ }
+
+ if (buf[0] == RESP_PREFIX) {
+ break;
+ }
+ }
+ count++;
+
+ /* The next two bytes are the event code and parameter total length. */
+ while (count < 3) {
+ rd = read(fd, buf + count, 3 - count);
+ if (rd <= 0)
+ return -1;
+ count += rd;
+ }
+
+ /* Now we read the parameters. */
+ if (buf[2] < (size - 3))
+ remain = buf[2];
+ else
+ remain = size - 3;
+
+ while ((count - 3) < remain) {
+ rd = read(fd, buf + count, remain - (count - 3));
+ if (rd <= 0)
+ return -1;
+ count += rd;
+ }
+
+ return count;
+}
+
+/* Function to read the Command complete event
+ *
+ * This will read the response for the change speed
+ * command that was sent to configure the UART speed
+ * with the custom baud rate
+ */
+static int read_command_complete(int fd, unsigned short opcode)
+{
+ command_complete_t resp;
+
+ UIM_START_FUNC();
+
+ UIM_VER(" Command complete started");
+ if (read_hci_event(fd, (unsigned char *)&resp, sizeof(resp)) < 0) {
+ UIM_ERR(" Invalid response");
+ return -1;
+ }
+
+ /* Response should be an event packet */
+ if (resp.uart_prefix != HCI_EVENT_PKT) {
+ UIM_ERR
+ (" Error in response: not an event packet, but 0x%02x!",
+ resp.uart_prefix);
+ return -1;
+ }
+
+ /* Response should be a command complete event */
+ if (resp.hci_hdr.evt != EVT_CMD_COMPLETE) {
+ /* event must be event-complete */
+ UIM_ERR
+ (" Error in response: not a cmd-complete event,but 0x%02x!",
+ resp.hci_hdr.evt);
+ return -1;
+ }
+
+ if (resp.hci_hdr.plen < 4) {
+ /* plen >= 4 for EVT_CMD_COMPLETE */
+ UIM_ERR(" Error in response: plen is not >= 4, but 0x%02x!",
+ resp.hci_hdr.plen);
+ return -1;
+ }
+
+ if (resp.cmd_complete.opcode != (unsigned short)opcode) {
+ UIM_ERR(" Error in response: opcode is 0x%04x, not 0x%04x!",
+ resp.cmd_complete.opcode, opcode);
+ return -1;
+ }
+
+ UIM_DBG(" Command complete done");
+ return resp.status == 0 ? 0 : -1;
+}
+
+/* Function to set the default baud rate
+ *
+ * The default baud rate of 115200 is set to the UART from the host side
+ * by making a call to this function.This function is also called before
+ * making a call to set the custom baud rate
+ */
+static int set_baud_rate()
+{
+ UIM_START_FUNC();
+
+ tcflush(dev_fd, TCIOFLUSH);
+
+ /* Get the attributes of UART */
+ if (tcgetattr(dev_fd, &ti) < 0) {
+ UIM_ERR(" Can't get port settings");
+ return -1;
+ }
+
+ /* Change the UART attributes before
+ * setting the default baud rate*/
+ cfmakeraw(&ti);
+
+ ti.c_cflag |= 1;
+ ti.c_cflag |= CRTSCTS;
+
+ /* Set the attributes of UART after making
+ * the above changes
+ */
+ tcsetattr(dev_fd, TCSANOW, &ti);
+
+ /* Set the actual default baud rate */
+ cfsetospeed(&ti, B115200);
+ cfsetispeed(&ti, B115200);
+ tcsetattr(dev_fd, TCSANOW, &ti);
+
+ tcflush(dev_fd, TCIOFLUSH);
+ UIM_DBG(" set_baud_rate() done");
+
+ return 0;
+}
+
+/* Function to set the UART custom baud rate.
+ *
+ * The UART baud rate has already been
+ * set to default value 115200 before calling this function.
+ * The baud rate is then changed to custom baud rate by this function*/
+static int set_custom_baud_rate()
+{
+ UIM_START_FUNC();
+
+ struct termios2 ti2;
+
+ UIM_VER(" Changing baud rate to %u, flow control to %u",
+ cust_baud_rate, uart_flow_control);
+
+ /* Flush non-transmitted output data,
+ * non-read input data or both*/
+ tcflush(dev_fd, TCIOFLUSH);
+
+ /*Set the UART flow control */
+ if (uart_flow_control)
+ ti.c_cflag |= CRTSCTS;
+ else
+ ti.c_cflag &= ~CRTSCTS;
+
+ /*
+ * Set the parameters associated with the UART
+ * The change will occur immediately by using TCSANOW
+ */
+ if (tcsetattr(dev_fd, TCSANOW, &ti) < 0) {
+ UIM_ERR(" Can't set port settings");
+ return -1;
+ }
+
+ tcflush(dev_fd, TCIOFLUSH);
+
+ /*Set the actual baud rate */
+ ioctl(dev_fd, TCGETS2, &ti2);
+ ti2.c_cflag &= ~CBAUD;
+ ti2.c_cflag |= BOTHER;
+ ti2.c_ospeed = cust_baud_rate;
+ ioctl(dev_fd, TCSETS2, &ti2);
+
+ UIM_DBG(" set_custom_baud_rate() done");
+ return 0;
+}
+
+/*
+ * Handling the Signals sent from the Kernel Init Manager.
+ * After receiving the signals, configure the baud rate, flow
+ * control and Install the N_TI_WL line discipline
+ */
+int st_sig_handler(int signo)
+{
+ int ldisc, len;
+ uim_speed_change_cmd cmd;
+
+ uim_bdaddr_change_cmd addr_cmd;
+
+ UIM_START_FUNC();
+
+ /* Raise a signal after when UIM is killed.
+ * This will exit UIM, and remove the inserted kernel
+ * modules
+ */
+ if (signo == SIGINT) {
+ UIM_DBG(" Exiting. . .");
+ exiting = 1;
+ return -1;
+ }
+
+ /* Install the line discipline when the signal is received by UIM.
+ * Whenever the first protocol tries to register with the ST core, the
+ * ST KIM will send a signal SIGUSR2 to the UIM to install the N_TI_WL
+ * line discipline and do the host side UART configurations.
+ *
+ * On failure, ST KIM's line discipline installation times out, and the
+ * relevant protocol register fails
+ */
+ if (st_state == INSTALL_N_TI_WL) {
+ UIM_VER(" signal received, opening %s", uart_dev_name);
+ dev_fd = open(uart_dev_name, O_RDWR);
+ if (dev_fd < 0) {
+ UIM_ERR(" Can't open %s", uart_dev_name);
+ return -1;
+ }
+ /*
+ * Set only the default baud rate.
+ * This will set the baud rate to default 115200
+ */
+ if (set_baud_rate() < 0) {
+ UIM_ERR(" set_baudrate() failed");
+ close(dev_fd);
+ return -1;
+ }
+
+ fcntl(dev_fd, F_SETFL,fcntl(dev_fd, F_GETFL) | O_NONBLOCK);
+ /* Set only thecustom baud rate */
+ if (cust_baud_rate) {
+
+ /* Forming the packet for Change speed command */
+ cmd.uart_prefix = HCI_COMMAND_PKT;
+ cmd.hci_hdr.opcode = HCI_HDR_OPCODE;
+ cmd.hci_hdr.plen = sizeof(unsigned long);
+ cmd.speed = cust_baud_rate;
+
+ /* Writing the change speed command to the UART
+ * This will change the UART speed at the controller
+ * side
+ */
+ UIM_VER(" Setting speed to %d", cust_baud_rate);
+ len = write(dev_fd, &cmd, sizeof(cmd));
+ if (len < 0) {
+ UIM_ERR(" Failed to write speed-set command");
+ close(dev_fd);
+ return -1;
+ }
+
+ /* Read the response for the Change speed command */
+ if (read_command_complete(dev_fd, HCI_HDR_OPCODE) < 0) {
+ close(dev_fd);
+ return -1;
+ }
+
+ UIM_VER(" Speed changed to %d", cust_baud_rate);
+
+ /* Set the actual custom baud rate at the host side */
+ if (set_custom_baud_rate() < 0) {
+ UIM_ERR(" set_custom_baud_rate() failed");
+ close(dev_fd);
+
+ return -1;
+ }
+
+ /* Set the uim BD address */
+ if (uim_bd_address[0] != 0) {
+
+ memset(&addr_cmd, 0, sizeof(addr_cmd));
+ /* Forming the packet for change BD address command*/
+ addr_cmd.uart_prefix = HCI_COMMAND_PKT;
+ addr_cmd.hci_hdr.opcode = WRITE_BD_ADDR_OPCODE;
+ addr_cmd.hci_hdr.plen = sizeof(bdaddr_t);
+ memcpy(&addr_cmd.addr, bd_addr, sizeof(bdaddr_t));
+
+ /* Writing the change BD address command to the UART
+ * This will change the change BD address at the controller
+ * side
+ */
+ len = write(dev_fd, &addr_cmd, sizeof(addr_cmd));
+ if (len < 0) {
+ UIM_ERR(" Failed to write BD address command");
+ close(dev_fd);
+ return -1;
+ }
+
+ /* Read the response for the change BD address command */
+ if (read_command_complete(dev_fd, WRITE_BD_ADDR_OPCODE) < 0) {
+ close(dev_fd);
+ return -1;
+ }
+
+ UIM_VER(" BD address changed to %s", uim_bd_address);
+ }
+#ifdef UIM_DEBUG
+ read_firmware_version();
+#endif
+ }
+
+ /* After the UART speed has been changed, the IOCTL is
+ * is called to set the line discipline to N_TI_WL
+ */
+ ldisc = line_discipline;
+ if (ioctl(dev_fd, TIOCSETD, &ldisc) < 0) {
+ UIM_ERR(" Can't set line discipline");
+ close(dev_fd);
+ return -1;
+ }
+
+ UIM_DBG(" Installed N_TI_WL Line displine");
+ }
+ else {
+ UIM_DBG(" Un-Installed N_TI_WL Line displine");
+ /* UNINSTALL_N_TI_WL - When the Signal is received from KIM */
+ /* closing UART fd */
+ close(dev_fd);
+ }
+ prev_st_state = st_state;
+ return 0;
+}
+int remove_modules()
+{
+ int err = 0;
+
+#ifdef ANDROID
+ UIM_VER(" Removing gps_drv ");
+ if (rmmod("gps_drv") != 0) {
+ UIM_ERR(" Error removing gps_drv module");
+ err = -1;
+ } else {
+ UIM_DBG(" Removed gps_drv module");
+ }
+
+ UIM_VER(" Removing fm_drv ");
+ if (rmmod("fm_drv") != 0) {
+ UIM_ERR(" Error removing fm_drv module");
+ err = -1;
+ } else {
+ UIM_DBG(" Removed fm_drv module");
+ }
+ UIM_DBG(" Removed fm_drv module");
+
+ UIM_VER(" Removing bt_drv ");
+
+ if (rmmod("bt_drv") != 0) {
+ UIM_ERR(" Error removing bt_drv module");
+ err = -1;
+ } else {
+ UIM_DBG(" Removed bt_drv module");
+ }
+ UIM_DBG(" Removed bt_drv module");
+
+ /*Remove the Shared Transport */
+ UIM_VER(" Removing st_drv ");
+
+ if (rmmod("st_drv") != 0) {
+ UIM_ERR(" Error removing st_drv module");
+ err = -1;
+ } else {
+ UIM_DBG(" Removed st_drv module ");
+ }
+ UIM_DBG(" Removed st_drv module ");
+#else
+#if INCLUDE_FM
+ UIM_VER(" Removing fm_drv ");
+ if (system("rmmod fm_drv") != 0) {
+ UIM_ERR(" Error removing fm_drv module");
+ err = -1;
+ } else {
+ UIM_DBG(" Removed fm_drv module");
+ }
+#endif /* INCLUDE_FM */
+ UIM_VER(" Removing bt_drv ");
+ if (system("rmmod bt_drv") != 0) {
+ UIM_ERR(" Error removing bt_drv module");
+ err = -1;
+ } else {
+ UIM_DBG(" Removed bt_drv module");
+ }
+
+ /*Remove the Shared Transport */
+ UIM_VER(" Removing st_drv ");
+
+ if (system("rmmod st_drv") != 0) {
+ UIM_ERR(" Error removing st_drv module");
+ err = -1;
+ } else {
+ UIM_DBG(" Removed st_drv module ");
+ }
+#endif
+ return err;
+}
+
+int change_rfkill_perms(void)
+{
+ int fd, id, sz;
+ char path[64];
+ char buf[16];
+ for (id = 0; id < 50; id++) {
+ snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ UIM_DBG("open(%s) failed: %s (%d)\n", path, strerror(errno), errno);
+ continue;
+ }
+ sz = read(fd, &buf, sizeof(buf));
+ close(fd);
+ if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0) {
+ UIM_DBG("found bluetooth rfkill entry @ %d\n", id);
+ rfkill_idx = id;
+ break;
+ }
+ }
+ if (id == 50) {
+ return -1;
+ }
+#ifdef ANDROID
+ sprintf(path, "/sys/class/rfkill/rfkill%d/state", id);
+ sz = chown(path, AID_BLUETOOTH, AID_BLUETOOTH);
+ if (sz < 0) {
+ UIM_ERR("change mode failed for %s (%d)\n", path, errno);
+ return -1;
+ }
+#endif /* ANDROID */
+ /*
+ * bluetooth group's user system needs write permission
+ */
+ sz = chmod(path, 0660);
+ if (sz < 0) {
+ UIM_ERR("change mode failed for %s (%d)\n", path, errno);
+ return -1;
+ }
+ UIM_DBG("changed permissions for %s(%d) \n", path, sz);
+ /* end of change_perms */
+
+ return 0;
+}
+
+void *bt_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+/* Function to convert the BD address from ascii to hex value */
+bdaddr_t *strtoba(const char *str)
+{
+ const char *ptr = str;
+ int i;
+
+ uint8_t *ba = bt_malloc(sizeof(bdaddr_t));
+ if (!ba)
+ return NULL;
+
+ for (i = 0; i < 6; i++) {
+ ba[i] = (uint8_t) strtol(ptr, NULL, 16);
+ if (i != 5 && !(ptr = strchr(ptr, ':')))
+ ptr = ":00:00:00:00:00";
+ ptr++;
+ }
+
+ return (bdaddr_t *) ba;
+}
+
+/*****************************************************************************/
+int main(int argc, char *argv[])
+{
+ int st_fd,err;
+ struct stat file_stat;
+#ifndef ANDROID /* used on ubuntu */
+ char *tist_ko_path;
+ struct utsname name;
+#endif
+ struct pollfd p;
+ sigset_t sigs;
+
+ UIM_START_FUNC();
+ err = 0;
+
+ /* Parse the user input */
+ if ((argc == 5) || (argc == 6)) {
+ strcpy(uart_dev_name, argv[1]);
+ uart_baud_rate = atoi(argv[2]);
+ uart_flow_control = atoi(argv[3]);
+ line_discipline = atoi(argv[4]);
+
+ /* Depending upon the baud rate value, differentiate
+ * the custom baud rate and default baud rate
+ */
+ switch (uart_baud_rate) {
+ case 115200:
+ UIM_VER(" Baudrate 115200");
+ break;
+ case 9600:
+ case 19200:
+ case 38400:
+ case 57600:
+ case 230400:
+ case 460800:
+ case 500000:
+ case 576000:
+ case 921600:
+ case 1000000:
+ case 1152000:
+ case 1500000:
+ case 2000000:
+ case 2500000:
+ case 3000000:
+ case 3500000:
+ case 3686400:
+ case 4000000:
+ cust_baud_rate = uart_baud_rate;
+ UIM_VER(" Baudrate %d", cust_baud_rate);
+ break;
+ default:
+ UIM_ERR(" Inavalid Baud Rate");
+ break;
+ }
+
+ memset(&uim_bd_address, 0, sizeof(uim_bd_address));
+ } else {
+ UIM_ERR(" Invalid arguements");
+ UIM_ERR(" Usage: uim [Uart device] [Baud rate] [Flow control] [Line discipline] <bd address>");
+ return -1;
+ }
+ if (argc == 6) {
+ /* BD address passed as string in xx:xx:xx:xx:xx:xx format */
+ strcpy(uim_bd_address, argv[5]);
+ bd_addr = strtoba(uim_bd_address);
+ }
+
+
+#ifndef ANDROID
+ if (uname (&name) == -1) {
+ UIM_ERR("cannot get kernel release name");
+ return -1;
+ }
+#else /* if ANDROID */
+
+ if (0 == lstat("/st_drv.ko", &file_stat)) {
+ if (insmod("/st_drv.ko", "") < 0) {
+ UIM_ERR(" Error inserting st_drv module");
+ return -1;
+ } else {
+ UIM_DBG(" Inserted st_drv module");
+ }
+ } else {
+ if (0 == lstat("/dev/rfkill", &file_stat)) {
+ UIM_DBG("ST built into the kernel ?");
+ } else {
+ UIM_ERR("BT/FM/GPS would be unavailable on system");
+ UIM_ERR(" rfkill device '/dev/rfkill' not found ");
+ return -1;
+ }
+ }
+#endif
+
+#ifndef ANDROID
+ /*-- Insmod of ST driver --*/
+ asprintf(&tist_ko_path,
+ "/lib/modules/%s/kernel/drivers/misc/ti-st/st_drv.ko",name.release);
+ if (0 == lstat(tist_ko_path, &file_stat)) {
+ if (system("insmod /lib/modules/`uname -r`/kernel/drivers/misc/ti-st/st_drv.ko") != 0) {
+ UIM_ERR(" Error inserting st_drv module");
+ free(tist_ko_path);
+ return -1;
+ } else {
+ UIM_DBG(" Inserted st_drv module");
+ }
+ } else {
+ UIM_ERR("ST driver built into the kernel ?");
+ }
+ free(tist_ko_path);
+#endif
+
+ if (change_rfkill_perms() < 0) {
+ /* possible error condition */
+ UIM_ERR("rfkill not enabled in st_drv - BT on from UI might fail\n");
+ }
+
+#ifndef ANDROID
+ /*-- Insmod of BT driver --*/
+ asprintf(&tist_ko_path,
+ "/lib/modules/%s/kernel/drivers/staging/ti-st/bt_drv.ko",name.release);
+ if (0 == lstat(tist_ko_path, &file_stat)) {
+ if (system("insmod /lib/modules/`uname -r`/kernel/drivers/staging/ti-st/bt_drv.ko") != 0) {
+ UIM_ERR(" Error inserting bt_drv module");
+ system("rmmod st_drv");
+ free(tist_ko_path);
+ return -1;
+ } else {
+ UIM_DBG(" Inserted bt_drv module");
+ }
+ } else {
+ UIM_ERR("BT driver built into the kernel ?");
+ }
+ free(tist_ko_path);
+
+#if INCLUDE_FM
+ /*-- Insmod of FM driver --*/
+ asprintf(&tist_ko_path,
+ "/lib/modules/%s/kernel/drivers/staging/ti-st/fm_drv.ko",name.release);
+ if (0 == lstat(tist_ko_path, &file_stat)) {
+ if (system("insmod /lib/modules/`uname -r`/kernel/drivers/staging/ti-st/fm_drv.ko") != 0) {
+ UIM_ERR(" Error inserting fm_drv module");
+ system("rmmod bt_drv");
+ system("rmmod st_drv");
+ free(tist_ko_path);
+ return -1;
+ } else {
+ UIM_DBG(" Inserted fm_drv module");
+ }
+ } else {
+ UIM_ERR("FM driver built into the kernel ?");
+ }
+ free(tist_ko_path);
+#endif /* INCLUDE_FM */
+#else /* if ANDROID */
+ if (0 == lstat("/bt_drv.ko", &file_stat)) {
+ if (insmod("/bt_drv.ko", "") < 0) {
+ UIM_ERR(" Error inserting bt_drv module, NO BT? ");
+ } else {
+ UIM_DBG(" Inserted bt_drv module");
+ }
+ } else {
+ UIM_DBG("BT driver module un-available... ");
+ UIM_DBG("BT driver built into the kernel ?");
+ }
+
+ if (0 == lstat("/fm_drv.ko", &file_stat)) {
+ if (insmod("/fm_drv.ko", "") < 0) {
+ UIM_ERR(" Error inserting fm_drv module, NO FM? ");
+ } else {
+ UIM_DBG(" Inserted fm_drv module");
+ }
+ } else {
+ UIM_DBG("FM driver module un-available... ");
+ UIM_DBG("FM driver built into the kernel ?");
+ }
+
+ if (0 == lstat("/gps_drv.ko", &file_stat)) {
+ if (insmod("/gps_drv.ko", "") < 0) {
+ UIM_ERR(" Error inserting gps_drv module, NO GPS? ");
+ } else {
+ UIM_DBG(" Inserted gps_drv module");
+ }
+ } else {
+ UIM_DBG("GPS driver module un-available... ");
+ UIM_DBG("GPS driver built into the kernel ?");
+ }
+
+ if (chmod("/dev/tifm", 0666) < 0) {
+ UIM_ERR("unable to chmod /dev/tifm");
+ }
+#endif
+ /* rfkill device's open/poll/read */
+ st_fd = open("/dev/rfkill", O_RDONLY);
+ if (st_fd < 0) {
+ UIM_DBG("unable to open /dev/rfkill (%s)", strerror(errno));
+ remove_modules();
+ return -1;
+ }
+
+
+ p.fd = st_fd;
+ p.events = POLLERR | POLLHUP | POLLOUT | POLLIN;
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+RE_POLL:
+ while (!exiting) {
+ p.revents = 0;
+#ifdef ANDROID
+ err = ppoll(&p, 1, NULL, &sigs);
+#else
+ err = poll(&p, 1, -1);
+#endif /* ANDROID */
+ if (err < 0 && errno == EINTR)
+ continue;
+ if (err)
+ break;
+ }
+ if (!exiting)
+ {
+ err = read(st_fd, &rf_event, sizeof(rf_event));
+ UIM_DBG("rf_event: %d, %d, %d, %d, %d\n", rf_event.idx,
+ rf_event.type, rf_event.op ,rf_event.hard,
+ rf_event.soft);
+ if ((rf_event.op == RFKILL_OP_CHANGE) &&
+ (rf_event.idx == rfkill_idx)) {
+ if (rf_event.hard == 1) /* hard blocked */
+ st_state = UNINSTALL_N_TI_WL;
+ else /* unblocked */
+ st_state = INSTALL_N_TI_WL;
+
+ if (prev_st_state != st_state)
+ st_sig_handler(SIGUSR2);
+ }
+ goto RE_POLL;
+ }
+
+ if(remove_modules() < 0) {
+ UIM_ERR(" Error removing modules ");
+ close(st_fd);
+ return -1;
+ }
+
+ close(st_fd);
+ return 0;
+}
diff --git a/uim_rfkill/uim.h b/uim_rfkill/uim.h
new file mode 100644
index 0000000..8797db1
--- /dev/null
+++ b/uim_rfkill/uim.h
@@ -0,0 +1,154 @@
+/*
+ * User Mode Init manager - For shared transport
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program;if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef UIM_H
+#define UIM_H
+
+/* Paramaters to set the baud rate*/
+#define FLOW_CTL 0x0001
+#define BOTHER 0x00001000
+#define ARM_NCCS 19
+
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+
+/*HCI Command and Event information*/
+#define HCI_HDR_OPCODE 0xff36
+#define WRITE_BD_ADDR_OPCODE 0xFC06
+#define RESP_PREFIX 0x04
+#define MAX_TRY 10
+
+/* HCI Packet types */
+#define HCI_COMMAND_PKT 0x01
+#define HCI_EVENT_PKT 0x04
+
+/* HCI command macros*/
+#define HCI_EVENT_HDR_SIZE 2
+#define HCI_COMMAND_HDR_SIZE 3
+#define UIM_WRITE_BD_ADDR_CP_SIZE 6
+
+
+/* HCI event macros*/
+#define EVT_CMD_COMPLETE_SIZE 3
+#define EVT_CMD_STATUS_SIZE 4
+#define EVT_CMD_COMPLETE 0x0E
+#define EVT_CMD_STATUS 0x0F
+
+
+#define VERBOSE
+#ifndef ANDROID
+#define LOGE printf
+#endif /* ANDROID */
+#define LOG_TAG "uim-rfkill: "
+#define UIM_ERR(fmt, arg...) LOGE("uim:"fmt"\n" , ##arg)
+#if defined(UIM_DEBUG) /* limited debug messages */
+#define UIM_START_FUNC() LOGE("uim: Inside %s\n", __FUNCTION__)
+#define UIM_DBG(fmt, arg...) LOGE("uim:"fmt"\n" , ## arg)
+#define UIM_VER(fmt, arg...)
+#elif defined(VERBOSE) /* very verbose */
+#define UIM_START_FUNC() LOGE("uim: Inside %s\n", __FUNCTION__)
+#define UIM_DBG(fmt, arg...) LOGE("uim:"fmt"\n" , ## arg)
+#define UIM_VER(fmt, arg...) LOGE("uim:"fmt"\n" , ## arg)
+#else /* error msgs only */
+#define UIM_START_FUNC()
+#define UIM_DBG(fmt, arg...)
+#define UIM_VER(fmt, arg...)
+#endif
+
+/*Termios2 structure for setting the Custom baud rate*/
+struct termios2 {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[ARM_NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+/* HCI command header*/
+typedef struct {
+ uint16_t opcode; /* OCF & OGF */
+ uint8_t plen;
+} __attribute__ ((packed)) hci_command_hdr;
+
+/* HCI event header*/
+typedef struct {
+ uint8_t evt;
+ uint8_t plen;
+} __attribute__ ((packed)) hci_event_hdr;
+
+/* HCI command complete event*/
+typedef struct {
+ uint8_t ncmd;
+ uint16_t opcode;
+} __attribute__ ((packed)) evt_cmd_complete;
+
+/* HCI event status*/
+typedef struct {
+ uint8_t status;
+ uint8_t ncmd;
+ uint16_t opcode;
+} __attribute__ ((packed)) evt_cmd_status;
+
+/* HCI Event structure to set the cusrom baud rate*/
+typedef struct {
+ uint8_t uart_prefix;
+ hci_event_hdr hci_hdr;
+ evt_cmd_complete cmd_complete;
+ uint8_t status;
+ uint8_t data[16];
+} __attribute__ ((packed)) command_complete_t;
+
+/* HCI Command structure to set the cusrom baud rate*/
+typedef struct {
+ uint8_t uart_prefix;
+ hci_command_hdr hci_hdr;
+ uint32_t speed;
+} __attribute__ ((packed)) uim_speed_change_cmd;
+
+/* BD address structure to set the uim BD address*/
+typedef struct {
+ unsigned char b[6];
+} __attribute__((packed)) bdaddr_t;
+
+/* HCI Command structure to set the uim BD address*/
+typedef struct {
+ uint8_t uart_prefix;
+ hci_command_hdr hci_hdr;
+ bdaddr_t addr;
+} __attribute__ ((packed)) uim_bdaddr_change_cmd;
+
+/* Signal received from KIM will install line discipline at first,
+ * the next signal received from KIM will un-install the
+ * line discipline*/
+enum {
+ /* expecting signal from KIM to setup uart fd for ST */
+ INSTALL_N_TI_WL,
+
+ /* expecting signal from KIM to close uart fd */
+ UNINSTALL_N_TI_WL,
+};
+
+/* Functions to insert and remove the kernel modules from the system*/
+extern int init_module(void *, unsigned int, const char *);
+extern int delete_module(const char *, unsigned int);
+extern int load_file(const char *, unsigned int *);
+
+#endif /* UIM_H */
diff --git a/wl18xx_plt.c b/wl18xx_plt.c
new file mode 100644
index 0000000..6bfaf2a
--- /dev/null
+++ b/wl18xx_plt.c
@@ -0,0 +1,787 @@
+/*
+ * This file is part of calibrator
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "calibrator.h"
+#include "plt.h"
+#include "wl18xx_plt.h"
+
+SECTION(wl18xx_plt);
+
+static int plt_wl18xx_set_antenna_diversity_5G(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_set_antenna_diversity_5G prms;
+
+ if (argc != 1)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_5GHZ_ANTENNA_DIVERSITY;
+ prms.mode = (__u8)atoi(argv[0]);
+
+ if (prms.mode > 1)
+ return 1;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ printf("Calibrator:: Set antenna diversity 5G (mode=%d)\n",
+ prms.mode);
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, set_antenna_diversity_5G , "<mode>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_set_antenna_diversity_5G,
+ " Set antenna diversity 5G\n");
+
+
+static int plt_wl18xx_tx_tone_stop(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_phy_tx_tone_stop prms;
+
+ if (argc != 0)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_STOP_TX_TONE;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ printf("Calibrator:: Stopping TX Tone\n");
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, tx_tone_stop , "",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_tx_tone_stop,
+ " Stop TX Tone\n");
+
+
+
+static int plt_wl18xx_tx_tone_start(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_phy_tx_tone_start prms;
+
+ if (argc != 4)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_START_TX_TONE;
+
+ prms.mode = (__u8)atoi(argv[0]);
+ prms.bin_index = (__s8)atoi(argv[1]);
+ prms.trigger_iqram_recording = 0;
+ prms.sig_gen_cw_en = 0;
+ prms.sig_gen_mod_en = 0;
+ prms.ant_mode = (__u8)atoi(argv[2]);
+ prms.set_rx_aux_on = 0;
+ prms.gain_index = (__u8)atoi(argv[3]);
+
+ if (prms.mode > 2)
+ return 1;
+
+ if ((prms.bin_index > 32) || (prms.bin_index < (-32)))
+ return 1;
+
+ if (prms.ant_mode > 2)
+ return 1;
+
+ if (prms.gain_index > 4)
+ return 1;
+
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ printf("Calibrator:: Starting TX Tone (mode=%d, bin_index=%d, ant_mode=%d, gain_index=%d)\n",
+ prms.mode, prms.bin_index, prms.ant_mode, prms.gain_index);
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, tx_tone_start , "<mode> <bin index> <antenna mode> <gain index>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_tx_tone_start,
+ "Start TX Tone\n\n"
+ "<mode>\t\t tone mode:\n"
+ "\t\t\t0 = silence\n"
+ "\t\t\t1 = carrier feedthrough\n"
+ "\t\t\t2 = single tone\n"
+ "<bin index>\t the offset (in round number of bins) of the tone from the carrier: [(-32)-32]\n"
+ "<ant mode>\t antenna selection:\n"
+ "\t\t\t0 = auto\n"
+ "\t\t\t1 = TX1\n"
+ "\t\t\t2 = TX2\n"
+ "<gain index>\t PA gain step: 2.4GHz: 0-1, 5GHz: 0-4\n");
+
+
+static int plt_wl18xx_phy_reg_write(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_phy_reg_write prms;
+
+ if (argc != 2)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_PHY_ADDR_WRITE;
+
+
+ prms.addr = strtol(argv[0], NULL, 16);
+ prms.data = strtol(argv[1], NULL, 16);
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, phy_reg_write , "<addr> <data> ",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_phy_reg_write,
+ " Write PHY register for PLT.\n");
+
+
+static int plt_wl18xx_display_phy_reg_read(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
+ struct wl18xx_cmd_phy_reg_read *prms;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_TESTDATA]) {
+ fprintf(stderr, "no data!\n");
+ return NL_SKIP;
+ }
+
+ nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
+ nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);
+
+ prms = (struct wl18xx_cmd_phy_reg_read *) nla_data(td[WL1271_TM_ATTR_DATA]);
+
+ printf("Register Address: \t0x%x\t", prms->addr);
+ printf("is:\t0x%x\n", prms->data);
+
+ return NL_SKIP;
+}
+
+
+static int plt_wl18xx_phy_reg_read(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_phy_reg_read prms;
+
+ if (argc != 1)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_PHY_ADDR_READ;
+
+ prms.addr = strtol(argv[0], NULL, 16);
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+ NLA_PUT_U8(msg, WL1271_TM_ATTR_ANSWER, 1);
+
+ nla_nest_end(msg, key);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ plt_wl18xx_display_phy_reg_read, NULL);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, phy_reg_read , "<addr>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_phy_reg_read,
+ " Read PHY register for PLT.\n");
+
+
+static int plt_wl18xx_set_antenna_mode_5G(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_set_antenna_mode_5G prms;
+
+ if (argc != 4)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_SET_ANTENNA_MODE_5G;
+
+
+ prms.mac_prim_rx_chain = (__u8)atoi(argv[0]);
+ prms.mac_rx_chain1_en = (__u8)atoi(argv[1]);
+ prms.mac_rx_chain2_en = (__u8)atoi(argv[2]);
+ prms.mac_tx_chain1_en = (__u8)atoi(argv[3]);
+
+ if ((prms.mac_prim_rx_chain != 1 && prms.mac_prim_rx_chain != 2 ))
+ return 1;
+
+ if ((prms.mac_rx_chain1_en > 1) || (prms.mac_rx_chain2_en > 1)
+ || (prms.mac_tx_chain1_en > 1))
+ return 1;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, set_antenna_mode_5G , "<mac_prim_rx_chain> <mac_rx_chain1_en> "
+ "<mac_rx_chain2_en> <mac_tx_chain1_en>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_set_antenna_mode_5G,
+ "set antenna mode 5G for PLT.\n");
+
+
+static int plt_wl18xx_set_antenna_mode_24G(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_set_antenna_mode_24G prms;
+
+ if (argc != 6)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_SET_ANTENNA_MODE_24G;
+
+
+ prms.mac_prim_rx_chain = (__u8)atoi(argv[0]);
+ prms.mac_prim_tx_chain = (__u8)atoi(argv[1]);
+ prms.mac_rx_chain1_en = (__u8)atoi(argv[2]);
+ prms.mac_rx_chain2_en = (__u8)atoi(argv[3]);
+ prms.mac_tx_chain1_en = (__u8)atoi(argv[4]);
+ prms.mac_tx_chain2_en = (__u8)atoi(argv[5]);
+
+ if ((prms.mac_prim_rx_chain != 1 && prms.mac_prim_rx_chain != 2 ) ||
+ (prms.mac_prim_tx_chain != 1 && prms.mac_prim_tx_chain != 2 ))
+ return 1;
+
+ if ((prms.mac_rx_chain1_en > 1) || (prms.mac_rx_chain2_en > 1) ||
+ (prms.mac_tx_chain1_en > 1) || (prms.mac_tx_chain2_en > 1))
+ return 1;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, set_antenna_mode_24G , "<mac_prim_rx_chain> <mac_prim_tx_chain> "
+ "<mac_rx_chain1_en> <mac_rx_chain2_en> <mac_tx_chain1_en> <mac_tx_chain2_en>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_set_antenna_mode_24G,
+ "set antenna mode 2.4G for PLT.\n");
+
+static int plt_wl18xx_set_tx_power(struct nl80211_state *state,
+ struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_set_tx_power prms;
+
+ if (argc != 12)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_TX_POWER;
+
+ prms.mac_des_pwr = (__s32)atoi(argv[0]);
+ prms.mac_lvl_idx = atoi(argv[1]);
+ prms.freq_band = atoi(argv[2]);
+ prms.freq_prim_chan_num = atoi(argv[3]);
+ prms.freq_prim_chan_loc = atoi(argv[4]);
+ prms.mac_ant_select = atoi(argv[5]);
+ prms.mac_non_srv = atoi(argv[6]);
+ prms.mac_chan_lim_dis = atoi(argv[7]);
+ prms.mac_fem_lim_dis = atoi(argv[8]);
+ prms.mac_gain_calc_mode = atoi(argv[9]);
+ prms.mac_analog_gain_control_idx = atoi(argv[10]);
+ prms.mac_post_dpd_gain = atoi(argv[11]);
+
+ if ((prms.mac_gain_calc_mode == 0) || (prms.mac_gain_calc_mode == 1)) {
+ if ((prms.mac_des_pwr > 20000) || (prms.mac_des_pwr < 0)) {
+ fprintf(stderr, "Power Mode: TX Output Power is out of range (0-20.000dBm)\n");
+ return 1;
+ }
+ }
+
+ if (prms.mac_gain_calc_mode == 2) {
+ if ((prms.mac_des_pwr > -4000) || (prms.mac_des_pwr < -15000)) {
+ fprintf(stderr, "dBPsat Mode: TX Output Power is out of range (-15.000-(-4.000)dBm)\n");
+ return 1;
+ }
+ }
+
+ if (prms.mac_lvl_idx > 3)
+ return 1;
+
+ if (prms.freq_band > 2)
+ return 1;
+
+ if (prms.freq_prim_chan_num <= 0)
+ return 1;
+
+ if (prms.mac_ant_select > 3)
+ return 1;
+
+ if (prms.mac_non_srv > 1)
+ return 1;
+
+ if (prms.mac_chan_lim_dis > 1)
+ return 1;
+
+ if (prms.mac_fem_lim_dis > 1)
+ return 1;
+
+ if (prms.mac_gain_calc_mode > 2)
+ return 1;
+
+ if (prms.mac_analog_gain_control_idx > 4)
+ return 1;
+
+ if (prms.mac_post_dpd_gain > 4)
+ return 1;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, set_tx_power, "<output_power> <level> <band> "
+ "<channel_number> <primary_channel_location> <antenna> <non_serving_channel> "
+ "<channel_limitation> <internal> <gain_calculation_mode> "
+ "<analog_gain_control_id> <post_dpd_gain>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_set_tx_power,
+ "set TX transmissions power for PLT.\n");
+
+static int plt_wl18xx_tune_channel(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_channel_tune prms;
+
+ if (argc != 3)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_CHANNEL_TUNE;
+ prms.channel = (__u8)atoi(argv[0]);
+ prms.band = (__u8)atoi(argv[1]);
+ prms.bandwidth = (__u8)atoi(argv[2]);
+ prms.rfSetIdx = 0; /* Set to Zero to support backward competability only for RTTT */
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, tune_channel, "<channel> <band> <bandwidth>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_tune_channel,
+ "Set channel, band and bandwidth for PLT.\n");
+
+#define RX_FILTER_MAGIC_NUMBER 0xabadabad
+
+static int plt_wl18xx_start_rx(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_start_rx prms;
+
+ if (argc > 2)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_START_RX_SIMULATION;
+
+ if (argc == 2) {
+ str2mac(prms.src_addr, argv[0]);
+ str2mac(prms.dst_addr, argv[1]);
+ prms.magic_num = RX_FILTER_MAGIC_NUMBER;
+ }
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+ printf("Calibrator:: Starting RX Simulation (Note that statistics counters are being reset)...\n");
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, start_rx, "<source address> <destination address>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_start_rx,
+ "Start gathering RX statistics for PLT.\n");
+
+static int plt_wl18xx_stop_rx(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_stop_rx prms;
+
+ if (argc != 0)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_STOP_RX_SIMULATION;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+ printf("Calibrator:: Stopping RX Simulation\n");
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, stop_rx, "",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_stop_rx,
+ "Stop gathering RX statistics for PLT.\n");
+
+static int plt_wl18xx_display_rx_stats(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *td[WL1271_TM_ATTR_MAX + 1];
+ struct wl18xx_cmd_rx_stats *prms;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_TESTDATA]) {
+ fprintf(stderr, "no data!\n");
+ return NL_SKIP;
+ }
+
+ nla_parse(td, WL1271_TM_ATTR_MAX, nla_data(tb[NL80211_ATTR_TESTDATA]),
+ nla_len(tb[NL80211_ATTR_TESTDATA]), NULL);
+
+ prms = (struct wl18xx_cmd_rx_stats *) nla_data(td[WL1271_TM_ATTR_DATA]);
+
+ printf("\nRX statistics (status %d)\n", prms->radio_status);
+ printf("Total Received Packets:\t%d\n", prms->total);
+ printf("FCS Errors:\t\t%d\n", prms->errors);
+ printf("MAC Mismatch:\t\t%d\n", prms->addr_mm);
+ printf("Good Packets:\t\t%d\n", prms->good);
+ printf("Average RSSI (SOC):\t%d\n", prms->rssi_soc);
+ printf("Average RSSI (ANT):\t%d\n", prms->rssi_ant);
+
+ if(prms->total) {
+ float per = ((float)prms->total - (float)prms->good)/(float)prms->total;
+ printf("PER:\t\t\t%f # PER = Total Bad / Total Received\n", per);
+ } else {
+ printf("PER:\t\t\tN/A # PER = Total Bad / Total Received\n");
+ }
+
+ return NL_SKIP;
+}
+
+static int plt_wl18xx_get_rx_stats(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_rx_stats prms;
+
+ if (argc != 0)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_GET_RX_STATISTICS;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+ NLA_PUT_U8(msg, WL1271_TM_ATTR_ANSWER, 1);
+
+ nla_nest_end(msg, key);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ plt_wl18xx_display_rx_stats, NULL);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, get_rx_stats, "",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_get_rx_stats,
+ "Retrieve RX statistics for PLT.\n");
+
+static int plt_wl18xx_start_tx(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_start_tx prms;
+
+ if (argc != 11)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_START_TX_SIMULATION;
+
+ prms.delay = atoi(argv[0]);
+ prms.rate = atoi(argv[1]);
+ prms.size = atoi(argv[2]);
+ prms.mode = atoi(argv[3]);
+ prms.data_type = atoi(argv[4]);
+ prms.gi = atoi(argv[5]);
+ prms.options1 = atoi(argv[6]);
+ prms.options2 = atoi(argv[7]);
+ str2mac(prms.src_addr, argv[8]);
+ str2mac(prms.dst_addr, argv[9]);
+ prms.bandwidth = atoi(argv[10]);
+
+ if (prms.delay < 200) {
+ fprintf(stderr, "Delay is out of range (valid range >=200us)\n");
+ return 1;
+ }
+ if (prms.size > 4065) {
+ fprintf(stderr, "Packet Size is out of range (valid range <=4065B)\n");
+ return 1;
+ }
+ if (prms.rate < 0 || prms.rate > 29)
+ return 1;
+ if (prms.gi != 0 && prms.gi != 1)
+ return 1;
+ if (prms.bandwidth != 0 && prms.bandwidth != 1)
+ return 1;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+ printf("Calibrator:: Starting TX Simulation (delay=%d, rate=%d, size=%d, mode=%d\n"
+ " data_type=%d, BW=%d, gi=%d, opt1=0x%x, opt2=0x%x\n"
+ " src=%02x:%02x:%02x:%02x:%02x:%02x\n"
+ " dst=%02x:%02x:%02x:%02x:%02x:%02x)...\n",
+ prms.delay, prms.rate, prms.size, prms.mode, prms.data_type,
+ prms.bandwidth, prms.gi, prms.options1,prms.options2,
+ prms.src_addr[0],prms.src_addr[1],prms.src_addr[2],prms.src_addr[3],prms.src_addr[4],prms.src_addr[5],
+ prms.dst_addr[0],prms.dst_addr[1],prms.dst_addr[2],prms.dst_addr[3],prms.dst_addr[4],prms.dst_addr[5]);
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, start_tx, "<delay> <rate> <size> <mode> <data_type> <gi> "
+ "<options1> <options2> <source MAC> <dest MAC> <channel-width>",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_start_tx,
+ "Start TX transmissions for PLT.\n\n"
+ "<delay>\t\tdelay between packets in us: 200-...\n"
+ "<rate>\t\ttransmission rate:\n"
+ "\t\t\t0 = 1.0 Mbps\t\t\t1 = 2.0 Mbps\n"
+ "\t\t\t2 = 5.0 Mbps\t\t\t3 = 11.0 Mbps\n"
+ "\t\t\t4 = 6.0 Mbps\t\t\t5 = 9.0 Mbps\n"
+ "\t\t\t6 = 12.0 Mbps\t\t\t7 = 18.0 Mbps\n"
+ "\t\t\t8 = 24.0 Mbps\t\t\t9 = 36.0 Mbps\n"
+ "\t\t\t10 = 48.0 Mbps\t\t\t11 = 54.0 Mbps\n"
+ "\t\t\t12 = 6.5 Mbps (MCS0)\t\t13 = 13.0 Mbps (MCS1)\n"
+ "\t\t\t14 = 19.5 Mbps (MCS2)\t\t15 = 26.0 Mbps (MCS3)\n"
+ "\t\t\t16 = 39.0 Mbps (MCS4)\t\t17 = 52.0 Mbps (MCS5)\n"
+ "\t\t\t18 = 58.5 Mbps (MCS6)\t\t19 = 65.0 Mbps (MCS7)\n"
+ "\t\t\t20 = MCS8/MCS4 at 40MHz\t21 = MCS9/MCS5 at 40MHz\n"
+ "\t\t\t22 = MCS10/MCS6 at 40MHz\t23 = MCS11/MCS7 at 40MHz\n"
+ "\t\t\t24 = MCS12/MCS7 at 40MHz SGI\t25 = MCS13\n"
+ "\t\t\t26 = MCS14\t\t\t27 = MCS15\n"
+ "<size>\t\tpacket size (bytes): 0-4065\n"
+ "<mode>\t\tnumber of packets (0 = endless)\n"
+ "<data_type>\tnot supported\n"
+ "<gi>\t\tguard interval (0 = normal, 1 = short)\n"
+ "<options1>\tunused\n"
+ "<options2>\tsupported options according to bitmap:\n"
+ "\t\t\tbit1 - override CCA\n"
+ "\t\t\tbit2 - fixed/incremental sequence number\n"
+ "<source MAC>\tsource MAC address (XX:XX:XX:XX:XX:XX)\n"
+ "<dest MAC>\tdestination MAC address (XX:XX:XX:XX:XX:XX)\n"
+ "<channel-width>\tchannel width (0 = 20 MHz, 1 = 40 MHz)");
+
+static int plt_wl18xx_stop_tx(struct nl80211_state *state, struct nl_cb *cb,
+ struct nl_msg *msg, int argc, char **argv)
+{
+ struct nlattr *key;
+ struct wl18xx_cmd_stop_tx prms;
+
+ if (argc != 0)
+ return 1;
+
+ prms.test.id = WL18XX_TEST_CMD_STOP_TX_SIMULATION;
+
+ key = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
+ if (!key) {
+ fprintf(stderr, "fail to nla_nest_start()\n");
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, WL1271_TM_ATTR_CMD_ID, WL1271_TM_CMD_TEST);
+ NLA_PUT(msg, WL1271_TM_ATTR_DATA, sizeof(prms), &prms);
+
+ nla_nest_end(msg, key);
+
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "%s> building message failed\n", __func__);
+ return 2;
+}
+
+COMMAND(wl18xx_plt, stop_tx, "",
+ NL80211_CMD_TESTMODE, 0, CIB_NETDEV, plt_wl18xx_stop_tx,
+ "Stop TX transmissions for PLT.\n");
+
diff --git a/wl18xx_plt.h b/wl18xx_plt.h
new file mode 100644
index 0000000..48108cd
--- /dev/null
+++ b/wl18xx_plt.h
@@ -0,0 +1,252 @@
+/*
+ * This file is part of calibrator
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_PLT_H__
+#define __WL18XX_PLT_H__
+
+enum wl18xx_test_cmds {
+ /* 0x1 */ WL18XX_TEST_CMD_PD_BUFFER_CAL = 0x1,
+ /* 0x2 */ WL18XX_TEST_CMD_P2G_CAL,
+ /* 0x3 */ WL18XX_TEST_CMD_RX_PLT_ENTER,
+ /* 0x4 */ WL18XX_TEST_CMD_RX_PLT_CAL,
+ /* 0x5 */ WL18XX_TEST_CMD_RX_PLT_EXIT,
+ /* 0x6 */ WL18XX_TEST_CMD_RX_PLT_GET,
+ /* 0x7 */ WL18XX_TEST_CMD_FCC,
+ /* 0x8 */ WL18XX_TEST_CMD_TELEC,
+ /* 0x9 */ WL18XX_TEST_CMD_STOP_TX,
+ /* 0xa */ WL18XX_TEST_CMD_PLT_TEMPLATE,
+ /* 0xb */ WL18XX_TEST_CMD_PLT_GAIN_ADJUST,
+ /* 0xc */ WL18XX_TEST_CMD_PLT_GAIN_GET,
+ /* 0xd */ WL18XX_TEST_CMD_CHANNEL_TUNE_OLD,
+ /* 0xe */ WL18XX_TEST_CMD_FREE_RUN_RSSI,
+ /* 0xf */ WL18XX_TEST_CMD_DEBUG,
+ /* 0x10 */ WL18XX_TEST_CMD_CLPC_COMMANDS,
+ /* 0x11 */ WL18XX_TEST_CMD_RESERVED,
+ /* 0x12 */ WL18XX_TEST_CMD_RX_STAT_STOP,
+ /* 0x13 */ WL18XX_TEST_CMD_RX_STAT_START,
+ /* 0x14 */ WL18XX_TEST_CMD_RX_STAT_RESET,
+ /* 0x15 */ WL18XX_TEST_CMD_RX_STAT_GET,
+ /* 0x16 */ WL18XX_TEST_CMD_LOOPBACK_START,
+ /* 0x17 */ WL18XX_TEST_CMD_LOOPBACK_STOP,
+ /* 0x18 */ WL18XX_TEST_CMD_GET_FW_VERSIONS,
+ /* 0x19 */ WL18XX_TEST_CMD_INI_FILE_RADIO_PARAM,
+ /* 0x1a */ WL18XX_TEST_CMD_RUN_CALIBRATION_TYPE,
+ /* 0x1b */ WL18XX_TEST_CMD_TX_GAIN_ADJUST,
+ /* 0x1c */ WL18XX_TEST_CMD_UPDATE_PD_BUFFER_ERRORS,
+ /* 0x1d */ WL18XX_TEST_CMD_UPDATE_PD_REFERENCE_POINT,
+ /* 0x1e */ WL18XX_TEST_CMD_INI_FILE_GENERAL_PARAM,
+ /* 0x1f */ WL18XX_TEST_CMD_SET_EFUSE,
+ /* 0x20 */ WL18XX_TEST_CMD_GET_EFUSE,
+ /* 0x21 */ WL18XX_TEST_CMD_TEST_TONE,
+ /* 0x22 */ WL18XX_TEST_CMD_POWER_MODE,
+ /* 0x23 */ WL18XX_TEST_CMD_SMART_REFLEX,
+ /* 0x24 */ WL18XX_TEST_CMD_CHANNEL_RESPONSE,
+ /* 0x25 */ WL18XX_TEST_CMD_DCO_ITRIM_FEATURE,
+ /* 0x26 */ WL18XX_TEST_CMD_START_TX_SIMULATION,
+ /* 0x27 */ WL18XX_TEST_CMD_STOP_TX_SIMULATION,
+ /* 0x28 */ WL18XX_TEST_CMD_START_RX_SIMULATION,
+ /* 0x29 */ WL18XX_TEST_CMD_STOP_RX_SIMULATION,
+ /* 0x2a */ WL18XX_TEST_CMD_GET_RX_STATISTICS,
+ /* 0x2b */ /*WL18XX_TEST_CMD_INI_FILE_RF_EXTENDED_PARAM*/
+ /* 0x2c */ WL18XX_TEST_CMD_SET_NVS_VERSION,
+ /* 0x2d */ WL18XX_TEST_CMD_CHANNEL_TUNE,
+ /* 0x2e */ WL18XX_TEST_CMD_TX_POWER,
+ /* 0x2f */ WL18XX_TEST_CMD_SET_ANTENNA_MODE_24G,
+ /* 0x30 */ WL18XX_TEST_CMD_GET_CALIB_RESULT,
+ /* 0x31 */ WL18XX_TEST_CMD_SET_ANTENNA_MODE_5G,
+ /* 0x32 */ WL18XX_TEST_CMD_PHY_ADDR_READ,
+ /* 0x33 */ WL18XX_TEST_CMD_PHY_ADDR_WRITE,
+ /* 0x34 */ WL18XX_TEST_CMD_START_TX_TONE,
+ /* 0x35 */ WL18XX_TEST_CMD_STOP_TX_TONE,
+ /* 0x36 */ WL18XX_TEST_CMD_START_RF_PARAMS_SET,
+ /* 0x37 */ WL18XX_TEST_CMD_STOP_RF_PARAMS_SET,
+ /* 0x38 */ WL18XX_TEST_CMD_REG_DOMAIN_UPDATE,
+ /* 0x39 */ WL18XX_TEST_CMD_5GHZ_ANTENNA_DIVERSITY,
+};
+
+struct wl18xx_cmd_channel_tune {
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le16 radio_status;
+ __u8 channel;
+ __u8 band;
+ __u8 bandwidth;
+ __u8 rfSetIdx;
+ __u8 padding[2];
+} __attribute__((packed));
+
+struct wl18xx_cmd_start_rx {
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __le32 magic_num;
+ __u8 src_addr[MAC_ADDR_LEN];
+ __u8 dst_addr[MAC_ADDR_LEN];
+} __attribute__((packed));
+
+struct wl18xx_cmd_stop_rx {
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+} __attribute__((packed));
+
+struct wl18xx_cmd_rx_stats {
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __le32 total;
+ __le32 errors;
+ __le32 addr_mm;
+ __le32 good;
+ __le32 rssi_soc;
+ __le32 rssi_ant;
+} __attribute__((packed));
+
+struct wl18xx_cmd_start_tx {
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __le32 delay;
+ __le32 rate;
+ __le32 size;
+ __le32 mode;
+ __le32 data_type;
+ __le32 gi;
+ __le32 options1;
+ __le32 options2;
+ __u8 src_addr[MAC_ADDR_LEN];
+ __u8 dst_addr[MAC_ADDR_LEN];
+ __le32 bandwidth;
+ __le32 padding;
+} __attribute__((packed));
+
+struct wl18xx_cmd_stop_tx {
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+} __attribute__((packed));
+
+struct wl18xx_cmd_set_tx_power {
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __s32 mac_des_pwr;
+ __le32 mac_lvl_idx;
+ __le32 freq_band;
+ __le32 freq_prim_chan_num;
+ __le32 freq_prim_chan_loc;
+ __le32 mac_ant_select;
+ __le32 mac_non_srv;
+ __le32 mac_chan_lim_dis;
+ __le32 mac_fem_lim_dis;
+ __le32 mac_gain_calc_mode;
+ __le32 mac_analog_gain_control_idx;
+ __le32 mac_post_dpd_gain;
+} __attribute__((packed));
+
+struct wl18xx_cmd_set_antenna_mode_24G { /* TEST_CMD_SET_ANTENNA_MODE24G */
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __u8 mac_prim_rx_chain;
+ __u8 mac_prim_tx_chain;
+ __u8 mac_rx_chain1_en;
+ __u8 mac_rx_chain2_en;
+ __u8 mac_tx_chain1_en;
+ __u8 mac_tx_chain2_en;
+ __u8 res1;
+ __u8 res2;
+} __attribute__((packed));
+
+struct wl18xx_cmd_set_antenna_mode_5G { /* TEST_CMD_SET_ANTENNA_MODE5G */
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __u8 mac_prim_rx_chain;
+ __u8 mac_rx_chain1_en;
+ __u8 mac_rx_chain2_en;
+ __u8 mac_tx_chain1_en;
+} __attribute__((packed));
+
+struct wl18xx_cmd_phy_reg_read { /* TEST_CMD_PHY_REG_READ */
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __le32 data;
+ __le32 addr;
+} __attribute__((packed));
+
+struct wl18xx_cmd_phy_reg_write { /* TEST_CMD_PHY_REG_WRITE */
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __le32 data;
+ __le32 addr;
+} __attribute__((packed));
+
+struct wl18xx_cmd_phy_tx_tone_start { /* TEST_CMD_START_TX_TONE */
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __u8 mode;
+ __s8 bin_index;
+ __u8 trigger_iqram_recording;
+ __u8 sig_gen_cw_en;
+ __u8 sig_gen_mod_en;
+ __u8 ant_mode;
+ __u8 set_rx_aux_on;
+ __u8 gain_index;
+} __attribute__((packed));
+
+struct wl18xx_cmd_phy_tx_tone_stop { /* TEST_CMD_STOP_TX_TONE */
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+} __attribute__((packed));
+
+struct wl18xx_cmd_set_antenna_diversity_5G { /* WL18XX_TEST_CMD_5GHZ_ANTENNA_DIVERSITY */
+ struct wl1271_cmd_header header;
+ struct wl1271_cmd_test_header test;
+
+ __le32 radio_status;
+
+ __u8 mode;
+ __u8 padding[3];
+
+} __attribute__((packed));
+
+#endif /* __WL18XX_PLT_H__ */