; ;============================================================================= ; PPIDE DISK DRIVER ;============================================================================= ; ; TODO: ; - GOPARTNER NEEDS TO HANDLE "NO PARTNER" CONDITION ; - DATA TRANSFERS LIMITED TO 512 BYTES WHICH IS INSUFFICIENT FOR CD=ROM MEDIA ; ; NOTES: ; - WELL KNOWN PPIDE PORT ADDRESSES: ; $60 - SBC/ZETA ONBOARD PPI ; $20 - ECB DISKIO3, RC FAMILY ; $44 - ECB MULTI-FUNCTION PIC ; $80 - N8 ONBOARD PPI ; $4C - DYNO ONBOARD PPI ; ; THE CONTROL PORT OF THE 8255 IS PROGRAMMED AS NEEDED TO READ OR WRITE ; DATA ON THE IDE BUS. PORT C OF THE 8255 IS ALWAYS IN OUTPUT MODE BECAUSE ; IT IS DRIVING THE ADDRESS BUS AND CONTROL SIGNALS. PORTS A & B WILL BE ; PLACED IN READ OR WRITE MODE DEPENDING ON THE DIRECTION OF THE DATA BUS. ; PPIDE_DIR_READ .EQU %10010010 ; IDE BUS DATA INPUT MODE PPIDE_DIR_WRITE .EQU %10000000 ; IDE BUS DATA OUTPUT MODE ; ; PORT C OF THE 8255 IS USED TO DRIVE THE IDE INTERFACE ADDRESS BUS ; AND VARIOUS CONTROL SIGNALS. THE CONSTANTS BELOW REFLECT THESE ; ASSIGNMENTS. ; PPIDE_CTL_DA0 .EQU %00000001 ; DRIVE ADDRESS BUS - BIT 0 (DA0) PPIDE_CTL_DA1 .EQU %00000010 ; DRIVE ADDRESS BUS - BIT 1 (DA1) PPIDE_CTL_DA2 .EQU %00000100 ; DRIVE ADDRESS BUS - BIT 2 (DA2) PPIDE_CTL_CS1 .EQU %00001000 ; DRIVE CHIP SELECT 0 (ACTIVE LOW, INVERTED) PPIDE_CTL_CS3 .EQU %00010000 ; DRIVE CHIP SELECT 1 (ACTIVE LOW, INVERTED) PPIDE_CTL_DIOW .EQU %00100000 ; DRIVE I/O WRITE (ACTIVE LOW, INVERTED) PPIDE_CTL_DIOR .EQU %01000000 ; DRIVE I/O READ (ACTIVE LOW, INVERTED) PPIDE_CTL_RESET .EQU %10000000 ; DRIVE RESET (ACTIVE LOW, INVERTED) ; ; +-----------------------------------------------------------------------+ ; | CONTROL BLOCK REGISTERS (CS3FX) | ; +-----------------------+-------+-------+-------------------------------+ ; | REGISTER | PORT | DIR | DESCRIPTION | ; +-----------------------+-------+-------+-------------------------------+ ; | PPIDE_REG_ALTSTAT | 0x06 | R | ALTERNATE STATUS REGISTER | ; | PPIDE_REG_CTRL | 0x06 | W | DEVICE CONTROL REGISTER | ; | PPIDE_REG_DRVADR | 0x07 | R | DRIVE ADDRESS REGISTER | ; +-----------------------+-------+-------+-------------------------------+ ; ; +-----------------------+-------+-------+-------------------------------+ ; | COMMAND BLOCK REGISTERS (CS1FX) | ; +-----------------------+-------+-------+-------------------------------+ ; | REGISTER | PORT | DIR | DESCRIPTION | ; +-----------------------+-------+-------+-------------------------------+ ; | PPIDE_REG_DATA | 0x00 | R/W | DATA INPUT/OUTPUT | ; | PPIDE_REG_ERR | 0x01 | R | ERROR REGISTER | ; | PPIDE_REG_FEAT | 0x01 | W | FEATURES REGISTER | ; | PPIDE_REG_COUNT | 0x02 | R/W | SECTOR COUNT REGISTER | ; | PPIDE_REG_SECT | 0x03 | R/W | SECTOR NUMBER REGISTER | ; | PPIDE_REG_CYLLO | 0x04 | R/W | CYLINDER NUM REGISTER (LSB) | ; | PPIDE_REG_CYLHI | 0x05 | R/W | CYLINDER NUM REGISTER (MSB) | ; | PPIDE_REG_DRVHD | 0x06 | R/W | DRIVE/HEAD REGISTER | ; | PPIDE_REG_LBA0* | 0x03 | R/W | LBA BYTE 0 (BITS 0-7) | ; | PPIDE_REG_LBA1* | 0x04 | R/W | LBA BYTE 1 (BITS 8-15) | ; | PPIDE_REG_LBA2* | 0x05 | R/W | LBA BYTE 2 (BITS 16-23) | ; | PPIDE_REG_LBA3* | 0x06 | R/W | LBA BYTE 3 (BITS 24-27) | ; | PPIDE_REG_STAT | 0x07 | R | STATUS REGISTER | ; | PPIDE_REG_CMD | 0x07 | W | COMMAND REGISTER (EXECUTE) | ; +-----------------------+-------+-------+-------------------------------+ ; * LBA0-3 ARE ALTERNATE DEFINITIONS OF SECT, CYL, AND DRVHD PORTS ; ; === STATUS REGISTER === ; ; 7 6 5 4 3 2 1 0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | BSY | DRDY | DWF | DSC | DRQ | CORR | IDX | ERR | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; ; BSY: BUSY ; DRDY: DRIVE READY ; DWF: DRIVE WRITE FAULT ; DSC: DRIVE SEEK COMPLETE ; DRQ: DATA REQUEST ; CORR: CORRECTED DATA ; IDX: INDEX ; ERR: ERROR ; ; === ERROR REGISTER === ; ; 7 6 5 4 3 2 1 0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | BBK | UNC | MC | IDNF | MCR | ABRT | TK0NF | AMNF | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; (VALID WHEN ERR BIT IS SET IN STATUS REGISTER) ; ; BBK: BAD BLOCK DETECTED ; UNC: UNCORRECTABLE DATA ERROR ; MC: MEDIA CHANGED ; IDNF: ID NOT FOUND ; MCR: MEDIA CHANGE REQUESTED ; ABRT: ABORTED COMMAND ; TK0NF: TRACK 0 NOT FOUND ; AMNF: ADDRESS MARK NOT FOUND ; ; === DRIVE/HEAD / LBA3 REGISTER === ; ; 7 6 5 4 3 2 1 0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | 1 | L | 1 | DRV | HS3 | HS2 | HS1 | HS0 | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; ; L: 0 = CHS ADDRESSING, 1 = LBA ADDRESSING ; DRV: 0 = DRIVE 0 (PRIMARY) SELECTED, 1 = DRIVE 1 (SLAVE) SELECTED ; HS: CHS = HEAD ADDRESS (0-15), LBA = BITS 24-27 OF LBA ; ; === DEVICE CONTROL REGISTER === ; ; 7 6 5 4 3 2 1 0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | X | X | X | X | 1 | SRST | ~IEN | 0 | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; ; SRST: SOFTWARE RESET ; ~IEN: INTERRUPT ENABLE ; ; CONTROL VALUES TO USE WHEN ACCESSING THE VARIOUS IDE DEVICE REGISTERS ; PPIDE_REG_DATA .EQU PPIDE_CTL_CS1 | $00 ; DATA INPUT/OUTPUT (R/W) PPIDE_REG_ERR .EQU PPIDE_CTL_CS1 | $01 ; ERROR REGISTER (R) PPIDE_REG_FEAT .EQU PPIDE_CTL_CS1 | $01 ; FEATURES REGISTER (W) PPIDE_REG_COUNT .EQU PPIDE_CTL_CS1 | $02 ; SECTOR COUNT REGISTER (R/W) PPIDE_REG_SECT .EQU PPIDE_CTL_CS1 | $03 ; SECTOR NUMBER REGISTER (R/W) PPIDE_REG_CYLLO .EQU PPIDE_CTL_CS1 | $04 ; CYLINDER NUM REGISTER (LSB) (R/W) PPIDE_REG_CYLHI .EQU PPIDE_CTL_CS1 | $05 ; CYLINDER NUM REGISTER (MSB) (R/W) PPIDE_REG_DRVHD .EQU PPIDE_CTL_CS1 | $06 ; DRIVE/HEAD REGISTER (R/W) PPIDE_REG_LBA0 .EQU PPIDE_CTL_CS1 | $03 ; LBA BYTE 0 (BITS 0-7) (R/W) PPIDE_REG_LBA1 .EQU PPIDE_CTL_CS1 | $04 ; LBA BYTE 1 (BITS 8-15) (R/W) PPIDE_REG_LBA2 .EQU PPIDE_CTL_CS1 | $05 ; LBA BYTE 2 (BITS 16-23) (R/W) PPIDE_REG_LBA3 .EQU PPIDE_CTL_CS1 | $06 ; LBA BYTE 3 (BITS 24-27) (R/W) PPIDE_REG_BCL .EQU PPIDE_CTL_CS1 | $04 ; PKT BYTE COUNT LOW (BITS 0-7) (R/W) PPIDE_REG_BCH .EQU PPIDE_CTL_CS1 | $05 ; PKT BYTE COUNT HIGH (BITS 8-15) (R/W) PPIDE_REG_STAT .EQU PPIDE_CTL_CS1 | $07 ; STATUS REGISTER (R) PPIDE_REG_CMD .EQU PPIDE_CTL_CS1 | $07 ; COMMAND REGISTER (EXECUTE) (W) PPIDE_REG_ALTSTAT .EQU PPIDE_CTL_CS3 | $06 ; ALTERNATE STATUS REGISTER (R) PPIDE_REG_CTRL .EQU PPIDE_CTL_CS3 | $06 ; DEVICE CONTROL REGISTER (W) PPIDE_REG_DRVADR .EQU PPIDE_CTL_CS3 | $07 ; DRIVE ADDRESS REGISTER (R) ; ; COMMAND BYTES ; PPIDE_CMD_NOP .EQU $00 PPIDE_CMD_DEVRES .EQU $08 PPIDE_CMD_RECAL .EQU $10 PPIDE_CMD_READ .EQU $20 PPIDE_CMD_WRITE .EQU $30 PPIDE_CMD_DEVDIAG .EQU $90 PPIDE_CMD_PACKET .EQU $A0 PPIDE_CMD_IDPKTDEV .EQU $A1 PPIDE_CMD_IDDEV .EQU $EC PPIDE_CMD_SETFEAT .EQU $EF ; ; FEATURE BYTES ; PPIDE_FEAT_ENABLE8BIT .EQU $01 PPIDE_FEAT_DISABLE8BIT .EQU $81 ; ; PPIDE DEVICE TYPES ; PPIDE_TYPEUNK .EQU 0 PPIDE_TYPEATA .EQU 1 PPIDE_TYPEATAPI .EQU 2 ; ; PPIDE DEVICE STATUS CODES ; PPIDE_STOK .EQU 0 PPIDE_STINVUNIT .EQU -1 PPIDE_STNOMEDIA .EQU -2 PPIDE_STCMDERR .EQU -3 PPIDE_STIOERR .EQU -4 PPIDE_STRDYTO .EQU -5 PPIDE_STDRQTO .EQU -6 PPIDE_STBSYTO .EQU -7 PPIDE_STNOTSUP .EQU -8 PPIDE_STNOTRDY .EQU -9 ; ; DRIVE SELECTION BYTES (FOR USE IN DRIVE/HEAD REGISTER) ; ;PPIDE_DRVSEL: PPIDE_DRVMASTER .EQU %11100000 ; LBA, MASTER DEVICE PPIDE_DRVSLAVE .EQU %11110000 ; LBA, SLAVE DEVICE ; ; PPIDE DEVICE CONFIGURATION ; PPIDE_CFGSIZ .EQU 18 ; SIZE OF CFG TBL ENTRIES ; ; PER DEVICE DATA OFFSETS ; PPIDE_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE) PPIDE_STAT .EQU 1 ; LAST STATUS (BYTE) PPIDE_TYPE .EQU 2 ; DEVICE TYPE (BYTE) PPIDE_ACC .EQU 3 ; ACCESS FLAG BITS BIT 0=MASTER, 1=8BIT (BYTE) PPIDE_MED .EQU 4 ; MEDIA FLAG BITS BIT 0=CF, 1=LBA (BYTE) PPIDE_MEDCAP .EQU 5 ; MEDIA CAPACITY (DWORD) PPIDE_LBA .EQU 9 ; OFFSET OF LBA (DWORD) PPIDE_DATALO .EQU 13 ; BASE PORT AND IDE DATA BUS LSB (8255 PORT A) (BYTE) PPIDE_CTL .EQU 14 ; IDE ADDRESS BUS AND CONTROL SIGNALS (8255 PORT C)(BYTE) PPIDE_PPI .EQU 15 ; 8255 CONTROL PORT(BYTE) PPIDE_PARTNER .EQU 16 ; PARTNER DEVICE (MASTER <-> SLAVE) (WORD) ; PPIDE_ACC_MAS .EQU %00000001 ; UNIT IS MASTER (ELSE SLAVE) PPIDE_ACC_8BIT .EQU %00000010 ; UNIT WANTS 8 BIT I/O (ELSE 16 BIT) ; PPIDE_MED_CF .EQU %00000001 ; MEDIA IS CF CARD PPIDE_MED_LBA .EQU %00000010 ; MEDIA HAS LBA CAPABILITY ; PPIDE_DEVCNT .EQU PPIDECNT * 2 ; PPIDE_CFGTBL: ; #IF (PPIDECNT >= 1) ; PPIDE_DEV0M: ; DEVICE 0, MASTER .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB 0 ; DEVICE STATUS .DB 0 ; DEVICE TYPE .DB PPIDE_ACC_MAS | (PPIDE0A8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS .DB 0 ; MEDIA FLAGS .DW 0,0 ; DEVICE CAPACITY .DW 0,0 ; CURRENT LBA .DB PPIDE0BASE ; DATALO .DB PPIDE0BASE+2 ; CTL .DB PPIDE0BASE+3 ; PPI .DW PPIDE_DEV0S ; PARTNER ; DEVECHO "PPIDE: IO=" DEVECHO PPIDE0BASE DEVECHO ", MASTER" DEVECHO "\n" ; PPIDE_DEV0S: ; DEVICE 0, SLAVE .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB 0 ; DEVICE STATUS .DB 0 ; DEVICE TYPE .DB (PPIDE0B8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS .DB 0 ; MEDIA FLAGS .DW 0,0 ; DEVICE CAPACITY .DW 0,0 ; CURRENT LBA .DB PPIDE0BASE ; DATALO .DB PPIDE0BASE+2 ; CTL .DB PPIDE0BASE+3 ; PPI .DW PPIDE_DEV0M ; PARTNER ; DEVECHO "PPIDE: IO=" DEVECHO PPIDE0BASE DEVECHO ", SLAVE" DEVECHO "\n" ; #ENDIF ; #IF (PPIDECNT >= 2) ; PPIDE_DEV1M: ; DEVICE 1, MASTER .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB 0 ; DEVICE STATUS .DB 0 ; DEVICE TYPE .DB PPIDE_ACC_MAS | (PPIDE1A8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS .DB 0 ; MEDIA FLAGS .DW 0,0 ; DEVICE CAPACITY .DW 0,0 ; CURRENT LBA .DB PPIDE1BASE ; DATALO .DB PPIDE1BASE+2 ; CTL .DB PPIDE1BASE+3 ; PPI .DW PPIDE_DEV1S ; PARTNER ; DEVECHO "PPIDE: IO=" DEVECHO PPIDE1BASE DEVECHO ", MASTER" DEVECHO "\n" ; PPIDE_DEV1S: ; DEVICE 1, SLAVE .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB 0 ; DEVICE STATUS .DB 0 ; DEVICE TYPE .DB (PPIDE1B8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS .DB 0 ; MEDIA FLAGS .DW 0,0 ; DEVICE CAPACITY .DW 0,0 ; CURRENT LBA .DB PPIDE1BASE ; DATALO .DB PPIDE1BASE+2 ; CTL .DB PPIDE1BASE+3 ; PPI .DW PPIDE_DEV1M ; PARTNER ; DEVECHO "PPIDE: IO=" DEVECHO PPIDE1BASE DEVECHO ", SLAVE" DEVECHO "\n" ; #ENDIF ; #IF (PPIDECNT >= 3) ; PPIDE_DEV2M: ; DEVICE 2, MASTER .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB 0 ; DEVICE STATUS .DB 0 ; DEVICE TYPE .DB PPIDE_ACC_MAS | (PPIDE2A8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS .DB 0 ; MEDIA FLAGS .DW 0,0 ; DEVICE CAPACITY .DW 0,0 ; CURRENT LBA .DB PPIDE2BASE ; DATALO .DB PPIDE2BASE+2 ; CTL .DB PPIDE2BASE+3 ; PPI .DW PPIDE_DEV2S ; PARTNER ; DEVECHO "PPIDE: IO=" DEVECHO PPIDE2BASE DEVECHO ", MASTER" DEVECHO "\n" ; PPIDE_DEV2S: ; DEVICE 2, SLAVE .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB 0 ; DEVICE STATUS .DB 0 ; DEVICE TYPE .DB (PPIDE2B8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS .DB 0 ; MEDIA FLAGS .DW 0,0 ; DEVICE CAPACITY .DW 0,0 ; CURRENT LBA .DB PPIDE2BASE ; DATALO .DB PPIDE2BASE+2 ; CTL .DB PPIDE2BASE+3 ; PPI .DW PPIDE_DEV2M ; PARTNER ; DEVECHO "PPIDE: IO=" DEVECHO PPIDE2BASE DEVECHO ", SLAVE" DEVECHO "\n" ; #ENDIF ; #IF ($ - PPIDE_CFGTBL) != (PPIDE_DEVCNT * PPIDE_CFGSIZ) .ECHO "*** INVALID PPIDE CONFIG TABLE ***\n" #ENDIF ; .DB $FF ; END OF TABLE MARKER ; ; THE PPIDE_WAITXXX FUNCTIONS ARE BUILT TO TIMEOUT AS NEEDED SO DRIVER WILL ; NOT HANG IF DEVICE IS UNRESPONSIVE. DIFFERENT TIMEOUTS ARE USED DEPENDING ; ON THE SITUATION. THE SLOW TIMEOUT IS USED TO WAIT FOR A DEVICE TO ; BECOME READY AFTER A HARD RESET (SPIN UP, ETC.). THE NORMAL TIMEOUT ; IS USED DURING NORMAL OPERATION FOR ALL I/O OPERATIONS WHICH SHOULD ; OCCUR PRETTY FAST. NOTE THAT THE ATA SPEC ALLOWS UP TO 30 SECONDS ; FOR DEVICES TO RESPOND. WE ARE USING MUCH MORE AGGRESSIVE VALUES ; BASED ON REAL WORLD EXPERIENCE. ; PPIDE_TOSLOW .EQU 200 ; SLOW TIMEOUT IS 20 SECS ;PPIDE_TONORM .EQU 5 ; NORMAL TIMEOUT IS 0.5 SECS PPIDE_TONORM .EQU 200 ; NORMAL TIMEOUT IS 0.5 SECS ; ;============================================================================= ; INITIALIZATION ENTRY POINT ;============================================================================= ; PPIDE_INIT: ; COMPUTE CPU SPEED COMPENSATED TIMEOUT SCALER ; ONE INTERNAL LOOP IN WAITBSY IS 263TS. ON A 1 MHZ CPU, 1 TS ; TAKES 1NS. SO 1/10 SECOND IS 100000 TS ON A 1 MHZ CPU. ; SINCE 1 INTERNAL LOOP IS 263 TS, IT TAKES 100000 / 263 = 356 ; INTERNAL LOOPS FOR 1/10 SECOND. SO, WE WANT TO USE ; 356 * CPU MHZ FOR INTERNAL LOOP COUNT. LD DE,380 ; LOAD SCALER FOR 1MHZ LD A,(CB_CPUMHZ) ; LOAD CPU SPEED IN MHZ CALL MULT8X16 ; HL := DE * A LD (PPIDE_TOSCALER),HL ; SAVE IT ; XOR A ; ZERO ACCUM LD (PPIDE_DEVNUM),A ; INIT DEV UNIT NUM FOR DYNAMIC ASSIGNMENT LD IY,PPIDE_CFGTBL ; POINT TO START OF CONFIG TABLE ; PPIDE_INIT1: LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END CP $FF ; CHECK FOR END OF TABLE VALUE JR NZ,PPIDE_INIT2 ; IF NOT END OF TABLE, CONTINUE XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; PPIDE_INIT2: BIT 0,(IY+PPIDE_ACC) ; MASTER? JR Z,PPIDE_INIT4 ; IF NOT MASTER, SKIP AHEAD ; CALL NEWLINE ; FORMATTING PRTS("PPIDE:$") ; LABEL FOR IO ADDRESS ; PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS LD A,(IY+PPIDE_DATALO) ; GET IO BASE ADDRES CALL PRTHEXBYTE ; DISPLAY IT ; CALL PPIDE_DETECT ; PROBE FOR INTERFACE JR Z,PPIDE_INIT3 ; GOT IT, MOVE ON TO INIT UNITS CALL PC_SPACE ; FORMATTING LD DE,PPIDE_STR_NOPPI ; NO PPI MESSAGE CALL WRITESTR ; DISPLAY IT JR PPIDE_INIT4 ; SKIP CFG ENTRY ; PPIDE_INIT3: CALL PPIDE_RESET ; RESET THE BUS CALL PPIDE_INIT5 ; DETECT/INIT MASTER PUSH IY ; SAVE CFG PTR CALL PPIDE_GOPARTNER ; SWITCH IY TO PARTNER CFG CALL PPIDE_INIT5 ; DETECT/INIT SLAVE POP IY ; RESTORE CFG PTR ; PPIDE_INIT4: LD DE,PPIDE_CFGSIZ ; SIZE OF CFG TABLE ENTRY ADD IY,DE ; BUMP POINTER JR PPIDE_INIT1 ; AND LOOP ; PPIDE_INIT5: ; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE LD A,(PPIDE_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN LD (IY+PPIDE_DEV),A ; UPDATE IT INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN LD (PPIDE_DEVNUM),A ; SAVE IT ; ; ADD UNIT TO GLOBAL DISK UNIT TABLE LD BC,PPIDE_FNTBL ; BC := FUNC TABLE ADR PUSH IY ; CFG ENTRY POINTER POP DE ; COPY TO DE CALL DIO_ADDENT ; ADD ENTRY TO GLOBAL DISK DEV TABLE ; ; START PRINTING DEVICE INFO CALL PPIDE_PRTPREFIX ; PRINT DEVICE PREFIX LD A,(IY+PPIDE_TYPE) LD DE,PPIDE_STR_TYPEATA CP PPIDE_TYPEATA CALL Z,WRITESTR LD DE,PPIDE_STR_TYPEATAPI CP PPIDE_TYPEATAPI CALL Z,WRITESTR ; ; CHECK FOR BAD STATUS LD A,(IY+PPIDE_STAT) ; GET STATUS OR A ; SET FLAGS JP Z,PPIDE_INIT6 CALL PC_SPACE JP NZ,PPIDE_PRTSTATSTR ; EXIT VIA PRINT STATUS STRING ; PPIDE_INIT6: LD DE,PPIDE_STR_8BIT BIT 1,(IY+PPIDE_ACC) ; 8 BIT ACCESS? CALL NZ,WRITESTR ; ; PRINT LBA/NOLBA CALL PC_SPACE ; FORMATTING BIT 1,(IY+PPIDE_MED) ; TEST LBA FLAG LD DE,PPIDE_STR_NO ; POINT TO "NO" STRING CALL Z,WRITESTR ; PRINT "NO" BEFORE "LBA" IF LBA NOT SUPPORTED PRTS("LBA$") ; PRINT "LBA" REGARDLESS ; ; PRINT STORAGE CAPACITY (BLOCK COUNT) PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL LD A,PPIDE_MEDCAP ; OFFSET TO CAPACITY FIELD CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL LD32 ; GET THE CAPACITY VALUE CALL PRTHEX32 ; PRINT HEX VALUE ; ; PRINT STORAGE SIZE IN MB PRTS(" SIZE=$") ; PRINT FIELD LABEL LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB CALL SRL32 ; RIGHT SHIFT ; CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED) CALL PRTDEC32 ; PRINT DWORD IN DECIMAL PRTS("MB$") ; PRINT SUFFIX ; RET ; ;---------------------------------------------------------------------- ; PROBE FOR PPI HARDWARE ;---------------------------------------------------------------------- ; ; ON RETURN, ZF SET INDICATES HARDWARE FOUND ; PPIDE_DETECT: ; ; TEST FOR PPI EXISTENCE ; WE SETUP THE PPI TO WRITE, THEN WRITE A VALUE OF $A5 ; TO PORT A (DATALO), THEN READ IT BACK. IF THE PPI IS THERE ; THEN THE BUS HOLD CIRCUITRY WILL READ BACK THE $A5. SINCE ; WE ARE IN WRITE MODE, AN IDE CONTROLLER WILL NOT BE ABLE TO ; INTERFERE WITH THE VALUE BEING READ. ; LD A,PPIDE_DIR_WRITE ; SET DATA BUS DIRECTION TO WRITE LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD OUT (C),A ; WRITE IT ; LD C,(IY+PPIDE_DATALO) ; PPI PORT A, DATALO LD A,$A5 ; TEST VALUE OUT (C),A ; PUSH VALUE TO PORT IN A,(C) ; GET PORT VALUE #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CP $A5 ; CHECK FOR TEST VALUE RET ; AND RETURN ; ;============================================================================= ; DRIVER FUNCTION TABLE ;============================================================================= ; PPIDE_FNTBL: .DW PPIDE_STATUS .DW PPIDE_RESET .DW PPIDE_SEEK .DW PPIDE_READ .DW PPIDE_WRITE .DW PPIDE_VERIFY .DW PPIDE_FORMAT .DW PPIDE_DEVICE .DW PPIDE_MEDIA .DW PPIDE_DEFMED .DW PPIDE_CAP .DW PPIDE_GEOM #IF (($ - PPIDE_FNTBL) != (DIO_FNCNT * 2)) .ECHO "*** INVALID PPIDE FUNCTION TABLE ***\n" #ENDIF ; PPIDE_VERIFY: PPIDE_FORMAT: PPIDE_DEFMED: SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED RET ; ; ; PPIDE_READ: CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR LD BC,PPIDE_RDSEC ; GET ADR OF SECTOR READ FUNC LD (PPIDE_IOFNADR),BC ; SAVE IT AS PENDING IO FUNC JR PPIDE_IO ; CONTINUE TO GENERIC IO ROUTINE ; ; ; PPIDE_WRITE: CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR LD BC,PPIDE_WRSEC ; GET ADR OF SECTOR WRITE FUNC LD (PPIDE_IOFNADR),BC ; SAVE IT AS PENDING IO FUNC JR PPIDE_IO ; CONTINUE TO GENERIC IO ROUTINE ; ; ; PPIDE_IO: LD (PPIDE_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS LD A,E ; BLOCK COUNT TO A OR A ; SET FLAGS RET Z ; ZERO SECTOR I/O, RETURN W/ E=0 & A=0 LD B,A ; INIT SECTOR DOWNCOUNTER LD C,0 ; INIT SECTOR READ/WRITE COUNT #IF (PPIDETRACE == 1) LD HL,PPIDE_PRTERR ; SET UP PPIDE_PRTERR PUSH HL ; ... TO FILTER ALL EXITS #ENDIF PUSH BC ; SAVE COUNTERS CALL PPIDE_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO POP BC ; RESTORE COUNTERS JR NZ,PPIDE_IO3 ; BAIL OUT ON ERROR PPIDE_IO1: PUSH BC ; SAVE COUNTERS CALL PPIDE_SELUNIT ; HARDWARE SELECTION OF TARGET UNIT LD HL,(PPIDE_IOFNADR) ; GET PENDING IO FUNCTION ADDRESS CALL JPHL ; ... AND CALL IT JR NZ,PPIDE_IO2 ; IF ERROR, SKIP INCREMENT ; INCREMENT LBA LD A,PPIDE_LBA ; LBA OFFSET CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL INC32HL ; INCREMENT THE VALUE ; INCREMENT DMA LD HL,PPIDE_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR INC (HL) ; BUMP DMA BY INC (HL) ; ... 512 BYTES XOR A ; SIGNAL SUCCESS PPIDE_IO2: POP BC ; RECOVER COUNTERS JR NZ,PPIDE_IO3 ; IF ERROR, BAIL OUT INC C ; BUMP COUNT OF SECTORS READ DJNZ PPIDE_IO1 ; LOOP AS NEEDED PPIDE_IO3: LD E,C ; SECTOR READ COUNT TO E LD HL,(PPIDE_DSKBUF) ; CURRENT DMA TO HL OR A ; SET FLAGS BASED ON RETURN CODE RET Z ; RETURN IF SUCCESS LD A,ERR_IO ; SIGNAL IO ERROR OR A ; SET FLAGS RET ; AND DONE ; ; ; PPIDE_STATUS: ; RETURN UNIT STATUS LD A,(IY+PPIDE_STAT) ; GET STATUS OF SELECTED DEVICE OR A ; SET FLAGS RET ; AND RETURN ; ; ; PPIDE_DEVICE: LD D,DIODEV_PPIDE ; D := DEVICE TYPE LD E,(IY+PPIDE_DEV) ; E := PHYSICAL DEVICE NUMBER LD C,%01111001 ; ATAPI ATTRIBUTES LD A,(IY+PPIDE_TYPE) ; CHECK TYPE VALUE CP PPIDE_TYPEATAPI ; ATAPI? JR Z,PPIDE_DEVICE1 ; IF SO, DONE LD C,%00110001 ; COMPACTFLASH ATTRIBUTES BIT 0,(IY+PPIDE_MED) ; TEST CF BIT IN FLAGS JR NZ,PPIDE_DEVICE1 ; IF SET, DONE LD C,%00110000 ; GENERIC HARD DISK ATTRIBUTES PPIDE_DEVICE1: LD H,0 ; H := 0, DRIVER HAS NO MODES LD L,(IY+PPIDE_DATALO) ; L := BASE I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; ; IDE_GETMED ; PPIDE_MEDIA: LD A,E ; GET FLAGS OR A ; SET FLAGS JR Z,PPIDE_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA ; ;CALL PPIDE_RESET ; RESET IDE INTERFACE CALL PPIDE_INITUNIT ; RE-INITIALIZE UNIT ; PPIDE_MEDIA1: LD A,(IY+PPIDE_STAT) ; GET STATUS OR A ; SET FLAGS LD D,0 ; NO MEDIA CHANGE DETECTED LD E,MID_HD ; ASSUME WE ARE OK RET Z ; RETURN IF GOOD INIT LD E,MID_NONE ; SIGNAL NO MEDIA LD A,ERR_NOMEDIA ; NO MEDIA ERROR OR A ; SET FLAGS RET ; AND RETURN ; ; ; PPIDE_SEEK: BIT 7,D ; CHECK FOR LBA FLAG CALL Z,HB_CHS2LBA ; CLEAR MEANS CHS, CONVERT TO LBA RES 7,D ; CLEAR FLAG REGARDLESS (DOES NO HARM IF ALREADY LBA) LD (IY+PPIDE_LBA+0),L ; SAVE NEW LBA LD (IY+PPIDE_LBA+1),H ; ... LD (IY+PPIDE_LBA+2),E ; ... LD (IY+PPIDE_LBA+3),D ; ... XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; ; PPIDE_CAP: LD A,(IY+PPIDE_STAT) ; GET STATUS PUSH AF ; SAVE IT LD A,PPIDE_MEDCAP ; OFFSET TO CAPACITY FIELD CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL LD32 ; GET THE CURRENT CAPACITY INTO DE:HL LD BC,512 ; 512 BYTES PER BLOCK POP AF ; RECOVER STATUS OR A ; SET FLAGS RET ; ; ; PPIDE_GEOM: ; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS ; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE CALL PPIDE_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC LD L,H ; DIVPPIDE BY 256 FOR # TRACKS LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL LD D,16 | $80 ; HEADS / CYL = 16, SET LBA CAPABILITY BIT LD E,16 ; SECTORS / TRACK = 16 RET ; DONE, A STILL HAS PPIDE_CAP STATUS ; ;============================================================================= ; FUNCTION SUPPORT ROUTINES ;============================================================================= ; PPIDE_SETFEAT: PUSH AF #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" SETFEAT$") #ENDIF LD A,(PPIDE_DRVHD) ;OUT (PPIDE_REG_DRVHD),A CALL PPIDE_OUT .DB PPIDE_REG_DRVHD #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF POP AF ;OUT (PPIDE_REG_FEAT),A ; SET THE FEATURE VALUE CALL PPIDE_OUT .DB PPIDE_REG_FEAT #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF LD A,PPIDE_CMD_SETFEAT ; CMD = SETFEAT LD (PPIDE_CMD),A ; SAVE IT JP PPIDE_RUNCMD ; RUN COMMAND AND EXIT ; ; ; PPIDE_IDENTIFY: #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" IDDEV$") #ENDIF LD A,(PPIDE_DRVHD) ;OUT (PPIDE_REG_DRVHD),A CALL PPIDE_OUT .DB PPIDE_REG_DRVHD #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF LD A,PPIDE_CMD_IDDEV LD (PPIDE_CMD),A CALL PPIDE_RUNCMD_ND RET NZ ; CALL PPIDE_IN .DB PPIDE_REG_STAT BIT 3,A ; IS DRQ SET? JP Z,PPIDE_NOMEDIA ; LD HL,HB_WRKBUF JP PPIDE_GETBUF ; EXIT THRU BUFRD ; ; ; PPIDE_IDENTIFYPACKET: #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" IDPKTDEV$") #ENDIF LD A,(PPIDE_DRVHD) ;OUT (PPIDE_REG_DRVHD),A CALL PPIDE_OUT .DB PPIDE_REG_DRVHD #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF LD A,PPIDE_CMD_IDPKTDEV LD (PPIDE_CMD),A CALL PPIDE_RUNCMD_ND RET NZ ; CALL PPIDE_IN .DB PPIDE_REG_STAT BIT 3,A ; IS DRQ SET? JP Z,PPIDE_NOMEDIA ; LD HL,HB_WRKBUF JP PPIDE_GETBUF ; EXIT THRU BUFRD ; ; ; PPIDE_PACKET: #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" PACKET$") #ENDIF LD A,(PPIDE_DRVHD) ;OUT (PPIDE_REG_DRVHD),A CALL PPIDE_OUT .DB PPIDE_REG_DRVHD #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF XOR A ; ZERO CALL PPIDE_OUT .DB PPIDE_REG_FEAT ; FEATURE REG = 0 CALL PPIDE_OUT .DB PPIDE_REG_BCL LD A,8 CALL PPIDE_OUT .DB PPIDE_REG_BCH ; BYTE COUNT = 512???? LD A,PPIDE_CMD_PACKET LD (PPIDE_CMD),A JP PPIDE_RUNCMD_ND ; ; ; PPIDE_RDSEC: ; #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" READ$") #ENDIF LD A,(PPIDE_DRVHD) ;OUT (PPIDE_REG_DRVHD),A CALL PPIDE_OUT .DB PPIDE_REG_DRVHD #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF LD A,(IY+PPIDE_TYPE) CP PPIDE_TYPEATA JR Z,PPIDE_ATA_RDSEC CP PPIDE_TYPEATAPI JR Z,PPIDE_PKT_RDSEC JP PPIDE_CMDERR ; PPIDE_ATA_RDSEC: #IF (PPIDETRACE >= 3) PRTS(" ATA$") #ENDIF CALL PPIDE_SETADDR ; SETUP CYL, TRK, HEAD LD A,PPIDE_CMD_READ LD (PPIDE_CMD),A CALL PPIDE_RUNCMD RET NZ LD HL,(PPIDE_DSKBUF) JP PPIDE_GETBUF ; PPIDE_PKT_RDSEC: #IF (PPIDETRACE >= 3) PRTS(" PKT$") #ENDIF ; SETUP LBA ; ;;;#IF (DSKYENABLE) ;;; #IF (DSKYDSKACT) LD A,PPIDE_LBA CALL LDHLIYA CALL HB_DSKACT ; SHOW ACTIVITY ;;; #ENDIF ;;;#ENDIF ; ; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN LD HL,PPIDE_PKTCMD_RW10+3 ; START OF LBA FIELD IN CDB (MSB) LD A,(IY+PPIDE_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB) LD (HL),A INC HL LD A,(IY+PPIDE_LBA+1) LD (HL),A INC HL LD A,(IY+PPIDE_LBA+0) LD (HL),A INC HL LD HL,PPIDE_PKTCMD_RW10 LD A,SCSI_CMD_READ10 LD (HL),A XOR A ; READ DIRECTION LD (PPIDE_XFRDIR),A ; SAVE IT CALL PPIDE_RUNPCMD JP NZ,PPIDE_CHKPCMD RET ; ; ; PPIDE_WRSEC: ; #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" WRITE$") #ENDIF LD A,(PPIDE_DRVHD) ;OUT (PPIDE_REG_DRVHD),A CALL PPIDE_OUT .DB PPIDE_REG_DRVHD #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF LD A,(IY+PPIDE_TYPE) CP PPIDE_TYPEATA JR Z,PPIDE_ATA_WRSEC CP PPIDE_TYPEATAPI JR Z,PPIDE_PKT_WRSEC JP PPIDE_CMDERR ; PPIDE_ATA_WRSEC: #IF (PPIDETRACE >= 3) PRTS(" ATA$") #ENDIF CALL PPIDE_SETADDR ; SETUP CYL, TRK, HEAD LD A,PPIDE_CMD_WRITE LD (PPIDE_CMD),A CALL PPIDE_RUNCMD RET NZ LD HL,(PPIDE_DSKBUF) JP PPIDE_PUTBUF ; PPIDE_PKT_WRSEC: #IF (PPIDETRACE >= 3) PRTS(" PKT$") #ENDIF ; SETUP LBA ; ;;;#IF (DSKYENABLE) ;;; #IF (DSKYDSKACT) LD A,PPIDE_LBA CALL LDHLIYA CALL HB_DSKACT ; SHOW ACTIVITY ;;; #ENDIF ;;;#ENDIF ; ; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN LD HL,PPIDE_PKTCMD_RW10+3 ; START OF LBA FIELD IN CDB (MSB) LD A,(IY+PPIDE_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB) LD (HL),A INC HL LD A,(IY+PPIDE_LBA+1) LD (HL),A INC HL LD A,(IY+PPIDE_LBA+0) LD (HL),A INC HL LD HL,PPIDE_PKTCMD_RW10 LD A,SCSI_CMD_WRITE10 LD (HL),A OR $FF ; WRITE DIRECTION LD (PPIDE_XFRDIR),A ; SAVE IT CALL PPIDE_RUNPCMD JP NZ,PPIDE_CHKPCMD RET ; ; ; PPIDE_SETADDR: ; ;;;#IF (DSKYENABLE) ;;; #IF (DSKYDSKACT) LD A,PPIDE_LBA CALL LDHLIYA CALL HB_DSKACT ; SHOW ACTIVITY ;;; #ENDIF ;;;#ENDIF ; SEND 3 LOWEST BYTES OF LBA IN REVERSE ORDER ; IDE_REG_LBA3 HAS ALREADY BEEN SET ; HSTLBA2-0 --> IDE_REG_LBA2-0 LD A,(IY+PPIDE_LBA+2) #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CALL PPIDE_OUT .DB PPIDE_REG_LBA2 ; LD A,(IY+PPIDE_LBA+1) #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CALL PPIDE_OUT .DB PPIDE_REG_LBA1 ; LD A,(IY+PPIDE_LBA+0) #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CALL PPIDE_OUT .DB PPIDE_REG_LBA0 ; LD A,1 #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CALL PPIDE_OUT .DB PPIDE_REG_COUNT ; RET ; ;============================================================================= ; COMMAND PROCESSING ;============================================================================= ; ; RUN AN ATA COMMAND. THERE ARE TWO ENTRY POINTS. THE NORMAL ENTRY ; POINT WILL WAIT FOR DRIVE READY. THE _ND ENTRY POINT ONLY WAITS ; FOR THE DEVICE TO BE NOT BUSY. THE CORRECT ENTRY POINT DEPENDS ON ; THE COMMAND. ; PPIDE_RUNCMD_ND: CALL PPIDE_WAITBSY ; WAIT WHILE DEVICE BUSY RET NZ ; BAIL OUT ON TIMEOUT JR PPIDE_RUNCMD1 ; CONTINUE PPIDE_RUNCMD: CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY RET NZ ; BAIL OUT ON TIMEOUT ; PPIDE_RUNCMD1: LD A,(PPIDE_CMD) ; GET THE COMMAND #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ;OUT (PPIDE_REG_CMD),A ; SEND IT (STARTS EXECUTION) CALL PPIDE_OUT .DB PPIDE_REG_CMD #IF (PPIDETRACE >= 3) PRTS(" -->$") #ENDIF ; CALL PPIDE_WAITBSY ; WAIT FOR DRIVE READY (COMMAND DONE) RET NZ ; BAIL OUT ON TIMEOUT ; CALL PPIDE_GETRES JP NZ,PPIDE_CMDERR RET ; ; PACKET COMMAND PROCESSOR ; HL: ADDRESS OF PACKET COMMAND BUFFER ; PPIDE_RUNPCMD: PUSH HL CALL PPIDE_PACKET POP HL RET NZ ; BAIL OUT ON ERROR ; #IF (PPIDETRACE >= 3) PRTS("\r\nPKTCMD:$") PUSH HL POP DE LD A,12 CALL PRTHEXBUF #ENDIF ; ; IF ZIP DRIVE HAS FALLEN ASLEEP, THEN IT WILL NEED EXTRA ; TIME HERE TO WAKE UP BEFORE ACCEPTING THE COMMAND. USE ; LONG TIMEOUT TO ACCOMMODATE THIS. LD DE,(PPIDE_TIMEOUT) ; GET CURRENT TIMEOUT PUSH DE ; SAVE IT LD DE,PPIDE_TOSLOW ; SLOW TIMEOUT FOR THIS LD (PPIDE_TIMEOUT),DE ; SET IT LD B,6 ; 6 WORDS ALWAYS CALL PPIDE_PUT POP DE ; RECOVER TIMEOUT LD (PPIDE_TIMEOUT),DE ; SET IT RET NZ ; CALL PPIDE_IN .DB PPIDE_REG_STAT BIT 3,A ; IS DRQ SET? RET Z ; IF NOT, ALL DONE ; CALL PPIDE_IN .DB PPIDE_REG_BCL LD C,A CALL PPIDE_IN .DB PPIDE_REG_BCH LD B,A ; ; BELOW ASSUMES MAX TRANSFER OF 512 BYTES!!! PUSH BC ; SAVE BYTE COUNT SRL B ; CONVERT RR C ; ... TO WORDS LD B,C ;LD HL,HB_WRKBUF ; SET XFR BUFFER LD HL,(PPIDE_DSKBUF) ; SET XFR BUFFER LD A,(PPIDE_XFRDIR) OR A JR NZ,PPIDE_RUNPCMD2 ; NZ = WRITE CALL PPIDE_GET ; GET SOME DATA JR PPIDE_RUNPCMD3 PPIDE_RUNPCMD2: CALL PPIDE_PUT ; PUT SOME DATA PPIDE_RUNPCMD3: POP BC ; RESTORE BYTE COUNT RET NZ ; BAIL OUT ON ERRORS ; XOR A RET ; ; THE FOLLOWING IS USED TO ASSESS ANY ERROR THAT OCCURS DURING ; RUNCMD AND SET AN APPROPRIATE ERROR CODE. ; PPIDE_CHKPCMD: ; LD HL,HB_WRKBUF LD (PPIDE_DSKBUF),HL LD HL,PPIDE_PKTCMD_SENSE CALL PPIDE_RUNPCMD RET NZ ; CALL PPIDE_IN .DB PPIDE_REG_BCL ; #IF (PPIDETRACE >= 3) CALL NEWLINE LD DE,HB_WRKBUF CALL PRTHEXBUF #ENDIF ; ; ASSESS SENSE DATA AND SET APPROPRIATE ERROR LD A,(HB_WRKBUF+12) CP $3A JP Z,PPIDE_NOMEDIA CP $04 JP Z,PPIDE_NOTRDY ; JP PPIDE_CMDERR ; ; HL=BUFFER ; PPIDE_GETBUF: LD B,0 ; FALL THRU!!! ; ; HL=BUFFER ; B=WORD COUNT, 0=256 ; PPIDE_GET: #IF (PPIDETRACE >= 3) PRTS(" GET$") #ENDIF ; ; WAIT FOR BUFFER PUSH BC PUSH HL CALL PPIDE_WAITDRQ ; WAIT FOR BUFFER READY POP HL POP BC RET NZ ; BAIL OUT IF TIMEOUT ; ; SETUP PPI TO READ LD A,PPIDE_DIR_READ ; SET DATA BUS DIRECTION TO READ ;OUT (PPIDE_REG_PPI),A ; DO IT LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD OUT (C),A ; WRITE IT ; ; SELECT READ/WRITE IDE REGISTER LD A,PPIDE_REG_DATA ; DATA REGISTER ;OUT (PPIDE_REG_CTL),A ; DO IT LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS OUT (C),A ; DO IT LD E,A ; E := READ UNASSERTED XOR PPIDE_CTL_DIOR ; SWAP THE READ LINE BIT LD D,A ; D := READ ASSERTED ; LD A,B ; LOOP COUNTER IN A LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS BIT 1,(IY+PPIDE_ACC) ; 8 BIT? JR Z,PPIDE_GET1 ; IF NOT, DO 16 BIT CALL PPIDE_GET8 ; 8-BIT READ JR PPIDE_GET2 ; CONTINUE PPIDE_GET1: CALL PPIDE_GET16 ; 16-0BIT READ PPIDE_GET2: CALL PPIDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED! RET NZ CALL PPIDE_GETRES JP NZ,PPIDE_IOERR RET ; PPIDE_GET8: ; 8 BIT WIDE READ LOOP ; ENTER W/ C = PPIDE_REG_CTL OUT (C),D ; ASSERT READ DEC C ; CTL -> MSB DEC C ; MSB -> LSB INI ; READ FROM LSB INC C ; LSB -> MSB INC C ; MSB -> CTL OUT (C),E ; DEASSERT READ OUT (C),D ; ASSERT READ DEC C ; CTL -> MSB DEC C ; MSB -> LSB INI ; READ FROM LSB INC C ; LSB -> MSB INC C ; MSB -> CTL OUT (C),E ; DEASSERT READ DEC A JR NZ,PPIDE_GET8 ; LOOP UNTIL DONE RET ; PPIDE_GET16: ; 16 BIT WIDE READ LOOP ; ENTER W/ C = PPIDE_REG_CTL OUT (C),D ; ASSERT READ DEC C ; CTL -> MSB DEC C ; MSB -> LSB INI ; READ FROM LSB INC C ; LSB -> MSB INI ; READ MSB FOR 16 BIT INC C ; MSB -> CTL OUT (C),E ; DEASSERT READ DEC A JR NZ,PPIDE_GET16 ; LOOP UNTIL DONE RET ; ; HL=BUFFER ; PPIDE_PUTBUF: LD B,0 ; FALL THRU!!! ; ; HL=BUFFER ; B=WORD COUNT, 0=256 ; PPIDE_PUT: #IF (PPIDETRACE >= 3) PRTS(" PUT$") #ENDIF ; ; WAIT FOR BUFFER PUSH BC PUSH HL CALL PPIDE_WAITDRQ ; WAIT FOR BUFFER READY POP HL POP BC RET NZ ; BAIL OUT IF TIMEOUT ; ; SETUP PPI TO WRITE LD A,PPIDE_DIR_WRITE ; SET DATA BUS DIRECTION TO WRITE ;OUT (PPIDE_REG_PPI),A ; DO IT LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD OUT (C),A ; WRITE IT ; ; SELECT READ/WRITE IDE REGISTER LD A,PPIDE_REG_DATA ; DATA REGISTER ;OUT (PPIDE_REG_CTL),A ; DO IT LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS OUT (C),A ; DO IT LD E,A ; E := WRITE UNASSERTED XOR PPIDE_CTL_DIOW ; SWAP THE READ LINE BIT LD D,A ; D := WRITE ASSERTED ; ; LOOP SETUP LD A,B ; LOOP COUNTER IN A LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS BIT 1,(IY+PPIDE_ACC) ; 8 BIT? JR Z,PPIDE_PUT1 ; IF NOT, DO 16 BIT CALL PPIDE_PUT8 ; SECOND PASS (LAST 256 BYTES) JR PPIDE_PUT2 ; CONTINUE PPIDE_PUT1: CALL PPIDE_PUT16 ; FIRST PASS (FIRST 256 BYTES) PPIDE_PUT2: CALL PPIDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED! RET NZ CALL PPIDE_GETRES JP NZ,PPIDE_IOERR RET ; PPIDE_PUT8: ; 8 BIT WIDE WRITE LOOP DEC C ; CTL -> MSB DEC C ; MSB -> LSB OUTI ; WRITE NEXT BYTE (LSB) INC C ; LSB -> MSB INC C ; MSB -> CTL OUT (C),D ; ASSERT WRITE OUT (C),E ; DEASSERT WRITE DEC C ; CTL -> MSB DEC C ; MSB -> LSB OUTI ; WRITE NEXT BYTE (LSB) INC C ; LSB -> MSB INC C ; MSB -> CTL OUT (C),D ; ASSERT WRITE OUT (C),E ; DEASSERT WRITE DEC A JR NZ,PPIDE_PUT8 ; LOOP UNTIL DONE RET ; PPIDE_PUT16: ; 16 BIT WIDE WRITE LOOP DEC C ; CTL -> MSB DEC C ; MSB -> LSB OUTI ; WRITE NEXT BYTE (LSB) INC C ; LSB -> MSB OUTI ; WRITE NEXT BYTE (MSB) INC C ; MSB -> CTL OUT (C),D ; ASSERT WRITE OUT (C),E ; DEASSERT WRITE DEC A JR NZ,PPIDE_PUT16 ; LOOP UNTIL DONE RET ; ; ; PPIDE_GETRES: ;IN A,(PPIDE_REG_STAT) ; READ STATUS CALL PPIDE_IN .DB PPIDE_REG_STAT #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF AND %00000001 ; ERROR BIT SET? RET Z ; NOPE, RETURN WITH ZF ; ;IN A,(PPIDE_REG_ERR) ; READ ERROR REGISTER CALL PPIDE_IN .DB PPIDE_REG_ERR #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF OR $FF ; FORCE NZ TO SIGNAL ERROR RET ; RETURN ; ;============================================================================= ; HARDWARE INTERFACE ROUTINES ;============================================================================= ; ; RESET ALL DEVICES ON BUS ; PPIDE_RESET: #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" RESET$") #ENDIF ; ; HARD RESET ; ; RESET LINE IS NORMALLY PULSED AT POWER ON. HOWEVER, THIS IS NOT ; DONE FOR PPIDE DEVICES, SO WE DO IT NOW. ; ; SETUP PPI TO READ LD A,PPIDE_DIR_READ ; SET DATA BUS DIRECTION TO READ ;OUT (PPIDE_REG_PPI),A ; DO IT LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD OUT (C),A ; WRITE IT ; ; IF A DSKYNG IS ACTIVE AND IS ON THE SAME PPI PORT AS THE PPIDE BEING ; RESET, THEN THE DSKYNG WILL ALSO BE RESET. SO, THE RESET CODE IS ; BRACKETED WITH CODE TO SAVE AND RESTORE THE STATE OF THE DSKYNG. ; THERE IS NO CHECK FOR THE SPECIFIC PPI PORT SINCE IT DOES NO HARM ; IF THE DSKYNG IS SAVED AND RESTORED. ; ; THIS DOES NOT TEST THAT A DSKYNG IS ACTUALLY PRESENT ; AND OPERATING -- COULD CAUSE PROBLEMS ; #IF (DSKYENABLE) #IF (PKDENABLE) ; SAVE CONTENTS OF DSKYNG DISPLAY ACROSS RESET LD B,8 LD C,0 LD HL,DSKY_BUF CALL PKD_GETSTR #ENDIF #ENDIF ; ; PULSE IDE RESET LINE #IF (PPIDETRACE >= 3) PRTS(" HARD$") #ENDIF LD A,PPIDE_CTL_RESET ;OUT (PPIDE_REG_CTL),A LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS OUT (C),A LD DE,20 ; DELAY 320US (SPEC IS >= 25US) CALL VDELAY XOR A ;OUT (PPIDE_REG_CTL),A OUT (C),A LD DE,20 CALL VDELAY ; #IF (DSKYENABLE) #IF (PKDENABLE) ; REININT DSKYNG AND RESTORE CONTENTS CALL PKD_REINIT LD B,8 LD C,0 LD HL,DSKY_BUF CALL PKD_PUTSTR #ENDIF #ENDIF ; ; SOME CF CARDS AND CF CARD EMULATORS NEED A LITTLE TIME TO ; "BOOT" THEIR INTERNAL ELECTRONICS, SO THEY CANNOT ASSERT BUSY ; IMMEDIATELY. A SMALL WAIT IS PERFORMED HERE TO GIVE SUCH DEVICES ; A BETTER CHANCE TO SUCCEED LATER. ; ; LD DE,150000 / 16 ; LD DE,300000 / 16 ; CALL VDELAY ; SMALL DELAY ; JR PPIDE_RESET3 ; SKIP SOFT RESET ; ; SOFT RESET ; ; RC CANNOT ACCESS DEVICE CONTROL REG, SO SKIP THIS ; PPIDE_RESET2: ; INITIATE SOFT RESET #IF (IDETRACE >= 3) PRTS(" SOFT$") #ENDIF LD A,%00001110 ; ASSERT RESET, NO INTERRUPTS ;OUT (PPIDE_REG_CTRL),A CALL PPIDE_OUT .DB PPIDE_REG_CTRL LD DE,20 ; DELAY 320US (SPEC IS >= 25US) CALL VDELAY ; PPIDE_RESET3: ; ; CONFIGURE OPERATION AND END SOFT RESET ; #IF (PPIDETRACE >= 3) PRTS(" CONFIG$") #ENDIF LD A,%00001010 ; DEASSERT RESET, NO INTERRUPTS ;OUT (PPIDE_REG_CTRL),A CALL PPIDE_OUT .DB PPIDE_REG_CTRL LD DE,20 ; DELAY 320US (SPEC IS >= 25US) CALL VDELAY ; PPIDE_RESET5: LD HL,PPIDE_TONORM ; NORMAL TIMEOUT NOW LD (PPIDE_TIMEOUT),HL ; AND RESTORE IT ; ; INITIALIZE THE INDIVIDUAL UNITS (MASTER AND SLAVE). ; BASED ON TESTING, IT APPEARS THAT THE MASTER UNIT MUST ; BE DONE FIRST OR THIS BEHAVES BADLY. ; PUSH IY ; SAVE CFG PTR BIT 0,(IY+PPIDE_ACC) ; MASTER? CALL Z,PPIDE_GOPARTNER ; IF NOT, SWITCH TO MASTER CALL PPIDE_INITUNIT ; INIT CURRENT UNIT CALL PPIDE_GOPARTNER ; POINT TO SLAVE CALL PPIDE_INITUNIT ; INIT PARTNER UNIT POP IY ; RECOVER ORIG CFG PTR ; XOR A ; SIGNAL SUCCESS RET ; AND DONE ; ; ; PPIDE_INITUNIT: CALL PPIDE_SELUNIT ; SELECT UNIT RET NZ ; ABORT IF ERROR CALL PPIDE_PROBE ; DO PROBE RET NZ ; JUST RETURN IF NOTHING THERE JP PPIDE_INITDEV ; EXIT VIA INITDEV ; ; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT ; PPIDE_SELUNIT: #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" SELUNIT$") #ENDIF BIT 0,(IY+PPIDE_ACC) ; MASTER? JR Z,PPIDE_SELUNIT1 ; HANDLE SLAVE LD A,PPIDE_DRVMASTER ; MASTER #IF (PPIDETRACE >= 3) PRTS(" MASTER$") #ENDIF JR PPIDE_SELUNIT2 PPIDE_SELUNIT1: LD A,PPIDE_DRVSLAVE ; SLAVE #IF (PPIDETRACE >= 3) PRTS(" SLAVE$") #ENDIF PPIDE_SELUNIT2: LD (PPIDE_DRVHD),A ; SAVE IT XOR A ; SUCCESS RET ; ; ; PPIDE_PROBE: ; ; PROBE FOR A DRIVE ON THE INTERFACE (EITHER MASTER OR SLAVE). ; IDEALLY, THIS IS BEING CALLED IMMEDIATELY AFTER A HARD OR SOFT ; INTERFACE RESET. HOWEVER, THERE ARE SOME HARDWARE IMPLEMENTATTIONS ; WHICH ARE CAPABLE OF NEITHER A HARD NOR SOFT RESET. SO THIS ; CODE SHOULD TRY TO HANDLE THE SCENARIO WHERE NO INTERFACE RESET ; HAS OCCURRED. ; #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" PROBE$") ; LABEL FOR IO ADDRESS #ENDIF ; #IF (PPIDETRACE >= 3) CALL PPIDE_IN .DB PPIDE_REG_STAT CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; ; SELECT DEVICE (MASTER/SLAVE) LD A,(PPIDE_DRVHD) ;OUT (IDE_REG_DRVHD),A CALL PPIDE_OUT .DB PPIDE_REG_DRVHD #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CALL DELAY ; DELAY ~16US ; ; IF WE GET HERE AND THE DRIVE IS STILL INITIALIZING, WE NEED TO ; WAIT UNTIL THE DRIVE IS READY. IN THIS CASE BUSY *WILL* BE HIGH. ; BASED ON TESTING, DRDY AND DSC VALUES VARY. EVERYTHING ELSE SEEMS ; TO BE ZERO. SO, WE FILTER OUT DRDY & DSC, THEN LOOK FOR BUSY=1 ; AND ALL ELSE ZERO. THIS GENERALLY AVOIDS VALUES THAT ARE TYPICAL ; FOR FLOATING PORTS AND SO CAN BE USED TO DETERMINE IF WE NEED TO ; WAIT FOR THE DEVICE TO BE READY. THIS WAIT IS MANDATORY BECAUSE ; SOME (IF NOT ALL) DEVICES WILL NOT PERSIST REGISTER VALUES UNTIL ; THE DRIVE IS READY. ; ; FIRST, WRITE A $7F VALUE TO THE PPIDE STATUS REGISTER. IF ; AN IDE DEVICE EXISTS, THIS WILL DO NO HARM. IF NOT, THIS ; WILL HELP AVOID A FALSE POSITIVE (STALL). LD A,$7F CALL PPIDE_OUT .DB PPIDE_REG_DATA ; CALL PPIDE_IN .DB PPIDE_REG_STAT #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; AND %10101111 ; FILTER OUT DRDY & DSC CP $80 ; INIT IN PROGRESS? JR NZ,PPIDE_PROBE1 ; IF NOT, SKIP AHEAD ; #IF (PPIDETRACE >= 3) PRTS(" WAIT$") #ENDIF ; LD HL,(PPIDE_TIMEOUT) ; GET CURRENT TIMEOUT PUSH HL ; SAVE IT LD HL,PPIDE_TOSLOW ; SLOW TIMEOUT FOR THIS LD (PPIDE_TIMEOUT),HL ; SET IT CALL PPIDE_WAITBSY ; WAIT FOR BUSY TO CLEAR POP HL ; RECOVER TIMEOUT LD (PPIDE_TIMEOUT),HL ; SET IT ; #IF (PPIDETRACE >= 3) CALL PPIDE_IN .DB PPIDE_REG_STAT CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; ; TEST FOR PRESENCE OF IDE REGISTERS. USE LBA0/1 TO SEE ; IF VALUE CAN BE PERSISTED. THE USE OF BOTH LBA0 AND LBA1 ; IS TO MAINTAIN CONSISTENCY WITH THE THE PPIDE DRIVER BECAUSE ; PPI ITSELF WILL PERSIST THE LAST VALUE WRITTEN, SO WE USE ; MULTIPLE REGISTERS TO WORK AROUND THIS FALSE POSITIVE. ; PPIDE_PROBE1: ; $AA -> LBA0 LD A,$AA CALL PPIDE_OUT .DB PPIDE_REG_LBA0 ; ; $55 => LBA1 LD A,$55 CALL PPIDE_OUT .DB PPIDE_REG_LBA1 ; ; TEST LBA0 == $AA CALL PPIDE_IN .DB PPIDE_REG_LBA0 #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CP $AA JP NZ,PPIDE_NOMEDIA ; ; TEST LBA1 == $55 CALL PPIDE_IN .DB PPIDE_REG_LBA1 #IF (PPIDETRACE >= 3) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF CP $55 JP NZ,PPIDE_NOMEDIA ; #IF (PPIDETRACE >= 3) CALL PPIDE_REGDUMP #ENDIF ; XOR A RET ; ; (RE)INITIALIZE DEVICE ; PPIDE_INITDEV: ; #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" INITDEV$") ; LABEL FOR IO ADDRESS #ENDIF ; #IF (PPIDETRACE >= 3) CALL PPIDE_REGDUMP #ENDIF ; ; ON ENTRY, WE HAVE ALREADY CHECKED THAT THE BUSY BIT IS CLEARED AND ; DRDY SHOULD BE SET. IF DRDY IS NOT SET, IF COULD MEAN EITHER A ; NON-EXISTENT SLAVE DEVICE OR AN ATAPI DEVICE. TO AVOID UNNECESSARY ; TIMEOUTS, WE CHECK FOR DRDY. IF IT IS NOT SET, THEN WE ASSUME THIS ; MUST BE AN ATAPI DEVICE AND GO TRY TO DO THE ATAPI INITIALIZATION. ; IF THIS WAS ACTUALLY A NON-EXISTENT SLAVE, THE ATAPI INITIALIZATION ; WILL HANDLE THIS PRETTY WELL. ; CALL PPIDE_IN .DB PPIDE_REG_STAT BIT 6,A ; DRDY? JR Z,PPIDE_INITPDEV ; ODD, MIGHT BE ATAPI ; ; WE NEED TO SETUP 8-BIT MODE BEFORE DOING ANYTHING ELSE ; BIT 1,(IY+PPIDE_ACC) ; 8 BIT ACCESS? JR Z,PPIDE_INITDEV0 ; NO, DO 16 BIT INIT LD A,PPIDE_FEAT_ENABLE8BIT ; FEATURE VALUE = ENABLE 8-BIT PIO CALL PPIDE_SETFEAT ; SET FEATURE RET NZ ; BAIL OUT ON ERROR JR PPIDE_INITDEV00 ; CONTINUE ; PPIDE_INITDEV0: ; "REAL" IDE DRIVES MAY NOT ACCEPT THE DISABLE8BIT FEATURE COMMAND, ; SO IT IS ONLY AN ERROR IF WE ARE ATTEMPTING TO ENABLE8BIT. ; CREDIT TO ED BRINDLEY FOR THIS CORRECTION. SO ERROR RETURN IGNORED HERE. LD A,PPIDE_FEAT_DISABLE8BIT ; FEATURE VALUE = ENABLE 8-BIT PIO CALL PPIDE_SETFEAT ; SET FEATURE, IGNORE ERRORS ; PPIDE_INITDEV00: ; ; WE NOW USE AN IDENTIFY DEVICE COMMAND TO CONFIRM THE ; DEVICE IS REALLY THERE AND GET SOME ATTRIBUTES. IF THE ; COMMAND FAILS, IT MAY BE THAT WE HAVE AN ATAPI DEVICE AND ; SO WE GO TO THE ATAPI INITIALIZATION ON FAILURE. CALL PPIDE_IDENTIFY ; EXECUTE PPIDENTIFY COMMAND JR NZ,PPIDE_INITPDEV ; TRY ATAPI ON FAILURE ; ; DECLARE WE ARE ATA LD A,PPIDE_TYPEATA ; OTHERWISE TYPE=ATA LD (IY+PPIDE_TYPE),A ; SET IT IN INSTANCE DATA ; LD DE,HB_WRKBUF ; POINT TO BUFFER #IF (PPIDETRACE >= 4) CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING #ENDIF ; LD (IY+PPIDE_MED),0 ; CLEAR MEDIA FLAGS ; #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" SIG=0x$") LD BC,(HB_WRKBUF) CALL PRTHEXWORD #ENDIF ; ; DETERMINE IF COMPACTFLASH MEDIA LD A,(HB_WRKBUF+(83*2)) ; LOW BYTE OF WORD 83 BIT 2,A ; TEST CFA FEATURE SET BIT JR Z,PPIDE_INITDEV1 ; IF NOT, SKIP SET 0,(IY+PPIDE_MED) ; ELSE SET FLAGS BIT FOR CF MEDIA ; PPIDE_INITDEV1: ; DETERMINE IF LBA CAPABLE LD A,(HB_WRKBUF+98+1) ; HIGH BYTE OF WORD 49 BIT 1,A ; CHECK THE LBA BIT JR Z,PPIDE_INITDEV2 ; NOT SET, BYPASS SET 1,(IY+PPIDE_MED) ; SET FLAGS BIT FOR LBA ; PPIDE_INITDEV2: ; GET DEVICE CAPACITY AND SAVE IT LD A,PPIDE_MEDCAP ; OFFSET TO CAPACITY FIELD CALL LDHLIYA ; HL := IY + A, REG A TRASHED PUSH HL ; SAVE POINTER LD HL,HB_WRKBUF ; POINT TO BUFFER START LD A,120 ; OFFSET OF SECTOR COUNT CALL ADDHLA ; POINT TO ADDRESS OF SECTOR COUNT CALL LD32 ; LOAD IT TO DE:HL POP BC ; RECOVER POINTER TO CAPACITY ENTRY CALL ST32 ; SAVE CAPACITY ; ; RECORD STATUS OK XOR A ; A := 0 (STATUS = OK) LD (IY+PPIDE_STAT),A ; SAVE IT ; RET ; RETURN, A=0, Z SET ; ; (RE)INITIALIZE PACKET DEVICE ; PPIDE_INITPDEV: ; #IF (PPIDETRACE >= 3) CALL PPIDE_PRTPREFIX PRTS(" INITPDEV$") ; LABEL FOR IO ADDRESS #ENDIF ; CALL PPIDE_IDENTIFYPACKET ; EXECUTE IDENTIFY COMMAND RET NZ ; BAIL OUT ON ERROR ; ; DECLARE WE ARE ATAPI LD A,PPIDE_TYPEATAPI ; OTHERWISE TYPE=ATAPI LD (IY+PPIDE_TYPE),A ; SET IT IN INSTANCE DATA ; LD DE,HB_WRKBUF ; POINT TO BUFFER #IF (PPIDETRACE >= 4) CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING #ENDIF ; LD (IY+PPIDE_MED),0 ; CLEAR FLAGS SET 1,(IY+PPIDE_MED) ; SET FLAGS BIT FOR LBA (ASSUMED) ; ; WAIT FOR UNIT READY LD B,0 ; MAX LOOPS LD C,4 ; MAX ERRORS PPIDE_INITPDEV1: DEC B ; CHECK LOOP COUNTER EXCEEDED JP Z,PPIDE_NOMEDIA ; TREAT AS NO MEDIA PUSH BC ; SAVE LOOP CONTROL LD HL,PPIDE_PKTCMD_TSTRDY ; TEST UNIT READY XOR A ; READ DIRECTION LD (PPIDE_XFRDIR),A ; SAVE IT CALL PPIDE_RUNPCMD ; ISSUE PACKET COMMAND CALL NZ,PPIDE_CHKPCMD ; IF ERROR, DIAGNOSE IT POP BC ; RESTORE LOOP CONTROL JR Z,PPIDE_INITPDEV2 ; IF NO ERROR, CONTINUE CP PPIDE_STNOMEDIA ; EXPLICIT NO MEDIA RESULT? RET Z ; EXIT REPORTING NO MEDIA CP PPIDE_STNOTRDY ; BECOMING READY? JR Z,PPIDE_INITDEVP1A ; IF SO, NOT AN ERROR, LOOP DEC C ; DEC ERROR LIMIT RET Z ; BAIL OUT, ERR LIMIT EXCEEDED JR PPIDE_INITPDEV1 ; LOOP PPIDE_INITDEVP1A: LD DE,100000/16 ; WAIT 1/10 SECOND CALL VDELAY ; DO IT JR PPIDE_INITPDEV1 ; AND LOOP ; PPIDE_INITPDEV2: #IF (PPIDETRACE >= 3) LD A,B NEG PRTS("\r\nLOOPS=$") CALL PRTHEXBYTE #ENDIF ; ; GET AND RECORD CAPACITY LD HL,HB_WRKBUF LD (PPIDE_DSKBUF),HL LD HL,PPIDE_PKTCMD_RDCAP XOR A ; READ DIRECTION LD (PPIDE_XFRDIR),A ; SAVE IT CALL PPIDE_RUNPCMD JP NZ,PPIDE_CHKPCMD ; #IF (PPIDETRACE >= 3) PRTS("\r\nRDCAP:$") LD A,8 LD DE,HB_WRKBUF CALL PRTHEXBUF #ENDIF ; ; CAPACITY IS RETURNED IN A 4 BYTE, BIG ENDIAN FIELD AND ; INDICATES THE LAST LBA VALUE. WE NEED TO CONVERT THIS TO ; LITTLE ENDIAN AND INCREMENT THE VALUE TO MAKE IT A CAPACITY ; COUNT INSTEAD OF A LAST LBA VALUE. LD A,PPIDE_MEDCAP ; OFFSET IN CFG FOR CAPACITY CALL LDHLIYA ; POINTER TO HL PUSH HL ; SAVE IT LD HL,HB_WRKBUF ; POINT TO VALUE IN CMD RESULT CALL LD32 ; LOAD IT TO DE:HL LD A,L ; FLIP BYTES LD L,D ; ... BIG ENDIAN LD D,A ; ... TO LITTLE ENDIAN LD A,H LD H,E LD E,A CALL INC32 ; INCREMENT TO FINAL VALUE POP BC ; RECOVER SAVE LOCATION CALL ST32 ; STORE VALUE ; ; CHECK BLOCK LENGTH. WE CURRENTLY ONLY SUPPORT 512 BYTE ; BLOCKS. CD-ROM DEVICES (WHICH USE 2k BLOCKS) WILL FAIL ; HERE AS NOT SUPPORTED. LD HL,HB_WRKBUF+4 ; POINT TO BLK SIZE IN RESULT CALL LD32 ; LOAD IT TO DE:HL ; VALUE IS BIG ENDIAN, SO LH:ED MUST BE EXACTLY 0000:0200 LD A,L ; CHECK THAT LH OR H ; ... IS ZERO JP NZ,PPIDE_NOTSUP ; IF NOT, FAIL AS NOT SUP LD A,D ; LOAD D OR A ; SET FLAGS JP NZ,PPIDE_NOTSUP ; IF NOT ZERO, FAIL AS NOT SUP LD A,E ; LOAD E CP 2 ; CHECK IT IF IS 2 JP NZ,PPIDE_NOTSUP ; IF NOT, FAIL AS NOT SUP ; ; RECORD STATUS OK XOR A ; A := 0 (STATUS = OK) LD (IY+PPIDE_STAT),A ; SAVE IT RET ; ; SWITCH IY POINTER FROM CURRENT UNIT CFG TO PARTNER UNIT CFG ; PPIDE_GOPARTNER: PUSH HL ; SAVE HL LD L,(IY+PPIDE_PARTNER) ; GET PARTNER ENTRY LD H,(IY+PPIDE_PARTNER+1) ; ... PUSH HL ; MOVE HL POP IY ; ... TO IY POP HL ; RESTORE INCOMING HL RET ; AND DONE ; ; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER ; VIA RESET IF DEVICE IS IN ERROR. ; PPIDE_CHKERR: LD A,(IY+PPIDE_STAT) ; GET STATUS OR A ; SET FLAGS CALL NZ,PPIDE_RESET ; IF ERROR STATUS, RESET BUS RET ; ; ; PPIDE_WAITRDY: LD A,(PPIDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS LD B,A ; PUT IN OUTER LOOP VAR PPIDE_WAITRDY1: LD DE,(PPIDE_TOSCALER) ; CPU SPEED SCALER TO INNER LOOP VAR PPIDE_WAITRDY2: ;IN A,(PPIDE_REG_STAT) ; READ STATUS CALL PPIDE_IN .DB PPIDE_REG_STAT LD C,A ; SAVE IT AND %11000000 ; ISOLATE BUSY AND RDY BITS XOR %01000000 ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1 RET Z ; ALL SET, RETURN WITH Z SET DEC DE LD A,D OR E JR NZ,PPIDE_WAITRDY2 ; INNER LOOP RETURN DJNZ PPIDE_WAITRDY1 ; OUTER LOOP RETURN JP PPIDE_RDYTO ; EXIT WITH RDYTO ERR ; ; ; PPIDE_WAITDRQ: LD A,(PPIDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS LD B,A ; PUT IN OUTER LOOP VAR PPIDE_WAITDRQ1: LD DE,(PPIDE_TOSCALER) ; CPU SPEED SCALER TO INNER LOOP VAR PPIDE_WAITDRQ2: ;IN A,(PPIDE_REG_STAT) ; READ STATUS CALL PPIDE_IN .DB PPIDE_REG_STAT LD C,A ; SAVE IT AND %10001000 ; TO FILL (OR READY TO FILL) XOR %00001000 RET Z DEC DE LD A,D OR E JR NZ,PPIDE_WAITDRQ2 DJNZ PPIDE_WAITDRQ1 JP PPIDE_DRQTO ; EXIT WITH BUFTO ERR ; ; ; PPIDE_WAITBSY: LD A,(PPIDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS LD B,A ; PUT IN OUTER LOOP VAR PPIDE_WAITBSY1: LD DE,(PPIDE_TOSCALER) ; CPU SPEED SCALER TO INNER LOOP VAR PPIDE_WAITBSY2: ;IN A,(PPIDE_REG_STAT) ; READ STATUS CALL PPIDE_IN ; 17TS + 204TS .DB PPIDE_REG_STAT LD C,A ; SAVE IT ; 4TS AND %10000000 ; TO FILL (OR READY TO FILL) ; 7TS RET Z ; 5TS DEC DE ; 6TS LD A,D ; 4TS OR E ; 4TS JR NZ,PPIDE_WAITBSY2 ; 12TS DJNZ PPIDE_WAITBSY1 ; ----- JP PPIDE_BSYTO ; EXIT WITH BSYTO ERR ; 263TS ; ; READ A VALUE FROM THE DEVICE POINTED TO BY IY AND RETURN IT IN A ; PPIDE_IN: EX (SP),HL ; GET PARM POINTER ; 19TS PUSH BC ; SAVE INCOMING BC ; 11TS LD A,PPIDE_DIR_READ ; SET DATA BUS DIRECTION TO READ ; 7TS ;OUT (PPIDE_REG_PPI),A ; DO IT LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD ; 19TS OUT (C),A ; WRITE IT ; 12TS ; LD B,(HL) ; GET CTL PORT VALUE ; 7TS ;LD C,PPIDE_REG_CTL ; SETUP PORT TO WRITE ;LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS DEC C ; SET IDE ADDRESS ; 4TS OUT (C),B ; SET ADDRESS LINES ; 12TS SET 6,B ; TURN ON READ BIT ; 8TS OUT (C),B ; ASSERT READ LINE ; 12TS ; ;IN A,(PPIDE_REG_DATALO) ; GET DATA VALUE FROM DEVICE DEC C ; 4TS DEC C ; 4TS IN A,(C) ; GET DATA VALUE FROM DEVICE ; 12 INC C ; 4TS INC C ; 4TS ; RES 6,B ; CLEAR READ BIT ; 8TS OUT (C),B ; DEASSERT READ LINE ; 12TS POP BC ; RECOVER INCOMING BC ; 10TS INC HL ; POINT PAST PARM ; 6TS EX (SP),HL ; RESTORE STACK ; 19TS RET ; 10TS ; ; ----- ; OUTPUT VALUE IN A TO THE DEVICE POINTED TO BY IY ; 204TS ; PPIDE_OUT: ; *** TODO *** FIX ORDER OF SET/CLEAR WRITE LINE EX (SP),HL ; GET PARM POINTER PUSH BC ; SAVE INCOMING BC PUSH AF ; PRESERVE INCOMING VALUE LD A,PPIDE_DIR_WRITE ; SET DATA BUS DIRECTION TO WRITE ;OUT (PPIDE_REG_PPI),A ; DO IT LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD OUT (C),A ; WRITE IT POP AF ; RECOVER VALUE TO WRITE ; LD B,(HL) ; GET IDE ADDRESS VALUE ;LD C,PPIDE_REG_CTL ; SETUP PORT TO WRITE ;LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS DEC C ; SET IDE ADDRESS OUT (C),B ; SET ADDRESS LINES SET 5,B ; TURN ON WRITE BIT OUT (C),B ; ASSERT WRITE LINE ; DEC C DEC C ;OUT (PPIDE_REG_DATALO),A ; SEND DATA VALUE TO DEVICE OUT (C),A ; SEND DATA VALUE TO DEVICE INC C INC C ; RES 5,B ; CLEAR WRITE BIT OUT (C),B ; DEASSERT WRITE LINE POP BC ; RECOVER INCOMING BC INC HL ; POINT PAST PARM EX (SP),HL ; RESTORE STACK RET ; ;============================================================================= ; ERROR HANDLING AND DIAGNOSTICS ;============================================================================= ; ; ERROR HANDLERS ; PPIDE_INVUNIT: LD A,PPIDE_STINVUNIT JR PPIDE_ERR2 ; SPECIAL CASE FOR INVALID UNIT ; PPIDE_NOMEDIA: LD A,PPIDE_STNOMEDIA JR PPIDE_ERR ; PPIDE_CMDERR: LD A,PPIDE_STCMDERR JR PPIDE_ERR ; PPIDE_IOERR: LD A,PPIDE_STIOERR JR PPIDE_ERR ; PPIDE_RDYTO: LD A,PPIDE_STRDYTO JR PPIDE_ERR ; PPIDE_DRQTO: LD A,PPIDE_STDRQTO JR PPIDE_ERR ; PPIDE_BSYTO: LD A,PPIDE_STBSYTO JR PPIDE_ERR ; PPIDE_NOTSUP: LD A,PPIDE_STNOTSUP JR PPIDE_ERR ; PPIDE_NOTRDY: LD A,PPIDE_STNOTRDY JR PPIDE_ERR ; PPIDE_ERR: LD (IY+PPIDE_STAT),A ; SAVE NEW STATUS ; PPIDE_ERR2: #IF (PPIDETRACE >= 2) CALL PPIDE_PRTSTAT CALL PPIDE_REGDUMP #ENDIF OR A ; SET FLAGS RET ; ; ; PPIDE_PRTERR: RET Z ; DONE IF NO ERRORS ; FALL THRU TO PPIDE_PRTSTAT ; ; PRINT FULL DEVICE STATUS LINE ; PPIDE_PRTSTAT: PUSH AF PUSH DE PUSH HL LD A,(IY+PPIDE_STAT) CP PPIDE_STINVUNIT JR Z,PPIDE_PRTSTAT2 ; INVALID UNIT IS SPECIAL CASE CALL PPIDE_PRTPREFIX ; PRINT UNIT PREFIX JR PPIDE_PRTSTAT3 PPIDE_PRTSTAT2: CALL NEWLINE PRTS("PPIDE:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT PPIDE_PRTSTAT3: CALL PC_SPACE ; FORMATTING CALL PPIDE_PRTSTATSTR POP HL POP DE POP AF RET ; ; PRINT STATUS STRING ; PPIDE_PRTSTATSTR: PUSH AF PUSH DE LD A,(IY+PPIDE_STAT) OR A LD DE,PPIDE_STR_STOK JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STINVUNIT JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STNOMEDIA JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STCMDERR JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STIOERR JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STRDYTO JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STDRQTO JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STBSYTO JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STNOTSUP JR Z,PPIDE_PRTSTATSTR1 INC A LD DE,PPIDE_STR_STNOTRDY JR Z,PPIDE_PRTSTATSTR1 LD DE,PPIDE_STR_STUNK PPIDE_PRTSTATSTR1: CALL WRITESTR POP DE POP AF RET ; ; PRINT ALL REGISTERS DIRECTLY FROM DEVICE ; DEVICE MUST BE SELECTED PRIOR TO CALL ; PPIDE_REGDUMP: PUSH AF PUSH BC push DE CALL PC_SPACE CALL PC_LBKT LD A,PPIDE_DIR_READ ; SET DATA BUS DIRECTION TO READ ;OUT (PPIDE_REG_PPI),A ; DO IT LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD OUT (C),A ; WRITE IT LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS LD E,PPIDE_REG_CMD LD B,7 PPIDE_REGDUMP1: LD A,E ; REGISTER ADDRESS ;OUT (PPIDE_REG_CTL),A ; SET IT OUT (C),A ; REGISTER ADDRESS XOR PPIDE_CTL_DIOR ; SET BIT TO ASSERT READ LINE ;OUT (PPIDE_REG_CTL),A ; ASSERT READ OUT (C),A ; ASSERT READ ;IN A,(PPIDE_REG_DATALO) ; GET VALUE DEC C ; CTL -> MSB DEC C ; MSB -> LSB IN A,(C) ; GET VALUE INC C ; LSB -> MSB INC C ; MSB -> CTL CALL PRTHEXBYTE ; DISPLAY IT ;LD A,C ; RELOAD ADDRESS W/ READ UNASSERTED ;OUT (PPIDE_REG_CTL),A ; AND SET IT OUT (C),E ; RELOAD ADDRESS W/ READ UNASSERTED ;DEC C ; NEXT LOWER REGISTER DEC E ; NEXT LOWER REGISTER DEC B ; DEC LOOP COUNTER CALL NZ,PC_SPACE ; FORMATTING JR NZ,PPIDE_REGDUMP1 ; LOOP AS NEEDED CALL PC_RBKT ; FORMATTING POP DE POP BC POP AF RET ; ; PRINT DIAGNONSTIC PREFIX ; PPIDE_PRTPREFIX: PUSH AF CALL NEWLINE PRTS("PPIDE$") LD A,(IY+PPIDE_DEV) ; GET CURRENT DEVICE NUM CP $FE ; NOT YET ASSIGNED? JR Z,PPIDE_PRTPREFIX1 ; SKIP DEV NUM IF SO CALL PRTDECB PPIDE_PRTPREFIX1: CALL PC_COLON POP AF RET ; ;============================================================================= ; STRING DATA ;============================================================================= ; PPIDE_STR_STOK .TEXT "OK$" PPIDE_STR_STINVUNIT .TEXT "INVALID UNIT$" PPIDE_STR_STNOMEDIA .TEXT "NO MEDIA$" PPIDE_STR_STCMDERR .TEXT "COMMAND ERROR$" PPIDE_STR_STIOERR .TEXT "IO ERROR$" PPIDE_STR_STRDYTO .TEXT "READY TIMEOUT$" PPIDE_STR_STDRQTO .TEXT "DRQ TIMEOUT$" PPIDE_STR_STBSYTO .TEXT "BUSY TIMEOUT$" PPIDE_STR_STNOTSUP .TEXT "NOT SUPPORTED$" PPIDE_STR_STNOTRDY .TEXT "NOT READY$" PPIDE_STR_STUNK .TEXT "UNKNOWN ERROR$" ; PPIDE_STR_NO .TEXT "NO$" PPIDE_STR_NOPPI .TEXT "PPI NOT PRESENT$" PPIDE_STR_8BIT .TEXT " 8-BIT$" ; PPIDE_STR_TYPEATA .TEXT " ATA$" PPIDE_STR_TYPEATAPI .TEXT " ATAPI$" ; ;============================================================================= ; DATA STORAGE ;============================================================================= ; PPIDE_TIMEOUT .DB PPIDE_TONORM ; WAIT FUNCS TIMEOUT IN TENTHS OF SEC PPIDE_TOSCALER .DW CPUMHZ * 380 ; WAIT FUNCS SCALER FOR CPU SPEED ; PPIDE_CMD .DB 0 ; PENDING COMMAND TO PROCESS PPIDE_IOFNADR .DW 0 ; PENDING IO FUNCTION ADDRESS PPIDE_DRVHD .DB 0 ; CURRENT DRIVE/HEAD MASK ; PPIDE_DSKBUF .DW 0 ; ACTIVE DISK BUFFER PPIDE_XFRDIR .DB 0 ; 0=READ, NON-0=WRITE ; PPIDE_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT ; ; SCSI COMMAND TEMPLATES (ALWAYS 12 BYTES FOR ATAPI) ; PPIDE_PKTCMD_RW .DB $00, $00, $00, $00, $01, $00, $00, $00, $00, $00, $00, $00 ; READ/WRITE SECTOR PPIDE_PKTCMD_SENSE .DB $03, $00, $00, $00, $FF, $00, $00, $00, $00, $00, $00, $00 ; REQUEST SENSE DATA PPIDE_PKTCMD_RDCAP .DB $25, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; READ CAPACITY PPIDE_PKTCMD_RW10 .DB $28, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00 ; READ/WRITE SECTOR PPIDE_PKTCMD_TSTRDY .DB $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; TEST UNIT READY