/*******************************************************************************
*
* File Name : atp_port.c
*
* Functions used by atp_services.c file to handle port structure
*
* (C) Texas Instruments, all rights reserved
*
* Version number	: 0.1      Date : 10-May-2000 from atp_port.c
*
* History			: 0.1  - Created by E. Baissus . Gathers functions used only
*								as internal services
*
* Author			: Eric Baissus : e-baissus@ti.com
*
*   (C) Copyright 2000 by Texas Instruments Incorporated, All Rights Reserved		
******************************************************************************/
#include "rv/rv_general.h"
#include "rvf/rvf_api.h"
#include "atp/atp_api.h"
#include "atp/atp_i.h"
#include "atp/atp_messages.h"
#include "rvm/rvm_use_id_list.h"



T_ATP_PORT_STRUCT * atp_first_port_p; /* Pointer on the first port structure */

T_ATP_RET atp_init_port(T_ATP_PORT_STRUCT *new_port_p);









/******************************************************************************
* Function name: atp_init_port
*
* Description : Initialise a new port
*
* Parameters :  pointer on the new port
*
* Return     :   Always return RV_OK
*
* History			: 0.1 (1-Marsh-2000) - Created
*					  0.9:(22-May-2000) - Added redirection
*
******************************************************************************/

T_ATP_RET atp_init_port(T_ATP_PORT_STRUCT *new_port_p)
{
	new_port_p->next_p                                      = NULL;
	new_port_p->port_state                                  = ATP_OPEN_PENDING;

	(new_port_p->port_info[0]).port_nb                      = INVALID_PORT_NB;
	(new_port_p->port_info[0]).sw_id                        = ATP_INVALID_SWE_ID;
	(new_port_p->port_info[0]).tx_mb                        = RVF_INVALID_MB_ID;
	(new_port_p->port_info[0]).rx_mb                        = RVF_INVALID_MB_ID;
	(new_port_p->port_info[0]).rx_data_left                 = 0;
	((new_port_p->port_info[0]).no_copy_info).packet_mode   = NORMAL_PACKET;
	((new_port_p->port_info[0]).no_copy_info).rx_head_size  = 0;
	((new_port_p->port_info[0]).no_copy_info).rx_trail_size = 0;
	((new_port_p->port_info[0]).no_copy_info).tx_head_size  = 0;
	((new_port_p->port_info[0]).no_copy_info).tx_trail_size = 0;
	(new_port_p->port_info[0]).signal                       = (ATP_RX_FLOW_ON | ATP_TX_FLOW_ON);
	
	(new_port_p->port_info[1]).port_nb                      = INVALID_PORT_NB;
	(new_port_p->port_info[1]).sw_id                        = ATP_INVALID_SWE_ID;
	(new_port_p->port_info[1]).tx_mb                        = RVF_INVALID_MB_ID;
	(new_port_p->port_info[1]).rx_mb                        = RVF_INVALID_MB_ID;
	(new_port_p->port_info[1]).rx_data_left                 = 0;
	((new_port_p->port_info[1]).no_copy_info).packet_mode   = NORMAL_PACKET;
	((new_port_p->port_info[1]).no_copy_info).rx_head_size  = 0;
	((new_port_p->port_info[1]).no_copy_info).rx_trail_size = 0;
	((new_port_p->port_info[1]).no_copy_info).tx_head_size  = 0;
	((new_port_p->port_info[1]).no_copy_info).tx_trail_size = 0;
	(new_port_p->port_info[1]).signal                       = (ATP_RX_FLOW_ON | ATP_TX_FLOW_ON);
	
	/* Redirection information */
	new_port_p->redirect_mode        = ATP_REDIRECT_OFF;
	new_port_p->redirect_port_end_nb = 0;
	new_port_p->redirect_port_p      = NULL;

	/* Data queue information */
	(new_port_p->port_info[0]).rx_queue.p_first = NULL;
	(new_port_p->port_info[0]).rx_queue.p_last  = NULL;
	(new_port_p->port_info[0]).rx_queue.count   = 0;

	(new_port_p->port_info[1]).rx_queue.p_first = NULL;
	(new_port_p->port_info[1]).rx_queue.p_last  = NULL;
	(new_port_p->port_info[1]).rx_queue.count   = 0;

	/* Pointer on DCE information */
	new_port_p->dce_info_p  = NULL;

	new_port_p->port_config = NOT_DEFINED_CONFIG;

	/* Flow control */
	new_port_p->port_waiting_for_mb_callback = ATP_MAX_SW_NB;

	/* Command info */
	new_port_p->cmd_info.cmd_txt_p = NULL;

	return	(atp_init_cmd_info_struct (new_port_p));
}







/******************************************************************************
* Function name: atp_create_port
*
* Description : Create a new port instance in the port chained list
*
* Parameters :  Output = pointeur on the new port structure
*
* Return     :   Error flag :
*                Possible values are RV_OK or RV_MEMORY_ERR
*
* History			: 0.1 (1-Marsh-2000) - Created / E.Baissus
*
******************************************************************************/

T_ATP_RET atp_create_port(T_ATP_PORT_STRUCT **port_pp)
{

	T_ATP_PORT_STRUCT *new_port_p,*p;
	
	/* get new buffer */
	switch(rvf_get_buf(atp_mb_prim,sizeof(T_ATP_PORT_STRUCT),(void **) &new_port_p))
	{
		case RVF_GREEN:
			{
				break;
			}
		case RVF_YELLOW:
			{
				rvf_free_buf ((T_RVF_BUFFER *) new_port_p);
			}
		default:
			{
				return RV_MEMORY_ERR;
			}
	}
		
	/* initialisation of the new instance */
	atp_init_port(new_port_p);
	
	
	// START : THIS SECTION MUST BE PROTECTED BY  A SEMAPHORE !!!!!!
	
	/* get latest port instance */
	if (atp_first_port_p==NULL)
	{ /* this new instance is the first one */
		atp_first_port_p=new_port_p;
	}
	else
	{
		p=atp_first_port_p;
		while(p->next_p!=NULL)
		{
			p=p->next_p;
		}
		/* p points on the last port instance */
		p->next_p=new_port_p;
	}
	// END : THIS SECTION MUST BE PROTECTTED BY  A SEMAPHORE !!!!!!
	
	*port_pp=new_port_p;
	
	return RV_OK;
}







/******************************************************************************
* Function name: atp_delete_port
*
* Description : delete port instance
*
* Parameters :  - port_p points on the port structure to remove
*
* Return     :   Standard error flag 
*                If OK, returns RV_OK
*
* History			: 0.1 (1-Marsh-2000) - Created / E.Baissus
*
******************************************************************************/

T_ATP_RET atp_delete_port(T_ATP_PORT_STRUCT *port_p)
{
	T_ATP_PORT_STRUCT *p;
	
	p=atp_first_port_p;
	

	// START : THIS SECTION MUST BE PROTECTED BY  A SEMAPHORE !!!!!!
	/* Delete buffer pointer by the port structure */
	if  (port_p->dce_info_p != NULL)
	{
		// Reset fields used by the escape sequence algorithm 
		atp_reset_escape_sequence(port_p);		
		rvf_free_buf(port_p->dce_info_p);
	}
	if (port_p->cmd_info.cmd_txt_p != NULL)
	{
		rvf_free_buf(port_p->cmd_info.cmd_txt_p);
	}
	if (p==port_p)
	{
		/* The instance to delete is the first one */
		atp_first_port_p=port_p->next_p;
		rvf_free_buf(port_p);
		return RV_OK;
	}
	else
	{
		
		while(p!=NULL)
		{
			if (p->next_p==port_p)
			{
				/* The instance to deleted has been found */
				if (port_p->next_p==NULL)
				{
					/* The instance to delete is the last instance of the chain */
					p->next_p=NULL;
				}
				else
				{
					p->next_p=port_p->next_p;
				}
				
				rvf_free_buf(port_p);
				return RV_OK;
				
			}			
			p=p->next_p;	
			
		} /* end of the while loop */
		// END : THIS SECTION MUST BE PROTECTTED BY  A SEMAPHORE !!!!!!
		
		/* The device has not been found */
		return RV_INTERNAL_ERR;
		
	}/* end of the if/else */
}





/******************************************************************************
* Function name: atp_get_port
*
* Description : provides the pointer pointing on the proper port structure
* value
*
* Parameters :  - sw_id : SW entity ID related to the port
*				 - port_nb : associated port number
*				 - &port_p : output :  pointer on the found port structure
*				 - &sw_nd : output : indicate which of the 2 sw entity of the port has been found
*
* Return     :   Standard error flag from BT
*                If OK, returns RV_OK. If port not found, return RV_INTERNAL_ERR.
*
* History			: 0.1 (1-Marsh-2000) - Created / E.Baissus
*
******************************************************************************/

T_ATP_RET atp_get_port(T_ATP_SW_ENTITY_ID sw_id, T_ATP_PORT_NB port_nb, T_ATP_PORT_STRUCT **port_found_pp, T_ATP_SW_NB *sw_nb_p)
{
	for (*port_found_pp = atp_first_port_p;
		 *port_found_pp != NULL;
		 *port_found_pp = (*port_found_pp)->next_p)
	{
		if ((((*port_found_pp)->port_info[0]).sw_id == sw_id) && \
			(((*port_found_pp)->port_info[0]).port_nb == port_nb))
		{
			/* The port instance has been found : sw_nb = 0 (initiator) */
			*sw_nb_p = 0;
			return (RV_OK);
		}
		if ((((*port_found_pp)->port_info[1]).sw_id == sw_id) && \
			(((*port_found_pp)->port_info[1]).port_nb == port_nb))
		{
			/* The port instance has been found : sw_nb = 1 (target) */
			*sw_nb_p = 1;
			return (RV_OK);
		}
	}
	return (RV_INVALID_PARAMETER);
}


/******************************************************************************
* Function name: atp_delete_all_port
*
* Description : delete all the ports
*
* Parameters :  
*
* Return     :   Standard error flag 
*                If OK, returns RV_OK
*
* History			: 0.1 (1-Marsh-2000) - Created / E.Baissus
*
******************************************************************************/
T_ATP_RET atp_delete_all_port(void)
{
	T_ATP_PORT_STRUCT *p,*next_p;
	T_ATP_RET return_status = RV_OK;

	p=atp_first_port_p;
	while((p != NULL) && (return_status == RV_OK))
	{
		next_p = p->next_p;
		return_status = atp_delete_port(p);
		p=next_p;
	}
	return return_status;
}




/******************************************************************************
* Function name: atp_send_message
*
* Description : Generic function to send message
*
* Parameters :  
*
* Return     :   RV_OK
*
* History			: 0.1 (1-Marsh-2000) - Created
*                     0.15 (15-Marsh-2000) - Added possibility to send to a mail box
*					  
******************************************************************************/
T_ATP_RET atp_send_message(T_ATP_CALLBACK path,T_ATP_MESSAGE * message_p)
{
	
	if (path.callback_func!= NULL)
	{
		path.callback_func((void *) message_p);
		/* It is up to the target id to free the message buffer later on !!!!*/
		return RV_OK;
	}
	else
	{
		return rvf_send_msg(path.addr_id,(void *) message_p);
	}
	
}



