// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
 *
 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
 *
 ******************************************************************************/

#include <linux/kernel.h>
#include <drv_types.h>
#include <rtw_debug.h>
#include "hal_com_h2c.h"

#include "odm_precomp.h"

u8 rtw_hal_data_init(struct adapter *padapter)
{
	if (is_primary_adapter(padapter)) {	/* if (padapter->isprimary) */
		padapter->hal_data_sz = sizeof(struct hal_com_data);
		padapter->HalData = vzalloc(padapter->hal_data_sz);
		if (!padapter->HalData)
			return _FAIL;
	}
	return _SUCCESS;
}

void rtw_hal_data_deinit(struct adapter *padapter)
{
	if (is_primary_adapter(padapter)) {	/* if (padapter->isprimary) */
		if (padapter->HalData) {
			vfree(padapter->HalData);
			padapter->HalData = NULL;
			padapter->hal_data_sz = 0;
		}
	}
}


void dump_chip_info(struct hal_version	ChipVersion)
{
	char buf[128];
	size_t cnt = 0;

	cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "Chip Version Info: CHIP_8723B_%s_",
			IS_NORMAL_CHIP(ChipVersion) ? "Normal_Chip" : "Test_Chip");

	if (IS_CHIP_VENDOR_TSMC(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "TSMC_");
	else if (IS_CHIP_VENDOR_UMC(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "UMC_");
	else if (IS_CHIP_VENDOR_SMIC(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "SMIC_");

	if (IS_A_CUT(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "A_CUT_");
	else if (IS_B_CUT(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "B_CUT_");
	else if (IS_C_CUT(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "C_CUT_");
	else if (IS_D_CUT(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "D_CUT_");
	else if (IS_E_CUT(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "E_CUT_");
	else if (IS_I_CUT(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "I_CUT_");
	else if (IS_J_CUT(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "J_CUT_");
	else if (IS_K_CUT(ChipVersion))
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "K_CUT_");
	else
		cnt += scnprintf(buf + cnt, sizeof(buf) - cnt,
				"UNKNOWN_CUT(%d)_", ChipVersion.CUTVersion);

	cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "1T1R_");

	cnt += scnprintf(buf + cnt, sizeof(buf) - cnt, "RomVer(%d)\n", ChipVersion.ROMVer);
}


#define	EEPROM_CHANNEL_PLAN_BY_HW_MASK	0x80

/*
 * Description:
 *Use hardware(efuse), driver parameter(registry) and default channel plan
 *to decide which one should be used.
 *
 * Parameters:
 *padapter			pointer of adapter
 *hw_channel_plan		channel plan from HW (efuse/eeprom)
 *					BIT[7] software configure mode; 0:Enable, 1:disable
 *					BIT[6:0] Channel Plan
 *sw_channel_plan		channel plan from SW (registry/module param)
 *def_channel_plan	channel plan used when HW/SW both invalid
 *AutoLoadFail		efuse autoload fail or not
 *
 * Return:
 *Final channel plan decision
 *
 */
u8 hal_com_config_channel_plan(
	struct adapter *padapter,
	u8 hw_channel_plan,
	u8 sw_channel_plan,
	u8 def_channel_plan,
	bool AutoLoadFail
)
{
	struct hal_com_data *pHalData;
	u8 chnlPlan;

	pHalData = GET_HAL_DATA(padapter);
	pHalData->bDisableSWChannelPlan = false;
	chnlPlan = def_channel_plan;

	if (0xFF == hw_channel_plan)
		AutoLoadFail = true;

	if (!AutoLoadFail) {
		u8 hw_chnlPlan;

		hw_chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK);
		if (rtw_is_channel_plan_valid(hw_chnlPlan)) {
			if (hw_channel_plan & EEPROM_CHANNEL_PLAN_BY_HW_MASK)
				pHalData->bDisableSWChannelPlan = true;

			chnlPlan = hw_chnlPlan;
		}
	}

	if (
		(false == pHalData->bDisableSWChannelPlan) &&
		rtw_is_channel_plan_valid(sw_channel_plan)
	)
		chnlPlan = sw_channel_plan;

	return chnlPlan;
}

bool HAL_IsLegalChannel(struct adapter *adapter, u32 Channel)
{
	bool bLegalChannel = true;

	if ((Channel <= 14) && (Channel >= 1)) {
		if (is_supported_24g(adapter->registrypriv.wireless_mode) == false)
			bLegalChannel = false;
	} else {
		bLegalChannel = false;
	}

	return bLegalChannel;
}

u8 MRateToHwRate(u8 rate)
{
	u8 ret = DESC_RATE1M;

	switch (rate) {
	case MGN_1M:
		ret = DESC_RATE1M;
		break;
	case MGN_2M:
		ret = DESC_RATE2M;
		break;
	case MGN_5_5M:
		ret = DESC_RATE5_5M;
		break;
	case MGN_11M:
		ret = DESC_RATE11M;
		break;
	case MGN_6M:
		ret = DESC_RATE6M;
		break;
	case MGN_9M:
		ret = DESC_RATE9M;
		break;
	case MGN_12M:
		ret = DESC_RATE12M;
		break;
	case MGN_18M:
		ret = DESC_RATE18M;
		break;
	case MGN_24M:
		ret = DESC_RATE24M;
		break;
	case MGN_36M:
		ret = DESC_RATE36M;
		break;
	case MGN_48M:
		ret = DESC_RATE48M;
		break;
	case MGN_54M:
		ret = DESC_RATE54M;
		break;
	case MGN_MCS0:
		ret = DESC_RATEMCS0;
		break;
	case MGN_MCS1:
		ret = DESC_RATEMCS1;
		break;
	case MGN_MCS2:
		ret = DESC_RATEMCS2;
		break;
	case MGN_MCS3:
		ret = DESC_RATEMCS3;
		break;
	case MGN_MCS4:
		ret = DESC_RATEMCS4;
		break;
	case MGN_MCS5:
		ret = DESC_RATEMCS5;
		break;
	case MGN_MCS6:
		ret = DESC_RATEMCS6;
		break;
	case MGN_MCS7:
		ret = DESC_RATEMCS7;
		break;
	default:
		break;
	}

	return ret;
}

u8 HwRateToMRate(u8 rate)
{
	u8 ret_rate = MGN_1M;

	switch (rate) {
	case DESC_RATE1M:
		ret_rate = MGN_1M;
		break;
	case DESC_RATE2M:
		ret_rate = MGN_2M;
		break;
	case DESC_RATE5_5M:
		ret_rate = MGN_5_5M;
		break;
	case DESC_RATE11M:
		ret_rate = MGN_11M;
		break;
	case DESC_RATE6M:
		ret_rate = MGN_6M;
		break;
	case DESC_RATE9M:
		ret_rate = MGN_9M;
		break;
	case DESC_RATE12M:
		ret_rate = MGN_12M;
		break;
	case DESC_RATE18M:
		ret_rate = MGN_18M;
		break;
	case DESC_RATE24M:
		ret_rate = MGN_24M;
		break;
	case DESC_RATE36M:
		ret_rate = MGN_36M;
		break;
	case DESC_RATE48M:
		ret_rate = MGN_48M;
		break;
	case DESC_RATE54M:
		ret_rate = MGN_54M;
		break;
	case DESC_RATEMCS0:
		ret_rate = MGN_MCS0;
		break;
	case DESC_RATEMCS1:
		ret_rate = MGN_MCS1;
		break;
	case DESC_RATEMCS2:
		ret_rate = MGN_MCS2;
		break;
	case DESC_RATEMCS3:
		ret_rate = MGN_MCS3;
		break;
	case DESC_RATEMCS4:
		ret_rate = MGN_MCS4;
		break;
	case DESC_RATEMCS5:
		ret_rate = MGN_MCS5;
		break;
	case DESC_RATEMCS6:
		ret_rate = MGN_MCS6;
		break;
	case DESC_RATEMCS7:
		ret_rate = MGN_MCS7;
		break;
	default:
		break;
	}

	return ret_rate;
}

void HalSetBrateCfg(struct adapter *Adapter, u8 *mBratesOS, u16 *pBrateCfg)
{
	u8 i, is_brate, brate;

	for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {

		is_brate = mBratesOS[i] & IEEE80211_BASIC_RATE_MASK;
		brate = mBratesOS[i] & 0x7f;

		if (is_brate) {
			switch (brate) {
			case IEEE80211_CCK_RATE_1MB:
				*pBrateCfg |= RATE_1M;
				break;
			case IEEE80211_CCK_RATE_2MB:
				*pBrateCfg |= RATE_2M;
				break;
			case IEEE80211_CCK_RATE_5MB:
				*pBrateCfg |= RATE_5_5M;
				break;
			case IEEE80211_CCK_RATE_11MB:
				*pBrateCfg |= RATE_11M;
				break;
			case IEEE80211_OFDM_RATE_6MB:
				*pBrateCfg |= RATE_6M;
				break;
			case IEEE80211_OFDM_RATE_9MB:
				*pBrateCfg |= RATE_9M;
				break;
			case IEEE80211_OFDM_RATE_12MB:
				*pBrateCfg |= RATE_12M;
				break;
			case IEEE80211_OFDM_RATE_18MB:
				*pBrateCfg |= RATE_18M;
				break;
			case IEEE80211_OFDM_RATE_24MB:
				*pBrateCfg |= RATE_24M;
				break;
			case IEEE80211_OFDM_RATE_36MB:
				*pBrateCfg |= RATE_36M;
				break;
			case IEEE80211_OFDM_RATE_48MB:
				*pBrateCfg |= RATE_48M;
				break;
			case IEEE80211_OFDM_RATE_54MB:
				*pBrateCfg |= RATE_54M;
				break;
			}
		}
	}
}

static void _OneOutPipeMapping(struct adapter *padapter)
{
	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);

	pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
	pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
	pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];/* BE */
	pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */

	pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
	pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
	pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
	pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
}

static void _TwoOutPipeMapping(struct adapter *padapter, bool bWIFICfg)
{
	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);

	if (bWIFICfg) { /* WMM */

		/* 	BK,	BE,	VI,	VO,	BCN,	CMD, MGT, HIGH, HCCA */
		/*   0,		1,	0,	1,	0,	0,	0,	0,		0	}; */
		/* 0:ep_0 num, 1:ep_1 num */

		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];/* VO */
		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */
		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */

		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */

	} else { /* typical setting */


		/* BK,	BE,	VI,	VO,	BCN,	CMD, MGT, HIGH, HCCA */
		/*   1,		1,	0,	0,	0,	0,	0,	0,		0	}; */
		/* 0:ep_0 num, 1:ep_1 num */

		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */
		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */

		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */

	}

}

static void _ThreeOutPipeMapping(struct adapter *padapter, bool bWIFICfg)
{
	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);

	if (bWIFICfg) { /* for WMM */

		/* 	BK,	BE,	VI,	VO,	BCN,	CMD, MGT, HIGH, HCCA */
		/*   1,		2,	1,	0,	0,	0,	0,	0,		0	}; */
		/* 0:H, 1:N, 2:L */

		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */
		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */
		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */

		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */

	} else { /* typical setting */


		/* 	BK,	BE,	VI,	VO,	BCN,	CMD, MGT, HIGH, HCCA */
		/*   2,		2,	1,	0,	0,	0,	0,	0,		0	}; */
		/* 0:H, 1:N, 2:L */

		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */
		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */
		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */

		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
	}

}

bool Hal_MappingOutPipe(struct adapter *padapter, u8 NumOutPipe)
{
	struct registry_priv *pregistrypriv = &padapter->registrypriv;

	bool bWIFICfg = (pregistrypriv->wifi_spec) ? true : false;

	bool result = true;

	switch (NumOutPipe) {
	case 2:
		_TwoOutPipeMapping(padapter, bWIFICfg);
		break;
	case 3:
	case 4:
		_ThreeOutPipeMapping(padapter, bWIFICfg);
		break;
	case 1:
		_OneOutPipeMapping(padapter);
		break;
	default:
		result = false;
		break;
	}

	return result;

}

void hal_init_macaddr(struct adapter *adapter)
{
	rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR, adapter->eeprompriv.mac_addr);
}

void rtw_init_hal_com_default_value(struct adapter *Adapter)
{
	struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);

	pHalData->AntDetection = 1;
}

/*
* C2H event format:
* Field	 TRIGGER		CONTENT	   CMD_SEQ	CMD_LEN		 CMD_ID
* BITS	 [127:120]	[119:16]      [15:8]		  [7:4]		   [3:0]
*/

void c2h_evt_clear(struct adapter *adapter)
{
	rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
}

/*
* C2H event format:
* Field    TRIGGER    CMD_LEN    CONTENT    CMD_SEQ    CMD_ID
* BITS    [127:120]   [119:112]    [111:16]	     [15:8]         [7:0]
*/
s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf)
{
	s32 ret = _FAIL;
	struct c2h_evt_hdr_88xx *c2h_evt;
	int i;
	u8 trigger;

	if (!buf)
		goto exit;

	trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR);

	if (trigger == C2H_EVT_HOST_CLOSE)
		goto exit; /* Not ready */
	else if (trigger != C2H_EVT_FW_CLOSE)
		goto clear_evt; /* Not a valid value */

	c2h_evt = (struct c2h_evt_hdr_88xx *)buf;

	memset(c2h_evt, 0, 16);

	c2h_evt->id = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL);
	c2h_evt->seq = rtw_read8(adapter, REG_C2HEVT_CMD_SEQ_88XX);
	c2h_evt->plen = rtw_read8(adapter, REG_C2HEVT_CMD_LEN_88XX);

	/* Read the content */
	for (i = 0; i < c2h_evt->plen; i++)
		c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 2 + i);

	ret = _SUCCESS;

clear_evt:
	/*
	* Clear event to notify FW we have read the command.
	* If this field isn't clear, the FW won't update the next command message.
	*/
	c2h_evt_clear(adapter);
exit:
	return ret;
}

u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type)
{
	return (network_type & WIRELESS_11B) ? RATEID_IDX_B : RATEID_IDX_G;
}

void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *psta)
{
	u8 i, limit;
	u32 tx_ra_bitmap;

	if (!psta)
		return;

	tx_ra_bitmap = 0;

	/* b/g mode ra_bitmap */
	for (i = 0; i < sizeof(psta->bssrateset); i++) {
		if (psta->bssrateset[i])
			tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f);
	}

	/* n mode ra_bitmap */
	if (psta->htpriv.ht_option) {
		limit = 8; /*   1R */

		for (i = 0; i < limit; i++) {
			if (psta->htpriv.ht_cap.mcs.rx_mask[i/8] & BIT(i%8))
				tx_ra_bitmap |= BIT(i+12);
		}
	}

	psta->ra_mask = tx_ra_bitmap;
	psta->init_rate = get_highest_rate_idx(tx_ra_bitmap)&0x3f;
}

void hw_var_port_switch(struct adapter *adapter)
{
}

void SetHwReg(struct adapter *adapter, u8 variable, u8 *val)
{
	struct hal_com_data *hal_data = GET_HAL_DATA(adapter);
	struct dm_odm_t *odm = &(hal_data->odmpriv);

	switch (variable) {
	case HW_VAR_PORT_SWITCH:
		hw_var_port_switch(adapter);
		break;
	case HW_VAR_INIT_RTS_RATE:
		rtw_warn_on(1);
		break;
	case HW_VAR_SEC_CFG:
	{
		u16 reg_scr;

		reg_scr = rtw_read16(adapter, REG_SECCFG);
		rtw_write16(adapter, REG_SECCFG, reg_scr|SCR_CHK_KEYID|SCR_RxDecEnable|SCR_TxEncEnable);
	}
		break;
	case HW_VAR_SEC_DK_CFG:
	{
		struct security_priv *sec = &adapter->securitypriv;
		u8 reg_scr = rtw_read8(adapter, REG_SECCFG);

		if (val) { /* Enable default key related setting */
			reg_scr |= SCR_TXBCUSEDK;
			if (sec->dot11AuthAlgrthm != dot11AuthAlgrthm_8021X)
				reg_scr |= (SCR_RxUseDK|SCR_TxUseDK);
		} else /* Disable default key related setting */
			reg_scr &= ~(SCR_RXBCUSEDK|SCR_TXBCUSEDK|SCR_RxUseDK|SCR_TxUseDK);

		rtw_write8(adapter, REG_SECCFG, reg_scr);
	}
		break;
	case HW_VAR_DM_FLAG:
		odm->SupportAbility = *((u32 *)val);
		break;
	case HW_VAR_DM_FUNC_OP:
		if (*((u8 *)val) == true) {
			/* save dm flag */
			odm->BK_SupportAbility = odm->SupportAbility;
		} else {
			/* restore dm flag */
			odm->SupportAbility = odm->BK_SupportAbility;
		}
		break;
	case HW_VAR_DM_FUNC_SET:
		if (*((u32 *)val) == DYNAMIC_ALL_FUNC_ENABLE) {
			struct dm_priv *dm = &hal_data->dmpriv;
			dm->DMFlag = dm->InitDMFlag;
			odm->SupportAbility = dm->InitODMFlag;
		} else {
			odm->SupportAbility |= *((u32 *)val);
		}
		break;
	case HW_VAR_DM_FUNC_CLR:
		/*
		* input is already a mask to clear function
		* don't invert it again! George, Lucas@20130513
		*/
		odm->SupportAbility &= *((u32 *)val);
		break;
	case HW_VAR_AMPDU_MIN_SPACE:
		/* TODO - Is something needed here? */
		break;
	case HW_VAR_WIRELESS_MODE:
		/* TODO - Is something needed here? */
		break;
	default:
		netdev_dbg(adapter->pnetdev,
			   FUNC_ADPT_FMT " variable(%d) not defined!\n",
			   FUNC_ADPT_ARG(adapter), variable);
		break;
	}
}

void GetHwReg(struct adapter *adapter, u8 variable, u8 *val)
{
	struct hal_com_data *hal_data = GET_HAL_DATA(adapter);
	struct dm_odm_t *odm = &(hal_data->odmpriv);

	switch (variable) {
	case HW_VAR_BASIC_RATE:
		*((u16 *)val) = hal_data->BasicRateSet;
		break;
	case HW_VAR_DM_FLAG:
		*((u32 *)val) = odm->SupportAbility;
		break;
	default:
		netdev_dbg(adapter->pnetdev,
			   FUNC_ADPT_FMT " variable(%d) not defined!\n",
			   FUNC_ADPT_ARG(adapter), variable);
		break;
	}
}




u8 SetHalDefVar(
	struct adapter *adapter, enum hal_def_variable variable, void *value
)
{
	struct hal_com_data *hal_data = GET_HAL_DATA(adapter);
	struct dm_odm_t *odm = &(hal_data->odmpriv);
	u8 bResult = _SUCCESS;

	switch (variable) {
	case HAL_DEF_DBG_RX_INFO_DUMP:

		if (odm->bLinked) {
			#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA
			rtw_dump_raw_rssi_info(adapter);
			#endif
		}
		break;
	case HW_DEF_ODM_DBG_FLAG:
		ODM_CmnInfoUpdate(odm, ODM_CMNINFO_DBG_COMP, *((u64 *)value));
		break;
	case HW_DEF_ODM_DBG_LEVEL:
		ODM_CmnInfoUpdate(odm, ODM_CMNINFO_DBG_LEVEL, *((u32 *)value));
		break;
	case HAL_DEF_DBG_DM_FUNC:
	{
		u8 dm_func = *((u8 *)value);
		struct dm_priv *dm = &hal_data->dmpriv;

		if (dm_func == 0) { /* disable all dynamic func */
			odm->SupportAbility = DYNAMIC_FUNC_DISABLE;
		} else if (dm_func == 1) {/* disable DIG */
			odm->SupportAbility  &= (~DYNAMIC_BB_DIG);
		} else if (dm_func == 2) {/* disable High power */
			odm->SupportAbility  &= (~DYNAMIC_BB_DYNAMIC_TXPWR);
		} else if (dm_func == 3) {/* disable tx power tracking */
			odm->SupportAbility  &= (~DYNAMIC_RF_CALIBRATION);
		} else if (dm_func == 4) {/* disable BT coexistence */
			dm->DMFlag &= (~DYNAMIC_FUNC_BT);
		} else if (dm_func == 5) {/* disable antenna diversity */
			odm->SupportAbility  &= (~DYNAMIC_BB_ANT_DIV);
		} else if (dm_func == 6) {/* turn on all dynamic func */
			if (!(odm->SupportAbility  & DYNAMIC_BB_DIG)) {
				struct dig_t	*pDigTable = &odm->DM_DigTable;
				pDigTable->CurIGValue = rtw_read8(adapter, 0xc50);
			}
			dm->DMFlag |= DYNAMIC_FUNC_BT;
			odm->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE;
		}
	}
		break;
	case HAL_DEF_DBG_DUMP_RXPKT:
		hal_data->bDumpRxPkt = *((u8 *)value);
		break;
	case HAL_DEF_DBG_DUMP_TXPKT:
		hal_data->bDumpTxPkt = *((u8 *)value);
		break;
	case HAL_DEF_ANT_DETECT:
		hal_data->AntDetection = *((u8 *)value);
		break;
	default:
		netdev_dbg(adapter->pnetdev,
			   "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n",
			   __func__, variable);
		bResult = _FAIL;
		break;
	}

	return bResult;
}

u8 GetHalDefVar(
	struct adapter *adapter, enum hal_def_variable variable, void *value
)
{
	struct hal_com_data *hal_data = GET_HAL_DATA(adapter);
	u8 bResult = _SUCCESS;

	switch (variable) {
	case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB:
		{
			struct mlme_priv *pmlmepriv;
			struct sta_priv *pstapriv;
			struct sta_info *psta;

			pmlmepriv = &adapter->mlmepriv;
			pstapriv = &adapter->stapriv;
			psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.mac_address);
			if (psta)
				*((int *)value) = psta->rssi_stat.UndecoratedSmoothedPWDB;
		}
		break;
	case HAL_DEF_DBG_DM_FUNC:
		*((u32 *)value) = hal_data->odmpriv.SupportAbility;
		break;
	case HAL_DEF_DBG_DUMP_RXPKT:
		*((u8 *)value) = hal_data->bDumpRxPkt;
		break;
	case HAL_DEF_DBG_DUMP_TXPKT:
		*((u8 *)value) = hal_data->bDumpTxPkt;
		break;
	case HAL_DEF_ANT_DETECT:
		*((u8 *)value) = hal_data->AntDetection;
		break;
	case HAL_DEF_MACID_SLEEP:
		*(u8 *)value = false;
		break;
	case HAL_DEF_TX_PAGE_SIZE:
		*((u32 *)value) = PAGE_SIZE_128;
		break;
	default:
		netdev_dbg(adapter->pnetdev,
			   "%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n",
			   __func__, variable);
		bResult = _FAIL;
		break;
	}

	return bResult;
}

void GetHalODMVar(
	struct adapter *Adapter,
	enum hal_odm_variable eVariable,
	void *pValue1,
	void *pValue2
)
{
	switch (eVariable) {
	default:
		break;
	}
}

void SetHalODMVar(
	struct adapter *Adapter,
	enum hal_odm_variable eVariable,
	void *pValue1,
	bool bSet
)
{
	struct hal_com_data	*pHalData = GET_HAL_DATA(Adapter);
	struct dm_odm_t *podmpriv = &pHalData->odmpriv;
	/* _irqL irqL; */
	switch (eVariable) {
	case HAL_ODM_STA_INFO:
		{
			struct sta_info *psta = pValue1;
			if (bSet) {
				ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta);
			} else {
				/* spin_lock_bh(&pHalData->odm_stainfo_lock); */
				ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL);

				/* spin_unlock_bh(&pHalData->odm_stainfo_lock); */
		    }
		}
		break;
	case HAL_ODM_P2P_STATE:
			ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet);
		break;
	case HAL_ODM_WIFI_DISPLAY_STATE:
			ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet);
		break;

	default:
		break;
	}
}


bool eqNByte(u8 *str1, u8 *str2, u32 num)
{
	if (num == 0)
		return false;
	while (num > 0) {
		num--;
		if (str1[num] != str2[num])
			return false;
	}
	return true;
}

/*  */
/* 	Description: */
/* 		Return true if chTmp is represent for hex digit and */
/* 		false otherwise. */
/*  */
/*  */
bool IsHexDigit(char chTmp)
{
	if (
		(chTmp >= '0' && chTmp <= '9') ||
		(chTmp >= 'a' && chTmp <= 'f') ||
		(chTmp >= 'A' && chTmp <= 'F')
	)
		return true;
	else
		return false;
}


/*  */
/* 	Description: */
/* 		Translate a character to hex digit. */
/*  */
u32 MapCharToHexDigit(char chTmp)
{
	if (chTmp >= '0' && chTmp <= '9')
		return chTmp - '0';
	else if (chTmp >= 'a' && chTmp <= 'f')
		return 10 + (chTmp - 'a');
	else if (chTmp >= 'A' && chTmp <= 'F')
		return 10 + (chTmp - 'A');
	else
		return 0;
}



/* 	Description: */
/* 		Parse hex number from the string pucStr. */
bool GetHexValueFromString(char *szStr, u32 *pu4bVal, u32 *pu4bMove)
{
	char *szScan = szStr;

	/*  Check input parameter. */
	if (!szStr || !pu4bVal || !pu4bMove)
		return false;

	/*  Initialize output. */
	*pu4bMove = 0;
	*pu4bVal = 0;

	/*  Skip leading space. */
	while (*szScan != '\0' && (*szScan == ' ' || *szScan == '\t')) {
		szScan++;
		(*pu4bMove)++;
	}

	/*  Skip leading '0x' or '0X'. */
	if (*szScan == '0' && (*(szScan+1) == 'x' || *(szScan+1) == 'X')) {
		szScan += 2;
		(*pu4bMove) += 2;
	}

	/*  Check if szScan is now pointer to a character for hex digit, */
	/*  if not, it means this is not a valid hex number. */
	if (!IsHexDigit(*szScan))
		return false;

	/*  Parse each digit. */
	do {
		(*pu4bVal) <<= 4;
		*pu4bVal += MapCharToHexDigit(*szScan);

		szScan++;
		(*pu4bMove)++;
	} while (IsHexDigit(*szScan));

	return true;
}

bool GetFractionValueFromString(
	char *szStr, u8 *pInteger, u8 *pFraction, u32 *pu4bMove
)
{
	char *szScan = szStr;

	/*  Initialize output. */
	*pu4bMove = 0;
	*pInteger = 0;
	*pFraction = 0;

	/*  Skip leading space. */
	while (*szScan != '\0' &&	(*szScan == ' ' || *szScan == '\t')) {
		++szScan;
		++(*pu4bMove);
	}

	/*  Parse each digit. */
	do {
		(*pInteger) *= 10;
		*pInteger += (*szScan - '0');

		++szScan;
		++(*pu4bMove);

		if (*szScan == '.') {
			++szScan;
			++(*pu4bMove);

			if (*szScan < '0' || *szScan > '9')
				return false;
			else {
				*pFraction = *szScan - '0';
				++szScan;
				++(*pu4bMove);
				return true;
			}
		}
	} while (*szScan >= '0' && *szScan <= '9');

	return true;
}

/*  */
/* 	Description: */
/* 		Return true if szStr is comment out with leading "//". */
/*  */
bool IsCommentString(char *szStr)
{
	if (*szStr == '/' && *(szStr+1) == '/')
		return true;
	else
		return false;
}

bool GetU1ByteIntegerFromStringInDecimal(char *Str, u8 *pInt)
{
	u16 i = 0;
	*pInt = 0;

	while (Str[i] != '\0') {
		if (Str[i] >= '0' && Str[i] <= '9') {
			*pInt *= 10;
			*pInt += (Str[i] - '0');
		} else
			return false;

		++i;
	}

	return true;
}

/*  <20121004, Kordan> For example,
 *  ParseQualifiedString(inString, 0, outString, '[', ']') gets "Kordan" from
 *  a string "Hello [Kordan]".
 *  If RightQualifier does not exist, it will hang in the while loop
 */
bool ParseQualifiedString(
	char *In, u32 *Start, char *Out, char LeftQualifier, char RightQualifier
)
{
	u32 i = 0, j = 0;
	char c = In[(*Start)++];

	if (c != LeftQualifier)
		return false;

	i = (*Start);
	while ((c = In[(*Start)++]) != RightQualifier)
		; /*  find ']' */
	j = (*Start) - 2;
	strncpy((char *)Out, (const char *)(In+i), j-i+1);

	return true;
}

bool isAllSpaceOrTab(u8 *data, u8 size)
{
	u8 cnt = 0, NumOfSpaceAndTab = 0;

	while (size > cnt) {
		if (data[cnt] == ' ' || data[cnt] == '\t' || data[cnt] == '\0')
			++NumOfSpaceAndTab;

		++cnt;
	}

	return size == NumOfSpaceAndTab;
}


void rtw_hal_check_rxfifo_full(struct adapter *adapter)
{
	struct dvobj_priv *psdpriv = adapter->dvobj;
	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
	int save_cnt = false;

	/* switch counter to RX fifo */
	/* printk("8723b or 8192e , MAC_667 set 0xf0\n"); */
	rtw_write8(adapter, REG_RXERR_RPT+3, rtw_read8(adapter, REG_RXERR_RPT+3)|0xf0);
	save_cnt = true;
	/* todo: other chips */

	if (save_cnt) {
		/* rtw_write8(adapter, REG_RXERR_RPT+3, rtw_read8(adapter, REG_RXERR_RPT+3)|0xa0); */
		pdbgpriv->dbg_rx_fifo_last_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow;
		pdbgpriv->dbg_rx_fifo_curr_overflow = rtw_read16(adapter, REG_RXERR_RPT);
		pdbgpriv->dbg_rx_fifo_diff_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow-pdbgpriv->dbg_rx_fifo_last_overflow;
	}
}

void linked_info_dump(struct adapter *padapter, u8 benable)
{
	struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);

	if (padapter->bLinkInfoDump == benable)
		return;

	if (benable) {
		pwrctrlpriv->org_power_mgnt = pwrctrlpriv->power_mgnt;/* keep org value */
		rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);

		pwrctrlpriv->ips_org_mode = pwrctrlpriv->ips_mode;/* keep org value */
		rtw_pm_set_ips(padapter, IPS_NONE);
	} else {
		rtw_pm_set_ips(padapter, pwrctrlpriv->ips_org_mode);

		rtw_pm_set_lps(padapter, pwrctrlpriv->ips_org_mode);
	}
	padapter->bLinkInfoDump = benable;
}

#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA
void rtw_get_raw_rssi_info(void *sel, struct adapter *padapter)
{
	u8 isCCKrate, rf_path;
	struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
	struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info;

	netdev_dbg(padapter->pnetdev,
		   "RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n",
		   HDATA_RATE(psample_pkt_rssi->data_rate),
		   psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all);

	isCCKrate = psample_pkt_rssi->data_rate <= DESC_RATE11M;

	if (isCCKrate)
		psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball;

	for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) {
		netdev_dbg(padapter->pnetdev,
			   "RF_PATH_%d =>signal_strength:%d(%%), signal_quality:%d(%%)\n",
			   rf_path,
			   psample_pkt_rssi->mimo_signal_strength[rf_path],
			   psample_pkt_rssi->mimo_signal_quality[rf_path]);

		if (!isCCKrate) {
			netdev_dbg(padapter->pnetdev,
				   "\trx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n",
				   psample_pkt_rssi->ofdm_pwr[rf_path],
				   psample_pkt_rssi->ofdm_snr[rf_path]);
		}
	}
}

void rtw_dump_raw_rssi_info(struct adapter *padapter)
{
	u8 isCCKrate, rf_path;
	struct hal_com_data *pHalData =  GET_HAL_DATA(padapter);
	struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info;

	isCCKrate = psample_pkt_rssi->data_rate <= DESC_RATE11M;

	if (isCCKrate)
		psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball;

	for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) {
		if (!isCCKrate) {
			printk(", rx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n",
			psample_pkt_rssi->ofdm_pwr[rf_path], psample_pkt_rssi->ofdm_snr[rf_path]);
		} else {
			printk("\n");
		}
	}
}

void rtw_store_phy_info(struct adapter *padapter, union recv_frame *prframe)
{
	u8 isCCKrate, rf_path;
	struct hal_com_data *pHalData =  GET_HAL_DATA(padapter);
	struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;

	struct odm_phy_info *pPhyInfo  = (PODM_PHY_INFO_T)(&pattrib->phy_info);
	struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info;

	psample_pkt_rssi->data_rate = pattrib->data_rate;
	isCCKrate = pattrib->data_rate <= DESC_RATE11M;

	psample_pkt_rssi->pwdball = pPhyInfo->rx_pwd_ba11;
	psample_pkt_rssi->pwr_all = pPhyInfo->recv_signal_power;

	for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) {
		psample_pkt_rssi->mimo_signal_strength[rf_path] = pPhyInfo->rx_mimo_signal_strength[rf_path];
		psample_pkt_rssi->mimo_signal_quality[rf_path] = pPhyInfo->rx_mimo_signal_quality[rf_path];
		if (!isCCKrate) {
			psample_pkt_rssi->ofdm_pwr[rf_path] = pPhyInfo->RxPwr[rf_path];
			psample_pkt_rssi->ofdm_snr[rf_path] = pPhyInfo->RxSNR[rf_path];
		}
	}
}
#endif

static u32 Array_kfreemap[] = {
	0xf8, 0xe,
	0xf6, 0xc,
	0xf4, 0xa,
	0xf2, 0x8,
	0xf0, 0x6,
	0xf3, 0x4,
	0xf5, 0x2,
	0xf7, 0x0,
	0xf9, 0x0,
	0xfc, 0x0,
};

void rtw_bb_rf_gain_offset(struct adapter *padapter)
{
	u8 value = padapter->eeprompriv.EEPROMRFGainOffset;
	u32 res, i = 0;
	u32 *Array = Array_kfreemap;
	u32 v1 = 0, v2 = 0, target = 0;

	if (value & BIT4) {
		if (padapter->eeprompriv.EEPROMRFGainVal != 0xff) {
			res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff);
			res &= 0xfff87fff;
			/* res &= 0xfff87fff; */
			for (i = 0; i < ARRAY_SIZE(Array_kfreemap); i += 2) {
				v1 = Array[i];
				v2 = Array[i+1];
				if (v1 == padapter->eeprompriv.EEPROMRFGainVal) {
					target = v2;
					break;
				}
			}
			PHY_SetRFReg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, BIT18|BIT17|BIT16|BIT15, target);

			/* res |= (padapter->eeprompriv.EEPROMRFGainVal & 0x0f)<< 15; */
			/* rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); */
			res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff);
		}
	}
}
