/*
 * Copyright (c) 2005 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology Limited and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
*/


/* Public API headers. */

/* Internal project headers. */
#include "../include/attribute.h"
#include "../include/card.h"
#include "../include/cards/card_initialization.h"
#include "../include/component.h"
#include "../include/components/pbm_component.h"
#include "../include/util/utility.h"
#include "../include/cards/common_dagx_constants.h"
#include "../include/util/enum_string_table.h"
#include "../include/components/xgmii_component.h"
#include "../include/components/xgmii_statistics_component.h"
#include "../include/attribute_factory.h"
#include "../include/create_attribute.h"

#include "../../../include/dag_platform.h"
#include "../../../include/dagutil.h"

#define BUFFER_SIZE 1024

typedef struct
{
    int mIndex;
} xgmii_state_t;


/* port component. */
static void xgmii_dispose(ComponentPtr component);
static void xgmii_reset(ComponentPtr component);
static void xgmii_default(ComponentPtr component);
static int xgmii_post_initialize(ComponentPtr component);
static dag_config_state_t xgmii_get_state_routine(ComponentPtr component);
void* rs_fault_enable_get_value(AttributePtr attribute);
void rs_fault_enable_set_value(AttributePtr attribute, void* value, int length);

typedef enum
{
    kConfig        = 0x00,
    kMac0          = 0x04,
    kMac1          = 0x08
}  xgmii_register_offset_t;

/**
 * XGMII's attribute definition array 
 */
Attribute_t xgmii_attr[]=
{

    {
        /* Name */                 "tx_crc",
        /* Attribute Code */       kBooleanAttributeTxCrc,
        /* Attribute Type */       kAttributeBoolean,
        /* Description */          "Enable or disable CRC appending onto transmitted frames.",
        /* Config-Status */        kDagAttrConfig,
        /* Index in register */    17,
        /* Register Address */     DAG_REG_XGMII,
        /* Offset */               kConfig,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 BIT17,
        /* Default Value */        0,
        /* SetValue */             attribute_boolean_set_value,
        /* GetValue */             attribute_boolean_get_value,
        /* SetToString */          attribute_boolean_to_string,
        /* SetFromString */        attribute_boolean_from_string,
        /* Dispose */              attribute_dispose,
        /* PostInit */             attribute_post_initialize,
    },

    {
        /* Name */                 "crcstrip",
        /* Attribute Code */       kBooleanAttributeCrcStrip,
        /* Attribute Type */       kAttributeBoolean,
        /* Description */          "Enable or disable CRC stripping from received frames.",
        /* Config-Status */        kDagAttrConfig,
        /* Index in register */    10,
        /* Register Address */     DAG_REG_XGMII,
        /* Offset */               kConfig,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 BIT10,
        /* Default Value */        0,
        /* SetValue */             attribute_boolean_set_value,
        /* GetValue */             attribute_boolean_get_value,
        /* SetToString */          attribute_boolean_to_string,
        /* SetFromString */        attribute_boolean_from_string,
        /* Dispose */              attribute_dispose,
        /* PostInit */             attribute_post_initialize,
    },
    {
        /* Name */                 "nic",
        /* Attribute Code */       kBooleanAttributeRSFaultEnable,
        /* Attribute Type */       kAttributeBoolean,
        /* Description */          "Reconciliation Sublayer Fault Enable.",
        /* Config-Status */        kDagAttrConfig,
        /* Index in register */    10,
        /* Register Address */     DAG_REG_XGMII,
        /* Offset */               kConfig,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 BIT24,
        /* Default Value */        0,
        /* SetValue */             rs_fault_enable_set_value,
        /* GetValue */             rs_fault_enable_get_value,
        /* SetToString */          attribute_boolean_to_string,
        /* SetFromString */        attribute_boolean_from_string,
        /* Dispose */              attribute_dispose,
        /* PostInit */             attribute_post_initialize,
    }
};

Attribute_t xgmii_ver2_attr[]=
{

    {
        /* Name */                 "rx_enable",
        /* Attribute Code */       kBooleanAttributeRxEnable,
        /* Attribute Type */       kAttributeBoolean,
        /* Description */          "Enable or disable RX.",
        /* Config-Status */        kDagAttrConfig,
        /* Index in register */    17,
        /* Register Address */     DAG_REG_XGMII,
        /* Offset */               kConfig,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 BIT9,
        /* Default Value */        0,
        /* SetValue */             attribute_boolean_set_value,
        /* GetValue */             attribute_boolean_get_value,
        /* SetToString */          attribute_boolean_to_string,
        /* SetFromString */        attribute_boolean_from_string,
        /* Dispose */              attribute_dispose,
        /* PostInit */             attribute_post_initialize,
    },

    {
        /* Name */                 "tx_enable",
        /* Attribute Code */       kBooleanAttributeTxEnable,
        /* Attribute Type */       kAttributeBoolean,
        /* Description */          "Enable or disable TX.",
        /* Config-Status */        kDagAttrConfig,
        /* Index in register */    17,
        /* Register Address */     DAG_REG_XGMII,
        /* Offset */               kConfig,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 BIT16,
        /* Default Value */        0,
        /* SetValue */             attribute_boolean_set_value,
        /* GetValue */             attribute_boolean_get_value,
        /* SetToString */          attribute_boolean_to_string,
        /* SetFromString */        attribute_boolean_from_string,
        /* Dispose */              attribute_dispose,
        /* PostInit */             attribute_post_initialize,
    },
    {
        /* Name */                 "mac_wan_mode",
        /* Attribute Code */       kBooleanAttributeMacWanMode,
        /* Attribute Type */       kAttributeBoolean,
        /* Description */          "If set to one,MAC will reduce the avg data rate to that of SONET.",
        /* Config-Status */        kDagAttrConfig,
        /* Index in register */    10,
        /* Register Address */     DAG_REG_XGMII,
        /* Offset */               kConfig,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 BIT13,
        /* Default Value */        0,
        /* SetValue */             attribute_boolean_set_value,
        /* GetValue */             attribute_boolean_get_value,
        /* SetToString */          attribute_boolean_to_string,
        /* SetFromString */        attribute_boolean_from_string,
        /* Dispose */              attribute_dispose,
        /* PostInit */             attribute_post_initialize,
    }
};

/* Number of elements in array */
#define NB_ELEM (sizeof(xgmii_attr) / sizeof(Attribute_t))
#define NB_ELEM_V2 (sizeof(xgmii_ver2_attr) / sizeof(Attribute_t))

ComponentPtr
xgmii_get_new_component(DagCardPtr card, uint32_t index)
{
    ComponentPtr result = component_init(kComponentXGMII, card);

    if (NULL != result)
    {
        xgmii_state_t* state = (xgmii_state_t*)malloc(sizeof(xgmii_state_t));
        component_set_dispose_routine(result, xgmii_dispose);
        component_set_reset_routine(result, xgmii_reset);
        component_set_default_routine(result, xgmii_default);
        component_set_post_initialize_routine(result, xgmii_post_initialize);
	component_set_getstate_routine(result,xgmii_get_state_routine);
        component_set_name(result, "xgmii");
        state->mIndex = index;
        component_set_private_state(result, state);
    }

    return result;
}

static void
xgmii_dispose(ComponentPtr component)
{
}

static void
xgmii_reset(ComponentPtr component)
{
}

static void
xgmii_default(ComponentPtr component)
{
    AttributePtr attribute;
    void* val;

    //sets the default values 
    if (1 == valid_component(component))
    {
        uint8_t  val_default = 1;

	attribute = component_get_attribute(component, kBooleanAttributeTxCrc); 
	val = (void *)1;
	attribute_set_value(attribute, &val, 1);

	attribute = component_get_attribute(component, kBooleanAttributeCrcStrip); 
	val = (void *)0;
	attribute_set_value(attribute, &val, 1);
        
        attribute = component_get_attribute(component, kBooleanAttributeRxEnable); 
        val_default = 1;
        attribute_set_value(attribute, &val_default, sizeof(val_default));

        attribute = component_get_attribute(component, kBooleanAttributeTxEnable); 
        val_default = 1;
        attribute_set_value(attribute, &val_default, sizeof(val_default));
	/*WAN mode turned off by default*/
        attribute = component_get_attribute(component,kBooleanAttributeMacWanMode); 
        val_default = 0;
        attribute_set_value(attribute, &val_default, sizeof(val_default));
        /* TODO . get default value and set as commented out below  and test*/
/*	int count = component_get_attribute_count(component);
        int index;
        
        for (index = 0; index < count; index++)
        {
           AttributePtr attribute = component_get_indexed_attribute(component, index); 
           void* val = attribute_get_default_value(attribute);
           attribute_set_value(attribute, &val, 1);
        }
	*/
    }	

}

static int
xgmii_post_initialize(ComponentPtr component)
{
	uintptr_t address = 0;
	uint32_t reg_val = 0;
	DagCardPtr card = NULL;
	xgmii_state_t* state = component_get_private_state(component);
	AttributePtr attr;
	GenericReadWritePtr grw = NULL;
        uint32_t mask = 0;
	int reg_version;
    int xgmii_version = -1;
	assert(state);
	card = component_get_card(component);
	address = card_get_register_address(card, DAG_REG_XGMII, state->mIndex);
	reg_val = card_read_iom(card, address);
	if ((reg_val & BIT0) == BIT0)
	{
		/* we have a stats module */
		dagutil_verbose_level(4, "Loading xgmii statistics component\n");
		component_add_subcomponent(component, xgmii_statistics_get_new_component(card, state->mIndex));
	}

	read_attr_array(component, xgmii_attr, NB_ELEM, state->mIndex);

	/* reverse logic for the tx_crc bit */
	attr = component_get_attribute(component, kBooleanAttributeTxCrc);
	grw = attribute_get_generic_read_write_object(attr);
	assert(grw);
	grw_set_on_operation(grw, kGRWClearBit);

	/* reverse logic for the crcstrip bit */
	attr = component_get_attribute(component, kBooleanAttributeCrcStrip);
	grw = attribute_get_generic_read_write_object(attr);
	assert(grw);
	grw_set_on_operation(grw, kGRWClearBit);

	 /* reverse logic for the RSFaultEnable - attribute name is nic */
        attr = component_get_attribute(component,kBooleanAttributeRSFaultEnable);
        grw = attribute_get_generic_read_write_object(attr);
        assert(grw);
        grw_set_on_operation(grw, kGRWClearBit);


	/* Add Ethernet MAC Address */
	reg_version = card_get_register_version(card,DAG_REG_ROM, 0); 
    	if(reg_version == -1)
	         dagutil_error("not able to find the register \n");	
    	/* Add Ethernet MAC Address */
    	address = 8 + (state->mIndex*8); /* First port */
    	

	address = 8 + (state->mIndex*8); /* First port */
	grw = grw_init(card, address, grw_rom_read, NULL);
	attr = attribute_factory_make_attribute(kStringAttributeEthernetMACAddress, grw, &mask, 1);
	component_add_attribute(component, attr);

    /* Add the dummy 'network mode' attribute here */
    /* check for any 'sonet pp' component.*/
    /* add xgmii v2 attribs */
    xgmii_version = card_get_register_version(card,DAG_REG_XGMII, state->mIndex);
    if ( xgmii_version >= 2)
    {
        read_attr_array(component, xgmii_ver2_attr, NB_ELEM_V2, state->mIndex);
      }
      /*Remove the crcstip attribute if the xgmii version is greater than or equal to 2.*/
      if ( xgmii_version >= 2)
      {
	   attr = component_get_attribute(component,kBooleanAttributeCrcStrip);
	   component_dispose_attribute(component,attr);
      }
      
	return 1;
}


static dag_config_state_t
xgmii_get_state_routine(ComponentPtr component)
{
    DagCardPtr card = NULL;
    ComponentPtr root_component = NULL;
    ComponentPtr phy_rate_component = NULL;
    AttributePtr phy_rate = NULL;
    xgmii_state_t *state = NULL;
    line_rate_t line_rate;
    
    state = component_get_private_state(component);
    card = component_get_card(component);

    root_component = card_get_root_component(card);
    phy_rate_component = component_get_subcomponent(root_component,kComponentPhyMode,state->mIndex);
    if(NULL != phy_rate_component)
    {
	  phy_rate = component_get_attribute(phy_rate_component,kUint32AttributePhyRate);
	  if(NULL != phy_rate)
	  {
	    line_rate = *(line_rate_t*)attribute_get_value(phy_rate);
	    if(line_rate == kLineRateEthernet10GE)
	    {
	      	return kStateActive;
            }
	    else if (line_rate == kLineRateWAN)
	    {
		return kStateActive;
	    }
	    else if (line_rate == kLineRateOC192c)
	    {
		return kStateInactive;
	    }
	    else
	    {
	        return kStateInactive;
	    }
	  }else
	  {
	      return kStateActive;
	  }
    }
    else
    {
        return kStateActive;
    }
}
void* rs_fault_enable_get_value(AttributePtr attribute)
{
	DagCardPtr card = NULL;
        ComponentPtr component = NULL;
        ComponentPtr root = NULL;
	ComponentPtr port = NULL;
        ComponentPtr minimac = NULL;
        uint8_t nic = 0;
        AttributePtr line_rate_attr = NULL;
        AttributePtr minimac_nic = NULL;
	line_rate_t line_rate_val = kLineRateInvalid;
        xgmii_state_t * state = NULL;
        component = attribute_get_component(attribute);
        state = component_get_private_state(component);
        root = component_get_parent(component);
        card = attribute_get_card(attribute);
	port = component_get_subcomponent(root,kComponentPort,state->mIndex);
        line_rate_attr = component_get_attribute(port,kUint32AttributeLineRate);
        line_rate_val = *(line_rate_t*)attribute_get_value(line_rate_attr);

        if(line_rate_val == kLineRateEthernet1000)
        {
                root = component_get_parent(component);
                minimac = component_get_subcomponent(root,kComponentMiniMac,state->mIndex);
                minimac_nic = component_get_attribute(minimac,kBooleanAttributeNic);
                nic = *(uint8_t*)attribute_get_value(minimac_nic);
        }else
        {
		nic = *(uint8_t*)attribute_boolean_get_value(attribute);
	}
        attribute_set_value_array(attribute,&nic,sizeof(uint8_t));
        return (void*)attribute_get_value_array(attribute);
}

void rs_fault_enable_set_value(AttributePtr attribute, void* value, int length)
{
	DagCardPtr card = NULL;
        ComponentPtr component = NULL;
        ComponentPtr root = NULL;
        ComponentPtr port = NULL;
	ComponentPtr minimac = NULL;
        uint8_t nic = 0;
        AttributePtr line_rate_attr = NULL;
        AttributePtr minimac_nic = NULL;
        line_rate_t line_rate_val = kLineRateInvalid;
        xgmii_state_t * state = NULL;
        component = attribute_get_component(attribute);
        state = component_get_private_state(component);
        root = component_get_parent(component);
	nic = *(uint8_t*)value;
        card = attribute_get_card(attribute);
	port = component_get_subcomponent(root,kComponentPort,state->mIndex);
        line_rate_attr = component_get_attribute(port,kUint32AttributeLineRate);
        line_rate_val = *(line_rate_t*)attribute_get_value(line_rate_attr);
	
        if(line_rate_val == kLineRateEthernet1000)
        {
                minimac = component_get_subcomponent(root,kComponentMiniMac,state->mIndex);
                minimac_nic = component_get_attribute(minimac,kBooleanAttributeNic);
                attribute_set_value(minimac_nic,&nic,sizeof(uint8_t));
        }else
        {
		attribute_boolean_set_value(attribute,&nic,sizeof(uint8_t));
        }
}



