;CF127E .TITLE "Apple /// CompactFlash/IDE Driver Ver 1.27E" ;Limit Maximum Volume Size to 32767 Blocks ;LoBuffer & HiBuffer zero page pointers ;No Status Check for R/W Block Transfers ;Test for CFFA card version 2.x .PROC CFIDE ; SOS Equates ExtPG .EQU 1401 ;driver extended bank address offset AllocSIR .EQU 1913 ;allocate system internal resource SELC800 .EQU 1922 ;Enable Expansion Rom Space SysErr .EQU 1928 ;report error to system EReg .EQU 0FFDF ;environment register ReqCode .EQU 0C0 ;request code SosUnit .EQU 0C1 ;unit number SosBuf .EQU 0C2 ;buffer pointer ReqCnt .EQU 0C4 ;requested byte count CtlStat .EQU 0C2 ;control/status code CSList .EQU 0C3 ;control/status list pointer SosBlk .EQU 0C6 ;starting block number QtyRead .EQU 0C8 ;bytes read return by D_READ ; Our temps in zero page CurPart .EQU 0CC FR_Code .EQU 0CD ;1 bytes Count .EQU 0CD ;2 bytes ;Parameter block specific to current SOS request ATA_Cmd .EQU 0CF Drv_Parm .EQU 0D0 Sect_HB .EQU 0D1 Sect_MB .EQU 0D2 Sect_LB .EQU 0D3 Num_Blks .EQU 0D4 ;2 bytes lb,hb LoBuffer .EQU 0D6 ;2 bytes HiBuffer .EQU 0D8 ;2 bytes CurDrive .EQU 0DA ;Current IDE drive number of SosUnit # CurDrvNo .EQU 0DB ;Current DIB drive number of SosUnit # ; SOS Error Codes XREQCODE .EQU 020 ;Invalid request code XCTLCODE .EQU 021 ;Invalid control/status code XCTLPARAM .EQU 022 ;Invalid control/status parameter XNORESRC .EQU 025 ;Resource not available XBADOP .EQU 026 ;Invalid operation XIOERROR .EQU 027 ;I/O error XNODRIVE .EQU 028 ;Drive not connected XBYTECNT .EQU 02C ;Byte count not a multiple of 512 XBLKNUM .EQU 02D ;Block number to large XDCMDERR .EQU 031 ;device command ABORTED error occurred XCKDEVER .EQU 032 ;Check device readiness routine failed XNORESET .EQU 033 ;Device reset failed XNODEVIC .EQU 038 ;Device not connected ;IFC I/O locations IFC_ID .EQU 0C820 IOBase .EQU 0C080 ATdataHB .EQU IOBase+0. SetCSMsk .EQU IOBase+1. ;Two special strobe locations to set and ;clear MASK bit that is used to disable ;CS0 line to the CompactFlash during the ;CPU read cycles. ClrCSMsk .EQU IOBase+2. ;that occur before every CPU write cycle. ;The normally innocuous read cycles were ;causing the SanDisk CF to double ;increment during sector writes commands. Alt_Stat .EQU IOBase+6. ;when reading (not used) ATAdCtrl .EQU IOBase+6. ;when writing ATdataLB .EQU IOBase+8. ATAError .EQU IOBase+9. Features .EQU IOBase+9. ATSectCt .EQU IOBase+10. ATSector .EQU IOBase+11. ;11=LB,12=MB,13=HB ATAHead .EQU IOBase+14. ATCmdReg .EQU IOBase+15. ;when writing ATA_Stat .EQU IOBase+15. ;when reading ; ATA/CF Commands Codes ATA_XErr .EQU 003 ATACRead .EQU 020 ATACWrit .EQU 030 ATA_Vrfy .EQU 040 ATA_Frmt .EQU 050 ATA_Diag .EQU 090 ATAIdent .EQU 0EC SetFeatr .EQU 0EF ;Constants for Wait Wait5ms .EQU 42. Wait150ms .EQU 242. ; Switch Macro .MACRO switch .IF "%1" <> "" ;if parameter 1 is present LDA %1 ;load A with switch index .ENDC CMP #%2+1 ;do bounds check BCS $010 ASL A TAY LDA %3+1,Y ;get switch index from table PHA LDA %3,Y PHA .IF "%4" <> "*" ;if parameter 4 omitted, RTS ;go to code .ENDC $010 .ENDM .WORD 0FFFF ;Comment Field .WORD 61. .ASCII "Apple /// CFFA v2.x Driver - " .ASCII "written by Dale S. Jackson 6/08" ;Device identification Block (DIB) - Volume #0 DIB_0 .WORD DIB_1 ;link pointer .WORD Entry ;entry pointer .BYTE 7 ;name length byte .ASCII ".CFIDE1 ";device name .BYTE 0C0 ;active, page aligned DIB0_Slot .BYTE 003 ;0FF ;slot number .BYTE 000 ;unit number .BYTE 0D1 ;type .BYTE 010 ;subtype .BYTE 000 ;filler DIB0_Blks .WORD 0000 ;# blocks in device .WORD 444A ;manufacturer - DJ .WORD 127E ;Version 1.27E .WORD 0003 ;DCB length followed by DCB Driv_No0 .BYTE 000 ;Drive #, Bit 0=$0 (master) or $1 (slave) ;Upper 6 bits = Partition address. ;64 different partition addresses avail. Part_No0 .BYTE 000 ;Partition number on the drive = $00-07 PIO_Mode .BYTE 000 ;PIO Transfer Mode (mode value plus $08) ;A value $00 turns off setting the PIO ;transfer mode during driver partition ;initialization. ;DIB Values for Map & Drive No. ;Map No. IDE $0 IDE $1 Map No. IDE $0 IDE $1 ; 0 $00 $01 32 $80 $81 ; 1 $04 $05 33 $84 $85 ; 2 $08 $09 34 $88 $89 ; 3 $0C $0D 35 $8C $8D ; 4 $10 $11 36 $90 $91 ; 5 $14 $15 37 $94 $95 ; 6 $18 $19 38 $98 $99 ; 7 $1C $1D 39 $9C $9D ; 8 $20 $21 40 $A0 $A1 ; 9 $24 $25 41 $A4 $A5 ; 10 $28 $29 42 $A8 $A9 ; 11 $2C $2D 43 $AC $AD ; 12 $30 $31 44 $B0 $B1 ; 13 $34 $35 45 $B4 $B5 ; 14 $38 $39 46 $B8 $B9 ; 15 $3C $3D 47 $BC $BD ; 16 $40 $41 48 $C0 $C1 ; 17 $44 $45 49 $C4 $C5 ; 18 $48 $49 50 $C8 $C9 ; 19 $4C $4D 51 $CC $CD ; 20 $50 $51 52 $D0 $D1 ; 21 $54 $55 53 $D4 $D5 ; 22 $58 $59 54 $D8 $D9 ; 23 $5C $5D 55 $DC $DD ; 24 $60 $61 56 $E0 $E1 ; 25 $64 $65 57 $E4 $E5 ; 26 $68 $69 58 $E8 $E9 ; 27 $6C $6D 59 $EC $ED ; 28 $70 $71 60 $F0 $F1 ; 29 $74 $75 61 $F4 $F5 ; 30 $78 $79 62 $F8 $F9 ; 31 $7C $7D 63 $FC $FD ;Device identification Block (DIB) - Volume #1 ;Page alignment begins here DIB_1 .WORD DIB_2 ;link pointer .WORD Entry ;entry pointer .BYTE 7 ;name length byte .ASCII ".CFIDE2 ";device name .BYTE 080 ;active .BYTE 003 ;0FF ;slot number .BYTE 001 ;unit number .BYTE 0D1 ;type .BYTE 010 ;subtype .BYTE 000 ;filler DIB1_Blks .WORD 0000 ;# blocks in device .WORD 444A ;manufacturer - DJ .WORD 127E ;Version 1.27E .WORD 0002 ;DCB length followed by DCB .BYTE 000 ;Drive # = $00 (master) or $01 (slave) ;Upper 6 bits = Partition address. ;64 different partition addresses avail. .BYTE 001 ;Partition number on the drive = $00-07 ;Device identification Block (DIB) - Volume #2 DIB_2 .WORD DIB_3 ;link pointer .WORD Entry ;entry pointer .BYTE 7 ;name length byte .ASCII ".CFIDE3 ";device name .BYTE 080 ;active .BYTE 003 ;0FF ;slot number .BYTE 002 ;unit number .BYTE 0D1 ;type .BYTE 010 ;subtype .BYTE 000 ;filler DIB2_Blks .WORD 0000 ;# blocks in device .WORD 444A ;manufacturer - DJ .WORD 127E ;Version 1.27E .WORD 0002 ;DCB length followed by DCB .BYTE 000 ;Drive # = $00 (master) or $01 (slave) ;Upper 6 bits = Partition address. ;64 different partition addresses avail. .BYTE 002 ;Partition number on the drive = $00-07 ;Device identification Block (DIB) - Volume #3 DIB_3 .WORD DIB_4 ;link pointer .WORD Entry ;entry pointer .BYTE 7 ;name length byte .ASCII ".CFIDE4 ";device name .BYTE 080 ;active .BYTE 003 ;0FF ;slot number .BYTE 003 ;unit number .BYTE 0D1 ;type .BYTE 010 ;subtype .BYTE 000 ;filler DIB3_Blks .WORD 0000 ;# blocks in device .WORD 444A ;manufacturer - DJ .WORD 127E ;Version 1.27E .WORD 0002 ;DCB length followed by DCB .BYTE 000 ;Drive # = $00 (master) or $01 (slave) ;Upper 6 bits = Partition address. ;64 different partition addresses avail. .BYTE 003 ;Partition number on the drive = $00-07 ;Device identification Block (DIB) - Volume #4 DIB_4 .WORD DIB_5 ;link pointer .WORD Entry ;entry pointer .BYTE 7 ;name length byte .ASCII ".CFIDE5 ";device name .BYTE 080 ;active .BYTE 003 ;0FF ;slot number .BYTE 004 ;unit number .BYTE 0D1 ;type .BYTE 010 ;subtype .BYTE 000 ;filler DIB4_Blks .WORD 0000 ;# blocks in device .WORD 444A ;manufacturer - DJ .WORD 127E ;Version 1.27E .WORD 0002 ;DCB length followed by DCB .BYTE 000 ;Drive # = $00 (master) or $01 (slave) ;Upper 6 bits = Partition address. ;64 different partition addresses avail. .BYTE 004 ;Partition number on the drive = $00-07 ;Device identification Block (DIB) - Volume #5 DIB_5 .WORD DIB_6 ;link pointer .WORD Entry ;entry pointer .BYTE 7 ;name length byte .ASCII ".CFIDE6 ";device name .BYTE 080 ;active .BYTE 003 ;0FF ;slot number .BYTE 005 ;unit number .BYTE 0D1 ;type .BYTE 010 ;subtype .BYTE 000 ;filler DIB5_Blks .WORD 0000 ;# blocks in device .WORD 444A ;manufacturer - DJ .WORD 127E ;Version 1.27E .WORD 0002 ;DCB length followed by DCB .BYTE 000 ;Drive # = $00 (master) or $01 (slave) ;Upper 6 bits = Partition address. ;64 different partition addresses avail. .BYTE 005 ;Partition number on the drive = $00-07 ;Device identification Block (DIB) - Volume #6 DIB_6 .WORD DIB_7 ;link pointer .WORD Entry ;entry pointer .BYTE 7 ;name length byte .ASCII ".CFIDE7 ";device name .BYTE 080 ;active .BYTE 003 ;0FF ;slot number .BYTE 006 ;unit number .BYTE 0D1 ;type .BYTE 010 ;subtype .BYTE 000 ;filler DIB6_Blks .WORD 0000 ;# blocks in device .WORD 444A ;manufacturer - DJ .WORD 127E ;Version 1.27E .WORD 0002 ;DCB length followed by DCB .BYTE 000 ;Drive # = $00 (master) or $01 (slave) ;Upper 6 bits = Partition address. ;64 different partition addresses avail. .BYTE 006 ;Partition number on the drive = $00-07 ;Device identification Block (DIB) - Volume #7 DIB_7 .WORD 0000 ;link pointer .WORD Entry ;entry pointer .BYTE 7 ;name length byte .ASCII ".CFIDE8 ";device name .BYTE 080 ;active .BYTE 003 ;0FF ;slot number .BYTE 007 ;unit number .BYTE 0D1 ;type .BYTE 010 ;subtype .BYTE 000 ;filler DIB7_Blks .WORD 0000 ;# blocks in device .WORD 444A ;manufacturer - DJ .WORD 127E ;Version 1.27E .WORD 0002 ;DCB length followed by DCB .BYTE 000 ;Drive # = $00 (master) or $01 (slave) ;Upper 6 bits = Partition address. ;64 different partition addresses avail. .BYTE 007 ;Partition number on the drive = $00-07 ;Read_Blk - Read requested blocks from device into memory Read_Blk JSR SetupLBA ;Program the device's task file registers LDA ATA_Cmd STA ATCmdReg,x ;Issue the read, verify, identity command ReadIt LDA ATA_Stat,x ;Wait for BUSY flag to clear BMI ReadIt AND #029 ;Check for error response from device CMP #008 ;If DF=1, DRQ=0, or ERR=1 an error occured BNE Read_Err PHP SEI ;No interuptions while I get the sector ;**** This segment must not cross page boundary **** $1 LDA ATdataLB,x STA (LoBuffer),y INY LDA ATdataHB,x STA (LoBuffer),y INY BNE $1 INC LoBuffer+1 $2 LDA ATdataLB,x STA (LoBuffer),y INY LDA ATdataHB,x STA (LoBuffer),y INY BNE $2 ;**** End of segment **** PLP JSR IncrAdr DEC Num_Blks ;did we get what was asked for BNE ReadIt DEC Num_Blks+1 BPL ReadIt JMP CSet2Mhz Read_Err JMP Save_Err ;D_WRITE call processing DWrite JSR CkCnt LDA #ATACWrit STA ATA_Cmd CWrite LDA Num_Blks ;check for Num_Blks greater than zero ORA Num_Blks+1 BEQ WritDone ;quantity to write is zero ; WriteBlk - Write requested blocks from memory to device JSR FixUp JSR SetupLBA ;Program the device's task file registers LDA ATA_Cmd STA ATCmdReg,x ;Issue the write/format command to drive WriteIt BCC $1 ;If carry clear, buffer pointer unchanged CLC LDA LoBuffer ADC #001 STA HiBuffer LDA LoBuffer+1 ADC #000 STA HiBuffer+1 LDA LoBuffer+ExtPG STA HiBuffer+ExtPG $1 LDA ATA_Stat,x ;Wait for BUSY flag to clear BMI $1 AND #029 ;Check for error response from device CMP #008 ;If DF=1 or DRQ=0 or ERR=1 a device error BNE Writ_Err PHP SEI ;No interuptions while I get the sector LDA SetCSMsk,x ;any access sets mask bit to block ;IDE -CS0 on I/O read to drive ;**** This segment must not cross page boundary **** $2 LDA (HiBuffer),y STA ATdataHB,x LDA (LoBuffer),y STA ATdataLB,x INY INY BNE $2 INC LoBuffer+1 INC HiBuffer+1 $3 LDA (HiBuffer),y STA ATdataHB,x LDA (LoBuffer),y STA ATdataLB,x INY INY BNE $3 ;**** End of segment **** LDA ClrCSMsk,x ;Set back to normal, allow CS0 assertions ;on read cycles PLP JSR BumpAdr DEC Num_Blks ;did we do what was asked for BNE WriteIt DEC Num_Blks+1 ;we might have to do this one more time BPL WriteIt WritDone JMP CSet2Mhz ;exit write routines Writ_Err JSR Save_Err LDA #XIOERROR ;I/O error JSR SysErr ;doesn't return ;Local storage locations SlotCX .BYTE 000 ;compute C0X0 and store on init PtBlkIdx .BYTE 0A3,0A8,0B3,0B8,0C3,0C8,0D3,0D8 ;Offsets to 8 block PtVolIdx .BYTE 0A6,0AB,0B6,0BB,0C6,0CB,0D6,0DB ;segment for ea partition UnitStat .BLOCK 008,0FF ;if UnitStat,X = $FF then partition info ;not initialized ;if UnitStat,X > $0F then UnitStat = error code ;else UnitStat,X = partition number ;if UnitStat,0 = #XNODRIVE then driver is ;nonfunctional LastOP .BLOCK 008,0FF ;last op for D_REPEAT calls StBlk_HB .BLOCK 008,000 ;Starting block number for SOS/ProDos StBlk_MB .BLOCK 008,000 ;vol #0, vol #1, vol #2, vol #3 StBlk_LB .BLOCK 008,000 ;vol #4, vol #5, vol #6, vol #7 Block_LB .BLOCK 008,000 ;Total blocks for each volume # Block_HB .BLOCK 008,000 DCB_Idx .BYTE 000 .BYTE DIB1_Blks-DIB0_Blks .BYTE DIB2_Blks-DIB0_Blks .BYTE DIB3_Blks-DIB0_Blks .BYTE DIB4_Blks-DIB0_Blks .BYTE DIB5_Blks-DIB0_Blks .BYTE DIB6_Blks-DIB0_Blks .BYTE DIB7_Blks-DIB0_Blks SIR_Addr .WORD SIR_Tbl SIR_Tbl .BLOCK 005,000 SIR_Len .EQU *-SIR_Tbl PmapCall .BLOCK 003,000 ;Block $hb mb lb for partition record .BYTE 001,000 ;Read 1 ATA sector (block) lb, hb .WORD PmapBuf ;Buffer address to place partition record PmapBuf .BLOCK 0100,000 Err_Data .BLOCK 0100,000 .ASCII "Written By Dale S. Jackson, initial writing 12/12/02" .ASCII "v1.27E revised 6/27/08" ; Main entry point Entry LDA UnitStat+0 CMP #XNODEVIC BEQ No_Drive LDX SosUnit ;get drive number for this unit LDY DCB_Idx,X LDA Driv_No0,Y STA CurDrvNo AND #001 ;only bit 0 counts STA CurDrive ;Set device to LBA mode ORA #00E ;device mode bits %00001(LBA)1(Drive#) ASL A ;shift left 4 bits to high order nibble ASL A ASL A ASL A STA Drv_Parm LDA ReqCode CMP #002 ;Status Call BCS $1 JSR InitPmap ;Check if partition table is current ;fetch it if not. $1 JSR Dispatch ;Now call the dispatcher LDX SosUnit ;Save current operation LDA ReqCode ;for D_REPEAT processing STA LastOP,X RTS ;Bye ;The Dispatcher. Does it depending on ReqCode. Note ;that if we came in on a D_INIT call, we do a branch to ;Dispatch, normally. Dispatch is called as a subroutine! ;We copy the buffer pointer and block # from the parameter ;area into our own temps, as the system seems to want them ;left ALONE. Dispatch SWITCH ReqCode,9,DoTable ;go do it. BadReq LDA #XREQCODE ;bad request code! JSR SysErr ;doesn't return Slot_Err LDA #XNODEVIC ;#XNORESRC SIR not available STA UnitStat+0 ;no! it didn't go ok. No_Drive LDA #XNODRIVE ;Flag this driver not useable Err_Out1 JSR SysErr ;doesn't return ;D_INIT call processing for all Volumes. ;Called at system init time only. Check DIB0_Slot to ;make sure that the user set a valid slot number for our ;interface. Allocate it by calling AllocSIR. If slot not ;available then set UnitStat+0 to XNORESRC error code. DInit LDA SIR_Tbl BNE Norm_Out LDA DIB0_Slot CMP #005 BCS Slot_Err ;Compute the system internal resource number (SIR) and ;call AllocSIR to try and grab that for us. It performs ;slot checking as a side effect. ORA #010 ;SIR = 16+slot# STA SIR_Tbl LDA #SIR_Len LDX SIR_Addr LDY SIR_Addr+1 JSR AllocSIR ;this one's mine! BCS Slot_Err LDA DIB0_Slot ;Compute CsXX for this slot ASL A ASL A ASL A ASL A STA SlotCX JSR ResetIFC ;Initialization of Device BCS Slot_Err LDY #007 ;Reset drive status to initial startup LDA #0FF $1 STA UnitStat,Y DEY BPL $1 Norm_Out CLC RTS .INCLUDE CF127F .END ;CF127F ; Initialize Partition Table Data InitPmap LDX SosUnit LDA UnitStat,X CMP #0FF BNE $2 ;Set ATA transfer mode for drive LDA PIO_Mode BEQ $1 ;If Mode=$0 then skip setting xfer mode LDA #003 ;CF Feature $03 = set transfer mode STA FR_Code JSR D_Featur $1 JSR GetPmap JSR PInit $2 CMP #010 ;Check if Unit driver is good. BCS Err_Out1 RTS ;Dispatch table. DoTable .WORD DRead-1 ;0 read request .WORD DWrite-1 ;1 write request .WORD DStatus-1 ;2 status request .WORD DControl-1 ;3 control request .WORD BadReq-1 ;4 unused .WORD BadReq-1 ;5 unused .WORD BadOp-1 ;6 open - invalid request .WORD BadOp-1 ;7 close - invalid request .WORD DInit-1 ;8 init request .WORD DRepeat-1 ;9 repeat request ;D_REPEAT - repeat the last D_READ or D_WRITE call DRepeat LDX SosUnit LDA LastOP,X ;look at the last thing we did CMP #002 BCS BadOp STA ReqCode JMP Dispatch BadOp LDA #XBADOP ;invalid operation! JSR SysErr ;doesn't return ;Get Partition Map from drive GetPmap LDA CurDrvNo AND #0FC ;get upper 6 bits of drive number for ;partition addr. STA PmapCall LDY #006 $1 LDA PmapCall,Y STA Sect_HB,Y DEY BPL $1 LDA #000 STA LoBuffer+ExtPG LDA #ATACRead STA ATA_Cmd JMP SRead ;Initialize partition info for each partition in the ;current table. PInit LDX #007 $1 LDY DCB_Idx,X LDA CurDrvNo CMP Driv_No0,Y BNE $4 LDA Part_No0,Y ;Get assigned partition number for this ;driver. CMP #008 BCS $2 ;Partition number is out of range TAY STY CurPart JSR GStrtBlk BCS $2 JSR GVolSize BCS $2 LDY DCB_Idx,X LDA Block_HB,X STA DIB0_Blks+1,Y LDA Block_LB,X STA DIB0_Blks,Y LDA CurPart BPL $3 $2 LDA #XNODRIVE ;Flag this driver not useable $3 STA UnitStat,X $4 DEX BPL $1 CLC RTS GStrtBlk LDA PtBlkIdx,Y ;Xreg contains DIB unit number, TAY ;Yreg contains drive partition count LDA PmapBuf+2,Y CMP #0FF ;Test if beginning track is valid BNE $1 CMP PmapBuf+1,Y BNE $1 CMP PmapBuf,Y BEQ Bad_Ptn ;Return with carry set $1 ORA PmapCall ;set upper 6 bits for partition address STA StBlk_HB,X LDA PmapBuf+1,Y STA StBlk_MB,X ORA PmapBuf+2,Y ;Check if beginning track is zero ORA PmapBuf,Y BEQ Bad_Ptn ;Return with carry set if zero LDA PmapBuf,Y STA StBlk_LB,X CLC RTS Bad_Ptn SEC RTS GVolSize LDY CurPart ;Xreg contains DIB unit number LDA PtVolIdx,Y TAY LDA PmapBuf,Y STA Block_LB,X ORA PmapBuf+1,Y BEQ Bad_Ptn ;Volume size cannot be zero LDA PmapBuf+1,Y STA Block_HB,X BMI Bad_Ptn ;Volume size is greater than 32767 blocks CLC RTS ;Random support and checking routines for the block driver ;Check ReqCnt to insure it's a multiple of 512. CkCnt LDA ReqCnt ;look at the lsb of bytes to do BNE $1 ;no good! lsb should be 00 STA Num_Blks+1 ;zero high byte of number of blocks LDA ReqCnt+1 ;look at the msb LSR A ;put bottom bit into carry, 0 into top STA Num_Blks ;save as number of blocks to transfer BCC CVTBLK ;Carry is set from LSR to mark error. $1 LDA #XBYTECNT JSR SysErr ;doesn't return ;Test for valid block number.Carry clear on return means ;no error. Carry set means block number bad. X register ;contains volume number. CVTBLK LDA SosBuf STA LoBuffer LDA SosBuf+1 STA LoBuffer+1 LDA SosBuf+ExtPG STA LoBuffer+ExtPG LDY SosUnit LDA SosBlk CMP Block_LB,y LDA SosBlk+1 SBC Block_HB,y BCC $2 LDA #XBLKNUM JSR SysErr ;doesn't return $2 LDA SosBlk ADC StBlk_LB,y STA Sect_LB LDA SosBlk+1 ADC StBlk_MB,y STA Sect_MB LDA StBlk_HB,y ADC #000 STA Sect_HB RTS ; D_READ call processing DRead JSR CkCnt LDA #ATACRead STA ATA_Cmd CRead LDA #000 ;Zero # bytes read STA Count STA Count+1 TAY STA (QtyRead),Y ;bytes read INY STA (QtyRead),Y ;msb of bytes read LDA Num_Blks ;check for Num_Blks greater than zero ORA Num_Blks+1 BEQ ReadDone ;quantity to read is already zero JSR FixUp JSR Read_Blk ;Transfer a block to/from the disk LDY #000 LDA count STA (QtyRead),y ;Update # of bytes actually read. INY LDA count+1 STA (QtyRead),y BCS IO_Error ;An error occurred ReadExit RTS ;exit read routines. ReadDone JMP CSet2Mhz SRead JSR Read_Blk ;Transfer a block to/from the disk BCC ReadExit IO_Error LDA #XIOERROR ;I/O error JSR SysErr ;doesn't return Save_Err LDA ATA_Stat,x STA Err_Data LSR A BCS $1 ;if status ERR bit is one then get error LDA #000 ;register data, else return error data BEQ $2 ;byte = zero. $1 LDA ATAError,x $2 STA Err_Data+1 LDA ATSector,x ;retrieve sector # error occurred STA Err_Data+2 ;LB LDA ATSector+1,x STA Err_Data+3 ;MB LDA ATSector+2,x STA Err_Data+4 ;HB LDA ATSectCt,x STA Err_Data+5 ;retrieve # of sectors left STY Count SEC JMP Set2Mhz ;D_STATUS call processing ; $00 Drivers Status - always $0 ; $01 Return device identification - $0200 bytes long ; $02 Return most recent device error information/data ; $03 Return partition table data - $0100 bytes long ; $04 Return DIB configuration bytes - 2 bytes long ; $FE Return preferrred bitmap location ($FFFF) DStatus LDA CtlStat ;status command BEQ Status CMP #001 BEQ S_Ident CMP #002 BEQ ErrStat CMP #003 BEQ ParTable CMP #004 BEQ DIBinfo CMP #0FE BEQ BitMap CS_Bad LDA #XCTLCODE ;control/status code no good Err_Out3 JSR SysErr ;doesn't return ;Driver Status Status TAY STA (CSList),Y RTS ;Return partition table of current SOSunit ParTable JSR GetPmap LDY #000 $1 LDA PmapBuf,Y STA (CSList),Y INY BNE $1 RTS ;Return most recent error data. ; Byte 0: Device Status Code ; Byte 1: Device Error Code (if status ERR bit is 0, ; then error code = 0) ; Byte 2,3,4: Sector# (LB,MB,HB) error occurred ; Byte 5: # of sectors left to transfer ErrStat LDY #005 $1 LDA Err_Data,y STA (CSList),Y DEY BPL $1 CLC RTS ;Return DIB configuration bytes DIBinfo LDX SosUnit LDY DCB_Idx,X LDA Part_No0,Y ;Get assigned partition # for this driver PHA LDA Driv_No0,Y ;Get assigned partition map/IDE device for ;this driver. LDY #000 STA @CSList,Y INY PLA STA @CSList,Y CLC RTS ;Return preferred bit map locations. We return FFFF. BitMap LDY #000 LDA #0FF STA (CSList),Y INY STA (CSList),Y ;return FFFF, don't care CLC RTS ;and leave ; Device Identification S_Ident LDA CSList STA LoBuffer LDA CSList+1 STA LoBuffer+1 LDA CSList+ExtPG STA LoBuffer+ExtPG LDA #ATAIdent STA ATA_Cmd C_Ident LDA #001 STA Num_Blks LDA #000 STA Num_Blks+1 JMP SRead ;Perform I/O with user supplied call block ;Call Block Organization: ; Byte 0: ATA Command Code ; Byte 1,2,3: Sector# (HB,MB,LB absolute sector) ; Byte 4: # of sectors ; Byte 5-6: Bytes returned to buffer ; Byte 7... Data Buffer CtrlCmds .BYTE ATA_Xerr .BYTE ATACRead .BYTE ATACWrit .BYTE ATA_Vrfy .BYTE ATA_Frmt .BYTE ATA_Diag .BYTE ATAIdent Cmd_Tbl .WORD Send_Cmd-1 ;Extended Error Info $03 .WORD CRead-1 ;Sector Read $20 .WORD CWrite-1 ;Sector Write $30 .WORD Verify-1 ;Read verify $40 .WORD CWrite-1 ;Sector Format $50 .WORD Send_Cmd-1 ;Internal Diagnostic Test $90 .WORD C_Ident-1 ;Device Identity $EC UserIO LDY #004 $1 LDA (CSList),Y STA ATA_Cmd+1,Y DEY BNE $1 LDA Num_Blks ;if zero then 256 blocks is requested BNE $2 INY $2 STY Num_Blks+1 CLC ;Setup data addresses LDA CSList ADC #005 STA QtyRead LDA CSList+1 ADC #000 STA QtyRead+1 LDA QtyRead ADC #002 STA LoBuffer LDA QtyRead+1 ADC #000 STA LoBuffer+1 LDA CSList+ExtPG STA QtyRead+ExtPG STA LoBuffer+ExtPG LDY #000 LDA (CSList),Y LDY #006 $3 CMP Ctrl_Cmds,y BEQ $4 DEY BPL $3 JMP CS_Bad $4 STA ATA_Cmd TYA ASL A TAY LDA Cmd_Tbl+1,Y PHA LDA Cmd_Tbl,Y PHA RTS ;D_CONTROL call processing ; $00 Reset device ; $01 Perform device I/O function with user supplied ; call block. ; $02 Set Device Features ; $04 Set DIB configuration bytes ; $FE Perform media formatting DControl LDA CtlStat ;control command BEQ CReset CMP #001 BEQ UserIO CMP #002 BEQ C_Featur CMP #004 BEQ New_DIB CMP #0FE ;formatting? BEQ MFormat JMP CS_Bad ;Control code no good! CReset JSR ResetIFC ;Reset CFFA card BCS $1 RTS $1 LDA #XNORESET JSR SysErr ;doesn't return ;Execute media formatting call. MFormat LDX #007 $1 LDY DCB_Idx,X LDA Driv_No0,Y CMP CurDrvNo BNE $2 LDA #0FF ;Invalidate partition table status STA UnitStat,X ;so subsequent read/writes $2 DEX ;will re-initialize the partition info BPL $1 ;for each driver designated for this CLC ;partiton table. RTS ;Save new DIB configuration bytes New_DIB LDX SosUnit LDA #0FF ;Invalidate partition table status. STA UnitStat,X LDY #000 LDA @CSList,Y PHA INY LDA @CSList,Y LDY DCB_Idx,X STA Part_No0,Y ;Get assigned partition # for this driver PLA STA Driv_No0,Y ;Get assigned partition map/IDE device for CLC ;this driver. RTS ;Set Device Features Command ;Call Block Organization: ; Byte 0: Feature Code ; Byte 1: PIO_Mode (for Set Transfer Mode ; feature only). C_Featur LDY #000 LDA @CSList,Y STA FR_Code CMP #003 ;check if feature code is set BNE D_Featur ;transfer mode $03. No, continue to INY ;set feature. LDA @CSList,Y STA PIO_Mode ;Save PIO mode for all subsequent D_Featur JSR CkDevice ;transfer settings. LDA FR_Code STA Features,x CMP #003 ;check if feature code is set BNE $1 ;transfer mode $03. No, continue to LDA PIO_Mode ;set feature. Yes, get PIO_Mode STA ATSectCt,x ;value. $1 LDA #SetFeatr STA ATCmdReg,x ;Issue the Set Features command $2 LDA ATA_Stat,x BMI $2 LDA ATAError,x STA Err_Data AND #004 JSR Set2Mhz BNE $3 RTS $3 LDA #XDCMDERR ;$31 device command ABORTED error JSR SysErr ;occurred -> doesn't return. ;Supplemental Subroutines ;Device Internal Diagnostic Routine ATA Command $90 ; Returns 1 byte of diagnostic code in Buffer ; $01 = No Error Detected ; $02 = Formatter Device Error ; $03 = Sector Buffer Error ; $04 = ECC Circuitry Error ; $05 = Controlling Microprocessor Error ; $8x = Slave Failed (true IDE mode) ;Extended Error Code Request ; Returns 1 byte of exteded error code in Buffer ; $00 = No Error Detected ; $01 = Self test OK (No error) ; $09 = Miscellaneous Error ; $20 = Invalid Command ; $21 = Invalid address (requested head or sector invalid) ; $2F = Address Overflow (address too large) ; $35,$36 = Supply voltage out of tolerance ; $11 = Uncorrectable ECC error ; $18 = Corrected ECC Error ; $05,$30-34,$37,$3E = Self test or diagnostic failed ; $10,$14 = ID not found ; $3A = Spare sectors exhausted ; $1F = Data transfer error/Aborted command ; $0C,$38,$3B,$3C,$3F = Corrupted Media Format ; $03 = Write/Erase failed Send_Cmd JSR CkDevice LDA #000 STA ATdataHB,x ;Clear high byte data latch LDA ATA_Cmd STA ATCmdReg,x ;Issue the ATA command to the drive $1 LDA ATA_Stat,x BMI $1 LDA ATAError,x LDY #000 STA (LoBuffer),y JMP CSet2Mhz ;Verify - Verify requested blocks Verify JSR SetupLBA ;Program the device's task file registers LDA #ATA_Vrfy STA ATCmdReg,x ;Issue the read verify command $1 LDA ATA_Stat,x ;Wait for BUSY flag to clear BMI $1 LSR a BCS $2 JMP Set2Mhz $2 JMP Writ_Err ;Check Slot for CFFA Ver 2.x Signature & Reset IFC ResetIFC JSR Set1Mhz LDA DIB0_Slot JSR SELC800 ;Turn on ROM LDA IFC_ID+2 AND #0F0 ;Check major ROM version is 2.xx EOR IFC_ID+1 EOR IFC_ID PHA LDA #000 JSR SELC800 ;Turn off ROM PLA CMP #015 BNE No_IFC LDX SlotCX ;Execute reset call to ATA IFC LDA ClrCSMsk,x ;reset MASK bit in PLD for normal CS0 LDA #000 ;signaling. STA ATdataHB,x ;Clear high byte data latch LDA #006 ;Reset bit=1, Disable INTRQ=1 STA ATAdCtrl,x JSR Norm_Out ;Per ATA-6 spec, need to wait 5us minimum. LDA #002 ;Reset bit=0, Disable INTRQ=1 STA ATAdCtrl,x LDY #208. ;Per ATA-6 spec, need to wait 2ms minimum LDA #Wait5ms ;Use a initial delay of 5ms. $1 JSR Wait LDA ATA_Stat,x ;Per ATA-6 spec, wait up to 31 sec for BMI $2 ;busy to clear if a slave is attached. JMP CSet2Mhz $2 LDA #Wait150ms ;Wait for up to 31 secs if a slave is DEY ;attached. After 31 secs pass, the card BNE $1 ;is not installed in slot. No_IFC SEC ;Drive(s) Not Ready JMP Set2Mhz ;Check Device - test drive status register is readable ;and equal to $40 CkDevice JSR Set1Mhz LDY #200. LDX SlotCX LDA ClrCSMsk,x ;reset MASK bit in PLD for normal CS0 $1 LDA ATA_Stat,x ;signaling. BMI $1 AND #008 ;%00001000 Check bus can receive a BEQ $2 ;device register setting DRQ=0 LDA #Wait5ms JSR Wait ;Wait 5ms to try again DEY BNE $1 ;Wait up to 1 second for drive to be ready BEQ NotReady ;always taken $2 LDA Drv_Parm ;Select drive to check STA ATAHead,x LDY #200. $3 LDA ATA_Stat,x BMI $3 AND #0E9 ;%11101001 Check if device is ready to CMP #040 ;receive a command. If BSY=0, RDY=1, BNE $4 ;DF=0, DRQ=0, and ERR=0 RTS ;We're good to go. Returns @ 1 Mhz clock ;Xreg = SlotCX, and carry set. $4 LDA #Wait5ms JSR Wait ;Wait 5ms to try again DEY BNE $3 ;Wait up to 1 seconds for drive readiness NotReady JSR Set2Mhz LDA #XCKDEVER ;DEVICE NOT READY error JSR SysErr ;SetupLBA - Programs devices task registers with LBA data ;Input: ; partition data Sect_HB, MB, & LB ; X = requested slot number in form $n0 where ; n = slot 1 to 7 ;This function programs the device registers with ;the ATA Logical Block Address (LBA) to be accessed. ;A SOS block and a ATA sector are both 512 bytes. ;Logical Block Mode, the Logical Block Address is ;interpreted as follows: ; LBA07-LBA00: Sector Number Register D7-D0. ; LBA15-LBA08: Cylinder Low Register D7-D0. ; LBA23-LBA16: Cylinder High Register D7-D0. ; LBA27-LBA24: Drive/Head Register bits HS3-HS0. SetupLBA JSR CkDevice ;returns with carry set LDA Sect_LB STA ATSector,x ;store low block # into LBA 0-7 LDA Sect_MB STA ATSector+1,x ;store mean block # into LBA 15-8 LDA Sect_HB STA ATSector+2,x ;store high block # LBA bits 23-16 LDA Num_Blks STA ATSectCt,x ;store # of blocks to be read/written LDA #000 STA ATdataHB,x TAY RTS IncrAdr INC Count+1 INC Count+1 BumpAdr INC LoBuffer+1 ;increment LoBuffer msb ;Fix up the buffer pointer to correct for an addressing ;anomalies! We just need to do the initial checking ;for two cases: ;00xx bank N -> 80xx bank N-1 ;20xx bank 8F if N was 0 ;FDxx bank N -> 7Dxx bank N+1 FixUp LDA LoBuffer+1 ;look at msb BEQ $1 ;that's one! CMP #0FD ;is it the other one? BCS $2 ;yep. fix it! RTS ;Pointer unchanged, return carry clear. $1 LDA #080 ;00xx -> 80xx STA LoBuffer+1 DEC LoBuffer+ExtPG ;bank N -> band N-1 LDA LoBuffer+ExtPG ;see if it was bank 0 CMP #07F ;(80) before the DEC. BNE $3 ;nope! all fixed. LDA #020 ;if it was, change both STA LoBuffer+1 ;msb of address and LDA #08F STA LoBuffer+ExtPG ;bank number for bank 8F RTS ;return carry set $2 AND #07F ;strip off high bit STA LoBuffer+1 ;FDxx ->7Dxx INC LoBuffer+ExtPG ;bank N -> bank N+1 $3 RTS ;return carry set ; Wait - Copy of Apple's wait routine. ; Input: ;A = delay time, where Delay(us) = 2.5A^2 + 13.5A + 36 ; including JSR to this routine. ;or more typically A = (Delay[in uS]/2.5 - 7.11)^.5 - 2.7 Wait PHP SEI SEC $1 PHA $2 SBC #001 BNE $2 PLA SBC #001 BNE $1 PLP RTS Set1Mhz PHP SEI LDA EReg ORA #080 ;Throttle back to 1 Mhz STA EReg PLP RTS CSet2Mhz CLC Set2Mhz PHP SEI LDA EReg AND #07F ;Throttle up to 2 Mhz STA EReg PLP RTS