aboutsummaryrefslogtreecommitdiffstats
path: root/tests/t_secdrive/t_secdrive.asm
diff options
context:
space:
mode:
Diffstat (limited to 'tests/t_secdrive/t_secdrive.asm')
-rw-r--r--tests/t_secdrive/t_secdrive.asm1476
1 files changed, 1476 insertions, 0 deletions
diff --git a/tests/t_secdrive/t_secdrive.asm b/tests/t_secdrive/t_secdrive.asm
new file mode 100644
index 0000000..4fc82c9
--- /dev/null
+++ b/tests/t_secdrive/t_secdrive.asm
@@ -0,0 +1,1476 @@
+;******************************************************************************
+;* *
+;* SECDRIVE - Treiber fr einen 2. HD-Kontroller im PC *
+;* *
+;* Historie: 12. 8.1993 Grundsteinlegung, Definitionen *
+;* 16. 8.1993 Dispatcher *
+;* Basislesefunktionen *
+;* 17. 8.1993 Partitionsinformationen zusammenkratzen *
+;* 18. 8.1993 Laufwerksparameter initialisieren *
+;* 19. 8.1993 Zylinder/Sektorregister setzen *
+;* Partitiossektorbaum durchgehen *
+;* 24. 8.1993 BPB aufbauen *
+;* 25. 8.1993 Parameterbersetzung *
+;* Einlesen *
+;* Sektoren schreiben *
+;* 26. 8.1993 Fehlerbehandlung *
+;* Verify *
+;* 1. Restore-Versuch mit Seek *
+;* 7. 9.1993 Versuch Version 1.39 mit Proc's *
+;* 28. 9.1993 etwas gekrzt *
+;* 27.12.1994 leichte Korrekturen im Restore *
+;* 28.12.1994 Trennung Low-Level-Routinen begonnen *
+;* 19. 1.1995 Fehlermeldungen im Klartext *
+;* *
+;******************************************************************************
+
+;******************************************************************************
+;* globale Definitionen *
+;******************************************************************************
+
+; A C H T U N G : Mono.SYS muá fr Debugging geladen sein !!!!
+
+debug equ 0
+debug2 equ 0
+
+ include bitfuncs.inc
+
+ cpu 80186 ; WD 1003 fordert min. 80286
+
+Diag_NoError equ 01h ; Selbstdiagnosecodes: kein Fehler
+Diag_ContError equ 02h ; Controller-Fehler
+Diag_SBufError equ 03h ; Sektorpuffer defekt
+Diag_ECCError equ 04h ; Fehlerkorrektor defekt
+Diag_ProcError equ 05h ; Steuerprozessor defekt
+Diag_Timeout equ 06h ; Controller antwortet nicht
+
+ParTab struct
+BFlag db ? ; Partitionseintrag: Partition aktiv ?
+FHead db ? ; Startkopf
+FSecCyl dw ? ; Startzylinder/sektor
+Type db ? ; Partitionstyp
+LHead db ? ; Endkopf
+LSecCyl dw ? ; Endzylinder/sektor
+LinSec dd ? ; Anzahl Sektoren
+NSecs dd ? ; linearer Startsektor
+ endstruct
+
+DErr_WrProtect equ 00h ; Treiberfehlercodes: Schreibschutz
+DErr_InvUnit equ 01h ; unbekannte Ger„tenummer
+DErr_NotReady equ 02h ; Laufwerk nicht bereit
+DErr_Unknown equ 03h ; Unbekannes Treiberkommando
+DErr_CRCError equ 04h ; Prfsummenfehler
+DErr_InvBlock equ 05h ; ungltiger Request-Header
+DErr_TrkNotFnd equ 06h ; Spur nicht gefunden
+DErr_InvMedia equ 07h ; Unbekanntes Tr„gerformat
+DErr_SecNotFnd equ 08h ; Sektor nicht gefunden
+DErr_PaperEnd equ 09h ; Papierende im Drucker
+DErr_WrError equ 0ah ; allg. Schreibfehler
+DErr_RdError equ 0bh ; allg. Schreibfehler
+DErr_GenFail equ 0ch ; allg. Fehler
+DErr_InvChange equ 0fh ; unerlaubter Diskettenwechsel
+
+DErr_UserTerm equ 0ffh ; Fehlercode Abbruch durch Benutzer
+
+SecSize equ 512 ; SektorgrӇe in Bytes
+MaxPDrives equ 2 ; Maximalzahl physikalischer Laufwerke
+MaxDrives equ 10 ; Maximalzahl verwaltbarer Laufwerke
+MaxParts equ 4 ; Maximalzahl Partitionen in einem Sektor
+MaxRetry equ 2 ; max. 2 Lese/Schreibversuche
+StackSize equ 512 ; etwas mehr wg. Rekursion
+
+DrPar_Offset equ 1aeh ; Offset Parametertabelle im Part.-Sektor
+ParTab_Offset equ 1beh ; Offset Partitionstabelle " " "
+ParSecID_Offset equ 1feh ; Offset Partitionssektorflag (55aa)
+BPBOfs equ 11 ; Offset BPB im Bootsektor
+
+INT_DOS equ 21h ; DOS-Funktionsaufruf
+INT_Mono equ 60h ; Haken zum VT100-Treiber
+INT_Clock equ 1ah ; BIOS-Uhreneinstieg
+INT_Keyboard equ 16h ; BIOS-Tastatureinstieg
+
+DOS_WrString equ 9 ; DOS-Funktionen
+DOS_WrChar equ 6
+DOS_RdString equ 10
+DOS_RdChar equ 8
+
+HD_ID equ 0f8h ; Media-ID fr Festplatten
+
+CR equ 13
+LF equ 10
+BEL equ 7
+ESC equ 27
+
+;******************************************************************************
+; Makros *
+;******************************************************************************
+
+;jmp macro adr
+; !jmp long adr
+; endm
+
+beep macro
+ push ax
+ mov ax,0e07h
+ int 10h
+ pop ax
+ endm
+
+PrMsg macro Adr ; Meldung ausgeben
+ push dx ; Register retten
+ lea dx,[Adr]
+ mov ah,DOS_WrString
+ int INT_DOS
+ pop dx ; Register zurck
+ endm
+
+PrChar macro Zeichen ; Zeichen ausgeben
+ push dx ; Register retten
+ push ax
+ mov dl,Zeichen
+ mov ah,DOS_WrChar
+ int INT_DOS
+ pop ax
+ pop dx ; Register zurck
+ endm
+
+;------------------------------------------------------------------------------
+
+btst macro op,bit ; ein einzelnes Bit testen
+ test op,(1<<bit)
+ endm
+
+;------------------------------------------------------------------------------
+
+ljnz macro adr ; lange Sprnge
+ jz Next
+ jmp adr
+Next:
+ endm
+
+ljne macro adr
+ je Next
+ jmp adr
+Next:
+ endm
+
+ljc macro adr
+ jnc Next
+ jmp adr
+Next:
+ endm
+
+lje macro adr
+ jne Next
+ jmp adr
+Next:
+ endm
+
+ljz macro adr
+ jnz Next
+ jmp adr
+Next:
+ endm
+
+ljb macro adr
+ jnb Next
+ jmp adr
+Next:
+ endm
+
+;------------------------------------------------------------------------------
+
+proc macro name
+ section name
+ public name:parent
+name label $
+ endm
+
+globproc macro name
+ section name
+ public name
+name label $
+ endm
+
+endp macro
+ endsection
+ endm
+
+;------------------------------------------------------------------------------
+; Fehlermakro
+
+JmpOnError macro Drv,Adr
+ jnc GoOn ; kein Fehler, weitermachen
+ mov ah,Drv
+ call WrErrorCode ; Fehler-->ausgeben...
+ jmp Adr ; ...Abbruch
+GoOn:
+ endm
+
+;******************************************************************************
+;* Treiberkopf *
+;******************************************************************************
+
+
+ assume cs:code,ds:nothing,ss:nothing,es:nothing
+
+ org 0
+
+DriverHead: dd -1 ; Zeiger auf Nachfolger
+ dw 0000100000000010b ; Attribut
+; ^ ^ ^
+; ³ ³ ÀÄ kann 32-Bit-Setornummern verarbeiten
+; ³ ÀÄÄÄÄÄÄÄÄÄÄÄ kennt Close/Open/Removeable
+; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Blocktreiber
+ dw StrategyProc ; Zeiger auf Strategieroutine
+ dw InterruptProc ; Zeiger auf eigentlichen Treibercode
+NrOfVols: db 0 ; Zahl log. Laufwerke
+ db "SECDRIV" ; bei Blocktreibern unbenutzt
+
+;******************************************************************************
+;* residente Daten *
+;******************************************************************************
+
+Rh_Ptr dd ? ; Speicher fr Request-Header
+
+JmpTable dw Init ; Sprungtabelle: Initialisierung
+ dw MediaCheck ; Medium gewechselt ?
+ dw BuildBPB ; Parameterblock laden
+ dw IOCTLRead ; Steuerdaten vom Treiber
+ dw Read ; Daten lesen
+ dw ND_Read ; Lesen, ohne Pufferstatus zu „ndern
+ dw InputStatus ; Daten im Eingabepuffer ?
+ dw InputFlush ; Eingabepuffer l”schen
+ dw Write ; Daten schreiben
+ dw Write_Verify ; Daten mit Prflesen schreiben
+ dw OutputStat ; Ausgabepuffer leer ?
+ dw OutputFlush ; Ausgabepuffer l”schen
+ dw IOCTLWrite ; Steuerdaten zum Treiber
+ dw DeviceOpen ; DOS hat eine Datei darauf ge”ffnet
+ dw DeviceClose ; DOS hat eine Datei darauf geschlossen
+ dw Removeable ; Ist Datentr„ger wechselbar ?
+ dw OutputTillBusy ; Ausgabe, bis Puffer voll
+ dw GenIOCTL ; genormtes IOCTL
+ dw GetLogical ; Laufwerkszuordnung lesen
+ dw SetLogical ; Laufwerkszuordnung setzen
+ dw IOCTLQuery ; Abfrage, ob GenIOCTL untersttzt
+
+SectorBuffer: db SecSize dup (?) ; Sektorpuffer fr Treiber selber
+
+ db StackSize dup (?) ; Treiberstack
+DriverStack:
+
+BPBSize equ 36
+DrTab struct ; Laufwerkstabelle:
+StartHead db ? ; Startkopf
+StartCyl dw ? ; Startzylinder
+StartSec db ? ; Startsektor
+LinStart dd ? ; lin. Startsektor
+SecCnt dd ? ; Gesamtsektorzahl
+Drive db ? ; Laufwerk
+BPB db BPBSize dup (?) ; BPB
+ endstruct
+
+DrTab db DrTab_Len*MaxDrives dup (?)
+DrTab_BPBs dd 2*MaxDrives dup (?)
+DrCnt db 0 ; Anzahl gefundener Laufwerke
+DrOfs db 0 ; erster freier Laufwerksbuchstabe
+
+DrPar struct ; Plattenparametersatz:
+Cyls dw ? ; Zylinderzahl
+Heads db ? ; Kopfzahl
+RedWr dw ? ; Startzylinder reduzierter Schreibstrom
+PrComp dw ? ; Startzylinder Pr„kompensation
+ECCLen db ? ; max. korrigierbarer Fehlerburst (Bits)
+CByte db ? ; Wert frs Plattensteuerregister
+TOut db ? ; genereller Timeout
+FTOut db ? ; Timeout Formatierung
+CTOut db ? ; Timeout fr Prfung
+LZone dw ? ; Landezylinder
+NSecs db ? ; Sektorzahl
+Dummy db ? ; unbenutzt
+ endstruct
+
+DrPars db DrPar_Len*MaxPDrives dup (0)
+
+;******************************************************************************
+;* Strategieroutine *
+;******************************************************************************
+
+StrategyProc: mov word ptr [Rh_Ptr],bx ; Zeiger speichern
+ mov word ptr [Rh_Ptr+2],es
+ retf
+
+;******************************************************************************
+;* Treiberdispatcher *
+;******************************************************************************
+
+Rh struct
+Size db ? ; gemeinsame Headerteile: L„nge Block
+Unit db ? ; angesprochenes Laufwerk
+Func db ? ; Treibersubfunktion
+Status dw ? ; Ergebnis
+Resvd db 8 dup (?) ; unbenutzt
+ endstruct
+
+InterruptProc: pusha ; alle Register retten
+
+ cli ; Stack umschalten
+ mov si,ss ; alten zwischenspeichern
+ mov di,sp
+ mov ax,cs ; neuen setzen
+ mov ss,ax
+ lea sp,[DriverStack]
+ push di ; alten auf neuem (!) speichern
+ push si
+ sti
+
+ mov ax,cs ; DS auf Treibersegment
+ mov ds,ax
+ assume ds:code
+
+ les bx,[Rh_Ptr] ; Zeiger laden
+ mov word ptr es:[bx+Rh_Status],0 ; Status l”schen
+
+ mov al,es:[bx+Rh_Func] ; Subfunktion ausrechnen
+ if debug
+ call PrByte
+ endif
+ mov ah,0
+ add ax,ax
+ mov si,ax
+ jmp JmpTable[si]
+
+ jmp Init
+
+;******************************************************************************
+;* gemeinsames Ende *
+;******************************************************************************
+
+StateError: btst al,1 ; Bit 1: Spur 0 nicht gefunden
+ jz StateError_N1
+ mov al,DErr_TrkNotFnd
+ jmp StateError_End
+StateError_N1: btst al,2 ; Bit 2: abgebrochenes Kommando
+ jz StateError_N2
+ btst ah,5 ; Bit S5: Schreibfehler
+ jz StateError_N21
+ mov al,DErr_WrError
+ jmp StateError_End
+StateError_N21: btst ah,4 ; Bit S4: Positionierung nicht vollst„ndig
+ jnz StateError_N22
+ mov al,DErr_TrkNotFnd
+ jmp StateError_End
+StateError_N22: btst ah,6 ; Bit S6: Laufwerk nicht bereit
+ jnz StateError_N23
+ mov al,DErr_NotReady
+ jmp StateError_End
+StateError_N23: mov al,DErr_GenFail ; Notnagel 1
+ jmp StateError_End
+StateError_N2: test al,11h ; Bit 0/4: Sektor nicht gefunden
+ jz StateError_N3
+ mov al,DErr_SecNotFnd
+ jmp StateError_End
+StateError_N3: btst al,6 ; Bit 6: Prfsummenfehler
+ jz StateError_N4
+ mov al,DErr_CRCError
+ jmp StateError_End
+StateError_N4: mov al,DErr_GenFail ; Notnagel 2
+StateError_End: les bx,[Rh_Ptr] ; Code einspeichern
+ mov es:[bx+Rh_Status],al
+ jmp Error
+
+Unknown: les bx,[Rh_Ptr]
+ mov byte ptr es:[bx+Rh_Status],DErr_Unknown ; unbek. Funktion
+
+Error: or byte ptr es:[bx+Rh_Status+1],80h ; Fehler-Flag setzen
+ jmp Done
+
+Busy: les bx,[Rh_Ptr]
+ or byte ptr es:[bx+Rh_Status+1],2 ; Busy-Flag setzen
+
+Done: les bx,[Rh_Ptr]
+ or byte ptr es:[bx+Rh_Status+1],1 ; Done-Flag setzen
+
+ if debug
+ call NxtLine
+ endif
+
+ cli ; Stack zurckschalten
+ pop si
+ pop di ; alten in SI:DI laden
+ mov sp,di ; einschreiben
+ mov ss,si
+ sti
+
+ popa ; Register zurck
+ retf
+
+;******************************************************************************
+;* Debugginghilfe *
+;******************************************************************************
+
+ if debug||debug2
+
+HexTab db "0123456789ABCDEF"
+
+PrByte: push es ; Register retten
+ push di
+ push bx
+ push ax
+
+ lea bx,[HexTab]
+
+
+ db 0d4h,10h ; AAM 16
+ push ax
+ mov al,ah
+ xlat
+ mov ah,0eh
+ int 10h
+ pop ax
+ xlat
+ mov ah,0eh
+ int 10h
+
+ pop ax ; Register zurck
+ pop bx
+ pop di
+ pop es
+ ret
+
+PrWord: xchg ah,al ; Hi-Byte
+ call PrByte
+ xchg ah,al
+ call PrByte
+ ret
+
+PrChar: push ax
+ mov ah,0eh
+ int 10h
+ pop ax
+ ret
+
+NxtLine: push ax ; Register retten
+ push bx
+ push dx
+
+ mov ax,0e0dh
+ int 10h
+ mov ax,0e0ah
+ int 10h
+
+ pop dx ; Register zurck
+ pop bx
+ pop ax
+
+ endif
+
+;******************************************************************************
+;* residente Subfunktionen *
+;******************************************************************************
+
+;******************************************************************************
+;* eine logische Laufwerksnummer berprfen *
+;* In : AL = Laufwerk *
+;* Out : C = 1, falls Fehler *
+;******************************************************************************
+
+ proc ChkDrive
+
+ cmp al,[DrCnt] ; C=1, falls < (d.h. OK)
+ cmc ; Deshalb noch einmal drehen
+ jnc OK ; C=0, alles in Butter
+ les bx,[Rh_Ptr] ; ansonsten Fehlerstatus setzen
+ mov byte ptr es:[bx+Rh_Status],DErr_InvUnit
+OK: ret
+
+ endp
+
+;******************************************************************************
+;* Adresse der phys. Laufwerkstabelle errechnen *
+;* In : AL = Laufwerk *
+;* Out : DI = Adresse *
+;******************************************************************************
+
+ proc GetPTabAdr
+
+ mov ah,DrPar_Len ; relative Adresse berechnen
+ mul ah
+ lea di,[DrPars] ; Offset dazu
+ add di,ax
+ ret
+
+ endp
+
+;******************************************************************************
+;* Adresse eines Partitionsdeskriptors errechnen *
+;* In : AL = log. Laufwerk *
+;* Out : DI = Adresse *
+;******************************************************************************
+
+ proc GetTabAdr
+
+ mov ah,DrTab_Len ; relative Adresse berechnen
+ mul ah
+ lea di,[DrTab] ; Offset dazu
+ add di,ax
+ ret
+
+ endp
+
+;******************************************************************************
+;* logische Parameter in physikalische bersetzen *
+;* In : BL = log. Laufwerk *
+;* DX:AX = relative Sektornummer *
+;* Out : AL = phys. Laufwerk *
+;* AH = Kopf *
+;* BX = Zylinder *
+;* CH = Sektor *
+;******************************************************************************
+
+ proc TranslateParams
+
+ push di ; Register retten
+
+ xchg bx,ax ; Adresse Parametertabelle holen
+ call GetTabAdr
+
+ add bx,[di+DrTab_LinStart] ; in absolute Sektornummer
+ adc dx,[di+DrTab_LinStart+2] ; umrechnen
+ mov al,[di+DrTab_Drive] ; phys. Laufwerksnummer holen
+ push ax ; bis zum Ende retten
+
+ call GetPTabAdr ; von dieser phys. Platte die Tabelle holen
+ mov ax,bx ; Sektor# wieder nach DX:AX
+ mov bl,[di+DrPar_NSecs] ; Sektorzahl auf 16 Bit
+ mov bh,0 ; aufblasen
+ div bx
+ mov ch,dl ; Modulo-Rest ist Sektornummer auf
+ inc ch ; Spur: Vorsicht, Numerierung ab 1 !!!
+ sub dx,dx ; wieder auf 32 Bit erweitern
+ mov bl,[di+DrPar_Heads] ; Kopfnummer herausfummeln
+ div bx
+ mov bx,ax ; Quotient ist Zylinder
+ pop ax ; Laufwerk zurck
+ mov ah,dl ; Rest ist Kopf
+
+ pop di ; Register zurck
+ ret
+
+ endp
+
+;******************************************************************************
+;* Einbindung Low-Level-Routinen *
+;******************************************************************************
+
+; definiert werden mssen:
+
+; LowLevelIdent: Meldung ber untersttzte Hardware ausgeben
+; ContDiag: Kontroller-Selbsttest durchfhren
+; Ergebniskode in AL
+; Recalibrate: Laufwerk [AL] auf Zylinder 0 fahren
+; Fehlerflag in C, Fehlerkode in AX
+; SetDriveParams: dem Kontroller die Geometrie fr Laufwerk [AL] einbleuen
+; Fehlerflag in C
+; ReadSectors: von Laufwerk [AL] ab Zylinder [BX], Kopf [AH], Sektor [CH]
+; [CL] Sektoren in Puffer ab ES:DI lesen
+; Fehlerflag in C, Fehlerkode in AX
+; WriteSectors: auf Laufwerk [AL] ab Zylinder [BX], Kopf [AH], Sektor [CH]
+; [CL] Sektoren von Puffer ab ES:SI schreiben
+; Fehlerflag in C, Fehlerkode in AX
+; VeriSectors: auf Laufwerk [AL] ab Zylinder [BX], Kopf [AH], Sektor [CH]
+; [CL] Sektoren verifizieren
+; Fehlerflag in C, Fehlerkode in AX
+; FormatUnit: Laufwerk [AL] mit Interleave [AH] formatieren, Fehlerkode
+; in AX
+; FormatTrack: Zylinder [BX], Kopf [AH] auf Laufwerk [AL] mit Interleave
+; [CL] formatieren, Fehlerkode in AX
+; MarkBad: Zylinder [BX], Kopf [AH] auf Laufwerk [AL] als defekt
+; markieren, Fehlerkode in AX
+
+ include "lowlevel.inc"
+
+;******************************************************************************
+;* Bootsektor eines log. Laufwerkes lesen *
+;* In : AL = Laufwerksnummer *
+;* Out : C+AX = Fehlerstatus *
+;******************************************************************************
+
+ proc ReadBootSec
+
+ push es ; Register retten
+ push bx
+ push cx
+ push di
+
+ call GetTabAdr ; Eintrag in Laufwerkstabelle ermitteln
+ mov al,[di+DrTab_Drive] ; davon ersten Sektor lesen
+ mov ah,[di+DrTab_StartHead]
+ mov bx,[di+DrTab_StartCyl]
+ mov cl,1
+ mov ch,[di+DrTab_StartSec]
+ mov di,cs
+ mov es,di
+ lea di,[SectorBuffer]
+ call ReadSectors
+
+ pop di ; Register zurck
+ pop cx
+ pop bx
+ pop es
+ ret
+
+ endp
+
+;******************************************************************************
+;* Funktion 1: Test, ob Medium gewechselt *
+;******************************************************************************
+
+ proc MediaCheck
+
+Rh_MediaID equ Rh_Resvd+8 ; erwartetes Media-ID
+Rh_Return equ Rh_MediaID+1 ; Ergebnis-Flag
+Rh_VolName equ Rh_Return+1 ; Adresse alter Laufwerksname
+
+ cmp byte ptr es:[bx+Rh_MediaID],HD_ID ; gltige ID ?
+ je OK
+ mov byte ptr es:[bx+Rh_Status],DErr_InvMedia ; nein...
+ jmp Error
+OK: mov byte ptr es:[bx+Rh_Return],1 ; nie gewechselt
+ jmp Done
+
+ endp
+
+;******************************************************************************
+;* Funktion 2: BPB aufbauen *
+;******************************************************************************
+
+ proc BuildBPB
+
+Rh2 struct
+ db Rh_Len dup (?)
+MediaID db ? ; erwartetes Media-ID
+FATSector dd ? ; Pufferadresse 1. FAT-Sektor
+BPBAddress dd ? ; Adresse neuer BPB
+ endstruct
+
+ mov al,es:[bx+Rh_Unit]
+ call ChkDrive ; Laufwerksnummer gltig ?
+ ljc Error ; nein-->Fehler & Ende
+
+ call ReadBootSec ; Bootsektor lesen
+ ljc StateError ; bei Fehlern Ende
+
+ les bx,[Rh_Ptr] ; Zeiger neu laden
+ mov al,es:[bx+Rh_Unit] ; Tabellenadresse aufbauen
+ call GetTabAdr
+ lea di,[di+DrTab_BPB] ; DI auf BPB-Speicher
+ mov es:[bx+Rh2_BPBAddress],di ; BPB-Zeiger abspeichern
+ mov es:[bx+Rh2_BPBAddress+2],cs
+
+ mov si,cs ; BPB umkopieren
+ mov es,si
+ lea si,[SectorBuffer+BPBOfs]
+ cld
+ mov cx,BPBSize
+ rep movsb
+
+ jmp Done
+
+ endp
+
+;******************************************************************************
+
+IOCTLRead: jmp Unknown
+
+;******************************************************************************
+;* Funktion 4: Sektoren lesen *
+;******************************************************************************
+
+Rh4 struct
+ db Rh_len dup (?)
+MediaID db ? ; Media-ID Laufwerk
+BufOfs dw ? ; Adresse Datenpuffer
+BufSeg dw ?
+NSecs dw ? ; Anzahl zu lesender Bl”cke
+FirstSec dw ? ; Startsektor bzw. $FFFF fr 32-Bit-Nummern
+VolID dd ? ; Adresse Laufwerksname
+LFirstSec dw ? ; lange Startsektornummer
+HFirstSec dw ?
+ endstruct
+
+Read: mov al,es:[bx+Rh_Unit] ; Laufwerksnummer prfen
+ call ChkDrive
+ ljc Error
+
+ mov ch,al ; Laufwerksnummer retten
+ mov ax,es:[bx+Rh4_FirstSec] ; Sektor holen (BIGDOS beachten)
+ sub dx,dx
+ cmp ax,-1
+ jne Read_SmallSec
+ mov ax,es:[bx+Rh4_LFirstSec]
+ mov dx,es:[bx+Rh4_HFirstSec]
+Read_SmallSec: mov cl,es:[bx+Rh4_NSecs] ; Sektorzahl laden (muá <=128 sein)
+ les di,es:[bx+Rh4_BufOfs] ; Zieladresse laden
+ mov bl,ch ; Laufwerksnummer nach BL
+
+ if debug
+ push ax
+ push cx
+ mov cx,ax
+ mov al,' '
+ call PrChar
+ mov al,bl ; Laufwerksnummer
+ call PrByte
+ mov al,' '
+ call PrChar
+ mov ax,dx ; Startsektor
+ call PrWord
+ mov ax,cx
+ call PrWord
+ mov al,' '
+ call PrChar
+ pop cx
+ mov al,cl ; Sektorzahl
+ call PrByte
+ mov al,' '
+ call PrChar
+ mov ax,es ; Startadresse
+ call PrWord
+ mov al,':'
+ call PrChar
+ mov ax,di
+ call PrWord
+ pop ax
+ endif
+
+ call TranslateParams ; umrechnen lassen
+ call ReadSectors ; der eigentliche Lesevorgang
+
+ ljc StateError ; bei Fehlern...
+ jmp Done ; ansonsten o.k.
+
+;******************************************************************************
+
+ND_Read: jmp Unknown
+
+InputStatus: jmp Unknown
+
+InputFlush: jmp Unknown
+
+;******************************************************************************
+;* Funktion 8: Sektoren schreiben *
+;******************************************************************************
+
+Rh8 struct
+ db Rh_len dup (?)
+MediaID db ? ; Media-ID Laufwerk
+BufOfs dw ? ; Adresse Datenpuffer
+BufSeg dw ?
+NSecs dw ? ; Anzahl zu lesender Bl”cke
+FirstSec dw ? ; Startsektor bzw. $FFFF fr 32-Bit-Nummern
+VolID dd ? ; Adresse Laufwerksname
+LFirstSec dw ? ; lange Startsektornummer
+HFirstSec dw ?
+ endstruct
+
+DoWrite: if debug2
+ mov al,es:[bx+Rh_Unit]
+ call PrByte
+ mov al,' '
+ call PrChar
+ mov ax,es:[bx+Rh8_FirstSec]
+ call PrWord
+ mov al,' '
+ mov ax,es:[bx+Rh8_HFirstSec]
+ call PrWord
+ mov ax,es:[bx+Rh8_LFirstSec]
+ call PrWord
+ call NxtLine
+ endif
+
+ mov al,es:[bx+Rh_Unit]
+ mov ch,al ; Laufwerksnummer retten
+ mov ax,es:[bx+Rh8_FirstSec] ; Sektor holen (BIGDOS beachten)
+ sub dx,dx
+ cmp ax,-1
+ jne DWrite_SmallSec
+ mov ax,es:[bx+Rh8_LFirstSec]
+ mov dx,es:[bx+Rh8_HFirstSec]
+DWrite_SmallSec:mov cl,es:[bx+Rh8_NSecs] ; Sektorzahl laden (muá <=128 sein)
+ les si,es:[bx+Rh8_BufOfs] ; Zieladresse laden
+ mov bl,ch ; Laufwerksnummer nach BL
+
+ if debug
+ push ax
+ push cx
+ mov cx,ax
+ mov al,' '
+ call PrChar
+ mov al,bl ; Laufwerksnummer
+ call PrByte
+ mov al,' '
+ call PrChar
+ mov ax,dx ; Startsektor
+ call PrWord
+ mov ax,cx
+ call PrWord
+ mov al,' '
+ call PrChar
+ pop cx
+ mov al,cl ; Sektorzahl
+ call PrByte
+ mov al,' '
+ call PrChar
+ mov ax,es ; Startadresse
+ call PrWord
+ mov al,':'
+ call PrChar
+ mov ax,si
+ call PrWord
+ pop ax
+ endif
+
+ call TranslateParams ; umrechnen lassen
+ call WriteSectors ; der eigentliche Lesevorgang
+
+ ret
+
+Write: mov al,es:[bx+Rh_Unit] ; Laufwerksnummer prfen
+ call ChkDrive
+ ljc Error
+
+ call DoWrite
+
+ ljc StateError ; bei Fehlern...
+ jmp Done ; ansonsten o.k.
+
+
+;******************************************************************************
+;* Funktion 9: Sektoren schreiben mit šberprfung *
+;******************************************************************************
+
+Rh9 struct
+ db Rh_len dup (?)
+MediaID db ? ; Media-ID Laufwerk
+BufOfs dw ? ; Adresse Datenpuffer
+BufSeg dw ?
+NSecs dw ? ; Anzahl zu lesender Bl”cke
+FirstSec dw ? ; Startsektor bzw. $FFFF fr 32-Bit-Nummern
+VolID dd ? ; Adresse Laufwerksname
+LFirstSec dw ? ; lange Startsektornummer
+HFirstSec dw ?
+ endstruct
+
+Write_Verify: mov al,es:[bx+Rh_Unit] ; Laufwerksnummer prfen
+ call ChkDrive
+ ljc Error
+
+ call DoWrite ; schreiben
+
+ ljc StateError ; bei Fehlern vorher abbrechen
+
+ les bx,[Rh_Ptr] ; Parameter nochmal fr Verify laden
+ mov al,es:[bx+Rh_Unit]
+ mov ch,al
+ mov ax,es:[bx+Rh9_FirstSec]
+ sub dx,dx
+ cmp ax,-1
+ jne VWrite_SmallSec
+ mov ax,es:[bx+Rh9_LFirstSec]
+ mov dx,es:[bx+Rh9_HFirstSec]
+VWrite_SmallSec:mov cl,es:[bx+Rh9_NSecs]
+ mov bl,ch
+
+ call TranslateParams ; nochmal umrechen...
+ call VeriSectors ; und prflesen
+
+ jmp Done ; alles gut gegangen
+
+;******************************************************************************
+
+OutputStat: jmp Unknown
+
+OutputFlush: jmp Unknown
+
+IOCTLWrite: jmp Unknown
+
+;******************************************************************************
+;* kein Device wechselbar, ™ffnen/Schleáen interessiert nicht *
+;******************************************************************************
+
+DeviceOpen: jmp Done
+
+DeviceClose: jmp Done
+
+Removeable: jmp Done
+
+;******************************************************************************
+
+OutputTillBusy: jmp Unknown
+
+GenIOCTL: jmp Unknown
+
+GetLogical: jmp Unknown
+
+SetLogical: jmp Unknown
+
+IOCTLQuery: jmp Unknown
+
+;******************************************************************************
+;* Funktion 0: Initialisierung *
+;******************************************************************************
+
+ include "secparam.inc"
+
+Rh0 struct
+ db Rh_len dup (?)
+Units db ? ; Zahl bedienter Laufwerke
+EndOfs dw ? ; Endadresse Offset
+EndSeg dw ? ; Endadresse Segment
+ParamOfs dw ? ; Parameter Offsetadresse
+ParamSeg dw ? ; Parameter Segmentadresse
+FirstDrive db ? ; erstes freies Laufwerk
+MsgFlag db ? ; Flag, ob DOS Fehler ausgeben darf
+ endstruct
+
+Init: PrMsg HelloMsg ; Meldung ausgeben
+ call LowLevelIdent ; Startmeldung des Low-Level-Treibers
+
+ mov byte ptr es:[bx+Rh0_Units],0 ; noch keine Laufwerke
+
+ mov al,es:[bx+Rh0_FirstDrive] ; Startlaufwerk retten
+ mov [DrOfs],al
+
+ mov ax,cs ; ES auf gem. Segment
+ mov es,ax
+
+; Schritt 1: Controller prfen
+
+ PrMsg DiagMsg0
+ call ContDiag ; Diagnose ausfhren
+ sub al,Diag_NoError
+ cmp al,6 ; auáerhalb ?
+ jae Diag_Over
+ add al,al ; Meldung ausrechnen
+ mov ah,0
+ mov si,ax
+ mov dx,DiagMsgTable[si]
+ mov ah,9
+ int INT_DOS
+ or si,si ; fehlerfrei ?
+ ljnz Init_Err ; Nein, Fehler
+ jmp Init_ChkDrives ; Ja, weiter zum Laufwerkstest
+
+Diag_Over: push ax
+ PrMsg UndefDiagMsg ; undefinierter Fehlercode
+ pop ax
+ add al,Diag_NoError ; Meldung rckkorrigieren
+ db 0d4h,10h ; AAM 16
+ add ax,'00'
+ push ax
+ mov al,ah
+ mov ah,14
+ int 10h
+ pop ax
+ mov ah,14
+ int 10h
+ PrChar CR
+ PrChar LF
+ jmp Init_Err
+
+
+; Schritt 2: Laufwerke testen
+
+; Menaufruf?
+
+Init_ChkDrives: mov ax,40h ; CTRL gedrckt ?
+ mov es,ax
+ btst byte ptr es:[17h],2
+ jz Init_Menu
+ call DiskMenu
+
+; Schritt 2a: Laufwerk rekalibrieren
+
+Init_Menu: mov al,[MomDrive]
+ call Recalibrate
+ ljc Init_NextDrive ; Fehler: Laufwerk berspringen
+
+; Schritt 2b: Masterpartitionssektor lesen
+
+ReadMaster: mov al,[MomDrive]
+ mov ah,0 ; Kopf...
+ sub bx,bx ; ...Zylinder...
+ mov cx,0101h ; ...ein Sektor ab Sektor 1
+ mov di,ds
+ mov es,di
+ lea di,[SectorBuffer] ; in den Sektorpuffer
+ call ReadSectors
+ JmpOnError [MomDrive],Init_NextDrive ; Fehler ?
+
+; Schritt 2c: Laufwerksparameter initialisieren
+
+ lea si,[SectorBuffer+DrPar_Offset] ; Quelladresse im Sektor
+ mov al,[MomDrive] ; Zieladresse ausrechnen
+ call GetPTabAdr
+ mov cx,DrPar_Len
+ cld
+ rep movsb
+
+ sub di,DrPar_Len ; Laufwerk nicht initialisiert ?
+ cmp word ptr[di+DrPar_Cyls],0
+ je DoQuery
+ cmp byte ptr[di+DrPar_Heads],0
+ je DoQuery
+ cmp byte ptr[di+DrPar_NSecs],0
+ jne NoQuery
+DoQuery: mov al,[MomDrive] ; wenn ja, dann nachfragen
+ mov ah,1 ; Rckschreiben hier erlaubt
+ call QueryParams
+ or al,al ; =0-->Laufwerk ignorieren
+ jz Init_NextDrive
+ dec al ; =1-->nochmal lesen
+ jz ReadMaster ; ansonsten weitermachen
+
+NoQuery: mov al,[MomDrive] ; Laufwerksparameter ausgeben...
+ call PrintPDrive
+ mov al,[MomDrive] ; ...und dem Controller einbleuen
+ call SetDriveParams
+ JmpOnError [MomDrive],Init_NextDrive
+ mov al,[MomDrive]
+ call Recalibrate
+ JmpOnError [MomDrive],Init_NextDrive
+
+; Schritt 2d: durch die Partitionssektoren hangeln
+
+ mov al,[MomDrive] ; Laufwerk : momentanes
+ cbw ; Kopf : 0
+ push ax
+ sub ax,ax
+ push ax ; Zylinder : 0
+ inc ax ; Sektor : 1
+ push ax
+ dec ax
+ push ax ; lin. Sektornummer 0
+ push ax
+ call ScanParts
+
+Init_NextDrive: inc [MomDrive] ; Z„hler weitersetzen
+ cmp [MomDrive],MaxPDrives
+ ljb Init_ChkDrives
+
+ cmp [DrCnt],0 ; keine Partitionen gefunden ?
+ jne Init_PDrives
+ PrMsg ErrMsgNoDrives ; ja: meckern
+ jmp Init_Err
+
+Init_PDrives: PrMsg LDriveMsg
+ mov [MomDrive],0 ; Parameter der Partitionen ausgeben
+ lea bp,[DrTab_BPBs] ; und BPB-Tabelle aufbauen
+ cld
+
+Init_PLDrives: mov al,[MomDrive]
+ call PrintLDrive
+
+ mov al,[MomDrive] ; Bootsdektor lesen
+ call ReadBootSec
+ lea si,[SectorBuffer+BPBOfs] ; BPB rauskopieren
+ mov al,[MomDrive]
+ call GetTabAdr
+ lea di,[di+DrTab_BPB]
+ mov ax,cs
+ mov es,ax
+ mov ds:[bp],di ; Adresse nebenbei ablegen
+ add bp,2
+ mov cx,BPBSize
+ rep movsb
+
+ inc [MomDrive]
+ mov al,[MomDrive]
+ cmp al,[DrCnt]
+ jb Init_PLDrives
+
+ PrChar LF ; sieht besser aus...
+
+ les bx,[Rh_Ptr] ; Zeiger auf BPB-Zeiger einschreiben
+ lea ax,[DrTab_BPBs]
+ mov es:[bx+Rh0_ParamOfs],ax
+ mov es:[bx+Rh0_ParamSeg],cs
+ jmp Init_OK ; Initialisierung erfolgeich zu Ende
+
+Init_Err: PrMsg WKeyMsg
+ xor ah,ah ; damit Meldung lesbar bleibt
+ int 16h
+ sub ax,ax ; Treiber aus Speicher entfernen
+ jmp Init_End
+
+Init_OK: mov al,[DrCnt] ; Laufwerkszahl holen
+ les bx,[Rh_Ptr]
+ mov es:[bx+Rh0_Units],al ; im Request Header eintragen
+ mov [NrOfVols],al ; im Treiberkopf eintragen
+ lea ax,[Init] ; residenten Teil installieren
+
+Init_End: les bx,[Rh_Ptr]
+ mov es:[bx+Rh0_EndOfs],ax ; Endadresse setzen
+ mov es:[bx+Rh0_EndSeg],cs
+
+ jmp Done
+
+;******************************************************************************
+;* transiente Unterroutinen *
+;******************************************************************************
+
+;******************************************************************************
+;* Partitionsbaum durchgehen *
+;* In : dw Kopf/Laufwerk *
+;* dw Zylinder *
+;* dw Sektor *
+;* dd lineare Nummer des Sektors *
+;******************************************************************************
+
+ScParts_DrHd equ 12 ; Parameteradressen auf Stack
+ScParts_Cyl equ 10
+ScParts_Sec equ 8
+ScParts_LinSec equ 4
+ScParts_ParTab equ 0-(MaxParts*ParTab_Len) ; Kopie Partitionstabelle
+ScParts_LocSize equ 0-ScParts_ParTab ; belegter Stack
+
+ScanParts: enter ScParts_LocSize,0
+
+; Partitionssektor lesen
+
+ mov ax,[bp+ScParts_DrHd]
+ mov bx,[bp+ScParts_Cyl]
+ mov ch,[bp+ScParts_Sec]
+ mov cl,1
+ mov di,cs
+ mov es,di
+ lea di,[SectorBuffer]
+ call ReadSectors
+ JmpOnError [MomDrive],ScanParts_End
+
+; Partitionssektorkennung o.k. ?
+
+ cmp word ptr SectorBuffer[ParSecID_Offset],0aa55h
+ ljne ScanParts_End
+
+; Partitionstabelle auslesen
+
+ lea si,[SectorBuffer+ParTab_Offset] ; Quelladresse
+ mov di,ss ; Zieladresse auf Stack
+ mov es,di
+ lea di,[bp+ScParts_ParTab]
+ mov cx,MaxParts*ParTab_Len ; L„nge
+ cld
+ rep movsb
+
+; Partitionstabelle durchgehen
+
+ mov si,ScParts_ParTab ; vorne anfangen
+ mov cx,MaxParts ; alle durchgehen
+ScanParts_Scan: push cx
+
+ mov al,[bp+si+ParTab_Type] ; Typ der Partition lesen
+ lea bx,[AccPartTypes-1] ; auf Suchtabelle
+ScanParts_LAcc: inc bx ; einen Eintrag weiter
+ cmp byte ptr [bx],0 ; Tabellenende ?
+ je ScanParts_Next ; ja-->war nix
+ cmp al,[bx] ; gefunden ?
+ jne ScanParts_LAcc ;
+
+ mov bx,[bp+si+ParTab_LinSec] ; linearen Startsektor ausrechnen
+ mov cx,[bp+si+ParTab_LinSec+2]
+ add bx,[bp+ScParts_LinSec] ; in CX:BX
+ adc cx,[bp+ScParts_LinSec+2]
+
+ cmp al,5 ; extended partition ?
+ jne ScanParts_Enter
+
+ push si ; ja: Zeiger fr Rekursion retten
+ mov al,[bp+ScParts_DrHd] ; Laufwerk & Kopf zusammenbauen
+ mov ah,[bp+si+ParTab_FHead]
+ push ax
+ mov ax,[bp+si+ParTab_FSecCyl] ; Zylinder ausfiltern
+ xchg ah,al
+ shr ah,6
+ push ax
+ mov al,[bp+si+ParTab_FSecCyl] ; Sektor ausfiltern
+ and ax,63
+ push ax
+ push cx
+ push bx
+ call ScanParts
+ pop si ; Zeiger zurck
+ jmp ScanParts_Next
+
+ScanParts_Enter:mov al,[DrCnt] ; Partition in Tabelle eintragen
+ call GetTabAdr ; dazu Adresse neuen Eintrags holen
+ cld
+ mov ax,cs ; Ziel im Segment
+ mov es,ax
+ mov al,[bp+si+ParTab_FHead] ; Kopf kopieren
+ stosb
+ mov ax,[bp+si+ParTab_FSecCyl] ; Zylinder kopieren
+ xchg ah,al
+ shr ah,6
+ stosw
+ mov al,[bp+si+ParTab_FSecCyl] ; Sektor kopieren
+ and al,63
+ stosb
+ mov ax,bx ; linearen Startsektor kopieren
+ stosw
+ mov ax,cx
+ stosw
+ mov ax,[bp+si+ParTab_NSecs] ; Sektorzahl kopieren
+ stosw
+ mov ax,[bp+si+ParTab_NSecs+2]
+ stosw
+ mov al,[bp+ScParts_DrHd] ; Laufwerksnummer kopieren
+ stosb
+ inc [DrCnt] ; ein log. Laufwerk mehr
+
+ScanParts_Next: add si,ParTab_Len ; auf n„chste Partition
+ pop cx
+ dec cx
+ ljnz ScanParts_Scan
+
+ScanParts_End: leave
+ ret 10
+
+;******************************************************************************
+;* Daten eines physikalischen Laufwerks ausgeben *
+;* In : AL = Laufwerk *
+;******************************************************************************
+
+ proc PrintPDrive
+
+ push cx ; Register retten
+ push dx
+ push di
+
+ cbw ; AH l”schen
+ push ax ; Laufwerk ausgeben
+ PrMsg PDriveMsg1
+ pop ax
+ push ax
+ inc ax
+ mov cl,1
+ call WriteDec
+ PrMsg PDriveMsg2
+
+ pop ax ; Adresse Laufwerkstabelle berechnen
+ call GetPTabAdr
+
+ mov ax,[di+DrPar_Cyls] ; Zylinder ausgeben
+ mov cl,5
+ call WriteDec
+ PrMsg PDriveMsg3
+
+ mov al,[di+DrPar_Heads] ; K”pfe ausgeben
+ mov ah,0
+ mov cl,3
+ call WriteDec
+ PrMsg PDriveMsg4
+
+ mov al,[di+DrPar_NSecs] ; Sektoren ausgeben
+ mov ah,0
+ mov cl,4
+ call WriteDec
+ PrMsg PDriveMsg5
+
+ mov al,[di+DrPar_Heads] ; Gesamtsektorzahl berechnen
+ mul byte ptr [di+DrPar_NSecs]
+ mul word ptr [di+DrPar_Cyls]
+ call WriteMBytes
+ PrMsg PDriveMsg6
+
+ pop di ; Register zurck
+ pop dx
+ pop cx
+ ret
+
+ endp
+
+;******************************************************************************
+;* Daten eines logischen Laufwerks ausgeben *
+;* In : AL = Laufwerk *
+;******************************************************************************
+
+ proc PrintLDrive
+
+ push cx ; Register retten
+ push dx
+ push di
+
+ mov dx,ax ; Laufwerk retten
+ push dx
+ mov cx,3 ; ausgeben
+ call WriteSpc
+ add dl,[DrOfs]
+ add dl,'A'
+ mov ah,DOS_WrChar
+ int INT_DOS
+ PrChar ':'
+
+ pop ax ; Tabelle holen
+ call GetTabAdr
+
+ mov al,[di+DrTab_Drive] ; Laufwerk ausgeben...
+ inc al
+ cbw
+ mov cl,9
+ call WriteDec
+
+ mov ax,[di+DrTab_StartCyl] ; ...Zylinder...
+ mov cl,10
+ call WriteDec
+
+ mov al,[di+DrTab_StartHead] ; ...Kopf...
+ cbw
+ mov cl,7
+ call WriteDec
+
+ mov al,[di+DrTab_StartSec] ; ...Sektor...
+ cbw
+ mov cl,8
+ call WriteDec
+
+ mov cx,2
+ call WriteSpc
+ mov ax,[di+DrTab_SecCnt] ; ...GrӇe
+ mov dx,[di+DrTab_SecCnt+2]
+ call WriteMBytes
+
+ PrMsg PDriveMsg6 ; Meldung wiederverwertet...
+
+ pop di ; Register zurck
+ pop dx
+ pop cx
+ ret
+
+ endp
+
+;******************************************************************************
+;* Fehlercode eines Laufwerks ausgeben *
+;* In : AL = Fehlercode *
+;* AH = Laufwerksnummer (0,1...) *
+;******************************************************************************
+
+ proc WrErrorCode
+
+ push bx ; Register retten
+ push cx
+ push dx
+
+ add ah,'1' ; LW-Nummer in ASCII umrechnen...
+ mov [DrvErrorMsg2],ah ; ...und einschreiben
+ mov ch,al ; Kode sichern
+ PrMsg DrvErrorMsg
+ mov cl,7 ; bei Bit 0 anfangen
+ErrLoop: rol ch,1 ; fagl. Bit in Carry
+ jnc NoErrBit
+ mov bl,cl ; Bit gefunden: Index ausrechnen
+ mov bh,0
+ add bx,bx
+ mov dx,[bx+Pointers]
+ mov ah,DOS_WrString
+ int INT_DOS
+NoErrBit: dec cl ; n„chstes Bit
+ jnz ErrLoop
+
+ pop dx ; Register zurck
+ pop cx
+ pop bx
+
+ ret
+
+DrvErrorMsg: db "Fehler auf Festplatte "
+DrvErrorMsg2: db "0:",CR,LF,'$'
+
+Pointers dw Msg0,Msg1,Msg2,Msg3,Msg4,Msg5,Msg6,Msg7
+Msg0 db " Adreámarke nicht gefunden",CR,LF,'$'
+Msg1 db " Spur 0 nicht gefunden",CR,LF,'$'
+Msg2 db " Kommandoabbruch",CR,LF,'$'
+Msg3 db "$"
+Msg4 db " Sektor nicht gefunden",CR,LF,'$'
+Msg5 db "$"
+Msg6 db " Datenfehler",CR,LF,'$'
+Msg7 db " Sektor als defekt markiert",CR,LF,'$'
+
+ endp
+
+;******************************************************************************
+;* Sektorenzahl als MBytes ausgeben *
+;* In: DX:AX = Sektorzahl *
+;******************************************************************************
+
+ proc WriteMBytes
+
+SecsPerMByte equ (2^20)/SecSize
+
+ push cx ; Register retten
+ push dx
+
+ add ax,SecsPerMByte/20 ; wg. Rundung
+ adc dx,0
+
+ mov cx,SecsPerMByte ; durch 2048 teilen = MByte
+ div cx
+ push dx ; Nachkommastellen retten
+ mov cl,6
+ call WriteDec
+
+ PrChar '.' ; Nachkommastelle
+ pop ax ; holen
+ cwd
+ mov cx,SecsPerMByte/10 ; Sektoren pro 100 KByte
+ div cx
+ mov cl,1 ; ausgeben
+ call WriteDec
+
+ pop dx ; Register zurck
+ pop cx
+ ret
+
+ endp
+
+;******************************************************************************
+;* transiente Daten *
+;******************************************************************************
+
+HelloMsg: db CR,LF,"Sekund„rlaufwerkstreiber V0.4",CR,LF,'$'
+
+ErrMsgNoDrives: db CR,LF,"Fehler: keine Partitionen gefunden",CR,LF,'$'
+
+DiagMsg0: db CR,LF,"Controller-Selbsttest: ",'$'
+DiagMsg1: db "OK",CR,LF,'$'
+DiagMsg2: db "Controller fehlerhaft",CR,LF,'$'
+DiagMsg3: db "Sektorpuffer defekt",CR,LF,'$'
+DiagMsg4: db "Fehlerkorrektur defekt",CR,LF,'$'
+DiagMsg5: db "Steuerprozessor defekt",CR,LF,'$'
+DiagMsg6: db "Timeout",CR,LF,'$'
+DiagMsgTable dw DiagMsg1,DiagMsg2,DiagMsg3,DiagMsg4,DiagMsg5,DiagMsg6
+UndefDiagMsg db "Unbekannter Fehlercode #$"
+WKeyMsg: db "Weiter mit beliebiger Taste...",CR,LF,'$'
+
+PDriveMsg1: db "Festplatte $"
+PDriveMsg2: db " :$"
+PDriveMsg3: db " Zylinder,$"
+PDriveMsg4: db " K”pfe,$"
+PDriveMsg5: db " Sektoren,$"
+PDriveMsg6: db " MByte",CR,LF,'$'
+
+LDriveMsg: db CR,LF,"vorhandene Partitionen:",CR,LF
+ db "Laufwerk Platte Zylinder Kopf"
+ db " Sektor Kapazit„t",CR,LF,'$'
+
+AccPartTypes db 1 ; akzeptierte Partitionstypen: DOS 2.x FAT12
+ db 4 ; DOS 3.x FAT16
+ db 5 ; DOS 3.3 extended
+ db 6 ; DOS 3.31 >32 MByte
+ db 0 ; Tabellenende
+
+MomDrive db 0 ; momentan gescanntes Laufwerk
+
+ end