; ;============================================================================= ; IDE DISK DRIVER ;============================================================================= ; ; TODO: ; - FIX SCALER CONSTANT ; - GOPARTNER NEEDS TO HANDLE "NO PARTNER" CONDITION ; - IMPLEMENT H/W PROBES FOR DIO AND DIDE ; ; 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_IO_ALTSTAT | 0x0E | R | ALTERNATE STATUS REGISTER | ; | IDE_IO_CTRL | 0x0E | W | DEVICE CONTROL REGISTER | ; | IDE_IO_DRVADR | 0x0F | R | DRIVE ADDRESS REGISTER | ; +-----------------------+-------+-------+-------------------------------+ ; ; +-----------------------+-------+-------+-------------------------------+ ; | COMMAND BLOCK REGISTERS | ; +-----------------------+-------+-------+-------------------------------+ ; | REGISTER | PORT | DIR | DESCRIPTION | ; +-----------------------+-------+-------+-------------------------------+ ; | IDE_IO_DATA | 0x00 | R/W | DATA INPUT/OUTPUT | ; | IDE_IO_ERR | 0x01 | R | ERROR REGISTER | ; | IDE_IO_FEAT | 0x01 | W | FEATURES REGISTER | ; | IDE_IO_COUNT | 0x02 | R/W | SECTOR COUNT REGISTER | ; | IDE_IO_SECT | 0x03 | R/W | SECTOR NUMBER REGISTER | ; | IDE_IO_CYLLO | 0x04 | R/W | CYLINDER NUM REGISTER (LSB) | ; | IDE_IO_CYLHI | 0x05 | R/W | CYLINDER NUM REGISTER (MSB) | ; | IDE_IO_DRVHD | 0x06 | R/W | DRIVE/HEAD REGISTER | ; | IDE_IO_LBA0* | 0x03 | R/W | LBA BYTE 0 (BITS 0-7) | ; | IDE_IO_LBA1* | 0x04 | R/W | LBA BYTE 1 (BITS 8-15) | ; | IDE_IO_LBA2* | 0x05 | R/W | LBA BYTE 2 (BITS 16-23) | ; | IDE_IO_LBA3* | 0x06 | R/W | LBA BYTE 3 (BITS 24-27) | ; | IDE_IO_STAT | 0x07 | R | STATUS REGISTER | ; | IDE_IO_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_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_CIDE_RECAL .EQU $10 IDE_CIDE_READ .EQU $20 IDE_CIDE_WRITE .EQU $30 IDE_CIDE_IDDEV .EQU $EC IDE_CIDE_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 ; 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 ; ; 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 0 ; DRIVER DEVICE NUMBER .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 ; IDE_DEV0S: ; DEVICE 0, SLAVE .DB 0 ; DRIVER DEVICE NUMBER .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 #ENDIF ; #IF (IDECNT >= 2) ; IDE_DEV1M: ; DEVICE 1, MASTER .DB 0 ; DRIVER DEVICE NUMBER .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 ; IDE_DEV1S: ; DEVICE 1, SLAVE .DB 0 ; DRIVER DEVICE NUMBER .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 #ENDIF ; #IF (IDECNT >= 3) ; IDE_DEV2M: ; DEVICE 2, MASTER .DB 0 ; DRIVER DEVICE NUMBER .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 ; IDE_DEV2S: ; DEVICE 2, SLAVE .DB 0 ; DRIVER DEVICE NUMBER .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 #ENDIF ; #IF ($ - IDE_CFGTBL) != (IDE_DEVCNT * IDE_CFGSIZ) .ECHO "*** INVALID IDE CONFIG TABLE ***\n" #ENDIF ; .DB $FF ; END 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. GENERALLY, THE FAST TIMEOUT IS USED TO PROBE FOR DEVICES ; USING FUNCTIONS THAT PERFORM NO I/O. OTHERWISE THE NORMAL TIMEOUT IS USED. ; IDE SPEC ALLOWS FOR UP TO 30 SECS MAX TO RESPOND. IN PRACTICE, THIS IS WAY ; TOO LONG, BUT IF YOU ARE USING A VERY OLD DEVICE, THESE TIMEOUTS MAY NEED TO ; BE ADJUSTED. NOTE THAT THESE ARE BYTE VALUES, SO YOU CANNOT EXCEED 255. ; THE TIMEOUTS ARE IN UNITS OF .05 SECONDS. ; IDE_TONORM .EQU 200 ; NORMAL TIMEOUT IS 10 SECS IDE_TOFAST .EQU 10 ; FAST TIMEOUT IS 0.5 SECS ; ;============================================================================= ; INITIALIZATION ENTRY POINT ;============================================================================= ; IDE_INIT: ; COMPUTE CPU SPEED COMPENSATED TIMEOUT SCALER ; AT 1MHZ, THE SCALER IS 218 (50000US / 229TS = 218) ; SCALER IS THEREFORE 218 * CPU SPEED IN MHZ LD DE,961 ; 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 ; ; CHECK FOR BAD STATUS LD A,(IY+IDE_STAT) ; GET STATUS OR A ; SET FLAGS JP NZ,IDE_PRTSTAT ; EXIT VIA PRINT STATUS ; CALL IDE_PRTPREFIX ; PRINT DEVICE PREFIX ; 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) 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: CALL SYSCHK ; NOT IMPLEMENTED LD A,ERR_NOTIMPL OR A 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_SELUNIT ; HARDWARE SELECTION OF TARGET UNIT 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 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 BIT 0,(IY+IDE_MED) ; TEST CF BIT IN FLAGS LD C,%00000000 ; ASSUME NON-REMOVABLE HARD DISK JR Z,IDE_DEVICE1 ; IF Z, WE ARE DONE LD C,%01001000 ; OTHERWISE REMOVABLE COMPACT FLASH 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_MEDIA2 ; JUST REPORT CURRENT STATUS AND MEDIA ; ; GET CURRENT STATUS LD A,(IY+IDE_STAT) ; GET STATUS OR A ; SET FLAGS JR NZ,IDE_MEDIA1 ; ERROR ACTIVE, GO RIGHT TO RESET ; ; USE IDENTIFY COMMAND TO CHECK DEVICE LD HL,IDE_TIMEOUT ; POINT TO TIMEOUT LD (HL),IDE_TOFAST ; USE FAST TIMEOUT DURING IDENTIFY COMMAND CALL IDE_SELUNIT ; HARDWARE SELECTION OF TARGET UNIT CALL IDE_IDENTIFY ; EXECUTE IDENTIFY COMMAND LD HL,IDE_TIMEOUT ; POINT TO TIMEOUT LD (HL),IDE_TONORM ; BACK TO NORMAL TIMEOUT JR Z,IDE_MEDIA2 ; IF SUCCESS, BYPASS RESET ; IDE_MEDIA1: CALL IDE_RESET ; RESET IDE INTERFACE ; IDE_MEDIA2: 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_IO_DRVHD),A CALL IDE_OUT .DB IDE_REG_DRVHD #IF (IDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF POP AF ;OUT (IDE_IO_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_CIDE_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_IO_DRVHD),A CALL IDE_OUT .DB IDE_REG_DRVHD #IF (IDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF LD A,IDE_CIDE_IDDEV LD (IDE_CMD),A CALL IDE_RUNCMD RET NZ LD HL,HB_WRKBUF JP IDE_GETBUF ; EXIT THRU BUFRD ; ; ; IDE_RDSEC: ; #IF (IDETRACE >= 3) CALL IDE_PRTPREFIX PRTS(" READ$") #ENDIF LD A,(IDE_DRVHD) ;OUT (IDE_IO_DRVHD),A CALL IDE_OUT .DB IDE_REG_DRVHD #IF (IDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CALL IDE_SETADDR ; SETUP CYL, TRK, HEAD LD A,IDE_CIDE_READ LD (IDE_CMD),A CALL IDE_RUNCMD RET NZ LD HL,(IDE_DSKBUF) JP IDE_GETBUF ; ; ; IDE_WRSEC: ; #IF (IDETRACE >= 3) CALL IDE_PRTPREFIX PRTS(" WRITE$") #ENDIF LD A,(IDE_DRVHD) ;OUT (IDE_IO_DRVHD),A CALL IDE_OUT .DB IDE_REG_DRVHD #IF (IDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CALL IDE_SETADDR ; SETUP CYL, TRK, HEAD LD A,IDE_CIDE_WRITE LD (IDE_CMD),A CALL IDE_RUNCMD RET NZ LD HL,(IDE_DSKBUF) JP IDE_PUTBUF ; ; ; IDE_SETADDR: ; #IF (DSKYENABLE) LD A,IDE_LBA CALL LDHLIYA CALL HB_DSKACT ; SHOW ACTIVITY #ENDIF ; SEND 3 LOWEST BYTES OF LBA IN REVERSE ORDER ; IDE_IO_LBA3 HAS ALREADY BEEN SET ; HSTLBA2-0 --> IDE_IO_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 ;;; ;;#IF (DSKYENABLE) ;; CALL IDE_DSKY ;;#ENDIF ; RET ; ;============================================================================= ; COMMAND PROCESSING ;============================================================================= ; IDE_RUNCMD: CALL IDE_WAITRDY ; WAIT FOR DRIVE READY RET NZ ; BAIL OUT ON TIMEOUT ; LD A,(IDE_CMD) ; GET THE COMMAND #IF (IDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ;OUT (IDE_IO_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 ; ; ; IDE_GETBUF: #IF (IDETRACE >= 3) PRTS(" GETBUF$") #ENDIF ; CALL IDE_WAITDRQ ; WAIT FOR BUFFER READY RET NZ ; BAIL OUT IF TIMEOUT ; LD B,0 ; BIT 1,(IY+IDE_ACC) ; 8 BIT? JR Z,IDE_GETBUF1 ; IF NOT, DO 16 BIT CALL IDE_GETBUF8 ; DO 8 BIT JR IDE_GETBUF2 ; IDE_GETBUF1: CALL IDE_GETBUF16 ; IDE_GETBUF2: CALL IDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED! CALL IDE_GETRES JP NZ,IDE_IOERR RET ; IDE_GETBUF8: ; 8 BIT I/O ;LD C,IDE_IO_DATA LD C,(IY+IDE_IOBASE) INIR INIR RET ; IDE_GETBUF16: ; 16 BIT I/O ;LD C,IDE_IO_DATAHI LD D,(IY+IDE_DATALO) LD E,(IY+IDE_DATAHI) CALL IDE_GETBUF16A ; GET FIRST 256 BYTES CALL IDE_GETBUF16A ; GET SECOND 256 BYTES RET ; IDE_GETBUF16A: 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 JR NZ,IDE_GETBUF16A ; LOOP TILL COUNTER EXHAUSTED RET ; ; ; IDE_PUTBUF: #IF (IDETRACE >= 3) PRTS(" PUTBUF$") #ENDIF ; CALL IDE_WAITDRQ ; WAIT FOR BUFFER READY RET NZ ; BAIL OUT IF TIMEOUT ; LD B,0 ; BIT 1,(IY+IDE_ACC) ; 8 BIT? JR Z,IDE_PUTBUF1 ; IF NOT, DO 16 BIT CALL IDE_PUTBUF8 ; DO 8 BIT JR IDE_PUTBUF2 ; IDE_PUTBUF1: CALL IDE_PUTBUF16 ; IDE_PUTBUF2: CALL IDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED! CALL IDE_GETRES JP NZ,IDE_IOERR RET ; IDE_PUTBUF8: ; 8 BIT I/O ;LD C,IDE_IO_DATA LD C,(IY+IDE_IOBASE) OTIR OTIR RET ; IDE_PUTBUF16: ; 16 BIT I/O ;LD C,IDE_IO_DATAHI LD D,(IY+IDE_DATALO) LD E,(IY+IDE_DATAHI) CALL IDE_PUTBUF16A ; PUT FIRST 256 BYTES CALL IDE_PUTBUF16A ; PUT SECOND 256 BYTES RET ; IDE_PUTBUF16A: LD C,D ; PORT FOR LSB OUTI ; PUT IT AND DEC B LD C,E ; PORT FOR MSB OUTI ; PUT IT AND DEC B JR NZ,IDE_PUTBUF16A ; LOOP TILL COUNTER EXHAUSTED RET ; ; ; IDE_GETRES: ;IN A,(IDE_IO_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_IO_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 ; ;#IF (IDEMODE == IDEMODE_RC) ; ; OLDER CF CARDS DO NOT SEEM TO SET THE ; REGISTERS ON RESET, SO HERE WE FAKE THINGS BY ; SETTING THEM AS A RESET WOULD. SO WE ALWAYS ; DO THE FAKE. ;LD A,(IY+IDE_MODE) ; GET MODE ;CP IDEMODE_RC ; RC2014? ;JR NZ,IDE_RESET2 ; IF NOT, BYPASS ; ; RC2014 CANNOT ADDRESS THE DEVICE CONTROL PORT AND ; HAS NO WAY TO PERFORM A HARD RESET FROM SOFTWARE, ; SO FAKE IT BY SETTING THE REGISTERS TO THE SAME ; VALUES THAT A RESET WOULD CAUSE. #IF (IDETRACE >= 3) PRTS(" FAKE$") #ENDIF XOR A ;OUT (IDE_IO_CYLLO),A CALL IDE_OUT .DB IDE_REG_CYLLO ;OUT (IDE_IO_CYLHI),A CALL IDE_OUT .DB IDE_REG_CYLHI INC A ;OUT (IDE_IO_COUNT),A CALL IDE_OUT .DB IDE_REG_COUNT ;OUT (IDE_IO_SECT),A CALL IDE_OUT .DB IDE_REG_SECT ; IDE_RESET2: ; ;#ENDIF ; ;#IF (IDEMODE == IDEMODE_MK4) ; LD A,(IY+IDE_MODE) ; GET MODE CP IDEMODE_MK4 ; MK4? JR NZ,IDE_RESET1 ; 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_IO_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_IO_XAR),A CALL IDE_OUT .DB IDE_REG_XAR LD DE,20 CALL VDELAY ; IDE_RESET1: ; ;#ENDIF ; ;#IF ((IDEMODE != IDEMODE_MK4) & (IDEMODE != IDEMODE_RC)) ; LD A,(IY+IDE_MODE) ; GET MODE CP IDEMODE_MK4 ; MK4? JR Z,IDE_RESET3 ; IF SO, BYPASS CP IDEMODE_RC ; RC2014? JR Z,IDE_RESET3 ; IF SO, BYPASS ; ; INITIATE SOFT RESET #IF (IDETRACE >= 3) PRTS(" SOFT$") #ENDIF LD A,%00001110 ; NO INTERRUPTS, ASSERT RESET BOTH DRIVES ;OUT (IDE_IO_CTRL),A CALL IDE_OUT .DB IDE_REG_CTRL ; IDE_RESET3: ; ;#ENDIF ; LD DE,2 ; DELAY 32US (SPEC IS >= 25US) CALL VDELAY ; ;#IF (IDEMODE != IDEMODE_RC) ; LD A,(IY+IDE_MODE) ; GET MODE CP IDEMODE_RC ; RC2014? JR Z,IDE_RESET4 ; IF SO, BYPASS ; ; CONFIGURE OPERATION AND END SOFT RESET #IF (IDETRACE >= 3) PRTS(" CONFIG$") #ENDIF LD A,%00001010 ; NO INTERRUPTS, DEASSERT RESET ;OUT (IDE_IO_CTRL),A ; PUSH TO REGISTER CALL IDE_OUT .DB IDE_REG_CTRL ; IDE_RESET4: ; ;#ENDIF ; ; SPEC ALLOWS UP TO 450MS FOR DEVICES TO ASSERT THEIR PRESENCE ; VIA -DASP. I ENCOUNTER PROBLEMS LATER ON IF I DON'T WAIT HERE ; FOR THAT TO OCCUR. THUS FAR, IT APPEARS THAT 150MS IS SUFFICIENT ; FOR ANY DEVICE ENCOUNTERED. MAY NEED TO EXTEND BACK TO 500MS ; IF A SLOWER DEVICE IS ENCOUNTERED. ; ;LD DE,500000/16 ; ~500MS LD DE,150000/16 ; ~???MS CALL VDELAY ; ; 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 LD HL,IDE_TIMEOUT ; POINT TO TIMEOUT LD (HL),IDE_TONORM ; SET NORMAL TIMEOUT CALL IDE_PROBE ; DO PROBE RET NZ ; JUST RETURN IF NOTHING THERE CALL IDE_INITDEV ; IF FOUND, ATTEMPT TO INIT DEVICE RET ; DONE ; ; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT ; UNIT IS SPECIFIED IN IDE_UNIT ; REGISTER A IS DESTROYED ; 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 JR IDE_SELUNIT2 IDE_SELUNIT1: LD A,IDE_DRVSLAVE ; SLAVE IDE_SELUNIT2: LD (IDE_DRVHD),A ; SAVE IT XOR A ; SUCCESS RET ; ; ; IDE_PROBE: #IF (IDETRACE >= 3) CALL IDE_PRTPREFIX PRTS(" PROBE$") ; LABEL FOR IO ADDRESS #ENDIF ; LD A,(IDE_DRVHD) ;OUT (IDE_IO_DRVHD),A CALL IDE_OUT .DB IDE_REG_DRVHD #IF (IDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CALL DELAY ; DELAY ~16US ; ;LD C,IDE_IO_STAT ;IN A,(C) CALL IDE_IN .DB IDE_REG_STAT #IF (IDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CP $FF JP Z,IDE_NOMEDIA CP $78 JP Z,IDE_NOMEDIA ; #IF (IDETRACE >= 3) CALL IDE_REGDUMP #ENDIF ; ;JR IDE_PROBE1 ; *DEBUG* ; IDE_PROBE0: CALL IDE_WAITBSY ; WAIT FOR BUSY TO CLEAR JP NZ,IDE_NOMEDIA ; CONVERT TIMEOUT TO NO MEDIA AND RETURN ; #IF (IDETRACE >= 3) CALL IDE_REGDUMP #ENDIF ; ; CHECK STATUS ;IN A,(IDE_IO_STAT) ; GET STATUS CALL IDE_IN .DB IDE_REG_STAT #IF (IDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE ; IF DEBUG, PRINT STATUS #ENDIF OR A ; SET FLAGS TO TEST FOR ZERO JP Z,IDE_NOMEDIA ; ; CHECK SIGNATURE #IF (IDETRACE >= 3) CALL PC_SPACE #ENDIF ;IN A,(IDE_IO_COUNT) CALL IDE_IN .DB IDE_REG_COUNT #IF (IDETRACE >= 3) CALL PRTHEXBYTE #ENDIF CP $01 JP NZ,IDE_NOMEDIA #IF (IDETRACE >= 3) CALL PC_SPACE #ENDIF ;IN A,(IDE_IO_SECT) CALL IDE_IN .DB IDE_REG_SECT #IF (IDETRACE >= 3) CALL PRTHEXBYTE #ENDIF CP $01 JP NZ,IDE_NOMEDIA #IF (IDETRACE >= 3) CALL PC_SPACE #ENDIF ;IN A,(IDE_IO_CYLLO) CALL IDE_IN .DB IDE_REG_CYLLO #IF (IDETRACE >= 3) CALL PRTHEXBYTE #ENDIF CP $00 JP NZ,IDE_NOMEDIA #IF (IDETRACE >= 3) CALL PC_SPACE #ENDIF ;IN A,(IDE_IO_CYLHI) CALL IDE_IN .DB IDE_REG_CYLHI #IF (IDETRACE >= 3) CALL PRTHEXBYTE #ENDIF CP $00 JP NZ,IDE_NOMEDIA ; IDE_PROBE1: ; SIGNATURE MATCHES ATA DEVICE, RECORD TYPE AND RETURN SUCCESS LD A,IDE_TYPEATA ; TYPE = ATA LD (IY+IDE_TYPE),A ; SET IT IN INSTANCE DATA XOR A ; SIGNAL SUCCESS RET ; DONE, NOTE THAT A=0 AND Z IS SET ; ; (RE)INITIALIZE DEVICE ; IDE_INITDEV: ; LD A,(IY+IDE_TYPE) ; GET THE DEVICE TYPE OR A ; SET FLAGS JP Z,IDE_NOMEDIA ; EXIT SETTING NO MEDIA STATUS ; 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: ; CALL IDE_IDENTIFY ; EXECUTE IDENTIFY COMMAND RET NZ ; BAIL OUT ON ERROR ; LD DE,HB_WRKBUF ; POINT TO BUFFER #IF (IDETRACE >= 3) CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING #ENDIF ; XOR A LD (IY+IDE_MED),0 ; CLEAR FLAGS ; DETERMINE IF CF DEVICE LD HL,HB_WRKBUF ; FIRST WORD OF IDENTIFY DATA HAS CF FLAG LD A,$8A ; FIRST BYTE OF MARKER IS $8A CP (HL) ; COMPARE JR NZ,IDE_INITDEV1 ; IF NO MATCH, NOT CF INC HL LD A,$84 ; SECOND BYTE OF MARKER IS $84 CP (HL) ; COMPARE JR NZ,IDE_INITDEV1 ; IF NOT MATCH, NOT CF SET 0,(IY+IDE_MED) ; SET FLAGS BIT FOR CF MEDIA ; IDE_INITDEV1: ; DETERMINE IF LBA CAPABLE LD A,(HB_WRKBUF+98+1) ; GET BYTE WITH LBA BIT FROM BUFFER 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 ; ; RESET CARD STATUS TO 0 (OK) XOR A ; A := 0 (STATUS = OK) LD (IY+IDE_STAT),A ; SAVE IT ; RET ; RETURN, A=0, Z SET ; ; 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.05 SECS LD B,A ; PUT IN OUTER LOOP VAR IDE_WAITRDY1: LD DE,(IDE_TOSCALER) ; CPU SPPED SCALER TO INNER LOOP VAR IDE_WAITRDY2: ;IN A,(IDE_IO_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.05 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_IO_STAT) ; WAIT FOR DRIVE'S 512 BYTE READ BUFFER 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.05 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_IO_STAT) ; WAIT FOR DRIVE'S 512 BYTE READ BUFFER ; 11TS CALL IDE_IN ; 17TS + ???TS .DB IDE_REG_STAT ; 0TS 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 ; ??TS ; ; READ A VALUE FROM THE DEVICE POINTED TO BY IY AND RETURN IT IN A ; IDE_IN: EX (SP),HL ; GET PARM POINTER PUSH BC LD A,(HL) INC HL LD C,(IY+IDE_IOBASE) ADD A,C LD C,A IN A,(C) POP BC EX (SP),HL ; RESTORE STACK RET ; ; OUTPUT VALUE IN A TO THE DEVICE POINTED TO BY IY ; 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_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 STATUS STRING (STATUS NUM IN A) ; IDE_PRTSTAT: PUSH AF PUSH DE PUSH HL LD A,(IY+IDE_STAT) OR A LD DE,IDE_STR_STOK JR Z,IDE_PRTSTAT1 INC A LD DE,IDE_STR_STINVUNIT JR Z,IDE_PRTSTAT2 ; INVALID UNIT IS SPECIAL CASE INC A LD DE,IDE_STR_STNOMEDIA JR Z,IDE_PRTSTAT1 INC A LD DE,IDE_STR_STCMDERR JR Z,IDE_PRTSTAT1 INC A LD DE,IDE_STR_STIOERR JR Z,IDE_PRTSTAT1 INC A LD DE,IDE_STR_STRDYTO JR Z,IDE_PRTSTAT1 INC A LD DE,IDE_STR_STDRQTO JR Z,IDE_PRTSTAT1 INC A LD DE,IDE_STR_STBSYTO JR Z,IDE_PRTSTAT1 LD DE,IDE_STR_STUNK IDE_PRTSTAT1: 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 WRITESTR POP HL 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_IO_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 ADD A,'0' CALL COUT CALL PC_COLON POP AF RET ;;; ;;; ;;; ;;#IF (DSKYENABLE) ;;IDE_DSKY: ;; LD HL,DSKY_HEXBUF ; POINT TO DSKY BUFFER ;; CALL IDE_IN ;; .DB IDE_REG_DRVHD ;; LD (HL),A ; SAVE IN BUFFER ;; INC HL ; INCREMENT BUFFER POINTER ;; CALL IDE_IN ;; .DB IDE_REG_CYLHI ;; LD (HL),A ; SAVE IN BUFFER ;; INC HL ; INCREMENT BUFFER POINTER ;; CALL IDE_IN ;; .DB IDE_REG_CYLLO ;; LD (HL),A ; SAVE IN BUFFER ;; INC HL ; INCREMENT BUFFER POINTER ;; CALL IDE_IN ;; .DB IDE_REG_SECT ;; LD (HL),A ; SAVE IN BUFFER ;; CALL DSKY_HEXOUT ; SEND IT TO DSKY ;; RET ;;#ENDIF ; ;============================================================================= ; 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_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$" ; ;============================================================================= ; DATA STORAGE ;============================================================================= ; IDE_TIMEOUT .DB IDE_TONORM ; WAIT FUNCS TIMEOUT IN TENTHS OF SEC IDE_TOSCALER .DW CPUMHZ * 961 ; 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_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT