/******************************************************************************
 *
 * Copyright(c) 2019 Realtek Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License 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.
 *
 *****************************************************************************/
#define _HAL_LD_FILE_C_
#include "hal_headers.h"
#include "hal_ld_file.h"

static int
_hal_parse_phyreg(void *drv_priv, void *para_info_t, u8 *psrc_buf, u32 buflen)
{
	struct rtw_para_info_t *para_info = (struct rtw_para_info_t *)para_info_t;
	u32 *pdest_buf = para_info->para_data;
	char	*sz_line, *ptmp;
	u32 dest_buf_idx = 0;
	u32	u4bregoffset, u4bregvalue, u4bmove;

	ptmp = (char *)psrc_buf;

	for (sz_line = hal_getLinefrombuffer(ptmp); sz_line != NULL; sz_line = hal_getLinefrombuffer(ptmp)) {
		if (!hal_is_comment_string(sz_line)) {
			/* Get 1st hex value as register offset. */
			if (hal_get_hexvalue_fromstring(sz_line, &u4bregoffset, &u4bmove)) {

				pdest_buf[dest_buf_idx] = u4bregoffset;
				dest_buf_idx++;

				if (u4bregoffset == 0xffff) {
					/* Ending. */
					pdest_buf[dest_buf_idx] = 0xffff;
					PHL_INFO(" dest_buf_len: %d \n", dest_buf_idx);
					break;
				}
				/* Get 2nd hex value as register value. */
				sz_line += u4bmove;
				if (hal_get_hexvalue_fromstring(sz_line, &u4bregvalue, &u4bmove)) {
					/* PHL_INFO("[BB-ADDR]%03lX=%08lX\n", u4bregoffset, u4bregvalue); */
					pdest_buf[dest_buf_idx] = u4bregvalue;
					dest_buf_idx++;
				}
			}
		}
	}
#if 0
	{ /*debug dump buf*/
		u32 i = 0;
		for (i = 0; i <= dest_buf_idx; i+=2)
			PHL_INFO("[BB-ADDR] 0x%x :[0x%x]\n", pdest_buf[i], pdest_buf[i+1]);
	}
#endif
	return dest_buf_idx;
}

static u32 phypg_combvalue_fromstring(		char *sz_line)
{
	u32	u4bmove;
	u32 combvalue = 0;
	u8	integer = 0, fraction = 0;
	u8 txgi_pdbm = 4;

	if (hal_get_fractionvalue_fromstring(sz_line, &integer, &fraction, &u4bmove))
		sz_line += u4bmove;
	else
		goto exit;

	combvalue |= ((integer * txgi_pdbm) + (fraction * txgi_pdbm / 100));

	if (hal_get_fractionvalue_fromstring(sz_line, &integer, &fraction, &u4bmove))
		sz_line += u4bmove;
	else
		goto exit;

	combvalue <<= 8;
	combvalue |= ((integer * txgi_pdbm) + (fraction * txgi_pdbm / 100));

	if (hal_get_fractionvalue_fromstring(sz_line, &integer, &fraction, &u4bmove))
		sz_line += u4bmove;
	else
		goto exit;

	combvalue <<= 8;
	combvalue |= ((integer * txgi_pdbm) + (fraction * txgi_pdbm / 100));

	if (hal_get_fractionvalue_fromstring(sz_line, &integer, &fraction, &u4bmove))
		sz_line += u4bmove;
	else
		goto exit;

	combvalue <<= 8;
	combvalue |= ((integer * txgi_pdbm) + (fraction * txgi_pdbm / 100));

	/*PHL_DBG("[combvalue 4] 0x%x , hex = %x\n", combvalue , integer);*/
exit:
	return combvalue;
}

static int
_hal_parse_txpwr_by_rate(void *drv_priv, void *para_info_t, u8 *psrc_buf, u32 buflen)
{
	struct rtw_para_info_t *para_info = (struct rtw_para_info_t *)para_info_t;
	u32 *pdest_buf = para_info->para_data;
	char	*sz_line, *ptmp;
	u8	band = 0;
	u8 phy_reg_pg_version = 0;
	u8 phy_reg_pg_value_type = 0;
	u32 pwrhexval = 0;
	u32 line_idx = 0;
	u32 buf_idx = 0;
	bool firstline = true;

	ptmp = (char*)psrc_buf;
	for (sz_line = hal_getLinefrombuffer(ptmp); sz_line != NULL; sz_line = hal_getLinefrombuffer(ptmp)) {
		if (hal_is_allspace_tab(sz_line, sizeof(*sz_line)))
			continue;

		if (!hal_is_comment_string(sz_line)) {
			if (firstline) {
				if (_os_strncmp(sz_line, "#[v2]", 5) == 0
					|| _os_strncmp(sz_line, "#[v3]", 5) == 0) {
					phy_reg_pg_version = sz_line[3] - '0'; /* store pg version*/
					PHL_INFO("phy_reg_pg_version %d\n", phy_reg_pg_version);
				} else {
					PHL_ERR("The format in PHY_REG_PG are invalid %s\n", sz_line);
					goto exit;
				}
				if (_os_strncmp(sz_line + 5, "[Exact]#", 8) == 0) {
					phy_reg_pg_value_type = 1; /* store PHY_REG_PG_EXACT_VALUE*/
					firstline = false;
					PHL_INFO("REG_PG_EXACT_VALUE\n");
					continue;
				} else {
					PHL_ERR("The values in PHY_REG_PG are invalid %s\n", sz_line);
					goto exit;
				}
			}
			if (_os_strncmp(sz_line , "#[2.4G]#", 8) == 0) {
					band = 0;
					continue;
			}
			if (_os_strncmp(sz_line , "#[5G]#", 6) == 0) {
					band = 1;
					continue;
			}
			if ((_os_strncmp(sz_line , "#[START]#", 9) == 0) || (_os_strncmp(sz_line , "#[END]#", 9) == 0) ) {
					continue;
			}
			if (_os_strncmp(sz_line , "[Nss1]", 6) == 0) {
				line_idx = 0;
				pwrhexval = 0;

				pdest_buf[buf_idx++] = band;
				pdest_buf[buf_idx++] = PHYPG_RF1Tx;
				line_idx += 6;
				PHL_INFO("[Line]%s , line_idx %d \n", sz_line, line_idx);

				while (sz_line[line_idx] == ' ' || sz_line[line_idx] == '\0' || sz_line[line_idx] == '\t')
					++line_idx;

				sz_line += line_idx;
				if (_os_strncmp(sz_line , "11M_1M", 6) == 0) {
					pdest_buf[buf_idx++] = CCK_11M_1M;
					sz_line += 6;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "18M_6M", 6) == 0) {
					pdest_buf[buf_idx++] = OFDM_18M_6M;
					sz_line += 6;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "54M_24M", 7) == 0) {
					pdest_buf[buf_idx++] = OFDM_54M_24M;
					sz_line += 7;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "MCS3_0", 6) == 0) {
					pdest_buf[buf_idx++] = HE1SS_MCS3_0;
					sz_line += 6;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "MCS7_4", 6) == 0) {
					pdest_buf[buf_idx++] = HE1SS_MCS7_4;
					sz_line += 6;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "MCS11_8", 6) == 0) {
					pdest_buf[buf_idx++] = HE1SS_MCS11_8;
					sz_line += 7;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "DCM4_0", 6) == 0) {
					pdest_buf[buf_idx++] = HE1SS_DCM4_0;
					sz_line += 6;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				}
			} else if (_os_strncmp(sz_line , "[Nss2]", 6) == 0) {
				line_idx = 0;
				pwrhexval = 0;

				pdest_buf[buf_idx++] = band;
				pdest_buf[buf_idx++] = PHYPG_RF2Tx;
				PHL_INFO("[Line]%s , line_idx %d \n", sz_line, line_idx);

				line_idx += 6;
				while (sz_line[line_idx] == ' ' || sz_line[line_idx] == '\0' || sz_line[line_idx] == '\t')
					++line_idx;

				sz_line += line_idx;
				if (_os_strncmp(sz_line , "MCS3_0", 6) == 0) {
					pdest_buf[buf_idx++] = HE2SS_MCS3_0;
					sz_line += 6;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "MCS7_4", 6) == 0) {
					pdest_buf[buf_idx++] = HE2SS_MCS7_4;
					sz_line += 6;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "MCS11_8", 6) == 0) {
					pdest_buf[buf_idx++] = HE2SS_MCS11_8;
					sz_line += 7;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				} else if (_os_strncmp(sz_line , "DCM4_0", 6) == 0) {
					pdest_buf[buf_idx++] = HE2SS_DCM4_0;
					sz_line += 6;
					PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
					pwrhexval = phypg_combvalue_fromstring(sz_line);
					PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
					pdest_buf[buf_idx++] = pwrhexval;
				}
			} else if (_os_strncmp(sz_line , "[Offset]", 8) == 0) {
				line_idx = 0;
				pwrhexval = 0;

				pdest_buf[buf_idx++] = band;
				pdest_buf[buf_idx++] = PHYPG_OFFSET;
				PHL_INFO("[Line]%s , line_idx %d \n", sz_line, line_idx);

				line_idx += 8;
				while (sz_line[line_idx] == ' ' || sz_line[line_idx] == '\t' || sz_line[line_idx] == '\0')
					++line_idx;

				sz_line += line_idx;
				if (band == 0) {
					if (_os_strncmp(sz_line , "AllRate1", 8) == 0) {
						pdest_buf[buf_idx++] = Legacy_AllRate;
						sz_line += 8;
						PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
						pwrhexval = phypg_combvalue_fromstring(sz_line);
						PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
						pdest_buf[buf_idx++] = pwrhexval;
					}
					else if (_os_strncmp(sz_line , "AllRate2", 8) == 0) {
						pdest_buf[buf_idx++] = HE_AllRate;
						sz_line += 8;
						PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
						pwrhexval = phypg_combvalue_fromstring(sz_line);
						PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
						pdest_buf[buf_idx++] = pwrhexval;
					}
				}
				if (band == 1) {
					if (_os_strncmp(sz_line , "AllRate1", 8) == 0) {
						pdest_buf[buf_idx++] = Legacy_AllRate; /* 5G band all rate only OFDM upper */
						sz_line += 8;
						PHL_INFO("[Line]%s, line_idx %d \n", sz_line, line_idx);
						pwrhexval = phypg_combvalue_fromstring(sz_line);
						PHL_INFO("combine Value Get Pwr hex Val = %x\n", pwrhexval);
						pdest_buf[buf_idx++] = pwrhexval;
					}
				}
			}
		}
	}
	return buf_idx;
exit:
#if 0 /*dbg dump*/
	{
		u32 i = 0 ;
		char *strbuf , *pextra;
		strbuf = _os_mem_alloc(drv_priv, buf_idx  * sizeof(u32));
		pextra = strbuf;

		sprintf(strbuf, "\n");
		pextra = strbuf + _os_strlen(strbuf);
		for (i = 0; i <= buf_idx; i ++) {
			pextra += sprintf(pextra, " %x \t", pdest_buf[i]);
			if ( ((i+1)%4 == 0) && (i != 0))
				pextra += sprintf(pextra, "\n");
		}
		printk( "%s \n" , strbuf);
		_os_mem_free(drv_priv, strbuf, buf_idx  * sizeof(u32));
	}
#endif
	return 0;
}

static int
_hal_parse_radio(void *drv_priv, void *para_info_t, u8 *psrc_buf, u32 buflen)
{
	struct rtw_para_info_t *para_info = (struct rtw_para_info_t *)para_info_t;
	u32 *pdest_buf = para_info->para_data;
	char	*sz_line, *ptmp;
	u32 dest_buf_idx = 0;
	u32 u4bregoffset, u4bregvalue, u4bmove;

	ptmp = (char *)psrc_buf;

	for (sz_line = hal_getLinefrombuffer(ptmp); sz_line != NULL; sz_line = hal_getLinefrombuffer(ptmp)) {
		if (!hal_is_comment_string(sz_line)) {
			/* Get 1st hex value as register offset. */
			if (hal_get_hexvalue_fromstring(sz_line, &u4bregoffset, &u4bmove)) {

				pdest_buf[dest_buf_idx] = u4bregoffset;
				dest_buf_idx++;

				if (u4bregoffset == 0xffff) {
					/* Ending. */
					pdest_buf[dest_buf_idx] = 0xffff;
					PHL_INFO(" dest_buf_len: %d \n", dest_buf_idx);
					break;
				}
				/* Get 2nd hex value as register value. */
				sz_line += u4bmove;
				if (hal_get_hexvalue_fromstring(sz_line, &u4bregvalue, &u4bmove)) {
					/*PHL_INFO("[RF-ADDR]%03lx=%08lx\n", u4bregoffset, u4bregvalue);*/
					pdest_buf[dest_buf_idx] = u4bregvalue;
					dest_buf_idx++;
				}
			}
		}
	}
#if 0
	{ /*debug dump buf*/
		u32 i = 0;
		for (i = 0; i <= dest_buf_idx; i+=2)
			PHL_INFO("[Radio-ADDR] 0x%x :[0x%x]\n", pdest_buf[i], pdest_buf[i+1]);
	}
#endif
	return dest_buf_idx;
}

static int
hal_phy_find_ext_regd_num(struct rtw_para_pwrlmt_info_t *para_info,
			char *regd_name)
{
	int i = 0;

	for (i = 0; i <= para_info->ext_regd_arridx ; i++) {
		if (_os_strcmp(regd_name, para_info->ext_regd_name[i]) == 0) {
			return i;
		}
	}
	return -1;
}

static void
_hal_add_ext_reg_codemap(void *d,
			struct rtw_para_pwrlmt_info_t *para_info,
			const char *country,
			u16 		domain,
			const char *regd_name,
			u32 		nlen)
{
	struct _hal_file_regd_ext *pregd_codemap;
	struct _hal_file_regd_ext *ent;

	if (!regd_name || !nlen) {
		PHL_ERR("regd_name || nlen Null\n");
		goto exit;
	}

	pregd_codemap = (struct _hal_file_regd_ext *)para_info->ext_reg_codemap;
	ent = &pregd_codemap[para_info->ext_reg_map_num];

	if (regd_name && _os_strlen((u8*)regd_name) < 10) {

		if (hal_phy_find_ext_regd_num(para_info, (char *)regd_name) == -1) {
			u8 idx = (u8)(para_info->ext_regd_arridx + 1);

			if (idx < regd_name_max_size) {
				_os_strcpy(para_info->ext_regd_name[idx], regd_name);
				para_info->ext_regd_arridx++;
				PHL_INFO("extrea reg [%d] = [%s]\n",
					idx, para_info->ext_regd_name[idx]);
			} else {
				PHL_ERR("extrea reg [%d] over size\n", idx);
				goto exit;
			}
		}

		_os_mem_cpy(d, ent->reg_name, (void*)regd_name, nlen);
		PHL_INFO("store reg_name = [%s]\n", ent->reg_name);
	} else {
		PHL_ERR("reg_name = [%s]\n", ent->reg_name);
		goto exit;
	}

	if (domain != 0)
		ent->domain = domain;
	else
		ent->domain = 0xffff;
	PHL_INFO("Store DomainCode = [0x%x]\n", ent->domain);

	if (country) {
		_os_mem_cpy(d, ent->country, (void*)country, 2);
		PHL_INFO("Store country = [%c%c]\n", ent->country[0], ent->country[1]);
	} else
		_os_mem_set(d, ent->country, '\0', 2);

	para_info->ext_reg_map_num++;
exit:
	return;
}

/*
* @@Ver=2.0
* or
* @@DomainCode=0x28, Regulation=C6
* or
* @@CountryCode=GB, Regulation=C7
*/
static u8
parse_reg_exc_config(void *drv_priv,
		char *sz_line ,
		struct rtw_para_pwrlmt_info_t *para_info)
{
#define VER_PREFIX "Ver="
#define DOMAIN_PREFIX "DomainCode=0x"
#define COUNTRY_PREFIX "CountryCode="
#define REG_PREFIX "Regulation="

	const u8 ver_prefix_len = (u8)_os_strlen((u8*)VER_PREFIX);
	const u8 domain_prefix_len = (u8)_os_strlen((u8*)DOMAIN_PREFIX);
	const u8 country_prefix_len = (u8)_os_strlen((u8*)COUNTRY_PREFIX);
	const u8 reg_prefix_len = (u8)_os_strlen((u8*)REG_PREFIX);
	u32 i, i_val_s, i_val_e;
	u32 j;
	u16 domain = 0;
	char *country = NULL;
	u8 parse_reg = 0;

	if (sz_line[0] != '@' || sz_line[1] != '@')
		return false;

	i = 2;
	if (_os_strncmp(sz_line + i, VER_PREFIX, ver_prefix_len) == 0)
		; /* nothing to do */
	else if (_os_strncmp(sz_line + i, DOMAIN_PREFIX, domain_prefix_len) == 0) {
		/* get string after domain prefix to ',' */
		i += domain_prefix_len;
		i_val_s = i;
		while (sz_line[i] != ',') {
			if (sz_line[i] == '\0')
				return false;
			i++;
		}
		i_val_e = i;

		/* check if all hex */
		for (j = i_val_s; j < i_val_e; j++)
			if (hal_ishexdigit(sz_line[j]) == false)
				return false;

		/* get value from hex string */
		if (_os_sscanf(sz_line + i_val_s, "%hx", &domain) != 1)
			return false;

		parse_reg = 1;
	} else if (_os_strncmp(sz_line + i, COUNTRY_PREFIX, country_prefix_len) == 0) {
		/* get string after country prefix to ',' */
		i += country_prefix_len;
		i_val_s = i;
		while (sz_line[i] != ',') {
			if (sz_line[i] == '\0')
				return false;
			i++;
		}
		i_val_e = i;

		if (i_val_e - i_val_s != 2)
			return false;

		/* check if all alpha */
		for (j = i_val_s; j < i_val_e; j++)
			if (hal_is_alpha(sz_line[j]) == false)
				return false;

		country = sz_line + i_val_s;

		parse_reg = 1;

	} else
		return false;

	if (parse_reg) {
		/* move to 'R' */
		while (sz_line[i] != 'R') {
			if (sz_line[i] == '\0')
				return false;
			i++;
		}

		/* check if matching regulation prefix */
		if (_os_strncmp(sz_line + i, REG_PREFIX, reg_prefix_len) != 0)
			return false;

		/* get string after regulation prefix ending with space */
		i += reg_prefix_len;
		i_val_s = i;
		while (sz_line[i] != ' ' && sz_line[i] != '\t' && sz_line[i] != '\0')
			i++;

		if (i == i_val_s)
			return false;

		_hal_add_ext_reg_codemap(drv_priv, para_info,
					country, domain,
					sz_line + i_val_s, i - i_val_s);
	}

	return true;
}

static void hal_phy_store_tx_power_limit		(void *drv_priv,
		u8				*sregulation,
		u8				*sband,
		u8				*sbandwidth,
		u8				*sratesection,
		u8				*sbf,
		u8				*sntx,
		u8				*schannel,
		u8				*spwrlimit,
		u8				*spshape_idx,
		void *pstc_txpwr_lmt,
		struct rtw_para_pwrlmt_info_t *para_info)
{
	u8 band = 0, bandwidth = 0, ratesec = 0, channel = 0;
	u8 ntx_idx = 0 , bf = 0 , pshape_idx = 0;
	int regulation = -1;
	s8 powerlimit = 0;

	struct hal_txpwr_lmt_t *array_tc_8852a_txpwr_lmt = (struct hal_txpwr_lmt_t *)pstc_txpwr_lmt;

	if (hal_get_u1bint_fromstr_indec((char *)schannel, &channel) == false
		|| hal_get_s1bint_fromstr_indec((char *)spwrlimit, &powerlimit) == false) {
		PHL_INFO("Illegal index of power limit table [ch %s][val %s]\n",
			 (char *)schannel, (char *)spwrlimit);
		return;
	}

	if (spshape_idx != NULL) {
		if (hal_get_u1bint_fromstr_indec((char *)spshape_idx, &pshape_idx) == false) {
			PHL_INFO("Illegal index of pshape idx [val %s]\n", (char *)spshape_idx);
			return;
		}
	}

	if (_os_strncmp((char *)sratesection, (const char *)"CCK", 3) == 0)
		ratesec = _PW_LMT_RS_CCK;
	else if (_os_strncmp((char *)sratesection, (const char *)"OFDM", 4) == 0)
		ratesec = _PW_LMT_RS_OFDM;
	else if (_os_strncmp((char *)sratesection, (const char *)"HT", 2) == 0)
		ratesec = _PW_LMT_RS_HT;
	else if (_os_strncmp((char *)sratesection, (const char *)"VHT", 3) == 0)
		ratesec = _PW_LMT_RS_VHT;
	else if (_os_strncmp((char *)sratesection, (const char *)"HE", 2) == 0)
		ratesec = _PW_LMT_RS_HE;
	else {
		PHL_INFO("Wrong rate section:%s\n", (char *)sratesection);
		return;
	}

	if (_os_strncmp((char *)sntx, (const char *)"1T", 2) == 0)
		ntx_idx = _PW_LMT_PH_1T;
	else if (_os_strncmp((char *)sntx, (const char *)"2T", 2) == 0)
		ntx_idx = _PW_LMT_PH_2T;
	else if (_os_strncmp((char *)sntx, (const char *)"3T", 2) == 0)
		ntx_idx = _PW_LMT_PH_3T;
	else if (_os_strncmp((char *)sntx, (const char *)"4T", 2) == 0)
		ntx_idx = _PW_LMT_PH_4T;
	else {
		PHL_INFO("Wrong tx num:%s\n", (char *)sntx);
		return;
	}

	if (_os_strncmp((char *)sbandwidth, (const char *)"20M", 3) == 0)
		bandwidth = _PW_LMT_BW_20M;
	else if (_os_strncmp((char *)sbandwidth, (const char *)"40M", 3) == 0)
		bandwidth = _PW_LMT_BW_40M;
	else if (_os_strncmp((char *)sbandwidth, (const char *)"80M", 3) == 0)
		bandwidth = _PW_LMT_BW_80M;
	else if (_os_strncmp((char *)sbandwidth, (const char *)"160M", 4) == 0)
		bandwidth = _PW_LMT_BW_160M;
	else {
		PHL_INFO("unknown bandwidth: %s\n", (char *)sbandwidth);
		return;
	}

	if (_os_strncmp((char *)sband, (const char *)"2.4G", 4) == 0)
		band = _PW_LMT_BAND_2_4G;
	else if (_os_strncmp((char *)sband, (const char *)"5G", 2) == 0)
		band = _PW_LMT_BAND_5G;
	else {
		PHL_INFO("unknown band: %s\n", (char *)sband);
		return;
	}

	if (_os_strncmp((char *)sbf, (const char *)"Non-BF", 6) == 0 || _os_strncmp((char *)sbf, (const char *)"NA", 2) == 0)
		bf = _PW_LMT_NONBF;
	else if (_os_strncmp((char *)sbf, (const char *)"BF", 2) == 0)
		bf = _PW_LMT_BF;
	else {
		PHL_INFO("unknown BF: %s\n", (char *)sbf);
		return;
	}

	regulation = rtw_hal_rf_get_predefined_pw_lmt_regu_type_from_str((char *)sregulation);
	if (regulation == -1) {
		int regd_num = hal_phy_find_ext_regd_num(para_info, (char *)sregulation);

		if (regd_num != -1) {
			regulation = (u8)regd_num;
			PHL_INFO("new regulation num: %d\n", regulation);
		} else {
		PHL_INFO("unknown regulation: %s\n", (char *)sregulation);
		return;
	}
	}

	array_tc_8852a_txpwr_lmt->band = band;
	array_tc_8852a_txpwr_lmt->bw = bandwidth;
	array_tc_8852a_txpwr_lmt->ch = channel;
	array_tc_8852a_txpwr_lmt->rs = ratesec;
	array_tc_8852a_txpwr_lmt->ntx = ntx_idx;
	array_tc_8852a_txpwr_lmt->bf = bf;
	array_tc_8852a_txpwr_lmt->val = powerlimit;
	array_tc_8852a_txpwr_lmt->reg = (u8)regulation;
	array_tc_8852a_txpwr_lmt->tx_shap_idx = pshape_idx;

	PHL_DBG("Store of power limit table [regulation %d][band %d][bw %d]"\
		"[rate section %d][ntx %d][BF %d][chnl %d][val %d] [sphape_idx %d]\n",
		array_tc_8852a_txpwr_lmt->reg, array_tc_8852a_txpwr_lmt->band,
		array_tc_8852a_txpwr_lmt->bw , array_tc_8852a_txpwr_lmt->rs,
		array_tc_8852a_txpwr_lmt->ntx, array_tc_8852a_txpwr_lmt->bf,
		array_tc_8852a_txpwr_lmt->ch, array_tc_8852a_txpwr_lmt->val,
		array_tc_8852a_txpwr_lmt->tx_shap_idx);

}


static int
_hal_parse_txpwrlmt(void *drv_priv, void *para_info_t, u8 *psrc_buf, u32 buflen)
{
#define LD_STAGE_EXC_MAPPING	0
#define LD_STAGE_TAB_DEFINE		1
#define LD_STAGE_TAB_START		2
#define LD_STAGE_COLUMN_DEFINE	3
#define LD_STAGE_COLUMN_REG		4
#define LD_STAGE_CH_ROW			5
#define LD_STAGE_PSHAPE_NUM		6

	struct rtw_para_pwrlmt_info_t *para_info = (struct rtw_para_pwrlmt_info_t *)para_info_t;
	u32 *pdest_buf = para_info->para_data;
	char **regulation = NULL;
	char **pshape = NULL;
	char	*sz_line = NULL, *ptmp = NULL;
	char band[10], bandwidth[10], ratesection[10], ntx[10], colnumbuf[10], bf_type[10];
	u8	colnum = 0;
	u8	loadingstage = LD_STAGE_EXC_MAPPING;
	u32 struct_idx = 0;
	u32	i = 0, forcnt = 0;
	PHAL_TXPWR_LMT_T array_tc_8852a_txpwr_lmt;

	if (pdest_buf == NULL || psrc_buf == NULL) {
		PHL_INFO("%s, fail !!! NULL buf !!!\n", __func__);
		return 0;
	}

	array_tc_8852a_txpwr_lmt = (PHAL_TXPWR_LMT_T)pdest_buf;

	ptmp = (char *)psrc_buf;
	for (sz_line = hal_getLinefrombuffer(ptmp); sz_line != NULL; sz_line = hal_getLinefrombuffer(ptmp)) {
line_start:
		if (hal_is_allspace_tab(sz_line, sizeof(*sz_line)))
			continue;

		if (hal_is_comment_string(sz_line))
			continue;

		if (loadingstage == LD_STAGE_EXC_MAPPING) {
			if (sz_line[0] == '#' || sz_line[1] == '#') {
				loadingstage = LD_STAGE_TAB_DEFINE;
			} else {
				if (parse_reg_exc_config(drv_priv, sz_line, para_info) == false) {
					PHL_ERR("Fail to parse regulation exception ruls!\n");
					goto exit;
				}
			continue;
			}
		}

		if (loadingstage == LD_STAGE_TAB_DEFINE) {
			/* read "## 2.4G, 20M, 1T, CCK" */
			if (sz_line[0] != '#' || sz_line[1] != '#')
				continue;

			/* skip the space */
			i = 2;
			while (sz_line[i] == ' ' || sz_line[i] == '\t')
				++i;

			sz_line[--i] = ' '; /* return the space in front of the regulation info */

			/* Parse the label of the table */
			_os_mem_set(drv_priv, (void *) band, 0, 10);
			_os_mem_set(drv_priv, (void *) bandwidth, 0, 10);
			_os_mem_set(drv_priv, (void *) ntx, 0, 10);
			_os_mem_set(drv_priv, (void *) ratesection, 0, 10);
			_os_mem_set(drv_priv, (void *) bf_type, 0, 10);

			if (!hal_parse_fiedstring(sz_line, &i, band, ' ', ',')) {
				PHL_ERR("Fail to parse band!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_parse_fiedstring(sz_line, &i, bandwidth, ' ', ',')) {
				PHL_ERR("Fail to parse bandwidth!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_parse_fiedstring(sz_line, &i, ntx, ' ', ',')) {
				PHL_ERR("Fail to parse ntx!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_parse_fiedstring(sz_line, &i, ratesection, ' ', ',')) {
				PHL_ERR("Fail to parse rate!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_parse_fiedstring(sz_line, &i, bf_type, ' ', '/')) {
				PHL_ERR("Fail to parse BF!\n");
				struct_idx = 0;
				goto exit;
			}

			loadingstage = LD_STAGE_TAB_START;
		} else if (loadingstage == LD_STAGE_TAB_START) {
			/* read "## START" */
			if (sz_line[0] != '#' || sz_line[1] != '#')
				continue;

			/* skip the space */
			i = 2;
			while (sz_line[i] == ' ' || sz_line[i] == '\t')
				++i;

			if (_os_strncmp((char *)(sz_line + i), (const char *)"START", 5)) {
				PHL_ERR("Missing \"##	START\" label\n");
				struct_idx = 0;
				goto exit;
			}
			loadingstage = LD_STAGE_COLUMN_DEFINE;
		} else if (loadingstage == LD_STAGE_COLUMN_DEFINE) {
			/* read "## #5# " */
			if (sz_line[0] != '#' || sz_line[1] != '#')

			/* skip the space */
			i = 2;
			while (sz_line[i] == ' ' || sz_line[i] == '\t')
				++i;

			_os_mem_set(drv_priv, (void *) colnumbuf, 0, 10);
			if (!hal_parse_fiedstring(sz_line, &i, colnumbuf, '#', '#')) {
				PHL_ERR("Fail to parse column number!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_get_u1bint_fromstr_indec(colnumbuf, &colnum)) {
				PHL_ERR("Column number \"%s\" is not unsigned decimal\n", colnumbuf);
				struct_idx = 0;
				goto exit;
			}
			if (colnum == 0) {
				PHL_ERR("Column number is 0\n");
				struct_idx = 0;
				goto exit;
			}
			PHL_INFO("[%s][%s][%s][%s][%s] column num:%d\n",
				band, bandwidth, ratesection, ntx, bf_type, colnum);

			regulation = (char **)_os_mem_alloc(drv_priv, sizeof(char *) * colnum);
			if (!regulation) {
				PHL_ERR("Regulation alloc fail\n");
				struct_idx = 0;
				goto exit;
			}
			pshape = (char **)_os_mem_alloc(drv_priv, sizeof(char *) * colnum);
			if (!pshape) {
				PHL_ERR("Regulation alloc fail\n");
				struct_idx = 0;
				goto exit;
			}
			loadingstage = LD_STAGE_COLUMN_REG;
		} else if (loadingstage == LD_STAGE_COLUMN_REG) {
			/* read "##		FCC ETSI	MKK IC	KCC" */
			if (sz_line[0] != '#' || sz_line[1] != '#')
				continue;

			/* skip the space */
			i = 2;
			for (forcnt = 0; forcnt < colnum; ++forcnt) {
				u32 i_ns;

				/* skip the space */
				while (sz_line[i] == ' ' || sz_line[i] == '\t')
					i++;
				i_ns = i;

				while (sz_line[i] != ' ' && sz_line[i] != '\t' && sz_line[i] != '\0')
					i++;

				regulation[forcnt] = (char *)_os_mem_alloc(drv_priv, i - i_ns + 1);
				if (!regulation[forcnt]) {
					PHL_ERR("Regulation alloc fail\n");
					struct_idx = 0;
					goto exit;
				}

				_os_mem_cpy(drv_priv, regulation[forcnt], sz_line + i_ns, i - i_ns);
				regulation[forcnt][i - i_ns] = '\0';
			}

			if (1) {
				PHL_INFO("column name:");
				for (forcnt = 0; forcnt < colnum; ++forcnt)
					PHL_INFO(" %s", regulation[forcnt]);
				PHL_INFO("\n");
			}

			loadingstage = LD_STAGE_PSHAPE_NUM;
		}else if (loadingstage == LD_STAGE_PSHAPE_NUM) {

			if (sz_line[0] == '#' || sz_line[1] == '#')
				continue;

			if ((sz_line[0] != 'p' && sz_line[0] != 'P') ||
				(sz_line[1] != 's' && sz_line[1] != 'S')) {
				PHL_INFO("No PShape prefix: '%c','%c'(%d,%d), continue to CH ROW\n",
					sz_line[0], sz_line[1], sz_line[0], sz_line[1]);
				loadingstage = LD_STAGE_CH_ROW;
				goto line_start;
			}
			PHL_INFO("1.sz_line[0 1] %c %c", sz_line[0], sz_line[1]);
			i = 6;/* move to the  location behind 'e' */

			for (forcnt = 0; forcnt < colnum; ++forcnt) {
				u32	i_ns;

				/* skip the space */
				while (sz_line[i] == ' ' || sz_line[i] == '\t')
					i++;
				i_ns = i;
				PHL_INFO("1.sz_line[%d] %c\n", i ,sz_line[i]);
				while (sz_line[i] != ' ' && sz_line[i] != '\t' && sz_line[i] != '\0')
					i++;

				pshape[forcnt] = (char *)_os_mem_alloc(drv_priv, i - i_ns + 1);
				if (!pshape[forcnt]) {
					PHL_ERR("Regulation alloc fail, pshape [%d]\n", forcnt);
					goto exit;
				}
				PHL_INFO("2.pshape [%d] = %s\n", forcnt, pshape[forcnt]);

				_os_mem_cpy(drv_priv, pshape[forcnt], sz_line + i_ns, i - i_ns);
				pshape[forcnt][i - i_ns] = '\0';
				PHL_INFO(" forcnt %d shape idx: %s:", forcnt, pshape[forcnt]);
			}

			if (1) {
				PHL_INFO("pshape idx:");
				for (forcnt = 0; forcnt < colnum; ++forcnt)
					PHL_INFO(" %s", pshape[forcnt]);
				PHL_INFO("\n");
			}

			loadingstage = LD_STAGE_CH_ROW;
		} else if (loadingstage == LD_STAGE_CH_ROW) {
			char	channel[10] = {0}, powerlimit[10] = {0};
			u8	cnt = 0;

			/* the table ends */
			if (sz_line[0] == '#' && sz_line[1] == '#') {
				i = 2;
				while (sz_line[i] == ' ' || sz_line[i] == '\t')
					++i;

				if (_os_strncmp((char *)(sz_line + i), (const char *)"END", 3) == 0) {
					loadingstage = LD_STAGE_TAB_DEFINE;
					if (regulation) {
						for (forcnt = 0; forcnt < colnum; ++forcnt) {
							if (regulation[forcnt]) {
								_os_mem_free(drv_priv,
									(u8 *)regulation[forcnt],
									_os_strlen((u8 *)regulation[forcnt]) + 1);
								regulation[forcnt] = NULL;
							}
						}
						_os_mem_free(drv_priv, (u8 *)regulation, sizeof(char *) * colnum);
						regulation = NULL;
					}
					if (pshape) {
						for (forcnt = 0; forcnt < colnum; ++forcnt) {
							if (pshape[forcnt]) {
								_os_mem_free(drv_priv,
									(u8 *)pshape[forcnt],
									_os_strlen((u8 *)pshape[forcnt]) + 1);
								pshape[forcnt] = NULL;
							}
						}
						_os_mem_free(drv_priv, (u8 *)pshape, sizeof(char *) * colnum);
						pshape = NULL;
					}
					colnum = 0;
					continue;
				} else {
					PHL_ERR("Missing \"##	END\" label\n");
					struct_idx = 0;
					goto exit;
				}
			}

			if ((sz_line[0] != 'c' && sz_line[0] != 'C') ||
				(sz_line[1] != 'h' && sz_line[1] != 'H')) {
				PHL_ERR("Wrong channel prefix: '%c','%c'(%d,%d)\n",
					sz_line[0], sz_line[1], sz_line[0], sz_line[1]);
				continue;
			}
			i = 2;/* move to the  location behind 'h' */

			/* load the channel number */
			cnt = 0;
			while (sz_line[i] >= '0' && sz_line[i] <= '9') {
				channel[cnt] = sz_line[i];
				++cnt;
				++i;
			}
			PHL_INFO("chnl %s!\n", channel);

			for (forcnt = 0; forcnt < colnum; ++forcnt) {
				/* skip the space between channel number and the power limit value */
				while (sz_line[i] == ' ' || sz_line[i] == '\t')
					++i;

				/* load the power limit value */
				_os_mem_set(drv_priv, (void *) powerlimit, 0, 10);

				if (sz_line[i] == 'W' && sz_line[i + 1] == 'W') {
					/*
					* case "WW" assign special ww value
					* means to get minimal limit in other regulations at same channel
					*/
					s8 ww_value = -63;
					_os_snprintf(powerlimit, 10, "%d", ww_value);
					i += 2;

				} else if (sz_line[i] == 'N' && sz_line[i + 1] == 'A') {
					/*
					* case "NA" assign max txgi value
					* means no limitation
					*/
					_os_snprintf(powerlimit, 10, "%d", 63);
					i += 2;

				} else if ((sz_line[i] >= '0' && sz_line[i] <= '9') || sz_line[i] == '.'
					|| sz_line[i] == '+' || sz_line[i] == '-') {
					/* case of dBm value */
					u8 integer = 0, fraction = 0, negative = 0;
					u32 u4bmove;
					s8 lmt = 0;

					if (sz_line[i] == '+' || sz_line[i] == '-') {
						if (sz_line[i] == '-')
							negative = 1;
						i++;
					}

					if (hal_get_fractionvalue_fromstring(&sz_line[i], &integer, &fraction, &u4bmove))
						i += u4bmove;
					else {
						PHL_ERR("Limit \"%s\" is not valid decimal\n", &sz_line[i]);
						struct_idx = 0;
						goto exit;
					}

					/* transform to string of value in unit of txgi */
					lmt = (integer * 4) + ((u16)fraction * 4 / 100);
					if (negative)
						lmt = -lmt;
					_os_snprintf(powerlimit, 10, "%d", lmt);

					} else {
						PHL_ERR("Wrong limit expression \"%c%c\"(%d, %d)\n"
							, sz_line[i], sz_line[i + 1], sz_line[i], sz_line[i + 1]);
						struct_idx = 0;
						goto exit;
					}

					/* store the power limit value */
					hal_phy_store_tx_power_limit(drv_priv, (u8 *)regulation[forcnt],
						(u8 *)band, (u8 *)bandwidth, (u8 *)ratesection,
						(u8 *)bf_type, (u8 *)ntx, (u8 *)channel,
						(u8 *)powerlimit, (u8 *)pshape[forcnt],
						(void*)&array_tc_8852a_txpwr_lmt[struct_idx], para_info);

					struct_idx++;
					}
				}
	}
exit:
	if (regulation) {
		for (forcnt = 0; forcnt < colnum; ++forcnt) {
			if (regulation[forcnt]) {
				_os_mem_free(drv_priv,
					(u8 *)regulation[forcnt],
					_os_strlen((u8 *)regulation[forcnt]) + 1);
				regulation[forcnt] = NULL;
			}
		}
		_os_mem_free(drv_priv, (u8 *)regulation, sizeof(char *) * colnum);
		regulation = NULL;
	}
	if (pshape) {
		for (forcnt = 0; forcnt < colnum; ++forcnt) {
			if (pshape[forcnt]) {
				_os_mem_free(drv_priv,
					(u8 *)pshape[forcnt],
					_os_strlen((u8 *)pshape[forcnt]) + 1);
				pshape[forcnt] = NULL;
			}
		}
		_os_mem_free(drv_priv, (u8 *)pshape, sizeof(char *) * colnum);
		pshape = NULL;
	}

	return struct_idx;
}


static void hal_phy_store_tx_power_limit_ru		(void *drv_priv,
		u8				*sregulation,
		u8				*sband,
		u8				*sbandwidth,
		u8				*sratesection,
		u8				*sntx,
		u8				*schannel,
		u8				*spwrlimit,
		u8				*spshape_idx,
		void *pstc_txpwr_lmt_ru,
		struct rtw_para_pwrlmt_info_t *para_info)
{
	u8 band = 0, bandwidth = 0, ratesec = 0, channel = 0;
	u8 ntx_idx = 0 , pshape_idx = 0;
	int regulation = -1;
	s8 powerlimit = 0;

	struct hal_txpwr_lmt_ru_t *array_tc_8852a_txpwr_lmt_ru = (struct hal_txpwr_lmt_ru_t *)pstc_txpwr_lmt_ru;

	if (hal_get_u1bint_fromstr_indec((char *)schannel, &channel) == false
		|| hal_get_s1bint_fromstr_indec((char *)spwrlimit, &powerlimit) == false) {
		PHL_INFO("Illegal index of power limit table [ch %s][val %s]\n",
			 (char *)schannel, (char *)spwrlimit);
		return;
	}

	if (spshape_idx != NULL) {
		if (hal_get_u1bint_fromstr_indec((char *)spshape_idx, &pshape_idx) == false) {
			PHL_INFO("Illegal index of pshape idx [val %s]\n", (char *)spshape_idx);
			return;
		}
	}

	if (_os_strncmp((char *)sband, (const char *)"2.4G", 4) == 0)
		band = _PW_LMT_BAND_2_4G;
	else if (_os_strncmp((char *)sband, (const char *)"5G", 2) == 0)
		band = _PW_LMT_BAND_5G;
	else {
		PHL_INFO("unknown band: %s\n", (char *)sband);
		return;
	}

	if (_os_strncmp((char *)sbandwidth, (const char *)"RU26", 4) == 0)
		bandwidth = _PW_LMT_RU_BW_RU26;
	else if (_os_strncmp((char *)sbandwidth, (const char *)"RU52", 4) == 0)
		bandwidth = _PW_LMT_RU_BW_RU52;
	else if (_os_strncmp((char *)sbandwidth, (const char *)"RU106", 5) == 0)
		bandwidth = _PW_LMT_RU_BW_RU106;
	else {
		PHL_INFO("unknown RU bandwidth: %s\n", (char *)sbandwidth);
		return;
	}

	if (_os_strncmp((char *)sntx, (const char *)"1T", 2) == 0)
		ntx_idx = _PW_LMT_PH_1T;
	else if (_os_strncmp((char *)sntx, (const char *)"2T", 2) == 0)
		ntx_idx = _PW_LMT_PH_2T;
	else if (_os_strncmp((char *)sntx, (const char *)"3T", 2) == 0)
		ntx_idx = _PW_LMT_PH_3T;
	else if (_os_strncmp((char *)sntx, (const char *)"4T", 2) == 0)
		ntx_idx = _PW_LMT_PH_4T;
	else {
		PHL_INFO("Wrong tx num:%s\n", (char *)sntx);
		return;
	}

	if (_os_strncmp((char *)sratesection, (const char *)"HE", 2) == 0)
		ratesec = _PW_LMT_RS_HE;
	else {
		PHL_INFO("Wrong RU rate section:%s\n", (char *)sratesection);
		return;
	}

	regulation = rtw_hal_rf_get_predefined_pw_lmt_regu_type_from_str((char *)sregulation);
	if (regulation == -1) {
		int regd_num = hal_phy_find_ext_regd_num(para_info, (char *)sregulation);

		if (regd_num != -1) {
			regulation = (u8)regd_num;
			PHL_INFO("new regulation num: %d\n", regulation);
		} else {
		PHL_INFO("unknown regulation: %s\n", (char *)sregulation);
		return;
	}

	}

	array_tc_8852a_txpwr_lmt_ru->band = band;
	array_tc_8852a_txpwr_lmt_ru->rubw = bandwidth;
	array_tc_8852a_txpwr_lmt_ru->ntx = ntx_idx;
	array_tc_8852a_txpwr_lmt_ru->rs = ratesec;
	array_tc_8852a_txpwr_lmt_ru->reg = (u8)regulation;
	array_tc_8852a_txpwr_lmt_ru->ch = channel;
	array_tc_8852a_txpwr_lmt_ru->val = powerlimit;
	array_tc_8852a_txpwr_lmt_ru->tx_shap_idx = pshape_idx;

	PHL_INFO("Store of power limit RU table [band %d][bw %d][ntx %d]"\
			"[rate section %d][regulation %d][chnl %d][val %d]  [sphape_idx %d]\n",
		array_tc_8852a_txpwr_lmt_ru->band , array_tc_8852a_txpwr_lmt_ru->rubw,
		array_tc_8852a_txpwr_lmt_ru->ntx, array_tc_8852a_txpwr_lmt_ru->rs,
		array_tc_8852a_txpwr_lmt_ru->reg, array_tc_8852a_txpwr_lmt_ru->ch,
		array_tc_8852a_txpwr_lmt_ru->val, array_tc_8852a_txpwr_lmt_ru->tx_shap_idx);
}


static int
_hal_parse_txpwrlmt_ru(void *drv_priv, void *para_info_t, u8 *psrc_buf, u32 buflen)
{
#define LD_STAGE_EXC_MAPPING	0
#define LD_STAGE_TAB_DEFINE		1
#define LD_STAGE_TAB_START		2
#define LD_STAGE_COLUMN_DEFINE	3
#define LD_STAGE_COLUMN_REG		4
#define LD_STAGE_CH_ROW			5
#define LD_STAGE_PSHAPE_NUM		6

	struct rtw_para_pwrlmt_info_t *para_info = (struct rtw_para_pwrlmt_info_t *)para_info_t;
	u32 *pdest_buf = para_info->para_data;
	char **regulation = NULL;
	char **pshape = NULL;
	char	*sz_line = NULL, *ptmp = NULL;
	char band[10], bandwidth[10], ratesection[10], ntx[10], col_num_buf[10];
	u8	col_num = 0;
	u8	loadingstage = LD_STAGE_EXC_MAPPING;
	u32 struct_idx = 0;
	u32	i = 0, for_cnt = 0;
	pHal_Txpwr_lmt_Ru_t array_tc_txpwr_lmt_ru;

	if (pdest_buf == NULL || psrc_buf == NULL) {
		PHL_INFO("%s, fail !!! NULL buf !!!\n", __func__);
		return 0;
	}

	array_tc_txpwr_lmt_ru = (pHal_Txpwr_lmt_Ru_t)pdest_buf;

	ptmp = (char *)psrc_buf;
	for (sz_line = hal_getLinefrombuffer(ptmp); sz_line != NULL; sz_line = hal_getLinefrombuffer(ptmp)) {
line_start:
		if (hal_is_allspace_tab(sz_line, sizeof(*sz_line)))
			continue;

		if (hal_is_comment_string(sz_line))
			continue;

		if (loadingstage == LD_STAGE_EXC_MAPPING) {
				if (sz_line[0] == '#' || sz_line[1] == '#') {
					loadingstage = LD_STAGE_TAB_DEFINE;
			} else {
				if (parse_reg_exc_config(drv_priv, sz_line, para_info) == false) {
					PHL_ERR("Fail to parse regulation exception ruls!\n");
					goto exit;
				}
				continue;
			}
		}

		if (loadingstage == LD_STAGE_TAB_DEFINE) {
			/* read "## 2.4G, RU26, 1T, HE //" */
			if (sz_line[0] != '#' || sz_line[1] != '#')
				continue;

			/* skip the space */
			i = 2;
			while (sz_line[i] == ' ' || sz_line[i] == '\t')
				++i;

			sz_line[--i] = ' '; /* return the space in front of the regulation info */

			/* Parse the label of the table */
			_os_mem_set(drv_priv, (void *) band, 0, 10);
			_os_mem_set(drv_priv, (void *) bandwidth, 0, 10);
			_os_mem_set(drv_priv, (void *) ntx, 0, 10);
			_os_mem_set(drv_priv, (void *) ratesection, 0, 10);

			if (!hal_parse_fiedstring(sz_line, &i, band, ' ', ',')) {
				PHL_ERR("Fail to parse band!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_parse_fiedstring(sz_line, &i, bandwidth, ' ', ',')) {
				PHL_ERR("Fail to parse bandwidth!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_parse_fiedstring(sz_line, &i, ntx, ' ', ',')) {
				PHL_ERR("Fail to parse ntx!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_parse_fiedstring(sz_line, &i, ratesection, ' ', ' ')) {
				PHL_ERR("Fail to parse rate!\n");
				struct_idx = 0;
				goto exit;
			}

			loadingstage = LD_STAGE_TAB_START;
		} else if (loadingstage == LD_STAGE_TAB_START) {
			/* read "## START" */
			if (sz_line[0] != '#' || sz_line[1] != '#')
				continue;

			/* skip the space */
			i = 2;
			while (sz_line[i] == ' ' || sz_line[i] == '\t')
				++i;

			if (_os_strncmp((char *)(sz_line + i), (const char *)"START", 5)) {
				PHL_ERR("Missing \"##	START\" label\n");
				struct_idx = 0;
				goto exit;
			}
			loadingstage = LD_STAGE_COLUMN_DEFINE;
		} else if (loadingstage == LD_STAGE_COLUMN_DEFINE) {
			/* read "## #5# " */
			if (sz_line[0] != '#' || sz_line[1] != '#')

			/* skip the space */
			i = 2;
			while (sz_line[i] == ' ' || sz_line[i] == '\t')
				++i;

			_os_mem_set(drv_priv, (void *) col_num_buf, 0, 10);
			if (!hal_parse_fiedstring(sz_line, &i, col_num_buf, '#', '#')) {
				PHL_ERR("Fail to parse column number!\n");
				struct_idx = 0;
				goto exit;
			}
			if (!hal_get_u1bint_fromstr_indec(col_num_buf, &col_num)) {
				PHL_ERR("Column number \"%s\" is not unsigned decimal\n", col_num_buf);
				struct_idx = 0;
				goto exit;
			}
			if (col_num == 0) {
				PHL_ERR("Column number is 0\n");
				struct_idx = 0;
				goto exit;
			}
			PHL_INFO("[%s][%s][%s][%s] column num:%d\n",
					band, bandwidth, ratesection, ntx, col_num);

			regulation = (char **)_os_mem_alloc(drv_priv, sizeof(char *) * col_num);
			if (!regulation) {
				PHL_ERR("Regulation alloc fail\n");
				struct_idx = 0;
				goto exit;
			}
			pshape = (char **)_os_mem_alloc(drv_priv, sizeof(char *) * col_num);
			if (!pshape) {
				PHL_ERR("Regulation alloc fail\n");
				struct_idx = 0;
				goto exit;
			}
			loadingstage = LD_STAGE_COLUMN_REG;
		}else if (loadingstage == LD_STAGE_COLUMN_REG) {
			/* read "##		FCC ETSI	MKK IC	KCC" */
			if (sz_line[0] != '#' || sz_line[1] != '#')
				continue;

			/* skip the space */
			i = 2;
			for (for_cnt = 0; for_cnt < col_num; ++for_cnt) {
				u32 i_ns;

				/* skip the space */
				while (sz_line[i] == ' ' || sz_line[i] == '\t')
					i++;
				i_ns = i;

				while (sz_line[i] != ' ' && sz_line[i] != '\t' && sz_line[i] != '\0')
					i++;

				regulation[for_cnt] = (char *)_os_mem_alloc(drv_priv, i - i_ns + 1);
				if (!regulation[for_cnt]) {
					PHL_ERR("Regulation alloc fail\n");
					struct_idx = 0;
					goto exit;
				}

				_os_mem_cpy(drv_priv, regulation[for_cnt], sz_line + i_ns, i - i_ns);
				regulation[for_cnt][i - i_ns] = '\0';
			}

			if (1) {
				PHL_INFO("column name:");
				for (for_cnt = 0; for_cnt < col_num; ++for_cnt)
					PHL_INFO(" %s", regulation[for_cnt]);
				PHL_INFO("\n");
			}
				loadingstage = LD_STAGE_PSHAPE_NUM;
		}else if (loadingstage == LD_STAGE_PSHAPE_NUM) {

			if (sz_line[0] == '#' || sz_line[1] == '#')
				continue;

			if ((sz_line[0] != 'p' && sz_line[0] != 'P') ||
				(sz_line[1] != 's' && sz_line[1] != 'S')) {
				PHL_INFO("No PShape prefix: '%c','%c'(%d,%d), continue to CH ROW\n",
					sz_line[0], sz_line[1], sz_line[0], sz_line[1]);
				loadingstage = LD_STAGE_CH_ROW;
				goto line_start;
			}
			PHL_INFO("1.sz_line[0 1] %c %c", sz_line[0], sz_line[1]);
			i = 6;/* move to the  location behind 'e' */

			for (for_cnt = 0; for_cnt < col_num; ++for_cnt) {
				u32	i_ns;

				/* skip the space */
				while (sz_line[i] == ' ' || sz_line[i] == '\t')
					i++;
				i_ns = i;
				PHL_INFO("1.sz_line[%d] %c\n", i ,sz_line[i]);
				while (sz_line[i] != ' ' && sz_line[i] != '\t' && sz_line[i] != '\0')
					i++;

				pshape[for_cnt] = (char *)_os_mem_alloc(drv_priv, i - i_ns + 1);
				if (!pshape[for_cnt]) {
					PHL_ERR("Regulation alloc fail, pshape [%d]\n", for_cnt);
					goto exit;
				}
				PHL_INFO("2.pshape [%d] = %s\n", for_cnt, pshape[for_cnt]);

				_os_mem_cpy(drv_priv, pshape[for_cnt], sz_line + i_ns, i - i_ns);
				pshape[for_cnt][i - i_ns] = '\0';
				PHL_INFO(" forcnt %d shape idx: %s:", for_cnt, pshape[for_cnt]);
			}

			if (1) {
				PHL_INFO("pshape idx:");
				for (for_cnt = 0; for_cnt < col_num; ++for_cnt)
					PHL_INFO(" %s", pshape[for_cnt]);
				PHL_INFO("\n");
			}

			loadingstage = LD_STAGE_CH_ROW;
		} else if (loadingstage == LD_STAGE_CH_ROW) {
			char	channel[10] = {0}, powerlimit[10] = {0};
			u8	cnt = 0;

			/* the table ends */
			if (sz_line[0] == '#' && sz_line[1] == '#') {
				i = 2;
				while (sz_line[i] == ' ' || sz_line[i] == '\t')
					++i;

				if (_os_strncmp((char *)(sz_line + i), (const char *)"END", 3) == 0) {
					loadingstage = LD_STAGE_TAB_DEFINE;
					if (regulation) {
						for (for_cnt = 0; for_cnt < col_num; ++for_cnt) {
							if (regulation[for_cnt]) {
								_os_mem_free(drv_priv,
									(u8 *)regulation[for_cnt],
									_os_strlen((u8 *)regulation[for_cnt]) + 1);
								regulation[for_cnt] = NULL;
							}
						}
						_os_mem_free(drv_priv, (u8 *)regulation, sizeof(char *) * col_num);
						regulation = NULL;
					}
					if (pshape) {
						for (for_cnt = 0; for_cnt < col_num; ++for_cnt) {
							if (pshape[for_cnt]) {
								_os_mem_free(drv_priv,
									(u8 *)pshape[for_cnt],
									_os_strlen((u8 *)pshape[for_cnt]) + 1);
								pshape[for_cnt] = NULL;
							}
						}
						_os_mem_free(drv_priv, (u8 *)pshape, sizeof(char *) * col_num);
						pshape = NULL;
					}
					col_num = 0;
					continue;
				} else {
					PHL_ERR("Missing \"##	END\" label\n");
					struct_idx = 0;
					goto exit;
				}
			}

			if ((sz_line[0] != 'c' && sz_line[0] != 'C') ||
				(sz_line[1] != 'h' && sz_line[1] != 'H')) {
				PHL_ERR("Wrong channel prefix: '%c','%c'(%d,%d)\n",
					sz_line[0], sz_line[1], sz_line[0], sz_line[1]);
				continue;
			}
			i = 2;/* move to the  location behind 'h' */

			/* load the channel number */
			cnt = 0;
			while (sz_line[i] >= '0' && sz_line[i] <= '9') {
				channel[cnt] = sz_line[i];
				++cnt;
				++i;
			}
			PHL_INFO("chnl %s!\n", channel);

			for (for_cnt = 0; for_cnt < col_num; ++for_cnt) {
				/* skip the space between channel number and the power limit value */
				while (sz_line[i] == ' ' || sz_line[i] == '\t')
					++i;

				/* load the power limit value */
				_os_mem_set(drv_priv, (void *) powerlimit, 0, 10);

				if (sz_line[i] == 'W' && sz_line[i + 1] == 'W') {
					/*
					* case "WW" assign special ww value
					* means to get minimal limit in other regulations at same channel
					*/
					s8 ww_value = -63;//phy_txpwr_ww_lmt_value(Adapter);

					_os_snprintf(powerlimit, 10, "%d", ww_value);
					i += 2;

				} else if (sz_line[i] == 'N' && sz_line[i + 1] == 'A') {
					/*
					* case "NA" assign max txgi value
					* means no limitation
					*/
					_os_snprintf(powerlimit, 10, "%d", 127);
					i += 2;

				} else if ((sz_line[i] >= '0' && sz_line[i] <= '9') || sz_line[i] == '.'
					|| sz_line[i] == '+' || sz_line[i] == '-') {
					/* case of dBm value */
					u8 integer = 0, fraction = 0, negative = 0;
					u32 u4bmove;
					s8 lmt = 0;

					if (sz_line[i] == '+' || sz_line[i] == '-') {
						if (sz_line[i] == '-')
							negative = 1;
						i++;
					}

					if (hal_get_fractionvalue_fromstring(&sz_line[i], &integer, &fraction, &u4bmove))
						i += u4bmove;
					else {
						PHL_ERR("Limit \"%s\" is not valid decimal\n", &sz_line[i]);
						struct_idx = 0;
						goto exit;
					}
					/* transform to string of value in unit of txgi */
					lmt = (integer * 4) + ((u16)fraction * 4 / 100);
					if (negative)
						lmt = -lmt;
					_os_snprintf(powerlimit, 10, "%d", lmt);

					} else {
						PHL_ERR("Wrong limit expression \"%c%c\"(%d, %d)\n"
							, sz_line[i], sz_line[i + 1], sz_line[i], sz_line[i + 1]);
						struct_idx = 0;
						goto exit;
					}

					/* store the power limit value */
					hal_phy_store_tx_power_limit_ru(drv_priv,
									(u8 *)regulation[for_cnt], (u8 *)band,
									(u8 *)bandwidth, (u8 *)ratesection,
									(u8 *)ntx, (u8 *)channel, (u8 *)powerlimit,
									(u8 *)pshape[for_cnt],
									(void*)&array_tc_txpwr_lmt_ru[struct_idx],
									para_info);
					PHL_DBG("array_tc_txpwr_lmt_ru[%d] \n", struct_idx);
					struct_idx++;
					}
				}
	}
exit:
	if (regulation) {
		for (for_cnt = 0; for_cnt < col_num; ++for_cnt) {
			if (regulation[for_cnt]) {
				_os_mem_free(drv_priv,
					(u8 *)regulation[for_cnt],
					_os_strlen((u8 *)regulation[for_cnt]) + 1);
				regulation[for_cnt] = NULL;
			}
		}
		_os_mem_free(drv_priv, (u8 *)regulation, sizeof(char *) * col_num);
		regulation = NULL;
	}
	if (pshape) {
		for (for_cnt = 0; for_cnt < col_num; ++for_cnt) {
			if (pshape[for_cnt]) {
				_os_mem_free(drv_priv,
					(u8 *)pshape[for_cnt],
					_os_strlen((u8 *)pshape[for_cnt]) + 1);
				pshape[for_cnt] = NULL;
			}
		}
		_os_mem_free(drv_priv, (u8 *)pshape, sizeof(char *) * col_num);
		pshape = NULL;
	}

	return struct_idx;
}

static void hal_phy_store_tx_power_track(
		void *drv_priv,
		char *band,
		char *path,
		char *sign,
		char *channel,
		char *rate,
		char *data,
		void *txpwr_track_table)
{
#define STR_EQUAL_5G(_band, _path, _sign, _rate, _chnl) \
	((_os_strcmp(band, _band) == 0) && (_os_strcmp(path, _path) == 0) && (_os_strcmp(sign, _sign) == 0) &&\
	 (_os_strcmp(rate, _rate) == 0) && (_os_strcmp(channel, _chnl) == 0)\
	)
#define STR_EQUAL_2G(_band, _path, _sign, _rate) \
	((_os_strcmp(band, _band) == 0) && (_os_strcmp(path, _path) == 0) && (_os_strcmp(sign, _sign) == 0) &&\
	 (_os_strcmp(rate, _rate) == 0)\
	)

#define STORE_SWING_TABLE(_array, _iteratedIdx) \
	do {	\
	for (token = (char *)_os_strsep(&data, delim); token != (char *)NULL; token = (char *)_os_strsep(&data, delim)) {\
		_os_sscanf(token, "%d", &idx);\
		_array[_iteratedIdx++] = (s8)idx;\
	} } while (0)\

	struct hal_txpwr_track_t *prfcalibrateInfo = (struct hal_txpwr_track_t *)txpwr_track_table;

	u32	j = 0;
	char	*token;
	char	delim[] = ",";
	u32	idx = 0;

	PHL_INFO("===>initDeltaSwingIndexTables():"\
		"Band: %s;\nPath: %s;\nSign: %s;\nChannel: %s;\nRate: %s;\n, Data: %s;\n",
	band, path, sign, channel, rate, data);

	if (STR_EQUAL_2G("2G", "A", "+", "CCK"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_2g_cck_a_p, j);
	else if (STR_EQUAL_2G("2G", "A", "-", "CCK"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_2g_cck_a_n, j);
	else if (STR_EQUAL_2G("2G", "B", "+", "CCK"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_2g_cck_b_p, j);
	else if (STR_EQUAL_2G("2G", "B", "-", "CCK"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_2g_cck_b_n, j);
	else if (STR_EQUAL_2G("2G", "A", "+", "ALL"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_2ga_p, j);
	else if (STR_EQUAL_2G("2G", "A", "-", "ALL"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_2ga_n, j);
	else if (STR_EQUAL_2G("2G", "B", "+", "ALL"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_2gb_p, j);
	else if (STR_EQUAL_2G("2G", "B", "-", "ALL"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_2gb_n, j);
	else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "0"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5ga_p[0], j);
	else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "0"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5ga_n[0], j);
	else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "0"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5gb_p[0], j);
	else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "0"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5gb_n[0], j);
	else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "1"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5ga_p[1], j);
	else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "1"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5ga_n[1], j);
	else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "1"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5gb_p[1], j);
	else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "1"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5gb_n[1], j);
	else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "2"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5ga_p[2], j);
	else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "2"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5ga_n[2], j);
	else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "2"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5gb_p[2], j);
	else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "2"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5gb_n[2], j);
	else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "3"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5ga_p[3], j);
	else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "3"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5ga_n[3], j);
	else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "3"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5gb_p[3], j);
	else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "3"))
		STORE_SWING_TABLE(prfcalibrateInfo->delta_swing_table_idx_5gb_n[3], j);
	else
		PHL_INFO("===>initDeltaSwingIndexTables(): The input is invalid!!\n");
}

static int
_hal_parse_txpwrtrack(void *drv_priv, void *para_info_t, u8 *psrc_buf, u32 buflen)
{
	struct rtw_para_info_t *para_info = (struct rtw_para_info_t *)para_info_t;
	u32 *pdest_buf = para_info->para_data;
	char *sz_line = NULL, *ptmp = NULL;
	u32	i = 0;
	struct hal_txpwr_track_t *txpwr_track;

	if (pdest_buf == NULL || psrc_buf == NULL) {
		PHL_INFO("%s, fail !!! NULL buf !!!\n", __func__);
		return 0;
	}
	/* Assing destination buffer to be Txpwr_track table format*/
	txpwr_track = (struct hal_txpwr_track_t *)pdest_buf;

	ptmp = (char *)psrc_buf;
	for (sz_line = hal_getLinefrombuffer(ptmp); sz_line != NULL;
								sz_line = hal_getLinefrombuffer(ptmp))
	{
		if (!hal_is_comment_string(sz_line)) {
			char band[5] = "", path[5] = "", sign[5]  = "";
			char chnl[5] = "", rate[10] = "";
			char data[300] = ""; /* 100 is too small */

			if (_os_strlen((u8 *)sz_line) < 10 || sz_line[0] != '[')
				continue;

			_os_strncpy(band, sz_line + 1, 2);
			_os_strncpy(path, sz_line + 5, 1);
			_os_strncpy(sign, sz_line + 8, 1);

			i = 10; /* sz_line+10 */
			if (!hal_parse_fiedstring(sz_line, &i, rate, '[', ']')) {
				PHL_ERR("Fail to parse rate!\n");
			}
			if (!hal_parse_fiedstring(sz_line, &i, chnl, '[', ']')) {
				if (!_os_strcmp("5G",band))
					PHL_ERR("Fail to parse channel group!\n");
			}
			while (i < _os_strlen((u8 *)sz_line) && '{' != sz_line[i])
				i++;
			if (!hal_parse_fiedstring(sz_line, &i, data, '{', '}')) {
				PHL_ERR("Fail to parse data!\n");
			}
			hal_phy_store_tx_power_track(drv_priv,
						band, path, sign,
						chnl, rate, data,
						(void*)txpwr_track);
		}
	}
	return 1;
}

void
_hal_dl_para_file(struct rtw_phl_com_t *phl_com,
	void *para_info_t, char *ic_name,
	int (*parser_fun)(void *drv_priv, void *para_info_t, u8 *psrc_buf, u32 buflen),
	const char *file_name)
{
#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE

	void *drv = phl_com->drv_priv;
	char hal_phy_folder[MAX_PATH_LEN] = {0};
	char para_file_name[MAX_PATH_LEN] = {0};
	char *sp, *ext = NULL;
	u8 i, dot_pos;
	u32 para_size = 0, postfix_size = 0;
	u8 *para_buf = NULL;
	struct rtw_para_info_t *para_info = (struct rtw_para_info_t *)para_info_t;

	if (para_info->para_src == RTW_PARA_SRC_INTNAL) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "%s.parser_fun=NULL \n", file_name);
		return;
	}

	if (!parser_fun || (!para_info->para_data)) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "%s.parser_fun=NULL \n", file_name);
		para_info->para_src = RTW_PARA_SRC_INTNAL;
		return;
	}

	if ((para_info->para_data_len != 0) && (para_info->para_src == RTW_PARA_SRC_EXTNAL)) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "%s. para_data_len != 0 !!!\n", file_name);
		return;
	}

	para_buf = _os_mem_alloc(drv, MAX_HWCONFIG_FILE_CONTENT);
	if (!para_buf) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "para_buf=NULL \n");
		para_info->para_src = RTW_PARA_SRC_INTNAL;
		return;
	}


	if (para_info->para_src == RTW_PARA_SRC_EXTNAL_BUF) {
		if (para_info->ext_para_file_buf != 0) {
			/* Parsing file content */
			para_info->para_data_len =
				parser_fun(drv, para_info,
					   para_info->ext_para_file_buf,
					   para_info->ext_para_file_buf_len);

			if (para_info->para_data_len) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
					"%s:: Download file ok.\n", __FUNCTION__);
			} else {
				PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
					"%s:: Failed to parser %s \n",
					__FUNCTION__, file_name);
				para_info->para_src = RTW_PARA_SRC_INTNAL;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s:: Download file ok.\n", file_name);
		} else {
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s:: Error reading file.\n", file_name);

			para_info->para_src = RTW_PARA_SRC_INTNAL;
			para_info->para_data_len = 0;
		}
	} else if (para_info->para_src == RTW_PARA_SRC_EXTNAL) {
		_os_snprintf(para_info->para_path, MAX_PATH_LEN, "%s%s%s%s",
			     hal_phy_folder ,ic_name, _os_path_sep, file_name);

		/* Determine parameter folder path */
		if (para_info->hal_phy_folder != NULL) {
			_os_snprintf(hal_phy_folder, MAX_PATH_LEN, "%s",
						 para_info->hal_phy_folder);
		} else {
			_os_snprintf(hal_phy_folder, MAX_PATH_LEN, "%s%s%s",
					     HAL_FILE_CONFIG_PATH , ic_name, _os_path_sep);
		}

		/* Determine parameter file name */
		_os_strncpy(para_file_name, file_name, _os_strlen((u8 *)file_name)+1);

		/* Add postfix into original file name if it is specified by user */
		postfix_size = _os_strlen((u8 *)para_info->postfix);

		if (postfix_size != 0) {
			/* find the position of latest dot char in file name */
			sp = para_file_name;
			for (i = 0, dot_pos = 0; i < _os_strlen((u8 *)file_name); i++) {
				if (sp[i] == '.')
					dot_pos = i;
			}

			/* Get file extension name from original file name string */
			ext = (char *)file_name + dot_pos;

			/* Attach postfix, extension name and null terminator */
			_os_strncpy(sp + dot_pos, para_info->postfix, postfix_size);
			_os_strncpy(sp + dot_pos + postfix_size, ext, _os_strlen((u8 *)ext));
			*(sp + dot_pos + postfix_size + _os_strlen((u8 *)ext)) = '\0';
		}

		/* Generate final parameter file full path */
		_os_snprintf(para_info->para_path, MAX_PATH_LEN, "%s%s",
				 hal_phy_folder, para_file_name);

		PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s:: %s\n",__FUNCTION__,
			  para_info->para_path);

		para_size = _os_read_file(para_info->para_path, para_buf,
					  MAX_HWCONFIG_FILE_CONTENT);
	} else if (para_info->para_src == RTW_PARA_SRC_CUSTOM) {
		_os_mem_cpy(drv, para_buf, para_info->para_data, para_info->para_data_len);
		_os_mem_set(drv, para_info->para_data, 0, para_info->para_data_len);
		para_size = para_info->para_data_len;
		para_info->para_data_len = 0;
	}

	if (para_size != 0) {
		/* Parsing file content */
		para_info->para_data_len = parser_fun(drv, para_info, para_buf,
						      para_size);

		if (para_info->para_data_len) {
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s:: Download file ok.\n", __FUNCTION__);
		} else {
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
			"%s::Failed to parser %s \n",
			__FUNCTION__, file_name);
			para_info->para_src = RTW_PARA_SRC_INTNAL;
		}
	} else {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s:: Error reading file.\n",
			  file_name);

		para_info->para_src = RTW_PARA_SRC_INTNAL;
		para_info->para_data_len = 0;
	}
	_os_mem_free(drv, para_buf, MAX_HWCONFIG_FILE_CONTENT);
#endif
}

enum rtw_hal_status
_phl_pwrlmt_para_alloc(struct rtw_phl_com_t* phl_com,
				struct rtw_para_pwrlmt_info_t *para_info)
{
#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
	if (para_info->para_src == RTW_PARA_SRC_EXTNAL) {
		u32 file_buf_sz = MAX_HWCONFIG_FILE_CONTENT;
		u32 buf_sz = MAX_LINES_HWCONFIG_TXT;
		void *drv = phl_com->drv_priv;
		u8 para_regd_str_arridx;
		const char * const *_para_regd_str = rtw_hal_rf_get_predefined_pw_lmt_regu_type_str_array(&para_regd_str_arridx);
		u8 i = 0;

		for (i = 0; i < para_regd_str_arridx ; i++) {
			_os_strcpy(para_info->ext_regd_name[i] , _para_regd_str[i]);
			PHL_INFO(" prepare ext_regd_name[%d] = %s",
					i , para_info->ext_regd_name[i]);
		}
		para_info->ext_regd_arridx = para_regd_str_arridx;

		para_info->para_data = _os_mem_alloc(drv, file_buf_sz * sizeof(u32));
		if (!para_info->para_data) {
			PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_,
				"%s::para_data allocmem fail\n",__FUNCTION__);
			return RTW_HAL_STATUS_FAILURE;
		}

		para_info->ext_reg_codemap = _os_mem_alloc(drv, buf_sz * sizeof(u8));
		if (!para_info->ext_reg_codemap) {
			if (para_info->para_data)
				_os_mem_free(drv, para_info->para_data, file_buf_sz * sizeof(u32));
			para_info->para_data = NULL;
			PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_,
				"%s::ext_reg_codemap allocmem fail\n",__FUNCTION__);
			return RTW_HAL_STATUS_FAILURE;
		}
		return RTW_HAL_STATUS_SUCCESS;
	} else
		return RTW_HAL_STATUS_FAILURE;
#else
	return RTW_HAL_STATUS_FAILURE;
#endif
}

enum rtw_hal_status
phl_load_file_data_alloc(struct rtw_phl_com_t* phl_com, struct rtw_para_info_t *para_info)
{
#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
	u32 buf_sz = MAX_HWCONFIG_FILE_CONTENT;
	void *drv = phl_com->drv_priv;

	if (para_info->para_src == RTW_PARA_SRC_EXTNAL) {
		if (para_info->para_data_len == 0) {
			para_info->para_data = _os_mem_alloc(drv, buf_sz * sizeof(u32));
	}
	if (!para_info->para_data) {
			PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_,
				"%s:: allocmem fail\n",__FUNCTION__);
			return RTW_HAL_STATUS_FAILURE;
		}
		return RTW_HAL_STATUS_SUCCESS;
	} else
		return RTW_HAL_STATUS_FAILURE;
#else
	return RTW_HAL_STATUS_FAILURE;
#endif
}

void
rtw_hal_dl_all_para_file(struct rtw_phl_com_t *phl_com,
							char *ic_name, void *hal)
{
#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
	struct hal_info_t *hal_info = hal;
	struct phy_sw_cap_t *phy_sw_cap = NULL;
	u8 idx=0;
	u8 max_phy_num = 1;

	if (hal_info->hal_com->dbcc_en == true)
		max_phy_num = 2;

	for (idx=0; idx < max_phy_num; idx++) {/*Temp modiy for 1 BB phy Reg file */

		phy_sw_cap = &phl_com->phy_sw_cap[idx];
		if (phl_load_file_data_alloc(phl_com,
					&phy_sw_cap->bb_phy_reg_info) == RTW_HAL_STATUS_SUCCESS)
			_hal_dl_para_file(phl_com,
					&phy_sw_cap->bb_phy_reg_info,
					ic_name,
					_hal_parse_phyreg,
					"PHY_REG.txt");

		if (phl_load_file_data_alloc(phl_com,
					&phy_sw_cap->bb_phy_reg_gain_info) == RTW_HAL_STATUS_SUCCESS)
			_hal_dl_para_file(phl_com,
					&phy_sw_cap->bb_phy_reg_gain_info,
					ic_name,
					_hal_parse_phyreg,
					"PHY_REG_GAIN.txt");

		if (phl_load_file_data_alloc(phl_com,
					&phy_sw_cap->rf_radio_a_info) == RTW_HAL_STATUS_SUCCESS)
			_hal_dl_para_file(phl_com,
					&phy_sw_cap->rf_radio_a_info,
					ic_name,
					_hal_parse_radio,
					"RadioA.txt");

		if (phl_load_file_data_alloc(phl_com,
					&phy_sw_cap->rf_radio_b_info) == RTW_HAL_STATUS_SUCCESS)
			_hal_dl_para_file(phl_com,
					&phy_sw_cap->rf_radio_b_info,
					ic_name,
					_hal_parse_radio,
					"RadioB.txt");

		if (phl_load_file_data_alloc(phl_com,
				&phy_sw_cap->rf_txpwr_byrate_info) == RTW_HAL_STATUS_SUCCESS)
			_hal_dl_para_file(phl_com,
					&phy_sw_cap->rf_txpwr_byrate_info,
					ic_name,
					_hal_parse_txpwr_by_rate,
					"TXPWR_ByRate.txt");

		if (phl_load_file_data_alloc(phl_com,
				&phy_sw_cap->rf_txpwrtrack_info) == RTW_HAL_STATUS_SUCCESS)
			_hal_dl_para_file(phl_com,
					&phy_sw_cap->rf_txpwrtrack_info,
					ic_name,
					_hal_parse_txpwrtrack,
					"TXPWR_TrackTSSI.txt");

		if (_phl_pwrlmt_para_alloc(phl_com,
				&phy_sw_cap->rf_txpwrlmt_info) == RTW_HAL_STATUS_SUCCESS)
			_hal_dl_para_file(phl_com,
					&phy_sw_cap->rf_txpwrlmt_info,
					ic_name,
					_hal_parse_txpwrlmt,
					"TXPWR_LMT.txt");

		if (_phl_pwrlmt_para_alloc(phl_com,
				&phy_sw_cap->rf_txpwrlmt_ru_info) == RTW_HAL_STATUS_SUCCESS)
			_hal_dl_para_file(phl_com,
					&phy_sw_cap->rf_txpwrlmt_ru_info,
					ic_name,
					_hal_parse_txpwrlmt_ru,
					"TXPWR_LMT_RU.txt");
	}
#endif
}

u8 rtw_hal_ld_fw_symbol(struct rtw_phl_com_t *phl_com,
	struct rtw_hal_com_t *hal_com, const char *name, u8 **buf, u32 *buf_size)
{
	struct rtw_fw_info_t *fw_info = &phl_com->fw_info;
	char path[256] = {0};
	char *ic_name = NULL;
	char *intf = NULL;
	void *d = phlcom_to_drvpriv(phl_com);

	switch (phl_com->hci_type) {
	case RTW_HCI_PCIE:
		intf = "e";
		break;
	case RTW_HCI_USB:
		intf = "u";
		break;
	case RTW_HCI_SDIO:
		intf = "s";
		break;
	default:
		PHL_WARN("%s unknown hci type %u \n", __func__, phl_com->hci_type);
		return (u8)RTW_HAL_STATUS_FAILURE;
	}

	switch (hal_com->chip_id) {
	case CHIP_WIFI6_8852A:
		ic_name = "rtl8852a";
		break;
	case CHIP_WIFI6_8852B:
		ic_name = "rtl8852b";
		break;
	default:
		PHL_WARN("%s unknown chip id %u \n", __func__, hal_com->chip_id);
		return (u8)RTW_HAL_STATUS_FAILURE;
	}

	if (name == NULL || buf_size == NULL)
		return (u8)RTW_HAL_STATUS_FAILURE;

	if (!fw_info->sym_buf) {

		fw_info->sym_buf = _os_mem_alloc(d, RTW_MAX_FW_SIZE);
		if (!fw_info->sym_buf) {
			PHL_WARN("%s : buf for fw symbol allocate fail!!\n", __func__);
			return (u8)RTW_HAL_STATUS_FAILURE;
		}
	}
	_os_snprintf(path, MAX_PATH_LEN, "%s%s%s%s%s", FW_FILE_CONFIG_PATH,
		     ic_name, intf, _os_path_sep, name);

	PHL_INFO("%s : %s\n", __func__, path);

	fw_info->sym_buf_size = _os_read_file(path, fw_info->sym_buf,
		RTW_MAX_FW_SIZE);
	/* reading fw file failed */
	if (0 == fw_info->sym_buf_size)
		return (u8)RTW_HAL_STATUS_FAILURE;

	*buf = fw_info->sym_buf;
	*buf_size = fw_info->sym_buf_size;

	return (u8)RTW_HAL_STATUS_SUCCESS;
}

u8 rtw_hal_efuse_shadow_file_load(void *hal, char *ic_name, bool is_limit)
{
	u8 status = true;
#ifdef CONFIG_EFUSE_CONFIG_FILE
	struct rtw_hal_com_t *hal_com = (struct rtw_hal_com_t *)hal;
	struct hal_info_t *hal_info = (struct hal_info_t *)hal_com->hal_priv;
	char *hal_phy_folder = HAL_FILE_CONFIG_PATH;
	char file_path[256];

	_os_snprintf(file_path, MAX_PATH_LEN, "%s%s%s%s",
			hal_phy_folder , ic_name, _os_path_sep, "efuse.map");
	PHL_INFO("%s::open map path: %s\n", __FUNCTION__, file_path);

	status = rtw_hal_efuse_file_map_load(hal_info, file_path, is_limit);
	if (status == RTW_HAL_STATUS_FAILURE) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
				"%s:: %s FAIL\n", __FUNCTION__, file_path);
		status = false;
		goto exit;
	}

	_os_snprintf(file_path, MAX_PATH_LEN, "%s%s%s%s",
			hal_phy_folder , ic_name, _os_path_sep, "efuse.mask");
	PHL_INFO("%s::open mask path: %s\n", __FUNCTION__, file_path);

	status = rtw_hal_efuse_file_mask_load(hal_info, file_path, is_limit);
	if (status == RTW_HAL_STATUS_FAILURE) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
				"%s:: %s FAIL\n", __FUNCTION__, file_path);
		status = false;
		goto exit;
	}
exit:
#endif
	return status;
}

