/*
 * Advanced Bios data structures and defines.
 *
 * The structure looks something like this:
 *
 *       +---------------+
 *     	 | Request Block |
 *     	 +---------------+
 *     	 |       *       |
 *     +-+  Logical ID   |
 *     | |       *       |
 *     | +---------------+
 *     |                       +----------------+
 *     |   +-------------------+ Anchor Pointer |
 *     |   |                   +----------------+
 *     |   |  +---------------------------------+
 *     |   +->|      Common Data Area           |
 *     |      +---------------------------------+
 *     |   +--+      Data pointer 0 Offset	|            +-----------------+
 *     |   |  |      Number Logical ID's        |     +----->|  Device Block n |
 *     |   |  |                *                |     |      +-----------------+
 *     +---+->|      Device Block Pointer n     |-----+      |        *        |
 *     +---+--+ Function Transfer Table Pointer |            |   Device Data   |
 *     |   |  |       for logial device n       |            |        *        |
 *     |   |  |                *                |            +-----------------+
 *     |   |  |                *                |            +-----------------+
 *     |   |  |         Data Pointer 'p'        |----------->|  Device Memory  |
 *     |   |  |                *                |            +-----------------+
 *     |   +->|         Data Pointer 0          |
 *     |      +---------------------------------+
 *     |      +---------------------------------+            +-----------------+
 *     +----->|     Function Transfer Table     |            | ABIOS Functions |
 *            +---------------------------------+            +-----------------+
 *            |                *                |            |        *        |
 *            |        Function 1 Pointer       |----------->|   Function 1    |
 *            |        Function 2 Pointer       |----------->|   Function 2    |
 *            |        Function 3 Pointer       |----------->|   Function 3    |
 *            |                *                |            |        *        |
 *            +---------------------------------+            +-----------------+
 *
 * This diagram is from Chapter 2 of the "Advanced BIOS Supplement for the IBM 
 * Personal System/2 and Personal Computer BIOS Interface Technical Reference"
 * P/N 68X2288.
 */

/*
 * the function transfer table contains
 * calls to the ABIOS start, interupt, and timeout
 * routines. Each logical device also has a number of
 * function call routines. The number of this are specified
 * by the function_count field.
 */
struct Function_call	{
	void	(far *x)();
};

struct	Function_transfer_table {
	void	(far *start)();
	void	(far *interupt)();
	void	(far *timeout)();
	u_short	function_count;
	u_short	Reserved1;
	struct Function_call	fun_call[1]; /* unknown size... */
};
#define	function_call(n)	fun_call[n].x

/*
 * the device block contains internal state information
 * about the device running. All fields fall under 2 catagories:
 * public (read-only areas which the OS may read), and private 
 * (data areas which the OS may never read data format veries between
 * different ABOIS implementations). Only the pulic areas of the structure
 * is defined in this .h file.
 */
struct Port_pairs {
	u_short	start;
	u_short end;
};

struct Device_block {
	u_short	device_block_length;
	u_char	revision;
	u_char	secondary_device_id;	/* additional revision info */
	u_short	logical_id;
	u_short	device_id;
	u_short	count_of_exclusive_ids;
	u_short count_of_common_ids;
	struct	Port_pairs	excl_ports[1]; /* unknown size */
};
#define exclusive_ports(n)	excl_ports[(n)]
#define common_ports(n)		excl_ports[(n)+count_of_exclusive_ids]
/*
 * The common block consists of a 1) header with the pointer to data '0',
 * and the number of logical ids, 2) an array of logical devices, 3) an
 * inverted array of data pointers.
 */
#define MAKE_POINTER(seg,data)	((char far *)((char far *)seg + \
							(u_short)data))
#ifdef ibm032
#define ALIGN_SEGMENT(pointer) (* (unsigned long *)(&pointer) = \
	    ((unsigned long)(FP_SEG(pointer) + ((FP_OFF(pointer)+15) >> 4))\
	    << 16))
#else
#define ALIGN_SEGMENT(pointer) ((unsigned long)(pointer) = \
	    ((unsigned long)(FP_SEG(pointer) + ((FP_OFF(pointer)+15) >> 4))\
	    << 16))
#endif

struct	Logical_device {
	struct Device_block far	*device_block;
	struct Function_transfer_table far *function_transfer_table;
};

struct Data_pointer {
	u_short		dp_length;
	u_short		dp_offset;
	u_short		dp_segment;
};

struct Common_data_area_head {
	u_short		data_ptr_0;
	u_short		number_logical_ids;
	u_short		Reserved1[2];
	struct	Logical_device	log_device[1]; /* unknown size */
} far *anchor_pointer;

#define ABIOS_HEAD	10

u_short anchor_seg;

#define logical_device(n)	(anchor_pointer->log_device[(n)-1])
#define datapointer ((struct Data_pointer far *)(&anchor_pointer->log_device \
	[anchor_pointer->number_logical_ids]))
#define data_pointer0 ((struct Data_pointer far *)MAKE_POINTER( \
			         anchor_pointer,anchor_pointer->data_ptr_0))
#define data_pointer(n) (datapointer[(data_pointer0 - &datapointer[n])])

/*
 * Initialization structures.
 */

/*
 * system parameter table. Contains the entry points into ABIOS.
 */
struct System_parameter_table {
	void	(far *common_start)();
	void	(far *common_interupt)();
	void	(far *common_timeout)();
	u_short	min_stack;
	u_long	Reserved1[4];
	u_short	number_of_entries;
} system_parameter_table;

#define abios_start(request)	((*system_parameter_table.common_start)(\
		(u_long)0,(u_long)0,(char far *)(request),anchor_seg))
#define abios_int(request)	((*system_parameter_table.common_interupt)(\
		(u_long)0,(u_long)0,(char far *)(request),anchor_seg))
#define abios_timeout(request)	((*system_parameter_table.common_timeout)(\
		(u_long)0,(u_long)0,(char far *)(request),anchor_seg))
/*
 * system init table. Temparary table used in ABIOS init and thrown away
 */
struct System_init_table {
	u_short		device_id;
	u_short		number_logical_ids;
	u_short		device_block_length;
	void		(far *log_device_init)();
	u_short		request_block_length;
	u_short		function_transfer_table_length;
	u_short		data_pointer_length;
	u_char		secondary_device_id;
	u_char		revision;
	u_short		Reserved[3];
};

/*
 * Request block defines.
 */
/* Function Parametes */
struct Request_header {
	u_short	Current_req_blck_len;	/* IN */
	u_short	Logical_id;		/* IN */
	u_short	Unit;			/* IN */
	u_short Function;		/* IN */
	u_short Reserved1[2];
	u_short Return_code;		/* IN/OUT */
	u_short Time_out;		/* OUT */
};
#define r_current_req_blck_len	request_header.Current_req_blck_len
#define r_logical_id		request_header.Logical_id
#define r_unit			request_header.Unit
#define r_function		request_header.Function
#define r_return_code		request_header.Return_code
#define r_time_out		request_header.Time_out

/* service specific info */
struct Logical_id_params {
	u_char	Hardware_intr;		/* OUT */
#define ABIOS_NO_INT	0xff	/* device doesn't interupt */
#define ABIOS_NMI_INT	0xfe	/* interupts on the NMI line */
	u_char	Arbitration_level;	/* OUT */
	u_short	Device_id;		/* OUT */
	u_short	Number_units;		/* OUT */
	u_short	Logical_id_flags;	/* OUT */
#define	OVERLAP_IO	0x08
#define POINTER_TYPES	0x03
#define NO_POINTERS	0x00
#define LOG_POINTER	0x01
#define PHYS_POINTER	0x02
#define BOTH_POINTER	0x03
#define GET_POINTER_TYPE(x) ((x) & POINTER_TYPES)
	u_short	Request_block_length;	/* OUT */
	u_char	Secondary_id;		/* OUT */
	u_char	Revision_level;		/* OUT */
	u_short	Reserved2[2];
}; 
#define	r_hardware_intr		un.logical_id_params.Hardware_intr
#define r_arbitration_level	un.logical_id_params.Arbitration_level
#define r_device_id		un.logical_id_params.Device_id
#define r_number_units		un.logical_id_params.Number_units
#define r_logical_id_flags	un.logical_id_params.Logical_id_flags
#define r_request_block_length	un.logical_id_params.Request_block_length
#define r_secondary_id		un.logical_id_params.Secondary_id
#define r_revision_level	un.logical_id_params.Revision_level

/*
 * Function codes.
 */
#define	ABIOS_DEFAULT_INTERUPT	0
#define	ABIOS_LOGICAL_PARAMETER	1
#define ABIOS_RESERVED_2	2
#define ABIOS_READ_PARAMETER	3
#define ABIOS_WRITE_PARAMETER	4
#define ABIOS_RESET		5
#define ABIOS_ENABLE_INTR	6
#define ABIOS_DISABLE_INTR	7
#define ABIOS_READ		8
#define ABIOS_WRITE		9
#define ABIOS_ADDITIONAL_XFER	0xa

/*
 * return codes, valid only if bit 15 is 0
 */
#define ABIOS_STAGE_ON_INT	0x0001
#define ABIOS_STAGE_ON_TIME	0x0002
#define	ABIOS_NOT_MY_INT	0x0004
#define ABIOS_ATTENTION		0x0008
#define ABIOS_INT_RESET		0x0080

/*
 * return codes, valid only if bit 15 is 1
 */
#define ABIOS_FAILED_OP		0x8000
#define ABIOS_BAD_PARAM		0x4000
#define ABIOS_TIME_OUT		0x2000
#define ABIOS_DEV_ERROR		0x1000
#define ABIOS_RETRYABLE		0x0100

/*
 * the following is the undefined return code
 */
#define ABIOS_UNDEFINED		0xffff

/*
 * macros to decipher ABIOS return codes
 */
#define ABIOS_STAGED(x)		((((x) & ABIOS_FAILED_OP)==0) && \
	((x) & (ABIOS_STAGE_ON_INT|ABIOS_STAGE_ON_TIME)))
#define ABIOS_RETRY(x)		((x) & ABIOS_RETRYABLE)

/*
 * the following structures are local structures built
 * to allow local storage of ABIOS information.
 */
struct Device_info {
	char		*name;		/* device name */
	u_short		init;		/* should device be inited? */
#define	INIT	1
#define NOINIT	0
	u_short		logical_id;	/* device logical id */
	u_short		device_count;	/* number of devices */
	u_short		fft;		/* address of func trans table */
	u_short		db;		/* address of device block */
};

#define	ABIOS_ID	0	/* ABIOS internal calls */
#define FD_ID		1	/* floppy */
#define HD_ID		2	/* hard disk */
#define VIDEO_ID	3	/* display */
#define	KBD_ID		4	/* keyboard */
#define LP_ID		5	/* parallel port */
#define ASY_ID		6	/* async port */
#define CLOCK_ID	7	/* real time clock */
#define SS_ID		8	/* system services */
#define NMI_ID		9	/* non-mask interupt */
#define	MS_ID		0xa	/* mouse */
#define NVR_ID		0xe	/* Non-volatile ram */
#define DMA_ID		0xf	/* dma */
#define POS_ID		0x10	/* programable option select */
#define KBDS_ID		0x16	/* keyboard security */
