aboutsummaryrefslogtreecommitdiffstats
path: root/tests/t_secdrive/wd1003at.inc
diff options
context:
space:
mode:
Diffstat (limited to 'tests/t_secdrive/wd1003at.inc')
-rw-r--r--tests/t_secdrive/wd1003at.inc952
1 files changed, 952 insertions, 0 deletions
diff --git a/tests/t_secdrive/wd1003at.inc b/tests/t_secdrive/wd1003at.inc
new file mode 100644
index 0000000..7714eec
--- /dev/null
+++ b/tests/t_secdrive/wd1003at.inc
@@ -0,0 +1,952 @@
+;******************************************************************************
+;* *
+;* Includedatei fr SECMAIN.ASM *
+;* liefert low-level-Routinen fr SecMain *
+;* Version hier fr WD1003-kompatible Kontroller: *
+;* MFM, RLL, ESDI, AT-Bus *
+;* *
+;* Historie: 28.12.1994 herberkopiert aus Hauptmodul *
+;* 30.12.1994 LowLevelIdent *
+;* 19. 1.1995 Workaround fr LCS6220 *
+;******************************************************************************
+
+ section wd1003at
+
+Base1 equ 170h ; Basisadresse Task-File
+Base2 equ 370h ; Basisadresse Floppy-Teil
+Task_Data equ Base1+0 ; Datentransferregister (R/W)
+Task_Error equ Base1+1 ; genauerer Fehlercode (R)
+Task_PreComp equ Base1+1 ; erster Zylinder Pr„komp. (/4, nur W)
+Task_SecCnt equ Base1+2 ; Zahl zu transferierender Sektoren (R/W)
+Task_SecNum equ Base1+3 ; Startsektor (R/W)
+Task_CylLo equ Base1+4 ; Startzylinder Bit 0..7 (R/W)
+Task_CylHi equ Base1+5 ; Startzylinder Bit 8..n (R/W)
+Task_DrHead equ Base1+6 ; Laufwerk/Startkopf (R/W)
+Task_Status equ Base1+7 ; Status Laufwerk & Controller (R)
+Task_Command equ Base1+7 ; Kommando Controller (W)
+Task_FDiskReg equ Base2+6 ; Bit 3=1: >8 K”pfe
+
+Cmd_Restore equ 10h ; Kommando: Rekalibrieren
+Cmd_Seek equ 70h ; Kommando: Zylinder anfahren
+Cmd_Read equ 20h ; Kommando: Sektoren lesen
+Cmd_Write equ 30h ; Kommando: Sektoren schreiben
+Cmd_Format equ 50h ; Kommando: Spur formatieren
+Cmd_Verify equ 40h ; Kommando: Sektoren auf Lesbarkeit prfen
+Cmd_Diagnose equ 90h ; Kommando: Selbsttest
+Cmd_SetParams equ 91h ; Kommando: Laufwerksparameter setzen
+
+ proc WriteParams
+
+ mov [axsave],ax
+ mov [cxsave],cx
+ PrChar ' '
+ mov ax,bx
+ mov cl,5
+ call WriteDec
+ PrChar ' '
+ mov al,byte ptr[axsave+1]
+ mov ah,0
+ mov cl,2
+ call WriteDec
+ PrChar ' '
+ mov al,byte ptr[cxsave+1]
+ mov ah,0
+ mov cl,2
+ call WriteDec
+ PrChar ' '
+ mov al,byte ptr[cxsave]
+ mov ah,0
+ mov cl,2
+ call WriteDec
+ PrChar ' '
+ mov ax,es
+ mov cl,4
+ call WriteHex
+ PrChar ':'
+ mov ax,bp
+ mov cl,4
+ call WriteHex
+ mov ax,[axsave]
+ mov cx,[cxsave]
+ ret
+
+cxsave dw ?
+axsave dw ?
+
+ endp
+
+;******************************************************************************
+;* Workaround fr LCS6220: Wird direkt nach dem Einschalten ein Seek ausge- *
+;* fhrt, gibt der Kontroller f„lschlicherweise Daten aus und blockiert alle *
+;* weiteren Kommandos. Diese Routine r„umt einfach den Puffer leer... *
+;******************************************************************************
+
+ proc ClearBuffer
+
+ push dx ; Register retten
+ push ax
+
+RdLoop: mov dx,Task_Status ; Bit 3 noch gesetzt ?
+ in al,dx
+ btst al,3
+ jz RdLoopEnd ; nein --> fertig
+ mov dx,Task_Data
+ in ax,dx
+ jmp RdLoop
+RdLoopEnd:
+ pop ax ; Register zurck
+ pop dx
+
+ ret
+
+ endp
+
+;******************************************************************************
+;* Interleave-Tabelle berechnen *
+;* In : AL = Sektorzahl *
+;* AH = Interleave *
+;* DH = Bad-Flag *
+;******************************************************************************
+
+ proc SetInterleaveBuffer
+
+ pusha ; Register retten
+ push es
+
+ push ax ; Sektorpuffer initialisieren
+ mov ax,ds
+ mov es,ax
+ sub ax,ax
+ lea di,[SectorBuffer]
+ mov cx,SecSize/2
+ cld
+ rep stosw
+ pop ax
+
+ sub di,di ; DI=Adresse in Puffer=(phys. Sektor-1)*2
+ mov dl,dh ; DL = Bad-Flag
+ mov dh,1 ; DH=log. Sektornummer
+ mov cl,al ; CX=Schleifenz„hler
+ mov ch,0
+ mov bl,al ; Sektorzahl*2 nach BX
+ mov bh,0
+ add bx,bx
+ mov si,ax ; Interleave*2 nach SI
+ shr si,8
+ add si,si
+InterLoop: cmp byte ptr SectorBuffer[di],0 ; Eintrag frei ?
+ je Inter_FreeFound ; ja, beenden
+ add di,2 ; nein, linear weitersuchen
+ cmp di,bx
+ jb InterLoop
+ mov di,0 ; Wrap-Around bercksichtigen
+ jmp InterLoop
+Inter_FreeFound:mov word ptr SectorBuffer[di],dx ; Sektor einschreiben
+ add di,si ; Interleave-Sprung dazu
+ cmp di,bx ; Modulo Sektorzahl
+ jb Inter_NoWrap
+ sub di,bx
+Inter_NoWrap: inc dh ; n„chster log. Sektor
+ loop InterLoop
+
+ pop es ; Register zurck
+ popa
+
+ ret
+
+ endp
+
+;******************************************************************************
+;* Laufwerk und Sonderwerte einprogrammieren *
+;* In : AL = Laufwerk *
+;* AH = Kopf *
+;******************************************************************************
+
+ proc SetDriveEnv
+
+ push di ; Register retten
+ push dx
+ mov dx,ax ; Laufwerk/Kopf retten
+
+ call GetPTabAdr ; Tabellenadresse holen
+
+ mov al,dl ; Laufwerk und Kopf zusammenbauen
+ shl al,4
+ or al,dh
+ or al,0a0h
+ mov dx,Task_DrHead
+ out dx,al
+ mov ax,[di+DrPar_PrComp] ; Startzylinder Pr„kompensation
+ shr ax,2
+ mov dl,Lo(Task_PreComp)
+ out dx,al
+ mov al,[di+DrPar_CByte] ; Wert fr Fixed Disk Register
+ mov dx,Task_FDiskReg
+ out dx,al
+ call WaitBusy
+
+ clc ; Ende ohne Fehler
+ pop dx
+ pop di
+ ret
+
+ endp
+
+;******************************************************************************
+;* Zylinder- und Sektorparameter an Kontroller ausgeben *
+;* In : BX = Startzylinder *
+;* CL = Sektorzahl *
+;* CH = Startsektor *
+;******************************************************************************
+
+ proc SetTransParams
+
+ push dx ; Register retten
+
+ mov dx,Task_CylLo ; Startzylinder programmieren
+ mov al,bl
+ out dx,al
+ mov dx,Task_CylHi ;***
+ mov al,bh
+ out dx,al
+ mov dx,Task_SecNum ; Startsektor... ;***
+ mov al,ch
+ out dx,al
+ mov dx,Task_SecCnt ; ...und Sektorzahl ;***
+ mov al,cl
+ out dx,al
+
+ pop dx ; Register zurck
+ ret
+
+ endp
+
+;******************************************************************************
+;* warten, bis Controller bereit oder Fehler *
+;* Out : AL = letzter Status *
+;******************************************************************************
+
+ proc WaitBusy
+
+ push dx ; Register retten
+ mov dx,Task_Status ; auf Statusregister
+Loop: in al,dx ; Status lesen
+ btst al,7 ; Bit 7 noch gesetzt ?
+ jnz Loop ; ja--> weiter pollen
+ pop dx ; Register zurck
+ ret
+
+ endp
+
+;******************************************************************************
+;* warten, bis Laufwerk bereit *
+;* Out : AL = letzter Status *
+;******************************************************************************
+
+ proc WaitDrive
+
+ push dx ; Register retten
+ mov dx,Task_Status ; auf Statusregister
+Loop: in al,dx ; Status lesen
+ btst al,7 ; Bit 7 = 0 ? ( Controller Busy )
+ jnz Loop
+ btst al,6 ; Bit 6 = 1 ? ( Drive not Ready )
+ jz Loop
+ btst al,4 ; Bit 4 = 1 ? ( Seek not complete )
+ jz Loop
+ pop dx
+ ret
+
+ endp
+
+;******************************************************************************
+;* warten, bis Datentransfer erforderlich *
+;* Out : AL = letzter Status *
+;* C = 1, falls Fehler *
+;******************************************************************************
+
+ proc WaitData
+
+ push dx ; Register retten
+ mov dx,Task_Status ; auf Statusregister
+Loop: in al,dx ; Status lesen
+ btst al,7 ; Bit 7 = 0 ?
+ jnz Loop
+ btst al,3 ; Bit 3 = 1 ?
+ jz Loop
+ pop dx ; Register zurck
+ ret
+
+ endp
+
+;******************************************************************************
+;* Status bilden *
+;* Out : C+AX = Status *
+;******************************************************************************
+
+ proc BuildError
+
+ push dx ; Register retten
+
+ mov dx,Task_Status ; Statusregister lesen
+ in al,dx
+ mov ah,al
+ btst ah,0 ; Fehlerflag gesetzt ?
+ clc
+ jz End ; kein Fehler
+
+ mov dx,Task_Error ; ja: Error-Register lesen ;***
+ in al,dx
+ stc
+
+End: pop dx ; Register zurck
+ ret
+
+ endp
+
+;******************************************************************************
+;* Begráungsmeldung ausgeben: *
+;******************************************************************************
+
+ globproc LowLevelIdent
+
+ push ax ; Register retten
+
+ PrMsg IdentMsg
+
+ pop ax
+
+ ret
+
+IdentMsg db "Low-Level-Routinen fr WD1003-WAH und kompatible Controller",CR,LF,'$'
+
+ endp
+
+;******************************************************************************
+;* Controller-Diagnose: *
+;* Out : AL = Diagnosecode *
+;******************************************************************************
+
+ globproc ContDiag
+
+ push cx ; Register retten
+ push dx
+
+ mov dx,Task_Status ; das erste Mal mit Timeout warten
+ sub cx,cx
+BWait: in al,dx
+ btst al,7 ; auf NOT BUSY warten
+ loopnz BWait ; oder bis 64K Durchl„ufe durch
+ or cx,cx ; Timeout ?
+ jne NTOut
+ mov al,Diag_Timeout ; ja: Fehlercode setzen...
+ jmp End ; ...und Feierabend
+
+NTOut: mov al,CMD_Diagnose ; Selbsttest starten
+ mov dl,Lo(Task_Command)
+ out dx,al
+ call WaitBusy ; auf Fertigstellung warten
+ mov dl,Lo(Task_Error) ; Ergebnis laden
+ in al,dx
+
+End: pop dx ; Register zurck
+ pop cx
+ ret
+
+ endp
+
+;******************************************************************************
+;* Dem Kontroller die Laufwerksgeometrie mitteilen *
+;* In : AL = Laufwerk *
+;* Out : C = 1-->Fehler *
+;******************************************************************************
+
+ globproc SetDriveParams
+
+ push di ; Register retten
+ push dx
+ mov dl,al ; Laufwerk retten
+
+ call GetPTabAdr ; Adresse Parametertabelle holen
+
+ call WaitBusy ; Kontroller muá frei sein
+
+ mov al,dl ; Kopfzahl/Laufwerk vorbesetzen
+ shl al,4
+ mov ah,[di+DrPar_Heads]
+ dec ah ; Maximalnummer anstelle Gesamtzahl
+ or al,ah
+ or al,0a0h
+ mov dx,Task_DrHead
+ out dx,al
+ mov dl,Lo(Task_SecCnt) ; Sektorzahl setzen
+ mov al,[di+DrPar_NSecs]
+ out dx,al
+
+ mov dl,Lo(Task_Command) ; Parameter bertragen
+ mov al,Cmd_SetParams
+ out dx,al
+
+ call WaitBusy ; auf Fertigstellung warten
+
+ clc ; Ende ohne Fehler
+ pop dx
+ pop di
+ ret
+
+ endp
+
+;******************************************************************************
+;* Laufwerk rekalibrieren, gleichzeitig Test, ob vorhanden *
+;* In : AL = Laufwerk *
+;* Out : C + AX = Status *
+;******************************************************************************
+
+ globproc Recalibrate
+
+ push cx ; Register retten
+ push dx
+
+ mov cx,ax ; Laufwerk retten
+ call WaitBusy ; warten, bis Controller frei
+
+ mov dx,Task_DrHead ; Laufwerk eintragen
+ mov al,cl
+ shl al,4
+ add al,0a0h
+ out dx,al
+
+ mov dl,Lo(Task_Status) ; Laufwerk muss jetzt bereit sein,
+ in al,dx ; da sich einige Kontroller sonst im
+ and al,50h ; folgenden aufh„ngen, falls
+ cmp al,50h ; keine Platte angeschlossen ist.
+ stc ; falls nicht bereit, Fehler simulieren
+ mov al,4 ; "Aborted Command"
+ jne TotEnde
+ mov al,0
+ mov dl,Lo(Task_CylLo) ; erstmal auf die sanfte Tour:
+ out dx,al ; Spur 0 anfahren
+ mov dl,Lo(Task_CylHi)
+ out dx,al
+ mov dl,Lo(Task_Command)
+ mov al,Cmd_Seek
+ out dx,al
+ call WaitBusy
+ call BuildError
+ jnc Ende ; wenn OK: fertig
+
+ call ClearBuffer ; falls sich der Longshine verheddert...
+ mov dl,Lo(Task_Command) ; 2. Anlauf: echtes Restore
+ mov al,Cmd_Restore
+ out dx,al
+
+ call WaitBusy ; auf Controller warten
+
+Ende: call BuildError ; Status einlesen
+TotEnde:
+ pop dx ; Register zurck
+ pop cx
+ ret
+
+ endp
+
+;******************************************************************************
+;* Sektor(en) lesen *
+;* In : AL = Laufwerk *
+;* AH = Startkopf *
+;* BX = Startzylinder *
+;* CL = Sektorzahl *
+;* CH = Startsektor *
+;* ES:DI = Zeiger auf Datenpuffer *
+;* Out : C+AX = Fehlerstatus *
+;******************************************************************************
+
+ globproc ReadSectors
+
+ push si ; Register sichern
+ push dx
+ push bp
+
+ if debug
+ PrChar 'R'
+ mov bp,di
+ call WriteParams
+ endif
+
+ sub bp,bp ; Fehlerz„hler auf 0
+
+Retry: push ax ; Parameter sichern
+ push bx
+ push cx
+ push di
+
+ mov si,ax ; Laufwerk/Kopf retten
+ call WaitBusy ; warten, bis Ruhe im Wald
+
+ mov ax,si
+ call SetDriveEnv ; Laufwerk jetzt schon setzen, damit
+ ; korr. Ready-Signal abgefragt wird
+ call WaitDrive ; bis Laufwerk bereit
+
+ call SetTransParams ; restliche Parameter ausgeben
+
+ mov ch,0 ; Sektorzahl nach SI
+ mov si,cx
+ mov dx,Task_Command ; Kommando triggern
+ mov al,Cmd_Read
+ out dx,al
+
+ mov dx,Task_Data ; Vorbereitung fr INSW
+ cld
+Loop: call WaitBusy ; auf gelesenen Sektor warten
+ btst al,0 ; Fehler ?
+ jnz Again ; -->neu aufsetzen
+ call WaitData
+ btst al,0
+ jnz Again
+ call WaitDrive
+ btst al,0
+ jnz Again
+ mov cx,SecSize/2 ; Daten transferieren
+ rep insw ; bagger, schaufel
+ dec si ; n„chster Sektor
+ jnz Loop
+
+End: pop di ; Parameter nicht mehr gebraucht
+ pop cx
+ pop bx
+ pop ax
+Term: if debug
+ PrChar CR
+ PrChar LF
+ endif
+ call BuildError
+ pop bp
+ pop dx
+ pop si
+
+ ret
+
+Again: inc bp ; Fehlerz„hler rauf
+ cmp bp,MaxRetry ; zu oft aufgetreten ?
+ jae End
+
+ pop di ; nein: Parameter vom Stack
+ pop cx
+ pop bx
+ pop ax
+ mov si,ax ; Laufwerk retten
+ call Recalibrate ; auf Spur 0 zurck
+ jc Term ; bei erneutem Fehler Abbruch
+ mov ax,si
+ call SetDriveParams ; Parameter neu initialisieren
+ mov ax,si
+ jmp Retry ; neuer Versuch
+
+
+ endp
+
+;******************************************************************************
+;* Sektor(en) verifizieren *
+;* In : AL = Laufwerk *
+;* AH = Startkopf *
+;* BX = Startzylinder *
+;* CL = Sektorzahl *
+;* CH = Startsektor *
+;* Out : C+AX = Fehlerstatus *
+;******************************************************************************
+
+ globproc VeriSectors
+
+ push si ; Register sichern
+ push dx
+ push bp
+
+ if debug
+ PrChar 'V'
+ mov bp,0
+ call WriteParams
+ endif
+
+ sub bp,bp ; Fehlerz„hler auf 0
+
+Retry: push ax ; Parameter sichern
+ push bx
+ push cx
+
+ mov si,ax ; Laufwerk/Kopf retten
+ call WaitBusy ; warten, bis Ruhe im Wald
+
+ mov ax,si
+ call SetDriveEnv ; Laufwerk jetzt schon setzen, damit
+ ; korr. Ready-Signal abgefragt wird
+ call WaitDrive ; bis Laufwerk bereit
+
+ call SetTransParams ; restliche Parameter ausgeben
+
+ mov dx,Task_Command ; Kommando triggern
+ mov al,Cmd_Verify
+ out dx,al
+
+ call WaitBusy ; auf Fertigstellung warten
+ mov cx,16 ; einige Kontroller brauchen
+DelStat: loop DelStat ; etwas fr das Fehlerflag
+ mov dx,Task_Status
+ in al,dx
+ btst al,0 ; Fehler ?
+ jnz Again ; -->neu aufsetzen
+ call WaitDrive
+ btst al,0
+ jnz Again
+
+Ende: pop cx ; Parameter nicht mehr gebraucht
+ pop bx
+ pop ax
+Term: if debug
+ PrChar CR
+ PrChar LF
+ endif
+ call BuildError
+ pop bp
+ pop dx
+ pop si
+
+ ret
+
+Again: inc bp ; Fehlerz„hler rauf
+ cmp bp,MaxRetry ; zu oft aufgetreten ?
+ jae Ende
+
+ pop cx ; nein: Parameter vom Stack
+ pop bx
+ pop ax
+ mov si,ax ; Laufwerk retten
+ call Recalibrate ; auf Spur 0 zurck
+ jc Term ; bei erneutem Fehler Abbruch
+ mov ax,si
+ call SetDriveParams ; Parameter neu initialisieren
+ mov ax,si
+ jmp Retry ; neuer Versuch
+ mov ax,si
+ endp
+
+;******************************************************************************
+;* Sektor(en) schreiben *
+;* In : AL = Laufwerk *
+;* AH = Startkopf *
+;* BX = Startzylinder *
+;* CL = Sektorzahl *
+;* CH = Startsektor *
+;* ES:SI = Zeiger auf Datenpuffer *
+;* Out : C+AX = Fehlerstatus *
+;******************************************************************************
+
+ globproc WriteSectors
+
+ push di ; Register sichern
+ push dx
+ push bp
+
+ if debug
+ PrChar 'W'
+ mov bp,si
+ call WriteParams
+ endif
+
+ xor bp,bp ; Fehlerz„hler auf 0
+
+Retry: push ax ; Parameter sichern
+ push bx
+ push cx
+ push si
+
+ mov di,ax ; Laufwerk/Kopf retten
+ call WaitBusy ; warten, bis Ruhe im Wald
+
+ mov ax,di
+ call SetDriveEnv ; Laufwerk jetzt schon setzen, damit
+ ; korr. Ready-Signal abgefragt wird
+ call WaitDrive ; bis Laufwerk bereit
+
+ call SetTransParams ; restliche Parameter ausgeben
+
+ mov ch,0 ; Sektorzahl nach DI
+ mov di,cx
+ mov dx,Task_Command ; Kommando triggern
+ mov al,Cmd_Write
+ out dx,al
+
+ mov dx,Task_Data ; Vorbereitung fr OUTSW
+ cld
+Loop: call WaitBusy ; auf Datenbereitschaft warten
+ btst al,0 ; Fehler ?
+ jnz Again ; ja-->neu aufsetzen
+ call WaitData
+ btst al,0
+ jnz Again
+ call WaitDrive
+ btst al,0
+ jnz Again
+ mov cx,SecSize/2 ; Daten transferieren
+ seges
+ rep outsw ; bagger, schaufel
+ call WaitBusy ; warten, bis Transfer fertig
+ btst al,0
+ jnz Again
+ dec di ; n„chster Sektor
+ jnz Loop
+
+End: pop si ; Parameter nicht mehr gebraucht
+ pop cx
+ pop bx
+ pop ax
+Term: if debug
+ PrChar CR
+ PrChar LF
+ endif
+ call BuildError
+ pop bp
+ pop dx
+ pop di
+
+ ret
+
+Again: inc bp ; Fehlerz„hler rauf
+ cmp bp,MaxRetry ; zu oft aufgetreten ?
+ jae End
+
+ pop si ; nein: Parameter vom Stack
+ pop cx
+ pop bx
+ pop ax
+ mov di,ax ; Laufwerk retten
+ call Recalibrate ; auf Spur 0 zurck
+ jc Term ; bei erneutem Fehler Abbruch
+ mov ax,di
+ call SetDriveParams ; Parameter neu initialisieren
+ mov ax,di
+ jmp Retry ; neuer Versuch
+
+ endp
+
+;******************************************************************************
+;* Laufwerk formatieren *
+;* In : AL = Laufwerk *
+;* AH = Interleave *
+;* Out : C+AX = Fehlerstatus *
+;******************************************************************************
+
+ globproc FormatUnit
+
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+ push bp
+
+ mov bx,ax ; Interleave retten
+ PrMsg ESCMsg
+ mov ax,bx
+ call GetPTabAdr ; Parametertabelle->DI
+ mov ax,bx
+ mov dh,0 ; gute Spuren schreiben
+ mov al,[di+DrPar_NSecs]
+ call SetInterleaveBuffer ; Tabelle berechnen
+ mov ax,bx
+ call Recalibrate ; Kontroller reinitialisieren
+ jc Fin
+ mov ax,bx
+ mov bp,[di+DrPar_Cyls] ; Zylinderz„hler in BP (abw„rts)
+ dec bp
+ mov dl,al ; Laufwerk in DL
+ cld
+CylLoop: mov dh,0 ; Kopf in dh
+HeadLoop: call WaitBusy ; warten, bis WD1003 frei
+ call WriteCoords ; Bildschirmausgabe
+ mov ax,dx ; Laufwerk+Kopf progr.
+ call SetDriveEnv
+ mov bx,bp ; Zylinder+Sektor progr.
+ mov cl,[di+DrPar_NSecs]
+ mov ch,1
+ call SetTransParams
+ mov bx,dx
+ mov dx,Task_Command
+ mov al,Cmd_Format
+ out dx,al
+ call WaitData ; Sektortabelle schicken
+ mov cx,SecSize/2
+ mov dx,Task_Data
+ lea si,[SectorBuffer]
+ rep outsw
+ call WaitBusy ; warten, bis Kontroller fertig
+ shr al,1 ; Fehlerbit in Carry laden
+ jnc GoOn
+ PrMsg ErrorMsg ; falls Fehler, Meldung ausgeben
+ mov dx,bx
+ call WriteCoords
+ PrChar LF
+GoOn: mov dx,bx ; Laufwerk und Kopf zurck
+ call BreakOnESC ; will der Benutzer abbrechen ?
+ jc UserTerm ; ja, Abbruch
+ inc dh ; n„chster Kopf
+ cmp dh,[di+DrPar_Heads]
+ jb HeadLoop
+ dec bp ; n„chster Zylinder
+ jns CylLoop
+TermLoop: mov al,dl ; damit die Seek-Rate wieder stimmt
+ call Recalibrate
+
+Fin: push ax ; Fehlerstatus halten
+ pushf
+ PrChar LF
+ popf ; Fehlerstatus zurck
+ pop ax
+ pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ ret
+
+UserTerm: mov al,dl ; Abbruch durch Benutzer: noch schnell
+ call Recalibrate ; rekalibrieren
+ jc Fin ; Fehler dabei ?
+ stc ; Ansonsten Sonderfehlercode
+ mov al,DErr_UserTerm
+ jmp Fin
+
+WriteCoords: push ax ; Kopf/Zylinder ausgeben
+ push cx
+
+ PrMsg CylMsg
+ mov ax,bp
+ mov cl,6
+ call WriteDec
+ PrMsg HeadMsg
+ mov al,dh
+ mov ah,0
+ mov cl,3
+ call WriteDec
+ PrChar CR
+
+ pop cx
+ pop ax
+ ret
+
+ESCMsg: db "Abbruch mit <ESC>",CR,LF,'$'
+CylMsg: db "Zylinder $"
+HeadMsg: db ", Kopf $"
+ErrorMsg: db "Formatierfehler auf $"
+
+ endp
+
+;******************************************************************************
+;* Spur formatieren *
+;* In : AL = Laufwerk *
+;* AH = Kopf *
+;* BX = Zylinder *
+;* CL = Interleave *
+;* Out : C+AX = Fehlerstatus *
+;******************************************************************************
+
+ globproc FormatTrack
+
+ push bx ; Register retten
+ push cx
+ push dx
+ push si
+ push di
+ push bp
+
+ mov bp,ax ; Laufwerk & Kopf retten
+ call Recalibrate ; Laufwerk sicherheitshalber rekalibrieren
+ mov ax,bp
+ call GetPTabAdr ; Sektortabelle aufbauen
+ mov dh,0 ; fehlerhafte Sektoren schreiben
+ mov ah,cl ; Interleave vorgeben
+ mov al,[di+DrPar_NSecs]
+ call SetInterleaveBuffer
+ mov ax,bp ; Laufwerk und Kopf zurck
+ call SetDriveEnv ; in Kontroller einprogrammieren
+ mov cl,[di+DrPar_NSecs] ; Sektor& Zylinder einschreiben
+ mov ch,1
+ call SetTransParams
+ mov dx,Task_Command ; Kommando schicken
+ mov al,Cmd_Format
+ out dx,al
+ call WaitData ; Sektortabelle schicken
+ mov cx,SecSize/2
+ mov dx,Task_Data
+ lea si,[SectorBuffer]
+ rep outsw
+ call WaitBusy ; warten, bis Kontroller fertig
+ jc Fin ; Abbruch bei Fehler
+ mov ax,bp ; Laufwerk nochmal rekalibrieren
+ call Recalibrate ; damit Steprate stimmt
+
+Fin: pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ ret
+
+ endp
+
+;******************************************************************************
+;* Spur als defekt markieren *
+;* In : AL = Laufwerk *
+;* AH = Kopf *
+;* BX = Zylinder *
+;* Out : C+AX = Fehlerstatus *
+;******************************************************************************
+
+ globproc MarkBad
+
+ push bx ; Register retten
+ push cx
+ push dx
+ push si
+ push di
+ push bp
+
+ mov bp,ax ; Laufwerk & Kopf retten
+ call Recalibrate ; Laufwerk sicherheitshalber rekalibrieren
+ mov ax,bp
+ call GetPTabAdr ;Sektortabelle aufbauen
+ mov dh,80h ; fehlerhafte Sektoren schreiben
+ mov ah,3 ; Interleave ist ziemlich egal...
+ mov al,[di+DrPar_NSecs]
+ call SetInterleaveBuffer
+ mov ax,bp ; Laufwerk und Kopf zurck
+ call SetDriveEnv ; in Kontroller einprogrammieren
+ mov cl,[di+DrPar_NSecs] ; Sektor& Zylinder einschreiben
+ mov ch,1
+ call SetTransParams
+ mov dx,Task_Command ; Kommando schicken
+ mov al,Cmd_Format
+ out dx,al
+ call WaitData ; Sektortabelle schicken
+ mov cx,SecSize/2
+ mov dx,Task_Data
+ lea si,[SectorBuffer]
+ rep outsw
+ call WaitBusy ; warten, bis Kontroller fertig
+ jc Fin ; Abbruch bei Fehler
+ mov ax,bp ; Laufwerk nochmal rekalibrieren
+ call Recalibrate ; damit Steprate stimmt
+
+Fin: pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ ret
+
+ endp
+
+ endsection