;
;=============================================================================
;   IDE DISK DRIVER
;=============================================================================
;
; TODO:
; - GOPARTNER NEEDS TO HANDLE "NO PARTNER" CONDITION
; - IMPLEMENT H/W PROBES FOR DIO AND DIDE
; - DATA TRANSFERS LIMITED TO 512 BYTES WHICH IS INSUFFICIENT FOR CD=ROM MEDIA
;
; NOTES:
;  - WELL KNOWN IDE PORT ADDRESSES:
;	BOARD	BASE	DATLO	DATHI
;	------	------	------	------
;	DIO	$20	$20	$28
;	DIDE-A	$20	$28	$28
;	DIDE-B	$30	$38	$38
;	MK4	$80	N/A	N/A
;	RC	$10	N/A	N/A
;	SMB	$E0	N/A	N/A
;	GIDE	$20	$20	$28  - Genesis IDE controller - Note Read Hi Low - Write - Low High   
;
;	+-----------------------------------------------------------------------+
;	| CONTROL BLOCK REGISTERS						|
;	+-----------------------+-------+-------+-------------------------------+
;	| REGISTER		| PORT	| DIR	| DESCRIPTION			|
;	+-----------------------+-------+-------+-------------------------------+
;	| IDE_REG_ALTSTAT	| 0x0E	| R	| ALTERNATE STATUS REGISTER	|
;	| IDE_REG_CTRL		| 0x0E	| W	| DEVICE CONTROL REGISTER	|
;	| IDE_REG_DRVADR		| 0x0F	| R	| DRIVE ADDRESS REGISTER|
;	+-----------------------+-------+-------+-------------------------------+
;
;	+-----------------------+-------+-------+-------------------------------+
;	| COMMAND BLOCK REGISTERS						|
;	+-----------------------+-------+-------+-------------------------------+
;	| REGISTER		| PORT	| DIR	| DESCRIPTION			|
;	+-----------------------+-------+-------+-------------------------------+
;	| IDE_REG_DATA		| 0x00	| R/W	| DATA INPUT/OUTPUT		|
;	| IDE_REG_ERR		| 0x01	| R	| ERROR REGISTER		|
;	| IDE_REG_FEAT		| 0x01	| W	| FEATURES REGISTER		|
;	| IDE_REG_COUNT		| 0x02	| R/W	| SECTOR COUNT REGISTER		|
;	| IDE_REG_SECT		| 0x03	| R/W	| SECTOR NUMBER REGISTER	|
;	| IDE_REG_CYLLO		| 0x04	| R/W	| CYLINDER NUM REGISTER (LSB)	|
;	| IDE_REG_CYLHI		| 0x05	| R/W	| CYLINDER NUM REGISTER (MSB)	|
;	| IDE_REG_DRVHD		| 0x06	| R/W	| DRIVE/HEAD REGISTER		|
;	| IDE_REG_LBA0*		| 0x03	| R/W	| LBA BYTE 0 (BITS 0-7)		|
;	| IDE_REG_LBA1*		| 0x04	| R/W	| LBA BYTE 1 (BITS 8-15)	|
;	| IDE_REG_LBA2*		| 0x05	| R/W	| LBA BYTE 2 (BITS 16-23)	|
;	| IDE_REG_LBA3*		| 0x06	| R/W	| LBA BYTE 3 (BITS 24-27)	|
;	| IDE_REG_STAT		| 0x07	| R	| STATUS REGISTER		|
;	| IDE_REG_CMD		| 0x07	| W	| COMMAND REGISTER (EXECUTE)	|
;	+-----------------------+-------+-------+-------------------------------+
;	* LBA0-3 ARE ALTERNATE DEFINITIONS OF SECT, CYL, AND DRVHD PORTS
;
;	=== STATUS REGISTER ===
;
;	    7	    6	    5	    4	    3	    2	    1	    0
;	+-------+-------+-------+-------+-------+-------+-------+-------+
;	|  BSY	| DRDY	|  DWF	|  DSC	|  DRQ	| CORR	|  IDX	|  ERR	|
;	+-------+-------+-------+-------+-------+-------+-------+-------+
;
;	BSY:	BUSY
;	DRDY:	DRIVE READY
;	DWF:	DRIVE WRITE FAULT
;	DSC:	DRIVE SEEK COMPLETE
;	DRQ:	DATA REQUEST
;	CORR:	CORRECTED DATA
;	IDX:	INDEX
;	ERR:	ERROR
;
;	=== ERROR REGISTER ===
;
;	    7	    6	    5	    4	    3	    2	    1	    0
;	+-------+-------+-------+-------+-------+-------+-------+-------+
;	| BBK	|  UNC	|  MC	|  IDNF |  MCR	| ABRT	| TK0NF |  AMNF |
;	+-------+-------+-------+-------+-------+-------+-------+-------+
;	(VALID WHEN ERR BIT IS SET IN STATUS REGISTER)
;
;	BBK:	BAD BLOCK DETECTED
;	UNC:	UNCORRECTABLE DATA ERROR
;	MC:	MEDIA CHANGED
;	IDNF:	ID NOT FOUND
;	MCR:	MEDIA CHANGE REQUESTED
;	ABRT:	ABORTED COMMAND
;	TK0NF:	TRACK 0 NOT FOUND
;	AMNF:	ADDRESS MARK NOT FOUND
;
;	=== DRIVE/HEAD / LBA3 REGISTER ===
;
;	    7	    6	    5	    4	    3	    2	    1	    0
;	+-------+-------+-------+-------+-------+-------+-------+-------+
;	|   1	|   L	|   1	|  DRV	|  HS3	|  HS2	|  HS1	|  HS0	|
;	+-------+-------+-------+-------+-------+-------+-------+-------+
;
;	L:	0 = CHS ADDRESSING, 1 = LBA ADDRESSING
;	DRV:	0 = DRIVE 0 (PRIMARY) SELECTED, 1 = DRIVE 1 (SLAVE) SELECTED
;	HS:	CHS = HEAD ADDRESS (0-15), LBA = BITS 24-27 OF LBA
;
;	=== DEVICE CONTROL REGISTER ===
;
;	    7	    6	    5	    4	    3	    2	    1	    0
;	+-------+-------+-------+-------+-------+-------+-------+-------+
;	|   X	|   X	|   X	|   X	|   1	| SRST	|  ~IEN |   0	|
;	+-------+-------+-------+-------+-------+-------+-------+-------+
;
;	SRST:	SOFTWARE RESET
;	~IEN:	INTERRUPT ENABLE
;
IDE_REG_DATA		.EQU	$00	; DATA 	/OUTPUT (R/W)
IDE_REG_ERR		.EQU	$01	; ERROR REGISTER (R)
IDE_REG_FEAT		.EQU	$01	; FEATURES REGISTER (W)
IDE_REG_COUNT		.EQU	$02	; SECTOR COUNT REGISTER (R/W)
IDE_REG_SECT		.EQU	$03	; SECTOR NUMBER REGISTER (R/W)
IDE_REG_CYLLO		.EQU	$04	; CYLINDER NUM REGISTER (LSB) (R/W)
IDE_REG_CYLHI		.EQU	$05	; CYLINDER NUM REGISTER (MSB) (R/W)
IDE_REG_DRVHD		.EQU	$06	; DRIVE/HEAD REGISTER (R/W)
IDE_REG_LBA0		.EQU	$03	; LBA BYTE 0 (BITS 0-7) (R/W)
IDE_REG_LBA1		.EQU	$04	; LBA BYTE 1 (BITS 8-15) (R/W)
IDE_REG_LBA2		.EQU	$05	; LBA BYTE 2 (BITS 16-23) (R/W)
IDE_REG_LBA3		.EQU	$06	; LBA BYTE 3 (BITS 24-27) (R/W)
IDE_REG_BCL		.EQU	$04	; PKT BYTE COUNT LOW (BITS 0-7) (R/W)
IDE_REG_BCH		.EQU	$05	; PKT BYTE COUNT HIGH (BITS 8-15) (R/W)
IDE_REG_STAT		.EQU	$07	; STATUS REGISTER (R)
IDE_REG_CMD		.EQU	$07	; COMMAND REGISTER (EXECUTE) (W)
IDE_REG_XAR		.EQU	$08	; ECB DIDE EXTERNAL ADDRESS REGISTER (W)
IDE_REG_ALTSTAT		.EQU	$0E	; ALTERNATE STATUS REGISTER (R)
IDE_REG_CTRL		.EQU	$0E	; DEVICE CONTROL REGISTER (W)
IDE_REG_DRVADR		.EQU	$0F	; DRIVE ADDRESS REGISTER (R)
;
; COMMAND BYTES
;
IDE_CMD_NOP		.EQU	$00
IDE_CMD_DEVRES		.EQU	$08
IDE_CMD_RECAL		.EQU	$10
IDE_CMD_READ		.EQU	$20
IDE_CMD_WRITE		.EQU	$30
IDE_CMD_DEVDIAG		.EQU	$90
IDE_CMD_PACKET		.EQU	$A0
IDE_CMD_IDPKTDEV	.EQU	$A1
IDE_CMD_IDDEV		.EQU	$EC
IDE_CMD_SETFEAT		.EQU	$EF
;
; FEATURE BYTES
;
IDE_FEAT_ENABLE8BIT	.EQU	$01
IDE_FEAT_DISABLE8BIT	.EQU	$81
;
; IDE DEVICE TYPES
;
IDE_TYPEUNK	.EQU	0
IDE_TYPEATA	.EQU	1
IDE_TYPEATAPI	.EQU	2
;
; IDE DEVICE STATUS CODES
;
IDE_STOK	.EQU	0
IDE_STINVUNIT	.EQU	-1
IDE_STNOMEDIA	.EQU	-2
IDE_STCMDERR	.EQU	-3
IDE_STIOERR	.EQU	-4
IDE_STRDYTO	.EQU	-5
IDE_STDRQTO	.EQU	-6
IDE_STBSYTO	.EQU	-7
IDE_STNOTSUP	.EQU	-8
IDE_STNOTRDY	.EQU	-9
;
; DRIVE SELECTION BYTES (FOR USE IN DRIVE/HEAD REGISTER)
;
;IDE_DRVSEL:
IDE_DRVMASTER	.EQU	%11100000	; LBA, MASTER DEVICE
IDE_DRVSLAVE	.EQU	%11110000	; LBA, SLAVE DEVICE
;
; IDE DEVICE CONFIGURATION
;
IDE_CFGSIZ	.EQU	19		; SIZE OF CFG TBL ENTRIES
;
; PER DEVICE DATA OFFSETS
;
IDE_DEV		.EQU	0		; OFFSET OF DEVICE NUMBER (BYTE)
IDE_MODE	.EQU	1		; OPERATION MODE: IDE MODE (BYTE)
IDE_STAT	.EQU	2		; LAST STATUS (BYTE)
IDE_TYPE	.EQU	3		; DEVICE TYPE (BYTE)
IDE_ACC		.EQU	4		; ACCESS FLAG BITS BIT 0=MASTER, 1=8BIT (BYTE)
IDE_MED		.EQU	5		; MEDIA FLAG BITS BIT 0=CF, 1=LBA (BYTE)
IDE_MEDCAP	.EQU	6		; MEDIA CAPACITY (DWORD)
IDE_LBA		.EQU	10		; OFFSET OF LBA (DWORD)
IDE_IOBASE	.EQU	14		; IO BASE ADDRESS (BYTE)
IDE_DATALO	.EQU	15		; 16 BIT DATA LO BYTE
IDE_DATAHI	.EQU	16		; 16 BIT DATA HI BYTE
IDE_PARTNER	.EQU	17		; PARTNER DEVICE (MASTER <-> SLAVE) (WORD)
;
IDE_ACC_MAS	.EQU	%00000001	; UNIT IS MASTER (ELSE SLAVE)
IDE_ACC_8BIT	.EQU	%00000010	; UNIT WANTS 8 BIT I/O (ELSE 16 BIT)
;
IDE_MED_CF	.EQU	%00000001	; MEDIA IS CF CARD
IDE_MED_LBA	.EQU	%00000010	; MEDIA HAS LBA CAPABILITY
;
IDE_DEVCNT	.EQU	IDECNT * 2
;
IDE_CFGTBL:
;
#IF (IDECNT >= 1)
;
IDE_DEV0M:	; DEVICE 0, MASTER
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	IDE0MODE		; DRIVER DEVICE MODE
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	IDE_ACC_MAS | (IDE0A8BIT & IDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	IDE0BASE		; IO BASE ADDRESS
	.DB	IDE0DATLO		; IO BASE ADDRESS
	.DB	IDE0DATHI		; IO BASE ADDRESS
	.DW	IDE_DEV0S		; PARTNER
;
	DEVECHO	"IDE: MODE="
  #IF (IDE0MODE == IDEMODE_NONE)
	DEVECHO	"NONE"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_DIO)
	DEVECHO	"DIO"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_DIDE)
	DEVECHO	"DIDE"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_GIDE)
	DEVECHO	"GIDE"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_MK4)
	DEVECHO	"MK4"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_RC)
	DEVECHO	"RC"
  #ENDIF
	DEVECHO	", IO="
	DEVECHO	IDE0BASE
	DEVECHO	", MASTER"
	DEVECHO	"\n"
;
IDE_DEV0S:	; DEVICE 0, SLAVE
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	IDE0MODE		; DRIVER DEVICE MODE
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	(IDE0B8BIT & IDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	IDE0BASE		; IO BASE ADDRESS
	.DB	IDE0DATLO		; IO BASE ADDRESS
	.DB	IDE0DATHI		; IO BASE ADDRESS
	.DW	IDE_DEV0M		; PARTNER
;
	DEVECHO	"IDE: MODE="
  #IF (IDE0MODE == IDEMODE_NONE)
	DEVECHO	"NONE"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_DIO)
	DEVECHO	"DIO"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_DIDE)
	DEVECHO	"DIDE"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_GIDE)
	DEVECHO	"GIDE"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_MK4)
	DEVECHO	"MK4"
  #ENDIF
  #IF (IDE0MODE == IDEMODE_RC)
	DEVECHO	"RC"
  #ENDIF
	DEVECHO	", IO="
	DEVECHO	IDE0BASE
	DEVECHO	", SLAVE"
	DEVECHO	"\n"
#ENDIF
;
#IF (IDECNT >= 2)
;
IDE_DEV1M:	; DEVICE 1, MASTER
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	IDE1MODE		; DRIVER DEVICE MODE
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	IDE_ACC_MAS | (IDE1A8BIT & IDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	IDE1BASE		; IO BASE ADDRESS
	.DB	IDE1DATLO		; IO BASE ADDRESS
	.DB	IDE1DATHI		; IO BASE ADDRESS
	.DW	IDE_DEV1S		; PARTNER
;
	DEVECHO	"IDE: MODE="
  #IF (IDE1MODE == IDEMODE_NONE)
	DEVECHO	"NONE"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_DIO)
	DEVECHO	"DIO"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_DIDE)
	DEVECHO	"DIDE"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_GIDE)
	DEVECHO	"GIDE"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_MK4)
	DEVECHO	"MK4"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_RC)
	DEVECHO	"RC"
  #ENDIF
	DEVECHO	", IO="
	DEVECHO	IDE1BASE
	DEVECHO	", MASTER"
	DEVECHO	"\n"
;
IDE_DEV1S:	; DEVICE 1, SLAVE
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	IDE1MODE		; DRIVER DEVICE MODE
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	(IDE1B8BIT & IDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	IDE1BASE		; IO BASE ADDRESS
	.DB	IDE1DATLO		; IO BASE ADDRESS
	.DB	IDE1DATHI		; IO BASE ADDRESS
	.DW	IDE_DEV1M		; PARTNER
;
	DEVECHO	"IDE: MODE="
  #IF (IDE1MODE == IDEMODE_NONE)
	DEVECHO	"NONE"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_DIO)
	DEVECHO	"DIO"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_DIDE)
	DEVECHO	"DIDE"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_GIDE)
	DEVECHO	"GIDE"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_MK4)
	DEVECHO	"MK4"
  #ENDIF
  #IF (IDE1MODE == IDEMODE_RC)
	DEVECHO	"RC"
  #ENDIF
	DEVECHO	", IO="
	DEVECHO	IDE1BASE
	DEVECHO	", SLAVE"
	DEVECHO	"\n"
#ENDIF
;
#IF (IDECNT >= 3)
;
IDE_DEV2M:	; DEVICE 2, MASTER
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	IDE2MODE		; DRIVER DEVICE MODE
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	IDE_ACC_MAS | (IDE2A8BIT & IDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	IDE2BASE		; IO BASE ADDRESS
	.DB	IDE2DATLO		; IO BASE ADDRESS
	.DB	IDE2DATHI		; IO BASE ADDRESS
	.DW	IDE_DEV2S		; PARTNER
;
	DEVECHO	"IDE: MODE="
  #IF (IDE2MODE == IDEMODE_NONE)
	DEVECHO	"NONE"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_DIO)
	DEVECHO	"DIO"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_DIDE)
	DEVECHO	"DIDE"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_GIDE)
	DEVECHO	"GIDE"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_MK4)
	DEVECHO	"MK4"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_RC)
	DEVECHO	"RC"
  #ENDIF
	DEVECHO	", IO="
	DEVECHO	IDE2BASE
	DEVECHO	", MASTER"
	DEVECHO	"\n"
;
IDE_DEV2S:	; DEVICE 2, SLAVE
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	IDE2MODE		; DRIVER DEVICE MODE
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	(IDE2B8BIT & IDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	IDE2BASE		; IO BASE ADDRESS
	.DB	IDE2DATLO		; IO BASE ADDRESS
	.DB	IDE2DATHI		; IO BASE ADDRESS
	.DW	IDE_DEV1M		; PARTNER
;
	DEVECHO	"IDE: MODE="
  #IF (IDE2MODE == IDEMODE_NONE)
	DEVECHO	"NONE"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_DIO)
	DEVECHO	"DIO"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_DIDE)
	DEVECHO	"DIDE"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_GIDE)
	DEVECHO	"GIDE"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_MK4)
	DEVECHO	"MK4"
  #ENDIF
  #IF (IDE2MODE == IDEMODE_RC)
	DEVECHO	"RC"
  #ENDIF
	DEVECHO	", IO="
	DEVECHO	IDE2BASE
	DEVECHO	", SLAVE"
	DEVECHO	"\n"
#ENDIF
;
#IF ($ - IDE_CFGTBL) != (IDE_DEVCNT * IDE_CFGSIZ)
	.ECHO	"*** INVALID IDE CONFIG TABLE ***\n"
#ENDIF
;
	.DB	$FF			; END OF TABLE MARKER
;
; THE IDE_WAITXXX FUNCTIONS ARE BUILT TO TIMEOUT AS NEEDED SO DRIVER WILL
; NOT HANG IF DEVICE IS UNRESPONSIVE.  DIFFERENT TIMEOUTS ARE USED DEPENDING
; ON THE SITUATION.  THE SLOW TIMEOUT IS USED TO WAIT FOR A DEVICE TO
; BECOME READY AFTER A HARD RESET (SPIN UP, ETC.).  THE NORMAL TIMEOUT
; IS USED DURING NORMAL OPERATION FOR ALL I/O OPERATIONS WHICH SHOULD
; OCCUR PRETTY FAST.  NOTE THAT THE ATA SPEC ALLOWS UP TO 30 SECONDS
; FOR DEVICES TO RESPOND.  WE ARE USING MUCH MORE AGGRESSIVE VALUES
; BASED ON REAL WORLD EXPERIENCE.
; THE PICO TIMEOUT (TOPICO) IS A SPECIAL TIMEOUT FOR THE RC2014 SD
; PICO TO WAIT FOR THE PICO DEVICE TO INITIALIZE.
;
IDE_TOSLOW	.EQU	200		; SLOW TIMEOUT IS 20 SECS
;IDE_TONORM	.EQU	5		; NORMAL TIMEOUT IS 0.5 SECS
IDE_TONORM	.EQU	200		; NORMAL TIMEOUT IS 0.5 SECS
IDE_TOPICO	.EQU	50		; RC2014 SD PICO (5 SECONDS)
;
;=============================================================================
; INITIALIZATION ENTRY POINT
;=============================================================================
;
IDE_INIT:
	; COMPUTE CPU SPEED COMPENSATED TIMEOUT SCALER
	; ONE INTERNAL LOOP IN WAITBSY IS 180TS.  ON A 1 MHZ CPU, 1 TS
	; TAKES 1NS.  SO 1/10 SECOND IS 100000 TS ON A 1 MHZ CPU.
	; SINCE 1 INTERNAL LOOP IS 180 TS, IT TAKES 100000 / 180 = 556
	; INTERNAL LOOPS FOR 1/10 SECOND.  SO, WE WANT TO USE
	; 523 * CPU MHZ FOR INTERNAL LOOP COUNT.
	LD	DE,556			; LOAD SCALER FOR 1MHZ
	LD	A,(CB_CPUMHZ)		; LOAD CPU SPEED IN MHZ
	CALL	MULT8X16		; HL := DE * A
	LD	(IDE_TOSCALER),HL	; SAVE IT
;
	XOR	A			; ZERO ACCUM
	LD	(IDE_DEVNUM),A		; INIT DEV UNIT NUM FOR DYNAMIC ASSIGNMENT
	LD	IY,IDE_CFGTBL		; POINT TO START OF CONFIG TABLE
;
IDE_INIT1:
	LD	A,(IY)			; LOAD FIRST BYTE TO CHECK FOR END
	CP	$FF			; CHECK FOR END OF TABLE VALUE
	JR	NZ,IDE_INIT2		; IF NOT END OF TABLE, CONTINUE
	XOR	A			; SIGNAL SUCCESS
	RET				; AND RETURN
;
IDE_INIT2:
	BIT	0,(IY+IDE_ACC)		; MASTER?
	JR	Z,IDE_INIT4		; IF NOT MASTER, SKIP AHEAD
;
	CALL	NEWLINE			; FORMATTING
	PRTS("IDE:$")			; LABEL FOR IO ADDRESS
;
	PRTS(" IO=0x$")			; LABEL FOR IO ADDRESS
	LD	A,(IY+IDE_IOBASE)	; GET IO BASE ADDRES
	CALL	PRTHEXBYTE		; DISPLAY IT
;
	PRTS(" MODE=$")			; LABEL FOR MODE
	LD	A,(IY+IDE_MODE)		; GET MODE BITS
	LD	DE,IDE_STR_MODE_DIO	; MODE LABEL
	CP	IDEMODE_DIO		; TEST FOR MODE
	JR	Z,IDE_INIT2A		; IF SO, DISPLAY IT
	LD	DE,IDE_STR_MODE_DIDE	; MODE LABEL
	CP	IDEMODE_DIDE		; TEST FOR MODE
	JR	Z,IDE_INIT2A		; IF SO, DISPLAY IT
	LD	DE,IDE_STR_MODE_MK4	; MODE LABEL
	CP	IDEMODE_MK4		; TEST FOR MODE
	JR	Z,IDE_INIT2A		; IF SO, DISPLAY IT
	LD	DE,IDE_STR_MODE_RC	; MODE LABEL
	CP	IDEMODE_RC		; TEST FOR MODE
	JR	Z,IDE_INIT2A		; IF SO, DISPLAY IT
	LD	DE,IDE_STR_MODE_GIDE	; MODE LABEL
	CP	IDEMODE_GIDE		; TEST FOR MODE
	JR	Z,IDE_INIT2A		; IF SO, DISPLAY IT
	JR	IDE_INIT4		; NO MODE?  BYPASS ENTRY
IDE_INIT2A:
	CALL	WRITESTR		; DISPLAY MODE
;
	CALL	IDE_DETECT		; PROBE FOR INTERFACE
	JR	Z,IDE_INIT3		; GOT IT, MOVE ON TO INIT UNITS
	CALL	PC_SPACE		; FORMATTING
	LD	DE,IDE_STR_NOHW		; NOT PRESENT MESSAGE
	CALL	WRITESTR		; DISPLAY IT
	JR	IDE_INIT4		; SKIP CFG ENTRY
;
IDE_INIT3:
	CALL	IDE_RESET		; RESET THE BUS
	CALL	IDE_INIT5		; DETECT/INIT MASTER
	PUSH	IY			; SAVE CFG PTR
	CALL	IDE_GOPARTNER		; SWITCH IY TO PARTNER CFG
	CALL	IDE_INIT5		; DETECT/INIT SLAVE
	POP	IY			; RESTORE CFG PTR
;
IDE_INIT4:
	LD	DE,IDE_CFGSIZ		; SIZE OF CFG TABLE ENTRY
	ADD	IY,DE			; BUMP POINTER
	JP	IDE_INIT1		; AND LOOP
;
IDE_INIT5:
	; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
	LD	A,(IDE_DEVNUM)		; GET NEXT UNIT NUM TO ASSIGN
	LD	(IY+IDE_DEV),A		; UPDATE IT
	INC	A			; BUMP TO NEXT UNIT NUM TO ASSIGN
	LD	(IDE_DEVNUM),A		; SAVE IT
;
	; ADD UNIT TO GLOBAL DISK UNIT TABLE
	LD	BC,IDE_FNTBL		; BC := FUNC TABLE ADR
	PUSH	IY			; CFG ENTRY POINTER
	POP	DE			; COPY TO DE
	CALL	DIO_ADDENT		; ADD ENTRY TO GLOBAL DISK DEV TABLE
;
	; START PRINTING DEVICE INFO
	CALL	IDE_PRTPREFIX		; PRINT DEVICE PREFIX
	LD	A,(IY+IDE_TYPE)
	LD	DE,IDE_STR_TYPEATA
	CP	IDE_TYPEATA
	CALL	Z,WRITESTR
	LD	DE,IDE_STR_TYPEATAPI
	CP	IDE_TYPEATAPI
	CALL	Z,WRITESTR
;
	; CHECK FOR BAD STATUS
	LD	A,(IY+IDE_STAT)		; GET STATUS
	OR	A			; SET FLAGS
	JP	Z,IDE_INIT6
	CALL	PC_SPACE
	JP	NZ,IDE_PRTSTATSTR	; EXIT VIA PRINT STATUS STRING
;
IDE_INIT6:
	LD	DE,IDE_STR_8BIT
	BIT	1,(IY+IDE_ACC)		; 8 BIT ACCESS?
	CALL	NZ,WRITESTR
;
	; PRINT LBA/NOLBA
	CALL	PC_SPACE		; FORMATTING
	BIT	1,(IY+IDE_MED)		; TEST LBA FLAG
	LD	DE,IDE_STR_NO		; POINT TO "NO" STRING
	CALL	Z,WRITESTR		; PRINT "NO" BEFORE "LBA" IF LBA NOT SUPPORTED
	PRTS("LBA$")			; PRINT "LBA" REGARDLESS
;
	; PRINT STORAGE CAPACITY (BLOCK COUNT)
	PRTS(" BLOCKS=0x$")		; PRINT FIELD LABEL
	LD	A,IDE_MEDCAP		; OFFSET TO CAPACITY FIELD
	CALL	LDHLIYA			; HL := IY + A, REG A TRASHED
	CALL	LD32			; GET THE CAPACITY VALUE
	CALL	PRTHEX32		; PRINT HEX VALUE
;
	; PRINT STORAGE SIZE IN MB
	PRTS(" SIZE=$")			; PRINT FIELD LABEL
	LD	B,11			; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
	CALL	SRL32			; RIGHT SHIFT
	;CALL	PRTDEC			; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED)
	CALL	PRTDEC32		; PRINT DWORD IN DECIMAL
	PRTS("MB$")			; PRINT SUFFIX
;
	RET
;
;----------------------------------------------------------------------
; PROBE FOR IDE HARDWARE
;----------------------------------------------------------------------
;
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
;
IDE_DETECT:
;
;#IF (IDEMODE == IDEMODE_DIDE)
;#ENDIF
;;
;#IF (IDEMODE == IDEMODE_DIO)
;#ENDIF
;
	XOR	A			; SIGNAL SUCCESS
	RET				; AND RETURN
;
;=============================================================================
; DRIVER FUNCTION TABLE
;=============================================================================
;
IDE_FNTBL:
	.DW	IDE_STATUS
	.DW	IDE_RESET
	.DW	IDE_SEEK
	.DW	IDE_READ
	.DW	IDE_WRITE
	.DW	IDE_VERIFY
	.DW	IDE_FORMAT
	.DW	IDE_DEVICE
	.DW	IDE_MEDIA
	.DW	IDE_DEFMED
	.DW	IDE_CAP
	.DW	IDE_GEOM
#IF (($ - IDE_FNTBL) != (DIO_FNCNT * 2))
	.ECHO	"*** INVALID IDE FUNCTION TABLE ***\n"
#ENDIF
;
IDE_VERIFY:
IDE_FORMAT:
IDE_DEFMED:
	SYSCHKERR(ERR_NOTIMPL)			; NOT IMPLEMENTED
	RET
;
;
;
IDE_READ:
	CALL	HB_DSKREAD		; HOOK HBIOS DISK READ SUPERVISOR
	LD	BC,IDE_RDSEC		; GET ADR OF SECTOR READ FUNC
	LD	(IDE_IOFNADR),BC	; SAVE IT AS PENDING IO FUNC
	JR	IDE_IO			; CONTINUE TO GENERIC IO ROUTINE
;
;
;
IDE_WRITE:
	CALL	HB_DSKWRITE		; HOOK HBIOS DISK WRITE SUPERVISOR
	LD	BC,IDE_WRSEC		; GET ADR OF SECTOR WRITE FUNC
	LD	(IDE_IOFNADR),BC	; SAVE IT AS PENDING IO FUNC
	JR	IDE_IO			; CONTINUE TO GENERIC IO ROUTINE
;
;
;
IDE_IO:
	LD	(IDE_DSKBUF),HL		; SAVE DISK BUFFER ADDRESS
	LD	A,E			; BLOCK COUNT TO A
	OR	A			; SET FLAGS
	RET	Z			; ZERO SECTOR I/O, RETURN W/ E=0 & A=0
	LD	B,A			; INIT SECTOR DOWNCOUNTER
	LD	C,0			; INIT SECTOR READ/WRITE COUNT
#IF (IDETRACE == 1)
	LD	HL,IDE_PRTERR		; SET UP IDE_PRTERR
	PUSH	HL			; ... TO FILTER ALL EXITS
#ENDIF
	PUSH	BC			; SAVE COUNTERS
	CALL	IDE_CHKERR		; CHECK FOR ERR STATUS AND RESET IF SO
	POP	BC			; RESTORE COUNTERS
	JR	NZ,IDE_IO3		; BAIL OUT ON ERROR
IDE_IO1:
	PUSH	BC			; SAVE COUNTERS
	CALL	IDE_SELUNIT		; HARDWARE SELECTION OF TARGET UNIT
	LD	HL,(IDE_IOFNADR)	; GET PENDING IO FUNCTION ADDRESS
	CALL	JPHL			; ... AND CALL IT
	JR	NZ,IDE_IO2		; IF ERROR, SKIP INCREMENT
	; INCREMENT LBA
	LD	A,IDE_LBA		; LBA OFFSET
	CALL	LDHLIYA			; HL := IY + A, REG A TRASHED
	CALL	INC32HL			; INCREMENT THE VALUE
	; INCREMENT DMA
	LD	HL,IDE_DSKBUF+1		; POINT TO MSB OF BUFFER ADR
	INC	(HL)			; BUMP DMA BY
	INC	(HL)			; ... 512 BYTES
	XOR	A			; SIGNAL SUCCESS
IDE_IO2:
	POP	BC			; RECOVER COUNTERS
	JR	NZ,IDE_IO3		; IF ERROR, BAIL OUT
	INC	C			; BUMP COUNT OF SECTORS READ
	DJNZ	IDE_IO1			; LOOP AS NEEDED
IDE_IO3:
	LD	E,C			; SECTOR READ COUNT TO E
	LD	HL,(IDE_DSKBUF)		; CURRENT DMA TO HL
	OR	A			; SET FLAGS BASED ON RETURN CODE
	RET	Z			; RETURN IF SUCCESS
	LD	A,ERR_IO		; SIGNAL IO ERROR
	OR	A			; SET FLAGS
	RET				; AND DONE
;
;
;
IDE_STATUS:
	; RETURN UNIT STATUS
	LD	A,(IY+IDE_STAT)		; GET STATUS OF SELECTED DEVICE
	OR	A			; SET FLAGS
	RET				; AND RETURN
;
;
;
IDE_DEVICE:
	LD	D,DIODEV_IDE		; D := DEVICE TYPE
	LD	E,(IY+IDE_DEV)		; E := PHYSICAL DEVICE NUMBER
	LD	C,%01111001		; ATAPI ATTRIBUTES
	LD	A,(IY+IDE_TYPE)		; CHECK TYPE VALUE
	CP	IDE_TYPEATAPI		; ATAPI?
	JR	Z,IDE_DEVICE1		; IF SO, DONE
	LD	C,%00110001		; COMPACTFLASH ATTRIBUTES
	BIT	0,(IY+IDE_MED)		; TEST CF BIT IN FLAGS
	JR	NZ,IDE_DEVICE1		; IF SET, DONE
	LD	C,%00110000		; GENERIC HARD DISK ATTRIBUTES
IDE_DEVICE1:
	LD	H,(IY+IDE_MODE)		; H := MODE
	LD	L,(IY+IDE_IOBASE)	; L := BASE I/O ADDRESS
	XOR	A			; SIGNAL SUCCESS
	RET
;
; IDE_GETMED
;
IDE_MEDIA:
	LD	A,E			; GET FLAGS
	OR	A			; SET FLAGS
	JR	Z,IDE_MEDIA1		; JUST REPORT CURRENT STATUS AND MEDIA
;
	;CALL	IDE_RESET		; RESET IDE INTERFACE
	CALL	IDE_INITUNIT		; RE-INITIALIZE UNIT
;
IDE_MEDIA1:
	LD	A,(IY+IDE_STAT)		; GET STATUS
	OR	A			; SET FLAGS
	LD	D,0			; NO MEDIA CHANGE DETECTED
	LD	E,MID_HD		; ASSUME WE ARE OK
	RET	Z			; RETURN IF GOOD INIT
	LD	E,MID_NONE		; SIGNAL NO MEDIA
	LD	A,ERR_NOMEDIA		; NO MEDIA ERROR
	OR	A			; SET FLAGS
	RET				; AND RETURN
;
;
;
IDE_SEEK:
	BIT	7,D			; CHECK FOR LBA FLAG
	CALL	Z,HB_CHS2LBA		; CLEAR MEANS CHS, CONVERT TO LBA
	RES	7,D			; CLEAR FLAG REGARDLESS (DOES NO HARM IF ALREADY LBA)
	LD	(IY+IDE_LBA+0),L	; SAVE NEW LBA
	LD	(IY+IDE_LBA+1),H	; ...
	LD	(IY+IDE_LBA+2),E	; ...
	LD	(IY+IDE_LBA+3),D	; ...
	XOR	A			; SIGNAL SUCCESS
	RET				; AND RETURN
;
;
;
IDE_CAP:
	LD	A,(IY+IDE_STAT)		; GET STATUS
	PUSH	AF			; SAVE IT
	LD	A,IDE_MEDCAP		; OFFSET TO CAPACITY FIELD
	CALL	LDHLIYA			; HL := IY + A, REG A TRASHED
	CALL	LD32			; GET THE CURRENT CAPACITY INTO DE:HL
	LD	BC,512			; 512 BYTES PER BLOCK
	POP	AF			; RECOVER STATUS
	OR	A			; SET FLAGS
	RET
;
;
;
IDE_GEOM:
	; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS
	; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE
	CALL	IDE_CAP			; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC
	LD	L,H			; DIVIDE BY 256 FOR # TRACKS
	LD	H,E			; ... HIGH BYTE DISCARDED, RESULT IN HL
	LD	D,16 | $80		; HEADS / CYL = 16, SET LBA CAPABILITY BIT
	LD	E,16			; SECTORS / TRACK = 16
	RET				; DONE, A STILL HAS IDE_CAP STATUS
;
;=============================================================================
; FUNCTION SUPPORT ROUTINES
;=============================================================================
;
IDE_SETFEAT:
	PUSH	AF
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" SETFEAT$")
#ENDIF
	LD	A,(IDE_DRVHD)
	;OUT	(IDE_REG_DRVHD),A
	CALL	IDE_OUT
	.DB	IDE_REG_DRVHD
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	POP	AF
	;OUT	(IDE_REG_FEAT),A	; SET THE FEATURE VALUE
	CALL	IDE_OUT
	.DB	IDE_REG_FEAT
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,IDE_CMD_SETFEAT	; CMD = SETFEAT
	LD	(IDE_CMD),A		; SAVE IT
	JP	IDE_RUNCMD		; RUN COMMAND AND EXIT
;
;
;
IDE_IDENTIFY:
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" IDDEV$")
#ENDIF
	LD	A,(IDE_DRVHD)
	;OUT	(IDE_REG_DRVHD),A
	CALL	IDE_OUT
	.DB	IDE_REG_DRVHD
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,IDE_CMD_IDDEV
	LD	(IDE_CMD),A
	CALL	IDE_RUNCMD_ND
	RET	NZ
;
	CALL	IDE_IN
	.DB	IDE_REG_STAT
	BIT	3,A			; IS DRQ SET?
	JP	Z,IDE_NOMEDIA
;
	LD	HL,HB_WRKBUF
	JP	IDE_GETBUF		; EXIT THRU BUFRD
;
;
;
IDE_IDENTIFYPACKET:
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" IDPKTDEV$")
#ENDIF
	LD	A,(IDE_DRVHD)
	;OUT	(IDE_REG_DRVHD),A
	CALL	IDE_OUT
	.DB	IDE_REG_DRVHD
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,IDE_CMD_IDPKTDEV
	LD	(IDE_CMD),A
	CALL	IDE_RUNCMD_ND
	RET	NZ
;
	CALL	IDE_IN
	.DB	IDE_REG_STAT
	BIT	3,A			; IS DRQ SET?
	JP	Z,IDE_NOMEDIA
;
	LD	HL,HB_WRKBUF
	JP	IDE_GETBUF		; EXIT THRU BUFRD
;
;
;
IDE_PACKET:
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" PACKET$")
#ENDIF
	LD	A,(IDE_DRVHD)
	;OUT	(IDE_REG_DRVHD),A
	CALL	IDE_OUT
	.DB	IDE_REG_DRVHD
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	XOR	A			; ZERO
	CALL	IDE_OUT
	.DB	IDE_REG_FEAT		; FEATURE REG = 0
	CALL	IDE_OUT
	.DB	IDE_REG_BCL
	LD	A,8
	CALL	IDE_OUT
	.DB	IDE_REG_BCH		; BYTE COUNT = 512????
	LD	A,IDE_CMD_PACKET
	LD	(IDE_CMD),A
	JP	IDE_RUNCMD_ND
;
;
;
IDE_RDSEC:
;
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" READ$")
#ENDIF
	LD	A,(IDE_DRVHD)
	;OUT	(IDE_REG_DRVHD),A
	CALL	IDE_OUT
	.DB	IDE_REG_DRVHD
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,(IY+IDE_TYPE)
	CP	IDE_TYPEATA
	JR	Z,IDE_ATA_RDSEC
	CP	IDE_TYPEATAPI
	JR	Z,IDE_PKT_RDSEC
	JP	IDE_CMDERR
;
IDE_ATA_RDSEC:
#IF (IDETRACE >= 3)
	PRTS(" ATA$")
#ENDIF
	CALL	IDE_SETADDR		; SETUP CYL, TRK, HEAD
	LD	A,IDE_CMD_READ
	LD	(IDE_CMD),A
	CALL	IDE_RUNCMD
	RET	NZ
	LD	HL,(IDE_DSKBUF)
	JP	IDE_GETBUF
;
IDE_PKT_RDSEC:
#IF (IDETRACE >= 3)
	PRTS(" PKT$")
#ENDIF
	; SETUP LBA
;
;;;#IF (DSKYENABLE)
;;;  #IF (DSKYDSKACT)
	LD	A,IDE_LBA
	CALL	LDHLIYA
	CALL	HB_DSKACT		; SHOW ACTIVITY
;;;  #ENDIF
;;;#ENDIF
;
	; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
	LD	HL,IDE_PKTCMD_RW10+3	; START OF LBA FIELD IN CDB (MSB)
	LD	A,(IY+IDE_LBA+2)	; THIRD BYTE OF LBA FIELD IN CFG (MSB)
	LD	(HL),A
	INC	HL
	LD	A,(IY+IDE_LBA+1)
	LD	(HL),A
	INC	HL
	LD	A,(IY+IDE_LBA+0)
	LD	(HL),A
	INC	HL
	LD	HL,IDE_PKTCMD_RW10
	LD	A,SCSI_CMD_READ10
	LD	(HL),A
	XOR	A			; READ DIRECTION
	LD	(IDE_XFRDIR),A		; SAVE IT
	CALL	IDE_RUNPCMD
	JP	NZ,IDE_CHKPCMD
	RET
;
;
;
IDE_WRSEC:
;
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" WRITE$")
#ENDIF
	LD	A,(IDE_DRVHD)
	;OUT	(IDE_REG_DRVHD),A
	CALL	IDE_OUT
	.DB	IDE_REG_DRVHD
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,(IY+IDE_TYPE)
	CP	IDE_TYPEATA
	JR	Z,IDE_ATA_WRSEC
	CP	IDE_TYPEATAPI
	JR	Z,IDE_PKT_WRSEC
	JP	IDE_CMDERR
;
IDE_ATA_WRSEC:
#IF (IDETRACE >= 3)
	PRTS(" ATA$")
#ENDIF
	CALL	IDE_SETADDR		; SETUP CYL, TRK, HEAD
	LD	A,IDE_CMD_WRITE
	LD	(IDE_CMD),A
	CALL	IDE_RUNCMD
	RET	NZ
	LD	HL,(IDE_DSKBUF)
	JP	IDE_PUTBUF
;
IDE_PKT_WRSEC:
#IF (IDETRACE >= 3)
	PRTS(" PKT$")
#ENDIF
	; SETUP LBA
;
;;;#IF (DSKYENABLE)
;;;  #IF (DSKYDSKACT)
	LD	A,IDE_LBA
	CALL	LDHLIYA
	CALL	HB_DSKACT		; SHOW ACTIVITY
;;;  #ENDIF
;;;#ENDIF
;
	; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
	LD	HL,IDE_PKTCMD_RW10+3	; START OF LBA FIELD IN CDB (MSB)
	LD	A,(IY+IDE_LBA+2)	; THIRD BYTE OF LBA FIELD IN CFG (MSB)
	LD	(HL),A
	INC	HL
	LD	A,(IY+IDE_LBA+1)
	LD	(HL),A
	INC	HL
	LD	A,(IY+IDE_LBA+0)
	LD	(HL),A
	INC	HL
	LD	HL,IDE_PKTCMD_RW10
	LD	A,SCSI_CMD_WRITE10
	LD	(HL),A
	OR	$FF			; WRITE DIRECTION
	LD	(IDE_XFRDIR),A		; SAVE IT
	CALL	IDE_RUNPCMD
	JP	NZ,IDE_CHKPCMD
	RET
;
;
;
IDE_SETADDR:
;
;;;#IF (DSKYENABLE)
;;;  #IF (DSKYDSKACT)
	LD	A,IDE_LBA
	CALL	LDHLIYA
	CALL	HB_DSKACT		; SHOW ACTIVITY
;;;  #ENDIF
;;;#ENDIF
	; SEND 3 LOWEST BYTES OF LBA IN REVERSE ORDER
	; IDE_REG_LBA3 HAS ALREADY BEEN SET
	; HSTLBA2-0 --> IDE_REG_LBA2-0
	LD	A,(IY+IDE_LBA+2)
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	IDE_OUT
	.DB	IDE_REG_LBA2
;
	LD	A,(IY+IDE_LBA+1)
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	IDE_OUT
	.DB	IDE_REG_LBA1
;
	LD	A,(IY+IDE_LBA+0)
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	IDE_OUT
	.DB	IDE_REG_LBA0
;
	LD	A,1
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	IDE_OUT
	.DB	IDE_REG_COUNT
;
	RET
;
;=============================================================================
; COMMAND PROCESSING
;=============================================================================
;
; RUN AN ATA COMMAND.  THERE ARE TWO ENTRY POINTS.  THE NORMAL ENTRY
; POINT WILL WAIT FOR DRIVE READY.  THE _ND ENTRY POINT ONLY WAITS
; FOR THE DEVICE TO BE NOT BUSY.  THE CORRECT ENTRY POINT DEPENDS ON
; THE COMMAND.
;
IDE_RUNCMD_ND:
	CALL	IDE_WAITBSY		; WAIT WHILE DEVICE BUSY
	RET	NZ			; BAIL OUT ON TIMEOUT
	JR	IDE_RUNCMD1		; CONTINUE

IDE_RUNCMD:
	CALL	IDE_WAITRDY		; WAIT FOR DRIVE READY
	RET	NZ			; BAIL OUT ON TIMEOUT
;
IDE_RUNCMD1:
	LD	A,(IDE_CMD)		; GET THE COMMAND
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	;OUT	(IDE_REG_CMD),A		; SEND IT (STARTS EXECUTION)
	CALL	IDE_OUT
	.DB	IDE_REG_CMD
#IF (IDETRACE >= 3)
	PRTS(" -->$")
#ENDIF
;
	CALL	IDE_WAITBSY		; WAIT FOR DRIVE READY (COMMAND DONE)
	RET	NZ			; BAIL OUT ON TIMEOUT
;
	CALL	IDE_GETRES
	JP	NZ,IDE_CMDERR
	RET
;
; PACKET COMMAND PROCESSOR
; HL: ADDRESS OF PACKET COMMAND BUFFER
;
IDE_RUNPCMD:
	PUSH	HL
	CALL	IDE_PACKET
	POP	HL
	RET	NZ			; BAIL OUT ON ERROR
;
#IF (IDETRACE >= 3)
	PRTS("\r\nPKTCMD:$")
	PUSH	HL
	POP	DE
	LD	A,12
	CALL	PRTHEXBUF
#ENDIF
;
	; IF ZIP DRIVE HAS FALLEN ASLEEP, THEN IT WILL NEED EXTRA
	; TIME HERE TO WAKE UP BEFORE ACCEPTING THE COMMAND.  USE
	; LONG TIMEOUT TO ACCOMMODATE THIS.
	LD	DE,(IDE_TIMEOUT)	; GET CURRENT TIMEOUT
	PUSH	DE			; SAVE IT
	LD	DE,IDE_TOSLOW		; SLOW TIMEOUT FOR THIS
	LD	(IDE_TIMEOUT),DE	; SET IT
	LD	B,6			; 6 WORDS ALWAYS
	CALL	IDE_PUT
	POP	DE			; RECOVER TIMEOUT
	LD	(IDE_TIMEOUT),DE	; SET IT
	RET	NZ
;
	CALL	IDE_IN
	.DB	IDE_REG_STAT
	BIT	3,A			; IS DRQ SET?
	RET	Z			; IF NOT, ALL DONE
;
	CALL	IDE_IN
	.DB	IDE_REG_BCL
	LD	C,A
	CALL	IDE_IN
	.DB	IDE_REG_BCH
	LD	B,A
;
	; BELOW ASSUMES MAX TRANSFER OF 512 BYTES!!!
	PUSH	BC			; SAVE BYTE COUNT
	SRL	B			; CONVERT
	RR	C			; ... TO WORDS
	LD	B,C
	;LD	HL,HB_WRKBUF		; SET XFR BUFFER
	LD	HL,(IDE_DSKBUF)		; SET XFR BUFFER
	
	LD	A,(IDE_XFRDIR)
	OR	A
	JR	NZ,IDE_RUNPCMD2		; NZ = WRITE
	CALL	IDE_GET			; GET SOME DATA
	JR	IDE_RUNPCMD3
IDE_RUNPCMD2:
	CALL	IDE_PUT			; PUT SOME DATA
IDE_RUNPCMD3:
	POP	BC			; RESTORE BYTE COUNT
	RET	NZ			; BAIL OUT ON ERRORS
;
	XOR	A
	RET
;
; THE FOLLOWING IS USED TO ASSESS ANY ERROR THAT OCCURS DURING
; RUNCMD AND SET AN APPROPRIATE ERROR CODE.
;
IDE_CHKPCMD:
;
	LD	HL,HB_WRKBUF
	LD	(IDE_DSKBUF),HL
	LD	HL,IDE_PKTCMD_SENSE
	CALL	IDE_RUNPCMD
	RET	NZ
;
	CALL	IDE_IN
	.DB	IDE_REG_BCL
;
#IF (IDETRACE >= 3)
	CALL	NEWLINE
	LD	DE,HB_WRKBUF
	CALL	PRTHEXBUF
#ENDIF
;
	; ASSESS SENSE DATA AND SET APPROPRIATE ERROR
	LD	A,(HB_WRKBUF+12)
	CP	$3A
	JP	Z,IDE_NOMEDIA
	CP	$04
	JP	Z,IDE_NOTRDY
;
	JP	IDE_CMDERR
;
; HL=BUFFER
;
IDE_GETBUF:
	LD	B,0
	; FALL THRU!!!
;
; HL=BUFFER
; B=WORD COUNT, 0=256
;
IDE_GET:
#IF (IDETRACE >= 3)
	PRTS(" GET$")
#ENDIF
;
	; WAIT FOR BUFFER
	PUSH	BC
	PUSH	HL
	CALL	IDE_WAITDRQ		; WAIT FOR BUFFER READY
	POP	HL
	POP	BC
	RET	NZ			; BAIL OUT IF TIMEOUT
;
	LD	A,B			; WORD COUNT IN A
;
	BIT	1,(IY+IDE_ACC)		; 8 BIT?
	JR	Z,IDE_GET1		; IF NOT, DO 16 BIT
	CALL	IDE_GET8		; DO 8 BIT
	JR	IDE_GET2
;
IDE_GET1:
	CALL	IDE_GET16
;
IDE_GET2:
	CALL	IDE_WAITRDY		; PROBLEMS IF THIS IS REMOVED!
	CALL	IDE_GETRES
	JP	NZ,IDE_IOERR
	RET
;
IDE_GET8:
	; 8 BIT I/O
	;LD	C,IDE_REG_DATA
	LD	C,(IY+IDE_IOBASE)
	LD	B,A
	EZ80_IO
	INIR
	LD	B,A
	EZ80_IO
	INIR
	RET
;
IDE_GET16:
	; 16 BIT I/O
	;LD	C,IDE_REG_DATAHI
	LD	D,(IY+IDE_DATALO)
	LD	E,(IY+IDE_DATAHI)
	CALL	IDE_GET16A		; GET FIRST 256 BYTES
	RET
;
IDE_GET16A:
#IF (IDE0MODE == IDEMODE_GIDE)		; GENESIS BOARD IS REVERSED
	LD	C,E			; PORT FOR MSB
	INI				; GET IT, SAVE IT, AND DEC B
	LD	C,D			; PORT FOR LSB
	INI				; GET IT, SAVE IT, AND DEC B
#ELSE
	LD	C,D			; PORT FOR LSB
	EZ80_IO
	INI				; GET IT, SAVE IT, AND DEC B
	LD	C,E			; PORT FOR MSB
	EZ80_IO
	INI				; GET IT, SAVE IT, AND DEC B
#ENDIF
	DEC	A
	JR	NZ,IDE_GET16A		; LOOP TILL COUNTER EXHAUSTED
	RET
;
; HL=BUFFER
;
IDE_PUTBUF:
	LD	B,0
	; FALL THRU!!!
;
; HL=BUFFER
; B=WORD COUNT, 0=256
;
IDE_PUT:
#IF (IDETRACE >= 3)
	PRTS(" PUT$")
#ENDIF
;
	; WAIT FOR BUFFER
	PUSH	BC
	PUSH	HL
	CALL	IDE_WAITDRQ		; WAIT FOR BUFFER READY
	POP	HL
	POP	BC
	RET	NZ			; BAIL OUT IF TIMEOUT
;
	LD	A,B			; WORD COUNT IN A
;
	BIT	1,(IY+IDE_ACC)		; 8 BIT?
	JR	Z,IDE_PUT1		; IF NOT, DO 16 BIT
	CALL	IDE_PUT8		; DO 8 BIT
	JR	IDE_PUT2
;
IDE_PUT1:
	CALL	IDE_PUT16
;
IDE_PUT2:
	CALL	IDE_WAITRDY		; PROBLEMS IF THIS IS REMOVED!
	CALL	IDE_GETRES
	JP	NZ,IDE_IOERR
	RET
;
IDE_PUT8:
	; 8 BIT I/O
	;LD	C,IDE_REG_DATA
	LD	C,(IY+IDE_IOBASE)
	LD	B,A
	EZ80_IO
	OTIR
	LD	B,A
	EZ80_IO
	OTIR
	RET
;
IDE_PUT16:
	; 16 BIT I/O
	;LD	C,IDE_REG_DATAHI
	LD	D,(IY+IDE_DATALO)
	LD	E,(IY+IDE_DATAHI)
	CALL	IDE_PUT16A		; PUT FIRST 256 BYTES
	RET
;
IDE_PUT16A:
#IF (IDE0MODE == IDEMODE_GIDE)		; GENESIS BOARD IS REVERSED
	LD	C,E			; PORT FOR MSB
	OUTI				; PUT IT AND DEC B
	LD	C,D			; PORT FOR LSB
	OUTI				; PUT IT AND DEC B
#ELSE
	LD	C,D			; PORT FOR LSB
	EZ80_IO
	OUTI				; PUT IT AND DEC B
	LD	C,E			; PORT FOR MSB
	EZ80_IO
	OUTI				; PUT IT AND DEC B
	DEC	A
#ENDIF
	JR	NZ,IDE_PUT16A		; LOOP TILL COUNTER EXHAUSTED
	RET
;
;
;
IDE_GETRES:
	;IN	A,(IDE_REG_STAT)		; GET STATUS
	CALL	IDE_IN
	.DB	IDE_REG_STAT
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	AND	%00000001		; ERROR BIT SET?
	RET	Z			; NOPE, RETURN WITH ZF
;
	;IN	A,(IDE_REG_ERR)		; READ ERROR REGISTER
	CALL	IDE_IN
	.DB	IDE_REG_ERR
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	OR	$FF			; FORCE NZ TO SIGNAL ERROR
	RET				; RETURN
;
;=============================================================================
; HARDWARE INTERFACE ROUTINES
;=============================================================================
;
; RESET ALL DEVICES ON BUS
;
IDE_RESET:
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" RESET$")
#ENDIF
;
; HARD RESET
;
; RESET LINE IS NORMALLY PULSED AT POWER ON.  HOWEVER, THIS IS NOT
; DONE FOR MK4 BUILT-IN IDE PORT, SO WE DO IT NOW.
;
	LD	A,(IY+IDE_MODE)		; GET MODE
	CP	IDEMODE_MK4		; MK4?
	JR	NZ,IDE_RESET2		; IF NOT, BYPASS
;
	; USE HARDWARE RESET LINE
#IF (IDETRACE >= 3)
	PRTS(" HARD$")
#ENDIF
	LD	A,$80			; HIGH BIT OF XAR IS IDE RESET
	;OUT	(IDE_REG_XAR),A
	CALL	IDE_OUT
	.DB	IDE_REG_XAR
	LD	DE,20			; DELAY 32US (SPEC IS >= 25US)
	CALL	VDELAY
	XOR	A			; CLEAR RESET BIT
	;OUT	(IDE_REG_XAR),A
	CALL	IDE_OUT
	.DB	IDE_REG_XAR
	LD	DE,20
	CALL	VDELAY
;
; SOME CF CARDS AND CF CARD EMULATORS NEED A LITTLE TIME TO
; "BOOT" THEIR INTERNAL ELECTRONICS, SO THEY CANNOT ASSERT BUSY
; IMMEDIATELY.  A SMALL WAIT IS PERFORMED HERE TO GIVE SUCH DEVICES
; A BETTER CHANCE TO SUCCEED LATER.
;
;	LD	DE,150000 / 16		; 
	LD	DE,300000 / 16		; 
	CALL	VDELAY			; SMALL DELAY
;
	JR	IDE_RESET3		; SKIP SOFT RESET
;
; SOFT RESET
;
; RC CANNOT ACCESS DEVICE CONTROL REG, SO SKIP THIS
;
IDE_RESET2:
	LD	A,(IY+IDE_MODE)		; GET MODE
	CP	IDEMODE_RC		; RCBUS?
	JR	Z,IDE_RESET4		; IF SO, BYPASS
;
	; INITIATE SOFT RESET
#IF (IDETRACE >= 3)
	PRTS(" SOFT$")
#ENDIF
	LD	A,%00001110		; ASSERT RESET, NO INTERRUPTS
	;OUT	(IDE_REG_CTRL),A
	CALL	IDE_OUT
	.DB	IDE_REG_CTRL
	LD	DE,20			; DELAY 320US (SPEC IS >= 25US)
	CALL	VDELAY
;
IDE_RESET3:
;
; CONFIGURE OPERATION AND END SOFT RESET
;
#IF (IDETRACE >= 3)
	PRTS(" CONFIG$")
#ENDIF
	LD	DE,20			; DELAY 320US (SPEC IS >= 25US)
	CALL	VDELAY
	LD	A,%00001010		; DEASSERT RESET, NO INTERRUPTS
	;OUT	(IDE_REG_CTRL),A		; PUSH TO REGISTER
	CALL	IDE_OUT
	.DB	IDE_REG_CTRL
;
IDE_RESET4:
	LD	HL,IDE_TONORM		; NORMAL TIMEOUT NOW
	LD	(IDE_TIMEOUT),HL	; AND RESTORE IT
;
	; INITIALIZE THE INDIVIDUAL UNITS (MASTER AND SLAVE).
	; BASED ON TESTING, IT APPEARS THAT THE MASTER UNIT MUST
	; BE DONE FIRST OR THIS BEHAVES BADLY.
;
	PUSH	IY			; SAVE CFG PTR
	BIT	0,(IY+IDE_ACC)		; MASTER?
	CALL	Z,IDE_GOPARTNER		; IF NOT, SWITCH TO MASTER
	CALL	IDE_INITUNIT		; INIT CURRENT UNIT
	CALL	IDE_GOPARTNER		; POINT TO SLAVE
	CALL	IDE_INITUNIT		; INIT PARTNER UNIT
	POP	IY			; RECOVER ORIG CFG PTR
;
	XOR	A			; SIGNAL SUCCESS
	RET				; AND DONE
;
;
;
IDE_INITUNIT:
	CALL	IDE_SELUNIT		; SELECT UNIT
	RET	NZ			; ABORT IF ERROR

	CALL	IDE_PROBE		; DO PROBE
	RET	NZ			; JUST RETURN IF NOTHING THERE

	JP	IDE_INITDEV		; EXIT VIA INITDEV
;
; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT
;
IDE_SELUNIT:
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" SELUNIT$")
#ENDIF
	BIT	0,(IY+IDE_ACC)		; MASTER?
	JR	Z,IDE_SELUNIT1		; HANDLE SLAVE
	LD	A,IDE_DRVMASTER		; MASTER
#IF (IDETRACE >= 3)
	PRTS(" MASTER$")
#ENDIF
	JR	IDE_SELUNIT2
IDE_SELUNIT1:
	LD	A,IDE_DRVSLAVE		; SLAVE
#IF (IDETRACE >= 3)
	PRTS(" SLAVE$")
#ENDIF
IDE_SELUNIT2:
	LD	(IDE_DRVHD),A		; SAVE IT
	XOR	A			; SUCCESS
	RET
;
;
;
IDE_PROBE:
;
; PROBE FOR A DRIVE ON THE INTERFACE (EITHER MASTER OR SLAVE).
; IDEALLY, THIS IS BEING CALLED IMMEDIATELY AFTER A HARD OR SOFT
; INTERFACE RESET.  HOWEVER, THERE ARE SOME HARDWARE IMPLEMENTATTIONS
; WHICH ARE CAPABLE OF NEITHER A HARD NOR SOFT RESET.  SO THIS
; CODE SHOULD TRY TO HANDLE THE SCENARIO WHERE NO INTERFACE RESET
; HAS OCCURRED.
;
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" PROBE$")			; LABEL FOR IO ADDRESS
#ENDIF
;
#IF (IDETRACE >= 3)
	CALL	IDE_IN
	.DB	IDE_REG_STAT
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
;
	; SELECT DEVICE (MASTER/SLAVE)
	LD	A,(IDE_DRVHD)
	;OUT	(IDE_REG_DRVHD),A
	CALL	IDE_OUT
	.DB	IDE_REG_DRVHD
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	DELAY			; DELAY ~16US
;
; THE RC2014 SD PICO TAKES A FEW SECONDS TO INITIALIZE.  ATEMPTING TO
; ACCESS IT DURING THIS TIME WILL FAIL.  THE DATA LINES ALL HAVE
; PULL-DOWN RESISTORS, SO WHILE IT IS INITIALIZING, READING ANY
; REGISTER WILL CONSISTENTLY RETURN $00.  THE FOLLOWING BIT OF CODE
; WILL SCAN THE IDE REGISTER BLOCK.  WHILE ALL REGISTERS REMAIN ZERO,
; WE WAIT (UNTIL TIMEOUT).  IN MY TESTING, IT SEEMS VERY UNLIKELY
; THAT ANY OTHER DEVICE WILL RETURN $00 FOR ALL REGISTERS.
;
	LD	A,(IY+IDE_MODE)		; GET MODE BITS
	CP	IDEMODE_RC		; RCBUS?
	JR	NZ,IDE_PROBE0		; IF NOT, BYPASS
;
	LD	A,(IDE_DRVHD)		; GET CURRENT SETTING
	BIT	4,A			; TEST SLAVE BIT
	JR	NZ,IDE_PROBE0		; IF SO, BYPASS
;
	CALL	IDE_IN
	.DB	IDE_REG_STAT
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	OR	A			; SET FLAGS
	JR	NZ,IDE_PROBE0		; SKIP IF NOT $00
;
#IF (IDETRACE >= 3)
	PRTS(" PICO$")
#ENDIF
	LD	HL,500			; 5 SECONDS
IDE_WAIT001:
	;CALL	NEWLINE
	LD	C,(IY+IDE_IOBASE)
	LD	B,8			; NUMBER OF REGISTERS TO CHECK
IDE_WAIT002:

	; THE EZ80_IO ROUTINE SEEMS TO ALWAYS RETURN $00 FOR UNOCCUPIED
	; PORTS.  THAT CAUSES AN INORDINATE DELAY HERE, SO WE HANDLE
	; 16 BIT I/O OURSELVES.

	;;;EZ80_IO
	;;;IN	A,(C)			; GET REGISTER VALUE
	
	PUSH	BC			; SAVE LOOP CONTROL
	LD	B,IO_SEGMENT		; MSB FOR I/O
	IN	A,(C)			; READ PORT
	POP	BC			; RESTORE LOOP CONTROL
	
	;CALL	PC_SPACE
	;CALL	PRTHEXBYTE
	OR	A			; SET FLAGS
	JR	NZ,IDE_PROBE0		; IF NOT ZERO, MOVE ON
	INC	C			; NEXT REGISTER
	DJNZ	IDE_WAIT002		; CHECK ALL 8 REGS
	LD	DE,10000/16		; .01 SECONDS
	CALL	VDELAY
	DEC	HL
	LD	A,H
	OR	L
	JR	NZ,IDE_WAIT001		; LOOP
	;JP	IDE_NOMEDIA		; GIVE UP?
;
; IF WE GET HERE AND THE DRIVE IS STILL INITIALIZING, WE NEED TO
; WAIT UNTIL THE DRIVE IS READY.  IN THIS CASE BUSY *WILL* BE HIGH.
; BASED ON TESTING, DRDY AND DSC VALUES VARY.  EVERYTHING ELSE SEEMS
; TO BE ZERO.  SO, WE FILTER OUT DRDY & DSC, THEN LOOK FOR BUSY=1
; AND ALL ELSE ZERO.  THIS GENERALLY AVOIDS VALUES THAT ARE TYPICAL
; FOR FLOATING PORTS AND SO CAN BE USED TO DETERMINE IF WE NEED TO
; WAIT FOR THE DEVICE TO BE READY.  THIS WAIT IS MANDATORY BECAUSE
; SOME (IF NOT ALL) DEVICES WILL NOT PERSIST REGISTER VALUES UNTIL
; THE DRIVE IS READY.
;
IDE_PROBE0:
	CALL	IDE_IN
	.DB	IDE_REG_STAT
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
;
	AND	%10101111		; FILTER OUT DRDY & DSC
	CP	$80			; INIT IN PROGRESS?
	JR	NZ,IDE_PROBE1		; IF NOT, SKIP AHEAD
;
#IF (IDETRACE >= 3)
	PRTS(" WAIT$")
#ENDIF
;
	LD	HL,(IDE_TIMEOUT)	; GET CURRENT TIMEOUT
	PUSH	HL			; SAVE IT
	LD	HL,IDE_TOSLOW		; SLOW TIMEOUT FOR THIS
	LD	(IDE_TIMEOUT),HL	; SET IT
	CALL	IDE_WAITBSY		; WAIT FOR BUSY TO CLEAR
	POP	HL			; RECOVER TIMEOUT
	LD	(IDE_TIMEOUT),HL	; SET IT
;
#IF (IDETRACE >= 3)
	CALL	IDE_IN
	.DB	IDE_REG_STAT
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
;
; TEST FOR PRESENCE OF IDE REGISTERS.  USE LBA0/1 TO SEE
; IF VALUE CAN BE PERSISTED.  THE USE OF BOTH LBA0 AND LBA1
; IS TO MAINTAIN CONSISTENCY WITH THE THE PPIDE DRIVER BECAUSE
; PPI ITSELF WILL PERSIST THE LAST VALUE WRITTEN, SO WE USE
; MULTIPLE REGISTERS TO WORK AROUND THIS FALSE POSITIVE.
;
IDE_PROBE1:
	; $AA -> LBA0
	LD	A,$AA
	CALL	IDE_OUT
	.DB	IDE_REG_LBA0
;
	; $55 => LBA1
	LD	A,$55
	CALL	IDE_OUT
	.DB	IDE_REG_LBA1
;
	; TEST LBA0 == $AA
	CALL	IDE_IN
	.DB	IDE_REG_LBA0
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CP	$AA
	JP	NZ,IDE_NOMEDIA
;
	; TEST LBA1 == $55
	CALL	IDE_IN
	.DB	IDE_REG_LBA1
#IF (IDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CP	$55
	JP	NZ,IDE_NOMEDIA
;
#IF (IDETRACE >= 3)
	CALL	IDE_REGDUMP
#ENDIF
;
	XOR	A
	RET
;
; (RE)INITIALIZE DEVICE
;
IDE_INITDEV:
;
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" INITDEV$")		; LABEL FOR IO ADDRESS
#ENDIF
;
#IF (IDETRACE >= 3)
	CALL	IDE_REGDUMP
#ENDIF
;
; ON ENTRY, WE HAVE ALREADY CHECKED THAT THE BUSY BIT IS CLEARED AND
; DRDY SHOULD BE SET.  IF DRDY IS NOT SET, IF COULD MEAN EITHER A
; NON-EXISTENT SLAVE DEVICE OR AN ATAPI DEVICE.  TO AVOID UNNECESSARY
; TIMEOUTS, WE CHECK FOR DRDY.  IF IT IS NOT SET, THEN WE ASSUME THIS
; MUST BE AN ATAPI DEVICE AND GO TRY TO DO THE ATAPI INITIALIZATION.
; IF THIS WAS ACTUALLY A NON-EXISTENT SLAVE, THE ATAPI INITIALIZATION
; WILL HANDLE THIS PRETTY WELL.
;
	CALL	IDE_IN
	.DB	IDE_REG_STAT
	BIT	6,A			; DRDY?
	JR	Z,IDE_INITPDEV		; ODD, MIGHT BE ATAPI
;
; WE NEED TO SETUP 8-BIT MODE BEFORE DOING ANYTHING ELSE
;
	BIT	1,(IY+IDE_ACC)		; 8 BIT ACCESS?
	JR	Z,IDE_INITDEV0		; NO, DO 16 BIT INIT
	LD	A,IDE_FEAT_ENABLE8BIT	; FEATURE VALUE = ENABLE 8-BIT PIO
	CALL	IDE_SETFEAT		; SET FEATURE
	RET	NZ			; BAIL OUT ON ERROR
	JR	IDE_INITDEV00		; CONTINUE
;
IDE_INITDEV0:
	; "REAL" IDE DRIVES MAY NOT ACCEPT THE DISABLE8BIT FEATURE COMMAND,
	; SO IT IS ONLY AN ERROR IF WE ARE ATTEMPTING TO ENABLE8BIT.
	; CREDIT TO ED BRINDLEY FOR THIS CORRECTION.  SO ERROR RETURN IGNORED HERE.
	LD	A,IDE_FEAT_DISABLE8BIT	; FEATURE VALUE = ENABLE 8-BIT PIO
	CALL	IDE_SETFEAT		; SET FEATURE, IGNORE ERRORS
;
IDE_INITDEV00:
;
	; WE NOW USE AN IDENTIFY DEVICE COMMAND TO CONFIRM THE
	; DEVICE IS REALLY THERE AND GET SOME ATTRIBUTES.  IF THE
	; COMMAND FAILS, IT MAY BE THAT WE HAVE AN ATAPI DEVICE AND
	; SO WE GO TO THE ATAPI INITIALIZATION ON FAILURE.
	CALL	IDE_IDENTIFY		; EXECUTE IDENTIFY COMMAND
	JR	NZ,IDE_INITPDEV		; TRY ATAPI ON FAILURE
;
	; DECLARE WE ARE ATA
	LD	A,IDE_TYPEATA		; OTHERWISE TYPE=ATA
	LD	(IY+IDE_TYPE),A		; SET IT IN INSTANCE DATA
;
	LD	DE,HB_WRKBUF		; POINT TO BUFFER
#IF (IDETRACE >= 4)
	CALL	DUMP_BUFFER		; DUMP IT IF DEBUGGING
#ENDIF
;
	LD	(IY+IDE_MED),0		; CLEAR MEDIA FLAGS
;
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" SIG=0x$")
	LD	BC,(HB_WRKBUF)
	CALL	PRTHEXWORD
#ENDIF
;
	; DETERMINE IF COMPACTFLASH MEDIA
	LD	A,(HB_WRKBUF+(83*2))	; LOW BYTE OF WORD 83
	BIT	2,A			; TEST CFA FEATURE SET BIT
	JR	Z,IDE_INITDEV1		; IF NOT, SKIP
	SET	0,(IY+IDE_MED)		; ELSE SET FLAGS BIT FOR CF MEDIA
;
IDE_INITDEV1:
	; DETERMINE IF LBA CAPABLE
	LD	A,(HB_WRKBUF+98+1)	; HIGH BYTE OF WORD 49
	BIT	1,A			; CHECK THE LBA BIT
	JR	Z,IDE_INITDEV2		; NOT SET, BYPASS
	SET	1,(IY+IDE_MED)		; SET FLAGS BIT FOR LBA
;
IDE_INITDEV2:
	; GET DEVICE CAPACITY AND SAVE IT
	LD	A,IDE_MEDCAP		; OFFSET TO CAPACITY FIELD
	CALL	LDHLIYA			; HL := IY + A, REG A TRASHED
	PUSH	HL			; SAVE POINTER
	LD	HL,HB_WRKBUF		; POINT TO BUFFER START
	LD	A,120			; OFFSET OF SECTOR COUNT
	CALL	ADDHLA			; POINT TO ADDRESS OF SECTOR COUNT
	CALL	LD32			; LOAD IT TO DE:HL
	POP	BC			; RECOVER POINTER TO CAPACITY ENTRY
	CALL	ST32			; SAVE CAPACITY
;
	; RECORD STATUS OK
	XOR	A			; A := 0 (STATUS = OK)
	LD	(IY+IDE_STAT),A		; SAVE IT
;
	RET				; RETURN, A=0, Z SET
;
; (RE)INITIALIZE PACKET DEVICE
;
IDE_INITPDEV:
;
#IF (IDETRACE >= 3)
	CALL	IDE_PRTPREFIX
	PRTS(" INITPDEV$")		; LABEL FOR IO ADDRESS
#ENDIF
	;
	CALL	IDE_IDENTIFYPACKET	; EXECUTE IDENTIFY COMMAND
	RET	NZ			; BAIL OUT ON ERROR
;
	; DECLARE WE ARE ATAPI
	LD	A,IDE_TYPEATAPI		; OTHERWISE TYPE=ATAPI
	LD	(IY+IDE_TYPE),A		; SET IT IN INSTANCE DATA
;
	LD	DE,HB_WRKBUF		; POINT TO BUFFER
#IF (IDETRACE >= 4)
	CALL	DUMP_BUFFER		; DUMP IT IF DEBUGGING
#ENDIF
;
	LD	(IY+IDE_MED),0		; CLEAR FLAGS
	SET	1,(IY+IDE_MED)		; SET FLAGS BIT FOR LBA (ASSUMED)
;
	; WAIT FOR UNIT READY
	LD	B,0			; MAX LOOPS
	LD	C,4			; MAX ERRORS
IDE_INITPDEV1:
	DEC	B			; CHECK LOOP COUNTER EXCEEDED
	JP	Z,IDE_NOMEDIA		; TREAT AS NO MEDIA
	PUSH	BC			; SAVE LOOP CONTROL
	LD	HL,IDE_PKTCMD_TSTRDY	; TEST UNIT READY
	XOR	A			; READ DIRECTION
	LD	(IDE_XFRDIR),A		; SAVE IT
	CALL	IDE_RUNPCMD		; ISSUE PACKET COMMAND
	CALL	NZ,IDE_CHKPCMD		; IF ERROR, DIAGNOSE IT
	POP	BC			; RESTORE LOOP CONTROL
	JR	Z,IDE_INITPDEV2		; IF NO ERROR, CONTINUE
	CP	IDE_STNOMEDIA		; EXPLICIT NO MEDIA RESULT?
	RET	Z			; EXIT REPORTING NO MEDIA
	CP	IDE_STNOTRDY		; BECOMING READY?
	JR	Z,IDE_INITDEVP1A	; IF SO, NOT AN ERROR, LOOP
	DEC	C			; DEC ERROR LIMIT
	RET	Z			; BAIL OUT, ERR LIMIT EXCEEDED
	JR	IDE_INITPDEV1		; LOOP
IDE_INITDEVP1A:
	LD	DE,100000/16		; WAIT 1/10 SECOND
	CALL	VDELAY			; DO IT
	JR	IDE_INITPDEV1		; AND LOOP
;
IDE_INITPDEV2:
#IF (IDETRACE >= 3)
	LD	A,B
	NEG
	PRTS("\r\nLOOPS=$")
	CALL	PRTHEXBYTE
#ENDIF
;
	; GET AND RECORD CAPACITY
	LD	HL,HB_WRKBUF
	LD	(IDE_DSKBUF),HL
	LD	HL,IDE_PKTCMD_RDCAP
	XOR	A			; READ DIRECTION
	LD	(IDE_XFRDIR),A		; SAVE IT
	CALL	IDE_RUNPCMD
	JP	NZ,IDE_CHKPCMD
;
#IF (IDETRACE >= 3)
	PRTS("\r\nRDCAP:$")
	LD	A,8
	LD	DE,HB_WRKBUF
	CALL	PRTHEXBUF
#ENDIF
;
	; CAPACITY IS RETURNED IN A 4 BYTE, BIG ENDIAN FIELD AND
	; INDICATES THE LAST LBA VALUE.  WE NEED TO CONVERT THIS TO
	; LITTLE ENDIAN AND INCREMENT THE VALUE TO MAKE IT A CAPACITY
	; COUNT INSTEAD OF A LAST LBA VALUE.
	LD	A,IDE_MEDCAP		; OFFSET IN CFG FOR CAPACITY
	CALL	LDHLIYA			; POINTER TO HL
	PUSH	HL			; SAVE IT
	LD	HL,HB_WRKBUF		; POINT TO VALUE IN CMD RESULT
	CALL	LD32			; LOAD IT TO DE:HL
	LD	A,L			; FLIP BYTES
	LD	L,D			; ... BIG ENDIAN
	LD	D,A			; ... TO LITTLE ENDIAN
	LD	A,H
	LD	H,E
	LD	E,A
	CALL	INC32			; INCREMENT TO FINAL VALUE
	POP	BC			; RECOVER SAVE LOCATION
	CALL	ST32			; STORE VALUE
;
	; CHECK BLOCK LENGTH.  WE CURRENTLY ONLY SUPPORT 512 BYTE
	; BLOCKS.  CD-ROM DEVICES (WHICH USE 2k BLOCKS) WILL FAIL
	; HERE AS NOT SUPPORTED.
	LD	HL,HB_WRKBUF+4		; POINT TO BLK SIZE IN RESULT
	CALL	LD32			; LOAD IT TO DE:HL
	; VALUE IS BIG ENDIAN, SO LH:ED MUST BE EXACTLY 0000:0200
	LD	A,L			; CHECK THAT LH
	OR	H			; ... IS ZERO
	JP	NZ,IDE_NOTSUP		; IF NOT, FAIL AS NOT SUP
	LD	A,D			; LOAD D
	OR	A			; SET FLAGS
	JP	NZ,IDE_NOTSUP		; IF NOT ZERO, FAIL AS NOT SUP
	LD	A,E			; LOAD E
	CP	2			; CHECK IT IF IS 2
	JP	NZ,IDE_NOTSUP		; IF NOT, FAIL AS NOT SUP
;
	; CHECK BLOCK LENGTH.  WE CURRENTLY ONLY SUPPORT 512 BYTE
	; BLOCKS.  CD-ROM DEVICES (WHICH USE 2k BLOCKS) WILL FAIL
	; HERE AS NOT SUPPORTED.
	LD	HL,HB_WRKBUF+4		; POINT TO BLK SIZE IN RESULT
	CALL	LD32			; LOAD IT TO DE:HL
	; VALUE IS BIG ENDIAN, SO LH:ED MUST BE EXACTLY 0000:0200
	LD	A,L			; CHECK THAT LH
	OR	H			; ... IS ZERO
	JP	NZ,IDE_NOTSUP		; IF NOT, FAIL AS NOT SUP
	LD	A,D			; LOAD E
	OR	A			; SET FLAGS
	JP	NZ,IDE_NOTSUP		; IF NOT ZERO, FAIL AS NOT SUP
	LD	A,E			; LOAD D
	CP	2			; CHECK IT IF IS 2
	JP	NZ,IDE_NOTSUP		; IF NOT, FAIL AS NOT SUP
;
	; RECORD STATUS OK
	XOR	A			; A := 0 (STATUS = OK)
	LD	(IY+IDE_STAT),A		; SAVE IT
	RET
;
; SWITCH IY POINTER FROM CURRENT UNIT CFG TO PARTNER UNIT CFG
;
IDE_GOPARTNER:
	PUSH	HL			; SAVE HL
	LD	L,(IY+IDE_PARTNER)	; GET PARTNER ENTRY
	LD	H,(IY+IDE_PARTNER+1)	; ...
	PUSH	HL			; MOVE HL
	POP	IY			; ... TO IY
	POP	HL			; RESTORE INCOMING HL
	RET				; AND DONE
;
; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER
; VIA RESET IF DEVICE IS IN ERROR.
;
IDE_CHKERR:
	LD	A,(IY+IDE_STAT)		; GET STATUS
	OR	A			; SET FLAGS
	CALL	NZ,IDE_RESET		; IF ERROR STATUS, RESET BUS
	RET
;
;
;
IDE_WAITRDY:
	LD	A,(IDE_TIMEOUT)		; GET TIMEOUT IN 0.1 SECS
	LD	B,A			; PUT IN OUTER LOOP VAR
IDE_WAITRDY1:
	LD	DE,(IDE_TOSCALER)	; CPU SPEED SCALER TO INNER LOOP VAR
IDE_WAITRDY2:
	;IN	A,(IDE_REG_STAT)	; READ STATUS
	CALL	IDE_IN
	.DB	IDE_REG_STAT
	LD	C,A			; SAVE IT
	AND	%11000000		; ISOLATE BUSY AND RDY BITS
	XOR	%01000000		; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1
	RET	Z			; ALL SET, RETURN WITH Z SET
	DEC	DE
	LD	A,D
	OR	E
	JR	NZ,IDE_WAITRDY2		; INNER LOOP RETURN
	DJNZ	IDE_WAITRDY1		; OUTER LOOP RETURN
	JP	IDE_RDYTO		; EXIT WITH RDYTO ERR
;
;
;
IDE_WAITDRQ:
	LD	A,(IDE_TIMEOUT)		; GET TIMEOUT IN 0.1 SECS
	LD	B,A			; PUT IN OUTER LOOP VAR
IDE_WAITDRQ1:
	LD	DE,(IDE_TOSCALER)	; CPU SPPED SCALER TO INNER LOOP VAR
IDE_WAITDRQ2:
	;IN	A,(IDE_REG_STAT)	; READ STATUS
	CALL	IDE_IN
	.DB	IDE_REG_STAT
	LD	C,A			; SAVE IT
	AND	%10001000		; TO FILL (OR READY TO FILL)
	XOR	%00001000
	RET	Z
	DEC	DE
	LD	A,D
	OR	E
	JR	NZ,IDE_WAITDRQ2
	DJNZ	IDE_WAITDRQ1
	JP	IDE_DRQTO		; EXIT WITH BUFTO ERR
;
;
;
IDE_WAITBSY:
	LD	A,(IDE_TIMEOUT)		; GET TIMEOUT IN 0.1 SECS
	LD	B,A			; PUT IN OUTER LOOP VAR
IDE_WAITBSY1:
	LD	DE,(IDE_TOSCALER)	; CPU SPPED SCALER TO INNER LOOP VAR
IDE_WAITBSY2:
	;IN	A,(IDE_REG_STAT)	; READ STATUS
	CALL	IDE_IN									; 17TS + 121TS
	.DB	IDE_REG_STAT
	LD	C,A			; SAVE IT					; 4TS
	AND	%10000000		; TO FILL (OR READY TO FILL)			; 7TS
	RET	Z									; 5TS
	DEC	DE									; 6TS
	LD	A,D									; 4TS
	OR	E									; 4TS
	JR	NZ,IDE_WAITBSY2								; 12TS
	DJNZ	IDE_WAITBSY1								; -----
	JP	IDE_BSYTO		; EXIT WITH BSYTO ERR				; 180
;
; READ A VALUE FROM THE DEVICE POINTED TO BY IY AND RETURN IT IN A
;
IDE_IN:
	EX	(SP),HL			; GET PARM POINTER				; 19TS
	PUSH	BC									; 11TS
	LD	A,(HL)									; 7TS
	INC	HL									; 6TS
	LD	C,(IY+IDE_IOBASE)							; 19TS
	ADD	A,C									; 4TS
	LD	C,A									; 4TS
	EZ80_IO
	IN	A,(C)									; 12TS
	POP	BC									; 10TS
	EX	(SP),HL			; RESTORE STACK					; 19TS
	RET										; 10TS
;											; ----
; OUTPUT VALUE IN A TO THE DEVICE POINTED TO BY IY					; 121TS
;
IDE_OUT:
	EX	(SP),HL			; GET PARM POINTER
	PUSH	BC
	PUSH	AF
;
#IF (IDE0MODE == IDEMODE_GIDE)    ; SET TOP BYTE TO 0 FOR GENESIS BOARD 
	LD	A,(HL)
	LD	C,(IY+IDE_DATAHI)
	ADD	A,C
	LD	C,A
	LD    A,0
	OUT	(C),A
#ENDIF
;
	LD	A,(HL)
	INC	HL
	LD	C,(IY+IDE_IOBASE)
	ADD	A,C
	LD	C,A
	POP	AF
	EZ80_IO 
	OUT	(C),A
	POP	BC
	EX	(SP),HL			; RESTORE STACK
	RET
;
;=============================================================================
; ERROR HANDLING AND DIAGNOSTICS
;=============================================================================
;
; ERROR HANDLERS
;
IDE_INVUNIT:
	LD	A,IDE_STINVUNIT
	JR	IDE_ERR2		; SPECIAL CASE FOR INVALID UNIT
;
IDE_NOMEDIA:
	LD	A,IDE_STNOMEDIA
	JR	IDE_ERR
;
IDE_CMDERR:
	LD	A,IDE_STCMDERR
	JR	IDE_ERR
;
IDE_IOERR:
	LD	A,IDE_STIOERR
	JR	IDE_ERR
;
IDE_RDYTO:
	LD	A,IDE_STRDYTO
	JR	IDE_ERR
;
IDE_DRQTO:
	LD	A,IDE_STDRQTO
	JR	IDE_ERR
;
IDE_BSYTO:
	LD	A,IDE_STBSYTO
	JR	IDE_ERR
;
IDE_NOTSUP:
	LD	A,IDE_STNOTSUP
	JR	IDE_ERR
;
IDE_NOTRDY:
	LD	A,IDE_STNOTRDY
	JR	IDE_ERR
;
IDE_ERR:
	LD	(IY+IDE_STAT),A		; SAVE NEW STATUS
;
IDE_ERR2:
#IF (IDETRACE >= 2)
	CALL	IDE_PRTSTAT
	CALL	IDE_REGDUMP
#ENDIF
	OR	A			; SET FLAGS
	RET
;
;
;
IDE_PRTERR:
	RET	Z			; DONE IF NO ERRORS
	; FALL THRU TO IDE_PRTSTAT
;
; PRINT FULL DEVICE STATUS LINE
;
IDE_PRTSTAT:
	PUSH	AF
	PUSH	DE
	PUSH	HL
	LD	A,(IY+IDE_STAT)
	CP	IDE_STINVUNIT
	JR	Z,IDE_PRTSTAT2		; INVALID UNIT IS SPECIAL CASE
	CALL	IDE_PRTPREFIX		; PRINT UNIT PREFIX
	JR	IDE_PRTSTAT3
IDE_PRTSTAT2:
	CALL	NEWLINE
	PRTS("IDE:$")			; NO UNIT NUM IN PREFIX FOR INVALID UNIT
IDE_PRTSTAT3:
	CALL	PC_SPACE		; FORMATTING
	CALL	IDE_PRTSTATSTR
	POP	HL
	POP	DE
	POP	AF
	RET
;
; PRINT STATUS STRING
;
IDE_PRTSTATSTR:
	PUSH	AF
	PUSH	DE
	LD	A,(IY+IDE_STAT)
	OR	A
	LD	DE,IDE_STR_STOK
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STINVUNIT
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STNOMEDIA
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STCMDERR
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STIOERR
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STRDYTO
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STDRQTO
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STBSYTO
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STNOTSUP
	JR	Z,IDE_PRTSTATSTR1
	INC	A
	LD	DE,IDE_STR_STNOTRDY
	JR	Z,IDE_PRTSTATSTR1
	LD	DE,IDE_STR_STUNK
IDE_PRTSTATSTR1:
	CALL	WRITESTR
	POP	DE
	POP	AF
	RET
;
; PRINT ALL REGISTERS DIRECTLY FROM DEVICE
; DEVICE MUST BE SELECTED PRIOR TO CALL
;
IDE_REGDUMP:
	PUSH	AF
	PUSH	BC
	CALL	PC_SPACE
	CALL	PC_LBKT
	;LD	C,IDE_REG_CMD
	LD	A,(IY+IDE_IOBASE)
	ADD	A,IDE_REG_CMD
	LD	C,A
	LD	B,7
IDE_REGDUMP1:
	EZ80_IO
	IN	A,(C)
	CALL	PRTHEXBYTE
	DEC	C
	DEC	B
	CALL	NZ,PC_SPACE
	JR	NZ,IDE_REGDUMP1
	CALL	PC_RBKT
	POP	BC
	POP	AF
	RET
;
; PRINT DIAGNONSTIC PREFIX
;
IDE_PRTPREFIX:
	PUSH	AF
	CALL	NEWLINE
	PRTS("IDE$")
	LD	A,(IY+IDE_DEV)		; GET CURRENT DEVICE NUM
	CP	$FE			; NOT YET ASSIGNED?
	JR	Z,IDE_PRTPREFIX1	; SKIP DEV NUM IF SO
	CALL	PRTDECB
IDE_PRTPREFIX1:
	CALL	PC_COLON
	POP	AF
	RET
;
;=============================================================================
; STRING DATA
;=============================================================================
;
IDE_STR_STOK		.TEXT	"OK$"
IDE_STR_STINVUNIT	.TEXT	"INVALID UNIT$"
IDE_STR_STNOMEDIA	.TEXT	"NO MEDIA$"
IDE_STR_STCMDERR	.TEXT	"COMMAND ERROR$"
IDE_STR_STIOERR		.TEXT	"IO ERROR$"
IDE_STR_STRDYTO		.TEXT	"READY TIMEOUT$"
IDE_STR_STDRQTO		.TEXT	"DRQ TIMEOUT$"
IDE_STR_STBSYTO		.TEXT	"BUSY TIMEOUT$"
IDE_STR_STNOTSUP	.TEXT	"NOT SUPPORTED$"
IDE_STR_STNOTRDY	.TEXT	"NOT READY$"
IDE_STR_STUNK		.TEXT	"UNKNOWN ERROR$"
;
IDE_STR_NO		.TEXT	"NO$"
IDE_STR_NOHW		.TEXT	"NOT PRESENT$"
IDE_STR_8BIT		.TEXT	" 8-BIT$"
;
IDE_STR_MODE_DIO	.TEXT	"DIO$"
IDE_STR_MODE_DIDE	.TEXT	"DIDE$"
IDE_STR_MODE_MK4	.TEXT	"MK4$"
IDE_STR_MODE_RC		.TEXT	"RC$"
IDE_STR_MODE_GIDE	.TEXT	"GIDE$"
;
IDE_STR_TYPEATA		.TEXT	" ATA$"
IDE_STR_TYPEATAPI	.TEXT	" ATAPI$"
;
;=============================================================================
; DATA STORAGE
;=============================================================================
;
IDE_TIMEOUT	.DB	IDE_TONORM	; WAIT FUNCS TIMEOUT IN TENTHS OF SEC
IDE_TOSCALER	.DW	CPUMHZ * 556	; WAIT FUNCS SCALER FOR CPU SPEED
;
IDE_CMD		.DB	0		; PENDING COMMAND TO PROCESS
IDE_IOFNADR	.DW	0		; PENDING IO FUNCTION ADDRESS
IDE_DRVHD	.DB	0		; CURRENT DRIVE/HEAD MASK
;
IDE_DSKBUF	.DW	0		; ACTIVE DISK BUFFER
IDE_XFRDIR	.DB	0		; 0=READ, NON-0=WRITE
;
IDE_DEVNUM	.DB	0		; TEMP DEVICE NUM USED DURING INIT
;
; SCSI COMMAND TEMPLATES (ALWAYS 12 BYTES FOR ATAPI)
;
IDE_PKTCMD_RW		.DB	$00, $00, $00, $00, $01, $00, $00, $00, $00, $00, $00, $00	; READ/WRITE SECTOR
IDE_PKTCMD_SENSE	.DB	$03, $00, $00, $00, $FF, $00, $00, $00, $00, $00, $00, $00	; REQUEST SENSE DATA
IDE_PKTCMD_RDCAP	.DB	$25, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00	; READ CAPACITY
IDE_PKTCMD_RW10		.DB	$28, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00	; READ/WRITE SECTOR
IDE_PKTCMD_TSTRDY	.DB	$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00	; TEST UNIT READY
