static inline VOID AutoChannelSkipListSetDirty(
	IN PRTMP_ADAPTER	pAd)
{
	UCHAR i;
	for (i=0; i < pAd->ApCfg.AutoChannelSkipListNum ; i++)
	{
			UCHAR channel_idx = GetChIdx(pAd, pAd->ApCfg.AutoChannelSkipList[i]);
			if ( channel_idx != pAd->ChannelListNum )
			{
				pAd->pChannelInfo->SkipList[channel_idx] = TRUE;
			}
	}
}
/* 
	==========================================================================
	Description:
        This routine calaulates the dirtyness of all channels by the 
        CCA value  and Rssi. Store dirtyness to pChannelInfo strcut.
		This routine is called at iwpriv cmmand or initialization. It chooses and returns 
		a good channel whith less interference.
	Return:
		ch -  channel number that
	NOTE:
	==========================================================================
 */
static inline UCHAR SelectClearChannelCCA(
	IN PRTMP_ADAPTER pAd
	)
{
	#define CCA_THRESHOLD (100)

	PBSSINFO pBssInfoTab = pAd->pBssInfoTab;
	PCHANNELINFO pChannelInfo = pAd->pChannelInfo;
	INT ch = 1, channel_idx, BssTab_idx;
	BSSENTRY *pBss;
	UINT32 min_dirty, min_falsecca;
	int candidate_ch;

	UCHAR  ExChannel[2] = {0};
	UCHAR  candidate_ExChannel[2] = {0};
	UCHAR base;

	if(pBssInfoTab == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR, ("pAd->pBssInfoTab equal NULL.\n"));
		return (FirstChannel(pAd));
	}

	if(pChannelInfo == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR, ("pAd->pChannelInfo equal NULL.\n"));
		return (FirstChannel(pAd));
	}

	for (BssTab_idx = 0; BssTab_idx < pBssInfoTab->BssNr; BssTab_idx++)
	{
		pBss = &(pBssInfoTab->BssEntry[BssTab_idx]);
		channel_idx = GetChIdx(pAd, pBss->Channel);
		if (channel_idx < 0 )
			continue;


		if (pBss->Rssi >= RSSI_TO_DBM_OFFSET-50)
		{
			/* high signal >= -50 dbm */
			pChannelInfo->dirtyness[channel_idx] += 50;
		}
		else if (pBss->Rssi <= RSSI_TO_DBM_OFFSET-80)
		{
			/* low signal <= -80 dbm */
			pChannelInfo->dirtyness[channel_idx] += 30;
		}
		else
		{
			/* mid signal -50 ~ -80 dbm */
			pChannelInfo->dirtyness[channel_idx] += 40;
		}

		pChannelInfo->dirtyness[channel_idx] += 40;

		{
			INT BelowBound;
			INT AboveBound;
			INT loop;

			switch(pBss->ExtChOffset)
			{
				case EXTCHA_ABOVE:
					BelowBound = pChannelInfo->IsABand ? 1 : 4;
					AboveBound = pChannelInfo->IsABand ? 2 : 8;
					break;

				case EXTCHA_BELOW:
					BelowBound = pChannelInfo->IsABand ? 2 : 8;
					AboveBound = pChannelInfo->IsABand ? 1 : 4;
					break;

				default:
					BelowBound = pChannelInfo->IsABand ? 1 : 4;
					AboveBound = pChannelInfo->IsABand ? 1 : 4;
					break;
			}

			/* check neighbor channel */
			for (loop = (channel_idx+1); loop <= (channel_idx+AboveBound); loop++)
			{
				if (loop >= MAX_NUM_OF_CHANNELS)
					break;

				if (pAd->ChannelList[loop].Channel - pAd->ChannelList[loop-1].Channel > 4)
					break;

				pChannelInfo->dirtyness[loop] +=
					((9 - (loop - channel_idx)) * 4);
			}
			/* check neighbor channel */
			for (loop=(channel_idx-1); loop >= (channel_idx-BelowBound); loop--)
			{
				if (loop < 0)
					break;

				if (pAd->ChannelList[loop+1].Channel - pAd->ChannelList[loop].Channel > 4)
					continue;

				pChannelInfo->dirtyness[loop] +=
					((9 - (channel_idx - loop)) * 4);
			}
		}

		printk(" ch%d bssid=%02x:%02x:%02x:%02x:%02x:%02x\n",
			pBss->Channel, pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5]);
	}
	
	AutoChannelSkipListSetDirty(pAd);
	
	printk("======================RT309x=========================\n");
	for (channel_idx = 0; channel_idx < pAd->ChannelListNum; channel_idx++)
	{
		printk("Channel %d : Dirty = %ld, False CCA = %u, Busy Time = %u, Skip Channel = %s\n",
					pAd->ChannelList[channel_idx].Channel,
					pChannelInfo->dirtyness[channel_idx],
					pChannelInfo->FalseCCA[channel_idx],
					pChannelInfo->chanbusytime[channel_idx],
					(pChannelInfo->SkipList[channel_idx] == TRUE) ? "TRUE" : "FALSE");
	}
	printk("=====================================================\n");

	min_dirty = min_falsecca = 0xFFFFFFFF;

	/* 
	 * Rule 1. Pick up a good channel that False_CCA =< CCA_THRESHOLD 
	 *		   by dirtyness
	 */
	candidate_ch = -1;
	
	for (channel_idx = 0; channel_idx < pAd->ChannelListNum; channel_idx++)
	{
		if (pChannelInfo->SkipList[channel_idx] == TRUE)
			continue;

		if (pChannelInfo->FalseCCA[channel_idx] <= CCA_THRESHOLD)
		{
			UINT32 dirtyness = pChannelInfo->dirtyness[channel_idx];
			ch = pAd->ChannelList[channel_idx].Channel;

#ifdef AP_QLOAD_SUPPORT
			/* QLOAD ALARM */
			/* when busy time of a channel > threshold, skip it */
			/* TODO: Use weight for different references to do channel selection */
			if (QBSS_LoadIsBusyTimeAccepted(pAd,
				pChannelInfo->chanbusytime[channel_idx]) == FALSE)
			{
				/* check next one */
				continue;
			}
#endif /* AP_QLOAD_SUPPORT */

#ifdef DOT11_N_SUPPORT
			/*
				User require 40MHz Bandwidth.
				In the case, ignor all channel
				doesn't support 40MHz Bandwidth.
			*/
			if ((pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)
				&& (pChannelInfo->IsABand && (GetABandChOffset(ch) == 0)))
				continue;

			/*
				Need to Consider the dirtyness of extending channel
				in 40 MHz bandwidth channel.
			*/
			if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)
			{
				if (pAd->pChannelInfo->IsABand)
				{
					if (((channel_idx + GetABandChOffset(ch)) >=0)
						&& ((channel_idx + GetABandChOffset(ch)) < pAd->ChannelListNum))
					{
						INT ChOffsetIdx = channel_idx + GetABandChOffset(ch);
						dirtyness += pChannelInfo->dirtyness[ChOffsetIdx];
					}
				}
				else
				{
					UCHAR ExChannel_idx = 0;
					if (pAd->ChannelList[channel_idx].Channel == 14)
					{
						dirtyness = 0xFFFFFFFF;
						break;
					}
					else
					{
						NdisZeroMemory(ExChannel, sizeof(ExChannel));
						if (((channel_idx - 4) >=0) && ((channel_idx - 4) < pAd->ChannelListNum))
						{
							dirtyness += pChannelInfo->dirtyness[channel_idx - 4];
							ExChannel[ExChannel_idx++] = pAd->ChannelList[channel_idx - 4].Channel;
					    }

						if (((channel_idx + 4) >=0) && ((channel_idx + 4) < pAd->ChannelListNum))
						{
						    dirtyness += pChannelInfo->dirtyness[channel_idx + 4];
						    ExChannel[ExChannel_idx++] = pAd->ChannelList[channel_idx + 4].Channel;
						}
					}
				}
			}
#endif /* DOT11_N_SUPPORT */

			if ((min_dirty > dirtyness))
			{
				min_dirty = dirtyness;
				candidate_ch = channel_idx;
				NdisMoveMemory(candidate_ExChannel, ExChannel, 2);
			}
		}
	}

	if (candidate_ch >= 0)
	{
		ch = pAd->ChannelList[candidate_ch].Channel;
		printk("Rule 1 CCA value : Min Dirtiness ==> Select Channel %d \n", ch);
		printk("Min Dirty = %u\n", min_dirty);
		printk("ExChannel = %d , %d\n", candidate_ExChannel[0], candidate_ExChannel[1]);
		printk("BW        = %s\n", (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)? "40" : "20");
		return ch;
	}

	/*
	 * Rule 2. Pick up a good channel that False_CCA > CCA_THRESHOLD 
	 *		   by FalseCCA (FalseCCA + Dirtyness)
	 */
	candidate_ch = -1;
	for (channel_idx = 0; channel_idx < pAd->ChannelListNum; channel_idx++)
	{
		if (pChannelInfo->SkipList[channel_idx] == TRUE)
			continue;
		
		if (pChannelInfo->FalseCCA[channel_idx] > CCA_THRESHOLD)
		{
			UINT32 falsecca = pChannelInfo->FalseCCA[channel_idx] + pChannelInfo->dirtyness[channel_idx];
			ch = pAd->ChannelList[channel_idx].Channel;

#ifdef DOT11_N_SUPPORT
			if ((pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)
				&& (pChannelInfo->IsABand && (GetABandChOffset(ch) == 0)))
				continue;
#endif /* DOT11_N_SUPPORT */

			if ((GetABandChOffset(ch) != 0)
					&& ((channel_idx + GetABandChOffset(ch)) >=0)
					&& ((channel_idx + GetABandChOffset(ch)) < pAd->ChannelListNum))
			{
				INT ChOffsetIdx = channel_idx + GetABandChOffset(ch);
				falsecca += (pChannelInfo->FalseCCA[ChOffsetIdx] +
							pChannelInfo->dirtyness[ChOffsetIdx]);
			}

#ifdef AP_QLOAD_SUPPORT
			/* QLOAD ALARM */
			/* when busy time of a channel > threshold, skip it */
			/* TODO: Use weight for different references to do channel selection */
			if (QBSS_LoadIsBusyTimeAccepted(pAd,
				pChannelInfo->chanbusytime[channel_idx]) == FALSE)
			{
				/* check next one */
				continue;
			}
#endif /* AP_QLOAD_SUPPORT */

			if ((min_falsecca > falsecca))
			{
				min_falsecca = falsecca;
				candidate_ch = channel_idx;
			}
		}
	}

	if (candidate_ch >= 0)
	{
		ch = pAd->ChannelList[candidate_ch].Channel;
		printk("Rule 2 CCA value : Min False CCA value ==> Select Channel %d, min falsecca = %d \n", ch, min_falsecca);
		return	ch;
	}

	base = RandomByte2(pAd);
	for (channel_idx=0 ; channel_idx < pAd->ChannelListNum ; channel_idx++)
	{
		ch = pAd->ChannelList[(base + channel_idx) % pAd->ChannelListNum].Channel;
	
		if (AutoChannelSkipListCheck(pAd, ch))
			continue;
		
#ifdef A_BAND_SUPPORT
		if ((pAd->ApCfg.bAvoidDfsChannel == TRUE)
			&& (pChannelInfo->IsABand == TRUE)
			&& RadarChannelCheck(pAd, ch))
			continue;
#endif

		break;
	}
	printk("Rule 3 CCA value : Randomly Select ==> Select Channel %d\n", ch);
	return ch;
}
INT32 ACS_UpdateDirtinessAll(RTMP_ADAPTER *pAd)
{
	PBSSINFO pBssInfoTab = pAd->pBssInfoTab;
	BSSENTRY *pBss = NULL;
	PCHANNELINFO pChannelInfo = pAd->pChannelInfo;
	INT32 channel_idx, BssTab_idx;
    UCHAR current_bss_ch = 0;
    INT32 current_bss_ch_is_5g = 0;

    if (!pBssInfoTab || !pChannelInfo)
    {
		DBGPRINT(RT_DEBUG_ERROR, ("Invalid pBssInfoTab or pChannelInfo!!\n"));
        return -1;
    }

    for (BssTab_idx = 0; BssTab_idx < pBssInfoTab->BssNr; BssTab_idx++)
    {
		pBss = &(pBssInfoTab->BssEntry[BssTab_idx]);
        current_bss_ch = pBss->Channel;
        current_bss_ch_is_5g = ACS_is5gChannel(current_bss_ch);
		channel_idx = GetChIdx(pAd, current_bss_ch);
		if (channel_idx < 0 )
			continue;
        /* ======== Dirtiness index #1 ======== */
		if (pBss->Rssi >= ACS_DIRTINESS_RSSI_STRONG)
		{ /* high signal >= -50 dbm */
			pChannelInfo->dirtyness[channel_idx] += 50;
		}
		else if (pBss->Rssi >= ACS_DIRTINESS_RSSI_WEAK)
		{ /* mid signal -50 ~ -80 dbm */
			pChannelInfo->dirtyness[channel_idx] += 40;
		}
		else
		{ /* low signal < -80 dbm */
			pChannelInfo->dirtyness[channel_idx] += 30;
		}
        /* ??? */
        //pChannelInfo->dirtyness[channel_idx] += 40;

        /* ======== Dirtiness index #2 ======== */
        {
            INT32 BelowBound = 0;
            INT32 AboveBound = 0;
            INT32 loop = 0;

            switch(pBss->ExtChOffset)
            {
                case EXTCHA_ABOVE:
                    AboveBound = (current_bss_ch_is_5g) ? (2) : (8);
                    BelowBound = (current_bss_ch_is_5g) ? (1) : (4);
                    break;

                case EXTCHA_BELOW:
                    AboveBound = (current_bss_ch_is_5g) ? (1) : (4);
                    BelowBound = (current_bss_ch_is_5g) ? (2) : (8);
                    break;

                default:
                    AboveBound = (current_bss_ch_is_5g) ? (1) : (4);
                    BelowBound = (current_bss_ch_is_5g) ? (1) : (4);
                    break;
            }
            /* check neighboring channel - ABOVE */
            for (loop = (channel_idx+1); loop <= (channel_idx+AboveBound); loop++)
            {
                if (loop >= MAX_NUM_OF_CHANNELS)
                    break;
                /* if above-neighboring channel is too far, don't need to consider it */
                if (pAd->ChannelList[loop].Channel - pAd->ChannelList[loop-1].Channel > 4)
                    break;
                pChannelInfo->dirtyness[loop] += ((9 - (loop - channel_idx)) * 4);
            }
            /* check neighboring channel - BELOW */
            for (loop=(channel_idx-1); loop >= (channel_idx-BelowBound); loop--)
            {
                if (loop < 0)
                    break;

                if (pAd->ChannelList[loop+1].Channel - pAd->ChannelList[loop].Channel > 4)
                    continue;

                pChannelInfo->dirtyness[loop] += ((9 - (channel_idx - loop)) * 4);
            }
        }
    }

    return 0;
}