Home | History | Annotate | Download | only in ti-utils
      1 /*
      2  * PLT utility for wireless chip supported by TI's driver wl12xx
      3  *
      4  * See README and COPYING for more details.
      5  */
      6 
      7 #include <sys/ioctl.h>
      8 #include <errno.h>
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 #include <sys/stat.h>
     13 #include <fcntl.h>
     14 #include <unistd.h>
     15 #include <stdbool.h>
     16 
     17 #include <netlink/genl/genl.h>
     18 #include <netlink/genl/family.h>
     19 #include <netlink/genl/ctrl.h>
     20 #include <netlink/msg.h>
     21 #include <netlink/attr.h>
     22 #include <linux/wireless.h>
     23 #include "nl80211.h"
     24 
     25 #include "calibrator.h"
     26 #include "plt.h"
     27 #include "ini.h"
     28 #include "nvs.h"
     29 
     30 static char *ini_get_line(char *s, int size, FILE *stream, int *line,
     31 				  char **_pos)
     32 {
     33 	char *pos, *end, *sstart;
     34 
     35 	while (fgets(s, size, stream)) {
     36 		s[size - 1] = '\0';
     37 		pos = s;
     38 
     39 		/* Skip white space from the beginning of line. */
     40 		while (*pos == ' ' || *pos == '\t' || *pos == '\r') {
     41 			pos++;
     42                 }
     43 
     44 		/* Skip comment lines and empty lines */
     45 		if (*pos == '#' || *pos == '\n' || *pos == '\0') {
     46 			continue;
     47                 }
     48 
     49 		/*
     50 		 * Remove # comments unless they are within a double quoted
     51 		 * string.
     52 		 */
     53 		sstart = strchr(pos, '"');
     54 		if (sstart) {
     55 			sstart = strrchr(sstart + 1, '"');
     56                 }
     57 		if (!sstart) {
     58 			sstart = pos;
     59                 }
     60 		end = strchr(sstart, '#');
     61 		if (end) {
     62 			*end-- = '\0';
     63                 } else {
     64 			end = pos + strlen(pos) - 1;
     65                 }
     66 
     67 		/* Remove trailing white space. */
     68 		while (end > pos &&
     69 		       (*end == '\n' || *end == ' ' || *end == '\t' ||
     70 			*end == '\r')) {
     71 			*end-- = '\0';
     72                 }
     73 
     74 		if (*pos == '\0') {
     75 			continue;
     76                 }
     77 
     78 		(*line)++;
     79 
     80 		if (_pos) {
     81 			*_pos = pos;
     82                 }
     83 		return pos;
     84 	}
     85 
     86 	if (_pos) {
     87 		*_pos = NULL;
     88         }
     89 
     90 	return NULL;
     91 }
     92 
     93 static int split_line(char *line, char **name, char **value)
     94 {
     95 	char *pos = line;
     96 
     97 	*value = strchr(pos, '=');
     98 	if (!*value) {
     99 		fprintf(stderr, "Wrong format of line\n");
    100 		return 1;
    101 	}
    102 
    103 	*name = *value;
    104 
    105 	(*name)--;
    106 	while (**name == ' ' || **name == '\t' || **name == '\r') {
    107 		(*name)--;
    108         }
    109 
    110 	*++(*name) = '\0';
    111 
    112 	(*value)++;
    113 	while (**value == ' ' || **value == '\t' || **value == '\r') {
    114 		(*value)++;
    115         }
    116 
    117 	return 0;
    118 }
    119 
    120 #define COMPARE_N_ADD(temp, str, val, ptr, size)		\
    121 	if (strncmp(temp, str, sizeof(temp)) == 0) {		\
    122 		int i;						\
    123 		unsigned char *p = ptr;				\
    124 		for (i = 0; i < size; i++) {			\
    125 			*p = strtol(val, NULL, 16);		\
    126 			if (i != sizeof(ptr)-1) {		\
    127 				val += 3; p++;			\
    128 			}					\
    129 		}						\
    130 		return 0;					\
    131 	}
    132 
    133 #define DBG_COMPARE_N_ADD(temp, str, val, ptr, size)		\
    134 	if (strncmp(temp, str, sizeof(temp)) == 0) {		\
    135 		int i;						\
    136 		unsigned char *p = ptr;				\
    137 		for (i = 0; i < size; i++) {			\
    138 			*p = strtol(val, NULL, 16);		\
    139 			if (i != sizeof(ptr)-1) {		\
    140 				val += 3; p++;			\
    141 			}					\
    142 		}						\
    143 		p = ptr;					\
    144 		printf("%s ", temp);				\
    145 		for (i = 0; i < size; i++) {			\
    146 			printf("%02X ", *p);			\
    147 			p++;					\
    148 		}						\
    149 		printf("\n");					\
    150 		return 0;					\
    151 	}
    152 
    153 #define COMPARE_N_ADD2(temp, str, val, ptr, size)		\
    154 	if (strncmp(temp, str, sizeof(temp)) == 0) {		\
    155 		int i;						\
    156 		unsigned short *p = ptr;			\
    157 		for (i = 0; i < size; i++) {			\
    158 			*p = strtol(val, NULL, 16);		\
    159 			if (i != sizeof(ptr)-1) {		\
    160 				val += 5; p++;			\
    161 			}					\
    162 		}						\
    163 		return 0;					\
    164 	}
    165 
    166 #define DBG_COMPARE_N_ADD2(temp, str, val, ptr, size)		\
    167 	if (strncmp(temp, str, sizeof(temp)) == 0) {		\
    168 		int i;						\
    169 		unsigned short *p = ptr;			\
    170 		for (i = 0; i < size; i++) {			\
    171 			*p = strtol(val, NULL, 16);		\
    172 			if (i != sizeof(ptr)-1) {		\
    173 				val += 5; p++;			\
    174 			}					\
    175 		}						\
    176 		p = ptr;					\
    177 		printf("%s ", temp);				\
    178 		for (i = 0; i < size; i++) {			\
    179 			printf("%04X ", *p);			\
    180 			p++;					\
    181 		}						\
    182 		printf("\n");					\
    183 		return 0;					\
    184 	}
    185 
    186 static int parse_general_prms(char *l, struct wl12xx_common *cmn,
    187 	struct wl12xx_ini *p)
    188 {
    189 	char *name, *val;
    190 	struct wl1271_ini_general_params *gp = &(p->ini1271.general_params);
    191 
    192 	if (split_line(l, &name, &val)) {
    193 		return 1;
    194         }
    195 
    196 	COMPARE_N_ADD("TXBiPFEMAutoDetect", l, val,
    197 		&gp->tx_bip_fem_auto_detect, 1);
    198 
    199 	COMPARE_N_ADD("TXBiPFEMManufacturer", l, val,
    200 		&gp->tx_bip_fem_manufacturer, 1);
    201 
    202 	COMPARE_N_ADD("RefClk", l, val, &gp->ref_clock, 1);
    203 
    204 	COMPARE_N_ADD("SettlingTime", l, val, &gp->settling_time, 1);
    205 
    206 	COMPARE_N_ADD("ClockValidOnWakeup", l, val,
    207 		&gp->clk_valid_on_wakeup, 1);
    208 
    209 	COMPARE_N_ADD("DC2DCMode", l, val, &gp->dc2dc_mode, 1);
    210 
    211 	COMPARE_N_ADD("Single_Dual_Band_Solution", l, val,
    212 		&gp->dual_mode_select, 1);
    213 
    214 	if (cmn->dual_mode == DUAL_MODE_UNSET) {
    215 		cmn->dual_mode = gp->dual_mode_select;
    216         }
    217 	else if (cmn->dual_mode != gp->dual_mode_select) {
    218 		fprintf(stderr, "Error, FEMs with different dual modes\n");
    219 		return 1;
    220 	}
    221 
    222 	COMPARE_N_ADD("Settings", l, val, &gp->general_settings, 1);
    223 
    224 	COMPARE_N_ADD("SRState", l, val, &gp->sr_state, 1);
    225 
    226 	COMPARE_N_ADD("SRF1", l, val,
    227 		gp->srf1, WL1271_INI_MAX_SMART_REFLEX_PARAM);
    228 
    229 	COMPARE_N_ADD("SRF2", l, val,
    230 		gp->srf2, WL1271_INI_MAX_SMART_REFLEX_PARAM);
    231 
    232 	COMPARE_N_ADD("SRF3", l, val,
    233 		gp->srf3, WL1271_INI_MAX_SMART_REFLEX_PARAM);
    234 
    235 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    236 
    237 	return 1;
    238 }
    239 
    240 static int parse_general_prms_128x(char *l, struct wl12xx_common *cmn,
    241 	struct wl12xx_ini *p)
    242 {
    243 	char *name, *val;
    244 	struct wl128x_ini_general_params *gp =
    245 		&(p->ini128x.general_params);
    246 
    247 	if (split_line(l, &name, &val)) {
    248 		return 1;
    249         }
    250 
    251 	COMPARE_N_ADD("TXBiPFEMAutoDetect", l, val,
    252 		&gp->tx_bip_fem_auto_detect, 1);
    253 
    254 	COMPARE_N_ADD("TXBiPFEMManufacturer", l, val,
    255 		&gp->tx_bip_fem_manufacturer, 1);
    256 
    257 	COMPARE_N_ADD("RefClk", l, val, &gp->ref_clock, 1);
    258 
    259 	COMPARE_N_ADD("SettlingTime", l, val, &gp->settling_time, 1);
    260 
    261 	COMPARE_N_ADD("ClockValidOnWakeup", l, val,
    262 		&gp->clk_valid_on_wakeup, 1);
    263 
    264 	COMPARE_N_ADD("TCXO_Clk", l, val, &gp->tcxo_ref_clock, 1);
    265 
    266 	COMPARE_N_ADD("TCXO_SettlingTime", l, val, &gp->tcxo_settling_time, 1);
    267 
    268 	COMPARE_N_ADD("TCXO_ClockValidOnWakeup", l, val,
    269 		&gp->tcxo_valid_on_wakeup, 1);
    270 
    271 	COMPARE_N_ADD("TCXO_LDO_Voltage", l, val,
    272 		&gp->tcxo_ldo_voltage, 1);
    273 
    274 	COMPARE_N_ADD("Platform_configuration", l, val,
    275 		&gp->platform_conf, 1);
    276 
    277 	COMPARE_N_ADD("Single_Dual_Band_Solution", l, val,
    278 		&gp->dual_mode_select, 1);
    279 
    280 	if (cmn->dual_mode == DUAL_MODE_UNSET) {
    281 		cmn->dual_mode = gp->dual_mode_select;
    282         } else if (cmn->dual_mode != gp->dual_mode_select) {
    283 		fprintf(stderr, "Error, FEMs with diferent dual modes\n");
    284 		return 1;
    285 	}
    286 
    287 	COMPARE_N_ADD("Settings", l, val,
    288 		gp->general_settings, WL128X_INI_MAX_SETTINGS_PARAM);
    289 
    290 	COMPARE_N_ADD("XTALItrimVal", l, val, &gp->xtal_itrim_val, 1);
    291 
    292 	COMPARE_N_ADD("SRState", l, val, &gp->sr_state, 1);
    293 
    294 	COMPARE_N_ADD("SRF1", l, val,
    295 		gp->srf1, WL1271_INI_MAX_SMART_REFLEX_PARAM);
    296 
    297 	COMPARE_N_ADD("SRF2", l, val,
    298 		gp->srf2, WL1271_INI_MAX_SMART_REFLEX_PARAM);
    299 
    300 	COMPARE_N_ADD("SRF3", l, val,
    301 		gp->srf3, WL1271_INI_MAX_SMART_REFLEX_PARAM);
    302 
    303 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    304 
    305 	return 1;
    306 }
    307 
    308 static int parse_band2_prms(char *l, struct wl12xx_ini *p)
    309 {
    310 	char *name, *val;
    311 	struct wl1271_ini_band_params_2 *gp =
    312 		&(p->ini1271.stat_radio_params_2);
    313 
    314 	if (split_line(l, &name, &val)) {
    315 		return 1;
    316         }
    317 
    318 	COMPARE_N_ADD("RxTraceInsertionLoss_2_4G", l, val,
    319 		&gp->rx_trace_insertion_loss, 1);
    320 
    321 	COMPARE_N_ADD("TXTraceLoss_2_4G", l, val,
    322 		&gp->tx_trace_loss, 1);
    323 
    324 	COMPARE_N_ADD("RxRssiAndProcessCompensation_2_4G", l, val,
    325 		gp->rx_rssi_process_compens,
    326 		WL1271_INI_RSSI_PROCESS_COMPENS_SIZE);
    327 
    328 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    329 
    330 	return 1;
    331 }
    332 
    333 static int parse_band2_prms_128x(char *l, struct wl12xx_ini *p)
    334 {
    335 	char *name, *val;
    336 	struct wl128x_ini_band_params_2 *gp = &(p->ini128x.stat_radio_params_2);
    337 
    338 	if (split_line(l, &name, &val)) {
    339 		return 1;
    340         }
    341 
    342 	COMPARE_N_ADD("RxTraceInsertionLoss_2_4G", l, val,
    343 		&gp->rx_trace_insertion_loss, 1);
    344 
    345 	COMPARE_N_ADD("TxTraceLoss_2_4G", l, val,
    346 		gp->tx_trace_loss, WL1271_INI_CHANNEL_COUNT_2);
    347 
    348 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    349 
    350 	return 1;
    351 }
    352 
    353 static int parse_band5_prms(char *l, struct wl12xx_ini *p)
    354 {
    355 	char *name, *val;
    356 	struct wl1271_ini_band_params_5 *gp =
    357 		&(p->ini1271.stat_radio_params_5);
    358 
    359 	if (split_line(l, &name, &val)) {
    360 		return 1;
    361         }
    362 
    363 	COMPARE_N_ADD("RxTraceInsertionLoss_5G", l, val,
    364 		gp->rx_trace_insertion_loss, 7);
    365 
    366 	COMPARE_N_ADD("TXTraceLoss_5G", l, val,
    367 		gp->tx_trace_loss, 7);
    368 
    369 	COMPARE_N_ADD("RxRssiAndProcessCompensation_5G", l, val,
    370 		gp->rx_rssi_process_compens,
    371 		WL1271_INI_RSSI_PROCESS_COMPENS_SIZE);
    372 
    373 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    374 
    375 	return 1;
    376 }
    377 
    378 static int parse_band5_prms_128x(char *l, struct wl12xx_ini *p)
    379 {
    380 	char *name, *val;
    381 	struct wl128x_ini_band_params_5 *gp = &(p->ini128x.stat_radio_params_5);
    382 
    383 	if (split_line(l, &name, &val)) {
    384 		return 1;
    385         }
    386 
    387 	COMPARE_N_ADD("RxTraceInsertionLoss_5G", l, val,
    388 		gp->rx_trace_insertion_loss, 7);
    389 
    390 	COMPARE_N_ADD("TxTraceLoss_5G", l, val,
    391 		gp->tx_trace_loss, 7);
    392 
    393 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    394 
    395 	return 1;
    396 }
    397 
    398 static int parse_fem0_band2_prms(char *l, struct wl12xx_ini *p)
    399 {
    400 	char *name, *val;
    401 	struct wl1271_ini_fem_params_2 *gp =
    402 		&(p->ini1271.dyn_radio_params_2[0].params);
    403 
    404 	if (split_line(l, &name, &val)) {
    405 		return 1;
    406         }
    407 
    408 	COMPARE_N_ADD2("FEM0_TXBiPReferencePDvoltage_2_4G", l, val,
    409 		&gp->tx_bip_ref_pd_voltage, 1);
    410 
    411 	COMPARE_N_ADD("FEM0_TxBiPReferencePower_2_4G", l, val,
    412 		&gp->tx_bip_ref_power, 1);
    413 
    414 	COMPARE_N_ADD("FEM0_TxBiPOffsetdB_2_4G", l, val,
    415 		&gp->tx_bip_ref_offset, 1);
    416 
    417 	COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Normal", l, val,
    418 		gp->tx_per_rate_pwr_limits_normal,
    419 		WL1271_INI_RATE_GROUP_COUNT);
    420 
    421 	COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Degraded", l, val,
    422 		gp->tx_per_rate_pwr_limits_degraded,
    423 		WL1271_INI_RATE_GROUP_COUNT);
    424 
    425 	COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Extreme", l, val,
    426 		gp->tx_per_rate_pwr_limits_extreme,
    427 		WL1271_INI_RATE_GROUP_COUNT);
    428 
    429 	COMPARE_N_ADD("FEM0_DegradedLowToNormalThr_2_4G", l, val,
    430 		&gp->degraded_low_to_normal_thr, 1);
    431 
    432 	COMPARE_N_ADD("FEM0_NormalToDegradedHighThr_2_4G", l, val,
    433 		&gp->normal_to_degraded_high_thr, 1);
    434 
    435 	COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_11b", l, val,
    436 		gp->tx_per_chan_pwr_limits_11b,
    437 		WL1271_INI_CHANNEL_COUNT_2);
    438 
    439 	COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
    440 		gp->tx_per_chan_pwr_limits_ofdm,
    441 		WL1271_INI_CHANNEL_COUNT_2);
    442 
    443 	COMPARE_N_ADD("FEM0_TxPDVsRateOffsets_2_4G", l, val,
    444 		gp->tx_pd_vs_rate_offsets,
    445 		WL1271_INI_RATE_GROUP_COUNT);
    446 
    447 	COMPARE_N_ADD("FEM0_TxIbiasTable_2_4G", l, val,
    448 		gp->tx_ibias,
    449 		WL1271_INI_RATE_GROUP_COUNT);
    450 
    451 	COMPARE_N_ADD("FEM0_RxFemInsertionLoss_2_4G", l, val,
    452 		&gp->rx_fem_insertion_loss, 1);
    453 
    454 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    455 
    456 	return 1;
    457 }
    458 
    459 static int parse_fem0_band2_prms_128x(char *l, struct wl12xx_ini *p)
    460 {
    461 	char *name, *val;
    462 	struct wl128x_ini_fem_params_2 *gp =
    463 		&(p->ini128x.dyn_radio_params_2[0].params);
    464 
    465 	if (split_line(l, &name, &val)) {
    466 		return 1;
    467         }
    468 
    469 	COMPARE_N_ADD2("FEM0_TxBiPReferencePDvoltage_2_4G", l, val,
    470 		&gp->tx_bip_ref_pd_voltage, 1);
    471 
    472 	COMPARE_N_ADD("FEM0_TxBiPReferencePower_2_4G", l, val,
    473 		&gp->tx_bip_ref_power, 1);
    474 
    475 	COMPARE_N_ADD("FEM0_TxBiPOffsetdB_2_4G", l, val,
    476 		&gp->tx_bip_ref_offset, 1);
    477 
    478 	COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Normal", l, val,
    479 		gp->tx_per_rate_pwr_limits_normal,
    480 		WL1271_INI_RATE_GROUP_COUNT);
    481 
    482 	COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Degraded", l, val,
    483 		gp->tx_per_rate_pwr_limits_degraded,
    484 		WL1271_INI_RATE_GROUP_COUNT);
    485 
    486 	COMPARE_N_ADD("FEM0_TxPerRatePowerLimits_2_4G_Extreme", l, val,
    487 		gp->tx_per_rate_pwr_limits_extreme,
    488 		WL1271_INI_RATE_GROUP_COUNT);
    489 
    490 	COMPARE_N_ADD("FEM0_DegradedLowToNormalThr_2_4G", l, val,
    491 		&gp->degraded_low_to_normal_thr, 1);
    492 
    493 	COMPARE_N_ADD("FEM0_NormalToDegradedHighThr_2_4G", l, val,
    494 		&gp->normal_to_degraded_high_thr, 1);
    495 
    496 	COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_11b", l, val,
    497 		gp->tx_per_chan_pwr_limits_11b,
    498 		WL1271_INI_CHANNEL_COUNT_2);
    499 
    500 	COMPARE_N_ADD("FEM0_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
    501 		gp->tx_per_chan_pwr_limits_ofdm,
    502 		WL1271_INI_CHANNEL_COUNT_2);
    503 
    504 	COMPARE_N_ADD("FEM0_TxPDVsRateOffsets_2_4G", l, val,
    505 		gp->tx_pd_vs_rate_offsets,
    506 		WL1271_INI_RATE_GROUP_COUNT);
    507 
    508 	COMPARE_N_ADD("FEM0_TxPDVsChannelOffsets_2_4G", l, val,
    509 		gp->tx_pd_vs_chan_offsets,
    510 		WL1271_INI_CHANNEL_COUNT_2);
    511 
    512 	COMPARE_N_ADD("FEM0_TxPDVsTemperature_2_4G", l, val,
    513 		gp->tx_pd_vs_temperature,
    514 		WL128X_INI_PD_VS_TEMPERATURE_RANGES);
    515 
    516 	COMPARE_N_ADD("FEM0_TxIbiasTable_2_4G", l, val,
    517 		gp->tx_ibias,
    518 		WL1271_INI_RATE_GROUP_COUNT);
    519 
    520 	COMPARE_N_ADD("FEM0_RxFemInsertionLoss_2_4G", l, val,
    521 		&gp->rx_fem_insertion_loss, 1);
    522 
    523 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    524 
    525 	return 1;
    526 }
    527 
    528 static int parse_fem1_band2_prms(char *l, struct wl12xx_ini *p)
    529 {
    530 	char *name, *val;
    531 	struct wl1271_ini_fem_params_2 *gp =
    532 		&(p->ini1271.dyn_radio_params_2[1].params);
    533 
    534 	if (split_line(l, &name, &val)) {
    535 		return 1;
    536         }
    537 
    538 	COMPARE_N_ADD2("FEM1_TXBiPReferencePDvoltage_2_4G", l, val,
    539 		&gp->tx_bip_ref_pd_voltage, 1);
    540 
    541 	COMPARE_N_ADD("FEM1_TxBiPReferencePower_2_4G", l, val,
    542 		&gp->tx_bip_ref_power, 1);
    543 
    544 	COMPARE_N_ADD("FEM1_TxBiPOffsetdB_2_4G", l, val,
    545 		&gp->tx_bip_ref_offset, 1);
    546 
    547 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Normal", l, val,
    548 		gp->tx_per_rate_pwr_limits_normal,
    549 		WL1271_INI_RATE_GROUP_COUNT);
    550 
    551 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Degraded", l, val,
    552 		gp->tx_per_rate_pwr_limits_degraded,
    553 		WL1271_INI_RATE_GROUP_COUNT);
    554 
    555 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Extreme", l, val,
    556 		gp->tx_per_rate_pwr_limits_extreme,
    557 		WL1271_INI_RATE_GROUP_COUNT);
    558 
    559 	COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_2_4G", l, val,
    560 		&gp->degraded_low_to_normal_thr, 1);
    561 
    562 	COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_2_4G", l, val,
    563 		&gp->normal_to_degraded_high_thr, 1);
    564 
    565 	COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_11b", l, val,
    566 		gp->tx_per_chan_pwr_limits_11b,
    567 		WL1271_INI_CHANNEL_COUNT_2);
    568 
    569 	COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
    570 		gp->tx_per_chan_pwr_limits_ofdm,
    571 		WL1271_INI_CHANNEL_COUNT_2);
    572 
    573 	COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_2_4G", l, val,
    574 		gp->tx_pd_vs_rate_offsets,
    575 		WL1271_INI_RATE_GROUP_COUNT);
    576 
    577 	COMPARE_N_ADD("FEM1_TxIbiasTable_2_4G", l, val,
    578 		gp->tx_ibias,
    579 		WL1271_INI_RATE_GROUP_COUNT);
    580 
    581 	COMPARE_N_ADD("FEM1_RxFemInsertionLoss_2_4G", l, val,
    582 		&gp->rx_fem_insertion_loss, 1);
    583 
    584 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    585 
    586 	return 1;
    587 }
    588 
    589 static int parse_fem1_band2_prms_128x(char *l, struct wl12xx_ini *p)
    590 {
    591 	char *name, *val;
    592 	struct wl128x_ini_fem_params_2 *gp =
    593 		&(p->ini128x.dyn_radio_params_2[1].params);
    594 
    595 	if (split_line(l, &name, &val)) {
    596 		return 1;
    597         }
    598 
    599 	COMPARE_N_ADD2("FEM1_TxBiPReferencePDvoltage_2_4G", l, val,
    600 		&gp->tx_bip_ref_pd_voltage, 1);
    601 
    602 	COMPARE_N_ADD("FEM1_TxBiPReferencePower_2_4G", l, val,
    603 		&gp->tx_bip_ref_power, 1);
    604 
    605 	COMPARE_N_ADD("FEM1_TxBiPOffsetdB_2_4G", l, val,
    606 		&gp->tx_bip_ref_offset, 1);
    607 
    608 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Normal", l, val,
    609 		gp->tx_per_rate_pwr_limits_normal,
    610 		WL128X_INI_RATE_GROUP_COUNT);
    611 
    612 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Degraded", l, val,
    613 		gp->tx_per_rate_pwr_limits_degraded,
    614 		WL128X_INI_RATE_GROUP_COUNT);
    615 
    616 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_2_4G_Extreme", l, val,
    617 		gp->tx_per_rate_pwr_limits_extreme,
    618 		WL128X_INI_RATE_GROUP_COUNT);
    619 
    620 	COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_2_4G", l, val,
    621 		&gp->degraded_low_to_normal_thr, 1);
    622 
    623 	COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_2_4G", l, val,
    624 		&gp->normal_to_degraded_high_thr, 1);
    625 
    626 	COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_11b", l, val,
    627 		gp->tx_per_chan_pwr_limits_11b,
    628 		WL1271_INI_CHANNEL_COUNT_2);
    629 
    630 	COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_2_4G_OFDM", l, val,
    631 		gp->tx_per_chan_pwr_limits_ofdm,
    632 		WL1271_INI_CHANNEL_COUNT_2);
    633 
    634 	COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_2_4G", l, val,
    635 		gp->tx_pd_vs_rate_offsets,
    636 		WL128X_INI_RATE_GROUP_COUNT);
    637 
    638 	COMPARE_N_ADD("FEM1_TxPDVsChannelOffsets_2_4G", l, val,
    639 		gp->tx_pd_vs_chan_offsets,
    640 		WL1271_INI_CHANNEL_COUNT_2);
    641 
    642 	COMPARE_N_ADD("FEM1_TxPDVsTemperature_2_4G", l, val,
    643 		gp->tx_pd_vs_temperature,
    644 		WL128X_INI_PD_VS_TEMPERATURE_RANGES);
    645 
    646 	COMPARE_N_ADD("FEM1_TxIbiasTable_2_4G", l, val,
    647 		gp->tx_ibias,
    648 		WL128X_INI_RATE_GROUP_COUNT);
    649 
    650 	COMPARE_N_ADD("FEM1_RxFemInsertionLoss_2_4G", l, val,
    651 		&gp->rx_fem_insertion_loss, 1);
    652 
    653 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    654 
    655 	return 1;
    656 }
    657 
    658 static int parse_fem1_band5_prms(char *l, struct wl12xx_ini *p)
    659 {
    660 	char *name, *val;
    661 	struct wl1271_ini_fem_params_5 *gp =
    662 		&(p->ini1271.dyn_radio_params_5[1].params);
    663 
    664 	if (split_line(l, &name, &val)) {
    665 		return 1;
    666         }
    667 
    668 	COMPARE_N_ADD2("FEM1_TXBiPReferencePDvoltage_5G", l, val,
    669 		gp->tx_bip_ref_pd_voltage, WL1271_INI_SUB_BAND_COUNT_5);
    670 
    671 	COMPARE_N_ADD("FEM1_TxBiPReferencePower_5G", l, val,
    672 		gp->tx_bip_ref_power, WL1271_INI_SUB_BAND_COUNT_5);
    673 
    674 	COMPARE_N_ADD("FEM1_TxBiPOffsetdB_5G", l, val,
    675 		gp->tx_bip_ref_offset, WL1271_INI_SUB_BAND_COUNT_5);
    676 
    677 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Normal", l, val,
    678 		gp->tx_per_rate_pwr_limits_normal,
    679 		WL1271_INI_RATE_GROUP_COUNT);
    680 
    681 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Degraded", l, val,
    682 		gp->tx_per_rate_pwr_limits_degraded,
    683 		WL1271_INI_RATE_GROUP_COUNT);
    684 
    685 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Extreme", l, val,
    686 		gp->tx_per_rate_pwr_limits_extreme,
    687 		WL1271_INI_RATE_GROUP_COUNT);
    688 
    689 	COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_5G", l, val,
    690 		&gp->degraded_low_to_normal_thr, 1);
    691 
    692 	COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_5G", l, val,
    693 		&gp->normal_to_degraded_high_thr, 1);
    694 
    695 	COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_5G_OFDM", l, val,
    696 		gp->tx_per_chan_pwr_limits_ofdm,
    697 		WL1271_INI_CHANNEL_COUNT_5);
    698 
    699 	COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_5G", l, val,
    700 		gp->tx_pd_vs_rate_offsets,
    701 		WL1271_INI_RATE_GROUP_COUNT);
    702 
    703 	COMPARE_N_ADD("FEM1_TxIbiasTable_5G", l, val,
    704 		gp->tx_ibias,
    705 		WL1271_INI_RATE_GROUP_COUNT);
    706 
    707 	COMPARE_N_ADD("FEM1_RxFemInsertionLoss_5G", l, val,
    708 		gp->rx_fem_insertion_loss, WL1271_INI_SUB_BAND_COUNT_5);
    709 
    710 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    711 
    712 	return 1;
    713 }
    714 
    715 static int parse_fem1_band5_prms_128x(char *l, struct wl12xx_ini *p)
    716 {
    717 	char *name, *val;
    718 	struct wl128x_ini_fem_params_5 *gp =
    719 		&(p->ini128x.dyn_radio_params_5[1].params);
    720 
    721 	if (split_line(l, &name, &val)) {
    722 		return 1;
    723         }
    724 
    725 	COMPARE_N_ADD2("FEM1_TxBiPReferencePDvoltage_5G", l, val,
    726 		gp->tx_bip_ref_pd_voltage, WL1271_INI_SUB_BAND_COUNT_5);
    727 
    728 	COMPARE_N_ADD("FEM1_TxBiPReferencePower_5G", l, val,
    729 		gp->tx_bip_ref_power, WL1271_INI_SUB_BAND_COUNT_5);
    730 
    731 	COMPARE_N_ADD("FEM1_TxBiPOffsetdB_5G", l, val,
    732 		gp->tx_bip_ref_offset, WL1271_INI_SUB_BAND_COUNT_5);
    733 
    734 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Normal", l, val,
    735 		gp->tx_per_rate_pwr_limits_normal,
    736 		WL128X_INI_RATE_GROUP_COUNT);
    737 
    738 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Degraded", l, val,
    739 		gp->tx_per_rate_pwr_limits_degraded,
    740 		WL128X_INI_RATE_GROUP_COUNT);
    741 
    742 	COMPARE_N_ADD("FEM1_TxPerRatePowerLimits_5G_Extreme", l, val,
    743 		gp->tx_per_rate_pwr_limits_extreme,
    744 		WL128X_INI_RATE_GROUP_COUNT);
    745 
    746 	COMPARE_N_ADD("FEM1_DegradedLowToNormalThr_5G", l, val,
    747 		&gp->degraded_low_to_normal_thr, 1);
    748 
    749 	COMPARE_N_ADD("FEM1_NormalToDegradedHighThr_5G", l, val,
    750 		&gp->normal_to_degraded_high_thr, 1);
    751 
    752 	COMPARE_N_ADD("FEM1_TxPerChannelPowerLimits_5G_OFDM", l, val,
    753 		gp->tx_per_chan_pwr_limits_ofdm,
    754 		WL1271_INI_CHANNEL_COUNT_5);
    755 
    756 	COMPARE_N_ADD("FEM1_TxPDVsRateOffsets_5G", l, val,
    757 		gp->tx_pd_vs_rate_offsets,
    758 		WL128X_INI_RATE_GROUP_COUNT);
    759 
    760 	COMPARE_N_ADD("FEM1_TxPDVsChannelOffsets_5G", l, val,
    761 		gp->tx_pd_vs_chan_offsets,
    762 		WL1271_INI_CHANNEL_COUNT_5);
    763 
    764 	COMPARE_N_ADD("FEM1_TxPDVsTemperature_5G", l, val,
    765 		gp->tx_pd_vs_temperature,
    766 		WL1271_INI_SUB_BAND_COUNT_5 * WL128X_INI_PD_VS_TEMPERATURE_RANGES);
    767 
    768 	COMPARE_N_ADD("FEM1_TxIbiasTable_5G", l, val,
    769 		gp->tx_ibias,
    770 		WL128X_INI_RATE_GROUP_COUNT);
    771 
    772 	COMPARE_N_ADD("FEM1_RxFemInsertionLoss_5G", l, val,
    773 		gp->rx_fem_insertion_loss, WL1271_INI_SUB_BAND_COUNT_5);
    774 
    775 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    776 
    777 	return 1;
    778 }
    779 
    780 static int parse_fem_prms_128x(char *l, struct wl12xx_ini *p)
    781 {
    782 	char *name, *val;
    783 	struct wl128x_ini *gp = &p->ini128x;
    784 
    785 	if (split_line(l, &name, &val)) {
    786 		return 1;
    787         }
    788 
    789 	COMPARE_N_ADD("FemVendorAndOptions", l, val,
    790 		&gp->fem_vendor_and_options, 1);
    791 
    792 	fprintf(stderr, "Unable to parse: (%s)\n", l);
    793 
    794 	return 1;
    795 }
    796 
    797 static int find_section(const char *l, enum wl1271_ini_section *st, int *cntr,
    798 	enum wl12xx_arch arch)
    799 {
    800 	if (strncmp("TXBiPFEMAutoDetect", l, 18) == 0) {
    801 		*st = GENERAL_PRMS;
    802 		if (arch == WL128X_ARCH) {
    803 			*cntr = 17;
    804                 } else {
    805 			*cntr = 12;
    806                 }
    807 
    808 		return 0;
    809 	}
    810 
    811 	if (strncmp("RxTraceInsertionLoss_2_4G", l, 25) == 0) {
    812 		*st = BAND2_PRMS;
    813 		if (arch == WL128X_ARCH){
    814 			*cntr = 2;
    815                 } else {
    816 			*cntr = 3;
    817                 }
    818 
    819 		return 0;
    820 	}
    821 
    822 	if (strncmp("FemVendorAndOptions", l, 19) == 0) {
    823 		*st = FEM_PRMS;
    824 		*cntr = 1;
    825 		return 0;
    826 	}
    827 
    828 	if (strncmp("RxTraceInsertionLoss_5G", l, 23) == 0) {
    829 		*st = BAND5_PRMS;
    830 		if (arch == WL128X_ARCH) {
    831 			*cntr = 2;
    832 		} else {
    833 			*cntr = 3;
    834                 }
    835 
    836 		return 0;
    837 	}
    838 
    839 	if (strncmp("FEM0_TXBiPReferencePDvoltage_2_4G", l, 33) == 0 ||
    840 		strncmp("FEM0_TxBiPReferencePDvoltage_2_4G", l, 33) == 0) {
    841 		*st = FEM0_BAND2_PRMS;
    842 		if (arch == WL128X_ARCH) {
    843 			*cntr = 15;
    844 		} else {
    845 			*cntr = 13;
    846                 }
    847 
    848 		return 0;
    849 	}
    850 
    851 	if (strncmp("FEM1_TXBiPReferencePDvoltage_2_4G", l, 33) == 0 ||
    852 		strncmp("FEM1_TxBiPReferencePDvoltage_2_4G", l, 33) == 0) {
    853 		*st = FEM1_BAND2_PRMS;
    854 		if (arch == WL128X_ARCH) {
    855 			*cntr = 15;
    856                 } else {
    857 			*cntr = 13;
    858                 }
    859 
    860 		return 0;
    861 	}
    862 
    863 	if (strncmp("FEM1_TXBiPReferencePDvoltage_5G", l, 31) == 0 ||
    864 		strncmp("FEM1_TxBiPReferencePDvoltage_5G", l, 31) == 0) {
    865 		*st = FEM1_BAND5_PRMS;
    866 		if (arch == WL128X_ARCH) {
    867 			*cntr = 14;
    868 		} else {
    869 			*cntr = 12;
    870                 }
    871 
    872 		return 0;
    873 	}
    874 
    875 	return 1;
    876 }
    877 
    878 static int ini_parse_line(char *l, int nbr, struct wl12xx_common *cmn)
    879 {
    880 	static enum wl1271_ini_section status;
    881 	static int cntr;
    882 
    883 	if (!cntr && find_section(l, &status, &cntr, cmn->arch)) {
    884 		fprintf(stderr, "Uknown ini section %s\n", l);
    885 		return 1;
    886 	}
    887 
    888 	switch (status) {
    889 	case GENERAL_PRMS:	/* general parameters */
    890 		cntr--;
    891 		return cmn->parse_ops->prs_general_prms(l, cmn, &cmn->ini);
    892 	case FEM_PRMS:	/* FEM parameters */
    893 		if (cmn->arch == WL1271_ARCH) {
    894 			fprintf(stderr, "The parameter not from 127x architecture\n");
    895 			return 1;
    896 		}
    897 		cntr--;
    898 		return parse_fem_prms_128x(l, &cmn->ini);
    899 	case BAND2_PRMS:	/* band 2.4GHz parameters */
    900 		cntr--;
    901 		return cmn->parse_ops->prs_band2_prms(l, &cmn->ini);
    902 	case BAND5_PRMS:	/* band 5GHz parameters */
    903 		cntr--;
    904 		return cmn->parse_ops->prs_band5_prms(l, &cmn->ini);
    905 	case FEM0_BAND2_PRMS:	/* FEM0 band 2.4GHz parameters */
    906 		cntr--;
    907 		return cmn->parse_ops->prs_fem0_band2_prms(l, &cmn->ini);
    908 	case FEM1_BAND2_PRMS:	/* FEM1 band 2.4GHz parameters */
    909 		cntr--;
    910 		return cmn->parse_ops->prs_fem1_band2_prms(l, &cmn->ini);
    911 	case FEM1_BAND5_PRMS:	/* FEM1 band 5GHz parameters */
    912 		cntr--;
    913 		return cmn->parse_ops->prs_fem1_band5_prms(l, &cmn->ini);
    914 	case UKNOWN_SECTION:
    915 		/* added because of compilation warning. handeled in find_section() */
    916 		break;
    917 	}
    918 
    919 	return 1;
    920 }
    921 
    922 #if 0
    923 static void ini_dump(struct wl1271_ini *ini)
    924 {
    925 	int i;
    926 
    927 	printf("\n");
    928 	printf("General params:\n");
    929 	printf("ref clock:                 %02X\n",
    930 		ini->general_params.ref_clock);
    931 	printf("settling time:             %02X\n",
    932 		ini->general_params.settling_time);
    933 	printf("clk valid on wakeup:       %02X\n",
    934 		ini->general_params.clk_valid_on_wakeup);
    935 	printf("dc2dc mode:                %02X\n",
    936 		ini->general_params.dc2dc_mode);
    937 	printf("dual band mode:            %02X\n",
    938 		ini->general_params.dual_mode_select);
    939 	printf("tx bip fem auto detect:    %02X\n",
    940 		ini->general_params.tx_bip_fem_auto_detect);
    941 	printf("tx bip fem manufacturer:   %02X\n",
    942 		ini->general_params.tx_bip_fem_manufacturer);
    943 	printf("general settings:          %02X\n",
    944 		ini->general_params.general_settings);
    945 	printf("sr state:                  %02X\n",
    946 		ini->general_params.sr_state);
    947 
    948 	printf("srf1:");
    949 	for (i = 0; i < WL1271_INI_MAX_SMART_REFLEX_PARAM; i++)
    950 		printf(" %02X", ini->general_params.srf1[i]);
    951 	printf("\n");
    952 
    953 	printf("srf2:");
    954 	for (i = 0; i < WL1271_INI_MAX_SMART_REFLEX_PARAM; i++)
    955 		printf(" %02X", ini->general_params.srf2[i]);
    956 	printf("\n");
    957 
    958 	printf("srf3:");
    959 	for (i = 0; i < WL1271_INI_MAX_SMART_REFLEX_PARAM; i++)
    960 		printf(" %02X", ini->general_params.srf3[i]);
    961 	printf("\n");
    962 
    963 	printf("Static 2.4 band params:\n");
    964 
    965 	printf("rx trace insertion loss: %02X\n",
    966 		ini->stat_radio_params_2.rx_trace_insertion_loss);
    967 
    968 	printf("rx rssi n process compensation:");
    969 	for (i = 0; i < WL1271_INI_RSSI_PROCESS_COMPENS_SIZE; i++)
    970 		printf(" %02X",
    971 			ini->stat_radio_params_2.rx_rssi_process_compens[i]);
    972 	printf("\n");
    973 
    974 	printf("tx trace: %02X\n",
    975 		ini->stat_radio_params_2.tx_trace_loss);
    976 
    977 	printf("Dynamic 2.4 band params for FEM\n");
    978 
    979 	printf("Static 5 band params:\n");
    980 
    981 	printf("rx trace insertion loss:");
    982 	for (i = 0; i < WL1271_INI_SUB_BAND_COUNT_5; i++)
    983 		printf(" %02X",
    984 			ini->stat_radio_params_5.rx_rssi_process_compens[i]);
    985 	printf("\n");
    986 
    987 	printf("rx rssi n process compensation:");
    988 	for (i = 0; i < WL1271_INI_RSSI_PROCESS_COMPENS_SIZE; i++)
    989 		printf(" %02X",
    990 			ini->stat_radio_params_5.rx_rssi_process_compens[i]);
    991 	printf("\n");
    992 
    993 	printf("tx trace:");
    994 	for (i = 0; i < WL1271_INI_SUB_BAND_COUNT_5; i++)
    995 		printf(" %02X",
    996 			ini->stat_radio_params_5.tx_trace_loss[i]);
    997 	printf("\n");
    998 
    999 	printf("Dynamic 5 band params for FEM\n");
   1000 
   1001 }
   1002 #endif
   1003 
   1004 static struct wl12xx_parse_ops wl1271_parse_ops = {
   1005 	.prs_general_prms       = parse_general_prms,
   1006 	.prs_band2_prms         = parse_band2_prms,
   1007 	.prs_band5_prms         = parse_band5_prms,
   1008 	.prs_fem0_band2_prms    = parse_fem0_band2_prms,
   1009 	.prs_fem1_band2_prms    = parse_fem1_band2_prms,
   1010 	.prs_fem1_band5_prms    = parse_fem1_band5_prms,
   1011 };
   1012 
   1013 static struct wl12xx_parse_ops wl128x_parse_ops = {
   1014 	.prs_general_prms       = parse_general_prms_128x,
   1015 	.prs_band2_prms         = parse_band2_prms_128x,
   1016 	.prs_band5_prms         = parse_band5_prms_128x,
   1017 	.prs_fem0_band2_prms    = parse_fem0_band2_prms_128x,
   1018 	.prs_fem1_band2_prms    = parse_fem1_band2_prms_128x,
   1019 	.prs_fem1_band5_prms    = parse_fem1_band5_prms_128x,
   1020 };
   1021 
   1022 int nvs_get_arch(int file_size, struct wl12xx_common *cmn)
   1023 {
   1024 	enum wl12xx_arch arch = UNKNOWN_ARCH;
   1025 
   1026 	switch (file_size) {
   1027 		case WL127X_NVS_FILE_SZ:
   1028 			arch = WL1271_ARCH;
   1029 			cmn->parse_ops = &wl1271_parse_ops;
   1030 			break;
   1031 		case WL128X_NVS_FILE_SZ:
   1032 			arch = WL128X_ARCH;
   1033 			cmn->parse_ops = &wl128x_parse_ops;
   1034 			break;
   1035 	}
   1036 
   1037 	if (cmn->arch != UNKNOWN_ARCH && cmn->arch != arch) {
   1038 		cmn->parse_ops = NULL;
   1039 		return 1;
   1040 	}
   1041 
   1042 	cmn->arch = arch;
   1043 
   1044 	return 0;
   1045 }
   1046 
   1047 static int ini_get_arch(FILE *f, struct wl12xx_common *cmn)
   1048 {
   1049 	char buf[1024], *pos;
   1050 	int line = 0;
   1051 	enum wl12xx_arch arch = UNKNOWN_ARCH;
   1052 
   1053 	while (ini_get_line(buf, sizeof(buf), f, &line, &pos)) {
   1054 		if (strncmp("TCXO_Clk", pos, 8) == 0) {
   1055 			arch = WL128X_ARCH;
   1056 			break;
   1057 		}
   1058 	}
   1059 
   1060 	if (arch == UNKNOWN_ARCH) {
   1061 		arch = WL1271_ARCH;
   1062         }
   1063 
   1064 	if (cmn->arch != UNKNOWN_ARCH && cmn->arch != arch) {
   1065 		return 1;
   1066         }
   1067 
   1068 	cmn->arch = arch;
   1069 
   1070 	if (cmn->arch == WL1271_ARCH) {
   1071 		cmn->parse_ops = &wl1271_parse_ops;
   1072         } else {
   1073 		cmn->parse_ops = &wl128x_parse_ops;
   1074         }
   1075 
   1076 	fseek(f, 0L, SEEK_SET);
   1077 
   1078 	return 0;
   1079 }
   1080 
   1081 int read_ini(const char *filename, struct wl12xx_common *cmn)
   1082 {
   1083 	FILE *f;
   1084 	char buf[1024], *pos;
   1085 	int ret = 0, line = 0;
   1086 
   1087 	f = fopen(filename, "r");
   1088 	if (f == NULL) {
   1089 		fprintf(stderr, "Unable to open file %s (%s)\n",
   1090 			filename, strerror(errno));
   1091 		return 1;
   1092 	}
   1093 
   1094 	/* check if it 127x or 128x */
   1095 	if (ini_get_arch(f, cmn)) {
   1096 		fprintf(stderr, "Unable to define wireless architecture\n");
   1097 		ret = 1;
   1098 		goto out;
   1099 	}
   1100 
   1101 	/* start parsing */
   1102 	while (ini_get_line(buf, sizeof(buf), f, &line, &pos)) {
   1103 		ret = ini_parse_line(pos, line, cmn);
   1104 		if (ret) break;
   1105 	}
   1106 
   1107 out:
   1108 	fclose(f);
   1109 #if 0
   1110 	ini_dump(ini);
   1111 #endif
   1112 	return ret;
   1113 }
   1114