From 4483f33637a6ed4760718ef1594b06f3959ff175 Mon Sep 17 00:00:00 2001 From: David Schmidt <1110325+david-schmidt@users.noreply.github.com> Date: Sun, 4 Jul 2021 09:58:17 -0400 Subject: [PATCH] Add Compact Flash/IDE --- build/manifest.json | 9 + drivers/cfideiii/CFIDE.s | 1327 ++++++++++++++++++++++++++++++++++++ drivers/cfideiii/README.md | 336 +++++++++ 3 files changed, 1672 insertions(+) create mode 100644 drivers/cfideiii/CFIDE.s create mode 100644 drivers/cfideiii/README.md diff --git a/build/manifest.json b/build/manifest.json index 2ae43dd..b5c95d8 100644 --- a/build/manifest.json +++ b/build/manifest.json @@ -25,5 +25,14 @@ "asm": "blob/master/src/focus3.s", "sha": "5699c3146c4f8c3577b1cbe1f9b8b726c09e0cfd", "local_asm": "focus3.s" + }, + { + "driver_dib1": ".CFIDE1", + "description": "Apple /// CompactFlash/IDE Driver by Dale S. Jackson 8/08, modified by D Schmenk 8/11", + "dir": "cfideiii", + "repo": "https://www.apple3.org/Software/system/drivers/CFIDE_140A.zip", + "asm": "CFIDE140A.TXT", + "sha": "", + "local_asm": "CFIDE.s" } ] \ No newline at end of file diff --git a/drivers/cfideiii/CFIDE.s b/drivers/cfideiii/CFIDE.s new file mode 100644 index 0000000..ea60663 --- /dev/null +++ b/drivers/cfideiii/CFIDE.s @@ -0,0 +1,1327 @@ +;CF140A +; .TITLE "Apple /// CompactFlash/IDE Driver Ver 1.40A" + ;Limit Maximum Volume Size to 32767 Blocks + +; .PROC CFIDE +; +; SOS Equates +; +ExtPG = $1401 ;driver extended bank address offset +AllocSIR = $1913 ;allocate system internal resource +SELC800 = $1922 ;Enable Expansion Rom Space +DeAlcSIR = $1916 ;de-allocate system internal resource +SysErr = $1928 ;report error to system +EReg = $FFDF ;environment register +ReqCode = $C0 ;request code +SOS_Unit = $C1 ;unit number +SosBuf = $C2 ;SOS buffer pointer +ReqCnt = $C4 ;requested byte count +CtlStat = $C2 ;control/status code +CSList = $C3 ;control/status list pointer +SosBlk = $C6 ;starting block number +QtyRead = $C8 ;bytes read return by D_READ +; +; Our temps in zero page +; +CurPart = $CC ;1 byte +Count = $CD ;2 bytes +Validate = $CE ;1 byte +; +; Parameter block specific to current SOS request +; +ATA_Cmd = $CF +Drv_Parm = $D0 +Sect_HB = $D1 +Sect_MB = $D2 +Sect_LB = $D3 +Num_Blks = $D4 ;2 bytes lb,hb +DataBuf = $D6 ;2 bytes +CurDrive = $D8 ;Current IDE drive number of SOS_Unit # +CurDrvNo = $DA ;Current DIB drive number of SOS_Unit # +; +; SOS Error Codes +; +XREQCODE = $20 ;Invalid request code +XCTLCODE = $21 ;Invalid control/status code +XCTLPARAM = $22 ;Invalid control/status parameter +XNORESRC = $25 ;Resource not available +XBADOP = $26 ;Invalid operation +XIOERROR = $27 ;I/O error +XNODRIVE = $28 ;Drive not connected +XBYTECNT = $2C ;Byte count not a multiple of 512 +XBLKNUM = $2D ;Block number to large +XDCMDERR = $31 ;device command ABORTED error occurred +XCKDEVER = $32 ;Check device readiness routine failed +XNORESET = $33 ;Device reset failed +XNODEVIC = $38 ;Device not connected +; +; IFC I/O locations +; +IFC_ID = $C820 +IOBase = $C080 +ATdataHB = IOBase+$00 +SetCSMsk = IOBase+$01 ;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 = IOBase+$02 ;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 = IOBase+$06 ;when reading (not used) +ATAdCtrl = IOBase+$06 ;when writing +ATdataLB = IOBase+$08 +ATAError = IOBase+$09 +Features = IOBase+$09 +ATSectCt = IOBase+$0a +ATSector = IOBase+$0b ;11=LB,12=MB,13=HB +ATAHead = IOBase+$0e +ATCmdReg = IOBase+$0f ;when writing +ATA_Stat = IOBase+$0f ;when reading +; +; ATA/CF Commands Codes +; +ATA_XErr = $03 +ATACRead = $20 +ATACWrit = $30 +ATA_Vrfy = $40 +ATA_Frmt = $50 +ATA_Diag = $90 +ATAIdent = $EC +SetFeatr = $EF +; +; Constants for Wait +; +Wait5ms = $2a ; 42. +Wait150ms = $f2 ; 242. +; +; Switch Macro +; + .MACRO SWITCH index,bounds,adrs_table,noexec + .IFNBLANK index ; If PARM1 is present, + lda index ; load A with switch index + .ENDIF + .IFNBLANK bounds ; If PARM2 is present, + cmp #bounds+1 ; perform bounds checking + bcs @110 ; on switch index + .ENDIF + asl A ; Multiply by 2 for table index + tay + lda adrs_table+1,y ; Get switch address from table + pha ; and push onto Stack + lda adrs_table,y + pha + .IFBLANK noexec + rts ; Exit to code + .ENDIF +@110: + .ENDMACRO + + .SEGMENT "TEXT" + +; +; Comment Field of driver +; + .WORD $FFFF + .WORD $53 + .byte "Apple /// CFFA Driver - " + .byte "written by Dale S. Jackson 8/08" + .byte ", modified by D Schmenk 8/11" + + .SEGMENT "DATA" + +; +; 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 #0 +; +;------------------------------------ + +DIB_0: .WORD DIB_1 ;link pointer + .WORD Entry ;entry pointer + .BYTE 7 ;name length byte + .byte ".CFIDE1 ";device name +; .BYTE 0C0 ;active, page aligned + .BYTE $80 ;active, no page alignment +DIB0_Slot: + .BYTE $FF ;slot number + .BYTE $00 ;unit number + .BYTE $D1 ;type + .BYTE $10 ;subtype + .BYTE $00 ;filler +DIB0_Blks: + .WORD $0000 ;# blocks in device + .WORD $444A ;manufacturer - DJ + .WORD $140A ;Version 1.40A + .WORD 0003 ;DCB length followed by DCB +Driv_No0: .BYTE $00 ;Drive #, Bit 0=$0 (master) or $1 (slave) + ;Upper 6 bits = Partition address. + ;64 different partition addresses avail. +Part_No0: .BYTE $00 ;Partition number on the drive = $00-07 +FastXfer: .BYTE $00 ;Fast transfer flag +; +; 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 + .byte ".CFIDE2 ";device name + .BYTE $80 ;active + .BYTE $FF ;slot number + .BYTE $01 ;unit number + .BYTE $D1 ;type + .BYTE $10 ;subtype + .BYTE $00 ;filler +DIB1_Blks: + .WORD $0000 ;# blocks in device + .WORD $444A ;manufacturer - DJ + .WORD $140A ;Version 1.40A + .WORD $0002 ;DCB length followed by DCB + .BYTE $00 ;Drive # = $00 (master) or $01 (slave) + ;Upper 6 bits = Partition address. + ;64 different partition addresses avail. + .BYTE $01 ;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 + .byte ".CFIDE3 ";device name + .BYTE $80 ;active + .BYTE $FF ;slot number + .BYTE 002 ;unit number + .BYTE $D1 ;type + .BYTE $10 ;subtype + .BYTE $00 ;filler +DIB2_Blks: + .WORD $0000 ;# blocks in device + .WORD $444A ;manufacturer - DJ + .WORD $140A ;Version 1.40A + .WORD $0002 ;DCB length followed by DCB + .BYTE $00 ;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 + .byte ".CFIDE4 ";device name + .BYTE $80 ;active + .BYTE $FF ;slot number + .BYTE 003 ;unit number + .BYTE $D1 ;type + .BYTE $10 ;subtype + .BYTE $00 ;filler +DIB3_Blks: + .WORD $0000 ;# blocks in device + .WORD $444A ;manufacturer - DJ + .WORD $140A ;Version 1.40A + .WORD $0002 ;DCB length followed by DCB + .BYTE $00 ;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 + .byte ".CFIDE5 ";device name + .BYTE $80 ;active + .BYTE $FF ;slot number + .BYTE 004 ;unit number + .BYTE $D1 ;type + .BYTE $10 ;subtype + .BYTE $00 ;filler +DIB4_Blks: + .WORD $0000 ;# blocks in device + .WORD $444A ;manufacturer - DJ + .WORD $140A ;Version 1.40A + .WORD $0002 ;DCB length followed by DCB + .BYTE $00 ;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 + .byte ".CFIDE6 ";device name + .BYTE $80 ;active + .BYTE $FF ;slot number + .BYTE 005 ;unit number + .BYTE $D1 ;type + .BYTE $10 ;subtype + .BYTE $00 ;filler +DIB5_Blks: + .WORD $0000 ;# blocks in device + .WORD $444A ;manufacturer - DJ + .WORD $140A ;Version 1.40A + .WORD $0002 ;DCB length followed by DCB + .BYTE $00 ;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 + .byte ".CFIDE7 ";device name + .BYTE $80 ;active + .BYTE $FF ;slot number + .BYTE $06 ;unit number + .BYTE $D1 ;type + .BYTE $10 ;subtype + .BYTE $00 ;filler +DIB6_Blks: + .WORD $0000 ;# blocks in device + .WORD $444A ;manufacturer - DJ + .WORD $140A ;Version 1.40A + .WORD $0002 ;DCB length followed by DCB + .BYTE $00 ;Drive # = $00 (master) or $01 (slave) + ;Upper 6 bits = Partition address. + ;64 different partition addresses avail. + .BYTE $06 ;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 + .byte ".CFIDE8 ";device name + .BYTE $80 ;active + .BYTE $FF ;slot number + .BYTE $07 ;unit number + .BYTE $D1 ;type + .BYTE $10 ;subtype + .BYTE $00 ;filler +DIB7_Blks: + .WORD $0000 ;# blocks in device + .WORD $444A ;manufacturer - DJ + .WORD $140A ;Version 1.40A + .WORD $0002 ;DCB length followed by DCB + .BYTE $00 ;Drive # = $00 (master) or $01 (slave) + ;Upper 6 bits = Partition address. + ;64 different partition addresses avail. + .BYTE $07 ;Partition number on the drive = $00-07 + + +;------------------------------------ +; +; Local storage locations +; +;------------------------------------ + +SlotCX: .BYTE $00 ;compute C0X0 and store on init +PtBlkIdx: .BYTE $A3,$A8,$B3,$B8,$C3,$C8,$D3,$D8 ;Offsets to 8 block +PtVolIdx: .BYTE $A6,$AB,$B6,$BB,$C6,$CB,$D6,$DB ;segment for ea partition +UnitStat: .RES $08,$FF ;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: .RES $08,$FF ;last op for D_REPEAT calls +StBlk_HB: .RES $08,$00 ;Starting block number for SOS/ProDos +StBlk_MB: .RES $08,$00 ;vol #0, vol #1, vol #2, vol #3 +StBlk_LB: .RES $08,$00 ;vol #4, vol #5, vol #6, vol #7 +Block_LB: .RES $08,$00 ;Total blocks for each volume # +Block_HB: .RES $08,$00 +DCB_Idx: .BYTE $00 + .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: .RES $05,$00 +SIR_Len = *-SIR_Tbl +PmapCall: .RES $03,$00 ;Block $hb mb lb for partition record + .BYTE $01,$00 ;Read 1 ATA sector (block) lb, hb + .WORD PmapBuf ;Buffer address to place partition record +PmapBuf: .RES $0100,$00 +Err_Data: .RES $0100,$00 +RdBlk1Pr: .WORD RdBlk1 +WrBlk1Pr: .WORD WrBlk1 +RdBlk2Pr: .WORD RdBlk2 +WrBlk2Pr: .WORD WrBlk2 +RdBlk_Proc: + .WORD $0000 +WrBlk_Proc: + .WORD $0000 + +; .byte "Written By Dale S. Jackson, initial writing 12/12/02" +; .byte "v1.40a revised 8/20/11 By Dave Schmenk" + +;------------------------------------ +; +; Driver request handlers +; +;------------------------------------ + +Entry: LDA UnitStat+0 + CMP #XNODEVIC + BEQ No_Drive + LDX SOS_Unit ;get drive number for this unit + LDY DCB_Idx,X + LDA Driv_No0,Y + STA CurDrvNo + AND #$01 ;only bit 0 counts + STA CurDrive ;Set device to LBA mode + ORA #$0E ;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 #$02 ;Status Call + BCS @2 + LDA UnitStat,X ;Check if partition table is current + CMP #$FF + BNE @1 + JSR GetPmap ;fetch it if not. + JSR PInit + LDX SOS_Unit + LDA UnitStat,X +@1: CMP #$10 ;Check if SOS_Unit driver is good. + BCS Err_Out1 +@2: JSR Dispatch ;Now call the dispatcher + LDX SOS_Unit ;Save current operation + LDA ReqCode ;for D_REPEAT processing + STA LastOP,X + RTS +; +; 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. +; +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 +Dispatch: SWITCH ReqCode,9,DoTable ;go do it. +; +; Errors +; +BadReq: LDA #XREQCODE ;bad request code! +Err_Out1: 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 + 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. +; +; 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. +; +DInit: LDA SIR_Tbl + BNE Norm_Out + LDA DIB0_Slot + AND #$07 + ORA #$10 ;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 C0X0 for this slot + ASL A + ASL A + ASL A + ASL A + STA SlotCX + JSR ResetIFC ;Initialization of Device + BCS Slot_Err + LDY #$07 ;Reset drive status to initial startup + LDA #$FF +@1: STA UnitStat,Y + DEY + BPL @1 +Norm_Out: CLC + RTS +; +; D_REPEAT - repeat the last D_READ or D_WRITE call +; +DRepeat: LDX SOS_Unit + LDA LastOP,X ;look at the last thing we did + CMP #$02 + BCS BadOp + STA ReqCode + JMP Dispatch +BadOp: LDA #XBADOP ;invalid operation! + JSR SysErr ;doesn't return +; +; D_READ call processing +; +DRead: JSR CkCnt + LDA #ATACRead + STA ATA_Cmd +CRead: LDA #$00 ;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 ReadExit +@1: JSR FixUp + JSR Read_Blk ;Transfer a block to/from the disk + LDY #$00 + 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 +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 +; +; 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 WriteExit ;quantity to write is zero + JSR FixUp + JSR Write_Blk + BCS IO_Error +WriteExit: + RTS +; +; 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 + BNE @1 + TAY ;Driver Status = $0 always + STA (CSList),Y + RTS +@1: CMP #$01 + BEQ S_Ident + CMP #$02 + BEQ ErrStat + CMP #$03 + BEQ ParTable + CMP #$04 + BEQ DIBinfo + CMP #$FE + BEQ BitMap +CS_Bad: LDA #XCTLCODE ;control/status code no good +Err_Out3: JSR SysErr ;doesn't return +ParTable: JSR GetPmap ;Return partn table of current SOS_Unit + BNE @2 ;Partition map is not valid + LDY #$00 +@1: LDA PmapBuf,Y + STA (CSList),Y + INY + BNE @1 + RTS +@2: JMP No_Drive +ErrStat: LDY #$05 ;Return most recent error data. +@1: LDA Err_Data,y ; Byte 0: Device Status Code + STA (CSList),Y ; Byte 1: Device Error Code + DEY ; (if status ERR bit is 0, error code = 0) + BPL @1 ; Byte 2,3,4: Sector# (LB,MB,HB) of error + CLC ; Byte 5: # of sectors left to xfer + RTS +DIBinfo: LDX SOS_Unit ;Return DIB configuration bytes + LDY DCB_Idx,X + LDA Part_No0,Y ;Get assigned partition number this driver + PHA + LDA Driv_No0,Y ;Get assigned partition map/IDE device + LDY #$00 ;for this driver. + STA (CSList),Y + INY + PLA + STA (CSList),Y + CLC + RTS +BitMap: LDY #$00 ;Return preferred bit map locations. + LDA #$FF ;We return FFFF, don't care + STA (CSList),Y + INY + STA (CSList),Y + CLC + RTS +S_Ident: LDA CSList ;Device Identification + STA DataBuf + LDA CSList+1 + STA DataBuf+1 + LDA CSList+ExtPG + STA DataBuf+ExtPG + LDA #ATAIdent + STA ATA_Cmd +C_Ident: LDA #$01 + STA Num_Blks + LDA #$00 + STA Num_Blks+1 + JMP SRead + +; +; D_CONTROL call processing +; $00 Reset device +; $01 Perform device I/O function with user supplied +; call block. +; $04 Set DIB configuration bytes +; $FE Perform media formatting +; +DControl: LDA CtlStat ;control command + BEQ CReset + CMP #$01 + BEQ UserIO + CMP #$04 + BEQ New_DIB + CMP #$FE ;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 +MFormat: LDX #$07 ;Execute media formatting call. +@1: LDY DCB_Idx,X + LDA Driv_No0,Y + CMP CurDrvNo + BNE @2 + LDA #$FF ;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 +New_DIB: LDX SOS_Unit ;Save new DIB configuration bytes + LDA #$FF ;Invalidate partition table status of driver + STA UnitStat,X + LDY #$00 + LDA (CSList),Y + PHA + INY + LDA (CSList),Y + LDY DCB_Idx,X + STA Part_No0,Y ;Get assigned partition number this driver + PLA + STA Driv_No0,Y ;Get assigned partition map/IDE device + CLC ;for this driver. + RTS +UserIO: LDY #$04 +@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 #$05 + STA QtyRead + LDA CSList+1 + ADC #$00 + STA QtyRead+1 + LDA QtyRead + ADC #$02 + STA DataBuf + LDA QtyRead+1 + ADC #$00 + STA DataBuf+1 + LDA CSList+ExtPG + STA QtyRead+ExtPG + STA DataBuf+ExtPG + LDY #$00 + LDA (CSList),Y + LDY #$06 +@3: CMP CtrlCmds,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 +; +; 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 + +Send_Cmd: JSR CkDevice + LDA #$00 + 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 #$00 + STA (DataBuf),y + JMP CSet2Mhz +; +; Verify - Verify requested blocks +; +Verify: LDA #ATA_Vrfy + JSR SetupLBA ;Program the device's task file registers +@1: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI @1 + LSR A + BCS @2 + JMP Set2Mhz +@2: JMP Save_Err + +;------------------------------------ +; +; Partition Table routines +; +;------------------------------------ + +; +; Get Partition Map from drive +; +GetPmap: LDA CurDrvNo + AND #$FC ;get upper 6 bits of drive number for + STA PmapCall ;partition address. + LDY #$06 +@1: LDA PmapCall,Y + STA Sect_HB,Y + DEY + BPL @1 + LDA #$00 + STA DataBuf+ExtPG + LDA #ATACRead + STA ATA_Cmd + JSR SRead + LDY #$02 ;Compute partition table checksum + LDA #$A5 ;Carry is initially clear +@2: EOR PmapBuf,Y + INY + ADC PmapBuf,Y + INY + BNE @2 + EOR PmapBuf,Y + STA Validate + RTS ;Return Validate=$0 if valid partition +; +; Initialize partition info for each partition in the current table. +; +PInit: LDX #$07 +Next_DIB: LDY DCB_Idx,X + LDA CurDrvNo + CMP Driv_No0,Y + BNE IncDIB_x + LDA Validate + BNE Bad_Drv + LDA Part_No0,Y ;Get assigned partition number for this + CMP #$08 ;driver. + BCS Bad_Drv ;Partition number is out of range + STA CurPart + JSR GVolParm + BCS Bad_Drv + LDY DCB_Idx,X + LDA Block_HB,X + STA DIB0_Blks+1,Y + LDA Block_LB,X + STA DIB0_Blks,Y + LDA CurPart + BPL Good_Drv +Bad_Drv: LDA #XNODRIVE ;Flag this driver not useable +Good_Drv: STA UnitStat,X +IncDIB_x: DEX + BPL Next_DIB + RTS +; +; Get the volume start block in this partition segment +; +GVolParm: LDY CurPart ;Xreg contains DIB unit number + LDA PtBlkIdx,Y + TAY + LDA PmapBuf+2,Y ;Block HB + CMP #$04 ;Test if beginning track is valid + BCS @1 ;Nope! Beginning block larger than 16 mb + ORA PmapCall ;set upper 6 bits for partition address + STA StBlk_HB,X + LDA PmapBuf+1,Y ;Block MB + STA StBlk_MB,X + ORA PmapBuf+2,Y ;Check if beginning track is zero + ORA PmapBuf,Y + BEQ Bad_Vol ;Volume start block can't be zero + LDA PmapBuf,Y ;Block LB + STA StBlk_LB,X + LDY CurPart ;Xreg contains DIB unit number + LDA PtVolIdx,Y ;Get the volume size + TAY + LDA PmapBuf,Y + STA Block_LB,X + ORA PmapBuf+1,Y + BEQ Bad_Vol ;Volume size cannot be zero + LDA PmapBuf+1,Y + STA Block_HB,X + BMI Bad_Vol ;Volume size is greater than 32767 blocks + CLC +@1: RTS +Bad_Vol: SEC + RTS + +;------------------------------------ +; +; Utility routines +; +;------------------------------------ + +; +; 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 DataBuf + LDA SosBuf+1 + STA DataBuf+1 + LDA SosBuf+ExtPG + STA DataBuf+ExtPG + LDY SOS_Unit + LDA SosBlk + CMP Block_LB,y + LDA SosBlk+1 + SBC Block_HB,y + BCS BlkErr + LDA SosBlk + ADC StBlk_LB,y + STA Sect_LB + LDA SosBlk+1 + ADC StBlk_MB,y + STA Sect_MB + LDA StBlk_HB,y + ADC #$00 + STA Sect_HB + RTS +BlkErr: LDA #XBLKNUM + JSR SysErr ;doesn't return +IncrAdr: INC Count+1 + INC Count+1 +BumpAdr: INC DataBuf+1 ;increment DataBuf 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 +; If pointer is adjusted, return with carry set +; +FixUp: LDA DataBuf+1 ;look at msb + BEQ @1 ;that's one! + CMP #$FD ;is it the other one? + BCS @2 ;yep. fix it! + RTS ;Pointer unchanged, return carry clear. +@1: LDA #$80 ;00xx -> 80xx + STA DataBuf+1 + DEC DataBuf+ExtPG ;bank N -> band N-1 + LDA DataBuf+ExtPG ;see if it was bank 0 + CMP #$7F ;(80) before the DEC. + BNE @3 ;nope! all fixed. + LDA #$20 ;if it was, change both + STA DataBuf+1 ;msb of address and + LDA #$8F + STA DataBuf+ExtPG ;bank number for bank 8F + RTS ;return carry set +@2: AND #$7F ;strip off high bit + STA DataBuf+1 ;FDxx ->7Dxx + INC DataBuf+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 #$01 + BNE @2 + PLA + SBC #$01 + BNE @1 + PLP + RTS +; +; Throttle back to 1 MHz +; +Set1Mhz: PHP + SEI + LDA EReg + ORA #$80 + STA EReg + PLP + RTS +; +; Throttle up to 2 MHz +; +CSet2Mhz: CLC +Set2Mhz: PHP + SEI + LDA EReg + AND #$7F + STA EReg + PLP + RTS + +;---------------------------------- +; +; Supplemental Device 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 +; +;---------------------------------- + +; +; Execute reset call to ATA device +; +ResetIFC: JSR Set1Mhz + LDA RdBlk1Pr + STA RdBlk_Proc + LDA RdBlk1Pr+1 + STA RdBlk_Proc+1 + LDA WrBlk1Pr + STA WrBlk_Proc + LDA WrBlk1Pr+1 + STA WrBlk_Proc+1 +; 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 +; TAX +; LDA #000 +; JSR SELC800 ;Turn off ROM +; CPX #015 +; BNE No_Ver2 + LDA FastXfer + BEQ No_Ver2 + LDA RdBlk2Pr + STA RdBlk_Proc + LDA RdBlk2Pr+1 + STA RdBlk_Proc+1 + LDA WrBlk2Pr + STA WrBlk_Proc + LDA WrBlk2Pr+1 + STA WrBlk_Proc+1 +No_Ver2: LDX SlotCX + LDA ClrCSMsk,x ;reset MASK bit in PLD for normal CS0 + LDA #$00 ;signaling. + STA ATdataHB,x ;Clear high byte data latch + LDA #$06 ;Reset bit=1, Disable INTRQ=1 + STA ATAdCtrl,x + JSR Norm_Out ;Per ATA-6 spec, need to wait 5us minimum. + LDA #$02 ;Reset bit=0, Disable INTRQ=1 + STA ATAdCtrl,x + LDY #$d0 ; 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. + SEC ;Drive(s) Not Ready + JMP Set2Mhz +; +; Check Device - test drive status register is readable +; and equal to $40 +; +CkDevice: JSR Set1Mhz + LDY #$c8 ;200. + LDX SlotCX + LDA ClrCSMsk,x ;reset MASK bit in PLD for normal CS0 +@1: LDA ATA_Stat,x ;signaling. + BMI @1 + AND #$08 ;%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 #$c8 ;200. +@3: LDA ATA_Stat,x + BMI @3 + AND #$E9 ;%11101001 Check if device is ready to + CMP #$40 ;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 +; A = command +; 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: PHA + 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 #$00 + STA ATdataHB,x + TAY + PLA + STA ATCmdReg,x ;Issue the command + RTS +; +; Save device error status +; +Save_Err: LDA ATA_Stat,x + STA Err_Data + LSR A + BCS @1 ;if status ERR bit is one then get error + LDA #$00 ;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 +; +; Read_Blk - Read requested blocks from device into memory +; +; +Read_Blk: LDA ATA_Cmd + JSR SetupLBA ;Program the device's task file registers + JMP (RdBlk_Proc) +; +; CFFA Ver 1.x +; +RdBlk1: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI RdBlk1 + AND #$09 ;Check for error response from device + CMP #$08 ;If DRQ=0 or ERR=1 a device error + BNE Read_Err +@1: LDA ATdataLB,x + STA (DataBuf),y + INY + LDA ATdataHB,x + STA (DataBuf),y +@2: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI @2 + INY + BNE @1 + INC DataBuf+1 +@3: LDA ATdataLB,x + STA (DataBuf),y + INY + LDA ATdataHB,x + STA (DataBuf),y +@4: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI @4 + INY + BNE @3 + JSR IncrAdr + DEC Num_Blks ;did we get what was asked for + BNE RdBlk1 + DEC Num_Blks+1 + BPL RdBlk1 + JMP CSet2Mhz +Read_Err: JMP Save_Err +; +; CFFA Ver 2.x +; +RdBlk2: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI RdBlk2 + AND #$09 ;Check for error response from device + CMP #$08 ;If DRQ=0 or ERR=1 a device error + BNE Read_Err +@1: LDA ATdataLB,x + STA (DataBuf),y + INY + LDA ATdataHB,x + STA (DataBuf),y + INY + BNE @1 + INC DataBuf+1 +@2: LDA ATdataLB,x + STA (DataBuf),y + INY + LDA ATdataHB,x + STA (DataBuf),y + INY + BNE @2 + JSR IncrAdr + DEC Num_Blks ;did we get what was asked for + BNE RdBlk2 + DEC Num_Blks+1 + BPL RdBlk2 + JMP CSet2Mhz +; +; Write_Blk - write requested blocks to device from memory +; +Write_Blk: + LDA ATA_Cmd + JSR SetupLBA ;Program the device's task file registers + JMP (WrBlk_Proc) +; +; CFFA Ver 1.x +; +WrBlk1: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI WrBlk1 + AND #$09 ;Check for error response from device + CMP #$01 ;If DRQ=0 and ERR=1 a device error + BEQ Write_Err +@1: LDA SetCSMsk,x ;any access sets mask bit to block + ;IDE -CS0 on I/O read to drive + INY + LDA (DataBuf),y + STA ATdataHB,x + DEY + LDA (DataBuf),y + STA ATdataLB,x + LDA ClrCSMsk,x +@2: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI @2 + INY + INY + BNE @1 + INC DataBuf+1 +@3: LDA SetCSMsk,x + INY + LDA (DataBuf),y + STA ATdataHB,x + DEY + LDA (DataBuf),y + STA ATdataLB,x + LDA ClrCSMsk,x ;Set back to normal, allow CS0 assertions + ;on read cycles +@4: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI @4 + INY + INY + BNE @3 + JSR BumpAdr + DEC Num_Blks ;did we do what was asked for + BNE WrBlk1 + DEC Num_Blks+1 ;we might have to do this one more time + BPL WrBlk1 + LDA ATA_Stat,x ;Wait for BUSY flag to clear + AND #$09 ;Check for error response from device + CMP #$01 ;If DF=1 or DRQ=0 or ERR=1 a device error + BEQ Write_Err + JMP CSet2Mhz ;exit write routines +Write_Err: + JMP Save_Err +; +; CFFA Ver 2.x +; +WrBlk2: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI WrBlk2 + AND #$09 ;Check for error response from device + CMP #$01 ;If DRQ=0 or ERR=1 a device error + BEQ Write_Err + LDA SetCSMsk,x ;any access sets mask bit to block + ;IDE -CS0 on I/O read to drive +@1: INY + LDA (DataBuf),y + STA ATdataHB,x + DEY + LDA (DataBuf),y + STA ATdataLB,x + INY + INY + BNE @1 + INC DataBuf+1 +@2: INY + LDA (DataBuf),y + STA ATdataHB,x + DEY + LDA (DataBuf),y + STA ATdataLB,x + INY + INY + BNE @2 + LDA ClrCSMsk,x ;Set back to normal, allow CS0 assertions + ;on read cycles + JSR BumpAdr + DEC Num_Blks ;did we do what was asked for + BNE WrBlk2 + DEC Num_Blks+1 ;we might have to do this one more time + BPL WrBlk2 +@3: LDA ATA_Stat,x ;Wait for BUSY flag to clear + BMI @3 + AND #$09 ;Check for error response from device + CMP #$01 ;If DF=1 or DRQ=0 or ERR=1 a device error + BEQ Write_Err + JMP CSet2Mhz ;exit write routines diff --git a/drivers/cfideiii/README.md b/drivers/cfideiii/README.md new file mode 100644 index 0000000..5700876 --- /dev/null +++ b/drivers/cfideiii/README.md @@ -0,0 +1,336 @@ +# Apple /// CF/IDE driver + +Features: + * Native Apple /// SOS driver written in 6502 code. + * Up to 8 user definable partitions - up to 16 mb each. + * Can manage up to 2 devices - master & slave. + +Master (device 0) can be either Compactflash memory installed in the built-in +socket on the interface card or a IDE HDD attached to the 40pin IDE connector +and configured as master. + +Slave (device 1) can be either Compactflash (you will need an adapter that +can be connected to a 40pin IDE connector and slave configurable) or an IDE HDD +configured as slave. + +Although any size of device can be attached and successfully used, the +maximum usable capacity is limited to 16,777,215 blocks (8 gig). Each device is +subdivided into 262,144 block partition maps and depending on the size of the +drive, 64 independent partition tables are possible. For example, a device +with a capacity of 2,822,400 blocks (1.4 gig) will have 11 partition maps. The +the first ten partitions (#0 thru 9) are 262,144 blocks long and the 11th (#10) +partition is 200,960 blocks long. + +### Driver Configuration Block (DCB): + +``` +Bytes: 00 01 02 + [Md] [0p] [0t] + d = Device Number, 0 for master, 1 for slave + M = Partition map number, 0 to 63 depending on drive size + + p = Partition Number, 0-7. This is the partition on the + device to use. +``` + +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 +``` + +### CF-IDE Status Requests + +The following list gives the status code and the contents of the status list for +each status request supported. + +Status Code: $00 (Device Status) +Status List: Device Status ($01 bytes) + +Always returns $00 for SOS device status + +Status Code: $01 (Device Identification) +Status List: $0200 Data Buffer + +Copies the device identification data block into the status list data buffer. +This buffer must be 512 bytes long. Refer to the CF/ATA interface specifications +for the format and content of the device identification data. + +Status Code: $02 (Device Error Status) +Status List: Error Data Buffer ($05 bytes) + +Returns 5 bytes of error data from the most recent read/write command that +failed. The format of the error data is as follows: + +``` + Byte 0: Device Error Code + Bit 7 = BBK bad block has been detected + Bit 6 = UNC uncorrectable error was encountered + Bit 5 = 0 (undefined) + Bit 4 = IDNF requested block ID is in error or cannot be found + Bit 3 = 0 (undefined) + Bit 2 = ABRT command was aborted or an invalid command + Bit 1 = 0 (undefined) + Bit 0 = AMNF general error + Byte 1,2,3: Sector Number (LB,MB,HB) that error occurred. + Byte 4: Number of blocks left to complete command +``` +Status Code: $03 (Partition Table Data) +Status List: Partition Data Buffer ($0100 bytes) + +Copies 256 bytes of partition table data to status list buffer. The format of +the partition table is as follows: + +``` + Byte $ 0: Checksum of partition table bytes $02 through $FF (1 byte) + Byte $10: Device serial number (20 ASCII characters) + Byte $24: Device firmware revision number (8 ASCII characters) + Byte $2C: Device model information (40 ASCII characters) + Byte $64: Original partition initialization date (8 ASCII characters) + Byte $6C: Date partition was last modified (8 ASCII characters) + Byte $A3: Partition #1 Start Block (3 bytes) + Byte $A6: Partition #1 Length (3 bytes) + Byte $A8: Partition #2 Start Block (3 bytes) + Byte $AB: Partition #2 Length (3 bytes) + Byte $B3: Partition #3 Start Block (3 bytes) + Byte $B6: Partition #3 Length (3 bytes) + Byte $B8: Partition #4 Start Block (3 bytes) + Byte $BB: Partition #4 Length (3 bytes) + Byte $C3: Partition #5 Start Block (3 bytes) + Byte $C6: Partition #5 Length (3 bytes) + Byte $C8: Partition #6 Start Block (3 bytes) + Byte $CB: Partition #6 Length (3 bytes) + Byte $D3: Partition #7 Start Block (3 bytes) + Byte $D6: Partition #7 Length (3 bytes) + Byte $D8: Partition #8 Start Block (3 bytes) + Byte $DB: Partition #8 Length (3 bytes) +``` + +Status Code: $04 (DIB configuration bytes) +Status List: DIB configuration bytes (2 bytes) + +``` + Byte $00: Drive number, Bit 0 = $0 (master) or $1 (slave) + ;Upper 5 bits = Partition address. + ;32 different partition addresses available + Byte $01: Partition number on the drive = $00-07 +``` +Status Code: $FE (Preferred Bitmap Location) +Status List: Bitmap Initial Block ($02 bytes) + +Always returns $FFFF. + +### CF-IDE Control Requests +The following list gives the control code and the contents of the control list +for each control request supported. + +Control Code: $00 (Reset Device) +Control List: None + +Execute a software reset call to all attached AT devices. + +Control Code: $01 (Device I/O Function) +Control List: None + +Perform device direct I/O function with user supplied call block. The format +of I/O buffer call block is as follows: + +``` + Byte $00: ATA Command Code + Byte $01: Sector Number HB + Byte $02: Sector Number MB + Byte $03: Sector Number LB + Byte $04: Number of sectors ($00=256 sectors) + Byte $05,$06 Bytes returned to buffer (HB,LB) + Byte $07... Data Buffer ($00 to call specific length) +``` +Supported ATA command codes: + +``` + $03 = Extended Error Info - Returns an extended error code for the compact + flash memory card. Data buffer length = 1 byte. + $20 = Sector Read - Reads from 1 to 256 sectors (blocks) as requested + beginning with the sector number specified. Data buffer length = 512 + bytes to 131072 bytes long depending on requested number of sectors. + $30 = Sector Write - Writes from 1 to 256 sectors (blocks) as requested + beginning with the sector number specified. Data buffer length = 512 + bytes to 131072 bytes long depending on requested number of sectors. + $40 = Read verify - Verifies the number of sectors requested beginning with + the sector number specified. Data buffer length = None. + $50 = Sector Format - Formats the specified sector numbers beginning with + sector number specified. Data buffer length = None. + $90 = Internal Diagnostic Test - Performs the device internal diagnostic test. + The diagnostic code is returned in Data Buffer. Data buffer + length = 1 byte. + $EC = Device Identity - Transfers 512 bytes of device identification data. + Format per CF/ATA specs applicable for the device. Data buffer + length = 512 bytes. +``` +Control Code: $04 (Set DIB configuration bytes) +Control List: DIB configuration bytes (2 bytes) + +``` + Byte $00: Drive number, Bit 0 = $0 (master) or $1 (slave), + Upper 5 bits = Partition address, 32 different partition addresses + available (See DIB Values for Map & Drive No. table above) + Byte $01: Partition number on the drive = $00-07 +``` +Control Code: $FE (Media Format) +Control List: None + +Invalidates partition table status flag internal to the driver so subsequent +read/writes will update its partition parameters with the current partition +values on the device. Physically does not perform any format operations. +Use the CF/IDE or System Utilities programs to format the drive or device. + +# Apple /// CF/IDE Utilities Program version 1.26 +Utility program to setup, test, and manage your CompactFlash or IDE drives +attached to the CFFA interface card. + +Features: +1. Can manage up to 2 devices - master & slave for each IFC installed. +2. Test the interface connectivity with the CF or IDE drives attached. +3. Displays identification summary of devices connected - model & serial #, + firmware version, CF command features & logic block capability, & total + block capacity of device. +4. Verify the media of each device. +5. Low Level format of devices with CFA features capability and initialize + partition table. +6. Setup drive partitions, a maximum of 8 drive partitions (up to 16 mb or + 32767 blocks each) per partition table. Up to 64 partition tables are + possible depending on the size of the IDE device. +7. Perform SOS system level formatting of each partition volume. + +## Main Menu +### LIST DEVICES ONLINE +Scans the SOS driver table and lists the drive name of the 1st SOS unitnum for +each CF/IDE device configured and operational. If an IDE drive is connected and +operational but is not configured in the driver then it is not listed. Up to 4 +interface cards are supported or a maximum of 12 devices (2 on each IFC). For +example, if there is only 1 interface card installed with both master +(device #0) and slave (device #1) attached then 2 drives are listed. All +functions of this utility are applicable to the attached devices and not to the +individual SOS drives that may be configured on each device (a maximum +combination of 8 drives is possible). + +### TEST IFC +Commands each device to perform its internal diagnostics. The diagnostic result +displayed will represent the result from both devices attached. All non-pass +diagnostic results for the slave device are preceded with "Slave Failed - " +followed by the appropriate diagnostic error reported. Currently the CFFA card +does not support the "device #1 passed diagnostic signal" from a slave device. +If a slave device is present and both master and slave devices pass the +diagnostics the diagnostic message displayed will always be "Slave Failed - No +Errors Detected" To receive the correct results you will need to connect the +PDIAG signal from pin 34 at the IDE header to pin 46 at the compactflash socket +with a jumper wire. + +Following the internal diagnostic message a summary of the device identification +is displayed for each device configured in the device driver. If 2 devices are +configured, the master device is displayed first followed by the slave device. +If more than 1 device driver is installed (CFFA cards installed in different +slots) then you will be prompted to select which driver to display device +identification. + +The information that is displayed is as follows: +DEVICE NO: Either 0 (master) or 1 (slave) +MODEL NO: 40 character model # information on the device +SERIAL NO: 20 character serial # of the device +FIRMWARE: 8 character firmware revision number +LBA SUPPORT: Logical Block Access supported by this device - Yes or No. This +driver and utility only supports devices with LBA support. +CFA FEATURE: Compactflash feature set support by the device - Yes or No. +If a device supports the CFA feature then low level formatting of the device +media will be permitted. +CAPACITY: The maximum number of usable blocks on the device. If device +capacity exceeds 16777215 blocks then > 16777K is displayed. + +### VERIFY DRIVE +A read verify of all usable blocks on the device is performed. A progress bar +displays the percentage of completion. Any bad blocks reported are displayed +in the active window above the progress bar. The verification can be +halted/resumed at any point through the progress of the verification process. + +### FORMAT DRIVE +OA-F - Low Level Format +If the device supports the CFA Feature Set then a complete low level media +format of all usable block on the device is performed beginning with block $0. +The low level format can be halted/resumed at any point through the progress of +the format process. If the device does not support the CFA Feature Set +(typical of most IDE HDD) all partition tables on the drive are re-formatted +(block $0 of each partition table segment). + +### OA-P - Format a Partition Table +This command will prompt you for a specific partition table number to format +if the size of the drive supports multiple partition tables. + +### PARTITION DRIVE +Edit or assign partitions for each partition table segment on the drive. A +maximum of 8 partitions is allowed on each partition table segment. This +command will prompt you for the specific partition table number to edit if the +size of the drive supports multiple partition tables. The information displayed +is an open edit table of partition information - starting block, Partition +Length, & Volume Name along with a header of device information (model #, slot, +drive, capacity), partition initialization date, last modified date, & remaining +unused blocks. +Starting Block: Acceptable values for starting block is anything from 1 to +262143 or the maximum capacity of the partition segment, whichever is less. +Block 0 is reserved for the partition table. Entering a zero starting block +will be interpreted by the partition editor to assign the next available +starting block. Any change to an existing starting block will result in the +erasure of the existing volume and all of its data for that partition. +Partition Length: Acceptable values for partition length is anything from 0 +to 32767 or the remaining capacity of the partition segment, whichever is less. +Any change to an existing partition length results in the erasure of the +existing volume and all of the data for that partition. +Volume Name: The current SOS formatted volume name on the partition. If a +volume has not been initialized or a change in either the partition starting +block or lengththen "UNFORMATTED" will appear in the volume name column so long +as the partition length is greater than 7 blocks. If the partition length is +less than 8 blocks then "Undefined" will appear in the volume name column. +To initialize or reformat the volume of the partition enter open-apple F or type +in a new name for the volume. This is a high level format routine to initialize +a standard SOS root directory and file control block on the partition. + +### CHANGE DRIVER CONFIGURATION +This function allows you to dynamically change the driver configuration byte +parameters for each of the CFide drivers online. The table of information +presented is the IDE device number (0 or 1), the partition table segment # +(0 thru 63 depending on device capacity) and partition number within the table +segment (0 thru 7). This is different than the actual configuration bytes as +entered with the Apple /// System Utilities SCP program. The changes made here +will remain in affect until you reboot which will reload the drivers from the +SOS.DRIVER file. Permanent changes to the configuration bytes will need to be +done with the Apple /// System Utilities SCP program.