Files
Pegasys-RomWBW/Source/HBIOS/ppide.asm
Wayne Warthen f8c800e527 Create DSKY Driver Framework
Added a new driver category for DSKY (Display/Keypad) devices.  Existing DSKY devices were converted into drivers ICM and PKD.  These devices were previously DSKY and DSKYNG.

This removes substantial code duplication and recovers significant space in romldr and dbgmon.
2023-06-28 15:06:53 -07:00

2150 lines
56 KiB
NASM

;
;=============================================================================
; 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
;
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
;
#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
;
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
;
#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
;
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
;
#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
;
;=============================================================================
; 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
OUT (C),A ; WRITE IT
;
LD C,(IY+PPIDE_DATALO) ; PPI PORT A, DATALO
LD A,$A5 ; TEST VALUE
OUT (C),A ; PUSH VALUE TO PORT
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
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
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
OUT (C),D ; ASSERT READ
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
INI ; READ FROM LSB
INC C ; LSB -> MSB
INC C ; MSB -> CTL
OUT (C),E ; DEASSERT READ
OUT (C),D ; ASSERT READ
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
INI ; READ FROM LSB
INC C ; LSB -> MSB
INC C ; MSB -> CTL
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
OUT (C),D ; ASSERT READ
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
INI ; READ FROM LSB
INC C ; LSB -> MSB
INI ; READ MSB FOR 16 BIT
INC C ; MSB -> CTL
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
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
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
OUTI ; WRITE NEXT BYTE (LSB)
INC C ; LSB -> MSB
INC C ; MSB -> CTL
OUT (C),D ; ASSERT WRITE
OUT (C),E ; DEASSERT WRITE
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
OUTI ; WRITE NEXT BYTE (LSB)
INC C ; LSB -> MSB
INC C ; MSB -> CTL
OUT (C),D ; ASSERT WRITE
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
OUTI ; WRITE NEXT BYTE (LSB)
INC C ; LSB -> MSB
OUTI ; WRITE NEXT BYTE (MSB)
INC C ; MSB -> CTL
OUT (C),D ; ASSERT WRITE
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
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.
;
; THIS DOES NOT TEST THAT A DSKYNG IS ACTUALLY PRESENT
; AND OPERATING -- COULD CAUSE PROBLEMS
;
#IF (DSKYENABLE)
#IF (PKDENABLE)
; SAVE CONTENTS OF DSKYNG DISPLAY ACROSS RESET
LD B,8
LD C,0
LD HL,DSKY_BUF
CALL PKD_GETSTR
#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
OUT (C),A
LD DE,20 ; DELAY 320US (SPEC IS >= 25US)
CALL VDELAY
XOR A
;OUT (PPIDE_REG_CTL),A
OUT (C),A
LD DE,20
CALL VDELAY
;
#IF (DSKYENABLE)
#IF (PKDENABLE)
; REININT DSKYNG AND RESTORE CONTENTS
CALL PKD_REINIT
LD B,8
LD C,0
LD HL,DSKY_BUF
CALL PKD_PUTSTR
#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.
;
;;; CALL LDELAY ; DELAY FOR SLAVE INIT
LD DE,150000 / 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.
;
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
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
OUT (C),B ; SET ADDRESS LINES ; 12TS
SET 6,B ; TURN ON READ BIT ; 8TS
OUT (C),B ; ASSERT READ LINE ; 12TS
;
;IN A,(PPIDE_REG_DATALO) ; GET DATA VALUE FROM DEVICE
DEC C ; 4TS
DEC C ; 4TS
IN A,(C) ; GET DATA VALUE FROM DEVICE ; 12
INC C ; 4TS
INC C ; 4TS
;
RES 6,B ; CLEAR READ BIT ; 8TS
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
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
OUT (C),B ; SET ADDRESS LINES
SET 5,B ; TURN ON WRITE BIT
OUT (C),B ; ASSERT WRITE LINE
;
DEC C
DEC C
;OUT (PPIDE_REG_DATALO),A ; SEND DATA VALUE TO DEVICE
OUT (C),A ; SEND DATA VALUE TO DEVICE
INC C
INC C
;
RES 5,B ; CLEAR WRITE BIT
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
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
OUT (C),A ; REGISTER ADDRESS
XOR PPIDE_CTL_DIOR ; SET BIT TO ASSERT READ LINE
;OUT (PPIDE_REG_CTL),A ; ASSERT READ
OUT (C),A ; ASSERT READ
;IN A,(PPIDE_REG_DATALO) ; GET VALUE
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
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
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