/*
 * SoftPC Version 2.0
 *
 * Title	: Generic Floppy Interface level definitions
 *
 * Description	: Data structures for GFI
 *
 * Author	: Henry Nash + various others
 *
 */

/*
   static char SccsID[]="@(#)gfi.h	1.11 11/28/92 Copyright Insignia Solutions Ltd.";
 */

/*
 * ============================================================================
 * Structure/Data definitions
 * ============================================================================
 */

#define MAX_COMMAND_LEN		9	/* max number of command bytes */
#define MAX_RESULT_LEN		7	/* max number of result bytes */

typedef unsigned char FDC_CMD_BLOCK;
typedef unsigned char FDC_RESULT_BLOCK;


/* START: FDC COMMAND BLOCK DEFINITIONS >>>>>>>>>>>>>>>>>>>>>>>>>>> */

/*
 * A simple access to the command type and drive
 */

/* the command itself	     */
#define get_type_cmd(ptr) (ptr[0] & 0x1f)
#define put_type_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* ...and the drive no	     */
#define get_type_drive(ptr) (ptr[1] & 0x3)
#define put_type_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)

/* 
 * Class 0 - read data, read deleted data, all scans 
 */

/* multi-track		     */
#define get_c0_MT(ptr) ((ptr[0] & 0x80) >> 7)
#define put_c0_MT(ptr,val) ptr[0] = (ptr[0] & ~0x80) | ((val << 7) & 0x80)
/* always 1 - FM not used    */
#define get_c0_MFM(ptr) ((ptr[0] & 0x40) >> 6)
#define put_c0_MFM(ptr,val) ptr[0] = (ptr[0] & ~0x40) | ((val << 6) & 0x40)
/* skip data 		     */
#define get_c0_skip(ptr) ((ptr[0] & 0x20) >> 5)
#define put_c0_skip(ptr,val) ptr[0] = (ptr[0] & ~0x20) | ((val << 5) & 0x20)
/* the command itself 	     */
#define get_c0_cmd(ptr) (ptr[0] & 0x1f)
#define put_c0_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* padding */
#define get_c0_pad(ptr) ((ptr[1] & 0xf8) >> 3)
#define put_c0_pad(ptr,val) ptr[1] = (ptr[1] & ~0xf8) | ((val << 3) & 0xf8)
/* which head 		     */
#define get_c0_head(ptr) ((ptr[1] & 0x4) >> 2)
#define put_c0_head(ptr,val) ptr[1] = (ptr[1] & ~0x4) | ((val << 2) & 0x4)
/* drive unit */
#define get_c0_drive(ptr) (ptr[1] & 0x3)
#define put_c0_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)
/* cylinder number 	     */
#define get_c0_cyl(ptr) ptr[2]
#define put_c0_cyl(ptr,val) ptr[2] = val
/* head number - again !     */
#define get_c0_hd(ptr) ptr[3]
#define put_c0_hd(ptr,val) ptr[3] = val
/* sector number 	     */
#define get_c0_sector(ptr) ptr[4]
#define put_c0_sector(ptr,val) ptr[4] = val
/* encoded bytes per sector  */
#define get_c0_N(ptr) ptr[5]
#define put_c0_N(ptr,val) ptr[5] = val
/* last sector on track      */
#define get_c0_EOT(ptr) ptr[6]
#define put_c0_EOT(ptr,val) ptr[6] = val
/* gap length 		     */
#define get_c0_GPL(ptr) ptr[7]
#define put_c0_GPL(ptr,val) ptr[7] = val
/* data length */
#define get_c0_DTL(ptr) ptr[8]
#define put_c0_DTL(ptr,val) ptr[8] = val

/* 
 * Class 1 - write data, write deleted data
 */

/* multi-track		     */
#define get_c1_MT(ptr) ((ptr[0] & 0x80) >> 7)
#define put_c1_MT(ptr,val) ptr[0] = (ptr[0] & ~0x80) | ((val << 7) & 0x80)
/* always 1 - FM not used    */
#define get_c1_MFM(ptr) ((ptr[0] & 0x40) >> 6)
#define put_c1_MFM(ptr,val) ptr[0] = (ptr[0] & ~0x40) | ((val << 6) & 0x40)
/* padding */
#define get_c1_pad(ptr) ((ptr[0] & 0x20) >> 5)
#define put_c1_pad(ptr,val) ptr[0] = (ptr[0] & ~0x20) | ((val << 5) & 0x20)
/* the command itself 	     */
#define get_c1_cmd(ptr) (ptr[0] & 0x1f)
#define put_c1_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* padding */
#define get_c1_pad1(ptr) ((ptr[1] & 0xf8) >> 3)
#define put_c1_pad1(ptr,val) ptr[1] = (ptr[1] & ~0xf8) | ((val << 3) & 0xf8)
/* which head 		     */
#define get_c1_head(ptr) ((ptr[1] & 0x4) >> 2)
#define put_c1_head(ptr,val) ptr[1] = (ptr[1] & ~0x4) | ((val << 2) & 0x4)
/* drive unit */
#define get_c1_drive(ptr) (ptr[1] & 0x3)
#define put_c1_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)
/* cylinder number 	     */
#define get_c1_cyl(ptr) ptr[2]
#define put_c1_cyl(ptr,val) ptr[2] = val
/* head number - again !     */
#define get_c1_hd(ptr) ptr[3]
#define put_c1_hd(ptr,val) ptr[3] = val
/* sector number 	     */
#define get_c1_sector(ptr) ptr[4]
#define put_c1_sector(ptr,val) ptr[4] = val
/* encoded bytes per sector  */
#define get_c1_N(ptr) ptr[5]
#define put_c1_N(ptr,val) ptr[5] = val
/* last sector on track      */
#define get_c1_EOT(ptr) ptr[6]
#define put_c1_EOT(ptr,val) ptr[6] = val
/* gap length 		     */
#define get_c1_GPL(ptr) ptr[7]
#define put_c1_GPL(ptr,val) ptr[7] = val
/* data length */
#define get_c1_DTL(ptr) ptr[8]
#define put_c1_DTL(ptr,val) ptr[8] = val

/* 
 * Class 2 - read a track
 */

/* always 1 - FM not used    */
#define get_c2_MFM(ptr) ((ptr[0] & 0x40) >> 6)
#define put_c2_MFM(ptr,val) ptr[0] = (ptr[0] & ~0x40) | ((val << 6) & 0x40)
/* skip data 		     */
#define get_c2_skip(ptr) ((ptr[0] & 0x20) >> 5)
#define put_c2_skip(ptr,val) ptr[0] = (ptr[0] & ~0x20) | ((val << 5) & 0x20)
/* the command itself 	     */
#define get_c2_cmd(ptr) (ptr[0] & 0x1f)
#define put_c2_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* padding */
/* padding */
#define get_c2_pad1(ptr) ((ptr[1] & 0xf8) >> 3)
#define put_c2_pad1(ptr,val) ptr[1] = (ptr[1] & ~0xf8) | ((val << 3) & 0xf8)
/* which head 		     */
#define get_c2_head(ptr) ((ptr[1] & 0x4) >> 2)
#define put_c2_head(ptr,val) ptr[1] = (ptr[1] & ~0x4) | ((val << 2) & 0x4)
/* drive unit */
#define get_c2_drive(ptr) (ptr[1] & 0x3)
#define put_c2_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)
/* cylinder number 	     */
#define get_c2_cyl(ptr) ptr[2]
#define put_c2_cyl(ptr,val) ptr[2] = val
/* head number - again !     */
#define get_c2_hd(ptr) ptr[3]
#define put_c2_hd(ptr,val) ptr[3] = val
/* sector number 	     */
#define get_c2_sector(ptr) ptr[4]
#define put_c2_sector(ptr,val) ptr[4] = val
/* encoded bytes per sector  */
#define get_c2_N(ptr) ptr[5]
#define put_c2_N(ptr,val) ptr[5] = val
/* last sector on track      */
#define get_c2_EOT(ptr) ptr[6]
#define put_c2_EOT(ptr,val) ptr[6] = val
/* gap length 		     */
#define get_c2_GPL(ptr) ptr[7]
#define put_c2_GPL(ptr,val) ptr[7] = val
/* data length */
#define get_c2_DTL(ptr) ptr[8]
#define put_c2_DTL(ptr,val) ptr[8] = val

/* 
 * Class 3 - format a track
 */

/* padding */
#define get_c3_pad(ptr) ((ptr[0] & 0x80) >> 7)
#define put_c3_pad(ptr,val) ptr[0] = (ptr[0] & ~0x80) | ((val << 7) & 0x80)
/* always 1 - FM not used    */
#define get_c3_MFM(ptr) ((ptr[0] & 0x40) >> 6)
#define put_c3_MFM(ptr,val) ptr[0] = (ptr[0] & ~0x40) | ((val << 6) & 0x40)
/* padding */
#define get_c3_pad1(ptr) ((ptr[0] & 0x20) >> 5)
#define put_c3_pad1(ptr,val) ptr[0] = (ptr[0] & ~0x20) | ((val << 5) & 0x20)
/* the command itself 	     */
#define get_c3_cmd(ptr) (ptr[0] & 0x1f)
#define put_c3_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* padding */
#define get_c3_pad2(ptr) ((ptr[1] & 0xf8) >> 3)
#define put_c3_pad2(ptr,val) ptr[1] = (ptr[1] & ~0xf8) | ((val << 3) & 0xf8)
/* which head 		     */
#define get_c3_head(ptr) ((ptr[1] & 0x4) >> 2)
#define put_c3_head(ptr,val) ptr[1] = (ptr[1] & ~0x4) | ((val << 2) & 0x4)
/* drive unit */
#define get_c3_drive(ptr) (ptr[1] & 0x3)
#define put_c3_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)
/* encoded bytes per sector  */
#define get_c3_N(ptr) ptr[2]
#define put_c3_N(ptr,val) ptr[2] = val
/* sectors per cylinder      */
#define get_c3_SC(ptr) ptr[3]
#define put_c3_SC(ptr,val) ptr[3] = val
/* gap length 		     */
#define get_c3_GPL(ptr) ptr[4]
#define put_c3_GPL(ptr,val) ptr[4] = val
/* filler byte		     */
#define get_c3_filler(ptr) ptr[5]
#define put_c3_filler(ptr,val) ptr[5] = val

/* 
 * Class 4 - read ID
 */

/* padding */
#define get_c4_pad(ptr) ((ptr[0] & 0x80) >> 7)
#define put_c4_pad(ptr,val) ptr[0] = (ptr[0] & ~0x80) | ((val << 7) & 0x80)
/* always 1 - FM not used    */
#define get_c4_MFM(ptr) ((ptr[0] & 0x40) >> 6)
#define put_c4_MFM(ptr,val) ptr[0] = (ptr[0] & ~0x40) | ((val << 6) & 0x40)
/* padding */
#define get_c4_pad1(ptr) ((ptr[0] & 0x20) >> 5)
#define put_c4_pad1(ptr,val) ptr[0] = (ptr[0] & ~0x20) | ((val << 5) & 0x20)
/* the command itself 	     */
#define get_c4_cmd(ptr) (ptr[0] & 0x1f)
#define put_c4_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* padding */
#define get_c4_pad2(ptr) ((ptr[1] & 0xf8) >> 3)
#define put_c4_pad2(ptr,val) ptr[1] = (ptr[1] & ~0xf8) | ((val << 3) & 0xf8)
/* which head 		     */
#define get_c4_head(ptr) ((ptr[1] & 0x4) >> 2)
#define put_c4_head(ptr,val) ptr[1] = (ptr[1] & ~0x4) | ((val << 2) & 0x4)
/* drive unit */
#define get_c4_drive(ptr) (ptr[1] & 0x3)
#define put_c4_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)

/* 
 * Class 5 - recalibrate
 */

/* padding */
#define get_c5_pad(ptr) ((ptr[0] & 0xe0) >> 5)
#define put_c5_pad(ptr,val) ptr[0] = (ptr[0] & ~0xe0) | ((val << 5) & 0xe0)
/* the command itself 	     */
#define get_c5_cmd(ptr) (ptr[0] & 0x1f)
#define put_c5_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* padding */
#define get_c5_pad1(ptr) ((ptr[1] & 0xfc) >> 2)
#define put_c5_pad1(ptr,val) ptr[1] = (ptr[1] & ~0xfc) | ((val << 2) & 0xfc)
/* drive unit */
#define get_c5_drive(ptr) (ptr[1] & 0x3)
#define put_c5_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)

/* 
 * Class 6 - specify
 */

/* the command itself 	     */
#define get_c6_cmd(ptr) (ptr[0] & 0x1f)
#define put_c6_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* step rate time	     */
#define get_c6_SRT(ptr) ((ptr[1] & 0xf0) >> 4)
#define put_c6_SRT(ptr,val) ptr[1] = (ptr[1] & ~0xf0) | ((val << 4) & 0xf0)
/* head unload time	     */
#define get_c6_HUT(ptr) (ptr[1] & 0xf)
#define put_c6_HUT(ptr,val) ptr[1] = (ptr[1] & ~0xf) | ((val << 0) & 0xf)
/* head load time	     */
#define get_c6_HLT(ptr) ((ptr[2] & 0xfe) >> 1)
#define put_c6_HLT(ptr,val) ptr[2] = (ptr[2] & ~0xfe) | ((val << 1) & 0xfe)
/* non-dma mode - not supp.  */
#define get_c6_ND(ptr) (ptr[2] & 0x1)
#define put_c6_ND(ptr,val) ptr[2] = (ptr[2] & ~0x1) | ((val << 0) & 0x1)

/* 
 * Class 7 - sense drive status
 */

/* the command itself 	     */
#define get_c7_cmd(ptr) (ptr[0] & 0x1f)
#define put_c7_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* which head 		     */
#define get_c7_head(ptr) ((ptr[1] & 0x4) >> 2)
#define put_c7_head(ptr,val) ptr[1] = (ptr[1] & ~0x4) | ((val << 2) & 0x4)
/* drive unit */
#define get_c7_drive(ptr) (ptr[1] & 0x3)
#define put_c7_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)

/* 
 * Class 8 - seek
 */

/* padding */
#define get_c8_pad(ptr) ((ptr[0] & 0xe0) >> 5)
#define put_c8_pad(ptr,val) ptr[0] = (ptr[0] & ~0xe0) | ((val << 5) & 0xe0)
/* the command itself 	     */
#define get_c8_cmd(ptr) (ptr[0] & 0x1f)
#define put_c8_cmd(ptr,val) ptr[0] = (ptr[0] & ~0x1f) | ((val << 0) & 0x1f)
/* padding */
#define get_c8_pad1(ptr) ((ptr[1] & 0xf8) >> 3)
#define put_c8_pad1(ptr,val) ptr[1] = (ptr[1] & ~0xf8) | ((val << 3) & 0xf8)
/* which head 		     */
#define get_c8_head(ptr) ((ptr[1] & 0x4) >> 2)
#define put_c8_head(ptr,val) ptr[1] = (ptr[1] & ~0x4) | ((val << 2) & 0x4)
/* drive unit */
#define get_c8_drive(ptr) (ptr[1] & 0x3)
#define put_c8_drive(ptr,val) ptr[1] = (ptr[1] & ~0x3) | ((val << 0) & 0x3)
/* new cylinder no for seek  */
#define get_c8_new_cyl(ptr) ptr[2]
#define put_c8_new_cyl(ptr,val) ptr[2] = val

/* END:   FDC COMMAND BLOCK DEFINITIONS <<<<<<<<<<<<<<<<<<<<<<<<<<< */

/* START: FDC RESULT BLOCK DEFINITIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>> */

/* 
 * Class 0 - read/write data, read/write deleted data, 
 *    	     all scans, read/format a track 
 */

/* status register 0         */
#define get_r0_ST0(ptr) ptr[0]
#define put_r0_ST0(ptr,val) ptr[0] = val
/* status register 1         */
#define get_r0_ST1(ptr) ptr[1]
#define put_r0_ST1(ptr,val) ptr[1] = val
/* status register 2         */
#define get_r0_ST2(ptr) ptr[2]
#define put_r0_ST2(ptr,val) ptr[2] = val
/* cylinder number 	     */
#define get_r0_cyl(ptr) ptr[3]
#define put_r0_cyl(ptr,val) ptr[3] = val
/* head number 		     */
#define get_r0_head(ptr) ptr[4]
#define put_r0_head(ptr,val) ptr[4] = val
/* sector number 	     */
#define get_r0_sector(ptr) ptr[5]
#define put_r0_sector(ptr,val) ptr[5] = val
/* encoded bytes per sector if N == 0  */
#define get_r0_N(ptr) ptr[6]
#define put_r0_N(ptr,val) ptr[6] = val

/*
 * Class 1 - a split up way of looking at Status registers
 * ST0 to ST2.
 */

/* Termination code  */
#define get_r1_ST0_int_code(ptr) ((ptr[0] & 0xc0) >> 6)
#define put_r1_ST0_int_code(ptr,val) ptr[0] = (ptr[0] & ~0xc0) | ((val << 6) & 0xc0)
/* End of seek cmd   */
#define get_r1_ST0_seek_end(ptr) ((ptr[0] & 0x20) >> 5)
#define put_r1_ST0_seek_end(ptr,val) ptr[0] = (ptr[0] & ~0x20) | ((val << 5) & 0x20)
/* Equipment fault   */
#define get_r1_ST0_equipment(ptr) ((ptr[0] & 0x10) >> 4)
#define put_r1_ST0_equipment(ptr,val) ptr[0] = (ptr[0] & ~0x10) | ((val << 4) & 0x10)
/* Device not ready  */
#define get_r1_ST0_not_ready(ptr) ((ptr[0] & 0x8) >> 3)
#define put_r1_ST0_not_ready(ptr,val) ptr[0] = (ptr[0] & ~0x8) | ((val << 3) & 0x8)
/* State of head     */
#define get_r1_ST0_head_address(ptr) ((ptr[0] & 0x4) >> 2)
#define put_r1_ST0_head_address(ptr,val) ptr[0] = (ptr[0] & ~0x4) | ((val << 2) & 0x4)
/* Which drive	     */
#define get_r1_ST0_unit(ptr) (ptr[0] & 0x3)
#define put_r1_ST0_unit(ptr,val) ptr[0] = (ptr[0] & ~0x3) | ((val << 0) & 0x3)
/* Access off end of cylinder 		*/
#define get_r1_ST1_end_of_cylinder(ptr) ((ptr[1] & 0x80) >> 7)
#define put_r1_ST1_end_of_cylinder(ptr,val) ptr[1] = (ptr[1] & ~0x80) | ((val << 7) & 0x80)
/* CRC error in data field/ID		*/
#define get_r1_ST1_data_error(ptr) ((ptr[1] & 0x20) >> 5)
#define put_r1_ST1_data_error(ptr,val) ptr[1] = (ptr[1] & ~0x20) | ((val << 5) & 0x20)
/* timeout of device */
#define get_r1_ST1_over_run(ptr) ((ptr[1] & 0x10) >> 4)
#define put_r1_ST1_over_run(ptr,val) ptr[1] = (ptr[1] & ~0x10) | ((val << 4) & 0x10)
/* sector not found  */
#define get_r1_ST1_no_data(ptr) ((ptr[1] & 0x4) >> 2)
#define put_r1_ST1_no_data(ptr,val) ptr[1] = (ptr[1] & ~0x4) | ((val << 2) & 0x4)
/* write protected   */
#define get_r1_ST1_write_protected(ptr) ((ptr[1] & 0x2) >> 1)
#define put_r1_ST1_write_protected(ptr,val) ptr[1] = (ptr[1] & ~0x2) | ((val << 1) & 0x2)
/* Cannot find adress mask/ID  		*/
#define get_r1_ST1_no_address_mark(ptr) (ptr[1] & 0x1)
#define put_r1_ST1_no_address_mark(ptr,val) ptr[1] = (ptr[1] & ~0x1) | ((val << 0) & 0x1)
/* Deleted data found in Read/Scan	*/
#define get_r1_ST2_control_mark(ptr) ((ptr[2] & 0x40) >> 6)
#define put_r1_ST2_control_mark(ptr,val) ptr[2] = (ptr[2] & ~0x40) | ((val << 6) & 0x40)
/* CRC error in data field		*/
#define get_r1_ST2_data_field_error(ptr) ((ptr[2] & 0x20) >> 5)
#define put_r1_ST2_data_field_error(ptr,val) ptr[2] = (ptr[2] & ~0x20) | ((val << 5) & 0x20)
/* cylinder miss-match 			*/
#define get_r1_ST2_wrong_cyclinder(ptr) ((ptr[2] & 0x10) >> 4)
#define put_r1_ST2_wrong_cyclinder(ptr,val) ptr[2] = (ptr[2] & ~0x10) | ((val << 4) & 0x10)
/* Match found in scan      		*/
#define get_r1_ST2_scan_equal_hit(ptr) ((ptr[2] & 0x8) >> 3)
#define put_r1_ST2_scan_equal_hit(ptr,val) ptr[2] = (ptr[2] & ~0x8) | ((val << 3) & 0x8)
/* Sector not found during scan command */
#define get_r1_ST2_scan_not_satisfied(ptr) ((ptr[2] & 0x4) >> 2)
#define put_r1_ST2_scan_not_satisfied(ptr,val) ptr[2] = (ptr[2] & ~0x4) | ((val << 2) & 0x4)
/* Invalid cylinder found		*/
#define get_r1_ST2_bad_cylinder(ptr) ((ptr[2] & 0x2) >> 1)
#define put_r1_ST2_bad_cylinder(ptr,val) ptr[2] = (ptr[2] & ~0x2) | ((val << 1) & 0x2)
/* Missing Address mark			*/
#define get_r1_ST2_no_address_mark(ptr) (ptr[2] & 0x1)
#define put_r1_ST2_no_address_mark(ptr,val) ptr[2] = (ptr[2] & ~0x1) | ((val << 0) & 0x1)

/* 
 * Class 2 - sense drive status
 */

/* Device fault      		*/
#define get_r2_ST3_fault(ptr) ((ptr[0] & 0x80) >> 7)
#define put_r2_ST3_fault(ptr,val) ptr[0] = (ptr[0] & ~0x80) | ((val << 7) & 0x80)
/* Write protected diskette	*/
#define get_r2_ST3_write_protected(ptr) ((ptr[0] & 0x40) >> 6)
#define put_r2_ST3_write_protected(ptr,val) ptr[0] = (ptr[0] & ~0x40) | ((val << 6) & 0x40)
/* Device is ready		*/
#define get_r2_ST3_ready(ptr) ((ptr[0] & 0x20) >> 5)
#define put_r2_ST3_ready(ptr,val) ptr[0] = (ptr[0] & ~0x20) | ((val << 5) & 0x20)
/* Track zero found		*/
#define get_r2_ST3_track_0(ptr) ((ptr[0] & 0x10) >> 4)
#define put_r2_ST3_track_0(ptr,val) ptr[0] = (ptr[0] & ~0x10) | ((val << 4) & 0x10)
/* Double sided diskette	*/
#define get_r2_ST3_two_sided(ptr) ((ptr[0] & 0x8) >> 3)
#define put_r2_ST3_two_sided(ptr,val) ptr[0] = (ptr[0] & ~0x8) | ((val << 3) & 0x8)
/* Side address signal		*/
#define get_r2_ST3_head_address(ptr) ((ptr[0] & 0x4) >> 2)
#define put_r2_ST3_head_address(ptr,val) ptr[0] = (ptr[0] & ~0x4) | ((val << 2) & 0x4)
/* Which unit is selected	*/
#define get_r2_ST3_unit(ptr) (ptr[0] & 0x3)
#define put_r2_ST3_unit(ptr,val) ptr[0] = (ptr[0] & ~0x3) | ((val << 0) & 0x3)

/* 
 * Class 3 - sense interrupt status
 */

/* status register 0         */
#define get_r3_ST0(ptr) ptr[0]
#define put_r3_ST0(ptr,val) ptr[0] = val
/* present cylinder number   */
#define get_r3_PCN(ptr) ptr[1]
#define put_r3_PCN(ptr,val) ptr[1] = val

/* 
 * Class 4 - invalid codes
 */

/* status register 0         */
#define get_r4_ST0(ptr) ptr[0]
#define put_r4_ST0(ptr,val) ptr[0] = val

/* END:   FDC RESULT BLOCK DEFINITIONS <<<<<<<<<<<<<<<<<<<<<<<<<<<< */


/*
 * An entry data structure that holds information describing the number of bytes
 * in the fdc command/result phases. The index is the fdc command code, see
 * the INTEL Application note on the 8272A for a full description.  
 *
 * The "result_byte" is the number of bytes in the standard FDC result phase 
 * while "gfi_result_byte" is the number of bytes in the pseudo result phase
 * used by GFI and its server modules (ie some commands that do not normally
 * have a result phase, use an implicit Sense Interrupt Status result phase).
 */

typedef struct {
		 half_word cmd_bytes;		/* number of command bytes */
		 half_word result_bytes;	/* number of result bytes  */
		 half_word gfi_result_bytes;	/* number of GFI result bytes  */
		 half_word cmd_class;		/* class of the command    */
		 half_word result_class;	/* class of the result     */
		 boolean   dma_required;	/* dma required ?	   */
		 boolean   int_required;	/* interrupts required ?   */
	       } FDC_DATA_ENTRY;


/*
 * The following list the error codes that the GFI commands (see gfi.f) can
 * return.  0 is considered to be success.
 */

#define GFI_PROTOCOL_ERROR	1
#define GFI_FDC_TIMEOUT		2
#define GFI_FDC_LOGICAL_ERROR	3

/*
 * GFI Drive types
 */

#define GFI_DRIVE_TYPE_NULL		0	/* unidentified */
#define GFI_DRIVE_TYPE_360		1	/* 360K 5.25" */
#define GFI_DRIVE_TYPE_12		2	/* 1.2M 5.25" */
#define GFI_DRIVE_TYPE_720		3	/* 720K 3.5" */
#define GFI_DRIVE_TYPE_144		4	/* 1.44M 3.5" */
#define	GFI_DRIVE_TYPE_288		5	/* 2.88M 3.5" */

#ifdef NTVDM
#define GFI_DRIVE_TYPE_MAX              6
#endif


/***************************************************************************
**
**      Definitions and prototypes for the gfi_function_table, 
**  the functions therein, and the orthogonal floppy interface functions.
**  Using the typedef'd prototypes should make it much easier to avoid
**  definition clashes. 
**	This is now the only base floppy header file, and if you use the
**  generic unix_flop.c module, the only floppy header anywhere. The generic
**  code is meant to help a new unix port get quick floppy support; it is
**  not meant to replace fancy host floppy code.
**	The improvements that I have made to the floppy system in general are
**  also supposed to make life easier.
**
**      GM.
****************************************************************************
**
**
**
** The GFI has a structure containing pointers to functions that provide
** the diskette support for all possible drives (0-1) and drive types.
**  Each floppy emmulator module has a function for loading this table 
** with the module's own local functions which can then be used by the 
** gfi system to emmulate the sort of device the module was designed for.
**
** 	This table (of two structures - one for each possible drive)
**  is of course GLOBAL.
**
** The structure has the following fields:
**
** The GFI command function:		GFI_FUNC_ENTRY.command_fn,
** The GFI drive on function:		GFI_FUNC_ENTRY.drive_on_fn,
** The GFI drive off function:		GFI_FUNC_ENTRY.drive_off_fn,
** The GFI reset function:		GFI_FUNC_ENTRY.reset_fn,
** The GFI set high density function:	GFI_FUNC_ENTRY.high_fn,
** The GFI drive type function:		GFI_FUNC_ENTRY.drive_type_fn,
** The GFI disk changed function:	GFI_FUNC_ENTRY.change_fn
**
**   Structure definition:
**  -----------------------
*/
typedef struct
{
	SHORT (*command_fn) IPT2( FDC_CMD_BLOCK *, ip, FDC_RESULT_BLOCK *, res );
	SHORT (*drive_on_fn) IPT1( UTINY, drive );
	SHORT (*drive_off_fn) IPT1( UTINY, drive );
	SHORT (*reset_fn) IPT2( FDC_RESULT_BLOCK *, res, UTINY, drive );
	SHORT (*high_fn) IPT2( UTINY, drive, half_word, n);
	SHORT (*drive_type_fn) IPT1( UTINY, drive );
	SHORT (*change_fn) IPT1( UTINY, drive );

} GFI_FUNCTION_ENTRY;

/*
** ============================================================================
** External declarations and macros
** ============================================================================
**
**
**
** The data structure describing the fdc command/result phases, and the
** function pointer table set up by calls to the individual init functions
** in each of the GFI server modules.
**
**
**
** 	These tables are in gfi.c
*/
	IMPORT GFI_FUNCTION_ENTRY gfi_function_table[];
	IMPORT FDC_DATA_ENTRY     gfi_fdc_description[];
/*
**	The following functions form the interface between the GFI system
**  and the floppy module (whichever). They are global, but the only access
**  to the other functions gfi needs is via the gfi_function_table.
*/

IMPORT SHORT host_gfi_rdiskette_valid  
	IPT3(UTINY,hostID,ConfigValues *,vals,CHAR *,err);

IMPORT SHORT host_gfi_rdiskette_active 
	IPT3(UTINY, hostID, BOOL, active, CHAR, *err);

IMPORT SHORT gfi_empty_active 
	IPT3(UTINY, hostID, BOOL, active, CHAR, *err);

IMPORT VOID  host_gfi_rdiskette_change 
	IPT2(UTINY, hostID, BOOL, apply);

#ifndef host_rflop_drive_type
/* new function to say what kind of drive we have 
*/
IMPORT SHORT host_rflop_drive_type IPT2 (INT, fd, CHAR *, name);
#endif /* host_rflop_drive_type */

/*  The gfi global functions. These need to be global because they are the 
** interface to the private host dependant floppy functions. Each one does
** little more than call the real function via the table.
*/
/* The gfi_reset is special; not the same as the other floppy inits because
** it is called from main() to startup the gfi system by making both drives
** 'empty'. This means that it has no drive parameter.
*/

IMPORT SHORT gfi_drive_on IPT1( UTINY, drive );
IMPORT SHORT gfi_drive_off IPT1( UTINY, drive );
IMPORT SHORT gfi_low IPT1( UTINY, drive );
IMPORT SHORT gfi_drive_type IPT1( UTINY, drive );
IMPORT SHORT gfi_change IPT1( UTINY, drive );
IMPORT VOID gfi_init IPT0();  
IMPORT SHORT gfi_reset IPT2( FDC_RESULT_BLOCK *, res, UTINY, drive );
IMPORT SHORT gfi_high IPT2( UTINY, drive, half_word, n);
IMPORT SHORT gfi_fdc_command IPT2( FDC_CMD_BLOCK *, ip, FDC_RESULT_BLOCK *, res );
