/*
 ***************************************************************************
 * MediaTek Inc.
 *
 * All rights reserved. source code is an unpublished work and the
 * use of a copyright notice does not imply otherwise. This source code
 * contains confidential trade secret material of MediaTek. Any attemp
 * or participation in deciphering, decoding, reverse engineering or in any
 * way altering the source code is stricitly prohibited, unless the prior
 * written consent of MediaTek, Inc. is obtained.
 ***************************************************************************

	Module Name:
	hdev_ctrl.c
*/
#include "rt_config.h"
#include "hdev/hdev.h"

/*
* local function
*/
#ifdef DBDC_MODE
static VOID hcGetBandTypeName(UCHAR Type, UCHAR *Str, UINT32 max_len)
{
	switch (Type) {
	case DBDC_TYPE_WMM:
		snprintf(Str, max_len, "%s", "WMM");
		break;

	case DBDC_TYPE_MGMT:
		snprintf(Str, max_len, "%s", "MGMT");
		break;

	case DBDC_TYPE_BSS:
		snprintf(Str, max_len, "%s", "BSS");
		break;

	case DBDC_TYPE_MBSS:
		snprintf(Str, max_len, "%s", "MBSS");
		break;

	case DBDC_TYPE_REPEATER:
		snprintf(Str, max_len, "%s", "REPEATER");
		break;

	case DBDC_TYPE_MU:
		snprintf(Str, max_len, "%s", "MU");
		break;

	case DBDC_TYPE_BF:
		snprintf(Str, max_len, "%s", "BF");
		break;

	case DBDC_TYPE_PTA:
		snprintf(Str, max_len, "%s", "PTA");
		break;
	}
}
#endif

/*
 *
*/
/*Only this function can use pAd*/
INT32 hdev_ctrl_init(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = NULL;
	UINT32 ret;

	ret = os_alloc_mem(NULL, (UCHAR **)&ctrl, sizeof(struct hdev_ctrl));

	if (ctrl == NULL) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_TRACE,
			 ("%s(): Allocate Hardware device Configure  fail!!\n",
			  __func__));
		return -1;
	}

	os_zero_mem(ctrl, sizeof(struct hdev_ctrl));
	ctrl->priv = (VOID *)pAd;
	pAd->hdev_ctrl = (VOID *)ctrl;
	return 0;
}

/*
*
*/
VOID hdev_resource_init(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;
	struct _RTMP_ADAPTER *ad = ctrl->priv;

	/*initial hardware resource*/
	HdevHwResourceInit(ctrl);
	/*initial resource*/
	/*hook hif*/
#if defined(RTMP_MAC_PCI)
	if (IS_PCIE_INF(ad) || IS_RBUS_INF(ad))
		ctrl->hif = &ad->PciHif;
#endif /*RTMP_MAC_PCI*/
	ctrl->cookie = ad->OS_Cookie;
	ctrl->mcu_ctrl = &ad->MCUCtrl;
	ctrl->arch_ops = &ad->archOps;
}

/*
 *
*/
VOID hdev_ctrl_exit(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	/*exist hw resource*/
	HdevHwResourceExit(ctrl);
	/*exist hdevcfg*/
	pAd->hdev_ctrl = NULL;
	os_free_mem(ctrl);
}

/*
 *
*/
VOID HcDevExit(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	UCHAR i;
	HD_RESOURCE_CFG *pHwResourceCfg = &ctrl->HwResourceCfg;

	for (i = 0; i < pHwResourceCfg->concurrent_bands; i++)
		HdevExit(ctrl, i);
}

/*
*
*/
INT32 HcAcquireRadioForWdev(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	INT32 ret = HC_STATUS_OK;
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	struct radio_dev *rdev = NULL;
	struct hdev_obj *obj = wdev->pHObj;

	rdev = RcAcquiredBandForObj(ctrl, obj, wdev->wdev_idx, wdev->PhyMode,
				    wdev->channel, wdev->wdev_type);

	/*correct wdev configure, if configure is not sync with hdev */
	if (!wmode_band_equal(wdev->PhyMode, RcGetPhyMode(rdev))) {
		wdev->PhyMode = RcGetPhyMode(rdev);
		wdev->channel = RcGetChannel(rdev);
	}

#ifdef EXT_BUILD_CHANNEL_LIST
	BuildChannelListEx(pAd);
#else
	BuildChannelList(pAd, wdev);
#endif
	/*temporal set, will be repaced by HcGetOmacIdx*/
	wdev->OmacIdx = obj->OmacIdx;
	/* Initialize the pDot11H of wdev */
	UpdateDot11hForWdev(wdev->sys_handle, wdev, TRUE);
	/*re-init operation*/
	wlan_operate_init(wdev);
	return ret;
}

/*
*
*/
INT32 HcReleaseRadioForWdev(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	INT32 ret = 0;
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	struct hdev_obj *obj = wdev->pHObj;

	OS_SPIN_LOCK(&obj->RefCntLock);

	if (obj->RefCnt > 0) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_OFF,
			 ("%s(): there are other link reference the Obj\n",
			  __func__));
		OS_SPIN_UNLOCK(&obj->RefCntLock);
		return ret;
	}

	OS_SPIN_UNLOCK(&obj->RefCntLock);
	RcReleaseBandForObj(ctrl, obj);
	return ret;
}

/*
*
*/
UCHAR HcGetBandByWdev(struct wifi_dev *wdev)
{
	UCHAR BandIdx = 0;
	struct hdev_obj *obj;
	struct _RTMP_ADAPTER *ad = (struct _RTMP_ADAPTER *)wdev->sys_handle;

	ASSERT(wdev);
	/* exit from here if wdev is null */
	if (!wdev)
		return 0;

	obj = wdev->pHObj;
	if (hdev_obj_state_ready(obj))
		BandIdx = RcGetBandIdx(obj->rdev);
	else {
		if ((ad->CommonCfg.dbdc_mode) && (!BOARD_IS_5G_ONLY(ad))) {
			if (WMODE_CAP_5G(wdev->PhyMode))
				BandIdx = DBDC_BAND1;
			else
				BandIdx = DBDC_BAND0;
		} else
			BandIdx = 0;
	}

	return BandIdx;
}

/*
*
*/
VOID HcSetRadioCurStatByWdev(struct wifi_dev *wdev, PHY_STATUS CurStat)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (hdev_obj_state_ready(obj))
		RcSetRadioCurStat(obj->rdev, CurStat);
	else
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): obj is not ready!!\n", __func__));
}

/*
*
*/
VOID HcSetRadioCurStatByChannel(RTMP_ADAPTER *pAd, UCHAR Channel,
				PHY_STATUS CurStat)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	struct radio_dev *rdev = NULL;

	rdev = RcGetHdevByChannel(ctrl, Channel);

	if (!rdev) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_INFO,
			 ("%s(): no hdev parking on channel:%d !!!\n", __func__,
			  Channel));
		return;
	}

	RcSetRadioCurStat(rdev, CurStat);
}

/*
*
*/
VOID HcSetAllSupportedBandsRadioOff(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = (struct hdev_ctrl *)pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResourceCfg = &ctrl->HwResourceCfg;
	struct radio_dev *rdev = NULL;
	UCHAR i;

	for (i = 0; i < pHwResourceCfg->concurrent_bands; i++) {
		rdev = &ctrl->rdev[i];
		rdev->pRadioCtrl->CurStat = PHY_RADIOOFF;
	}
}

/*
*
*/
VOID HcSetAllSupportedBandsRadioOn(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResourceCfg = &ctrl->HwResourceCfg;
	struct radio_dev *rdev = NULL;
	UCHAR i;

	for (i = 0; i < pHwResourceCfg->concurrent_bands; i++) {
		rdev = &ctrl->rdev[i];
		rdev->pRadioCtrl->CurStat = PHY_INUSE;
	}
}

/*
*
*/
BOOLEAN IsHcRadioCurStatOffByWdev(struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(
			DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			("%s(): wdev_idx %d obj is not ready, return TRUE !!!\n",
			 __func__, wdev->wdev_idx));
		return TRUE;
	}

	if (!obj->rdev) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_TRACE,
			 ("%s(): no hdev parking on wdev_idx:%d!!!\n", __func__,
			  wdev->wdev_idx));
		return TRUE;
	}

	if (RcGetRadioCurStat(obj->rdev) == PHY_RADIOOFF)
		return TRUE;
	else
		return FALSE;
}

/*
*
*/
BOOLEAN IsHcRadioCurStatOffByChannel(RTMP_ADAPTER *pAd, UCHAR Channel)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	struct radio_dev *rdev = NULL;

	rdev = RcGetHdevByChannel(ctrl, Channel);

	if (!rdev) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_INFO,
			 ("%s(): no hdev parking on channel:%d!!!\n", __func__,
			  Channel));
		return TRUE;
	}

	if (RcGetRadioCurStat(rdev) == PHY_RADIOOFF)
		return TRUE;
	else
		return FALSE;
}

/*
*
*/
BOOLEAN IsHcAllSupportedBandsRadioOff(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResourceCfg = &ctrl->HwResourceCfg;
	struct radio_dev *rdev = NULL;
	UCHAR i;
	BOOLEAN AllSupportedBandsRadioOff = TRUE;

	for (i = 0; i < pHwResourceCfg->concurrent_bands; i++) {
		rdev = &ctrl->rdev[i];

		if ((rdev->pRadioCtrl->CurStat == PHY_INUSE) &&
		    (rdev->pRadioCtrl->CurStat != PHY_RADIOOFF)) {
			AllSupportedBandsRadioOff = FALSE;
			break;
		}
	}

	return AllSupportedBandsRadioOff;
}

#ifdef GREENAP_SUPPORT
/*
*
*/
VOID HcSetGreenAPActiveByBand(RTMP_ADAPTER *pAd, UCHAR BandIdx,
			      BOOLEAN bGreenAPActive)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	struct radio_dev *rdev = NULL;

	if (!ctrl)
		return;

	rdev = &ctrl->rdev[BandIdx];

	if (!rdev)
		return;

	rdev->pRadioCtrl->bGreenAPActive = bGreenAPActive;
}

/*
*
*/
BOOLEAN IsHcGreenAPActiveByBand(RTMP_ADAPTER *pAd, UCHAR BandIdx)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	struct radio_dev *rdev = NULL;

	if (!ctrl)
		return FALSE;

	rdev = &ctrl->rdev[BandIdx];

	if (!rdev)
		return FALSE;

	return rdev->pRadioCtrl->bGreenAPActive;
}

/*
*
*/
BOOLEAN IsHcGreenAPActiveByWdev(struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;
	struct radio_dev *rdev = NULL;

	if (!hdev_obj_state_ready(obj))
		return FALSE;

	rdev = obj->rdev;

	return rdev->pRadioCtrl->bGreenAPActive;
}
#endif /* GREENAP_SUPPORT */

/*
*
*/
UCHAR HcGetChannelByBf(RTMP_ADAPTER *pAd)
{
	struct radio_dev *rdev = RcGetBandIdxByBf(pAd->hdev_ctrl);

	if (rdev == NULL) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): no hdev can support beamform!\n", __func__));
		return 0;
	}

	return rdev->pRadioCtrl->Channel;
}

/*
*
*/
BOOLEAN HcIsBfCapSupport(struct wifi_dev *wdev)
{
	if (!hdev_obj_state_ready(wdev->pHObj))
		return FALSE;

	return RcIsBfCapSupport(wdev->pHObj);
}

#ifdef MAC_REPEATER_SUPPORT
/*
*
*/
INT32 HcAddRepeaterEntry(struct wifi_dev *wdev, UINT32 ReptIdx)
{
	INT32 ret = 0;
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return HC_STATUS_FAIL;
	}

	/*Acquire Repeater OMACIdx*/
	OcAddRepeaterEntry(obj, ReptIdx);
	RcUpdateRepeaterEntry(obj->rdev, ReptIdx);
	return ret;
}

/*
*
*/
INT32 HcDelRepeaterEntry(struct wifi_dev *wdev, UINT32 ReptIdx)
{
	INT32 ret = 0;
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return HC_STATUS_FAIL;
	}

	/*Acquire Repeater OMACIdx*/
	OcDelRepeaterEntry(obj, ReptIdx);
	return ret;
}

/*
*
*/
UCHAR HcGetRepeaterOmac(RTMP_ADAPTER *pAd, MAC_TABLE_ENTRY *pEntry)
{
	REPEATER_CLIENT_ENTRY *pReptEntry = NULL;
	HD_REPT_ENRTY *pHReptEntry = NULL;
	UCHAR ReptOmacIdx = 0xff;

	pReptEntry = RTMPLookupRepeaterCliEntry(pAd, FALSE, pEntry->ReptCliAddr,
						TRUE);

	if (pReptEntry) {
		pHReptEntry = OcGetRepeaterEntry(pReptEntry->wdev->pHObj,
						 pReptEntry->MatchLinkIdx);

		if (pHReptEntry)
			ReptOmacIdx = pHReptEntry->ReptOmacIdx;
	}

	MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_TRACE,
		 ("%s(): Get ReptOmacIdx: %d!\n", __func__, ReptOmacIdx));
	return ReptOmacIdx;
}
#endif /*#MAC_REPEATER_SUPPORT*/

/*
*
*/
INT32 HcRadioInit(RTMP_ADAPTER *pAd, UCHAR RfIC, UCHAR DbdcMode)
{
	INT32 ret = 0;
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;

	RcRadioInit(ctrl, RfIC, DbdcMode);
	return ret;
}

/*
*
*/
INT32 HcUpdateCsaCntByChannel(RTMP_ADAPTER *pAd, UCHAR Channel)
{
	INT32 ret = 0;
	struct radio_dev *rdev = NULL;
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	struct hdev_obj *obj;
	struct wifi_dev *wdev;
	struct DOT11_H *pDot11h = NULL;

	rdev = RcGetHdevByChannel(ctrl, Channel);
	if (!rdev) {
		MTWF_LOG(
			DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			("%s(): Update Channel %d faild, not support this RF\n",
			 __func__, Channel));
		return -1;
	}

	DlListForEach(obj, &rdev->DevObjList, struct hdev_obj, list)
	{
		wdev = pAd->wdev_list[obj->Idx];

		if (wdev == NULL)
			continue;

		pDot11h = wdev->pDot11_H;

		if (pDot11h == NULL)
			return -1;
#ifdef CUSTOMER_DCC_FEATURE
		if (pAd->CommonCfg.channelSwitch.CHSWMode ==
		    CHANNEL_SWITCHING_MODE) {
			wdev->csa_count =
				pAd->CommonCfg.channelSwitch.CHSWPeriod;
			UpdateBeaconHandler(pAd, wdev, BCN_UPDATE_IE_CHG);
		} else
#endif
			if (pDot11h->RDMode != RD_SILENCE_MODE) {
			pAd->CommonCfg.set_ch_async_flag = TRUE;
			pDot11h->wdev_count++;
			wdev->csa_count = pDot11h->CSPeriod;
			UpdateBeaconHandler(pAd, wdev, BCN_UPDATE_IE_CHG);
		}
	}
	return ret;
}

#ifdef DBDC_MODE
/*
*
*/
VOID HcShowBandInfo(RTMP_ADAPTER *pAd)
{
	UINT32 i;
	BCTRL_INFO_T BctrlInfo;
	BCTRL_ENTRY_T *pEntry = NULL;
	CHAR TempStr[16] = "";

	os_zero_mem(&BctrlInfo, sizeof(BCTRL_INFO_T));
	AsicGetDbdcCtrl(pAd, &BctrlInfo);
	MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
		 ("\tDbdcEnable: %d\n", BctrlInfo.DBDCEnable));

	for (i = 0; i < BctrlInfo.TotalNum; i++) {
		pEntry = &BctrlInfo.BctrlEntries[i];
		hcGetBandTypeName(pEntry->Type, TempStr, sizeof(TempStr));

		if (pEntry->Type != DBDC_TYPE_MBSS)
			MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
				 ("\t(%s,%d): Band %d\n", TempStr,
				  pEntry->Index, pEntry->BandIdx));
		else
			MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
				 ("\t(%s,0-%d): Band %d\n", TempStr,
				  pEntry->Index + 1, pEntry->BandIdx));
	}
}
#endif

VOID HcShowChCtrlInfo(struct _RTMP_ADAPTER *pAd)
{
	UCHAR BandIdx, ChIdx;
	CHANNEL_CTRL *pChCtrl;

	MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
		 ("=====================START====================\n "));
	MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
		 ("---------------------------------------------\n "));

	for (BandIdx = 0; BandIdx < DBDC_BAND_NUM; BandIdx++) {
		pChCtrl = hc_get_channel_ctrl(pAd->hdev_ctrl, BandIdx);

		if (pChCtrl->ChListNum == 0) {
			MTWF_LOG(
				DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_TRACE,
				("\t\x1b[1;33mBandIdx = %d\x1b[m, ChannelListNum = %d (it is not available)\n ",
				 BandIdx, pChCtrl->ChListNum));
			break;
		} else {
			MTWF_LOG(
				DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
				("\t\x1b[1;33mBandIdx = %d\x1b[m, ChannelListNum = %d\n ",
				 BandIdx, pChCtrl->ChListNum));
			MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
				 ("\tChGrpABandEn = %d\n ",
				  pChCtrl->ChGrpABandEn));
			MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
				 ("\tChannel list information:\n "));
			MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
				 ("\tChannel \tPwr0/1 \t\tFlags\n "));
			for (ChIdx = 0; ChIdx < pChCtrl->ChListNum; ChIdx++) {
				MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL,
					 DBG_LVL_OFF,
					 ("\t#%d \t\t%d/%d \t\t%x\n ",
					  pChCtrl->ChList[ChIdx].Channel,
					  pChCtrl->ChList[ChIdx].Power,
					  pChCtrl->ChList[ChIdx].Power2,
					  pChCtrl->ChList[ChIdx].Flags));
			}
		}
		MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
			 ("---------------------------------------------\n "));
	}
	MTWF_LOG(DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_OFF,
		 ("=====================END=====================\n "));
}
#ifdef GREENAP_SUPPORT
/*
 *
 */
VOID HcShowGreenAPInfo(RTMP_ADAPTER *pAd)
{
	struct greenap_ctrl *greenap = &pAd->ApCfg.greenap;

	greenap_show(pAd, greenap);
}
#endif /* GREENAP_SUPPORT */

/*
*
*/
void hc_show_edca_info(struct _RTMP_ADAPTER *ad)
{
	struct hdev_ctrl *ctrl = ad->hdev_ctrl;

	WcShowEdca(ctrl);
}

/*
*
*/
void hc_show_radio_info(struct _RTMP_ADAPTER *ad)
{
	struct hdev_ctrl *ctrl = ad->hdev_ctrl;

	HdevCfgShow(ctrl);
}

/*
*
*/
void hc_show_hdev_obj(struct wifi_dev *wdev)
{
	if (!hdev_obj_state_ready(wdev->pHObj))
		return;

	HdevObjShow(wdev->pHObj);
}

/*
*
*/
VOID HcAcquiredEdca(RTMP_ADAPTER *pAd, struct wifi_dev *wdev, EDCA_PARM *pEdca)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return;
	}
	WcAcquiredEdca(obj, pEdca);
}

/*
*
*/
VOID HcReleaseEdca(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return;
	}
	WcReleaseEdca(obj);
}

/*
*
*/
VOID HcSetEdca(struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return;
	}
	WcSetEdca(obj);
}

/*
*
*/
UCHAR HcGetOmacIdx(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return 0xff;
	}
	return obj->OmacIdx;
}

/*
*  Need refine
*/

/*
* Only temporal usage, should remove when cmm_asic_xxx.c is not apply pAd
*/

UCHAR HcGetChannelByRf(RTMP_ADAPTER *pAd, UCHAR RfIC)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;
	UCHAR i;

	for (i = 0; i < pHwResource->concurrent_bands; i++) {
		if (pHwResource->PhyCtrl[i].rf_band_cap & RfIC)
			return pHwResource->PhyCtrl[i].RadioCtrl.Channel;
	}

	return 0;
}

/*
* for Single Band Usage
*/
UCHAR HcGetRadioChannel(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;

	return pHwResource->PhyCtrl[0].RadioCtrl.Channel;
}

/*
*
*/
UCHAR HcGetRadioPhyMode(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;

	return pHwResource->PhyCtrl[0].RadioCtrl.PhyMode;
}

UCHAR HcGetRadioPhyModeByBandIdx(RTMP_ADAPTER *pAd, UCHAR BandIdx)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;

	return pHwResource->PhyCtrl[BandIdx].RadioCtrl.PhyMode;
}
/*
*
*/
UCHAR HcGetRadioRfIC(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;

	return ctrl->HwResourceCfg.PhyCtrl[0].rf_band_cap;
}

/*
*
*/
BOOLEAN HcIsRfSupport(RTMP_ADAPTER *pAd, UCHAR RfIC)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;
	UCHAR i;

	for (i = 0; i < pHwResource->concurrent_bands; i++) {
		if (pHwResource->PhyCtrl[i].rf_band_cap & RfIC)
			return TRUE;
	}

	return FALSE;
}

/*
*
*/
BOOLEAN HcIsRfRun(RTMP_ADAPTER *pAd, UCHAR RfIC)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;
	struct radio_dev *rdev;
	UCHAR i;

	for (i = 0; i < pHwResource->concurrent_bands; i++) {
		rdev = &ctrl->rdev[i];

		if (WMODE_CAP_2G(rdev->pRadioCtrl->PhyMode) &&
		    (RfIC & RFIC_24GHZ))
			return TRUE;
		else if (WMODE_CAP_5G(rdev->pRadioCtrl->PhyMode) &&
			 (RfIC & RFIC_5GHZ))
			return TRUE;
	}

	return FALSE;
}

#ifdef CONFIG_AP_SUPPORT
#ifdef AP_QLOAD_SUPPORT
/*
*
*/
QLOAD_CTRL *HcGetQloadCtrlByRf(RTMP_ADAPTER *pAd, UINT32 RfIC)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;
	UCHAR i;

	for (i = 0; i < pHwResource->concurrent_bands; i++) {
		if (pHwResource->PhyCtrl[i].rf_band_cap & RfIC)
			return &pHwResource->PhyCtrl[i].QloadCtrl;
	}

	return 0;
}

/*
*
*/
QLOAD_CTRL *HcGetQloadCtrl(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;

	return &pHwResource->PhyCtrl[0].QloadCtrl;
}
#endif /*AP_QLOAD_SUPPORT*/

/*
*
*/
AUTO_CH_CTRL *HcGetAutoChCtrl(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;

	return &pHwResource->PhyCtrl[0].AutoChCtrl;
}
#endif /*CONFIG_AP_SUPPORT*/
#ifdef CONFIG_AP_SUPPORT
AUTO_CH_CTRL *HcGetAutoChCtrlbyBandIdx(RTMP_ADAPTER *pAd, UCHAR BandIdx)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;

	return &pHwResource->PhyCtrl[BandIdx].AutoChCtrl;
}
#endif

#ifdef CHANNEL_SWITCH_MONITOR_CONFIG
struct ch_switch_cfg *HcGetChanSwitchMonbyBandIdx(RTMP_ADAPTER *pAd,
						  UCHAR BandIdx)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	HD_RESOURCE_CFG *pHwResource = &ctrl->HwResourceCfg;

	return &pHwResource->PhyCtrl[BandIdx].ch_sw_cfg;
}
#endif

/*
*
*/
UCHAR HcGetBw(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return 0xff;
	}

	return RcGetBw(obj->rdev);
}

/*
*
*/
UINT32 HcGetMgmtQueueIdx(RTMP_ADAPTER *pAd, struct wifi_dev *wdev,
			 enum PACKET_TYPE pkt_type)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return TxQ_IDX_ALTX0;
	}

	return RcGetMgmtQueueIdx(obj, pkt_type);
}

/*
*
*/
UINT32 HcGetBcnQueueIdx(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return TxQ_IDX_BCN0;
	}

	return RcGetBcnQueueIdx(obj);
}

/*
*
*/
UINT32 HcGetTxRingIdx(RTMP_ADAPTER *pAd, struct wifi_dev *wdev,
		      enum PACKET_TYPE pkt_type, UCHAR q_idx)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return 0;
	}

	return RcGetTxRingIdx(obj);
}

/*
*
*/
UINT32 HcGetWmmIdx(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return 0;
	}

	return RcGetWmmIdx(obj);
}

#ifdef CUSTOMER_DCC_FEATURE
INT32 HcUpdateExtCha(RTMP_ADAPTER *pAd, UCHAR Channel, UCHAR ExtCha)
{
	INT32 ret = 0;
	struct radio_dev *pHdev = NULL;
	struct hdev_ctrl *pHdCfg = (struct hdev_ctrl *)pAd->hdev_ctrl;

	pHdev = RcGetHdevByChannel(pHdCfg, Channel);
	if (!pHdev) {
		MTWF_LOG(
			DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			("%s(): Get Hdev by Channel %d faild, not support this RF\n",
			 __FUNCTION__, Channel));
		return -1;
	}

	/*Update ExtCha to radio*/
	ret = RcUpdateExtCha(pHdev, ExtCha);

	return ret;
}

UCHAR HcGetExtCha(RTMP_ADAPTER *pAd, UCHAR Channel)
{
	struct radio_dev *rdev = NULL;
	struct hdev_ctrl *pHdCfg = pAd->hdev_ctrl;

	rdev = RcGetHdevByChannel(pHdCfg, Channel);

	if (!rdev) {
		MTWF_LOG(
			DBG_CAT_ALL, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			("%s(): Get Hdev by Channel %d faild, not support this RF\n",
			 __FUNCTION__, Channel));
		return 0;
	}
	return RcGetExtCha(rdev);
}
#endif

/*
*
*/
UCHAR HcGetBandByChannel(RTMP_ADAPTER *pAd, UCHAR Channel)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	struct radio_dev *rdev = NULL;
	UCHAR BandIdx;

	rdev = RcGetHdevByChannel(ctrl, Channel);

	if (!rdev) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_INFO,
			 ("%s(): no hdev parking on channel:%d!\n", __func__,
			  Channel));
		return 0;
	}

	BandIdx = RcGetBandIdx(rdev);
	return BandIdx;
}

/*
*
*/
EDCA_PARM *HcGetEdca(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	EDCA_PARM *pEdca = NULL;
	struct hdev_obj *obj = wdev->pHObj;
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return NULL;
	}

	pEdca = WcGetWmmByIdx(ctrl, obj->WmmIdx);
	return pEdca;
}

/*
*
*/
VOID HcCrossChannelCheck(RTMP_ADAPTER *pAd, struct wifi_dev *wdev,
			 UCHAR Channel)
{
	UCHAR PhyMode = wdev->PhyMode;
	UCHAR WChannel = wdev->channel;

	/*check channel is belong to differet band*/
	if (Channel > 14 && WChannel > 14)
		return;

	if (Channel <= 14 && WChannel <= 14)
		return;

	/*is mixed mode, change default channel and */
	if (!WMODE_5G_ONLY(PhyMode) || !WMODE_2G_ONLY(PhyMode)) {
		/*update wdev channel to new band*/
		wdev->channel = Channel;
		/*need change to other band*/
		HcAcquireRadioForWdev(pAd, wdev);
	}

	return;
}

/*
 * Description:
 *
 * the function will check all enabled function,
 * check the bssid num is defined,
 *
 * preserve the group key wtbl num will be used.
 * then decide the max station number could be used.
 */
UCHAR HcGetMaxStaNum(RTMP_ADAPTER *pAd)
{
	UCHAR MaxStaNum = WtcGetMaxStaNum(pAd->hdev_ctrl);

	if (MaxStaNum > MAX_LEN_OF_MAC_TABLE)
		MaxStaNum = MAX_LEN_OF_MAC_TABLE;

	return MaxStaNum;
}

UCHAR HcSetMaxStaNum(RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;
	UCHAR BssidNum = 0, MSTANum = 0;
#ifdef CONFIG_AP_SUPPORT
	BssidNum = pAd->ApCfg.BssidNum;
#endif /*CONFIG_AP_SUPPORT*/
	return WtcSetMaxStaNum(ctrl, BssidNum, MSTANum);
}

/*
*
*/
UCHAR HcAcquireGroupKeyWcid(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return INVAILD_WCID;
	}

	wdev->tr_tb_idx = WtcAcquireGroupKeyWcid(pAd->hdev_ctrl, obj);
	return wdev->tr_tb_idx;
}

/*
*
*/
VOID HcReleaseGroupKeyWcid(RTMP_ADAPTER *pAd, struct wifi_dev *wdev, UCHAR idx)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return;
	}

	wdev->tr_tb_idx = WtcReleaseGroupKeyWcid(pAd->hdev_ctrl, obj, idx);
}

/*
*
*/
UCHAR HcGetWcidLinkType(RTMP_ADAPTER *pAd, UCHAR Wcid)
{
	return WtcGetWcidLinkType(pAd->hdev_ctrl, Wcid);
}

/*
*
*/
UCHAR HcAcquireUcastWcid(RTMP_ADAPTER *pAd, struct wifi_dev *wdev)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return INVAILD_WCID;
	}

	return WtcAcquireUcastWcid(pAd->hdev_ctrl, obj);
}

/*
*
*/
UCHAR HcReleaseUcastWcid(RTMP_ADAPTER *pAd, struct wifi_dev *wdev, UCHAR idx)
{
	struct hdev_obj *obj = wdev->pHObj;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		if (idx > 0) {
			MTWF_LOG(
				DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
				("%s(): releasing wcid %d, hobj is not ready!\n",
				 __func__, idx));
		} else
			return INVAILD_WCID;
	}

	return WtcReleaseUcastWcid(pAd->hdev_ctrl, obj, idx);
}

/*
*
*/
VOID HcWtblRecDump(RTMP_ADAPTER *pAd)
{
	WtcRecDump(pAd->hdev_ctrl);
}

/*
*
*/
BOOLEAN HcIsRadioAcq(struct wifi_dev *wdev)
{
	return hdev_obj_state_ready(wdev->pHObj);
}

UCHAR HcGetAmountOfBand(struct _RTMP_ADAPTER *pAd)
{
	struct hdev_ctrl *ctrl = pAd->hdev_ctrl;

	return ctrl->HwResourceCfg.concurrent_bands;
}

static INT32 HcSuspendMSDUTx(struct radio_dev *rdev)
{
	INT32 ret = 0;
	struct hdev_obj *obj;
	struct hdev_ctrl *ctrl = rdev->priv;
	struct _RTMP_ADAPTER *ad = ctrl->priv;
	struct wifi_dev *wdev;

	/*update all of wdev*/
	DlListForEach(obj, &rdev->DevObjList, struct hdev_obj, list)
	{
		wdev = ad->wdev_list[obj->Idx];
		RTMPSuspendMsduTransmission(wdev->sys_handle, wdev);
	}
	return ret;
}

static INT32 HcUpdateMSDUTxAllow(struct radio_dev *rdev)
{
	INT32 ret = 0;
	struct hdev_obj *obj;
	struct hdev_ctrl *ctrl = rdev->priv;
	struct _RTMP_ADAPTER *ad = ctrl->priv;
	struct wifi_dev *wdev;

	/*update all of wdev*/
	DlListForEach(obj, &rdev->DevObjList, struct hdev_obj, list)
	{
		wdev = ad->wdev_list[obj->Idx];

		if (wdev->channel == rdev->pRadioCtrl->Channel)
			RTMPResumeMsduTransmission(wdev->sys_handle, wdev);
		else
			RTMPSuspendMsduTransmission(wdev->sys_handle, wdev);
	}
	return ret;
}

/*
*
*/
static VOID hc_radio_update(struct wifi_dev *wdev, struct radio_res *res)
{
	struct hdev_obj *obj = wdev->pHObj;
	struct radio_dev *rdev;
	struct freq_oper *oper = res->oper;
#if defined(MT_DFS_SUPPORT) && defined(BACKGROUND_SCAN_SUPPORT)
	struct _RTMP_ADAPTER *ad = (struct _RTMP_ADAPTER *)wdev->sys_handle;
#endif
	BOOLEAN scan = (res->reason == REASON_NORMAL_SCAN) ? TRUE : FALSE;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return;
	}
	rdev = obj->rdev;
#ifdef CONFIG_AP_SUPPORT
#ifdef AP_QLOAD_SUPPORT
	/* clear all statistics count for QBSS Load */
	QBSS_LoadStatusClear(wdev->sys_handle, oper->prim_ch);
#endif /* AP_QLOAD_SUPPORT */
#endif /* CONFIG_AP_SUPPORT */
	HcSuspendMSDUTx(rdev);
	AsicSwitchChannel(wdev->sys_handle, rdev->Idx, oper, scan);
	AsicSetBW(wdev->sys_handle, oper->bw, rdev->Idx);
	RcUpdateRadio(rdev, oper->bw, oper->cen_ch_1, oper->cen_ch_2,
		      oper->ext_cha);
	RcUpdateChannel(rdev, oper->prim_ch, scan);
	/*after update channel resum tx*/
	HcUpdateMSDUTxAllow(rdev);
#if defined(MT_DFS_SUPPORT) && defined(BACKGROUND_SCAN_SUPPORT)
	DfsInitDedicatedScanStart(ad);
#endif
}

/*
*
*/
BOOLEAN hc_radio_res_request(struct wifi_dev *wdev, struct radio_res *res)
{
	struct hdev_obj *obj = wdev->pHObj;
	struct radio_dev *rdev;
#ifdef ANTENNA_CONTROL_SUPPORT
	UINT8 BandIdx = 0;
	struct _RTMP_ADAPTER *pAd = (struct _RTMP_ADAPTER *)wdev->sys_handle;

	BandIdx = HcGetBandByWdev(wdev);
#endif /* ANTENNA_CONTROL_SUPPORT */
#ifdef MT_WOW_SUPPORT
	struct _RTMP_ADAPTER *ad = (struct _RTMP_ADAPTER *)wdev->sys_handle;
#endif /*MT_WOW_SUPPORT*/

#ifdef BW_VENDOR10_CUSTOM_FEATURE
	/* Sync SoftAp BW for Down Case */
	if (wdev->wdev_type == WDEV_TYPE_AP &&
	    wlan_operate_get_state(wdev) == WLAN_OPER_STATE_INVALID) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_TRACE,
			 ("%s(): AP wdev=%d, Interface Down!\n", __func__,
			  wdev->wdev_idx));
		return FALSE;
	}
#endif

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return FALSE;
	}

	rdev = obj->rdev;
	if (
#ifdef ANTENNA_CONTROL_SUPPORT
		(!pAd->bAntennaSetAPEnable[BandIdx]) &&
#endif /* ANTENNA_CONTROL_SUPPORT */
		(rc_radio_equal(rdev, res->oper))) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_TRACE,
			 ("%s(): radio is equal, prim_ch=%d!\n", __func__,
			  res->oper->prim_ch));
		return TRUE;
	}

	if (rc_radio_res_acquire(rdev, res) != TRUE) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_TRACE,
			 ("%s(): can't acquire radio resource!\n", __func__));
		return FALSE;
	}

#ifdef MT_WOW_SUPPORT

	if (ad->WOW_Cfg.bWoWRunning) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_TRACE,
			 ("[%s] WoW is running, skip!\n", __func__));
		return FALSE;
	}

#endif /*MT_WOW_SUPPORT*/
	/*update to radio resouce*/
	hc_radio_update(wdev, res);
	return TRUE;
}

/*
*
*/
UCHAR hc_reset_radio(struct _RTMP_ADAPTER *ad)
{
	struct hdev_ctrl *ctrl = ad->hdev_ctrl;
	struct radio_dev *rdev = NULL;
	struct freq_oper freq;
	struct _RADIO_CTRL *radio_ctrl;
	UCHAR i;

	for (i = 0; i < ctrl->HwResourceCfg.concurrent_bands; i++) {
		os_zero_mem(&freq, sizeof(freq));
		rdev = &ctrl->rdev[i];
		radio_ctrl = rdev->pRadioCtrl;
		freq.bw = radio_ctrl->Bw;
		freq.prim_ch = radio_ctrl->Channel;
		freq.cen_ch_1 = radio_ctrl->CentralCh;
		freq.cen_ch_2 = radio_ctrl->Channel2;
		AsicSwitchChannel(ad, i, &freq, FALSE);
	}
	return TRUE;
}

/*
*
*/
VOID hc_set_rrm_init(struct wifi_dev *wdev)
{
	struct _RTMP_ADAPTER *ad = wdev->sys_handle;
	UCHAR band_idx = HcGetBandByWdev(wdev);

	AsicSetTxStream(wdev->sys_handle, ad->Antenna.field.TxPath, OPMODE_AP,
			TRUE, band_idx);
	AsicSetRxStream(wdev->sys_handle, ad->Antenna.field.RxPath, band_idx);
}

/*
*
*/
INT hc_radio_query_by_wdev(struct wifi_dev *wdev, struct freq_oper *oper)
{
	struct hdev_obj *obj = wdev->pHObj;
	struct radio_dev *rdev;
	struct _RADIO_CTRL *radio;

	if (!hdev_obj_state_ready(obj)) {
		MTWF_LOG(DBG_CAT_HW, DBG_SUBCAT_ALL, DBG_LVL_ERROR,
			 ("%s(): wdev=%d, hobj is not ready!\n", __func__,
			  wdev->wdev_idx));
		return HC_STATUS_FAIL;
	}

	rdev = obj->rdev;
	radio = rdev->pRadioCtrl;
	oper->bw = radio->Bw;
	oper->cen_ch_1 = radio->CentralCh;
	oper->cen_ch_2 = radio->Channel2;
	oper->ext_cha = radio->ExtCha;
	oper->prim_ch = radio->Channel;
	oper->ht_bw = (oper->bw > BW_20) ? HT_BW_40 : HT_BW_20;
	oper->vht_bw = rf_bw_2_vht_bw(oper->bw);
	return HC_STATUS_OK;
}

/*
*
*/
INT hc_radio_query_by_channel(struct _RTMP_ADAPTER *ad, UCHAR channel,
			      struct freq_oper *oper)
{
	INT ret = HC_STATUS_FAIL;
	struct hdev_ctrl *ctrl = ad->hdev_ctrl;
	struct _HD_RESOURCE_CFG *res = &ctrl->HwResourceCfg;
	struct _RADIO_CTRL *radio = NULL;
	UCHAR i;

	for (i = 0; i < res->concurrent_bands; i++) {
		radio = &res->PhyCtrl[i].RadioCtrl;
		if (radio->Channel == channel) {
			oper->bw = radio->Bw;
			oper->cen_ch_1 = radio->CentralCh;
			oper->cen_ch_2 = radio->Channel2;
			oper->ext_cha = radio->ExtCha;
			oper->prim_ch = radio->Channel;
			oper->ht_bw = (oper->bw > BW_20) ? HT_BW_40 : HT_BW_20;
			oper->vht_bw = rf_bw_2_vht_bw(oper->bw);
			ret = HC_STATUS_OK;
			break;
		}
	}
	return ret;
}

/*
* suggest only used by phy related features, others should use hc_radio_query_by_wdev
*/
INT hc_radio_query_by_index(struct _RTMP_ADAPTER *ad, UCHAR index,
			    struct freq_oper *oper)
{
	INT ret = HC_STATUS_OK;
	struct hdev_ctrl *ctrl = ad->hdev_ctrl;
	struct _HD_RESOURCE_CFG *res = &ctrl->HwResourceCfg;
	struct _RADIO_CTRL *radio = NULL;

	radio = &res->PhyCtrl[index].RadioCtrl;
	oper->bw = radio->Bw;
	oper->cen_ch_1 = radio->CentralCh;
	oper->cen_ch_2 = radio->Channel2;
	oper->ext_cha = radio->ExtCha;
	oper->prim_ch = radio->Channel;
	oper->ht_bw = (oper->bw > BW_20) ? HT_BW_40 : HT_BW_20;
	oper->vht_bw = rf_bw_2_vht_bw(oper->bw);
	return ret;
}

/*
* temporally use, only query first freq_oper by rfic, not support in 5G+5G or 2G+2G case
*/
INT hc_radio_query_by_rf(struct _RTMP_ADAPTER *ad, UCHAR rfic,
			 struct freq_oper *oper)
{
	INT ret = HC_STATUS_FAIL;
	struct hdev_ctrl *ctrl = ad->hdev_ctrl;
	struct _HD_RESOURCE_CFG *res = &ctrl->HwResourceCfg;
	struct _RADIO_CTRL *radio = NULL;
	UCHAR i;

	for (i = 0; i < res->concurrent_bands; i++) {
		radio = &res->PhyCtrl[i].RadioCtrl;
		if (wmode_2_rfic(radio->PhyMode) & rfic) {
			oper->bw = radio->Bw;
			oper->cen_ch_1 = radio->CentralCh;
			oper->cen_ch_2 = radio->Channel2;
			oper->ext_cha = radio->ExtCha;
			oper->prim_ch = radio->Channel;
			oper->ht_bw = (oper->bw > BW_20) ? HT_BW_40 : HT_BW_20;
			oper->vht_bw = rf_bw_2_vht_bw(oper->bw);
			ret = HC_STATUS_OK;
			break;
		}
	}
	return ret;
}

/*
*
*/
INT hc_obj_init(struct wifi_dev *wdev, INT idx)
{
	struct _RTMP_ADAPTER *ad = wdev->sys_handle;
	struct hdev_ctrl *ctrl = ad->hdev_ctrl;

	wdev->pHObj = &ctrl->HObjList[idx];
	return HC_STATUS_OK;
}

/*
*
*/
VOID hc_obj_exit(struct wifi_dev *wdev)
{
	wdev->pHObj = NULL;
}

/*
*
*/
inline struct _RTMP_CHIP_CAP *hc_get_chip_cap(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;
	return &ctrl->chip_cap;
}
#ifndef MT76XX_COMBO_DUAL_DRIVER_SUPPORT
EXPORT_SYMBOL(hc_get_chip_cap);
#endif /* MT76XX_COMBO_DUAL_DRIVER_SUPPORT */

/*
*
*/
struct _RTMP_CHIP_OP *hc_get_chip_ops(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return &ctrl->chip_ops;
}
#ifndef MT76XX_COMBO_DUAL_DRIVER_SUPPORT
EXPORT_SYMBOL(hc_get_chip_ops);
#endif /* MT76XX_COMBO_DUAL_DRIVER_SUPPORT */
/*
*
*/
void hc_register_chip_ops(void *hdev_ctrl, struct _RTMP_CHIP_OP *ops)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	os_move_mem(&ctrl->chip_ops, ops, sizeof(*ops));
}

/*
*
*/
UCHAR hc_set_ChCtrl(CHANNEL_CTRL *ChCtrl, RTMP_ADAPTER *pAd, UCHAR ChIdx,
		    UCHAR ChIdx2)
{
	os_move_mem(&ChCtrl->ChList[ChIdx], &pAd->TxPower[ChIdx2],
		    sizeof(CHANNEL_TX_POWER));
	return HC_STATUS_OK;
}

UCHAR hc_set_ChCtrlFlags_CAP(CHANNEL_CTRL *ChCtrl, UINT ChannelListFlag,
			     UCHAR ChIdx)
{
	ChCtrl->ChList[ChIdx].Flags |= ChannelListFlag;
	return HC_STATUS_OK;
}

UCHAR hc_set_ChCtrlChListStat(CHANNEL_CTRL *ChCtrl, CH_LIST_STATE ChListStat)
{
	ChCtrl->ChListStat = ChListStat;
	return HC_STATUS_OK;
}

CHANNEL_CTRL *hc_get_channel_ctrl(void *hdev_ctrl, UCHAR BandIdx)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;
	return &ctrl->ChCtrl[BandIdx];
}

UCHAR hc_init_ChCtrl(RTMP_ADAPTER *pAd)
{
	UCHAR BandIdx;
	CHANNEL_CTRL *pChCtrl;
	for (BandIdx = 0; BandIdx < DBDC_BAND_NUM; BandIdx++) {
		pChCtrl = hc_get_channel_ctrl(pAd->hdev_ctrl, BandIdx);
		os_zero_mem(pChCtrl, sizeof(CHANNEL_CTRL));
	}
	return HC_STATUS_OK;
}
#ifdef CONFIG_AP_SUPPORT
UCHAR hc_init_ACSChCtrl(RTMP_ADAPTER *pAd)
{
	UCHAR BandIdx;
	AUTO_CH_CTRL *pAutoChCtrl;
	for (BandIdx = 0; BandIdx < DBDC_BAND_NUM; BandIdx++) {
		pAutoChCtrl = HcGetAutoChCtrlbyBandIdx(pAd, BandIdx);
		pAutoChCtrl->AutoChSelCtrl.pScanReqwdev = NULL;
		pAutoChCtrl->AutoChSelCtrl.ScanChIdx = 0;
		pAutoChCtrl->AutoChSelCtrl.ChListNum = 0;
		pAutoChCtrl->AutoChSelCtrl.ACSChStat = ACS_CH_STATE_NONE;
		os_zero_mem(pAutoChCtrl->AutoChSelCtrl.AutoChSelChList,
			    (MAX_NUM_OF_CHANNELS + 1) *
				    sizeof(AUTOCH_SEL_CH_LIST));
	}
	return HC_STATUS_OK;
}
UCHAR hc_init_ACSChCtrlByBandIdx(RTMP_ADAPTER *pAd, UCHAR BandIdx)
{
	AUTO_CH_CTRL *pAutoChCtrl = HcGetAutoChCtrlbyBandIdx(pAd, BandIdx);
	pAutoChCtrl->AutoChSelCtrl.pScanReqwdev = NULL;
	pAutoChCtrl->AutoChSelCtrl.ScanChIdx = 0;
	pAutoChCtrl->AutoChSelCtrl.ChListNum = 0;
	pAutoChCtrl->AutoChSelCtrl.ACSChStat = ACS_CH_STATE_NONE;
	os_zero_mem(pAutoChCtrl->AutoChSelCtrl.AutoChSelChList,
		    (MAX_NUM_OF_CHANNELS + 1) * sizeof(AUTOCH_SEL_CH_LIST));
	return HC_STATUS_OK;
}
#endif

UCHAR hc_check_ChCtrlChListStat(CHANNEL_CTRL *ChCtrl, CH_LIST_STATE ChListStat)
{
	return (ChCtrl->ChListStat == ChListStat);
}
struct _RTMP_CHIP_DBG *hc_get_chip_dbg(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return &ctrl->chip_dbg;
}

/*
*
*/
UINT32 hc_get_hif_type(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->chip_cap.hif_type;
}

/*
*
*/
UINT32 hc_get_asic_cap(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->chip_cap.asic_caps;
}

/*
*
*/
VOID hc_set_asic_cap(void *hdev_ctrl, UINT32 caps)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	ctrl->chip_cap.asic_caps |= caps;
}

/*
*
*/
VOID hc_clear_asic_cap(void *hdev_ctrl, UINT32 caps)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	ctrl->chip_cap.asic_caps &= ~(caps);
}

/*
*
*/
UINT8 hc_get_chip_bcn_max_num(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->chip_cap.BcnMaxNum;
}

/*
*
*/
UINT8 hc_get_chip_bcn_hw_num(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->chip_cap.BcnMaxHwNum;
}

/*
*
*/
BOOLEAN hc_get_chip_wapi_sup(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->chip_cap.FlgIsHwWapiSup;
}

/*
*
*/
inline VOID *hc_get_hif_ctrl(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->hif;
}

/*
*
*/
VOID *hc_get_os_cookie(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->cookie;
}

/*
*
*/
VOID *hc_get_mcu_ctrl(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->mcu_ctrl;
}

/*
*
*/
struct _RTMP_ARCH_OP *hc_get_asic_ops(void *hdev_ctrl)
{
	struct hdev_ctrl *ctrl = hdev_ctrl;

	return ctrl->arch_ops;
}
