/*
  * Copyright (c) 2016 MediaTek Inc.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
  * General Public License (GPL) Version 2, available from the file
  * COPYING in the main directory of this source tree, or the
  * BSD license below:
  *
  *     Redistribution and use in source and binary forms, with or
  *     without modification, are permitted provided that the following
  *     conditions are met:
  *
  *      - Redistributions of source code must retain the above
  *        copyright notice, this list of conditions and the following
  *        disclaimer.
  *
  *      - Redistributions in binary form must reproduce the above
  *        copyright notice, this list of conditions and the following
  *        disclaimer in the documentation and/or other materials
  *        provided with the distribution.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */

/****************************************************************************

    Module Name:
    vr_ikans.c
 
    Abstract:
    Only for IKANOS Vx160 or Vx180 platform.
 
    Revision History:
    Who        When          What
    ---------  ----------    ----------------------------------------------
    Sample Lin	01-28-2008    Created

***************************************************************************/

#define RTMP_MODULE_OS
#define RTMP_MODULE_OS_UTIL

#define MODULE_IKANOS

#include "rt_config.h"
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <netpro/apprehdr.h>


#ifdef IKANOS_VX_1X0

#define IKANOS_PERAP_ID		7 /* IKANOS Fix Peripheral ID */
#define K0_TO_K1(x)			((unsigned)(x)|0xA0000000) /* kseg0 to kseg1 */
/*#define IKANOS_DEBUG */


extern INT rt28xx_send_packets(struct sk_buff *skb_p, struct net_device	*net_dev);
static INT32 IKANOS_WlanDataFramesTx(void *_pAdBuf, struct net_device *pNetDev);
static void IKANOS_WlanPktFromAp(apPreHeader_t *pFrame);


/* --------------------------------- Public -------------------------------- */

/*
========================================================================
Routine Description:
	Init IKANOS fast path function.

Arguments:
	pApMac			- the MAC of AP

Return Value:
	None

Note:
	If you want to enable RX fast path, you must call the function.
========================================================================
*/
void VR_IKANOS_FP_Init(UINT8 BssNum, UINT8 *pApMac)
{
	UINT32 i;
	UINT8 mac[6];


	memcpy(mac, pApMac, 6);

	/* add all MAC of multiple BSS */
	for(i=0; i<BssNum; i++)
	{
		apMacAddrConfig(7, mac, 0xAD);
		mac[5] ++;
	}
}


/*
========================================================================
Routine Description:
	Ikanos LAN --> WLAN transmit fast path function.

Arguments:
	skb				- the transmitted packet (SKB packet format)
	netdev			- our WLAN network device

Return Value:
	

Note:
========================================================================
*/
INT32 IKANOS_DataFramesTx(struct sk_buff *pSkb, struct net_device *pNetDev)
{
	PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)pNetDev->priv;
	IkanosWlanTxCbFuncP *fp = &IKANOS_WlanDataFramesTx;

	pSkb->apFlowData.txDev = pNetDev;
	pSkb->apFlowData.txApId = IKANOS_PERAP_ID;
	pAd->IkanosTxInfo.netdev = pNetDev;
	pAd->IkanosTxInfo.fp = fp;
	pSkb->apFlowData.txHandle = &(pAd->IkanosTxInfo);
	ap2apFlowProcess(pSkb, pNetDev);

#ifdef IKANOS_DEBUG
	printk("ikanos> tx no fp\n"); /* debug use */
#endif /* IKANOS_DEBUG */

	return rt28xx_send_packets(pSkb, pNetDev);
}


/*
========================================================================
Routine Description:
	Ikanos WLAN --> LAN transmit fast path function.

Arguments:
	pAd				- WLAN control block
	pRxParam		-
	pSkb			- the transmitted packet (SKB packet format)
	Length			- packet length

Return Value:
	None

Note:
	Because no unsigned long private parameters in apPreHeader_t can be used,
	we use a global variable to record pAd.
	So we can not use multiple card function in Ikanos platform.
========================================================================
*/
PRTMP_ADAPTER	pIkanosAd;
void IKANOS_DataFrameRx(RTMP_ADAPTER *pAd, struct sk_buff *pSkb)
{
	apPreHeader_t *apBuf;
	void *pRxParam = pSkb->dev;
	UINT32 Length = pSkb->len;

	apBuf = (apPreHeader_t *)(translateMbuf2Apbuf(pSkb, 0));
	apBuf->flags1 = 1 << AP_FLAG1_IS_ETH_BIT;
	apBuf->specInfoElement = RTMP_GET_PACKET_NET_DEVICE_MBSSID(pSkb); /* MBSS */
	pIkanosAd = pAd;

	apBuf->flags2 = 0;

	apClassify(IKANOS_PERAP_ID, apBuf, (void *)IKANOS_WlanPktFromAp);
	dev_kfree_skb(pSkb); 
}



/* --------------------------------- Private -------------------------------- */

/*
========================================================================
Routine Description:
	Ikanos LAN --> WLAN transmit fast path function.

Arguments:
	_pAdBuf			- the transmitted packet (Ikanos packet format)
	netdev			- our WLAN network device

Return Value:
	

Note:
========================================================================
*/
static INT32 IKANOS_WlanDataFramesTx(void *_pAdBuf, struct net_device *pNetDev)
{
	apPreHeader_t *pApBuf = (apPreHeader_t *)_pAdBuf;
	struct sk_buff *sk = NULL;

	sk = (struct sk_buff *)translateApbuf2Mbuf(pApBuf);
	if (sk == NULL)
	{
		printk("ikanos> translateApbuf2Mbuf returned NULL!\n");
		return 1;
	}

	sk->apFlowData.flags2 = 0;
	sk->apFlowData.wlanFlags = 0;
	sk->protocol = ETH_P_IP;
	sk->dev = pNetDev;
	sk->priority = 0;

	return rt28xx_send_packets(sk, pNetDev);
}


/*
========================================================================
Routine Description:
	Get real interface index, used in get_netdev_from_bssid()

Arguments:
	pAd				- 
	FromWhichBSSID	- 

Return Value:
	None

Note:
========================================================================
*/
static INT32 GetSpecInfoIdxFromBssid(PRTMP_ADAPTER pAd, INT32 FromWhichBSSID)
{
	INT32 IfIdx = MAIN_MBSSID;

#ifdef CONFIG_AP_SUPPORT
	IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
	{
#ifdef APCLI_SUPPORT
		if(FromWhichBSSID >= MIN_NET_DEVICE_FOR_APCLI)
		{
			IfIdx = MAX_MBSSID_NUM(pAd) + MAX_WDS_ENTRY;
		} 
		else
#endif /* APCLI_SUPPORT */
#ifdef WDS_SUPPORT
		if(FromWhichBSSID >= MIN_NET_DEVICE_FOR_WDS)
		{
			INT WdsIndex = FromWhichBSSID - MIN_NET_DEVICE_FOR_WDS;
			IfIdx = MAX_MBSSID_NUM(pAd) + WdsIndex;
		}
		else
#endif /* WDS_SUPPORT */
		{
			IfIdx = FromWhichBSSID;
		}
	}
#endif /* CONFIG_AP_SUPPORT */

#ifdef CONFIG_STA_SUPPORT
	IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
	{
		IfIdx = MAIN_MBSSID;
	}
#endif /* CONFIG_STA_SUPPORT */

	return IfIdx; /* return one of MBSS */
}


/*
========================================================================
Routine Description:
	Ikanos WLAN --> LAN transmit fast path function.

Arguments:
	pFrame			- the received packet (Ikanos packet format)

Return Value:
	None

Note:
	Ikanos platform supports only 8 VAPs
========================================================================
*/
static void IKANOS_WlanPktFromAp(apPreHeader_t *pFrame)
{
	RTMP_ADAPTER *pAd;
	struct net_device *dev = NULL;
	struct sk_buff *skb;
	INT32 index;
	apPreHeader_t *apBuf = K0_TO_K1(pFrame);


	pAd = pIkanosAd;
    /*index = apBuf->specInfoElement; */
	/*dev = pAd->ApCfg.MBSSID[index].MSSIDDev; */
	index = GetSpecInfoIdxFromBssid(pAd, apBuf->specInfoElement);
	dev = get_netdev_from_bssid(pAd, apBuf->specInfoElement);
    if (dev == NULL)
    {
        printk("ikanos> %s: ERROR null device ***************\n", __FUNCTION__);
        return;
    }

    skb = (struct sk_buff *)translateApbuf2Mbuf(apBuf);
    if (NULL == skb)
    {
        printk("ikanos> %s: skb is null *********************\n", __FUNCTION__);
        return;
    }

    pAd->IkanosRxInfo[index].netdev = dev;
    pAd->IkanosRxInfo[index].fp = &IKANOS_WlanDataFramesTx;

    skb->dev = dev;
    skb->apFlowData.rxApId = IKANOS_PERAP_ID;
    /*skb->apFlowData.txHandle = &(txinforx[index]); */
    skb->apFlowData.rxHandle = &(pAd->IkanosRxInfo[index]);
    skb->protocol = eth_type_trans(skb, skb->dev);

#ifdef IKANOS_DEBUG
	printk("ikanos> rx no fp!\n"); /* debug use */
#endif /* IKANOS_DEBUG */

    netif_rx(skb);
    return;
}

#endif /* IKANOS_VX_1X0 */

