;
;=============================================================================
;   PPIDE DISK DRIVER
;=============================================================================
;
; TODO:
; - GOPARTNER NEEDS TO HANDLE "NO PARTNER" CONDITION
; - DATA TRANSFERS LIMITED TO 512 BYTES WHICH IS INSUFFICIENT FOR CD=ROM MEDIA
;
; NOTES:
;  - WELL KNOWN PPIDE PORT ADDRESSES:
;      $60 - SBC/ZETA ONBOARD PPI
;      $20 - ECB DISKIO3, RC FAMILY
;      $44 - ECB MULTI-FUNCTION PIC
;      $80 - N8 ONBOARD PPI
;      $4C - DYNO ONBOARD PPI
;
; THE CONTROL PORT OF THE 8255 IS PROGRAMMED AS NEEDED TO READ OR WRITE
; DATA ON THE IDE BUS.	PORT C OF THE 8255 IS ALWAYS IN OUTPUT MODE BECAUSE
; IT IS DRIVING THE ADDRESS BUS AND CONTROL SIGNALS.  PORTS A & B WILL BE
; PLACED IN READ OR WRITE MODE DEPENDING ON THE DIRECTION OF THE DATA BUS.
;
PPIDE_DIR_READ	.EQU	%10010010	; IDE BUS DATA INPUT MODE
PPIDE_DIR_WRITE	.EQU	%10000000	; IDE BUS DATA OUTPUT MODE
;
; PORT C OF THE 8255 IS USED TO DRIVE THE IDE INTERFACE ADDRESS BUS
; AND VARIOUS CONTROL SIGNALS.	THE CONSTANTS BELOW REFLECT THESE
; ASSIGNMENTS.
;
PPIDE_CTL_DA0	.EQU	%00000001	; DRIVE ADDRESS BUS - BIT 0 (DA0)
PPIDE_CTL_DA1	.EQU	%00000010	; DRIVE ADDRESS BUS - BIT 1 (DA1)
PPIDE_CTL_DA2	.EQU	%00000100	; DRIVE ADDRESS BUS - BIT 2 (DA2)
PPIDE_CTL_CS1	.EQU	%00001000	; DRIVE CHIP SELECT 0 (ACTIVE LOW, INVERTED)
PPIDE_CTL_CS3	.EQU	%00010000	; DRIVE CHIP SELECT 1 (ACTIVE LOW, INVERTED)
PPIDE_CTL_DIOW	.EQU	%00100000	; DRIVE I/O WRITE (ACTIVE LOW, INVERTED)
PPIDE_CTL_DIOR	.EQU	%01000000	; DRIVE I/O READ (ACTIVE LOW, INVERTED)
PPIDE_CTL_RESET	.EQU	%10000000	; DRIVE RESET (ACTIVE LOW, INVERTED)
;
;	+-----------------------------------------------------------------------+
;	| CONTROL BLOCK REGISTERS (CS3FX)					|
;	+-----------------------+-------+-------+-------------------------------+
;	| REGISTER		| PORT	| DIR	| DESCRIPTION			|
;	+-----------------------+-------+-------+-------------------------------+
;	| PPIDE_REG_ALTSTAT	| 0x06	| R	| ALTERNATE STATUS REGISTER	|
;	| PPIDE_REG_CTRL	| 0x06	| W	| DEVICE CONTROL REGISTER	|
;	| PPIDE_REG_DRVADR	| 0x07	| R	| DRIVE ADDRESS REGISTER	|
;	+-----------------------+-------+-------+-------------------------------+
;
;	+-----------------------+-------+-------+-------------------------------+
;	| COMMAND BLOCK REGISTERS (CS1FX)					|
;	+-----------------------+-------+-------+-------------------------------+
;	| REGISTER		| PORT	| DIR	| DESCRIPTION			|
;	+-----------------------+-------+-------+-------------------------------+
;	| PPIDE_REG_DATA	| 0x00	| R/W	| DATA INPUT/OUTPUT		|
;	| PPIDE_REG_ERR		| 0x01	| R	| ERROR REGISTER		|
;	| PPIDE_REG_FEAT	| 0x01	| W	| FEATURES REGISTER		|
;	| PPIDE_REG_COUNT	| 0x02	| R/W	| SECTOR COUNT REGISTER		|
;	| PPIDE_REG_SECT	| 0x03	| R/W	| SECTOR NUMBER REGISTER	|
;	| PPIDE_REG_CYLLO	| 0x04	| R/W	| CYLINDER NUM REGISTER (LSB)	|
;	| PPIDE_REG_CYLHI	| 0x05	| R/W	| CYLINDER NUM REGISTER (MSB)	|
;	| PPIDE_REG_DRVHD	| 0x06	| R/W	| DRIVE/HEAD REGISTER		|
;	| PPIDE_REG_LBA0*	| 0x03	| R/W	| LBA BYTE 0 (BITS 0-7)		|
;	| PPIDE_REG_LBA1*	| 0x04	| R/W	| LBA BYTE 1 (BITS 8-15)	|
;	| PPIDE_REG_LBA2*	| 0x05	| R/W	| LBA BYTE 2 (BITS 16-23)	|
;	| PPIDE_REG_LBA3*	| 0x06	| R/W	| LBA BYTE 3 (BITS 24-27)	|
;	| PPIDE_REG_STAT	| 0x07	| R	| STATUS REGISTER		|
;	| PPIDE_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
;
; CONTROL VALUES TO USE WHEN ACCESSING THE VARIOUS IDE DEVICE REGISTERS
;
PPIDE_REG_DATA		.EQU	PPIDE_CTL_CS1 | $00	; DATA INPUT/OUTPUT (R/W)
PPIDE_REG_ERR		.EQU	PPIDE_CTL_CS1 | $01	; ERROR REGISTER (R)
PPIDE_REG_FEAT		.EQU	PPIDE_CTL_CS1 | $01	; FEATURES REGISTER (W)
PPIDE_REG_COUNT		.EQU	PPIDE_CTL_CS1 | $02	; SECTOR COUNT REGISTER (R/W)
PPIDE_REG_SECT		.EQU	PPIDE_CTL_CS1 | $03	; SECTOR NUMBER REGISTER (R/W)
PPIDE_REG_CYLLO		.EQU	PPIDE_CTL_CS1 | $04	; CYLINDER NUM REGISTER (LSB) (R/W)
PPIDE_REG_CYLHI		.EQU	PPIDE_CTL_CS1 | $05	; CYLINDER NUM REGISTER (MSB) (R/W)
PPIDE_REG_DRVHD		.EQU	PPIDE_CTL_CS1 | $06	; DRIVE/HEAD REGISTER (R/W)
PPIDE_REG_LBA0		.EQU	PPIDE_CTL_CS1 | $03	; LBA BYTE 0 (BITS 0-7) (R/W)
PPIDE_REG_LBA1		.EQU	PPIDE_CTL_CS1 | $04	; LBA BYTE 1 (BITS 8-15) (R/W)
PPIDE_REG_LBA2		.EQU	PPIDE_CTL_CS1 | $05	; LBA BYTE 2 (BITS 16-23) (R/W)
PPIDE_REG_LBA3		.EQU	PPIDE_CTL_CS1 | $06	; LBA BYTE 3 (BITS 24-27) (R/W)
PPIDE_REG_BCL		.EQU	PPIDE_CTL_CS1 | $04	; PKT BYTE COUNT LOW (BITS 0-7) (R/W)
PPIDE_REG_BCH		.EQU	PPIDE_CTL_CS1 | $05	; PKT BYTE COUNT HIGH (BITS 8-15) (R/W)
PPIDE_REG_STAT		.EQU	PPIDE_CTL_CS1 | $07	; STATUS REGISTER (R)
PPIDE_REG_CMD		.EQU	PPIDE_CTL_CS1 | $07	; COMMAND REGISTER (EXECUTE) (W)
PPIDE_REG_ALTSTAT	.EQU	PPIDE_CTL_CS3 | $06	; ALTERNATE STATUS REGISTER (R)
PPIDE_REG_CTRL		.EQU	PPIDE_CTL_CS3 | $06	; DEVICE CONTROL REGISTER (W)
PPIDE_REG_DRVADR	.EQU	PPIDE_CTL_CS3 | $07	; DRIVE ADDRESS REGISTER (R)
;
; COMMAND BYTES
;
PPIDE_CMD_NOP		.EQU	$00
PPIDE_CMD_DEVRES	.EQU	$08
PPIDE_CMD_RECAL		.EQU	$10
PPIDE_CMD_READ		.EQU	$20
PPIDE_CMD_WRITE		.EQU	$30
PPIDE_CMD_DEVDIAG	.EQU	$90
PPIDE_CMD_PACKET	.EQU	$A0
PPIDE_CMD_IDPKTDEV	.EQU	$A1
PPIDE_CMD_IDDEV		.EQU	$EC
PPIDE_CMD_SETFEAT	.EQU	$EF
;
; FEATURE BYTES
;
PPIDE_FEAT_ENABLE8BIT	.EQU	$01
PPIDE_FEAT_DISABLE8BIT	.EQU	$81
;
; PPIDE DEVICE TYPES
;
PPIDE_TYPEUNK	.EQU	0
PPIDE_TYPEATA	.EQU	1
PPIDE_TYPEATAPI	.EQU	2
;
; PPIDE DEVICE STATUS CODES
;
PPIDE_STOK	.EQU	0
PPIDE_STINVUNIT	.EQU	-1
PPIDE_STNOMEDIA	.EQU	-2
PPIDE_STCMDERR	.EQU	-3
PPIDE_STIOERR	.EQU	-4
PPIDE_STRDYTO	.EQU	-5
PPIDE_STDRQTO	.EQU	-6
PPIDE_STBSYTO	.EQU	-7
PPIDE_STNOTSUP	.EQU	-8
PPIDE_STNOTRDY	.EQU	-9
;
; DRIVE SELECTION BYTES (FOR USE IN DRIVE/HEAD REGISTER)
;
;PPIDE_DRVSEL:
PPIDE_DRVMASTER	.EQU	%11100000	; LBA, MASTER DEVICE
PPIDE_DRVSLAVE	.EQU	%11110000	; LBA, SLAVE DEVICE
;
; PPIDE DEVICE CONFIGURATION
;
PPIDE_CFGSIZ	.EQU	18		; SIZE OF CFG TBL ENTRIES
;
; PER DEVICE DATA OFFSETS
;
PPIDE_DEV	.EQU	0		; OFFSET OF DEVICE NUMBER (BYTE)
PPIDE_STAT	.EQU	1		; LAST STATUS (BYTE)
PPIDE_TYPE	.EQU	2		; DEVICE TYPE (BYTE)
PPIDE_ACC	.EQU	3		; ACCESS FLAG BITS BIT 0=MASTER, 1=8BIT (BYTE)
PPIDE_MED	.EQU	4		; MEDIA FLAG BITS BIT 0=CF, 1=LBA (BYTE)
PPIDE_MEDCAP	.EQU	5		; MEDIA CAPACITY (DWORD)
PPIDE_LBA	.EQU	9		; OFFSET OF LBA (DWORD)
PPIDE_DATALO	.EQU	13		; BASE PORT AND IDE DATA BUS LSB (8255 PORT A) (BYTE)
PPIDE_CTL	.EQU	14		; IDE ADDRESS BUS AND CONTROL SIGNALS (8255 PORT C)(BYTE)
PPIDE_PPI	.EQU	15		; 8255 CONTROL PORT(BYTE)
PPIDE_PARTNER	.EQU	16		; PARTNER DEVICE (MASTER <-> SLAVE) (WORD)
;
PPIDE_ACC_MAS	.EQU	%00000001	; UNIT IS MASTER (ELSE SLAVE)
PPIDE_ACC_8BIT	.EQU	%00000010	; UNIT WANTS 8 BIT I/O (ELSE 16 BIT)
;
PPIDE_MED_CF	.EQU	%00000001	; MEDIA IS CF CARD
PPIDE_MED_LBA	.EQU	%00000010	; MEDIA HAS LBA CAPABILITY
;
PPIDE_DEVCNT	.EQU	PPIDECNT * 2
;
PPIDE_CFGTBL:
;
#IF (PPIDECNT >= 1)
;
PPIDE_DEV0M:	; DEVICE 0, MASTER
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	PPIDE_ACC_MAS | (PPIDE0A8BIT & PPIDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	PPIDE0BASE  		; DATALO
	.DB	PPIDE0BASE+2		; CTL
	.DB	PPIDE0BASE+3		; PPI
	.DW	PPIDE_DEV0S		; PARTNER
;
	DEVECHO	"PPIDE: IO="
	DEVECHO	PPIDE0BASE
	DEVECHO	", MASTER"
	DEVECHO	"\n"
;
PPIDE_DEV0S:	; DEVICE 0, SLAVE
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	(PPIDE0B8BIT & PPIDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	PPIDE0BASE  		; DATALO
	.DB	PPIDE0BASE+2		; CTL
	.DB	PPIDE0BASE+3		; PPI
	.DW	PPIDE_DEV0M		; PARTNER
;
	DEVECHO	"PPIDE: IO="
	DEVECHO	PPIDE0BASE
	DEVECHO	", SLAVE"
	DEVECHO	"\n"
;
#ENDIF
;
#IF (PPIDECNT >= 2)
;
PPIDE_DEV1M:	; DEVICE 1, MASTER
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	PPIDE_ACC_MAS | (PPIDE1A8BIT & PPIDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	PPIDE1BASE  		; DATALO
	.DB	PPIDE1BASE+2		; CTL
	.DB	PPIDE1BASE+3		; PPI
	.DW	PPIDE_DEV1S		; PARTNER
;
	DEVECHO	"PPIDE: IO="
	DEVECHO	PPIDE1BASE
	DEVECHO	", MASTER"
	DEVECHO	"\n"
;
PPIDE_DEV1S:	; DEVICE 1, SLAVE
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	(PPIDE1B8BIT & PPIDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	PPIDE1BASE  		; DATALO
	.DB	PPIDE1BASE+2		; CTL
	.DB	PPIDE1BASE+3		; PPI
	.DW	PPIDE_DEV1M		; PARTNER
;
	DEVECHO	"PPIDE: IO="
	DEVECHO	PPIDE1BASE
	DEVECHO	", SLAVE"
	DEVECHO	"\n"
;
#ENDIF
;
#IF (PPIDECNT >= 3)
;
PPIDE_DEV2M:	; DEVICE 2, MASTER
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	PPIDE_ACC_MAS | (PPIDE2A8BIT & PPIDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	PPIDE2BASE  		; DATALO
	.DB	PPIDE2BASE+2		; CTL
	.DB	PPIDE2BASE+3		; PPI
	.DW	PPIDE_DEV2S		; PARTNER
;
	DEVECHO	"PPIDE: IO="
	DEVECHO	PPIDE2BASE
	DEVECHO	", MASTER"
	DEVECHO	"\n"
;
PPIDE_DEV2S:	; DEVICE 2, SLAVE
	.DB	$FE			; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
	.DB	0			; DEVICE STATUS
	.DB	0			; DEVICE TYPE
	.DB	(PPIDE2B8BIT & PPIDE_ACC_8BIT)	; UNIT ACCESS FLAGS
	.DB	0			; MEDIA FLAGS
	.DW	0,0			; DEVICE CAPACITY
	.DW	0,0			; CURRENT LBA
	.DB	PPIDE2BASE  		; DATALO
	.DB	PPIDE2BASE+2		; CTL
	.DB	PPIDE2BASE+3		; PPI
	.DW	PPIDE_DEV2M		; PARTNER
;
	DEVECHO	"PPIDE: IO="
	DEVECHO	PPIDE2BASE
	DEVECHO	", SLAVE"
	DEVECHO	"\n"
;
#ENDIF
;
#IF ($ - PPIDE_CFGTBL) != (PPIDE_DEVCNT * PPIDE_CFGSIZ)
	.ECHO	"*** INVALID PPIDE CONFIG TABLE ***\n"
#ENDIF
;
	.DB	$FF			; END OF TABLE MARKER
;
; THE PPIDE_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.
;
PPIDE_TOSLOW	.EQU	200		; SLOW TIMEOUT IS 20 SECS
;PPIDE_TONORM	.EQU	5		; NORMAL TIMEOUT IS 0.5 SECS
PPIDE_TONORM	.EQU	200		; NORMAL TIMEOUT IS 0.5 SECS
;
;=============================================================================
; INITIALIZATION ENTRY POINT
;=============================================================================
;
PPIDE_INIT:
	; COMPUTE CPU SPEED COMPENSATED TIMEOUT SCALER
	; ONE INTERNAL LOOP IN WAITBSY IS 263TS.  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 263 TS, IT TAKES 100000 / 263 = 356
	; INTERNAL LOOPS FOR 1/10 SECOND.  SO, WE WANT TO USE
	; 356 * CPU MHZ FOR INTERNAL LOOP COUNT.
	LD	DE,380			; LOAD SCALER FOR 1MHZ
	LD	A,(CB_CPUMHZ)		; LOAD CPU SPEED IN MHZ
	CALL	MULT8X16		; HL := DE * A
	LD	(PPIDE_TOSCALER),HL	; SAVE IT
;
	XOR	A			; ZERO ACCUM
	LD	(PPIDE_DEVNUM),A	; INIT DEV UNIT NUM FOR DYNAMIC ASSIGNMENT
	LD	IY,PPIDE_CFGTBL		; POINT TO START OF CONFIG TABLE
;
PPIDE_INIT1:
	LD	A,(IY)			; LOAD FIRST BYTE TO CHECK FOR END
	CP	$FF			; CHECK FOR END OF TABLE VALUE
	JR	NZ,PPIDE_INIT2		; IF NOT END OF TABLE, CONTINUE
	XOR	A			; SIGNAL SUCCESS
	RET				; AND RETURN
;
PPIDE_INIT2:
	BIT	0,(IY+PPIDE_ACC)	; MASTER?
	JR	Z,PPIDE_INIT4		; IF NOT MASTER, SKIP AHEAD
;
	CALL	NEWLINE			; FORMATTING
	PRTS("PPIDE:$")			; LABEL FOR IO ADDRESS
;
	PRTS(" IO=0x$")			; LABEL FOR IO ADDRESS
	LD	A,(IY+PPIDE_DATALO)	; GET IO BASE ADDRES
	CALL	PRTHEXBYTE		; DISPLAY IT
;
	CALL	PPIDE_DETECT		; PROBE FOR INTERFACE
	JR	Z,PPIDE_INIT3		; GOT IT, MOVE ON TO INIT UNITS
	CALL	PC_SPACE		; FORMATTING
	LD	DE,PPIDE_STR_NOPPI	; NO PPI MESSAGE
	CALL	WRITESTR		; DISPLAY IT
	JR	PPIDE_INIT4		; SKIP CFG ENTRY
;
PPIDE_INIT3:
	CALL	PPIDE_RESET		; RESET THE BUS
	CALL	PPIDE_INIT5		; DETECT/INIT MASTER
	PUSH	IY			; SAVE CFG PTR
	CALL	PPIDE_GOPARTNER		; SWITCH IY TO PARTNER CFG
	CALL	PPIDE_INIT5		; DETECT/INIT SLAVE
	POP	IY			; RESTORE CFG PTR
;
PPIDE_INIT4:
	LD	DE,PPIDE_CFGSIZ		; SIZE OF CFG TABLE ENTRY
	ADD	IY,DE			; BUMP POINTER
	JR	PPIDE_INIT1		; AND LOOP
;
PPIDE_INIT5:
	; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
	LD	A,(PPIDE_DEVNUM)	; GET NEXT UNIT NUM TO ASSIGN
	LD	(IY+PPIDE_DEV),A	; UPDATE IT
	INC	A			; BUMP TO NEXT UNIT NUM TO ASSIGN
	LD	(PPIDE_DEVNUM),A	; SAVE IT
;
	; ADD UNIT TO GLOBAL DISK UNIT TABLE
	LD	BC,PPIDE_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	PPIDE_PRTPREFIX		; PRINT DEVICE PREFIX
	LD	A,(IY+PPIDE_TYPE)
	LD	DE,PPIDE_STR_TYPEATA
	CP	PPIDE_TYPEATA
	CALL	Z,WRITESTR
	LD	DE,PPIDE_STR_TYPEATAPI
	CP	PPIDE_TYPEATAPI
	CALL	Z,WRITESTR
;
	; CHECK FOR BAD STATUS
	LD	A,(IY+PPIDE_STAT)	; GET STATUS
	OR	A			; SET FLAGS
	JP	Z,PPIDE_INIT6
	CALL	PC_SPACE
	JP	NZ,PPIDE_PRTSTATSTR	; EXIT VIA PRINT STATUS STRING
;
PPIDE_INIT6:
	LD	DE,PPIDE_STR_8BIT
	BIT	1,(IY+PPIDE_ACC)	; 8 BIT ACCESS?
	CALL	NZ,WRITESTR
;
	; PRINT LBA/NOLBA
	CALL	PC_SPACE		; FORMATTING
	BIT	1,(IY+PPIDE_MED)	; TEST LBA FLAG
	LD	DE,PPIDE_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,PPIDE_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 PPI HARDWARE
;----------------------------------------------------------------------
;
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
;
PPIDE_DETECT:
;
	; TEST FOR PPI EXISTENCE
	; WE SETUP THE PPI TO WRITE, THEN WRITE A VALUE OF $A5
	; TO PORT A (DATALO), THEN READ IT BACK.  IF THE PPI IS THERE
	; THEN THE BUS HOLD CIRCUITRY WILL READ BACK THE $A5. SINCE
	; WE ARE IN WRITE MODE, AN IDE CONTROLLER WILL NOT BE ABLE TO
	; INTERFERE WITH THE VALUE BEING READ.
;
	LD	A,PPIDE_DIR_WRITE	; SET DATA BUS DIRECTION TO WRITE
	LD	C,(IY+PPIDE_PPI)	; PPI CONTROL WORD
	EZ80_IO
	OUT	(C),A			; WRITE IT
;
	LD	C,(IY+PPIDE_DATALO)	; PPI PORT A, DATALO
	LD	A,$A5			; TEST VALUE
	EZ80_IO
	OUT	(C),A			; PUSH VALUE TO PORT
	EZ80_IO
	IN	A,(C)			; GET PORT VALUE
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CP	$A5			; CHECK FOR TEST VALUE
	RET				; AND RETURN
;
;=============================================================================
; DRIVER FUNCTION TABLE
;=============================================================================
;
PPIDE_FNTBL:
	.DW	PPIDE_STATUS
	.DW	PPIDE_RESET
	.DW	PPIDE_SEEK
	.DW	PPIDE_READ
	.DW	PPIDE_WRITE
	.DW	PPIDE_VERIFY
	.DW	PPIDE_FORMAT
	.DW	PPIDE_DEVICE
	.DW	PPIDE_MEDIA
	.DW	PPIDE_DEFMED
	.DW	PPIDE_CAP
	.DW	PPIDE_GEOM
#IF (($ - PPIDE_FNTBL) != (DIO_FNCNT * 2))
	.ECHO	"*** INVALID PPIDE FUNCTION TABLE ***\n"
#ENDIF
;
PPIDE_VERIFY:
PPIDE_FORMAT:
PPIDE_DEFMED:
	SYSCHKERR(ERR_NOTIMPL)		; NOT IMPLEMENTED
	RET
;
;
;
PPIDE_READ:
	CALL	HB_DSKREAD		; HOOK HBIOS DISK READ SUPERVISOR
	LD	BC,PPIDE_RDSEC		; GET ADR OF SECTOR READ FUNC
	LD	(PPIDE_IOFNADR),BC	; SAVE IT AS PENDING IO FUNC
	JR	PPIDE_IO		; CONTINUE TO GENERIC IO ROUTINE
;
;
;
PPIDE_WRITE:
	CALL	HB_DSKWRITE		; HOOK HBIOS DISK WRITE SUPERVISOR
	LD	BC,PPIDE_WRSEC		; GET ADR OF SECTOR WRITE FUNC
	LD	(PPIDE_IOFNADR),BC	; SAVE IT AS PENDING IO FUNC
	JR	PPIDE_IO		; CONTINUE TO GENERIC IO ROUTINE
;
;
;
PPIDE_IO:
	LD	(PPIDE_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 (PPIDETRACE == 1)
	LD	HL,PPIDE_PRTERR		; SET UP PPIDE_PRTERR
	PUSH	HL			; ... TO FILTER ALL EXITS
#ENDIF
	PUSH	BC			; SAVE COUNTERS
	CALL	PPIDE_CHKERR		; CHECK FOR ERR STATUS AND RESET IF SO
	POP	BC			; RESTORE COUNTERS
	JR	NZ,PPIDE_IO3		; BAIL OUT ON ERROR
PPIDE_IO1:
	PUSH	BC			; SAVE COUNTERS
	CALL	PPIDE_SELUNIT		; HARDWARE SELECTION OF TARGET UNIT
	LD	HL,(PPIDE_IOFNADR)	; GET PENDING IO FUNCTION ADDRESS
	CALL	JPHL			; ... AND CALL IT
	JR	NZ,PPIDE_IO2		; IF ERROR, SKIP INCREMENT
	; INCREMENT LBA
	LD	A,PPIDE_LBA		; LBA OFFSET
	CALL	LDHLIYA			; HL := IY + A, REG A TRASHED
	CALL	INC32HL			; INCREMENT THE VALUE
	; INCREMENT DMA
	LD	HL,PPIDE_DSKBUF+1	; POINT TO MSB OF BUFFER ADR
	INC	(HL)			; BUMP DMA BY
	INC	(HL)			; ... 512 BYTES
	XOR	A			; SIGNAL SUCCESS
PPIDE_IO2:
	POP	BC			; RECOVER COUNTERS
	JR	NZ,PPIDE_IO3		; IF ERROR, BAIL OUT
	INC	C			; BUMP COUNT OF SECTORS READ
	DJNZ	PPIDE_IO1		; LOOP AS NEEDED
PPIDE_IO3:
	LD	E,C			; SECTOR READ COUNT TO E
	LD	HL,(PPIDE_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
;
;
;
PPIDE_STATUS:
	; RETURN UNIT STATUS
	LD	A,(IY+PPIDE_STAT)	; GET STATUS OF SELECTED DEVICE
	OR	A			; SET FLAGS
	RET				; AND RETURN
;
;
;
PPIDE_DEVICE:
	LD	D,DIODEV_PPIDE		; D := DEVICE TYPE
	LD	E,(IY+PPIDE_DEV)	; E := PHYSICAL DEVICE NUMBER
	LD	C,%01111001		; ATAPI ATTRIBUTES
	LD	A,(IY+PPIDE_TYPE)	; CHECK TYPE VALUE
	CP	PPIDE_TYPEATAPI		; ATAPI?
	JR	Z,PPIDE_DEVICE1		; IF SO, DONE
	LD	C,%00110001		; COMPACTFLASH ATTRIBUTES
	BIT	0,(IY+PPIDE_MED)	; TEST CF BIT IN FLAGS
	JR	NZ,PPIDE_DEVICE1	; IF SET, DONE
	LD	C,%00110000		; GENERIC HARD DISK ATTRIBUTES
PPIDE_DEVICE1:
	LD	H,0			; H := 0, DRIVER HAS NO MODES
	LD	L,(IY+PPIDE_DATALO)	; L := BASE I/O ADDRESS
	XOR	A			; SIGNAL SUCCESS
	RET
;
; IDE_GETMED
;
PPIDE_MEDIA:
	LD	A,E			; GET FLAGS
	OR	A			; SET FLAGS
	JR	Z,PPIDE_MEDIA1		; JUST REPORT CURRENT STATUS AND MEDIA
;
	;CALL	PPIDE_RESET		; RESET IDE INTERFACE
	CALL	PPIDE_INITUNIT		; RE-INITIALIZE UNIT
;
PPIDE_MEDIA1:
	LD	A,(IY+PPIDE_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
;
;
;
PPIDE_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+PPIDE_LBA+0),L	; SAVE NEW LBA
	LD	(IY+PPIDE_LBA+1),H	; ...
	LD	(IY+PPIDE_LBA+2),E	; ...
	LD	(IY+PPIDE_LBA+3),D	; ...
	XOR	A			; SIGNAL SUCCESS
	RET				; AND RETURN
;
;
;
PPIDE_CAP:
	LD	A,(IY+PPIDE_STAT)	; GET STATUS
	PUSH	AF			; SAVE IT
	LD	A,PPIDE_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
;
;
;
PPIDE_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	PPIDE_CAP		; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC
	LD	L,H			; DIVPPIDE 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 PPIDE_CAP STATUS
;
;=============================================================================
; FUNCTION SUPPORT ROUTINES
;=============================================================================
;
PPIDE_SETFEAT:
	PUSH	AF
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" SETFEAT$")
#ENDIF
	LD	A,(PPIDE_DRVHD)
	;OUT	(PPIDE_REG_DRVHD),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	POP	AF
	;OUT	(PPIDE_REG_FEAT),A	; SET THE FEATURE VALUE
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_FEAT
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,PPIDE_CMD_SETFEAT	; CMD = SETFEAT
	LD	(PPIDE_CMD),A		; SAVE IT
	JP	PPIDE_RUNCMD		; RUN COMMAND AND EXIT
;
;
;
PPIDE_IDENTIFY:
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" IDDEV$")
#ENDIF
	LD	A,(PPIDE_DRVHD)
	;OUT	(PPIDE_REG_DRVHD),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,PPIDE_CMD_IDDEV
	LD	(PPIDE_CMD),A
	CALL	PPIDE_RUNCMD_ND
	RET	NZ
;
	CALL	PPIDE_IN
	.DB	PPIDE_REG_STAT
	BIT	3,A			; IS DRQ SET?
	JP	Z,PPIDE_NOMEDIA
;
	LD	HL,HB_WRKBUF
	JP	PPIDE_GETBUF		; EXIT THRU BUFRD
;
;
;
PPIDE_IDENTIFYPACKET:
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" IDPKTDEV$")
#ENDIF
	LD	A,(PPIDE_DRVHD)
	;OUT	(PPIDE_REG_DRVHD),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,PPIDE_CMD_IDPKTDEV
	LD	(PPIDE_CMD),A
	CALL	PPIDE_RUNCMD_ND
	RET	NZ
;
	CALL	PPIDE_IN
	.DB	PPIDE_REG_STAT
	BIT	3,A			; IS DRQ SET?
	JP	Z,PPIDE_NOMEDIA
;
	LD	HL,HB_WRKBUF
	JP	PPIDE_GETBUF		; EXIT THRU BUFRD
;
;
;
PPIDE_PACKET:
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" PACKET$")
#ENDIF
	LD	A,(PPIDE_DRVHD)
	;OUT	(PPIDE_REG_DRVHD),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	XOR	A			; ZERO
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_FEAT		; FEATURE REG = 0
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_BCL
	LD	A,8
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_BCH		; BYTE COUNT = 512????
	LD	A,PPIDE_CMD_PACKET
	LD	(PPIDE_CMD),A
	JP	PPIDE_RUNCMD_ND
;
;
;
PPIDE_RDSEC:
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" READ$")
#ENDIF
	LD	A,(PPIDE_DRVHD)
	;OUT	(PPIDE_REG_DRVHD),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,(IY+PPIDE_TYPE)
	CP	PPIDE_TYPEATA
	JR	Z,PPIDE_ATA_RDSEC
	CP	PPIDE_TYPEATAPI
	JR	Z,PPIDE_PKT_RDSEC
	JP	PPIDE_CMDERR
;
PPIDE_ATA_RDSEC:
#IF (PPIDETRACE >= 3)
	PRTS(" ATA$")
#ENDIF
	CALL	PPIDE_SETADDR		; SETUP CYL, TRK, HEAD
	LD	A,PPIDE_CMD_READ
	LD	(PPIDE_CMD),A
	CALL	PPIDE_RUNCMD
	RET	NZ
	LD	HL,(PPIDE_DSKBUF)
	JP	PPIDE_GETBUF
;
PPIDE_PKT_RDSEC:
#IF (PPIDETRACE >= 3)
	PRTS(" PKT$")
#ENDIF
	; SETUP LBA
;
;;;#IF (DSKYENABLE)
;;;  #IF (DSKYDSKACT)
	LD	A,PPIDE_LBA
	CALL	LDHLIYA
	CALL	HB_DSKACT		; SHOW ACTIVITY
;;;  #ENDIF
;;;#ENDIF
;
	; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
	LD	HL,PPIDE_PKTCMD_RW10+3	; START OF LBA FIELD IN CDB (MSB)
	LD	A,(IY+PPIDE_LBA+2)	; THIRD BYTE OF LBA FIELD IN CFG (MSB)
	LD	(HL),A
	INC	HL
	LD	A,(IY+PPIDE_LBA+1)
	LD	(HL),A
	INC	HL
	LD	A,(IY+PPIDE_LBA+0)
	LD	(HL),A
	INC	HL
	LD	HL,PPIDE_PKTCMD_RW10
	LD	A,SCSI_CMD_READ10
	LD	(HL),A
	XOR	A			; READ DIRECTION
	LD	(PPIDE_XFRDIR),A	; SAVE IT
	CALL	PPIDE_RUNPCMD
	JP	NZ,PPIDE_CHKPCMD
	RET
;
;
;
PPIDE_WRSEC:
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" WRITE$")
#ENDIF
	LD	A,(PPIDE_DRVHD)
	;OUT	(PPIDE_REG_DRVHD),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	LD	A,(IY+PPIDE_TYPE)
	CP	PPIDE_TYPEATA
	JR	Z,PPIDE_ATA_WRSEC
	CP	PPIDE_TYPEATAPI
	JR	Z,PPIDE_PKT_WRSEC
	JP	PPIDE_CMDERR
;
PPIDE_ATA_WRSEC:
#IF (PPIDETRACE >= 3)
	PRTS(" ATA$")
#ENDIF
	CALL	PPIDE_SETADDR		; SETUP CYL, TRK, HEAD
	LD	A,PPIDE_CMD_WRITE
	LD	(PPIDE_CMD),A
	CALL	PPIDE_RUNCMD
	RET	NZ
	LD	HL,(PPIDE_DSKBUF)
	JP	PPIDE_PUTBUF
;
PPIDE_PKT_WRSEC:
#IF (PPIDETRACE >= 3)
	PRTS(" PKT$")
#ENDIF
	; SETUP LBA
;
;;;#IF (DSKYENABLE)
;;;  #IF (DSKYDSKACT)
	LD	A,PPIDE_LBA
	CALL	LDHLIYA
	CALL	HB_DSKACT		; SHOW ACTIVITY
;;;  #ENDIF
;;;#ENDIF
;
	; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
	LD	HL,PPIDE_PKTCMD_RW10+3	; START OF LBA FIELD IN CDB (MSB)
	LD	A,(IY+PPIDE_LBA+2)	; THIRD BYTE OF LBA FIELD IN CFG (MSB)
	LD	(HL),A
	INC	HL
	LD	A,(IY+PPIDE_LBA+1)
	LD	(HL),A
	INC	HL
	LD	A,(IY+PPIDE_LBA+0)
	LD	(HL),A
	INC	HL
	LD	HL,PPIDE_PKTCMD_RW10
	LD	A,SCSI_CMD_WRITE10
	LD	(HL),A
	OR	$FF			; WRITE DIRECTION
	LD	(PPIDE_XFRDIR),A	; SAVE IT
	CALL	PPIDE_RUNPCMD
	JP	NZ,PPIDE_CHKPCMD
	RET
;
;
;
PPIDE_SETADDR:
;
;;;#IF (DSKYENABLE)
;;;  #IF (DSKYDSKACT)
	LD	A,PPIDE_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+PPIDE_LBA+2)
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_LBA2
;
	LD	A,(IY+PPIDE_LBA+1)
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_LBA1
;
	LD	A,(IY+PPIDE_LBA+0)
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_LBA0
;
	LD	A,1
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	PPIDE_OUT
	.DB	PPIDE_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.
;
PPIDE_RUNCMD_ND:
	CALL	PPIDE_WAITBSY		; WAIT WHILE DEVICE BUSY
	RET	NZ			; BAIL OUT ON TIMEOUT
	JR	PPIDE_RUNCMD1		; CONTINUE

PPIDE_RUNCMD:
	CALL	PPIDE_WAITRDY		; WAIT FOR DRIVE READY
	RET	NZ			; BAIL OUT ON TIMEOUT
;
PPIDE_RUNCMD1:
	LD	A,(PPIDE_CMD)		; GET THE COMMAND
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	;OUT	(PPIDE_REG_CMD),A	; SEND IT (STARTS EXECUTION)
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_CMD
#IF (PPIDETRACE >= 3)
	PRTS(" -->$")
#ENDIF
;
	CALL	PPIDE_WAITBSY		; WAIT FOR DRIVE READY (COMMAND DONE)
	RET	NZ			; BAIL OUT ON TIMEOUT
;
	CALL	PPIDE_GETRES
	JP	NZ,PPIDE_CMDERR
	RET
;
; PACKET COMMAND PROCESSOR
; HL: ADDRESS OF PACKET COMMAND BUFFER
;
PPIDE_RUNPCMD:
	PUSH	HL
	CALL	PPIDE_PACKET
	POP	HL
	RET	NZ			; BAIL OUT ON ERROR
;
#IF (PPIDETRACE >= 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,(PPIDE_TIMEOUT)	; GET CURRENT TIMEOUT
	PUSH	DE			; SAVE IT
	LD	DE,PPIDE_TOSLOW		; SLOW TIMEOUT FOR THIS
	LD	(PPIDE_TIMEOUT),DE	; SET IT
	LD	B,6			; 6 WORDS ALWAYS
	CALL	PPIDE_PUT
	POP	DE			; RECOVER TIMEOUT
	LD	(PPIDE_TIMEOUT),DE	; SET IT
	RET	NZ
;
	CALL	PPIDE_IN
	.DB	PPIDE_REG_STAT
	BIT	3,A			; IS DRQ SET?
	RET	Z			; IF NOT, ALL DONE
;
	CALL	PPIDE_IN
	.DB	PPIDE_REG_BCL
	LD	C,A
	CALL	PPIDE_IN
	.DB	PPIDE_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,(PPIDE_DSKBUF)	; SET XFR BUFFER
	
	LD	A,(PPIDE_XFRDIR)
	OR	A
	JR	NZ,PPIDE_RUNPCMD2	; NZ = WRITE
	CALL	PPIDE_GET		; GET SOME DATA
	JR	PPIDE_RUNPCMD3
PPIDE_RUNPCMD2:
	CALL	PPIDE_PUT		; PUT SOME DATA
PPIDE_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.
;
PPIDE_CHKPCMD:
;
	LD	HL,HB_WRKBUF
	LD	(PPIDE_DSKBUF),HL
	LD	HL,PPIDE_PKTCMD_SENSE
	CALL	PPIDE_RUNPCMD
	RET	NZ
;
	CALL	PPIDE_IN
	.DB	PPIDE_REG_BCL
;
#IF (PPIDETRACE >= 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,PPIDE_NOMEDIA
	CP	$04
	JP	Z,PPIDE_NOTRDY
;
	JP	PPIDE_CMDERR
;
; HL=BUFFER
;
PPIDE_GETBUF:
	LD	B,0
	; FALL THRU!!!
;
; HL=BUFFER
; B=WORD COUNT, 0=256
;
PPIDE_GET:
#IF (PPIDETRACE >= 3)
	PRTS(" GET$")
#ENDIF
;
	; WAIT FOR BUFFER
	PUSH	BC
	PUSH	HL
	CALL	PPIDE_WAITDRQ		; WAIT FOR BUFFER READY
	POP	HL
	POP	BC
	RET	NZ			; BAIL OUT IF TIMEOUT
;
	; SETUP PPI TO READ
	LD	A,PPIDE_DIR_READ	; SET DATA BUS DIRECTION TO READ
	;OUT	(PPIDE_REG_PPI),A	; DO IT
	LD	C,(IY+PPIDE_PPI)	; PPI CONTROL WORD
	EZ80_IO
	OUT	(C),A			; WRITE IT
;
	; SELECT READ/WRITE IDE REGISTER
	LD	A,PPIDE_REG_DATA	; DATA REGISTER
	;OUT	(PPIDE_REG_CTL),A	; DO IT
	LD	C,(IY+PPIDE_CTL)	; SET IDE ADDRESS
	EZ80_IO
	OUT	(C),A			; DO IT
	LD	E,A			; E := READ UNASSERTED
	XOR	PPIDE_CTL_DIOR		; SWAP THE READ LINE BIT
	LD	D,A			; D := READ ASSERTED
;
	LD	A,B			; LOOP COUNTER IN A
	LD	C,(IY+PPIDE_CTL)	; SET IDE ADDRESS
	BIT	1,(IY+PPIDE_ACC)	; 8 BIT?
	JR	Z,PPIDE_GET1		; IF NOT, DO 16 BIT
	CALL	PPIDE_GET8		; 8-BIT READ
	JR	PPIDE_GET2		; CONTINUE
PPIDE_GET1:
	CALL	PPIDE_GET16		; 16-0BIT READ
PPIDE_GET2:
	CALL	PPIDE_WAITRDY		; PROBLEMS IF THIS IS REMOVED!
	RET	NZ
	CALL	PPIDE_GETRES
	JP	NZ,PPIDE_IOERR
	RET
;
PPIDE_GET8:	; 8 BIT WIDE READ LOOP
	; ENTER W/ C = PPIDE_REG_CTL
	EZ80_IO
	OUT	(C),D			; ASSERT READ
	DEC	C			; CTL -> MSB
	DEC	C			; MSB -> LSB
	EZ80_IO
	INI				; READ FROM LSB
	INC	C			; LSB -> MSB
	INC	C			; MSB -> CTL
	EZ80_IO
	OUT	(C),E			; DEASSERT READ
	EZ80_IO
	OUT	(C),D			; ASSERT READ
	DEC	C			; CTL -> MSB
	DEC	C			; MSB -> LSB
	EZ80_IO
	INI				; READ FROM LSB
	INC	C			; LSB -> MSB
	INC	C			; MSB -> CTL
	EZ80_IO
	OUT	(C),E			; DEASSERT READ
	DEC	A
	JR	NZ,PPIDE_GET8		; LOOP UNTIL DONE
	RET
;
PPIDE_GET16:	; 16 BIT WIDE READ LOOP
	; ENTER W/ C = PPIDE_REG_CTL
	EZ80_IO
	OUT	(C),D			; ASSERT READ
	DEC	C			; CTL -> MSB
	DEC	C			; MSB -> LSB
	EZ80_IO
	INI				; READ FROM LSB
	INC	C			; LSB -> MSB
	EZ80_IO
	INI				; READ MSB FOR 16 BIT
	INC	C			; MSB -> CTL
	EZ80_IO
	OUT	(C),E			; DEASSERT READ
	DEC	A
	JR	NZ,PPIDE_GET16		; LOOP UNTIL DONE
	RET
;
; HL=BUFFER
;
PPIDE_PUTBUF:
	LD	B,0
	; FALL THRU!!!
;
; HL=BUFFER
; B=WORD COUNT, 0=256
;
PPIDE_PUT:
#IF (PPIDETRACE >= 3)
	PRTS(" PUT$")
#ENDIF
;
	; WAIT FOR BUFFER
	PUSH	BC
	PUSH	HL
	CALL	PPIDE_WAITDRQ		; WAIT FOR BUFFER READY
	POP	HL
	POP	BC
	RET	NZ			; BAIL OUT IF TIMEOUT
;
	; SETUP PPI TO WRITE
	LD	A,PPIDE_DIR_WRITE	; SET DATA BUS DIRECTION TO WRITE
	;OUT	(PPIDE_REG_PPI),A	; DO IT
	LD	C,(IY+PPIDE_PPI)	; PPI CONTROL WORD
	EZ80_IO
	OUT	(C),A			; WRITE IT
;
	; SELECT READ/WRITE IDE REGISTER
	LD	A,PPIDE_REG_DATA	; DATA REGISTER
	;OUT	(PPIDE_REG_CTL),A	; DO IT
	LD	C,(IY+PPIDE_CTL)	; SET IDE ADDRESS
	EZ80_IO
	OUT	(C),A			; DO IT
	LD	E,A			; E := WRITE UNASSERTED
	XOR	PPIDE_CTL_DIOW		; SWAP THE READ LINE BIT
	LD	D,A			; D := WRITE ASSERTED
;
	; LOOP SETUP
	LD	A,B			; LOOP COUNTER IN A
	LD	C,(IY+PPIDE_CTL)	; SET IDE ADDRESS
	BIT	1,(IY+PPIDE_ACC)	; 8 BIT?
	JR	Z,PPIDE_PUT1		; IF NOT, DO 16 BIT
	CALL	PPIDE_PUT8		; SECOND PASS (LAST 256 BYTES)
	JR	PPIDE_PUT2		; CONTINUE
PPIDE_PUT1:
	CALL	PPIDE_PUT16		; FIRST PASS (FIRST 256 BYTES)
PPIDE_PUT2:
	CALL	PPIDE_WAITRDY		; PROBLEMS IF THIS IS REMOVED!
	RET	NZ
	CALL	PPIDE_GETRES
	JP	NZ,PPIDE_IOERR
	RET
;
PPIDE_PUT8:	; 8 BIT WIDE WRITE LOOP
	DEC	C			; CTL -> MSB
	DEC	C			; MSB -> LSB
	EZ80_IO
	OUTI				; WRITE NEXT BYTE (LSB)
	INC	C			; LSB -> MSB
	INC	C			; MSB -> CTL
	EZ80_IO
	OUT	(C),D			; ASSERT WRITE
	EZ80_IO
	OUT	(C),E			; DEASSERT WRITE
	DEC	C			; CTL -> MSB
	DEC	C			; MSB -> LSB
	EZ80_IO
	OUTI				; WRITE NEXT BYTE (LSB)
	INC	C			; LSB -> MSB
	INC	C			; MSB -> CTL
	EZ80_IO
	OUT	(C),D			; ASSERT WRITE
	EZ80_IO
	OUT	(C),E			; DEASSERT WRITE
	DEC	A
	JR	NZ,PPIDE_PUT8		; LOOP UNTIL DONE
	RET
;
PPIDE_PUT16:	; 16 BIT WIDE WRITE LOOP
	DEC	C			; CTL -> MSB
	DEC	C			; MSB -> LSB
	EZ80_IO
	OUTI				; WRITE NEXT BYTE (LSB)
	INC	C			; LSB -> MSB
	EZ80_IO
	OUTI				; WRITE NEXT BYTE (MSB)
	INC	C			; MSB -> CTL
	EZ80_IO
	OUT	(C),D			; ASSERT WRITE
	EZ80_IO
	OUT	(C),E			; DEASSERT WRITE
	DEC	A
	JR	NZ,PPIDE_PUT16		; LOOP UNTIL DONE
	RET
;
;
;
PPIDE_GETRES:
	;IN	A,(PPIDE_REG_STAT)	; READ STATUS
	CALL	PPIDE_IN
	.DB	PPIDE_REG_STAT
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	AND	%00000001		; ERROR BIT SET?
	RET	Z			; NOPE, RETURN WITH ZF
;
	;IN	A,(PPIDE_REG_ERR)	; READ ERROR REGISTER
	CALL	PPIDE_IN
	.DB	PPIDE_REG_ERR
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	OR	$FF			; FORCE NZ TO SIGNAL ERROR
	RET				; RETURN
;
;=============================================================================
; HARDWARE INTERFACE ROUTINES
;=============================================================================
;
; RESET ALL DEVICES ON BUS
;
PPIDE_RESET:
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" RESET$")
#ENDIF
;
; HARD RESET
;
; RESET LINE IS NORMALLY PULSED AT POWER ON.  HOWEVER, THIS IS NOT
; DONE FOR PPIDE DEVICES, SO WE DO IT NOW.
;
	; SETUP PPI TO READ
	LD	A,PPIDE_DIR_READ	; SET DATA BUS DIRECTION TO READ
	;OUT	(PPIDE_REG_PPI),A	; DO IT
	LD	C,(IY+PPIDE_PPI)	; PPI CONTROL WORD
	EZ80_IO
	OUT	(C),A			; WRITE IT
;
; IF A DSKYNG IS ACTIVE AND IS ON THE SAME PPI PORT AS THE PPIDE BEING
; RESET, THEN THE DSKYNG WILL ALSO BE RESET.  SO, THE RESET CODE IS
; BRACKETED WITH CODE TO SAVE AND RESTORE THE STATE OF THE DSKYNG.
; THERE IS NO CHECK FOR THE SPECIFIC PPI PORT SINCE IT DOES NO HARM
; IF THE DSKYNG IS SAVED AND RESTORED.
;
;;;#IF (DSKYENABLE)
#IF (PKDENABLE)
	; SAVE CONTENTS OF DSKYNG DISPLAY ACROSS RESET
	LD	A,(PKD_PRESENT)		; GET PKD PRESENCE FLAG
	OR	A			; TEST FOR ZERO
	JR	Z,PPIDE_RESET_PKD1	; IF ZERO, NOT THERE, BYPASS
	LD	B,8			; LENGTH
	LD	C,0			; START
	LD	HL,PKD_BUF		; BUFFER
	CALL	PKD_GETSTR		; GET CURRENT DISPLAY TO BUF
PPIDE_RESET_PKD1:
#ENDIF
;;;#ENDIF
;
	; PULSE IDE RESET LINE
#IF (PPIDETRACE >= 3)
	PRTS(" HARD$")
#ENDIF
	LD	A,PPIDE_CTL_RESET
	;OUT	(PPIDE_REG_CTL),A
	LD	C,(IY+PPIDE_CTL)	; SET IDE ADDRESS
	EZ80_IO
	OUT	(C),A
	LD	DE,20			; DELAY 320US (SPEC IS >= 25US)
	CALL	VDELAY
	XOR	A
	;OUT	(PPIDE_REG_CTL),A
	EZ80_IO
	OUT	(C),A
	LD	DE,20
	CALL	VDELAY
;
;;;#IF (DSKYENABLE)
#IF (PKDENABLE)
	; REININT DSKYNG AND RESTORE CONTENTS
	LD	A,(PKD_PRESENT)		; GET PKD PRESENCE FLAG
	OR	A			; TEST FOR ZERO
	JR	Z,PPIDE_RESET_PKD2	; IF ZERO, NOT THERE, BYPASS
	CALL	PKD_REINIT		; REINIT PKD
	LD	B,8			; LENGTH
	LD	C,0			; START
	LD	HL,PKD_BUF		; BUFFER
	CALL	PKD_PUTSTR		; RESTORE DISPLAY CONTENTS
PPIDE_RESET_PKD2:
#ENDIF
;;;#ENDIF
;
; 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	PPIDE_RESET3		; SKIP SOFT RESET
;
; SOFT RESET
;
; RC CANNOT ACCESS DEVICE CONTROL REG, SO SKIP THIS
;
PPIDE_RESET2:
	; INITIATE SOFT RESET
#IF (IDETRACE >= 3)
	PRTS(" SOFT$")
#ENDIF
	LD	A,%00001110		; ASSERT RESET, NO INTERRUPTS
	;OUT	(PPIDE_REG_CTRL),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_CTRL
	LD	DE,20			; DELAY 320US (SPEC IS >= 25US)
	CALL	VDELAY
;
PPIDE_RESET3:
;
; CONFIGURE OPERATION AND END SOFT RESET
;
#IF (PPIDETRACE >= 3)
	PRTS(" CONFIG$")
#ENDIF
	LD	A,%00001010		; DEASSERT RESET, NO INTERRUPTS
	;OUT	(PPIDE_REG_CTRL),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_CTRL
	LD	DE,20			; DELAY 320US (SPEC IS >= 25US)
	CALL	VDELAY
;
PPIDE_RESET5:
	LD	HL,PPIDE_TONORM		; NORMAL TIMEOUT NOW
	LD	(PPIDE_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+PPIDE_ACC)	; MASTER?
	CALL	Z,PPIDE_GOPARTNER	; IF NOT, SWITCH TO MASTER
	CALL	PPIDE_INITUNIT		; INIT CURRENT UNIT
	CALL	PPIDE_GOPARTNER		; POINT TO SLAVE
	CALL	PPIDE_INITUNIT		; INIT PARTNER UNIT
	POP	IY			; RECOVER ORIG CFG PTR
;
	XOR	A			; SIGNAL SUCCESS
	RET				; AND DONE
;
;
;
PPIDE_INITUNIT:
	CALL	PPIDE_SELUNIT		; SELECT UNIT
	RET	NZ			; ABORT IF ERROR

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

	JP	PPIDE_INITDEV		; EXIT VIA INITDEV
;
; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT
;
PPIDE_SELUNIT:
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" SELUNIT$")
#ENDIF
	BIT	0,(IY+PPIDE_ACC)	; MASTER?
	JR	Z,PPIDE_SELUNIT1	; HANDLE SLAVE
	LD	A,PPIDE_DRVMASTER	; MASTER
#IF (PPIDETRACE >= 3)
	PRTS(" MASTER$")
#ENDIF
	JR	PPIDE_SELUNIT2
PPIDE_SELUNIT1:
	LD	A,PPIDE_DRVSLAVE	; SLAVE
#IF (PPIDETRACE >= 3)
	PRTS(" SLAVE$")
#ENDIF
PPIDE_SELUNIT2:
	LD	(PPIDE_DRVHD),A		; SAVE IT
	XOR	A			; SUCCESS
	RET
;
;
;
PPIDE_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 (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" PROBE$")			; LABEL FOR IO ADDRESS
#ENDIF
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_IN
	.DB	PPIDE_REG_STAT
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
;
	; SELECT DEVICE (MASTER/SLAVE)
	LD	A,(PPIDE_DRVHD)
	;OUT	(IDE_REG_DRVHD),A
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CALL	DELAY			; DELAY ~16US
;
; 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.
;
	; FIRST, WRITE A $7F VALUE TO THE PPIDE STATUS REGISTER.  IF
	; AN IDE DEVICE EXISTS, THIS WILL DO NO HARM.  IF NOT, THIS
	; WILL HELP AVOID A FALSE POSITIVE (STALL).
	LD	A,$7F
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_DATA
;
	CALL	PPIDE_IN
	.DB	PPIDE_REG_STAT
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
;
	AND	%10101111		; FILTER OUT DRDY & DSC
	CP	$80			; INIT IN PROGRESS?
	JR	NZ,PPIDE_PROBE1		; IF NOT, SKIP AHEAD
;
#IF (PPIDETRACE >= 3)
	PRTS(" WAIT$")
#ENDIF
;
	LD	HL,(PPIDE_TIMEOUT)	; GET CURRENT TIMEOUT
	PUSH	HL			; SAVE IT
	LD	HL,PPIDE_TOSLOW		; SLOW TIMEOUT FOR THIS
	LD	(PPIDE_TIMEOUT),HL	; SET IT
	CALL	PPIDE_WAITBSY		; WAIT FOR BUSY TO CLEAR
	POP	HL			; RECOVER TIMEOUT
	LD	(PPIDE_TIMEOUT),HL	; SET IT
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_IN
	.DB	PPIDE_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.
;
PPIDE_PROBE1:
	; $AA -> LBA0
	LD	A,$AA
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_LBA0
;
	; $55 => LBA1
	LD	A,$55
	CALL	PPIDE_OUT
	.DB	PPIDE_REG_LBA1
;
	; TEST LBA0 == $AA
	CALL	PPIDE_IN
	.DB	PPIDE_REG_LBA0
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CP	$AA
	JP	NZ,PPIDE_NOMEDIA
;
	; TEST LBA1 == $55
	CALL	PPIDE_IN
	.DB	PPIDE_REG_LBA1
#IF (PPIDETRACE >= 3)
	CALL	PC_SPACE
	CALL	PRTHEXBYTE
#ENDIF
	CP	$55
	JP	NZ,PPIDE_NOMEDIA
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_REGDUMP
#ENDIF
;
	XOR	A
	RET
;
; (RE)INITIALIZE DEVICE
;
PPIDE_INITDEV:
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" INITDEV$")		; LABEL FOR IO ADDRESS
#ENDIF
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_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	PPIDE_IN
	.DB	PPIDE_REG_STAT
	BIT	6,A			; DRDY?
	JR	Z,PPIDE_INITPDEV	; ODD, MIGHT BE ATAPI
	
;
; WE NEED TO SETUP 8-BIT MODE BEFORE DOING ANYTHING ELSE
;
	BIT	1,(IY+PPIDE_ACC)	; 8 BIT ACCESS?
	JR	Z,PPIDE_INITDEV0	; NO, DO 16 BIT INIT
	LD	A,PPIDE_FEAT_ENABLE8BIT	; FEATURE VALUE = ENABLE 8-BIT PIO
	CALL	PPIDE_SETFEAT		; SET FEATURE
	RET	NZ			; BAIL OUT ON ERROR
	JR	PPIDE_INITDEV00		; CONTINUE
;
PPIDE_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,PPIDE_FEAT_DISABLE8BIT	; FEATURE VALUE = ENABLE 8-BIT PIO
	CALL	PPIDE_SETFEAT		; SET FEATURE, IGNORE ERRORS
;
PPIDE_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	PPIDE_IDENTIFY		; EXECUTE PPIDENTIFY COMMAND
	JR	NZ,PPIDE_INITPDEV	; TRY ATAPI ON FAILURE
;
	; DECLARE WE ARE ATA
	LD	A,PPIDE_TYPEATA		; OTHERWISE TYPE=ATA
	LD	(IY+PPIDE_TYPE),A	; SET IT IN INSTANCE DATA
;
	LD	DE,HB_WRKBUF		; POINT TO BUFFER
#IF (PPIDETRACE >= 4)
	CALL	DUMP_BUFFER		; DUMP IT IF DEBUGGING
#ENDIF
;
	LD	(IY+PPIDE_MED),0	; CLEAR MEDIA FLAGS
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_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,PPIDE_INITDEV1	; IF NOT, SKIP
	SET	0,(IY+PPIDE_MED)	; ELSE SET FLAGS BIT FOR CF MEDIA
;
PPIDE_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,PPIDE_INITDEV2	; NOT SET, BYPASS
	SET	1,(IY+PPIDE_MED)	; SET FLAGS BIT FOR LBA
;
PPIDE_INITDEV2:
	; GET DEVICE CAPACITY AND SAVE IT
	LD	A,PPIDE_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+PPIDE_STAT),A	; SAVE IT
;
	RET				; RETURN, A=0, Z SET
;
; (RE)INITIALIZE PACKET DEVICE
;
PPIDE_INITPDEV:
;
#IF (PPIDETRACE >= 3)
	CALL	PPIDE_PRTPREFIX
	PRTS(" INITPDEV$")		; LABEL FOR IO ADDRESS
#ENDIF
;
	CALL	PPIDE_IDENTIFYPACKET	; EXECUTE IDENTIFY COMMAND
	RET	NZ			; BAIL OUT ON ERROR
;
	; DECLARE WE ARE ATAPI
	LD	A,PPIDE_TYPEATAPI	; OTHERWISE TYPE=ATAPI
	LD	(IY+PPIDE_TYPE),A	; SET IT IN INSTANCE DATA
;
	LD	DE,HB_WRKBUF		; POINT TO BUFFER
#IF (PPIDETRACE >= 4)
	CALL	DUMP_BUFFER		; DUMP IT IF DEBUGGING
#ENDIF
;
	LD	(IY+PPIDE_MED),0	; CLEAR FLAGS
	SET	1,(IY+PPIDE_MED)	; SET FLAGS BIT FOR LBA (ASSUMED)
;
	; WAIT FOR UNIT READY
	LD	B,0			; MAX LOOPS
	LD	C,4			; MAX ERRORS
PPIDE_INITPDEV1:
	DEC	B			; CHECK LOOP COUNTER EXCEEDED
	JP	Z,PPIDE_NOMEDIA		; TREAT AS NO MEDIA
	PUSH	BC			; SAVE LOOP CONTROL
	LD	HL,PPIDE_PKTCMD_TSTRDY	; TEST UNIT READY
	XOR	A			; READ DIRECTION
	LD	(PPIDE_XFRDIR),A	; SAVE IT
	CALL	PPIDE_RUNPCMD		; ISSUE PACKET COMMAND
	CALL	NZ,PPIDE_CHKPCMD	; IF ERROR, DIAGNOSE IT
	POP	BC			; RESTORE LOOP CONTROL
	JR	Z,PPIDE_INITPDEV2	; IF NO ERROR, CONTINUE
	CP	PPIDE_STNOMEDIA		; EXPLICIT NO MEDIA RESULT?
	RET	Z			; EXIT REPORTING NO MEDIA
	CP	PPIDE_STNOTRDY		; BECOMING READY?
	JR	Z,PPIDE_INITDEVP1A	; IF SO, NOT AN ERROR, LOOP
	DEC	C			; DEC ERROR LIMIT
	RET	Z			; BAIL OUT, ERR LIMIT EXCEEDED
	JR	PPIDE_INITPDEV1		; LOOP
PPIDE_INITDEVP1A:
	LD	DE,100000/16		; WAIT 1/10 SECOND
	CALL	VDELAY			; DO IT
	JR	PPIDE_INITPDEV1		; AND LOOP
;
PPIDE_INITPDEV2:
#IF (PPIDETRACE >= 3)
	LD	A,B
	NEG
	PRTS("\r\nLOOPS=$")
	CALL	PRTHEXBYTE
#ENDIF
;
	; GET AND RECORD CAPACITY
	LD	HL,HB_WRKBUF
	LD	(PPIDE_DSKBUF),HL
	LD	HL,PPIDE_PKTCMD_RDCAP
	XOR	A			; READ DIRECTION
	LD	(PPIDE_XFRDIR),A	; SAVE IT
	CALL	PPIDE_RUNPCMD
	JP	NZ,PPIDE_CHKPCMD
;
#IF (PPIDETRACE >= 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,PPIDE_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,PPIDE_NOTSUP		; IF NOT, FAIL AS NOT SUP
	LD	A,D			; LOAD D
	OR	A			; SET FLAGS
	JP	NZ,PPIDE_NOTSUP		; IF NOT ZERO, FAIL AS NOT SUP
	LD	A,E			; LOAD E
	CP	2			; CHECK IT IF IS 2
	JP	NZ,PPIDE_NOTSUP		; IF NOT, FAIL AS NOT SUP
;
	; RECORD STATUS OK
	XOR	A			; A := 0 (STATUS = OK)
	LD	(IY+PPIDE_STAT),A	; SAVE IT
	RET
;
; SWITCH IY POINTER FROM CURRENT UNIT CFG TO PARTNER UNIT CFG
;
PPIDE_GOPARTNER:
	PUSH	HL			; SAVE HL
	LD	L,(IY+PPIDE_PARTNER)	; GET PARTNER ENTRY
	LD	H,(IY+PPIDE_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.
;
PPIDE_CHKERR:
	LD	A,(IY+PPIDE_STAT)	; GET STATUS
	OR	A			; SET FLAGS
	CALL	NZ,PPIDE_RESET		; IF ERROR STATUS, RESET BUS
	RET
;
;
;
PPIDE_WAITRDY:
	LD	A,(PPIDE_TIMEOUT)	; GET TIMEOUT IN 0.1 SECS
	LD	B,A			; PUT IN OUTER LOOP VAR
PPIDE_WAITRDY1:
	LD	DE,(PPIDE_TOSCALER)	; CPU SPEED SCALER TO INNER LOOP VAR
PPIDE_WAITRDY2:
	;IN	A,(PPIDE_REG_STAT)	; READ STATUS
	CALL	PPIDE_IN
	.DB	PPIDE_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,PPIDE_WAITRDY2	; INNER LOOP RETURN
	DJNZ	PPIDE_WAITRDY1		; OUTER LOOP RETURN
	JP	PPIDE_RDYTO		; EXIT WITH RDYTO ERR
;
;
;
PPIDE_WAITDRQ:
	LD	A,(PPIDE_TIMEOUT)	; GET TIMEOUT IN 0.1 SECS
	LD	B,A			; PUT IN OUTER LOOP VAR
PPIDE_WAITDRQ1:
	LD	DE,(PPIDE_TOSCALER)	; CPU SPEED SCALER TO INNER LOOP VAR
PPIDE_WAITDRQ2:
	;IN	A,(PPIDE_REG_STAT)	; READ STATUS
	CALL	PPIDE_IN
	.DB	PPIDE_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,PPIDE_WAITDRQ2
	DJNZ	PPIDE_WAITDRQ1
	JP	PPIDE_DRQTO		; EXIT WITH BUFTO ERR
;
;
;
PPIDE_WAITBSY:
	LD	A,(PPIDE_TIMEOUT)	; GET TIMEOUT IN 0.1 SECS
	LD	B,A			; PUT IN OUTER LOOP VAR
PPIDE_WAITBSY1:
	LD	DE,(PPIDE_TOSCALER)	; CPU SPEED SCALER TO INNER LOOP VAR
PPIDE_WAITBSY2:
	;IN	A,(PPIDE_REG_STAT)	; READ STATUS
	CALL	PPIDE_IN							; 17TS + 204TS
	.DB	PPIDE_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,PPIDE_WAITBSY2						; 12TS
	DJNZ	PPIDE_WAITBSY1							; -----
	JP	PPIDE_BSYTO		; EXIT WITH BSYTO ERR			; 263TS
;
; READ A VALUE FROM THE DEVICE POINTED TO BY IY AND RETURN IT IN A
;
PPIDE_IN:
	EX	(SP),HL			; GET PARM POINTER			; 19TS
	PUSH	BC			; SAVE INCOMING BC			; 11TS
	LD	A,PPIDE_DIR_READ	; SET DATA BUS DIRECTION TO READ	; 7TS
	;OUT	(PPIDE_REG_PPI),A	; DO IT
	LD	C,(IY+PPIDE_PPI)	; PPI CONTROL WORD			; 19TS
	EZ80_IO
	OUT	(C),A			; WRITE IT				; 12TS
;
	LD	B,(HL)			; GET CTL PORT VALUE			; 7TS
	;LD	C,PPIDE_REG_CTL		; SETUP PORT TO WRITE
	;LD	C,(IY+PPIDE_CTL)	; SET IDE ADDRESS
	DEC	C			; SET IDE ADDRESS			; 4TS
	EZ80_IO
	OUT	(C),B			; SET ADDRESS LINES			; 12TS
	SET	6,B			; TURN ON READ BIT			; 8TS
	EZ80_IO
	OUT	(C),B			; ASSERT READ LINE			; 12TS
;
	;IN	A,(PPIDE_REG_DATALO)	; GET DATA VALUE FROM DEVICE
	DEC	C								; 4TS
	DEC	C								; 4TS
	EZ80_IO
	IN	A,(C)			; GET DATA VALUE FROM DEVICE		; 12
	INC	C								; 4TS
	INC	C								; 4TS
;
	RES	6,B			; CLEAR READ BIT			; 8TS
	EZ80_IO
	OUT	(C),B			; DEASSERT READ LINE			; 12TS
	POP	BC			; RECOVER INCOMING BC			; 10TS
	INC	HL			; POINT PAST PARM			; 6TS
	EX	(SP),HL			; RESTORE STACK				; 19TS
	RET									; 10TS
;										; -----
; OUTPUT VALUE IN A TO THE DEVICE POINTED TO BY IY				; 204TS
;
PPIDE_OUT:
	; *** TODO *** FIX ORDER OF SET/CLEAR WRITE LINE
	EX	(SP),HL			; GET PARM POINTER
	PUSH	BC			; SAVE INCOMING BC
	PUSH	AF			; PRESERVE INCOMING VALUE
	LD	A,PPIDE_DIR_WRITE	; SET DATA BUS DIRECTION TO WRITE
	;OUT	(PPIDE_REG_PPI),A	; DO IT
	LD	C,(IY+PPIDE_PPI)	; PPI CONTROL WORD
	EZ80_IO
	OUT	(C),A			; WRITE IT
	POP	AF			; RECOVER VALUE TO WRITE
;
	LD	B,(HL)			; GET IDE ADDRESS VALUE
	;LD	C,PPIDE_REG_CTL		; SETUP PORT TO WRITE
	;LD	C,(IY+PPIDE_CTL)	; SET IDE ADDRESS
	DEC	C			; SET IDE ADDRESS
	EZ80_IO
	OUT	(C),B			; SET ADDRESS LINES
	SET	5,B			; TURN ON WRITE BIT
	EZ80_IO
	OUT	(C),B			; ASSERT WRITE LINE
;
	DEC	C
	DEC	C
	;OUT	(PPIDE_REG_DATALO),A	; SEND DATA VALUE TO DEVICE
	EZ80_IO
	OUT	(C),A			; SEND DATA VALUE TO DEVICE
	INC	C
	INC	C
;
	RES	5,B			; CLEAR WRITE BIT
	EZ80_IO
	OUT	(C),B			; DEASSERT WRITE LINE
	POP	BC			; RECOVER INCOMING BC
	INC	HL			; POINT PAST PARM
	EX	(SP),HL			; RESTORE STACK
	RET
;
;=============================================================================
; ERROR HANDLING AND DIAGNOSTICS
;=============================================================================
;
; ERROR HANDLERS
;
PPIDE_INVUNIT:
	LD	A,PPIDE_STINVUNIT
	JR	PPIDE_ERR2		; SPECIAL CASE FOR INVALID UNIT
;
PPIDE_NOMEDIA:
	LD	A,PPIDE_STNOMEDIA
	JR	PPIDE_ERR
;
PPIDE_CMDERR:
	LD	A,PPIDE_STCMDERR
	JR	PPIDE_ERR
;
PPIDE_IOERR:
	LD	A,PPIDE_STIOERR
	JR	PPIDE_ERR
;
PPIDE_RDYTO:
	LD	A,PPIDE_STRDYTO
	JR	PPIDE_ERR
;
PPIDE_DRQTO:
	LD	A,PPIDE_STDRQTO
	JR	PPIDE_ERR
;
PPIDE_BSYTO:
	LD	A,PPIDE_STBSYTO
	JR	PPIDE_ERR
;
PPIDE_NOTSUP:
	LD	A,PPIDE_STNOTSUP
	JR	PPIDE_ERR
;
PPIDE_NOTRDY:
	LD	A,PPIDE_STNOTRDY
	JR	PPIDE_ERR
;
PPIDE_ERR:
	LD	(IY+PPIDE_STAT),A	; SAVE NEW STATUS
;
PPIDE_ERR2:
#IF (PPIDETRACE >= 2)
	CALL	PPIDE_PRTSTAT
	CALL	PPIDE_REGDUMP
#ENDIF
	OR	A			; SET FLAGS
	RET
;
;
;
PPIDE_PRTERR:
	RET	Z			; DONE IF NO ERRORS
	; FALL THRU TO PPIDE_PRTSTAT
;
; PRINT FULL DEVICE STATUS LINE
;
PPIDE_PRTSTAT:
	PUSH	AF
	PUSH	DE
	PUSH	HL
	LD	A,(IY+PPIDE_STAT)
	CP	PPIDE_STINVUNIT
	JR	Z,PPIDE_PRTSTAT2	; INVALID UNIT IS SPECIAL CASE
	CALL	PPIDE_PRTPREFIX		; PRINT UNIT PREFIX
	JR	PPIDE_PRTSTAT3
PPIDE_PRTSTAT2:
	CALL	NEWLINE
	PRTS("PPIDE:$")			; NO UNIT NUM IN PREFIX FOR INVALID UNIT
PPIDE_PRTSTAT3:
	CALL	PC_SPACE		; FORMATTING
	CALL	PPIDE_PRTSTATSTR
	POP	HL
	POP	DE
	POP	AF
	RET
;
; PRINT STATUS STRING
;
PPIDE_PRTSTATSTR:
	PUSH	AF
	PUSH	DE
	LD	A,(IY+PPIDE_STAT)
	OR	A
	LD	DE,PPIDE_STR_STOK
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STINVUNIT
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STNOMEDIA
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STCMDERR
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STIOERR
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STRDYTO
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STDRQTO
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STBSYTO
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STNOTSUP
	JR	Z,PPIDE_PRTSTATSTR1
	INC	A
	LD	DE,PPIDE_STR_STNOTRDY
	JR	Z,PPIDE_PRTSTATSTR1
	LD	DE,PPIDE_STR_STUNK
PPIDE_PRTSTATSTR1:
	CALL	WRITESTR
	POP	DE
	POP	AF
	RET
;
; PRINT ALL REGISTERS DIRECTLY FROM DEVICE
; DEVICE MUST BE SELECTED PRIOR TO CALL
;
PPIDE_REGDUMP:
	PUSH	AF
	PUSH	BC
	push	DE
	CALL	PC_SPACE
	CALL	PC_LBKT
	LD	A,PPIDE_DIR_READ	; SET DATA BUS DIRECTION TO READ
	;OUT	(PPIDE_REG_PPI),A	; DO IT
	LD	C,(IY+PPIDE_PPI)	; PPI CONTROL WORD
	EZ80_IO
	OUT	(C),A			; WRITE IT
	LD	C,(IY+PPIDE_CTL)	; SET IDE ADDRESS
	LD	E,PPIDE_REG_CMD
	LD	B,7
PPIDE_REGDUMP1:
	LD	A,E			; REGISTER ADDRESS
	;OUT	(PPIDE_REG_CTL),A	; SET IT
	EZ80_IO
	OUT	(C),A			; REGISTER ADDRESS
	XOR	PPIDE_CTL_DIOR		; SET BIT TO ASSERT READ LINE
	;OUT	(PPIDE_REG_CTL),A	; ASSERT READ
	EZ80_IO
	OUT	(C),A			; ASSERT READ
	;IN	A,(PPIDE_REG_DATALO)	; GET VALUE
	DEC	C			; CTL -> MSB
	DEC	C			; MSB -> LSB
	EZ80_IO
	IN	A,(C)			; GET VALUE
	INC	C			; LSB -> MSB
	INC	C			; MSB -> CTL
	CALL	PRTHEXBYTE		; DISPLAY IT
	;LD	A,C			; RELOAD ADDRESS W/ READ UNASSERTED
	;OUT	(PPIDE_REG_CTL),A	; AND SET IT
	EZ80_IO
	OUT	(C),E			; RELOAD ADDRESS W/ READ UNASSERTED
	;DEC	C			; NEXT LOWER REGISTER
	DEC	E			; NEXT LOWER REGISTER
	DEC	B			; DEC LOOP COUNTER
	CALL	NZ,PC_SPACE		; FORMATTING
	JR	NZ,PPIDE_REGDUMP1	; LOOP AS NEEDED
	CALL	PC_RBKT			; FORMATTING
	POP	DE
	POP	BC
	POP	AF
	RET
;
; PRINT DIAGNONSTIC PREFIX
;
PPIDE_PRTPREFIX:
	PUSH	AF
	CALL	NEWLINE
	PRTS("PPIDE$")
	LD	A,(IY+PPIDE_DEV)	; GET CURRENT DEVICE NUM
	CP	$FE			; NOT YET ASSIGNED?
	JR	Z,PPIDE_PRTPREFIX1	; SKIP DEV NUM IF SO
	CALL	PRTDECB
PPIDE_PRTPREFIX1:
	CALL	PC_COLON
	POP	AF
	RET
;
;=============================================================================
; STRING DATA
;=============================================================================
;
PPIDE_STR_STOK		.TEXT	"OK$"
PPIDE_STR_STINVUNIT	.TEXT	"INVALID UNIT$"
PPIDE_STR_STNOMEDIA	.TEXT	"NO MEDIA$"
PPIDE_STR_STCMDERR	.TEXT	"COMMAND ERROR$"
PPIDE_STR_STIOERR	.TEXT	"IO ERROR$"
PPIDE_STR_STRDYTO	.TEXT	"READY TIMEOUT$"
PPIDE_STR_STDRQTO	.TEXT	"DRQ TIMEOUT$"
PPIDE_STR_STBSYTO	.TEXT	"BUSY TIMEOUT$"
PPIDE_STR_STNOTSUP	.TEXT	"NOT SUPPORTED$"
PPIDE_STR_STNOTRDY	.TEXT	"NOT READY$"
PPIDE_STR_STUNK		.TEXT	"UNKNOWN ERROR$"
;
PPIDE_STR_NO		.TEXT	"NO$"
PPIDE_STR_NOPPI		.TEXT	"PPI NOT PRESENT$"
PPIDE_STR_8BIT		.TEXT	" 8-BIT$"
;
PPIDE_STR_TYPEATA	.TEXT	" ATA$"
PPIDE_STR_TYPEATAPI	.TEXT	" ATAPI$"
;
;=============================================================================
; DATA STORAGE
;=============================================================================
;
PPIDE_TIMEOUT	.DB	PPIDE_TONORM	; WAIT FUNCS TIMEOUT IN TENTHS OF SEC
PPIDE_TOSCALER	.DW	CPUMHZ * 380	; WAIT FUNCS SCALER FOR CPU SPEED
;
PPIDE_CMD	.DB	0		; PENDING COMMAND TO PROCESS
PPIDE_IOFNADR	.DW	0		; PENDING IO FUNCTION ADDRESS
PPIDE_DRVHD	.DB	0		; CURRENT DRIVE/HEAD MASK
;
PPIDE_DSKBUF	.DW	0		; ACTIVE DISK BUFFER
PPIDE_XFRDIR	.DB	0		; 0=READ, NON-0=WRITE
;
PPIDE_DEVNUM	.DB	0		; TEMP DEVICE NUM USED DURING INIT
;
; SCSI COMMAND TEMPLATES (ALWAYS 12 BYTES FOR ATAPI)
;
PPIDE_PKTCMD_RW		.DB	$00, $00, $00, $00, $01, $00, $00, $00, $00, $00, $00, $00	; READ/WRITE SECTOR
PPIDE_PKTCMD_SENSE	.DB	$03, $00, $00, $00, $FF, $00, $00, $00, $00, $00, $00, $00	; REQUEST SENSE DATA
PPIDE_PKTCMD_RDCAP	.DB	$25, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00	; READ CAPACITY
PPIDE_PKTCMD_RW10	.DB	$28, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00	; READ/WRITE SECTOR
PPIDE_PKTCMD_TSTRDY	.DB	$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00	; TEST UNIT READY
