/* -*- Mode:C; Tab-width:4 -*- */
/*                                                                       */
/*                                                                       */
/*                      RESTRICTED RIGHTS LEGEND                         */
/*                                                                       */
/* Use, duplication, or disclosure by the Government is subject to       */
/* restrictions as set forth in subdivision (c)(1)(ii) of the Rights in  */
/* Technical Data and Computer Software clause at 252.227-7013.          */
/*                                                                       */
/*                    TEXAS INSTRUMENTS INCORPORATED.                    */
/*                            P.O. BOX 149149                            */
/*                         AUSTIN, TEXAS 78714-9149                      */
/*                              MS 2151                                  */
/*                                                                       */
/*  Copyright (C)   1987,1988,1989,1990 Texas Instruments Incorporated.  */
/*  All rights reserved.                                                 */
/*                                                                       */

/* 3-13-89   BJ  Add physical <> virtual translations for acb link field. */

#ifndef __AddinComm__
#define __AddinComm__

#define  REL4P 1

#include <memory.h> 	/* Needed for BlockMove() 	*/
#include <utility.h>

extern Boolean verbose;

/************************************************************/
/*                                                          */
/* Queueing                                                 */
/*                                                          */
/************************************************************/

extern queue_struct *find_q(size);

/************************************************************/
/*                                                          */
/* Channel definitions                                      */
/*                                                          */
/************************************************************/

#define MAX_NUMBER_OF_CHANNELS 16 /* The maximum number of channels on the explorer. */

/* 16 bit accessors for channel status. */
struct channel_status_16b
	{
		unsigned short attribute;		/* The 16 bit word with the channels attributes in it.	*/
		unsigned short ch_status;		/* The 16 bit word with the channels status in it. 		*/
	};
	
/* channel status flags. */
struct channel_status_1b
	{
		unsigned char :4;
		unsigned char initialized:1;	/* Tells whether the channel has been initialized by the addin. */
		unsigned char enabled:1;		/* Tells if channel has been enabled by the addin.				 */
		unsigned char error:1;			/* User flags tells whether cmd resulted in an error. 			*/
	    unsigned char debugenabled:1;	/* explorer only */
		unsigned char unused1;
		unsigned char :5;
		unsigned char interrupt:1;		/* Tells whether the servicer is handling this channel by polling (0) or interrupts (1). set by the servicer. */
		unsigned char requestor:1; 		/* host (1) or addin (0). 				*/
		unsigned char queued:1;			/* tells whether the addin is queueing. */
		unsigned char unused2;
	};

/* Made channel two way with queueing. *BJ* */
typedef struct channel
	{
		union
			{
				struct channel_status_16b s16b;
				struct channel_status_1b s1b;
			}ch_status;
		long max_q_length;
		queue_struct queue_host;
		queue_struct queue_mx;
		long unused;
	} channel;

/* These would be needed by anyone trying to add a handler for a channel from another file. */	
extern channel *channels[MAX_NUMBER_OF_CHANNELS]; 		/* An array of pointers to the bank of comm channels. 	*/
extern Boolean (*channel_handlers[MAX_NUMBER_OF_CHANNELS]) (); /* The array of handlers for each channel. 				*/

#define channel_interrupt(ch)																\
	ch->ch_status.s1b.interrupt

#define set_channel_interrupt(ch, val)														\
	ch->ch_status.s1b.interrupt = val

#define HOST  0 /* The value that indicates that the host processor is the requestor for a channel. */
#define ADDIN 1 /* The value that indicates that the addin processor is the requestor for a channel. */

#define channel_requestor(ch)																\
	ch->ch_status.s1b.requestor
	
#define set_channel_requestor(ch, val)														\
	ch->ch_status.s1b.requestor = val
	
#define channel_queued(ch)																	\
	ch->ch_status.s1b.queued

#define set_channel_queued(ch, val)															\
	ch->ch_status.s1b.queued = val

#define channel_error(ch)																	\
	ch->ch_status.s1b.error

#define set_channel_error(ch, val)															\
	ch->ch_status.s1b.error = val
	
#define channel_enabled(ch)																	\
	ch->ch_status.s1b.enabled

#define set_channel_enabled(ch, val)														\
	ch->ch_status.s1b.enabled = val
	
#define channel_initialized(ch)																\
	ch->ch_status.s1b.initialized

#define set_channel_initialized(ch, val)													\
	ch->ch_status.s1b.initialized = val


/************************************************************/
/*                                                          */
/* ACB Definitions.                                         */
/*                                                          */
/************************************************************/
/* clm 8/21/89 - changed the value of the following to 0xfff */
/* under MPW 3.0, structures may not be larger that 32k.     */
#define MAX_PARM_BYTES 0x1dff /* The maximum number of bytes of parameters in an ACB. */

struct acb_status_32b
	{
		unsigned long stat;		/* 32 bit acb status word. */
	};

struct acb_status_8b
	{
          unsigned char unused1;
	  unsigned char requestor_stat;
          unsigned char unused2;
	  unsigned char servicer_stat;		
	};


struct acb_status_1b
	{
		unsigned char :8;
		unsigned char :8;                       /* values back in the block. */
	   	unsigned char acb_requestor_complete:1;	/* Requestor is finished copying return values out of acb. */
		unsigned char acb_deallocatable:1;		/* Acb can be deallocated. 									*/
		unsigned char :6;

	   	unsigned char acb_servicer_complete:1;	/* Servicer has completed all input and has placed any return */
		unsigned char acb_input_complete:1;		/* Servicer has completed input and will not return any values. */
		unsigned char :6;  
	};

struct acb_parms_8b 
	{	
	   	unsigned char parm[MAX_PARM_BYTES];	/* 8 bit parm accessors. 	*/
	};
				   
struct acb_parms_16b 
	{
	   	unsigned short parm[MAX_PARM_BYTES];/* 16 bit parm accessors. 	*/
	};
		
struct acb_parms_32b 
	{
   		unsigned int parm[MAX_PARM_BYTES];/* 32 bit parm accessors. 	*/
	};

typedef struct acb_addr
{
  unsigned short port;
  unsigned short slot;
} acb_addr;

/* Channel specific refers to the fact that opcodes should be unique among the users of a specific channel. */

struct acb_header
	{	
		struct acb_header *acb_queue_link;			/* A long word for constructing queues. */
		struct queue_header *acb_return_queue;
		struct acb_addr src_addr;
		struct acb_addr dest_addr;

	   	unsigned char unused1;					
	        unsigned char acb_subopcode;				/* An application defined sub-opcode. 				*/
		unsigned char unused2;
	        unsigned char acb_opcode;					/* A channel specific application defined opcode. 	*/	

		unsigned char unused3;
	   	unsigned char acb_error_code; 				/* An application defined code to describe errors. 	*/
		unsigned char unused4;
		unsigned char acb_return_action;
		
		union
			{
				struct acb_status_32b s32b;
				struct acb_status_8b s8b;
				struct acb_status_1b s1b;
			} acb_status;	

		unsigned long total_data_bytes;			/* The number of data bytes actually available in the acb.  */
		unsigned long number_parm_bytes;			/* The number of bytes of parms actually placed in the acb. */
		unsigned long reserved1;					/* This is a virtual memory pointer used by the addin. 		*/
	};
	
typedef struct acb
	{ 
		struct acb_header header;
		union
		{
			struct acb_parms_8b p8b;
			struct acb_parms_16b p16b;
			struct acb_parms_32b p32b;
		}parms;
	} acb;

#define ACB_OVERHEAD_LENGTH sizeof(struct acb_header) /* The number of 8 bit elements of overhead in a parameter block*/

extern acb *get_acb_fast(size);
extern void return_acb_fast(cmd);
extern void return_acb_server(cmd);

#define return_acb(acb)				\
	return_acb_fast(acb)
	
#define get_acb(size)				\
	get_acb_fast(size)
	  
/************************************************************/
/*                                                          */
/* Communications definitions                               */
/*                                                          */
/************************************************************/

#define wait_for_condition(boolean_expression) 												\
	while (!(boolean_expression)) 															\
		with_24_bit_mode(event_handler(0,0))


#define send_command(cmd, channel)															\
    q_element(&(channels[channel]->queue_host), (q_elem *) cmd);                  			\

/*  3.0 C compiler was barfing because of calls to transmit_packet with only */
/*  two arguments, appears noone is using third argument anyway, so dropped it  */
/*  #define transmit_packet(acb, channel, slot)                                                 \   */
/*           send_command(acb, channel)                                                                     */

#define transmit_packet(acb, channel)                                                 \
            send_command(acb, channel)


/*
   This is somewhat of a kludge used my the multi-channel version of microNet ports. It places a packet
   into the mx queue for a channel instead of the host queue.
*/
#define transmit_packet_local(cmd, channel)													\
    q_element(&(channels[channel]->queue_mx), (q_elem *) cmd);                  			\

#define receive_packet(channel, no_hang_p)                                                  \
            get_command(channel, no_hang_p)

#define send_command_and_wait(acb, channel)													\
         	send_command(acb, channel);														\
			wait_for_condition (acb->header.acb_status.s1b.acb_servicer_complete == 1)
			 
extern acb *get_command();

#define return_queue(cmd)                                \
        (cmd)->header.acb_return_queue

#define set_return_queue(cmd, value)                     \
        (cmd)->header.acb_return_queue = value

#define source_address(cmd)                              \
        (cmd)->header.src_addr

/* ANSI C  - type in (cast) must be scalar */
/* so changed this to the version below  - clm 8/22/89 */
/*  #define set_source_address(cmd, value)                \   */
/*          (cmd)->header.src_addr = ((acb_addr) value)  */


#define set_source_address(cmd, value)                   \
        (cmd)->header.src_addr = value


#define source_port(cmd)                                 \
        swap_16b((cmd)->header.src_addr.port)

#define set_source_port(cmd, value)                      \
        (cmd)->header.src_addr.port = swap_16b(value)

#define source_slot(cmd)                                 \
        swap_16b((cmd)->header.src_addr.slot)

#define set_source_slot(cmd, value)                      \
        (cmd)->header.src_addr.slot = swap_16b(value)

#define destination_address(cmd)                              \
        (cmd)->header.dest_addr


/* ANSI C  - type in (cast) must be scalar */
/* so changed this to the version below  - clm 8/22/89 */
/*  #define set_destination_address(cmd, value)                   \   */
/*       (cmd)->header.dest_addr = ((acb_addr) value)     */

#define set_destination_address(cmd, value)                   \
        (cmd)->header.dest_addr = value


#define destination_port(cmd)                                 \
        swap_16b((cmd)->header.dest_addr.port)

#define set_destination_port(cmd, value)                      \
        (cmd)->header.dest_addr.port = swap_16b(value)

#define destination_slot(cmd)                                 \
        swap_16b((cmd)->header.dest_addr.slot)

#define set_destination_slot(cmd, value)                      \
        (cmd)->header.dest_addr.slot = swap_16b(value)

#define return_action(cmd)                                    \
        (cmd)->header.acb_return_action

#define set_return_action(cmd)                                \
        (cmd)->header.acb_return_action = value

#define opcode(acb)																			\
	acb->header.acb_opcode
	
#define set_opcode(acb, op) 																\
	acb->header.acb_opcode = op

#define subopcode(acb)																		\
	acb->header.acb_subopcode
	
#define set_subopcode(acb, op) 																\
	acb->header.acb_subopcode = op
	
#define status(acb)																			\
	swap_32b(acb->header.acb_status.s32b.stat)

#define set_status(acb, value)																 \
	acb->header.acb_status.s32b.stat = swap_32b(value)

#define servicer_status(acb)																\
	acb->header.acb_status.s8b.servicer_stat
	
#define set_servicer_status(acb, value)														\
	acb->header.acb_status.s8b.servicer_stat = value
	
#define requestor_status(acb)																\
	acb->header.acb_status.s8b.requestor_stat
	
#define set_requestor_status(acb,value)														\
	acb->header.acb_status.s8b.requestor_stat = value

#define servicer_complete(acb)																\
	acb->header.acb_status.s1b.acb_servicer_complete
	
#define set_servicer_complete(acb, value) 													\
	acb->header.acb_status.s1b.acb_servicer_complete = value

#define input_complete(acb)														            \
	acb->header.acb_status.s1b.acb_input_complete
	
#define set_input_complete(acb, value) 														\
	acb->header.acb_status.s1b.acb_input_complete = value

#define requestor_complete(acb)																\
	acb->header.acb_status.s1b.acb_requestor_complete
	
#define set_requestor_complete(acb, value) 													\
	acb->header.acb_status.s1b.acb_requestor_complete = value
		
#define deallocatable(acb)																	\
	acb->header.acb_status.s1b.acb_deallocatable
	
#define set_deallocatable(acb, value) 														\
	acb->header.acb_status.s1b.acb_deallocatable = value

#define error_code(acb) 																	\
	acb->header.acb_error_code
	
#define set_error_code(acb, code) 															\
	acb->header.acb_error_code = code
	
#define parm_bytes(acb)																		\
	swap_32b(acb->header.number_parm_bytes)
	
#define set_parm_bytes(cmd, n)																\
	cmd->header.number_parm_bytes = swap_32b(n)

#define data_bytes(acb)																		\
	swap_32b(acb->header.total_data_bytes)
	
#define set_data_bytes(acb, n)																\
	acb->header.total_data_bytes = swap_32b(n)

#define queue_link(cmd)																		\
	((acb *)physical_to_virtual(swap_32b(cmd->header.acb_queue_link)))
	
#define set_queue_link(cmd, ptr)															\
	cmd->header.acb_queue_link = ((acb *)swap_32b(virtual_to_physical(ptr)))
	
#define parm_8b(acb, parm_number)															\
	acb->parms.p8b.parm[parm_number]

#define set_parm_8b(acb, parm_number, value)												\
	acb->parms.p8b.parm[parm_number] = value

#define parm_8b_addr(acb, parm_number)														\
	acb->parms.p8b.parm + parm_number

#define TO_ACB 0 /* Value to pass to copy_parms_* to copy from array to acb*/
#define TO_ARRAY 1      /* Value to pass to copy_parms_* to copy from acb to array*/
#define copy_parms_8b(acb, array, parm_n, number_of_parms_to_copy, Direction)				\
	if (Direction == TO_ACB)																\
		BlockMove(array, 																	\
				   acb->parms.p8b.parm + parm_n,											\
				   number_of_parms_to_copy);												\
	else																					\
		BlockMove(acb->parms.p8b.parm + parm_n,												\
				   array,																	\
				   number_of_parms_to_copy)

#define parm_16b(acb, parm_number)															\
	swap_16b(acb->parms.p16b.parm[parm_number])
	
#define set_parm_16b(acb, parm_number, value)												\
	acb->parms.p16b.parm[parm_number] = swap_16b(value)
			 
#define parm_16b_addr(acb, parm_number)														\
	acb->parms.p16b.parm + parm_number

#define copy_parms_16b(acb, array, parm_n, number_of_parms_to_copy, Direction) 				\
			if (Direction == TO_ACB)														\
				block_swap_16b(array,														\
						  	     acb->parms.p16b.parm + parm_n,								\
								 number_of_parms_to_copy);		    						\
			 else  																			\
				block_swap_16b(acb->parms.p16b.parm + parm_n, 								\
						    	 array,														\
								 number_of_parms_to_copy)

#define parm_32b(acb, parm_number)															\
	swap_32b(acb->parms.p32b.parm[parm_number])
	
#define set_parm_32b(acb, parm_number, value)												\
	acb->parms.p32b.parm[parm_number] = swap_32b(value)
			 
#define parm_32b_addr(acb, parm_number)														\
	acb->parms.p32b.parm + parm_number

#define copy_parms_32b(acb, array, parm_n, number_of_parms_to_copy, Direction) 				\
			if (Direction == TO_ACB)														\
				block_swap_32b(array,														\
						      acb->parms.p32b.parm + parm_n,								\
						      number_of_parms_to_copy);										\
			 else  																			\
				block_swap_32b(acb->parms.p32b.parm + parm_n,								\
						 array,																\
						 number_of_parms_to_copy)


#endif