forked from MirrorRepos/RomWBW
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2217 lines
54 KiB
2217 lines
54 KiB
;
|
|
;=============================================================================
|
|
; IDE DISK DRIVER
|
|
;=============================================================================
|
|
;
|
|
; TODO:
|
|
; - GOPARTNER NEEDS TO HANDLE "NO PARTNER" CONDITION
|
|
; - IMPLEMENT H/W PROBES FOR DIO AND DIDE
|
|
; - DATA TRANSFERS LIMITED TO 512 BYTES WHICH IS INSUFFICIENT FOR CD=ROM MEDIA
|
|
;
|
|
; NOTES:
|
|
; - WELL KNOWN IDE PORT ADDRESSES:
|
|
; BOARD BASE DATLO DATHI
|
|
; ------ ------ ------ ------
|
|
; DIO $20 $20 $28
|
|
; DIDE-A $20 $28 $28
|
|
; DIDE-B $30 $38 $38
|
|
; MK4 $80 N/A N/A
|
|
; RC $10 N/A N/A
|
|
; SMB $E0 N/A N/A
|
|
;
|
|
; +-----------------------------------------------------------------------+
|
|
; | CONTROL BLOCK REGISTERS |
|
|
; +-----------------------+-------+-------+-------------------------------+
|
|
; | REGISTER | PORT | DIR | DESCRIPTION |
|
|
; +-----------------------+-------+-------+-------------------------------+
|
|
; | IDE_REG_ALTSTAT | 0x0E | R | ALTERNATE STATUS REGISTER |
|
|
; | IDE_REG_CTRL | 0x0E | W | DEVICE CONTROL REGISTER |
|
|
; | IDE_REG_DRVADR | 0x0F | R | DRIVE ADDRESS REGISTER|
|
|
; +-----------------------+-------+-------+-------------------------------+
|
|
;
|
|
; +-----------------------+-------+-------+-------------------------------+
|
|
; | COMMAND BLOCK REGISTERS |
|
|
; +-----------------------+-------+-------+-------------------------------+
|
|
; | REGISTER | PORT | DIR | DESCRIPTION |
|
|
; +-----------------------+-------+-------+-------------------------------+
|
|
; | IDE_REG_DATA | 0x00 | R/W | DATA INPUT/OUTPUT |
|
|
; | IDE_REG_ERR | 0x01 | R | ERROR REGISTER |
|
|
; | IDE_REG_FEAT | 0x01 | W | FEATURES REGISTER |
|
|
; | IDE_REG_COUNT | 0x02 | R/W | SECTOR COUNT REGISTER |
|
|
; | IDE_REG_SECT | 0x03 | R/W | SECTOR NUMBER REGISTER |
|
|
; | IDE_REG_CYLLO | 0x04 | R/W | CYLINDER NUM REGISTER (LSB) |
|
|
; | IDE_REG_CYLHI | 0x05 | R/W | CYLINDER NUM REGISTER (MSB) |
|
|
; | IDE_REG_DRVHD | 0x06 | R/W | DRIVE/HEAD REGISTER |
|
|
; | IDE_REG_LBA0* | 0x03 | R/W | LBA BYTE 0 (BITS 0-7) |
|
|
; | IDE_REG_LBA1* | 0x04 | R/W | LBA BYTE 1 (BITS 8-15) |
|
|
; | IDE_REG_LBA2* | 0x05 | R/W | LBA BYTE 2 (BITS 16-23) |
|
|
; | IDE_REG_LBA3* | 0x06 | R/W | LBA BYTE 3 (BITS 24-27) |
|
|
; | IDE_REG_STAT | 0x07 | R | STATUS REGISTER |
|
|
; | IDE_REG_CMD | 0x07 | W | COMMAND REGISTER (EXECUTE) |
|
|
; +-----------------------+-------+-------+-------------------------------+
|
|
; * LBA0-3 ARE ALTERNATE DEFINITIONS OF SECT, CYL, AND DRVHD PORTS
|
|
;
|
|
; === STATUS REGISTER ===
|
|
;
|
|
; 7 6 5 4 3 2 1 0
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
; | BSY | DRDY | DWF | DSC | DRQ | CORR | IDX | ERR |
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
;
|
|
; BSY: BUSY
|
|
; DRDY: DRIVE READY
|
|
; DWF: DRIVE WRITE FAULT
|
|
; DSC: DRIVE SEEK COMPLETE
|
|
; DRQ: DATA REQUEST
|
|
; CORR: CORRECTED DATA
|
|
; IDX: INDEX
|
|
; ERR: ERROR
|
|
;
|
|
; === ERROR REGISTER ===
|
|
;
|
|
; 7 6 5 4 3 2 1 0
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
; | BBK | UNC | MC | IDNF | MCR | ABRT | TK0NF | AMNF |
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
; (VALID WHEN ERR BIT IS SET IN STATUS REGISTER)
|
|
;
|
|
; BBK: BAD BLOCK DETECTED
|
|
; UNC: UNCORRECTABLE DATA ERROR
|
|
; MC: MEDIA CHANGED
|
|
; IDNF: ID NOT FOUND
|
|
; MCR: MEDIA CHANGE REQUESTED
|
|
; ABRT: ABORTED COMMAND
|
|
; TK0NF: TRACK 0 NOT FOUND
|
|
; AMNF: ADDRESS MARK NOT FOUND
|
|
;
|
|
; === DRIVE/HEAD / LBA3 REGISTER ===
|
|
;
|
|
; 7 6 5 4 3 2 1 0
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
; | 1 | L | 1 | DRV | HS3 | HS2 | HS1 | HS0 |
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
;
|
|
; L: 0 = CHS ADDRESSING, 1 = LBA ADDRESSING
|
|
; DRV: 0 = DRIVE 0 (PRIMARY) SELECTED, 1 = DRIVE 1 (SLAVE) SELECTED
|
|
; HS: CHS = HEAD ADDRESS (0-15), LBA = BITS 24-27 OF LBA
|
|
;
|
|
; === DEVICE CONTROL REGISTER ===
|
|
;
|
|
; 7 6 5 4 3 2 1 0
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
; | X | X | X | X | 1 | SRST | ~IEN | 0 |
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
;
|
|
; SRST: SOFTWARE RESET
|
|
; ~IEN: INTERRUPT ENABLE
|
|
;
|
|
IDE_REG_DATA .EQU $00 ; DATA /OUTPUT (R/W)
|
|
IDE_REG_ERR .EQU $01 ; ERROR REGISTER (R)
|
|
IDE_REG_FEAT .EQU $01 ; FEATURES REGISTER (W)
|
|
IDE_REG_COUNT .EQU $02 ; SECTOR COUNT REGISTER (R/W)
|
|
IDE_REG_SECT .EQU $03 ; SECTOR NUMBER REGISTER (R/W)
|
|
IDE_REG_CYLLO .EQU $04 ; CYLINDER NUM REGISTER (LSB) (R/W)
|
|
IDE_REG_CYLHI .EQU $05 ; CYLINDER NUM REGISTER (MSB) (R/W)
|
|
IDE_REG_DRVHD .EQU $06 ; DRIVE/HEAD REGISTER (R/W)
|
|
IDE_REG_LBA0 .EQU $03 ; LBA BYTE 0 (BITS 0-7) (R/W)
|
|
IDE_REG_LBA1 .EQU $04 ; LBA BYTE 1 (BITS 8-15) (R/W)
|
|
IDE_REG_LBA2 .EQU $05 ; LBA BYTE 2 (BITS 16-23) (R/W)
|
|
IDE_REG_LBA3 .EQU $06 ; LBA BYTE 3 (BITS 24-27) (R/W)
|
|
IDE_REG_BCL .EQU $04 ; PKT BYTE COUNT LOW (BITS 0-7) (R/W)
|
|
IDE_REG_BCH .EQU $05 ; PKT BYTE COUNT HIGH (BITS 8-15) (R/W)
|
|
IDE_REG_STAT .EQU $07 ; STATUS REGISTER (R)
|
|
IDE_REG_CMD .EQU $07 ; COMMAND REGISTER (EXECUTE) (W)
|
|
IDE_REG_XAR .EQU $08 ; ECB DIDE EXTERNAL ADDRESS REGISTER (W)
|
|
IDE_REG_ALTSTAT .EQU $0E ; ALTERNATE STATUS REGISTER (R)
|
|
IDE_REG_CTRL .EQU $0E ; DEVICE CONTROL REGISTER (W)
|
|
IDE_REG_DRVADR .EQU $0F ; DRIVE ADDRESS REGISTER (R)
|
|
;
|
|
; COMMAND BYTES
|
|
;
|
|
IDE_CMD_NOP .EQU $00
|
|
IDE_CMD_DEVRES .EQU $08
|
|
IDE_CMD_RECAL .EQU $10
|
|
IDE_CMD_READ .EQU $20
|
|
IDE_CMD_WRITE .EQU $30
|
|
IDE_CMD_DEVDIAG .EQU $90
|
|
IDE_CMD_PACKET .EQU $A0
|
|
IDE_CMD_IDPKTDEV .EQU $A1
|
|
IDE_CMD_IDDEV .EQU $EC
|
|
IDE_CMD_SETFEAT .EQU $EF
|
|
;
|
|
; FEATURE BYTES
|
|
;
|
|
IDE_FEAT_ENABLE8BIT .EQU $01
|
|
IDE_FEAT_DISABLE8BIT .EQU $81
|
|
;
|
|
; IDE DEVICE TYPES
|
|
;
|
|
IDE_TYPEUNK .EQU 0
|
|
IDE_TYPEATA .EQU 1
|
|
IDE_TYPEATAPI .EQU 2
|
|
;
|
|
; IDE DEVICE STATUS CODES
|
|
;
|
|
IDE_STOK .EQU 0
|
|
IDE_STINVUNIT .EQU -1
|
|
IDE_STNOMEDIA .EQU -2
|
|
IDE_STCMDERR .EQU -3
|
|
IDE_STIOERR .EQU -4
|
|
IDE_STRDYTO .EQU -5
|
|
IDE_STDRQTO .EQU -6
|
|
IDE_STBSYTO .EQU -7
|
|
IDE_STNOTSUP .EQU -8
|
|
IDE_STNOTRDY .EQU -9
|
|
;
|
|
; DRIVE SELECTION BYTES (FOR USE IN DRIVE/HEAD REGISTER)
|
|
;
|
|
;IDE_DRVSEL:
|
|
IDE_DRVMASTER .EQU %11100000 ; LBA, MASTER DEVICE
|
|
IDE_DRVSLAVE .EQU %11110000 ; LBA, SLAVE DEVICE
|
|
;
|
|
; IDE DEVICE CONFIGURATION
|
|
;
|
|
IDE_CFGSIZ .EQU 19 ; SIZE OF CFG TBL ENTRIES
|
|
;
|
|
; PER DEVICE DATA OFFSETS
|
|
;
|
|
IDE_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
|
|
IDE_MODE .EQU 1 ; OPERATION MODE: IDE MODE (BYTE)
|
|
IDE_STAT .EQU 2 ; LAST STATUS (BYTE)
|
|
IDE_TYPE .EQU 3 ; DEVICE TYPE (BYTE)
|
|
IDE_ACC .EQU 4 ; ACCESS FLAG BITS BIT 0=MASTER, 1=8BIT (BYTE)
|
|
IDE_MED .EQU 5 ; MEDIA FLAG BITS BIT 0=CF, 1=LBA (BYTE)
|
|
IDE_MEDCAP .EQU 6 ; MEDIA CAPACITY (DWORD)
|
|
IDE_LBA .EQU 10 ; OFFSET OF LBA (DWORD)
|
|
IDE_IOBASE .EQU 14 ; IO BASE ADDRESS (BYTE)
|
|
IDE_DATALO .EQU 15 ; 16 BIT DATA LO BYTE
|
|
IDE_DATAHI .EQU 16 ; 16 BIT DATA HI BYTE
|
|
IDE_PARTNER .EQU 17 ; PARTNER DEVICE (MASTER <-> SLAVE) (WORD)
|
|
;
|
|
IDE_ACC_MAS .EQU %00000001 ; UNIT IS MASTER (ELSE SLAVE)
|
|
IDE_ACC_8BIT .EQU %00000010 ; UNIT WANTS 8 BIT I/O (ELSE 16 BIT)
|
|
;
|
|
IDE_MED_CF .EQU %00000001 ; MEDIA IS CF CARD
|
|
IDE_MED_LBA .EQU %00000010 ; MEDIA HAS LBA CAPABILITY
|
|
;
|
|
IDE_DEVCNT .EQU IDECNT * 2
|
|
;
|
|
IDE_CFGTBL:
|
|
;
|
|
#IF (IDECNT >= 1)
|
|
;
|
|
IDE_DEV0M: ; DEVICE 0, MASTER
|
|
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB IDE0MODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB 0 ; DEVICE TYPE
|
|
.DB IDE_ACC_MAS | (IDE0A8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
|
|
.DB 0 ; MEDIA FLAGS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
.DB IDE0BASE ; IO BASE ADDRESS
|
|
.DB IDE0DATLO ; IO BASE ADDRESS
|
|
.DB IDE0DATHI ; IO BASE ADDRESS
|
|
.DW IDE_DEV0S ; PARTNER
|
|
;
|
|
DEVECHO "IDE: MODE="
|
|
#IF (IDE0MODE == IDEMODE_NONE)
|
|
DEVECHO "NONE"
|
|
#ENDIF
|
|
#IF (IDE0MODE == IDEMODE_DIO)
|
|
DEVECHO "DIO"
|
|
#ENDIF
|
|
#IF (IDE0MODE == IDEMODE_DIDE)
|
|
DEVECHO "DIDE"
|
|
#ENDIF
|
|
#IF (IDE0MODE == IDEMODE_MK4)
|
|
DEVECHO "MK4"
|
|
#ENDIF
|
|
#IF (IDE0MODE == IDEMODE_RC)
|
|
DEVECHO "RC"
|
|
#ENDIF
|
|
DEVECHO ", IO="
|
|
DEVECHO IDE0BASE
|
|
DEVECHO ", MASTER"
|
|
DEVECHO "\n"
|
|
;
|
|
IDE_DEV0S: ; DEVICE 0, SLAVE
|
|
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB IDE0MODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB 0 ; DEVICE TYPE
|
|
.DB (IDE0B8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
|
|
.DB 0 ; MEDIA FLAGS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
.DB IDE0BASE ; IO BASE ADDRESS
|
|
.DB IDE0DATLO ; IO BASE ADDRESS
|
|
.DB IDE0DATHI ; IO BASE ADDRESS
|
|
.DW IDE_DEV0M ; PARTNER
|
|
;
|
|
DEVECHO "IDE: MODE="
|
|
#IF (IDE0MODE == IDEMODE_NONE)
|
|
DEVECHO "NONE"
|
|
#ENDIF
|
|
#IF (IDE0MODE == IDEMODE_DIO)
|
|
DEVECHO "DIO"
|
|
#ENDIF
|
|
#IF (IDE0MODE == IDEMODE_DIDE)
|
|
DEVECHO "DIDE"
|
|
#ENDIF
|
|
#IF (IDE0MODE == IDEMODE_MK4)
|
|
DEVECHO "MK4"
|
|
#ENDIF
|
|
#IF (IDE0MODE == IDEMODE_RC)
|
|
DEVECHO "RC"
|
|
#ENDIF
|
|
DEVECHO ", IO="
|
|
DEVECHO IDE0BASE
|
|
DEVECHO ", SLAVE"
|
|
DEVECHO "\n"
|
|
#ENDIF
|
|
;
|
|
#IF (IDECNT >= 2)
|
|
;
|
|
IDE_DEV1M: ; DEVICE 1, MASTER
|
|
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB IDE1MODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB 0 ; DEVICE TYPE
|
|
.DB IDE_ACC_MAS | (IDE1A8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
|
|
.DB 0 ; MEDIA FLAGS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
.DB IDE1BASE ; IO BASE ADDRESS
|
|
.DB IDE1DATLO ; IO BASE ADDRESS
|
|
.DB IDE1DATHI ; IO BASE ADDRESS
|
|
.DW IDE_DEV1S ; PARTNER
|
|
;
|
|
DEVECHO "IDE: MODE="
|
|
#IF (IDE1MODE == IDEMODE_NONE)
|
|
DEVECHO "NONE"
|
|
#ENDIF
|
|
#IF (IDE1MODE == IDEMODE_DIO)
|
|
DEVECHO "DIO"
|
|
#ENDIF
|
|
#IF (IDE1MODE == IDEMODE_DIDE)
|
|
DEVECHO "DIDE"
|
|
#ENDIF
|
|
#IF (IDE1MODE == IDEMODE_MK4)
|
|
DEVECHO "MK4"
|
|
#ENDIF
|
|
#IF (IDE1MODE == IDEMODE_RC)
|
|
DEVECHO "RC"
|
|
#ENDIF
|
|
DEVECHO ", IO="
|
|
DEVECHO IDE1BASE
|
|
DEVECHO ", MASTER"
|
|
DEVECHO "\n"
|
|
;
|
|
IDE_DEV1S: ; DEVICE 1, SLAVE
|
|
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB IDE1MODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB 0 ; DEVICE TYPE
|
|
.DB (IDE1B8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
|
|
.DB 0 ; MEDIA FLAGS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
.DB IDE1BASE ; IO BASE ADDRESS
|
|
.DB IDE1DATLO ; IO BASE ADDRESS
|
|
.DB IDE1DATHI ; IO BASE ADDRESS
|
|
.DW IDE_DEV1M ; PARTNER
|
|
;
|
|
DEVECHO "IDE: MODE="
|
|
#IF (IDE1MODE == IDEMODE_NONE)
|
|
DEVECHO "NONE"
|
|
#ENDIF
|
|
#IF (IDE1MODE == IDEMODE_DIO)
|
|
DEVECHO "DIO"
|
|
#ENDIF
|
|
#IF (IDE1MODE == IDEMODE_DIDE)
|
|
DEVECHO "DIDE"
|
|
#ENDIF
|
|
#IF (IDE1MODE == IDEMODE_MK4)
|
|
DEVECHO "MK4"
|
|
#ENDIF
|
|
#IF (IDE1MODE == IDEMODE_RC)
|
|
DEVECHO "RC"
|
|
#ENDIF
|
|
DEVECHO ", IO="
|
|
DEVECHO IDE1BASE
|
|
DEVECHO ", SLAVE"
|
|
DEVECHO "\n"
|
|
#ENDIF
|
|
;
|
|
#IF (IDECNT >= 3)
|
|
;
|
|
IDE_DEV2M: ; DEVICE 2, MASTER
|
|
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB IDE2MODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB 0 ; DEVICE TYPE
|
|
.DB IDE_ACC_MAS | (IDE2A8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
|
|
.DB 0 ; MEDIA FLAGS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
.DB IDE2BASE ; IO BASE ADDRESS
|
|
.DB IDE2DATLO ; IO BASE ADDRESS
|
|
.DB IDE2DATHI ; IO BASE ADDRESS
|
|
.DW IDE_DEV2S ; PARTNER
|
|
;
|
|
DEVECHO "IDE: MODE="
|
|
#IF (IDE2MODE == IDEMODE_NONE)
|
|
DEVECHO "NONE"
|
|
#ENDIF
|
|
#IF (IDE2MODE == IDEMODE_DIO)
|
|
DEVECHO "DIO"
|
|
#ENDIF
|
|
#IF (IDE2MODE == IDEMODE_DIDE)
|
|
DEVECHO "DIDE"
|
|
#ENDIF
|
|
#IF (IDE2MODE == IDEMODE_MK4)
|
|
DEVECHO "MK4"
|
|
#ENDIF
|
|
#IF (IDE2MODE == IDEMODE_RC)
|
|
DEVECHO "RC"
|
|
#ENDIF
|
|
DEVECHO ", IO="
|
|
DEVECHO IDE2BASE
|
|
DEVECHO ", MASTER"
|
|
DEVECHO "\n"
|
|
;
|
|
IDE_DEV2S: ; DEVICE 2, SLAVE
|
|
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB IDE2MODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB 0 ; DEVICE TYPE
|
|
.DB (IDE2B8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
|
|
.DB 0 ; MEDIA FLAGS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
.DB IDE2BASE ; IO BASE ADDRESS
|
|
.DB IDE2DATLO ; IO BASE ADDRESS
|
|
.DB IDE2DATHI ; IO BASE ADDRESS
|
|
.DW IDE_DEV1M ; PARTNER
|
|
;
|
|
DEVECHO "IDE: MODE="
|
|
#IF (IDE2MODE == IDEMODE_NONE)
|
|
DEVECHO "NONE"
|
|
#ENDIF
|
|
#IF (IDE2MODE == IDEMODE_DIO)
|
|
DEVECHO "DIO"
|
|
#ENDIF
|
|
#IF (IDE2MODE == IDEMODE_DIDE)
|
|
DEVECHO "DIDE"
|
|
#ENDIF
|
|
#IF (IDE2MODE == IDEMODE_MK4)
|
|
DEVECHO "MK4"
|
|
#ENDIF
|
|
#IF (IDE2MODE == IDEMODE_RC)
|
|
DEVECHO "RC"
|
|
#ENDIF
|
|
DEVECHO ", IO="
|
|
DEVECHO IDE2BASE
|
|
DEVECHO ", SLAVE"
|
|
DEVECHO "\n"
|
|
#ENDIF
|
|
;
|
|
#IF ($ - IDE_CFGTBL) != (IDE_DEVCNT * IDE_CFGSIZ)
|
|
.ECHO "*** INVALID IDE CONFIG TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
.DB $FF ; END OF TABLE MARKER
|
|
;
|
|
; THE IDE_WAITXXX FUNCTIONS ARE BUILT TO TIMEOUT AS NEEDED SO DRIVER WILL
|
|
; NOT HANG IF DEVICE IS UNRESPONSIVE. DIFFERENT TIMEOUTS ARE USED DEPENDING
|
|
; ON THE SITUATION. THE SLOW TIMEOUT IS USED TO WAIT FOR A DEVICE TO
|
|
; BECOME READY AFTER A HARD RESET (SPIN UP, ETC.). THE NORMAL TIMEOUT
|
|
; IS USED DURING NORMAL OPERATION FOR ALL I/O OPERATIONS WHICH SHOULD
|
|
; OCCUR PRETTY FAST. NOTE THAT THE ATA SPEC ALLOWS UP TO 30 SECONDS
|
|
; FOR DEVICES TO RESPOND. WE ARE USING MUCH MORE AGGRESSIVE VALUES
|
|
; BASED ON REAL WORLD EXPERIENCE.
|
|
; THE PICO TIMEOUT (TOPICO) IS A SPECIAL TIMEOUT FOR THE RC2014 SD
|
|
; PICO TO WAIT FOR THE PICO DEVICE TO INITIALIZE.
|
|
;
|
|
IDE_TOSLOW .EQU 200 ; SLOW TIMEOUT IS 20 SECS
|
|
IDE_TONORM .EQU 5 ; NORMAL TIMEOUT IS 0.5 SECS
|
|
IDE_TOPICO .EQU 50 ; RC2014 SD PICO (5 SECONDS)
|
|
;
|
|
;=============================================================================
|
|
; INITIALIZATION ENTRY POINT
|
|
;=============================================================================
|
|
;
|
|
IDE_INIT:
|
|
; COMPUTE CPU SPEED COMPENSATED TIMEOUT SCALER
|
|
; ONE INTERNAL LOOP IN WAITBSY IS 180TS. ON A 1 MHZ CPU, 1 TS
|
|
; TAKES 1NS. SO 1/10 SECOND IS 100000 TS ON A 1 MHZ CPU.
|
|
; SINCE 1 INTERNAL LOOP IS 180 TS, IT TAKES 100000 / 180 = 556
|
|
; INTERNAL LOOPS FOR 1/10 SECOND. SO, WE WANT TO USE
|
|
; 523 * CPU MHZ FOR INTERNAL LOOP COUNT.
|
|
LD DE,556 ; LOAD SCALER FOR 1MHZ
|
|
LD A,(CB_CPUMHZ) ; LOAD CPU SPEED IN MHZ
|
|
CALL MULT8X16 ; HL := DE * A
|
|
LD (IDE_TOSCALER),HL ; SAVE IT
|
|
;
|
|
XOR A ; ZERO ACCUM
|
|
LD (IDE_DEVNUM),A ; INIT DEV UNIT NUM FOR DYNAMIC ASSIGNMENT
|
|
LD IY,IDE_CFGTBL ; POINT TO START OF CONFIG TABLE
|
|
;
|
|
IDE_INIT1:
|
|
LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END
|
|
CP $FF ; CHECK FOR END OF TABLE VALUE
|
|
JR NZ,IDE_INIT2 ; IF NOT END OF TABLE, CONTINUE
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
IDE_INIT2:
|
|
BIT 0,(IY+IDE_ACC) ; MASTER?
|
|
JR Z,IDE_INIT4 ; IF NOT MASTER, SKIP AHEAD
|
|
;
|
|
CALL NEWLINE ; FORMATTING
|
|
PRTS("IDE:$") ; LABEL FOR IO ADDRESS
|
|
;
|
|
PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS
|
|
LD A,(IY+IDE_IOBASE) ; GET IO BASE ADDRES
|
|
CALL PRTHEXBYTE ; DISPLAY IT
|
|
;
|
|
PRTS(" MODE=$") ; LABEL FOR MODE
|
|
LD A,(IY+IDE_MODE) ; GET MODE BITS
|
|
LD DE,IDE_STR_MODE_DIO ; MODE LABEL
|
|
CP IDEMODE_DIO ; TEST FOR MODE
|
|
JR Z,IDE_INIT2A ; IF SO, DISPLAY IT
|
|
LD DE,IDE_STR_MODE_DIDE ; MODE LABEL
|
|
CP IDEMODE_DIDE ; TEST FOR MODE
|
|
JR Z,IDE_INIT2A ; IF SO, DISPLAY IT
|
|
LD DE,IDE_STR_MODE_MK4 ; MODE LABEL
|
|
CP IDEMODE_MK4 ; TEST FOR MODE
|
|
JR Z,IDE_INIT2A ; IF SO, DISPLAY IT
|
|
LD DE,IDE_STR_MODE_RC ; MODE LABEL
|
|
CP IDEMODE_RC ; TEST FOR MODE
|
|
JR Z,IDE_INIT2A ; IF SO, DISPLAY IT
|
|
JR IDE_INIT4 ; NO MODE? BYPASS ENTRY
|
|
IDE_INIT2A:
|
|
CALL WRITESTR ; DISPLAY MODE
|
|
;
|
|
CALL IDE_DETECT ; PROBE FOR INTERFACE
|
|
JR Z,IDE_INIT3 ; GOT IT, MOVE ON TO INIT UNITS
|
|
CALL PC_SPACE ; FORMATTING
|
|
LD DE,IDE_STR_NOHW ; NOT PRESENT MESSAGE
|
|
CALL WRITESTR ; DISPLAY IT
|
|
JR IDE_INIT4 ; SKIP CFG ENTRY
|
|
;
|
|
IDE_INIT3:
|
|
CALL IDE_RESET ; RESET THE BUS
|
|
CALL IDE_INIT5 ; DETECT/INIT MASTER
|
|
PUSH IY ; SAVE CFG PTR
|
|
CALL IDE_GOPARTNER ; SWITCH IY TO PARTNER CFG
|
|
CALL IDE_INIT5 ; DETECT/INIT SLAVE
|
|
POP IY ; RESTORE CFG PTR
|
|
;
|
|
IDE_INIT4:
|
|
LD DE,IDE_CFGSIZ ; SIZE OF CFG TABLE ENTRY
|
|
ADD IY,DE ; BUMP POINTER
|
|
JP IDE_INIT1 ; AND LOOP
|
|
;
|
|
IDE_INIT5:
|
|
; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
|
|
LD A,(IDE_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN
|
|
LD (IY+IDE_DEV),A ; UPDATE IT
|
|
INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN
|
|
LD (IDE_DEVNUM),A ; SAVE IT
|
|
;
|
|
; ADD UNIT TO GLOBAL DISK UNIT TABLE
|
|
LD BC,IDE_FNTBL ; BC := FUNC TABLE ADR
|
|
PUSH IY ; CFG ENTRY POINTER
|
|
POP DE ; COPY TO DE
|
|
CALL DIO_ADDENT ; ADD ENTRY TO GLOBAL DISK DEV TABLE
|
|
;
|
|
; START PRINTING DEVICE INFO
|
|
CALL IDE_PRTPREFIX ; PRINT DEVICE PREFIX
|
|
LD A,(IY+IDE_TYPE)
|
|
LD DE,IDE_STR_TYPEATA
|
|
CP IDE_TYPEATA
|
|
CALL Z,WRITESTR
|
|
LD DE,IDE_STR_TYPEATAPI
|
|
CP IDE_TYPEATAPI
|
|
CALL Z,WRITESTR
|
|
;
|
|
; CHECK FOR BAD STATUS
|
|
LD A,(IY+IDE_STAT) ; GET STATUS
|
|
OR A ; SET FLAGS
|
|
JP Z,IDE_INIT6
|
|
CALL PC_SPACE
|
|
JP NZ,IDE_PRTSTATSTR ; EXIT VIA PRINT STATUS STRING
|
|
;
|
|
IDE_INIT6:
|
|
LD DE,IDE_STR_8BIT
|
|
BIT 1,(IY+IDE_ACC) ; 8 BIT ACCESS?
|
|
CALL NZ,WRITESTR
|
|
;
|
|
; PRINT LBA/NOLBA
|
|
CALL PC_SPACE ; FORMATTING
|
|
BIT 1,(IY+IDE_MED) ; TEST LBA FLAG
|
|
LD DE,IDE_STR_NO ; POINT TO "NO" STRING
|
|
CALL Z,WRITESTR ; PRINT "NO" BEFORE "LBA" IF LBA NOT SUPPORTED
|
|
PRTS("LBA$") ; PRINT "LBA" REGARDLESS
|
|
;
|
|
; PRINT STORAGE CAPACITY (BLOCK COUNT)
|
|
PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL
|
|
LD A,IDE_MEDCAP ; OFFSET TO CAPACITY FIELD
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL LD32 ; GET THE CAPACITY VALUE
|
|
CALL PRTHEX32 ; PRINT HEX VALUE
|
|
;
|
|
; PRINT STORAGE SIZE IN MB
|
|
PRTS(" SIZE=$") ; PRINT FIELD LABEL
|
|
LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
|
|
CALL SRL32 ; RIGHT SHIFT
|
|
;CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED)
|
|
CALL PRTDEC32 ; PRINT DWORD IN DECIMAL
|
|
PRTS("MB$") ; PRINT SUFFIX
|
|
;
|
|
RET
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; PROBE FOR IDE HARDWARE
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
|
|
;
|
|
IDE_DETECT:
|
|
;
|
|
;#IF (IDEMODE == IDEMODE_DIDE)
|
|
;#ENDIF
|
|
;;
|
|
;#IF (IDEMODE == IDEMODE_DIO)
|
|
;#ENDIF
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
;=============================================================================
|
|
; DRIVER FUNCTION TABLE
|
|
;=============================================================================
|
|
;
|
|
IDE_FNTBL:
|
|
.DW IDE_STATUS
|
|
.DW IDE_RESET
|
|
.DW IDE_SEEK
|
|
.DW IDE_READ
|
|
.DW IDE_WRITE
|
|
.DW IDE_VERIFY
|
|
.DW IDE_FORMAT
|
|
.DW IDE_DEVICE
|
|
.DW IDE_MEDIA
|
|
.DW IDE_DEFMED
|
|
.DW IDE_CAP
|
|
.DW IDE_GEOM
|
|
#IF (($ - IDE_FNTBL) != (DIO_FNCNT * 2))
|
|
.ECHO "*** INVALID IDE FUNCTION TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
IDE_VERIFY:
|
|
IDE_FORMAT:
|
|
IDE_DEFMED:
|
|
SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_READ:
|
|
CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR
|
|
LD BC,IDE_RDSEC ; GET ADR OF SECTOR READ FUNC
|
|
LD (IDE_IOFNADR),BC ; SAVE IT AS PENDING IO FUNC
|
|
JR IDE_IO ; CONTINUE TO GENERIC IO ROUTINE
|
|
;
|
|
;
|
|
;
|
|
IDE_WRITE:
|
|
CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR
|
|
LD BC,IDE_WRSEC ; GET ADR OF SECTOR WRITE FUNC
|
|
LD (IDE_IOFNADR),BC ; SAVE IT AS PENDING IO FUNC
|
|
JR IDE_IO ; CONTINUE TO GENERIC IO ROUTINE
|
|
;
|
|
;
|
|
;
|
|
IDE_IO:
|
|
LD (IDE_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS
|
|
LD A,E ; BLOCK COUNT TO A
|
|
OR A ; SET FLAGS
|
|
RET Z ; ZERO SECTOR I/O, RETURN W/ E=0 & A=0
|
|
LD B,A ; INIT SECTOR DOWNCOUNTER
|
|
LD C,0 ; INIT SECTOR READ/WRITE COUNT
|
|
#IF (IDETRACE == 1)
|
|
LD HL,IDE_PRTERR ; SET UP IDE_PRTERR
|
|
PUSH HL ; ... TO FILTER ALL EXITS
|
|
#ENDIF
|
|
PUSH BC ; SAVE COUNTERS
|
|
CALL IDE_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO
|
|
POP BC ; RESTORE COUNTERS
|
|
JR NZ,IDE_IO3 ; BAIL OUT ON ERROR
|
|
IDE_IO1:
|
|
PUSH BC ; SAVE COUNTERS
|
|
CALL IDE_SELUNIT ; HARDWARE SELECTION OF TARGET UNIT
|
|
LD HL,(IDE_IOFNADR) ; GET PENDING IO FUNCTION ADDRESS
|
|
CALL JPHL ; ... AND CALL IT
|
|
JR NZ,IDE_IO2 ; IF ERROR, SKIP INCREMENT
|
|
; INCREMENT LBA
|
|
LD A,IDE_LBA ; LBA OFFSET
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL INC32HL ; INCREMENT THE VALUE
|
|
; INCREMENT DMA
|
|
LD HL,IDE_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
|
|
INC (HL) ; BUMP DMA BY
|
|
INC (HL) ; ... 512 BYTES
|
|
XOR A ; SIGNAL SUCCESS
|
|
IDE_IO2:
|
|
POP BC ; RECOVER COUNTERS
|
|
JR NZ,IDE_IO3 ; IF ERROR, BAIL OUT
|
|
INC C ; BUMP COUNT OF SECTORS READ
|
|
DJNZ IDE_IO1 ; LOOP AS NEEDED
|
|
IDE_IO3:
|
|
LD E,C ; SECTOR READ COUNT TO E
|
|
LD HL,(IDE_DSKBUF) ; CURRENT DMA TO HL
|
|
OR A ; SET FLAGS BASED ON RETURN CODE
|
|
RET Z ; RETURN IF SUCCESS
|
|
LD A,ERR_IO ; SIGNAL IO ERROR
|
|
OR A ; SET FLAGS
|
|
RET ; AND DONE
|
|
;
|
|
;
|
|
;
|
|
IDE_STATUS:
|
|
; RETURN UNIT STATUS
|
|
LD A,(IY+IDE_STAT) ; GET STATUS OF SELECTED DEVICE
|
|
OR A ; SET FLAGS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
IDE_DEVICE:
|
|
LD D,DIODEV_IDE ; D := DEVICE TYPE
|
|
LD E,(IY+IDE_DEV) ; E := PHYSICAL DEVICE NUMBER
|
|
LD C,%01111001 ; ATAPI ATTRIBUTES
|
|
LD A,(IY+IDE_TYPE) ; CHECK TYPE VALUE
|
|
CP IDE_TYPEATAPI ; ATAPI?
|
|
JR Z,IDE_DEVICE1 ; IF SO, DONE
|
|
LD C,%00110001 ; COMPACTFLASH ATTRIBUTES
|
|
BIT 0,(IY+IDE_MED) ; TEST CF BIT IN FLAGS
|
|
JR NZ,IDE_DEVICE1 ; IF SET, DONE
|
|
LD C,%00110000 ; GENERIC HARD DISK ATTRIBUTES
|
|
IDE_DEVICE1:
|
|
LD H,(IY+IDE_MODE) ; H := MODE
|
|
LD L,(IY+IDE_IOBASE) ; L := BASE I/O ADDRESS
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
; IDE_GETMED
|
|
;
|
|
IDE_MEDIA:
|
|
LD A,E ; GET FLAGS
|
|
OR A ; SET FLAGS
|
|
JR Z,IDE_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA
|
|
;
|
|
;CALL IDE_RESET ; RESET IDE INTERFACE
|
|
CALL IDE_INITUNIT ; RE-INITIALIZE UNIT
|
|
;
|
|
IDE_MEDIA1:
|
|
LD A,(IY+IDE_STAT) ; GET STATUS
|
|
OR A ; SET FLAGS
|
|
LD D,0 ; NO MEDIA CHANGE DETECTED
|
|
LD E,MID_HD ; ASSUME WE ARE OK
|
|
RET Z ; RETURN IF GOOD INIT
|
|
LD E,MID_NONE ; SIGNAL NO MEDIA
|
|
LD A,ERR_NOMEDIA ; NO MEDIA ERROR
|
|
OR A ; SET FLAGS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
IDE_SEEK:
|
|
BIT 7,D ; CHECK FOR LBA FLAG
|
|
CALL Z,HB_CHS2LBA ; CLEAR MEANS CHS, CONVERT TO LBA
|
|
RES 7,D ; CLEAR FLAG REGARDLESS (DOES NO HARM IF ALREADY LBA)
|
|
LD (IY+IDE_LBA+0),L ; SAVE NEW LBA
|
|
LD (IY+IDE_LBA+1),H ; ...
|
|
LD (IY+IDE_LBA+2),E ; ...
|
|
LD (IY+IDE_LBA+3),D ; ...
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
IDE_CAP:
|
|
LD A,(IY+IDE_STAT) ; GET STATUS
|
|
PUSH AF ; SAVE IT
|
|
LD A,IDE_MEDCAP ; OFFSET TO CAPACITY FIELD
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL LD32 ; GET THE CURRENT CAPACITY INTO DE:HL
|
|
LD BC,512 ; 512 BYTES PER BLOCK
|
|
POP AF ; RECOVER STATUS
|
|
OR A ; SET FLAGS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_GEOM:
|
|
; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS
|
|
; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE
|
|
CALL IDE_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC
|
|
LD L,H ; DIVIDE BY 256 FOR # TRACKS
|
|
LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL
|
|
LD D,16 | $80 ; HEADS / CYL = 16, SET LBA CAPABILITY BIT
|
|
LD E,16 ; SECTORS / TRACK = 16
|
|
RET ; DONE, A STILL HAS IDE_CAP STATUS
|
|
;
|
|
;=============================================================================
|
|
; FUNCTION SUPPORT ROUTINES
|
|
;=============================================================================
|
|
;
|
|
IDE_SETFEAT:
|
|
PUSH AF
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" SETFEAT$")
|
|
#ENDIF
|
|
LD A,(IDE_DRVHD)
|
|
;OUT (IDE_REG_DRVHD),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_DRVHD
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
POP AF
|
|
;OUT (IDE_REG_FEAT),A ; SET THE FEATURE VALUE
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_FEAT
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
LD A,IDE_CMD_SETFEAT ; CMD = SETFEAT
|
|
LD (IDE_CMD),A ; SAVE IT
|
|
JP IDE_RUNCMD ; RUN COMMAND AND EXIT
|
|
;
|
|
;
|
|
;
|
|
IDE_IDENTIFY:
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" IDDEV$")
|
|
#ENDIF
|
|
LD A,(IDE_DRVHD)
|
|
;OUT (IDE_REG_DRVHD),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_DRVHD
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
LD A,IDE_CMD_IDDEV
|
|
LD (IDE_CMD),A
|
|
CALL IDE_RUNCMD_ND
|
|
RET NZ
|
|
;
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
BIT 3,A ; IS DRQ SET?
|
|
JP Z,IDE_NOMEDIA
|
|
;
|
|
LD HL,HB_WRKBUF
|
|
JP IDE_GETBUF ; EXIT THRU BUFRD
|
|
;
|
|
;
|
|
;
|
|
IDE_IDENTIFYPACKET:
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" IDPKTDEV$")
|
|
#ENDIF
|
|
LD A,(IDE_DRVHD)
|
|
;OUT (IDE_REG_DRVHD),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_DRVHD
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
LD A,IDE_CMD_IDPKTDEV
|
|
LD (IDE_CMD),A
|
|
CALL IDE_RUNCMD_ND
|
|
RET NZ
|
|
;
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
BIT 3,A ; IS DRQ SET?
|
|
JP Z,IDE_NOMEDIA
|
|
;
|
|
LD HL,HB_WRKBUF
|
|
JP IDE_GETBUF ; EXIT THRU BUFRD
|
|
;
|
|
;
|
|
;
|
|
IDE_PACKET:
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" PACKET$")
|
|
#ENDIF
|
|
LD A,(IDE_DRVHD)
|
|
;OUT (IDE_REG_DRVHD),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_DRVHD
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
XOR A ; ZERO
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_FEAT ; FEATURE REG = 0
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_BCL
|
|
LD A,8
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_BCH ; BYTE COUNT = 512????
|
|
LD A,IDE_CMD_PACKET
|
|
LD (IDE_CMD),A
|
|
JP IDE_RUNCMD_ND
|
|
;
|
|
;
|
|
;
|
|
IDE_RDSEC:
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" READ$")
|
|
#ENDIF
|
|
LD A,(IDE_DRVHD)
|
|
;OUT (IDE_REG_DRVHD),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_DRVHD
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
LD A,(IY+IDE_TYPE)
|
|
CP IDE_TYPEATA
|
|
JR Z,IDE_ATA_RDSEC
|
|
CP IDE_TYPEATAPI
|
|
JR Z,IDE_PKT_RDSEC
|
|
JP IDE_CMDERR
|
|
;
|
|
IDE_ATA_RDSEC:
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" ATA$")
|
|
#ENDIF
|
|
CALL IDE_SETADDR ; SETUP CYL, TRK, HEAD
|
|
LD A,IDE_CMD_READ
|
|
LD (IDE_CMD),A
|
|
CALL IDE_RUNCMD
|
|
RET NZ
|
|
LD HL,(IDE_DSKBUF)
|
|
JP IDE_GETBUF
|
|
;
|
|
IDE_PKT_RDSEC:
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" PKT$")
|
|
#ENDIF
|
|
; SETUP LBA
|
|
;
|
|
#IF (DSKYENABLE)
|
|
#IF (DSKYDSKACT)
|
|
LD A,IDE_LBA
|
|
CALL LDHLIYA
|
|
CALL HB_DSKACT ; SHOW ACTIVITY
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
|
|
LD HL,IDE_PKTCMD_RW10+3 ; START OF LBA FIELD IN CDB (MSB)
|
|
LD A,(IY+IDE_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IY+IDE_LBA+1)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IY+IDE_LBA+0)
|
|
LD (HL),A
|
|
INC HL
|
|
LD HL,IDE_PKTCMD_RW10
|
|
LD A,SCSI_CMD_READ10
|
|
LD (HL),A
|
|
XOR A ; READ DIRECTION
|
|
LD (IDE_XFRDIR),A ; SAVE IT
|
|
CALL IDE_RUNPCMD
|
|
JP NZ,IDE_CHKPCMD
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_WRSEC:
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" WRITE$")
|
|
#ENDIF
|
|
LD A,(IDE_DRVHD)
|
|
;OUT (IDE_REG_DRVHD),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_DRVHD
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
LD A,(IY+IDE_TYPE)
|
|
CP IDE_TYPEATA
|
|
JR Z,IDE_ATA_WRSEC
|
|
CP IDE_TYPEATAPI
|
|
JR Z,IDE_PKT_WRSEC
|
|
JP IDE_CMDERR
|
|
;
|
|
IDE_ATA_WRSEC:
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" ATA$")
|
|
#ENDIF
|
|
CALL IDE_SETADDR ; SETUP CYL, TRK, HEAD
|
|
LD A,IDE_CMD_WRITE
|
|
LD (IDE_CMD),A
|
|
CALL IDE_RUNCMD
|
|
RET NZ
|
|
LD HL,(IDE_DSKBUF)
|
|
JP IDE_PUTBUF
|
|
;
|
|
IDE_PKT_WRSEC:
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" PKT$")
|
|
#ENDIF
|
|
; SETUP LBA
|
|
;
|
|
#IF (DSKYENABLE)
|
|
#IF (DSKYDSKACT)
|
|
LD A,IDE_LBA
|
|
CALL LDHLIYA
|
|
CALL HB_DSKACT ; SHOW ACTIVITY
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
|
|
LD HL,IDE_PKTCMD_RW10+3 ; START OF LBA FIELD IN CDB (MSB)
|
|
LD A,(IY+IDE_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IY+IDE_LBA+1)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IY+IDE_LBA+0)
|
|
LD (HL),A
|
|
INC HL
|
|
LD HL,IDE_PKTCMD_RW10
|
|
LD A,SCSI_CMD_WRITE10
|
|
LD (HL),A
|
|
OR $FF ; WRITE DIRECTION
|
|
LD (IDE_XFRDIR),A ; SAVE IT
|
|
CALL IDE_RUNPCMD
|
|
JP NZ,IDE_CHKPCMD
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_SETADDR:
|
|
;
|
|
#IF (DSKYENABLE)
|
|
#IF (DSKYDSKACT)
|
|
LD A,IDE_LBA
|
|
CALL LDHLIYA
|
|
CALL HB_DSKACT ; SHOW ACTIVITY
|
|
#ENDIF
|
|
#ENDIF
|
|
; SEND 3 LOWEST BYTES OF LBA IN REVERSE ORDER
|
|
; IDE_REG_LBA3 HAS ALREADY BEEN SET
|
|
; HSTLBA2-0 --> IDE_REG_LBA2-0
|
|
LD A,(IY+IDE_LBA+2)
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_LBA2
|
|
;
|
|
LD A,(IY+IDE_LBA+1)
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_LBA1
|
|
;
|
|
LD A,(IY+IDE_LBA+0)
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_LBA0
|
|
;
|
|
LD A,1
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_COUNT
|
|
;
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; COMMAND PROCESSING
|
|
;=============================================================================
|
|
;
|
|
; RUN AN ATA COMMAND. THERE ARE TWO ENTRY POINTS. THE NORMAL ENTRY
|
|
; POINT WILL WAIT FOR DRIVE READY. THE _ND ENTRY POINT ONLY WAITS
|
|
; FOR THE DEVICE TO BE NOT BUSY. THE CORRECT ENTRY POINT DEPENDS ON
|
|
; THE COMMAND.
|
|
;
|
|
IDE_RUNCMD_ND:
|
|
CALL IDE_WAITBSY ; WAIT WHILE DEVICE BUSY
|
|
RET NZ ; BAIL OUT ON TIMEOUT
|
|
JR IDE_RUNCMD1 ; CONTINUE
|
|
|
|
IDE_RUNCMD:
|
|
CALL IDE_WAITRDY ; WAIT FOR DRIVE READY
|
|
RET NZ ; BAIL OUT ON TIMEOUT
|
|
;
|
|
IDE_RUNCMD1:
|
|
LD A,(IDE_CMD) ; GET THE COMMAND
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;OUT (IDE_REG_CMD),A ; SEND IT (STARTS EXECUTION)
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_CMD
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" -->$")
|
|
#ENDIF
|
|
;
|
|
CALL IDE_WAITBSY ; WAIT FOR DRIVE READY (COMMAND DONE)
|
|
RET NZ ; BAIL OUT ON TIMEOUT
|
|
;
|
|
CALL IDE_GETRES
|
|
JP NZ,IDE_CMDERR
|
|
RET
|
|
;
|
|
; PACKET COMMAND PROCESSOR
|
|
; HL: ADDRESS OF PACKET COMMAND BUFFER
|
|
;
|
|
IDE_RUNPCMD:
|
|
PUSH HL
|
|
CALL IDE_PACKET
|
|
POP HL
|
|
RET NZ ; BAIL OUT ON ERROR
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
PRTS("\r\nPKTCMD:$")
|
|
PUSH HL
|
|
POP DE
|
|
LD A,12
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; IF ZIP DRIVE HAS FALLEN ASLEEP, THEN IT WILL NEED EXTRA
|
|
; TIME HERE TO WAKE UP BEFORE ACCEPTING THE COMMAND. USE
|
|
; LONG TIMEOUT TO ACCOMMODATE THIS.
|
|
LD DE,(IDE_TIMEOUT) ; GET CURRENT TIMEOUT
|
|
PUSH DE ; SAVE IT
|
|
LD DE,IDE_TOSLOW ; SLOW TIMEOUT FOR THIS
|
|
LD (IDE_TIMEOUT),DE ; SET IT
|
|
LD B,6 ; 6 WORDS ALWAYS
|
|
CALL IDE_PUT
|
|
POP DE ; RECOVER TIMEOUT
|
|
LD (IDE_TIMEOUT),DE ; SET IT
|
|
RET NZ
|
|
;
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
BIT 3,A ; IS DRQ SET?
|
|
RET Z ; IF NOT, ALL DONE
|
|
;
|
|
CALL IDE_IN
|
|
.DB IDE_REG_BCL
|
|
LD C,A
|
|
CALL IDE_IN
|
|
.DB IDE_REG_BCH
|
|
LD B,A
|
|
;
|
|
; BELOW ASSUMES MAX TRANSFER OF 512 BYTES!!!
|
|
PUSH BC ; SAVE BYTE COUNT
|
|
SRL B ; CONVERT
|
|
RR C ; ... TO WORDS
|
|
LD B,C
|
|
;LD HL,HB_WRKBUF ; SET XFR BUFFER
|
|
LD HL,(IDE_DSKBUF) ; SET XFR BUFFER
|
|
|
|
LD A,(IDE_XFRDIR)
|
|
OR A
|
|
JR NZ,IDE_RUNPCMD2 ; NZ = WRITE
|
|
CALL IDE_GET ; GET SOME DATA
|
|
JR IDE_RUNPCMD3
|
|
IDE_RUNPCMD2:
|
|
CALL IDE_PUT ; PUT SOME DATA
|
|
IDE_RUNPCMD3:
|
|
POP BC ; RESTORE BYTE COUNT
|
|
RET NZ ; BAIL OUT ON ERRORS
|
|
;
|
|
XOR A
|
|
RET
|
|
;
|
|
; THE FOLLOWING IS USED TO ASSESS ANY ERROR THAT OCCURS DURING
|
|
; RUNCMD AND SET AN APPROPRIATE ERROR CODE.
|
|
;
|
|
IDE_CHKPCMD:
|
|
;
|
|
LD HL,HB_WRKBUF
|
|
LD (IDE_DSKBUF),HL
|
|
LD HL,IDE_PKTCMD_SENSE
|
|
CALL IDE_RUNPCMD
|
|
RET NZ
|
|
;
|
|
CALL IDE_IN
|
|
.DB IDE_REG_BCL
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL NEWLINE
|
|
LD DE,HB_WRKBUF
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; ASSESS SENSE DATA AND SET APPROPRIATE ERROR
|
|
LD A,(HB_WRKBUF+12)
|
|
CP $3A
|
|
JP Z,IDE_NOMEDIA
|
|
CP $04
|
|
JP Z,IDE_NOTRDY
|
|
;
|
|
JP IDE_CMDERR
|
|
;
|
|
; HL=BUFFER
|
|
;
|
|
IDE_GETBUF:
|
|
LD B,0
|
|
; FALL THRU!!!
|
|
;
|
|
; HL=BUFFER
|
|
; B=WORD COUNT, 0=256
|
|
;
|
|
IDE_GET:
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" GET$")
|
|
#ENDIF
|
|
;
|
|
; WAIT FOR BUFFER
|
|
PUSH BC
|
|
PUSH HL
|
|
CALL IDE_WAITDRQ ; WAIT FOR BUFFER READY
|
|
POP HL
|
|
POP BC
|
|
RET NZ ; BAIL OUT IF TIMEOUT
|
|
;
|
|
LD A,B ; WORD COUNT IN A
|
|
;
|
|
BIT 1,(IY+IDE_ACC) ; 8 BIT?
|
|
JR Z,IDE_GET1 ; IF NOT, DO 16 BIT
|
|
CALL IDE_GET8 ; DO 8 BIT
|
|
JR IDE_GET2
|
|
;
|
|
IDE_GET1:
|
|
CALL IDE_GET16
|
|
;
|
|
IDE_GET2:
|
|
CALL IDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED!
|
|
CALL IDE_GETRES
|
|
JP NZ,IDE_IOERR
|
|
RET
|
|
;
|
|
IDE_GET8:
|
|
; 8 BIT I/O
|
|
;LD C,IDE_REG_DATA
|
|
LD C,(IY+IDE_IOBASE)
|
|
LD B,A
|
|
INIR
|
|
LD B,A
|
|
INIR
|
|
RET
|
|
;
|
|
IDE_GET16:
|
|
; 16 BIT I/O
|
|
;LD C,IDE_REG_DATAHI
|
|
LD D,(IY+IDE_DATALO)
|
|
LD E,(IY+IDE_DATAHI)
|
|
CALL IDE_GET16A ; GET FIRST 256 BYTES
|
|
RET
|
|
;
|
|
IDE_GET16A:
|
|
LD C,D ; PORT FOR LSB
|
|
INI ; GET IT, SAVE IT, AND DEC B
|
|
LD C,E ; PORT FOR MSB
|
|
INI ; GET IT, SAVE IT, AND DEC B
|
|
DEC A
|
|
JR NZ,IDE_GET16A ; LOOP TILL COUNTER EXHAUSTED
|
|
RET
|
|
;
|
|
; HL=BUFFER
|
|
;
|
|
IDE_PUTBUF:
|
|
LD B,0
|
|
; FALL THRU!!!
|
|
;
|
|
; HL=BUFFER
|
|
; B=WORD COUNT, 0=256
|
|
;
|
|
IDE_PUT:
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" PUT$")
|
|
#ENDIF
|
|
;
|
|
; WAIT FOR BUFFER
|
|
PUSH BC
|
|
PUSH HL
|
|
CALL IDE_WAITDRQ ; WAIT FOR BUFFER READY
|
|
POP HL
|
|
POP BC
|
|
RET NZ ; BAIL OUT IF TIMEOUT
|
|
;
|
|
LD A,B ; WORD COUNT IN A
|
|
;
|
|
BIT 1,(IY+IDE_ACC) ; 8 BIT?
|
|
JR Z,IDE_PUT1 ; IF NOT, DO 16 BIT
|
|
CALL IDE_PUT8 ; DO 8 BIT
|
|
JR IDE_PUT2
|
|
;
|
|
IDE_PUT1:
|
|
CALL IDE_PUT16
|
|
;
|
|
IDE_PUT2:
|
|
CALL IDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED!
|
|
CALL IDE_GETRES
|
|
JP NZ,IDE_IOERR
|
|
RET
|
|
;
|
|
IDE_PUT8:
|
|
; 8 BIT I/O
|
|
;LD C,IDE_REG_DATA
|
|
LD C,(IY+IDE_IOBASE)
|
|
LD B,A
|
|
OTIR
|
|
LD B,A
|
|
OTIR
|
|
RET
|
|
;
|
|
IDE_PUT16:
|
|
; 16 BIT I/O
|
|
;LD C,IDE_REG_DATAHI
|
|
LD D,(IY+IDE_DATALO)
|
|
LD E,(IY+IDE_DATAHI)
|
|
CALL IDE_PUT16A ; PUT FIRST 256 BYTES
|
|
RET
|
|
;
|
|
IDE_PUT16A:
|
|
LD C,D ; PORT FOR LSB
|
|
OUTI ; PUT IT AND DEC B
|
|
LD C,E ; PORT FOR MSB
|
|
OUTI ; PUT IT AND DEC B
|
|
DEC A
|
|
JR NZ,IDE_PUT16A ; LOOP TILL COUNTER EXHAUSTED
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_GETRES:
|
|
;IN A,(IDE_REG_STAT) ; GET STATUS
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
AND %00000001 ; ERROR BIT SET?
|
|
RET Z ; NOPE, RETURN WITH ZF
|
|
;
|
|
;IN A,(IDE_REG_ERR) ; READ ERROR REGISTER
|
|
CALL IDE_IN
|
|
.DB IDE_REG_ERR
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
OR $FF ; FORCE NZ TO SIGNAL ERROR
|
|
RET ; RETURN
|
|
;
|
|
;=============================================================================
|
|
; HARDWARE INTERFACE ROUTINES
|
|
;=============================================================================
|
|
;
|
|
; RESET ALL DEVICES ON BUS
|
|
;
|
|
IDE_RESET:
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" RESET$")
|
|
#ENDIF
|
|
;
|
|
; HARD RESET
|
|
;
|
|
; RESET LINE IS NORMALLY PULSED AT POWER ON. HOWEVER, THIS IS NOT
|
|
; DONE FOR MK4 BUILT-IN IDE PORT, SO WE DO IT NOW.
|
|
;
|
|
LD A,(IY+IDE_MODE) ; GET MODE
|
|
CP IDEMODE_MK4 ; MK4?
|
|
JR NZ,IDE_RESET2 ; IF NOT, BYPASS
|
|
;
|
|
; USE HARDWARE RESET LINE
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" HARD$")
|
|
#ENDIF
|
|
LD A,$80 ; HIGH BIT OF XAR IS IDE RESET
|
|
;OUT (IDE_REG_XAR),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_XAR
|
|
LD DE,20 ; DELAY 32US (SPEC IS >= 25US)
|
|
CALL VDELAY
|
|
XOR A ; CLEAR RESET BIT
|
|
;OUT (IDE_REG_XAR),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_XAR
|
|
LD DE,20
|
|
CALL VDELAY
|
|
;
|
|
; SOME CF CARDS AND CF CARD EMULATORS NEED A LITTLE TIME TO
|
|
; "BOOT" THEIR INTERNAL ELECTRONICS, SO THEY CANNOT ASSERT BUSY
|
|
; IMMEDIATELY. A SMALL WAIT IS PERFORMED HERE TO GIVE SUCH DEVICES
|
|
; A BETTER CHANCE TO SUCCEED LATER.
|
|
;
|
|
; LD DE,150000 / 16 ;
|
|
LD DE,300000 / 16 ;
|
|
CALL VDELAY ; SMALL DELAY
|
|
;
|
|
JR IDE_RESET3 ; SKIP SOFT RESET
|
|
;
|
|
; SOFT RESET
|
|
;
|
|
; RC CANNOT ACCESS DEVICE CONTROL REG, SO SKIP THIS
|
|
;
|
|
IDE_RESET2:
|
|
LD A,(IY+IDE_MODE) ; GET MODE
|
|
CP IDEMODE_RC ; RCBUS?
|
|
JR Z,IDE_RESET4 ; IF SO, BYPASS
|
|
;
|
|
; INITIATE SOFT RESET
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" SOFT$")
|
|
#ENDIF
|
|
LD A,%00001110 ; ASSERT RESET, NO INTERRUPTS
|
|
;OUT (IDE_REG_CTRL),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_CTRL
|
|
LD DE,20 ; DELAY 320US (SPEC IS >= 25US)
|
|
CALL VDELAY
|
|
;
|
|
IDE_RESET3:
|
|
;
|
|
; CONFIGURE OPERATION AND END SOFT RESET
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" CONFIG$")
|
|
#ENDIF
|
|
LD DE,20 ; DELAY 320US (SPEC IS >= 25US)
|
|
CALL VDELAY
|
|
LD A,%00001010 ; DEASSERT RESET, NO INTERRUPTS
|
|
;OUT (IDE_REG_CTRL),A ; PUSH TO REGISTER
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_CTRL
|
|
;
|
|
IDE_RESET4:
|
|
LD HL,IDE_TONORM ; NORMAL TIMEOUT NOW
|
|
LD (IDE_TIMEOUT),HL ; AND RESTORE IT
|
|
;
|
|
; INITIALIZE THE INDIVIDUAL UNITS (MASTER AND SLAVE).
|
|
; BASED ON TESTING, IT APPEARS THAT THE MASTER UNIT MUST
|
|
; BE DONE FIRST OR THIS BEHAVES BADLY.
|
|
;
|
|
PUSH IY ; SAVE CFG PTR
|
|
BIT 0,(IY+IDE_ACC) ; MASTER?
|
|
CALL Z,IDE_GOPARTNER ; IF NOT, SWITCH TO MASTER
|
|
CALL IDE_INITUNIT ; INIT CURRENT UNIT
|
|
CALL IDE_GOPARTNER ; POINT TO SLAVE
|
|
CALL IDE_INITUNIT ; INIT PARTNER UNIT
|
|
POP IY ; RECOVER ORIG CFG PTR
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND DONE
|
|
;
|
|
;
|
|
;
|
|
IDE_INITUNIT:
|
|
CALL IDE_SELUNIT ; SELECT UNIT
|
|
RET NZ ; ABORT IF ERROR
|
|
|
|
CALL IDE_PROBE ; DO PROBE
|
|
RET NZ ; JUST RETURN IF NOTHING THERE
|
|
|
|
JP IDE_INITDEV ; EXIT VIA INITDEV
|
|
;
|
|
; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT
|
|
;
|
|
IDE_SELUNIT:
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" SELUNIT$")
|
|
#ENDIF
|
|
BIT 0,(IY+IDE_ACC) ; MASTER?
|
|
JR Z,IDE_SELUNIT1 ; HANDLE SLAVE
|
|
LD A,IDE_DRVMASTER ; MASTER
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" MASTER$")
|
|
#ENDIF
|
|
JR IDE_SELUNIT2
|
|
IDE_SELUNIT1:
|
|
LD A,IDE_DRVSLAVE ; SLAVE
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" SLAVE$")
|
|
#ENDIF
|
|
IDE_SELUNIT2:
|
|
LD (IDE_DRVHD),A ; SAVE IT
|
|
XOR A ; SUCCESS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_PROBE:
|
|
;
|
|
; PROBE FOR A DRIVE ON THE INTERFACE (EITHER MASTER OR SLAVE).
|
|
; IDEALLY, THIS IS BEING CALLED IMMEDIATELY AFTER A HARD OR SOFT
|
|
; INTERFACE RESET. HOWEVER, THERE ARE SOME HARDWARE IMPLEMENTATTIONS
|
|
; WHICH ARE CAPABLE OF NEITHER A HARD NOR SOFT RESET. SO THIS
|
|
; CODE SHOULD TRY TO HANDLE THE SCENARIO WHERE NO INTERFACE RESET
|
|
; HAS OCCURRED.
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" PROBE$") ; LABEL FOR IO ADDRESS
|
|
#ENDIF
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
; SELECT DEVICE (MASTER/SLAVE)
|
|
LD A,(IDE_DRVHD)
|
|
;OUT (IDE_REG_DRVHD),A
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_DRVHD
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
CALL DELAY ; DELAY ~16US
|
|
;
|
|
; THE RC2014 SD PICO TAKES A FEW SECONDS TO INITIALIZE. ATEMPTING TO
|
|
; ACCESS IT DURING THIS TIME WILL FAIL. THE DATA LINES ALL HAVE
|
|
; PULL-DOWN RESISTORS, SO WHILE IT IS INITIALIZING, READING ANY
|
|
; REGISTER WILL CONSISTENTLY RETURN $00. THE FOLLOWING BIT OF CODE
|
|
; WILL SCAN THE IDE REGISTER BLOCK. WHILE ALL REGISTERS REMAIN ZERO,
|
|
; WE WAIT (UNTIL TIMEOUT). IN MY TESTING, IT SEEMS VERY UNLIKELY
|
|
; THAT ANY OTHER DEVICE WILL RETURN $00 FOR ALL REGISTERS.
|
|
;
|
|
LD A,(IY+IDE_MODE) ; GET MODE BITS
|
|
CP IDEMODE_RC ; RCBUS?
|
|
JR NZ,IDE_PROBE0 ; IF NOT, BYPASS
|
|
;
|
|
LD A,(IDE_DRVHD) ; GET CURRENT SETTING
|
|
BIT 4,A ; TEST SLAVE BIT
|
|
JR NZ,IDE_PROBE0 ; IF SO, BYPASS
|
|
;
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
OR A ; SET FLAGS
|
|
JR NZ,IDE_PROBE0 ; SKIP IF NOT $00
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" PICO$")
|
|
#ENDIF
|
|
LD HL,500 ; 5 SECONDS
|
|
IDE_WAIT001:
|
|
;CALL NEWLINE
|
|
LD C,(IY+IDE_IOBASE)
|
|
LD B,8 ; NUMBER OF REGISTERS TO CHECK
|
|
IDE_WAIT002:
|
|
IN A,(C) ; GET REGISTER VALUE
|
|
;CALL PC_SPACE
|
|
;CALL PRTHEXBYTE
|
|
OR A ; SET FLAGS
|
|
JR NZ,IDE_PROBE0 ; IF NOT ZERO, MOVE ON
|
|
INC C ; NEXT REGISTER
|
|
DJNZ IDE_WAIT002 ; CHECK ALL 8 REGS
|
|
LD DE,10000/16 ; .01 SECONDS
|
|
CALL VDELAY
|
|
DEC HL
|
|
LD A,H
|
|
OR L
|
|
JR NZ,IDE_WAIT001 ; LOOP
|
|
;JP IDE_NOMEDIA ; GIVE UP?
|
|
;
|
|
; IF WE GET HERE AND THE DRIVE IS STILL INITIALIZING, WE NEED TO
|
|
; WAIT UNTIL THE DRIVE IS READY. IN THIS CASE BUSY *WILL* BE HIGH.
|
|
; BASED ON TESTING, DRDY AND DSC VALUES VARY. EVERYTHING ELSE SEEMS
|
|
; TO BE ZERO. SO, WE FILTER OUT DRDY & DSC, THEN LOOK FOR BUSY=1
|
|
; AND ALL ELSE ZERO. THIS GENERALLY AVOIDS VALUES THAT ARE TYPICAL
|
|
; FOR FLOATING PORTS AND SO CAN BE USED TO DETERMINE IF WE NEED TO
|
|
; WAIT FOR THE DEVICE TO BE READY. THIS WAIT IS MANDATORY BECAUSE
|
|
; SOME (IF NOT ALL) DEVICES WILL NOT PERSIST REGISTER VALUES UNTIL
|
|
; THE DRIVE IS READY.
|
|
;
|
|
IDE_PROBE0:
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
AND %10101111 ; FILTER OUT DRDY & DSC
|
|
CP $80 ; INIT IN PROGRESS?
|
|
JR NZ,IDE_PROBE1 ; IF NOT, SKIP AHEAD
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
PRTS(" WAIT$")
|
|
#ENDIF
|
|
;
|
|
LD HL,(IDE_TIMEOUT) ; GET CURRENT TIMEOUT
|
|
PUSH HL ; SAVE IT
|
|
LD HL,IDE_TOSLOW ; SLOW TIMEOUT FOR THIS
|
|
LD (IDE_TIMEOUT),HL ; SET IT
|
|
CALL IDE_WAITBSY ; WAIT FOR BUSY TO CLEAR
|
|
POP HL ; RECOVER TIMEOUT
|
|
LD (IDE_TIMEOUT),HL ; SET IT
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
; TEST FOR PRESENCE OF IDE REGISTERS. USE LBA0/1 TO SEE
|
|
; IF VALUE CAN BE PERSISTED. THE USE OF BOTH LBA0 AND LBA1
|
|
; IS TO MAINTAIN CONSISTENCY WITH THE THE PPIDE DRIVER BECAUSE
|
|
; PPI ITSELF WILL PERSIST THE LAST VALUE WRITTEN, SO WE USE
|
|
; MULTIPLE REGISTERS TO WORK AROUND THIS FALSE POSITIVE.
|
|
;
|
|
IDE_PROBE1:
|
|
; $AA -> LBA0
|
|
LD A,$AA
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_LBA0
|
|
;
|
|
; $55 => LBA1
|
|
LD A,$55
|
|
CALL IDE_OUT
|
|
.DB IDE_REG_LBA1
|
|
;
|
|
; TEST LBA0 == $AA
|
|
CALL IDE_IN
|
|
.DB IDE_REG_LBA0
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
CP $AA
|
|
JP NZ,IDE_NOMEDIA
|
|
;
|
|
; TEST LBA1 == $55
|
|
CALL IDE_IN
|
|
.DB IDE_REG_LBA1
|
|
#IF (IDETRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
CP $55
|
|
JP NZ,IDE_NOMEDIA
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_REGDUMP
|
|
#ENDIF
|
|
;
|
|
XOR A
|
|
RET
|
|
;
|
|
; (RE)INITIALIZE DEVICE
|
|
;
|
|
IDE_INITDEV:
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" INITDEV$") ; LABEL FOR IO ADDRESS
|
|
#ENDIF
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_REGDUMP
|
|
#ENDIF
|
|
;
|
|
; ON ENTRY, WE HAVE ALREADY CHECKED THAT THE BUSY BIT IS CLEARED AND
|
|
; DRDY SHOULD BE SET. IF DRDY IS NOT SET, IF COULD MEAN EITHER A
|
|
; NON-EXISTENT SLAVE DEVICE OR AN ATAPI DEVICE. TO AVOID UNNECESSARY
|
|
; TIMEOUTS, WE CHECK FOR DRDY. IF IT IS NOT SET, THEN WE ASSUME THIS
|
|
; MUST BE AN ATAPI DEVICE AND GO TRY TO DO THE ATAPI INITIALIZATION.
|
|
; IF THIS WAS ACTUALLY A NON-EXISTENT SLAVE, THE ATAPI INITIALIZATION
|
|
; WILL HANDLE THIS PRETTY WELL.
|
|
;
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
BIT 6,A ; DRDY?
|
|
JR Z,IDE_INITPDEV ; ODD, MIGHT BE ATAPI
|
|
;
|
|
; WE NEED TO SETUP 8-BIT MODE BEFORE DOING ANYTHING ELSE
|
|
;
|
|
BIT 1,(IY+IDE_ACC) ; 8 BIT ACCESS?
|
|
JR Z,IDE_INITDEV0 ; NO, DO 16 BIT INIT
|
|
LD A,IDE_FEAT_ENABLE8BIT ; FEATURE VALUE = ENABLE 8-BIT PIO
|
|
CALL IDE_SETFEAT ; SET FEATURE
|
|
RET NZ ; BAIL OUT ON ERROR
|
|
JR IDE_INITDEV00 ; CONTINUE
|
|
;
|
|
IDE_INITDEV0:
|
|
; "REAL" IDE DRIVES MAY NOT ACCEPT THE DISABLE8BIT FEATURE COMMAND,
|
|
; SO IT IS ONLY AN ERROR IF WE ARE ATTEMPTING TO ENABLE8BIT.
|
|
; CREDIT TO ED BRINDLEY FOR THIS CORRECTION. SO ERROR RETURN IGNORED HERE.
|
|
LD A,IDE_FEAT_DISABLE8BIT ; FEATURE VALUE = ENABLE 8-BIT PIO
|
|
CALL IDE_SETFEAT ; SET FEATURE, IGNORE ERRORS
|
|
;
|
|
IDE_INITDEV00:
|
|
;
|
|
; WE NOW USE AN IDENTIFY DEVICE COMMAND TO CONFIRM THE
|
|
; DEVICE IS REALLY THERE AND GET SOME ATTRIBUTES. IF THE
|
|
; COMMAND FAILS, IT MAY BE THAT WE HAVE AN ATAPI DEVICE AND
|
|
; SO WE GO TO THE ATAPI INITIALIZATION ON FAILURE.
|
|
CALL IDE_IDENTIFY ; EXECUTE IDENTIFY COMMAND
|
|
JR NZ,IDE_INITPDEV ; TRY ATAPI ON FAILURE
|
|
;
|
|
; DECLARE WE ARE ATA
|
|
LD A,IDE_TYPEATA ; OTHERWISE TYPE=ATA
|
|
LD (IY+IDE_TYPE),A ; SET IT IN INSTANCE DATA
|
|
;
|
|
LD DE,HB_WRKBUF ; POINT TO BUFFER
|
|
#IF (IDETRACE >= 4)
|
|
CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING
|
|
#ENDIF
|
|
;
|
|
LD (IY+IDE_MED),0 ; CLEAR MEDIA FLAGS
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" SIG=0x$")
|
|
LD BC,(HB_WRKBUF)
|
|
CALL PRTHEXWORD
|
|
#ENDIF
|
|
;
|
|
; DETERMINE IF COMPACTFLASH MEDIA
|
|
LD A,(HB_WRKBUF+(83*2)) ; LOW BYTE OF WORD 83
|
|
BIT 2,A ; TEST CFA FEATURE SET BIT
|
|
JR Z,IDE_INITDEV1 ; IF NOT, SKIP
|
|
SET 0,(IY+IDE_MED) ; ELSE SET FLAGS BIT FOR CF MEDIA
|
|
;
|
|
IDE_INITDEV1:
|
|
; DETERMINE IF LBA CAPABLE
|
|
LD A,(HB_WRKBUF+98+1) ; HIGH BYTE OF WORD 49
|
|
BIT 1,A ; CHECK THE LBA BIT
|
|
JR Z,IDE_INITDEV2 ; NOT SET, BYPASS
|
|
SET 1,(IY+IDE_MED) ; SET FLAGS BIT FOR LBA
|
|
;
|
|
IDE_INITDEV2:
|
|
; GET DEVICE CAPACITY AND SAVE IT
|
|
LD A,IDE_MEDCAP ; OFFSET TO CAPACITY FIELD
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
PUSH HL ; SAVE POINTER
|
|
LD HL,HB_WRKBUF ; POINT TO BUFFER START
|
|
LD A,120 ; OFFSET OF SECTOR COUNT
|
|
CALL ADDHLA ; POINT TO ADDRESS OF SECTOR COUNT
|
|
CALL LD32 ; LOAD IT TO DE:HL
|
|
POP BC ; RECOVER POINTER TO CAPACITY ENTRY
|
|
CALL ST32 ; SAVE CAPACITY
|
|
;
|
|
; RECORD STATUS OK
|
|
XOR A ; A := 0 (STATUS = OK)
|
|
LD (IY+IDE_STAT),A ; SAVE IT
|
|
;
|
|
RET ; RETURN, A=0, Z SET
|
|
;
|
|
; (RE)INITIALIZE PACKET DEVICE
|
|
;
|
|
IDE_INITPDEV:
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
CALL IDE_PRTPREFIX
|
|
PRTS(" INITPDEV$") ; LABEL FOR IO ADDRESS
|
|
#ENDIF
|
|
;
|
|
CALL IDE_IDENTIFYPACKET ; EXECUTE IDENTIFY COMMAND
|
|
RET NZ ; BAIL OUT ON ERROR
|
|
;
|
|
; DECLARE WE ARE ATAPI
|
|
LD A,IDE_TYPEATAPI ; OTHERWISE TYPE=ATAPI
|
|
LD (IY+IDE_TYPE),A ; SET IT IN INSTANCE DATA
|
|
;
|
|
LD DE,HB_WRKBUF ; POINT TO BUFFER
|
|
#IF (IDETRACE >= 4)
|
|
CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING
|
|
#ENDIF
|
|
;
|
|
LD (IY+IDE_MED),0 ; CLEAR FLAGS
|
|
SET 1,(IY+IDE_MED) ; SET FLAGS BIT FOR LBA (ASSUMED)
|
|
;
|
|
; WAIT FOR UNIT READY
|
|
LD B,0 ; MAX LOOPS
|
|
LD C,4 ; MAX ERRORS
|
|
IDE_INITPDEV1:
|
|
DEC B ; CHECK LOOP COUNTER EXCEEDED
|
|
JP Z,IDE_NOMEDIA ; TREAT AS NO MEDIA
|
|
PUSH BC ; SAVE LOOP CONTROL
|
|
LD HL,IDE_PKTCMD_TSTRDY ; TEST UNIT READY
|
|
XOR A ; READ DIRECTION
|
|
LD (IDE_XFRDIR),A ; SAVE IT
|
|
CALL IDE_RUNPCMD ; ISSUE PACKET COMMAND
|
|
CALL NZ,IDE_CHKPCMD ; IF ERROR, DIAGNOSE IT
|
|
POP BC ; RESTORE LOOP CONTROL
|
|
JR Z,IDE_INITPDEV2 ; IF NO ERROR, CONTINUE
|
|
CP IDE_STNOMEDIA ; EXPLICIT NO MEDIA RESULT?
|
|
RET Z ; EXIT REPORTING NO MEDIA
|
|
CP IDE_STNOTRDY ; BECOMING READY?
|
|
JR Z,IDE_INITDEVP1A ; IF SO, NOT AN ERROR, LOOP
|
|
DEC C ; DEC ERROR LIMIT
|
|
RET Z ; BAIL OUT, ERR LIMIT EXCEEDED
|
|
JR IDE_INITPDEV1 ; LOOP
|
|
IDE_INITDEVP1A:
|
|
LD DE,100000/16 ; WAIT 1/10 SECOND
|
|
CALL VDELAY ; DO IT
|
|
JR IDE_INITPDEV1 ; AND LOOP
|
|
;
|
|
IDE_INITPDEV2:
|
|
#IF (IDETRACE >= 3)
|
|
LD A,B
|
|
NEG
|
|
PRTS("\r\nLOOPS=$")
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
; GET AND RECORD CAPACITY
|
|
LD HL,HB_WRKBUF
|
|
LD (IDE_DSKBUF),HL
|
|
LD HL,IDE_PKTCMD_RDCAP
|
|
XOR A ; READ DIRECTION
|
|
LD (IDE_XFRDIR),A ; SAVE IT
|
|
CALL IDE_RUNPCMD
|
|
JP NZ,IDE_CHKPCMD
|
|
;
|
|
#IF (IDETRACE >= 3)
|
|
PRTS("\r\nRDCAP:$")
|
|
LD A,8
|
|
LD DE,HB_WRKBUF
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; CAPACITY IS RETURNED IN A 4 BYTE, BIG ENDIAN FIELD AND
|
|
; INDICATES THE LAST LBA VALUE. WE NEED TO CONVERT THIS TO
|
|
; LITTLE ENDIAN AND INCREMENT THE VALUE TO MAKE IT A CAPACITY
|
|
; COUNT INSTEAD OF A LAST LBA VALUE.
|
|
LD A,IDE_MEDCAP ; OFFSET IN CFG FOR CAPACITY
|
|
CALL LDHLIYA ; POINTER TO HL
|
|
PUSH HL ; SAVE IT
|
|
LD HL,HB_WRKBUF ; POINT TO VALUE IN CMD RESULT
|
|
CALL LD32 ; LOAD IT TO DE:HL
|
|
LD A,L ; FLIP BYTES
|
|
LD L,D ; ... BIG ENDIAN
|
|
LD D,A ; ... TO LITTLE ENDIAN
|
|
LD A,H
|
|
LD H,E
|
|
LD E,A
|
|
CALL INC32 ; INCREMENT TO FINAL VALUE
|
|
POP BC ; RECOVER SAVE LOCATION
|
|
CALL ST32 ; STORE VALUE
|
|
;
|
|
; CHECK BLOCK LENGTH. WE CURRENTLY ONLY SUPPORT 512 BYTE
|
|
; BLOCKS. CD-ROM DEVICES (WHICH USE 2k BLOCKS) WILL FAIL
|
|
; HERE AS NOT SUPPORTED.
|
|
LD HL,HB_WRKBUF+4 ; POINT TO BLK SIZE IN RESULT
|
|
CALL LD32 ; LOAD IT TO DE:HL
|
|
; VALUE IS BIG ENDIAN, SO LH:ED MUST BE EXACTLY 0000:0200
|
|
LD A,L ; CHECK THAT LH
|
|
OR H ; ... IS ZERO
|
|
JP NZ,IDE_NOTSUP ; IF NOT, FAIL AS NOT SUP
|
|
LD A,D ; LOAD D
|
|
OR A ; SET FLAGS
|
|
JP NZ,IDE_NOTSUP ; IF NOT ZERO, FAIL AS NOT SUP
|
|
LD A,E ; LOAD E
|
|
CP 2 ; CHECK IT IF IS 2
|
|
JP NZ,IDE_NOTSUP ; IF NOT, FAIL AS NOT SUP
|
|
;
|
|
; CHECK BLOCK LENGTH. WE CURRENTLY ONLY SUPPORT 512 BYTE
|
|
; BLOCKS. CD-ROM DEVICES (WHICH USE 2k BLOCKS) WILL FAIL
|
|
; HERE AS NOT SUPPORTED.
|
|
LD HL,HB_WRKBUF+4 ; POINT TO BLK SIZE IN RESULT
|
|
CALL LD32 ; LOAD IT TO DE:HL
|
|
; VALUE IS BIG ENDIAN, SO LH:ED MUST BE EXACTLY 0000:0200
|
|
LD A,L ; CHECK THAT LH
|
|
OR H ; ... IS ZERO
|
|
JP NZ,IDE_NOTSUP ; IF NOT, FAIL AS NOT SUP
|
|
LD A,D ; LOAD E
|
|
OR A ; SET FLAGS
|
|
JP NZ,IDE_NOTSUP ; IF NOT ZERO, FAIL AS NOT SUP
|
|
LD A,E ; LOAD D
|
|
CP 2 ; CHECK IT IF IS 2
|
|
JP NZ,IDE_NOTSUP ; IF NOT, FAIL AS NOT SUP
|
|
;
|
|
; RECORD STATUS OK
|
|
XOR A ; A := 0 (STATUS = OK)
|
|
LD (IY+IDE_STAT),A ; SAVE IT
|
|
RET
|
|
;
|
|
; SWITCH IY POINTER FROM CURRENT UNIT CFG TO PARTNER UNIT CFG
|
|
;
|
|
IDE_GOPARTNER:
|
|
PUSH HL ; SAVE HL
|
|
LD L,(IY+IDE_PARTNER) ; GET PARTNER ENTRY
|
|
LD H,(IY+IDE_PARTNER+1) ; ...
|
|
PUSH HL ; MOVE HL
|
|
POP IY ; ... TO IY
|
|
POP HL ; RESTORE INCOMING HL
|
|
RET ; AND DONE
|
|
;
|
|
; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER
|
|
; VIA RESET IF DEVICE IS IN ERROR.
|
|
;
|
|
IDE_CHKERR:
|
|
LD A,(IY+IDE_STAT) ; GET STATUS
|
|
OR A ; SET FLAGS
|
|
CALL NZ,IDE_RESET ; IF ERROR STATUS, RESET BUS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_WAITRDY:
|
|
LD A,(IDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS
|
|
LD B,A ; PUT IN OUTER LOOP VAR
|
|
IDE_WAITRDY1:
|
|
LD DE,(IDE_TOSCALER) ; CPU SPEED SCALER TO INNER LOOP VAR
|
|
IDE_WAITRDY2:
|
|
;IN A,(IDE_REG_STAT) ; READ STATUS
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
LD C,A ; SAVE IT
|
|
AND %11000000 ; ISOLATE BUSY AND RDY BITS
|
|
XOR %01000000 ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1
|
|
RET Z ; ALL SET, RETURN WITH Z SET
|
|
DEC DE
|
|
LD A,D
|
|
OR E
|
|
JR NZ,IDE_WAITRDY2 ; INNER LOOP RETURN
|
|
DJNZ IDE_WAITRDY1 ; OUTER LOOP RETURN
|
|
JP IDE_RDYTO ; EXIT WITH RDYTO ERR
|
|
;
|
|
;
|
|
;
|
|
IDE_WAITDRQ:
|
|
LD A,(IDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS
|
|
LD B,A ; PUT IN OUTER LOOP VAR
|
|
IDE_WAITDRQ1:
|
|
LD DE,(IDE_TOSCALER) ; CPU SPPED SCALER TO INNER LOOP VAR
|
|
IDE_WAITDRQ2:
|
|
;IN A,(IDE_REG_STAT) ; READ STATUS
|
|
CALL IDE_IN
|
|
.DB IDE_REG_STAT
|
|
LD C,A ; SAVE IT
|
|
AND %10001000 ; TO FILL (OR READY TO FILL)
|
|
XOR %00001000
|
|
RET Z
|
|
DEC DE
|
|
LD A,D
|
|
OR E
|
|
JR NZ,IDE_WAITDRQ2
|
|
DJNZ IDE_WAITDRQ1
|
|
JP IDE_DRQTO ; EXIT WITH BUFTO ERR
|
|
;
|
|
;
|
|
;
|
|
IDE_WAITBSY:
|
|
LD A,(IDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS
|
|
LD B,A ; PUT IN OUTER LOOP VAR
|
|
IDE_WAITBSY1:
|
|
LD DE,(IDE_TOSCALER) ; CPU SPPED SCALER TO INNER LOOP VAR
|
|
IDE_WAITBSY2:
|
|
;IN A,(IDE_REG_STAT) ; READ STATUS
|
|
CALL IDE_IN ; 17TS + 121TS
|
|
.DB IDE_REG_STAT
|
|
LD C,A ; SAVE IT ; 4TS
|
|
AND %10000000 ; TO FILL (OR READY TO FILL) ; 7TS
|
|
RET Z ; 5TS
|
|
DEC DE ; 6TS
|
|
LD A,D ; 4TS
|
|
OR E ; 4TS
|
|
JR NZ,IDE_WAITBSY2 ; 12TS
|
|
DJNZ IDE_WAITBSY1 ; -----
|
|
JP IDE_BSYTO ; EXIT WITH BSYTO ERR ; 180
|
|
;
|
|
; READ A VALUE FROM THE DEVICE POINTED TO BY IY AND RETURN IT IN A
|
|
;
|
|
IDE_IN:
|
|
EX (SP),HL ; GET PARM POINTER ; 19TS
|
|
PUSH BC ; 11TS
|
|
LD A,(HL) ; 7TS
|
|
INC HL ; 6TS
|
|
LD C,(IY+IDE_IOBASE) ; 19TS
|
|
ADD A,C ; 4TS
|
|
LD C,A ; 4TS
|
|
IN A,(C) ; 12TS
|
|
POP BC ; 10TS
|
|
EX (SP),HL ; RESTORE STACK ; 19TS
|
|
RET ; 10TS
|
|
; ; ----
|
|
; OUTPUT VALUE IN A TO THE DEVICE POINTED TO BY IY ; 121TS
|
|
;
|
|
IDE_OUT:
|
|
EX (SP),HL ; GET PARM POINTER
|
|
PUSH BC
|
|
PUSH AF
|
|
LD A,(HL)
|
|
INC HL
|
|
LD C,(IY+IDE_IOBASE)
|
|
ADD A,C
|
|
LD C,A
|
|
POP AF
|
|
OUT (C),A
|
|
POP BC
|
|
EX (SP),HL ; RESTORE STACK
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; ERROR HANDLING AND DIAGNOSTICS
|
|
;=============================================================================
|
|
;
|
|
; ERROR HANDLERS
|
|
;
|
|
IDE_INVUNIT:
|
|
LD A,IDE_STINVUNIT
|
|
JR IDE_ERR2 ; SPECIAL CASE FOR INVALID UNIT
|
|
;
|
|
IDE_NOMEDIA:
|
|
LD A,IDE_STNOMEDIA
|
|
JR IDE_ERR
|
|
;
|
|
IDE_CMDERR:
|
|
LD A,IDE_STCMDERR
|
|
JR IDE_ERR
|
|
;
|
|
IDE_IOERR:
|
|
LD A,IDE_STIOERR
|
|
JR IDE_ERR
|
|
;
|
|
IDE_RDYTO:
|
|
LD A,IDE_STRDYTO
|
|
JR IDE_ERR
|
|
;
|
|
IDE_DRQTO:
|
|
LD A,IDE_STDRQTO
|
|
JR IDE_ERR
|
|
;
|
|
IDE_BSYTO:
|
|
LD A,IDE_STBSYTO
|
|
JR IDE_ERR
|
|
;
|
|
IDE_NOTSUP:
|
|
LD A,IDE_STNOTSUP
|
|
JR IDE_ERR
|
|
;
|
|
IDE_NOTRDY:
|
|
LD A,IDE_STNOTRDY
|
|
JR IDE_ERR
|
|
;
|
|
IDE_ERR:
|
|
LD (IY+IDE_STAT),A ; SAVE NEW STATUS
|
|
;
|
|
IDE_ERR2:
|
|
#IF (IDETRACE >= 2)
|
|
CALL IDE_PRTSTAT
|
|
CALL IDE_REGDUMP
|
|
#ENDIF
|
|
OR A ; SET FLAGS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_PRTERR:
|
|
RET Z ; DONE IF NO ERRORS
|
|
; FALL THRU TO IDE_PRTSTAT
|
|
;
|
|
; PRINT FULL DEVICE STATUS LINE
|
|
;
|
|
IDE_PRTSTAT:
|
|
PUSH AF
|
|
PUSH DE
|
|
PUSH HL
|
|
LD A,(IY+IDE_STAT)
|
|
CP IDE_STINVUNIT
|
|
JR Z,IDE_PRTSTAT2 ; INVALID UNIT IS SPECIAL CASE
|
|
CALL IDE_PRTPREFIX ; PRINT UNIT PREFIX
|
|
JR IDE_PRTSTAT3
|
|
IDE_PRTSTAT2:
|
|
CALL NEWLINE
|
|
PRTS("IDE:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT
|
|
IDE_PRTSTAT3:
|
|
CALL PC_SPACE ; FORMATTING
|
|
CALL IDE_PRTSTATSTR
|
|
POP HL
|
|
POP DE
|
|
POP AF
|
|
RET
|
|
;
|
|
; PRINT STATUS STRING
|
|
;
|
|
IDE_PRTSTATSTR:
|
|
PUSH AF
|
|
PUSH DE
|
|
LD A,(IY+IDE_STAT)
|
|
OR A
|
|
LD DE,IDE_STR_STOK
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STINVUNIT
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STNOMEDIA
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STCMDERR
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STIOERR
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STRDYTO
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STDRQTO
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STBSYTO
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STNOTSUP
|
|
JR Z,IDE_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IDE_STR_STNOTRDY
|
|
JR Z,IDE_PRTSTATSTR1
|
|
LD DE,IDE_STR_STUNK
|
|
IDE_PRTSTATSTR1:
|
|
CALL WRITESTR
|
|
POP DE
|
|
POP AF
|
|
RET
|
|
;
|
|
; PRINT ALL REGISTERS DIRECTLY FROM DEVICE
|
|
; DEVICE MUST BE SELECTED PRIOR TO CALL
|
|
;
|
|
IDE_REGDUMP:
|
|
PUSH AF
|
|
PUSH BC
|
|
CALL PC_SPACE
|
|
CALL PC_LBKT
|
|
;LD C,IDE_REG_CMD
|
|
LD A,(IY+IDE_IOBASE)
|
|
ADD A,IDE_REG_CMD
|
|
LD C,A
|
|
LD B,7
|
|
IDE_REGDUMP1:
|
|
IN A,(C)
|
|
CALL PRTHEXBYTE
|
|
DEC C
|
|
DEC B
|
|
CALL NZ,PC_SPACE
|
|
JR NZ,IDE_REGDUMP1
|
|
CALL PC_RBKT
|
|
POP BC
|
|
POP AF
|
|
RET
|
|
;
|
|
; PRINT DIAGNONSTIC PREFIX
|
|
;
|
|
IDE_PRTPREFIX:
|
|
PUSH AF
|
|
CALL NEWLINE
|
|
PRTS("IDE$")
|
|
LD A,(IY+IDE_DEV) ; GET CURRENT DEVICE NUM
|
|
CP $FE ; NOT YET ASSIGNED?
|
|
JR Z,IDE_PRTPREFIX1 ; SKIP DEV NUM IF SO
|
|
CALL PRTDECB
|
|
IDE_PRTPREFIX1:
|
|
CALL PC_COLON
|
|
POP AF
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; STRING DATA
|
|
;=============================================================================
|
|
;
|
|
IDE_STR_STOK .TEXT "OK$"
|
|
IDE_STR_STINVUNIT .TEXT "INVALID UNIT$"
|
|
IDE_STR_STNOMEDIA .TEXT "NO MEDIA$"
|
|
IDE_STR_STCMDERR .TEXT "COMMAND ERROR$"
|
|
IDE_STR_STIOERR .TEXT "IO ERROR$"
|
|
IDE_STR_STRDYTO .TEXT "READY TIMEOUT$"
|
|
IDE_STR_STDRQTO .TEXT "DRQ TIMEOUT$"
|
|
IDE_STR_STBSYTO .TEXT "BUSY TIMEOUT$"
|
|
IDE_STR_STNOTSUP .TEXT "NOT SUPPORTED$"
|
|
IDE_STR_STNOTRDY .TEXT "NOT READY$"
|
|
IDE_STR_STUNK .TEXT "UNKNOWN ERROR$"
|
|
;
|
|
IDE_STR_NO .TEXT "NO$"
|
|
IDE_STR_NOHW .TEXT "NOT PRESENT$"
|
|
IDE_STR_8BIT .TEXT " 8-BIT$"
|
|
;
|
|
IDE_STR_MODE_DIO .TEXT "DIO$"
|
|
IDE_STR_MODE_DIDE .TEXT "DIDE$"
|
|
IDE_STR_MODE_MK4 .TEXT "MK4$"
|
|
IDE_STR_MODE_RC .TEXT "RC$"
|
|
;
|
|
IDE_STR_TYPEATA .TEXT " ATA$"
|
|
IDE_STR_TYPEATAPI .TEXT " ATAPI$"
|
|
;
|
|
;=============================================================================
|
|
; DATA STORAGE
|
|
;=============================================================================
|
|
;
|
|
IDE_TIMEOUT .DB IDE_TONORM ; WAIT FUNCS TIMEOUT IN TENTHS OF SEC
|
|
IDE_TOSCALER .DW CPUMHZ * 556 ; WAIT FUNCS SCALER FOR CPU SPEED
|
|
;
|
|
IDE_CMD .DB 0 ; PENDING COMMAND TO PROCESS
|
|
IDE_IOFNADR .DW 0 ; PENDING IO FUNCTION ADDRESS
|
|
IDE_DRVHD .DB 0 ; CURRENT DRIVE/HEAD MASK
|
|
;
|
|
IDE_DSKBUF .DW 0 ; ACTIVE DISK BUFFER
|
|
IDE_XFRDIR .DB 0 ; 0=READ, NON-0=WRITE
|
|
;
|
|
IDE_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT
|
|
;
|
|
; SCSI COMMAND TEMPLATES (ALWAYS 12 BYTES FOR ATAPI)
|
|
;
|
|
IDE_PKTCMD_RW .DB $00, $00, $00, $00, $01, $00, $00, $00, $00, $00, $00, $00 ; READ/WRITE SECTOR
|
|
IDE_PKTCMD_SENSE .DB $03, $00, $00, $00, $FF, $00, $00, $00, $00, $00, $00, $00 ; REQUEST SENSE DATA
|
|
IDE_PKTCMD_RDCAP .DB $25, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; READ CAPACITY
|
|
IDE_PKTCMD_RW10 .DB $28, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00 ; READ/WRITE SECTOR
|
|
IDE_PKTCMD_TSTRDY .DB $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; TEST UNIT READY
|
|
|