| /* |
| * 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 <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; |
| } |
| |
| #define COMPARE_N_ADD(temp, str, val, ptr, size) \ |
| if (strncmp(temp, str, sizeof(temp)) == 0) { \ |
| int i; \ |
| unsigned char *p = ptr; \ |
| for (i = 0; i < size; i++) { \ |
| *p = strtol(val, NULL, 16); \ |
| if (i != sizeof(ptr)-1) { \ |
| val += 3; p++; \ |
| } \ |
| } \ |
| return 0; \ |
| } |
| |
| #define DBG_COMPARE_N_ADD(temp, str, val, ptr, size) \ |
| if (strncmp(temp, str, sizeof(temp)) == 0) { \ |
| int i; \ |
| unsigned char *p = ptr; \ |
| for (i = 0; i < size; i++) { \ |
| *p = strtol(val, NULL, 16); \ |
| if (i != sizeof(ptr)-1) { \ |
| val += 3; p++; \ |
| } \ |
| } \ |
| p = ptr; \ |
| printf("%s ", temp); \ |
| for (i = 0; i < size; i++) { \ |
| printf("%02X ", *p); \ |
| p++; \ |
| } \ |
| printf("\n"); \ |
| return 0; \ |
| } |
| |
| #define COMPARE_N_ADD2(temp, str, val, ptr, size) \ |
| if (strncmp(temp, str, sizeof(temp)) == 0) { \ |
| int i; \ |
| unsigned short *p = ptr; \ |
| for (i = 0; i < size; i++) { \ |
| *p = strtol(val, NULL, 16); \ |
| if (i != sizeof(ptr)-1) { \ |
| val += 5; p++; \ |
| } \ |
| } \ |
| return 0; \ |
| } |
| |
| #define DBG_COMPARE_N_ADD2(temp, str, val, ptr, size) \ |
| if (strncmp(temp, str, sizeof(temp)) == 0) { \ |
| int i; \ |
| unsigned short *p = ptr; \ |
| for (i = 0; i < size; i++) { \ |
| *p = strtol(val, NULL, 16); \ |
| if (i != sizeof(ptr)-1) { \ |
| val += 5; p++; \ |
| } \ |
| } \ |
| p = ptr; \ |
| printf("%s ", temp); \ |
| for (i = 0; i < size; i++) { \ |
| printf("%04X ", *p); \ |
| p++; \ |
| } \ |
| printf("\n"); \ |
| return 0; \ |
| } |
| |
| 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, 1); |
| |
| COMPARE_N_ADD("TXBiPFEMManufacturer", l, val, |
| &gp->tx_bip_fem_manufacturer, 1); |
| |
| COMPARE_N_ADD("RefClk", l, val, &gp->ref_clock, 1); |
| |
| COMPARE_N_ADD("SettlingTime", l, val, &gp->settling_time, 1); |
| |
| COMPARE_N_ADD("ClockValidOnWakeup", l, val, |
| &gp->clk_valid_on_wakeup, 1); |
| |
| COMPARE_N_ADD("DC2DCMode", l, val, &gp->dc2dc_mode, 1); |
| |
| COMPARE_N_ADD("Single_Dual_Band_Solution", l, val, |
| &gp->dual_mode_select, 1); |
| |
| if (cmn->dual_mode == DUAL_MODE_UNSET) { |
| cmn->dual_mode = gp->dual_mode_select; |
| } |
| else if (cmn->dual_mode != gp->dual_mode_select) { |
| fprintf(stderr, "Error, FEMs with different dual modes\n"); |
| return 1; |
| } |
| |
| COMPARE_N_ADD("Settings", l, val, &gp->general_settings, 1); |
| |
| COMPARE_N_ADD("SRState", l, val, &gp->sr_state, 1); |
| |
| COMPARE_N_ADD("SRF1", l, val, |
| gp->srf1, WL1271_INI_MAX_SMART_REFLEX_PARAM); |
| |
| COMPARE_N_ADD("SRF2", l, val, |
| gp->srf2, WL1271_INI_MAX_SMART_REFLEX_PARAM); |
| |
| COMPARE_N_ADD("SRF3", l, val, |
| gp->srf3, WL1271_INI_MAX_SMART_REFLEX_PARAM); |
| |
| 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, 1); |
| |
| COMPARE_N_ADD("TXBiPFEMManufacturer", l, val, |
| &gp->tx_bip_fem_manufacturer, 1); |
| |
| COMPARE_N_ADD("RefClk", l, val, &gp->ref_clock, 1); |
| |
| COMPARE_N_ADD("SettlingTime", l, val, &gp->settling_time, 1); |
| |
| COMPARE_N_ADD("ClockValidOnWakeup", l, val, |
| &gp->clk_valid_on_wakeup, 1); |
| |
| COMPARE_N_ADD("TCXO_Clk", l, val, &gp->tcxo_ref_clock, 1); |
| |
| COMPARE_N_ADD("TCXO_SettlingTime", l, val, &gp->tcxo_settling_time, 1); |
| |
| COMPARE_N_ADD("TCXO_ClockValidOnWakeup", l, val, |
| &gp->tcxo_valid_on_wakeup, 1); |
| |
| COMPARE_N_ADD("TCXO_LDO_Voltage", l, val, |
| &gp->tcxo_ldo_voltage, 1); |
| |
| COMPARE_N_ADD("Platform_configuration", l, val, |
| &gp->platform_conf, 1); |
| |
| COMPARE_N_ADD("Single_Dual_Band_Solution", l, val, |
| &gp->dual_mode_select, 1); |
| |
| if (cmn->dual_mode == DUAL_MODE_UNSET) { |
| cmn->dual_mode = gp->dual_mode_select; |
| } else if (cmn->dual_mode != gp->dual_mode_select) { |
| fprintf(stderr, "Error, FEMs with diferent dual modes\n"); |
| return 1; |
| } |
| |
| COMPARE_N_ADD("Settings", l, val, |
| gp->general_settings, WL128X_INI_MAX_SETTINGS_PARAM); |
| |
| COMPARE_N_ADD("XTALItrimVal", l, val, &gp->xtal_itrim_val, 1); |
| |
| COMPARE_N_ADD("SRState", l, val, &gp->sr_state, 1); |
| |
| COMPARE_N_ADD("SRF1", l, val, |
| gp->srf1, WL1271_INI_MAX_SMART_REFLEX_PARAM); |
| |
| COMPARE_N_ADD("SRF2", l, val, |
| gp->srf2, WL1271_INI_MAX_SMART_REFLEX_PARAM); |
| |
| COMPARE_N_ADD("SRF3", l, val, |
| gp->srf3, WL1271_INI_MAX_SMART_REFLEX_PARAM); |
| |
| 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, 1); |
| |
| COMPARE_N_ADD("TXTraceLoss_2_4G", l, val, |
| &gp->tx_trace_loss, 1); |
| |
| COMPARE_N_ADD("RxRssiAndProcessCompensation_2_4G", l, val, |
| gp->rx_rssi_process_compens, |
| WL1271_INI_RSSI_PROCESS_COMPENS_SIZE); |
| |
| 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, 1); |
| |
| COMPARE_N_ADD("TxTraceLoss_2_4G", l, val, |
| gp->tx_trace_loss, WL1271_INI_CHANNEL_COUNT_2); |
| |
| 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, 7); |
| |
| COMPARE_N_ADD("TXTraceLoss_5G", l, val, |
| gp->tx_trace_loss, 7); |
| |
| COMPARE_N_ADD("RxRssiAndProcessCompensation_5G", l, val, |
| gp->rx_rssi_process_compens, |
| WL1271_INI_RSSI_PROCESS_COMPENS_SIZE); |
| |
| 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, 7); |
| |
| COMPARE_N_ADD("TxTraceLoss_5G", l, val, |
| gp->tx_trace_loss, 7); |
| |
| 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, 1); |
| |
| COMPARE_N_ADD("FEM0_TxBiPReferencePower_2_4G", l, val, |
| &gp->tx_bip_ref_power, 1); |
| |
| COMPARE_N_ADD("FEM0_TxBiPOffsetdB_2_4G", l, val, |
| &gp->tx_bip_ref_offset, 1); |
| |
| COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Normal", l, val, |
| gp->tx_per_rate_pwr_limits_normal, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Degraded", l, val, |
| gp->tx_per_rate_pwr_limits_degraded, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Extreme", l, val, |
| gp->tx_per_rate_pwr_limits_extreme, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_DegradedLowToNormalThr_2_4G", l, val, |
| &gp->degraded_low_to_normal_thr, 1); |
| |
| COMPARE_N_ADD("FEM0_NormalToDegradedHighThr_2_4G", l, val, |
| &gp->normal_to_degraded_high_thr, 1); |
| |
| COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_11b", l, val, |
| gp->tx_per_chan_pwr_limits_11b, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_OFDM", l, val, |
| gp->tx_per_chan_pwr_limits_ofdm, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM0_TxPDVsRateOffsets_2_4G", l, val, |
| gp->tx_pd_vs_rate_offsets, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_TxIbiasTable_2_4G", l, val, |
| gp->tx_ibias, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_RxFemInsertionLoss_2_4G", l, val, |
| &gp->rx_fem_insertion_loss, 1); |
| |
| 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, 1); |
| |
| COMPARE_N_ADD("FEM0_TxBiPReferencePower_2_4G", l, val, |
| &gp->tx_bip_ref_power, 1); |
| |
| COMPARE_N_ADD("FEM0_TxBiPOffsetdB_2_4G", l, val, |
| &gp->tx_bip_ref_offset, 1); |
| |
| COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Normal", l, val, |
| gp->tx_per_rate_pwr_limits_normal, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Degraded", l, val, |
| gp->tx_per_rate_pwr_limits_degraded, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Extreme", l, val, |
| gp->tx_per_rate_pwr_limits_extreme, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_DegradedLowToNormalThr_2_4G", l, val, |
| &gp->degraded_low_to_normal_thr, 1); |
| |
| COMPARE_N_ADD("FEM0_NormalToDegradedHighThr_2_4G", l, val, |
| &gp->normal_to_degraded_high_thr, 1); |
| |
| COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_11b", l, val, |
| gp->tx_per_chan_pwr_limits_11b, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_OFDM", l, val, |
| gp->tx_per_chan_pwr_limits_ofdm, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM0_TxPDVsRateOffsets_2_4G", l, val, |
| gp->tx_pd_vs_rate_offsets, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_TxPDVsChannelOffsets_2_4G", l, val, |
| gp->tx_pd_vs_chan_offsets, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM0_TxPDVsTemperature_2_4G", l, val, |
| gp->tx_pd_vs_temperature, |
| WL128X_INI_PD_VS_TEMPERATURE_RANGES); |
| |
| COMPARE_N_ADD("FEM0_TxIbiasTable_2_4G", l, val, |
| gp->tx_ibias, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM0_RxFemInsertionLoss_2_4G", l, val, |
| &gp->rx_fem_insertion_loss, 1); |
| |
| 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, 1); |
| |
| COMPARE_N_ADD("FEM1_TxBiPReferencePower_2_4G", l, val, |
| &gp->tx_bip_ref_power, 1); |
| |
| COMPARE_N_ADD("FEM1_TxBiPOffsetdB_2_4G", l, val, |
| &gp->tx_bip_ref_offset, 1); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Normal", l, val, |
| gp->tx_per_rate_pwr_limits_normal, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Degraded", l, val, |
| gp->tx_per_rate_pwr_limits_degraded, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Extreme", l, val, |
| gp->tx_per_rate_pwr_limits_extreme, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_2_4G", l, val, |
| &gp->degraded_low_to_normal_thr, 1); |
| |
| COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_2_4G", l, val, |
| &gp->normal_to_degraded_high_thr, 1); |
| |
| COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_11b", l, val, |
| gp->tx_per_chan_pwr_limits_11b, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_OFDM", l, val, |
| gp->tx_per_chan_pwr_limits_ofdm, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_2_4G", l, val, |
| gp->tx_pd_vs_rate_offsets, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxIbiasTable_2_4G", l, val, |
| gp->tx_ibias, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_RxFemInsertionLoss_2_4G", l, val, |
| &gp->rx_fem_insertion_loss, 1); |
| |
| 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, 1); |
| |
| COMPARE_N_ADD("FEM1_TxBiPReferencePower_2_4G", l, val, |
| &gp->tx_bip_ref_power, 1); |
| |
| COMPARE_N_ADD("FEM1_TxBiPOffsetdB_2_4G", l, val, |
| &gp->tx_bip_ref_offset, 1); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Normal", l, val, |
| gp->tx_per_rate_pwr_limits_normal, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Degraded", l, val, |
| gp->tx_per_rate_pwr_limits_degraded, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Extreme", l, val, |
| gp->tx_per_rate_pwr_limits_extreme, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_2_4G", l, val, |
| &gp->degraded_low_to_normal_thr, 1); |
| |
| COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_2_4G", l, val, |
| &gp->normal_to_degraded_high_thr, 1); |
| |
| COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_11b", l, val, |
| gp->tx_per_chan_pwr_limits_11b, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_OFDM", l, val, |
| gp->tx_per_chan_pwr_limits_ofdm, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_2_4G", l, val, |
| gp->tx_pd_vs_rate_offsets, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPDVsChannelOffsets_2_4G", l, val, |
| gp->tx_pd_vs_chan_offsets, |
| WL1271_INI_CHANNEL_COUNT_2); |
| |
| COMPARE_N_ADD("FEM1_TxPDVsTemperature_2_4G", l, val, |
| gp->tx_pd_vs_temperature, |
| WL128X_INI_PD_VS_TEMPERATURE_RANGES); |
| |
| COMPARE_N_ADD("FEM1_TxIbiasTable_2_4G", l, val, |
| gp->tx_ibias, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_RxFemInsertionLoss_2_4G", l, val, |
| &gp->rx_fem_insertion_loss, 1); |
| |
| 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, WL1271_INI_SUB_BAND_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxBiPReferencePower_5G", l, val, |
| gp->tx_bip_ref_power, WL1271_INI_SUB_BAND_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxBiPOffsetdB_5G", l, val, |
| gp->tx_bip_ref_offset, WL1271_INI_SUB_BAND_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Normal", l, val, |
| gp->tx_per_rate_pwr_limits_normal, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Degraded", l, val, |
| gp->tx_per_rate_pwr_limits_degraded, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Extreme", l, val, |
| gp->tx_per_rate_pwr_limits_extreme, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_5G", l, val, |
| &gp->degraded_low_to_normal_thr, 1); |
| |
| COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_5G", l, val, |
| &gp->normal_to_degraded_high_thr, 1); |
| |
| COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_5G_OFDM", l, val, |
| gp->tx_per_chan_pwr_limits_ofdm, |
| WL1271_INI_CHANNEL_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_5G", l, val, |
| gp->tx_pd_vs_rate_offsets, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxIbiasTable_5G", l, val, |
| gp->tx_ibias, |
| WL1271_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_RxFemInsertionLoss_5G", l, val, |
| gp->rx_fem_insertion_loss, WL1271_INI_SUB_BAND_COUNT_5); |
| |
| 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, WL1271_INI_SUB_BAND_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxBiPReferencePower_5G", l, val, |
| gp->tx_bip_ref_power, WL1271_INI_SUB_BAND_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxBiPOffsetdB_5G", l, val, |
| gp->tx_bip_ref_offset, WL1271_INI_SUB_BAND_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Normal", l, val, |
| gp->tx_per_rate_pwr_limits_normal, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Degraded", l, val, |
| gp->tx_per_rate_pwr_limits_degraded, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Extreme", l, val, |
| gp->tx_per_rate_pwr_limits_extreme, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_5G", l, val, |
| &gp->degraded_low_to_normal_thr, 1); |
| |
| COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_5G", l, val, |
| &gp->normal_to_degraded_high_thr, 1); |
| |
| COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_5G_OFDM", l, val, |
| gp->tx_per_chan_pwr_limits_ofdm, |
| WL1271_INI_CHANNEL_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_5G", l, val, |
| gp->tx_pd_vs_rate_offsets, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_TxPDVsChannelOffsets_5G", l, val, |
| gp->tx_pd_vs_chan_offsets, |
| WL1271_INI_CHANNEL_COUNT_5); |
| |
| COMPARE_N_ADD("FEM1_TxPDVsTemperature_5G", l, val, |
| gp->tx_pd_vs_temperature, |
| WL1271_INI_SUB_BAND_COUNT_5 * WL128X_INI_PD_VS_TEMPERATURE_RANGES); |
| |
| COMPARE_N_ADD("FEM1_TxIbiasTable_5G", l, val, |
| gp->tx_ibias, |
| WL128X_INI_RATE_GROUP_COUNT); |
| |
| COMPARE_N_ADD("FEM1_RxFemInsertionLoss_5G", l, val, |
| gp->rx_fem_insertion_loss, WL1271_INI_SUB_BAND_COUNT_5); |
| |
| 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, 1); |
| |
| fprintf(stderr, "Unable to parse: (%s)\n", l); |
| |
| return 1; |
| } |
| |
| static int find_section(const char *l, enum wl1271_ini_section *st, int *cntr, |
| enum wl12xx_arch 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; |
| 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; |
| if (arch == WL128X_ARCH) { |
| *cntr = 15; |
| } else { |
| *cntr = 13; |
| } |
| |
| return 0; |
| } |
| |
| if (strncmp("FEM1_TXBiPReferencePDvoltage_5G", l, 31) == 0 || |
| strncmp("FEM1_TxBiPReferencePDvoltage_5G", l, 31) == 0) { |
| *st = FEM1_BAND5_PRMS; |
| if (arch == WL128X_ARCH) { |
| *cntr = 14; |
| } else { |
| *cntr = 12; |
| } |
| |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int ini_parse_line(char *l, int nbr, struct wl12xx_common *cmn) |
| { |
| static enum wl1271_ini_section status; |
| static int cntr; |
| |
| if (!cntr && find_section(l, &status, &cntr, cmn->arch)) { |
| 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 FEM1_BAND5_PRMS: /* FEM1 band 5GHz parameters */ |
| cntr--; |
| return cmn->parse_ops->prs_fem1_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 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_fem1_band5_prms = parse_fem1_band5_prms, |
| }; |
| |
| 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_fem1_band5_prms = parse_fem1_band5_prms_128x, |
| }; |
| |
| 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; |
| |
| 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, line, cmn); |
| if (ret) break; |
| } |
| |
| out: |
| fclose(f); |
| #if 0 |
| ini_dump(ini); |
| #endif |
| return ret; |
| } |