summaryrefslogtreecommitdiff
path: root/mac80211/ti-utils/nvs.c
diff options
context:
space:
mode:
Diffstat (limited to 'mac80211/ti-utils/nvs.c')
-rw-r--r--mac80211/ti-utils/nvs.c836
1 files changed, 836 insertions, 0 deletions
diff --git a/mac80211/ti-utils/nvs.c b/mac80211/ti-utils/nvs.c
new file mode 100644
index 00000000..dcd36a30
--- /dev/null
+++ b/mac80211/ti-utils/nvs.c
@@ -0,0 +1,836 @@
+/*
+ * 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 <netinet/in.h>
+
+#include <netlink/netlink.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"
+/* 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";
+
+int nvs_fill_radio_params(int fd, struct wl12xx_ini *ini, char *buf)
+{
+ int size;
+ struct wl1271_ini *gp;
+
+ if (ini) {
+ gp = &ini->ini1271;
+ }
+
+ size = sizeof(struct wl1271_ini);
+
+ if (ini) { /* for reference NVS */
+ unsigned char *c = (unsigned char *)gp;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ write(fd, c++, 1);
+ }
+ } else {
+ char *p = buf + 0x1D4;
+ write(fd, (const void *)p, size);
+ }
+
+ return 0;
+}
+
+static int nvs_fill_radio_params_128x(int fd, struct wl12xx_ini *ini, char *buf)
+{
+ int size;
+ struct wl128x_ini *gp = &ini->ini128x;
+
+ size = sizeof(struct wl128x_ini);
+
+ if (ini) { /* for reference NVS */
+ unsigned char *c = (unsigned char *)gp;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ write(fd, c++, 1);
+ }
+
+ } else {
+ char *p = buf + 0x1D4;
+ write(fd, p, size);
+ }
+
+ return 0;
+}
+
+int nvs_set_autofem(int fd, char *buf, unsigned char val)
+{
+ int size;
+ struct wl1271_ini *gp;
+ unsigned char *c;
+ int i;
+
+ 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)
+{
+ int size;
+ struct wl128x_ini *gp;
+ unsigned char *c;
+ int i;
+
+ 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)
+{
+ int size;
+ struct wl1271_ini *gp;
+ unsigned char *c;
+ int i;
+
+ 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)
+{
+ int size;
+ struct wl128x_ini *gp;
+ unsigned char *c;
+ int i;
+
+ 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) {
+ fprintf(stderr, "fail to stat file %s (%s)\n", filename,
+ strerror(errno));
+ 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)", 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;
+ char file2read[FILENAME_MAX];
+
+ if (nvs_file == NULL || strlen(nvs_file) < 2) {
+ printf("\nThe path to NVS file not provided, "
+ "use default (%s)\n", CURRENT_NVS_NAME);
+
+ strncpy(file2read, CURRENT_NVS_NAME, strlen(CURRENT_NVS_NAME));
+
+ } else
+ strncpy(file2read, nvs_file, strlen(nvs_file));
+
+ fl_sz = file_exist(file2read);
+ if (fl_sz < 0) {
+ fprintf(stderr, "File %s not exists\n", CURRENT_NVS_NAME);
+ return 1;
+ }
+
+ return read_from_current_nvs(file2read, 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;
+ 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(NEW_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;
+ }
+
+ 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(NEW_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_file, struct wl12xx_common *cmn)
+{
+ int new_nvs, res = 0;
+ char buf[2048];
+
+ res = read_nvs(nvs_file, buf, BUF_SIZE_4_NVS_FILE, NULL);
+ if (res) {
+ return 1;
+ }
+
+ /* create new NVS file */
+ new_nvs = open(NEW_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_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, struct wl12xx_common *cmn)
+{
+ 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(NEW_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_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(NEW_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_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;
+}
+