diff options
Diffstat (limited to 'tests/t_secdrive')
| -rw-r--r-- | tests/t_secdrive/asflags | 0 | ||||
| l--------- | tests/t_secdrive/lowlevel.inc | 1 | ||||
| -rw-r--r-- | tests/t_secdrive/secparam.inc | 1619 | ||||
| -rw-r--r-- | tests/t_secdrive/t_secdrive.asm | 1476 | ||||
| -rw-r--r-- | tests/t_secdrive/t_secdrive.doc | 9 | ||||
| -rwxr-xr-x | tests/t_secdrive/t_secdrive.ori | bin | 0 -> 11271 bytes | |||
| -rw-r--r-- | tests/t_secdrive/wd1002xt.inc | 773 | ||||
| -rw-r--r-- | tests/t_secdrive/wd1003at.inc | 952 | 
8 files changed, 4830 insertions, 0 deletions
| diff --git a/tests/t_secdrive/asflags b/tests/t_secdrive/asflags new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/t_secdrive/asflags diff --git a/tests/t_secdrive/lowlevel.inc b/tests/t_secdrive/lowlevel.inc new file mode 120000 index 0000000..968acf7 --- /dev/null +++ b/tests/t_secdrive/lowlevel.inc @@ -0,0 +1 @@ +wd1003at.inc
\ No newline at end of file diff --git a/tests/t_secdrive/secparam.inc b/tests/t_secdrive/secparam.inc new file mode 100644 index 0000000..8bf8381 --- /dev/null +++ b/tests/t_secdrive/secparam.inc @@ -0,0 +1,1619 @@ +;***************************************************************************** +;* Sekund„rlaufwerkstreiber, Modul SecParam                                  * +;* liefert Laufwerksparameter, falls fehlend im Bootsektor                   * +;* stellt das ganze Formatiermen zur Verfgung                              * +;***************************************************************************** + +                section SecParam + +;***************************************************************************** +;* gemeinsam benutzte Meldungen                                              * +;***************************************************************************** + +TrackMsg        db      "Spur (0..Spurzahl-1) : $" +HeadMsg         db      "Kopf (0..Kopfzahl-1) : $" +ConfirmMsg      db      "Sind Sie sicher ?$" +InterleaveMsg   db     "Interleave (1..Sektorzahl-1) : $" + +;***************************************************************************** +;* Routine BreakOnESC                                                        * +;* schaut nach, ob ESC gedrckt wurde                                        * +;* Ausgabe:     C=1, falls ja                                                * +;***************************************************************************** + +                GlobProc BreakOnESC + +                push    ax              ; Register retten +                mov     ah,1            ; Tastaturpuffer antesten +                int     INT_Keyboard +                clc                     ; Annahme nicht gedrckt +                jz      Ende +                mov     ah,0            ; Zeichen da: dies abholen +                int     INT_Keyboard +                cmp     al,ESC          ; ist es ESC ? +                clc                     ; Annahme nein +                jne     Ende +                stc                     ; jawoll! +Ende:           pop     ax              ; Register zurck +                ret + +                endp + +;***************************************************************************** +;* Routine YesNo                                                             * +;* fragt nach Ja oder Nein                                                   * +;* Ausgabe:     C=0, falls ja                                                * +;***************************************************************************** + +                proc    YesNo + +                push    ax              ; Register retten + +QueryLoop:      mov     ah,DOS_RdChar   ; ein Zeichen lesen +                int     INT_DOS + +                cmp     al,'a'          ; Kleinbuchstaben ? +                jb      Upper +                cmp     al,'z' +                ja      Upper +                add     al,'A' +                sub     al,'a' +Upper: +                cmp     al,'J'          ; akzeptierte Zeichen fr Ja +                clc +                je      YNDone +                cmp     al,'Y' +                clc +                je      YNDone +                cmp     al,'N'          ; akzeptierte Zeichen fr Nein +                stc +                je      YNDone + +                PrChar  BEL             ; alles andere anmeckern +                jmp     QueryLoop + +YNDone:         PrChar  al              ; Zeichen als Echo ausgeben +                PrChar  CR              ; Zeilenvorschub +                PrChar  LF +                pop     ax              ; Register zurck + +                ret + +                endp + +;***************************************************************************** +;* Routine ReadNumber                                                        * +;* liest einen Wert von 0..n in AX ein                                       * +;* Eingabe:     AX = Maximalwert                                             * +;*              DI = Zeiger auf Meldung                                      * +;* Ausgabe:     AX = eingelesene Zahl                                        * +;***************************************************************************** + +                proc    ReadNumber + +                push    bx              ; Register retten +                push    cx +                push    dx +                push    si + +                mov     si,ax           ; Maximalwert retten +InLoop:         mov     dx,di           ; Meldung ausgeben +                mov     ah,DOS_WrString +                int     INT_DOS +                lea     dx,[KeyBuffer]  ; Zahl als String einlesen +                mov     ah,DOS_RdString +                int     INT_DOS +                PrChar  CR +                PrChar  LF +                mov     ax,0            ; jetzt Zeichen verarbeiten +                mov     cl,[KeyBuffer+1] +                mov     ch,0 +                lea     bx,[KeyBuffer+2] +                jcxz    InvFormat       ; Nullschleife abfangen +ConvLoop:       mov     dx,10           ; bisheriges Ergebnis hochmultiplizieren +                mul     dx +                mov     dl,[bx]         ; ein Zeichen holen +                inc     bx +                sub     dl,'0'          ; ASCII-Offset abziehen +                jc      InvFormat       ; bei Formatfehler abbrechen +                cmp     dl,9            ; nur 0..9 erlaubt +                ja      InvFormat +                add     al,dl           ; dazuaddieren +                adc     ah,0 +                loop    ConvLoop +                jmp     ChkRange        ; fertig: weiter zur Bereichsprfung +InvFormat:      PrMsg   InvMsg          ; wenn fehlerhaft, meckern +                jmp     InLoop          ; und nochmal versuchen +ChkRange:       cmp     ax,si           ; auáerhalb Bereich ? +                jbe     OK +                PrMsg   OverMsg         ; ja: meckern... +                jmp     InLoop          ; ...und auf ein neues + +OK:             pop     si              ; Register zurck +                pop     dx +                pop     cx +                pop     bx + +                ret + +KeyBufferLen    equ     30              ; 30 Zeichen sollten fr Zahlen reichen... +KeyBuffer       db      KeyBufferLen    ; Maimall„nge fr DOS +                db      0               ; effektive L„nge Eingabe +                db      KeyBufferLen dup (0) ; Platz fr Eingabe +InvMsg          db      "Ungltiges Zahlenformat",CR,LF,'$' +OverMsg         db      "Bereichsberschreitung",CR,LF,'$' + +                endp + +;****************************************************************************** +;* eine Anzahl Leerzeichen ausgeben                                           * +;*              In  :   CX = Anzahl                                           * +;****************************************************************************** + +                globproc WriteSpc + +                push    dx              ; Register retten + +                jcxz    NULL            ; Nullschleife abfangen +Loop:           mov     ah,DOS_WrChar +                mov     dl,' ' +                int     INT_DOS +                loop    Loop + +NULL:           pop     dx              ; Register zurck +                ret + +                endp + +;****************************************************************************** +;* vorzeichenlose Zahl dezimal ausgeben                                       * +;*              In  :   AX = Zahl                                             * +;*                      CL = min. Stellenzahl                                 * +;****************************************************************************** + +                globproc WriteDec + +                push    di              ; Register retten +                push    cx +                push    dx + +                mov     ch,0            ; CH z„hlt effektive Zeichenzahl +InLoop:         sub     dx,dx           ; Stellendivision +                mov     di,10           ; gewnschtes Zahlensystem +                div     di +                mov     di,ax           ; war es vorher 0 ? +                or      di,dx           ; (wenn Quotient & Rest 0) +                jnz     NZero           ; nein-->normal ausgeben +                or      ch,ch           ; noch erste Stelle ? +                jz      NZero           ; dann auf jeden Fall 0 ausgeben +                mov     dl,0f0h         ; ansonsten Leerzeichen fr leading 0 +NZero:          push    dx              ; Zeichen speichern... +                inc     ch              ; ...und mitz„hlen +                cmp     ch,cl           ; Mindestzahl ausgegeben ? +                jb      InLoop          ; nein-->weiter +                or      ax,ax           ; ansonsten: 0 ? +                jnz     InLoop          ; nein, weitermachen + +                shr     cx,8            ; effektive Zahl nach CX +OLoop:          pop     dx              ; ein Zeichen runterholen +                add     dl,'0'          ; in ASCII konvertieren +                mov     ah,DOS_WrChar   ; ber DOS ausgeben +                int     INT_DOS +                loop    OLoop + +                pop     dx +                pop     cx +                pop     di              ; Register zurck +                ret + +                endp + +;****************************************************************************** +;* vorzeichenlose Zahl hexadezimal ausgeben                                   * +;*              In  :   AX = Zahl                                             * +;*                      CL = min. Stellenzahl                                 * +;****************************************************************************** + +                globproc WriteHex + +                push    di              ; Register retten +                push    cx +                push    dx + +                mov     ch,0            ; CH z„hlt effektive Zeichenzahl +InLoop:         sub     dx,dx           ; Stellendivision +                mov     di,16           ; gewnschtes Zahlensystem +                div     di +                mov     di,ax           ; war es vorher 0 ? +                or      di,dx           ; (wenn Quotient & Rest 0) +                jnz     NZero           ; nein-->normal ausgeben +                or      ch,ch           ; noch erste Stelle ? +                jz      NZero           ; dann auf jeden Fall 0 ausgeben +                mov     dl,0f0h         ; ansonsten Leerzeichen fr leading 0 +NZero:          push    dx              ; Zeichen speichern... +                inc     ch              ; ...und mitz„hlen +                cmp     ch,cl           ; Mindestzahl ausgegeben ? +                jb      InLoop          ; nein-->weiter +                or      ax,ax           ; ansonsten: 0 ? +                jnz     InLoop          ; nein, weitermachen + +                shr     cx,8            ; effektive Zahl nach CX +OLoop:          pop     dx              ; ein Zeichen runterholen +                add     dl,'0'          ; in ASCII konvertieren +                cmp     dl,'9' +                jbe     NoHex +                add     dl,7 +NoHex:          mov     ah,DOS_WrChar   ; ber DOS ausgeben +                int     INT_DOS +                loop    OLoop + +                pop     dx +                pop     cx +                pop     di              ; Register zurck +                ret + +                endp + +;***************************************************************************** +;* Routine GeometryDefined - stellt fest, ob Geometrie fr ei Laufwerk defi- * +;* niert ist                                                                 * +;* Eingabe:     AL = Laufwerksnummer                                         * +;* Ausgabe:     C  = 0, falls OK                                             * +;***************************************************************************** + +                proc    GeometryDefined + +                push    di              ; Register retten +                call    GetPTabAdr      ; Tabellenadresse bilden +                cmp     word ptr[di+DrPar_Cyls],0 ; Zylinderzahl 0 ? +                stc +                je      Fin +                cmp     byte ptr[di+DrPar_Heads],0 ; Kopfzahl 0 ? +                stc +                je      Fin +                cmp     byte ptr[di+DrPar_NSecs],0 ; Sektorzahl 0 ? +                stc +                je      Fin +                clc                     ; alles OK +Fin:            pop     di              ; Register zurck +                ret + +                endp + +;***************************************************************************** +;* Routine QueryRedefine - fragt nach, ob Geometrie neu definert werden soll * +;* Eingabe:     AL = Laufwerk                                                * +;* Ausgabe:     C = 0, falls ja                                              * +;***************************************************************************** + +                proc    QueryRedefine + +                add     al,'1'          ; Laufwerksnummer in ASCII umrechnen +                mov     [UndefMsg2],al  ; in Meldung einschreiben +                PrMsg   UndefMsg +                PrMsg   DoQueryMsg      ; nachfragen, ob Definition erwnscht +                call    YesNo +                ret + +UndefMsg        db      "Geometrie fr Laufwerk " +UndefMsg2       db      "  undefiniert.",CR,LF,"$" +DoQueryMsg      db      "Geometrie neu definieren ? $" + +                endp + +;***************************************************************************** +;* Routine ReadGeomety - liest Laufwerksgeometrie vom Benutzer ein           * +;* Eingabe:     AL = phys. Laufwerksnummer                                   * +;***************************************************************************** + +                proc    ReadGeometry + +                push    ax              ; Register retten +                push    si +                push    di + +                call    GetPTabAdr      ; Zeiger auf Parametertabelle holen +                mov     si,di + +                lea     di,[CylInpMsg]  ; Zylinderzahl erfragen +                mov     ax,1024 +                call    ReadNumber +                mov     [si+DrPar_Cyls],ax + +                lea     di,[HeadInpMsg] ; Kopfzahl erfragen +                mov     ax,16 +                call    ReadNumber +                mov     [si+DrPar_Heads],al + +                lea     di,[RWCInpMsg]  ; RWC-Zylinder erfragen +                mov     ax,65535 +                call    ReadNumber +                mov     [si+DrPar_RedWr],ax + +                lea     di,[PreInpMsg]  ; Pr„kompensations-Zylinder erfragen +                mov     ax,65535 +                call    ReadNumber +                mov     [si+DrPar_PrComp],ax + +                lea     di,[ECCInpMsg]  ; ECC-L„nge erfragen +                mov     ax,11 +                call    ReadNumber +                mov     [si+DrPar_ECCLen],ax + +                mov     al,[si+DrPar_Heads] ; Steuerbyte Bit 3=1, falls Platte +                dec     al +                and     al,8            ; mehr als 8 K”pfe hat +                mov     [si+DrPar_CByte],al + +                mov     al,0            ; Timeouts unbenutzt +                mov     [si+DrPar_TOut],al +                mov     [si+DrPar_FTOut],al +                mov     [si+DrPar_CTOut],al + +                mov     ax,[si+DrPar_Cyls] ; Parkzylinder=Zylinderzahl+1 +                inc     ax +                mov     [si+DrPar_LZone],ax + +                lea     di,[SecInpMsg]  ; Sektorzahl erfragen +                mov     ax,255 +                call    ReadNumber +                mov     [si+DrPar_NSecs],al + +                pop     di              ; Register zurck +                pop     si +                pop     ax +                ret + +CylInpMsg       db      "Anzahl Zylinder (max. 1024) : $" +HeadInpMsg      db      "Anzahl K”pfe (max. 16) : $" +RWCInpMsg       db      "Startzylinder fr reduzierten Schreibstrom (max. 65535) : $" +PreInpMsg       db      "Startzylinder fr Pr„kompensation (max. 65535) : $" +ECCInpMsg       db      "max. ECC-Fehlerburstl„nge (5 oder 11) : $" +SecInpMsg       db      "Sektorzahl (max. 255) : $" + +                endp + +;***************************************************************************** +;* Routine WriteGeoToDisk - schreibt Laufwerksgeometrie auf Platte           * +;* Eingabe:     AL = phys. Laufwerksnummer                                   * +;* Ausgabe:     C+AX = Fehlerstatus                                          * +;***************************************************************************** + +                proc    WriteGeoToDisk + +                push    bx              ; Register retten +                push    cx +                push    dx +                push    si +                push    di +                push    es + +                mov     dx,ds           ; alles im folgenden im Datensegment +                mov     es,dx + +                mov     dl,al           ; Laufwerksnummer retten +                mov     ah,0            ; Kopf 0, +                sub     bx,bx           ; Spur 0, +                mov     cx,0101h        ; Sektor 1 lesen +                lea     di,[SectorBuffer] +                call    ReadSectors +                jc      GeoError        ; Abbruch bei Fehler + +                mov     al,dl           ; Geometrietabelle adressieren +                call    GetPTabAdr +                mov     si,di           ; selbige in MBR einschreiben +                lea     di,[SectorBuffer+DrPar_Offset] +                mov     cx,DrPar_Len/2 +                cld +                rep     movsw + +                mov     al,dl           ; jetzt den ganzen Kram zurckschreiben +                mov     ah,0 +                sub     bx,bx +                mov     cx,0101h +                lea     si,[SectorBuffer] +                call    WriteSectors +                jc      GeoError + +Fin:            pop     es              ; Register zurck +                pop     di +                pop     si +                pop     dx +                pop     cx +                pop     bx +                ret + +GeoError:       mov     ah,bl           ; Fehlerausgabe +                call    WrErrorCode +                jmp     Fin + +                endp + +;***************************************************************************** +;* Routine QueryParams                                                       * +;* Eingabe:     AL = Laufwerksnummer                                         * +;*              AH = 1, falls Rckschreiben erlaubt                          * +;* Ausgabe:     AL = 0: Laufwerk vergessen                                   * +;*              AL = 1: Mastersektor neu lesen                               * +;*              AL = 2: Tabelle nur transient eingetragen, kein Neulesen     * +;***************************************************************************** + +                globproc QueryParams + +                push    bx              ; Register retten +                push    cx +                push    dx +                push    si +                push    di +                push    es + +                mov     bx,ax           ; Laufwerksnummer retten +                call    QueryRedefine   ; nachfragen, ob Neudefinition erwnscht +                mov     al,0            ; Abbruch bei Nein +                ljc     Terminate + +                mov     al,bl           ; Geometrie einlesen +                call    ReadGeometry + +                shr     bh,1            ; Rckschreiben erlaubt ? +                cmc                     ; C=1-->verboten +                jc      NoWriteBack + +                PrMsg   WriteBackMsg    ; nachfragen, ob Rckschreiben erwnscht +                call    YesNo +NoWriteBack:    mov     al,2            ; Neulesen bei Nein verhindern +                jc      Terminate + +                mov     al,bl +                call    WriteGeoToDisk +                jc      WrError + +                mov     al,1            ; Ergebnis: MBR-Lesen wiederholen +                jmp     Terminate +WrError:        mov     al,0            ; Schreibfehler: Laufwerk ignorieren + +Terminate:      pop     es              ; Register zurck +                pop     di +                pop     si +                pop     dx +                pop     cx +                pop     bx + +                ret + +WriteBackMsg    db      "Parametersatz zurckschreiben ? $" + +                endp + +;**************************************************************************** +;* Laufwerksnummer einlesen                                                 * +;* Ausgabe:     AL = Laufwerksnummer                                        * +;**************************************************************************** + +                proc    InputDrive + +                push    dx              ; Register retten + +RdLoop:         PrMsg   PromptMsg       ; Anfrage ausgeben +                mov     ah,DOS_RdChar   ; ein Zeichen holen +                int     INT_DOS +                mov     dl,al           ; Zeichen retten +                PrChar  dl              ; Laufwerk als Echo zurckgeben +                PrChar  CR +                PrChar  LF +                sub     dl,'1'          ; nur 1 oder 2 erlaubt +                jc      RdLoop +                cmp     dl,MaxPDrives +                jae     RdLoop +                mov     al,dl           ; Laufwerk in AL zurckgeben + +                pop     dx              ; Register zurck +                ret + +PromptMsg       db      "Laufwerksnummer (1 oder 2) : $" + +                endp + +;**************************************************************************** +;* Men fr Plattenfunktionen                                               * +;**************************************************************************** + +                proc    SelectDisk + +                push    ax              ; Register sichern +                push    bx +                push    cx +                push    dx +                push    si +                push    di +                push    es + +                mov     dh,ah           ; Rckschreibeflag sichern +                call    InputDrive +                mov     dl,al           ; Laufwerksnummer sichern + +                mov     al,dl           ; Geometrie noch undefiniert ? +                call    GeometryDefined +                jnc     IsOK            ; Nein, alles in Butter + +                mov     al,dl           ; nicht definiert: versuchen, +                mov     ah,0            ; Geometrie vom MBR zu lesen +                mov     bx,ds +                mov     es,bx +                sub     bx,bx +                mov     cx,0101h +                lea     di,[SectorBuffer] +                call    ReadSectors +                jnc     CopyTable       ; kein Fehler->Tabelle auslesen +                mov     dh,0            ; wenn Fehler, nie zurckschreiben +                jmp     ReadManual      ; und manuell probieren +CopyTable:      lea     si,[SectorBuffer+DrPar_Offset] +                mov     al,dl +                call    GetPTabAdr +                mov     cx,DrPar_Len/2 +                cld +                rep     movsw +                mov     al,dl           ; Geometrie jetzt da ? +                call    GeometryDefined +                jnc     IsOK            ; falls ja, Ende + +ReadManual:     mov     al,dl           ; fragen, ob Redefinition erwnscht +                call    QueryRedefine +                jc      NotOK           ; falls nein, Abbruch +                mov     al,dl           ; ansonsten einlesen +                call    ReadGeometry +                shr     dh,1            ; zurckschreiben ? +                jnc     IsOK +                mov     al,dl           ; ja... +                call    WriteGeoToDisk  ; Fehler ignorieren + +IsOK:           mov     [MomDrive],dl   ; Laufwerk akzeptiert + +NotOK:          pop     es              ; Register zurck +                pop     di +                pop     si +                pop     dx +                pop     cx +                pop     bx +                pop     ax + +                ret + +                endp + +;---------------------------------------------------------------------------- + +                proc    ChangeGeometry + +                cmp     [MomDrive],-1   ; Laufwerk berhaupt schon definiert ? +                jne     DriveDefined +                call    InputDrive      ; nein: lesen & einschreiben +                mov     [MomDrive],al +DriveDefined:   mov     al,[MomDrive]   ; neue Geometrie einlesen +                call    ReadGeometry +                mov     al,[MomDrive] +                call    WriteGeoToDisk  ; die auch gleich zu schreiben versuchen + +                ret + +                endp + +;---------------------------------------------------------------------------- + +                proc    VerifyDisk + +                pusha                   ; restlos alles... + +                mov     al,[MomDrive]   ; erstmal sicherstellen, daá der +                call    SetDriveParams  ; Kontroller die Geometrie kennt + +                mov     al,[MomDrive]   ; die Geometrie brauchen wir auch +                call    GetPTabAdr + +                PrMsg   ESCMsg +                sub     bp,bp           ; Fehlerz„hler +                mov     si,bp           ; Zylinderz„hler +                mov     dx,bp           ; Folgefehlerz„hler +CylLoop:        mov     dl,0            ; Kopfz„hler +HeadLoop:       PrMsg   CylMsg          ; zu testende Spur ausgeben +                mov     ax,si +                mov     cl,4 +                call    WriteDec +                PrMsg   HeadMsg +                mov     al,dl +                mov     ah,0 +                mov     cl,2 +                call    WriteDec +                PrChar  CR + +                mov     al,[MomDrive]   ; eine Spur testen +                mov     ah,dl +                mov     bx,si +                mov     cl,[di+DrPar_NSecs] +                mov     ch,1 +                call    VeriSectors + +                jnc     NoError         ; evtl. Fehlerbehandlung +                push    ax +                PrChar  LF +                pop     ax +                mov     ah,[MomDrive] +                call    WrErrorCode +                inc     bp              ; Fehlerz„hler rauf +                inc     dh +                test    dh,7            ; alle 8 Fehler in Reihe nachfragen +                jnz     NextTrack +                PrMsg   GoOnMsg +                call    YesNo +                jc      Terminate +                jmp     NextTrack +NoError:        mov     dh,0            ; eine Spur gut->Folgenz„hler l”schen +NextTrack:      call    BreakONESC      ; Abbruch ? +                jc      Terminate +                inc     dl              ; n„chster Kopf +                cmp     dl,[di+DrPar_Heads] +                jb      HeadLoop +                inc     si              ; n„chster Zylinder +                cmp     si,[di+DrPar_Cyls] +                ljb     CylLoop + +Terminate:      mov     ax,bp           ; Fehlerzahl ausgeben +                mov     cl,5 +                call    WriteDec +                PrMsg   ErrorMsg + +                popa                    ; Register zurck + +                ret + +EscMsg          db      "Verifizieren..",CR,LF,"Abbruch mit <ESC>",CR,LF,'$' +CylMsg          db      "Zylinder $" +HeadMsg         db      ", Kopf $" +GoOnMsg         db      "Test fortsetzen? $" +ErrorMsg:       db      " Fehler gefunden     ",CR,LF,'$' + +                endp + +;---------------------------------------------------------------------------- + +                proc    FormatDisk + +                push    ax              ; Register retten +                push    bx +                push    cx +                push    di +                push    es + +                mov     al,[MomDrive]   ; erstmal sicherstellen, daá der +                call    SetDriveParams  ; Kontroller die Geometrie kennt + +                mov     al,[MomDrive] +                call    GetPTabAdr +InterLoop:      mov     al,[di+DrPar_NSecs] ; Maximum=Sektorzahl-1 +                dec     al +                mov     ah,0 +                lea     di,[InterleaveMsg] ; Interleave erfragen +                call    ReadNumber +                or      ax,ax           ; Null wollen wir nicht +                jz      InterLoop +                mov     bl,al           ; Interleave retten +                PrMsg   ConfirmMsg      ; sicherheitshalber nachfragen +                call    YesNo +                jc      Fin +                PrMsg   NewLine +                PrMsg   FormatMsg +                mov     ah,bl           ; Interleave zurck +                mov     al,[MomDrive] +                call    FormatUnit +                jc      FormatError     ; Fehler beim Formatieren ? + +NoFormatError:  PrMsg   WriteMsg +                lea     di,[SectorBuffer] ; MBR erzeugen +                cld +                mov     cx,SecSize/2-1  ; letztes Wort anders! +                mov     ax,ds +                mov     es,ax +                sub     ax,ax           ; prinzipiell erstmal alles Nullen +                rep     stosw +                mov     word ptr[di],0aa55h ; Gltigkeitsflag am Ende +                mov     al,[MomDrive]   ; Geometrietabelle eintragen +                call    GetPTabAdr +                mov     si,di +                lea     di,[SectorBuffer+DrPar_Offset] +                mov     cx,DrPar_Len/2 +                rep     movsw +                mov     al,[MomDrive]   ; Sektor schreiben +                mov     ah,0            ; MBR auf Kopf 0, +                mov     bx,0            ; Spur 0, +                mov     cx,0101h        ; Sektor 1 +                lea     si,[SectorBuffer] +                call    WriteSectors +                jc      FormatError     ; Fehler beim Schreiben ? + +Fin:            pop     es              ; Register zurck +                pop     di +                pop     cx +                pop     bx +                pop     ax +                ret + +FormatError:    cmp     al,DErr_UserTerm ; Abbruch durch Benutzer ? +                je      Fin             ; dann nicht meckern +                push    ax              ; Fehlercode retten +                pushf +                PrMsg   NewLine +                popf +                pop     ax +                mov     ah,[MomDrive]   ; Fehlermeldung ausgeben +                call    WrErrorCode +                jmp     Fin + +FormatMsg        db     "Formatieren...",CR,LF,'$' +WriteMsg         db     "MBR schreiben...",CR,LF,'$' + +                endp + +;---------------------------------------------------------------------------- + +                proc    BadTrack + +                push    bx +                push    si +                push    di + +                mov     al,[MomDrive]   ; Zeiger auf Geometrietabelle +                call    GetPTabAdr      ; holen +                mov     si,di + +                lea     di,[TrackMsg]   ; Spurnummer abfragen +                mov     ax,[si+DrPar_Cyls] +                dec     ax +                call    ReadNumber +                mov     bx,ax +                lea     di,[HeadMsg]    ; Kopfnummer abfragen +                mov     ax,[si+DrPar_Heads] +                dec     ax +                call    ReadNumber +                mov     ah,al +                push    ax              ; sicherheitshalber noch best„tigen +                PrMsg   ConfirmMsg +                call    YesNo +                pop     ax +                jc      NoError +                mov     al,[MomDrive]   ; Spur markieren +                call    MarkBad       +                jnc     NoError +                push    ax              ; Fehlercode retten +                pushf +                PrMsg   NewLine +                popf +                pop     ax +                mov     ah,[MomDrive] +                call    WrErrorCode +NoError: +                pop     di +                pop     si +                pop     bx + +                ret + +                endp + +;---------------------------------------------------------------------------- + +                proc    FormTrack + +                push    bx +                push    si +                push    di + +                mov     al,[MomDrive]   ; Zeiger auf Geometrietabelle +                call    GetPTabAdr      ; holen +                mov     si,di + +                lea     di,[TrackMsg]   ; Spurnummer abfragen +                mov     ax,[si+DrPar_Cyls] +                dec     ax +                call    ReadNumber +                mov     bx,ax +                lea     di,[HeadMsg]    ; Kopfnummer abfragen +                mov     ax,[si+DrPar_Heads] +                dec     ax +                call    ReadNumber +                mov     ah,al +                push    ax              ; Kopf retten +InterLoop:      mov     al,[si+DrPar_NSecs] ; Interleave-Maximum=Sektorzahl-1 +                dec     al +                mov     ah,0 +                lea     di,[InterleaveMsg] ; Interleave erfragen +                call    ReadNumber +                or      ax,ax           ; Null wollen wir nicht +                jz      InterLoop +                mov     cl,al           ; Interleave passend ablegen +                PrMsg   ConfirmMsg      ; nochmal nachfragen +                call    YesNo +                pop     ax +                jc      NoError +                mov     al,[MomDrive]   ; Kopf zurck +                call    FormatTrack +                jnc     NoError +                push    ax              ; Fehlercode retten +                pushf +                PrMsg   NewLine +                popf +                pop     ax +                mov     ah,[MomDrive] +                call    WrErrorCode +NoError: +                pop     di +                pop     si +                pop     bx + +                ret + +                endp + +;---------------------------------------------------------------------------- + +; packt eine Sektorkoordinate ins BIOS-Format +; -->Zylinder=BX, Kopf=AH, Sektor=AL +; <--Zylinder/Sektor=BX, Kopf=AH + +                proc    PackCoordinate + +                shl     bh,6 +                or      bh,al +                xchg    bl,bh +                ret + +                endp + +                proc    UnpackCoordinate + +                xchg    bh,bl           ; Zylinderbytes in richtige Reihenfolge +                mov     al,bh           ; Sektor ausmaskieren +                and     al,00111111b +                shr     bh,6            ; Zylinder korrigieren + +                ret + +                endp + +; berechnet aus einer Sektorkoordinate die lineare Sektornummer +; -->Zylinder/Sektor=BX, Kopf=AH, Geometriezeiger=SI +; <--Sektornummer=DX/AX + +                proc    LinearizeCoordinate + +                push    bx +                push    cx + +                mov     cx,ax           ; Kopf retten +                mov     al,bh           ; Zylinder rekonstruieren +                mov     ah,bl +                shr     ah,6 +                mov     dl,[si+DrPar_Heads] +                mov     dh,0 +                mul     dx              ; = Anzahl Spuren bis Zylinderbeginn +                add     al,ch           ; Startkopf dazuaddieren +                adc     ah,0            ; bisher hoffentlich nur 16 Bit... +                mov     dl,[si+DrPar_NSecs] +                mov     dh,0 +                mul     dx              ; = Anzahl Spuren bis Spurbeginn +                and     bl,3fh          ; letztendlich Sektor-1 dazu +                dec     bl +                add     al,bl +                adc     ah,0 +                adc     dx,0 + +                pop     cx +                pop     bx + +                ret + +                endp + +                proc    MakePart + +                push    bx +                push    cx +                push    dx +                push    si +                push    di +                push    es + +                PrMsg   ConfirmMsg      ; sind wir sicher ? +                call    YesNo +                ljc     End + +                mov     al,[MomDrive]   ; Laufwerk rekalibrieren +                call    Recalibrate +                ljc     PartError + +                mov     al,[MomDrive]   ; alten MBR auslesen +                mov     ah,0 +                mov     bx,0 +                mov     cx,0101h +                mov     si,ds +                mov     es,si +                lea     di,[SectorBuffer] +                call    ReadSectors +                ljc     PartError + +                mov     al,[MomDrive]   ; Plattengeometrie holen +                call    GetPTabAdr +                mov     si,di + +                lea     di,[SectorBuffer+ParTab_Offset] ; an erste Tabelle schreiben +                mov     byte ptr [di+ParTab_BFlag],80h ; Partition aktiv +                cmp     byte ptr[si+DrPar_Heads],1 ; nur ein Kopf ? +                ja      MoreHeads +                mov     bx,1            ; ja: Start auf Zyl. 1, Kopf 0 +                mov     ah,0 +                jmp     WriteStart +MoreHeads:      sub     bx,bx           ; nein: Start auf Zyl. 0, Kopf 1 +                mov     ah,1 +WriteStart:     mov     al,01h          ; Startsektor immer 1 +                call    PackCoordinate +                mov     [di+ParTab_FHead],ah +                mov     [di+ParTab_FSecCyl],bx +                call    LinearizeCoordinate ; linearen Start schreiben +                mov     [di+ParTab_LinSec],ax +                mov     [di+ParTab_LinSec+2],dx +                push    dx +                push    ax +                mov     bx,[si+DrPar_Cyls] ; Ende: Zylinder n-2, Kopf n-1, Sektor n +                sub     bx,2 +                mov     ah,[si+DrPar_Heads] +                dec     ah +                mov     al,[si+DrPar_NSecs] +                call    PackCoordinate +                mov     [di+ParTab_LHead],ah +                mov     [di+ParTab_LSecCyl],bx +                call    LinearizeCoordinate ; Sektorzahl berechnen +                pop     bx              ; dazu Start abziehen +                sub     ax,bx +                pop     bx +                sbb     dx,bx +                add     ax,1            ; !!! L„nge=Stop-Start+1 +                adc     dx,0 +                mov     [di+ParTab_NSecs],ax +                mov     [di+ParTab_NSecs+2],dx +                or      dx,dx            ; falls >64K Sektoren, +                jz      NoBigDOS        ; eine BigDOS-Partition +                mov     bl,6 +                jmp     TypeFound +NoBigDOS:       cmp     ax,32679        ; ab 32680 Sektoren 16-Bit-FAT +                jb      NoFAT16 +                mov     bl,04 +                jmp     TypeFound +NoFAT16:        mov     bl,1            ; kleine 12-Bit-Partition +TypeFound:      mov     [di+ParTab_Type],bl +                add     di,ParTab_Len   ; die anderen 3 Partitionen l”schen +                mov     cx,3*(ParTab_Len/2) +                sub     ax,ax +                cld +                rep     stosw + +                mov     al,[MomDrive]   ; neuen MBR schreiben +                mov     ah,0 +                mov     bx,0 +                mov     cx,0101h +                lea     si,[SectorBuffer] +                call    WriteSectors +                ljc     PartError + +End:            pop     es +                pop     di +                pop     si +                pop     dx +                pop     cx +                pop     bx + +                ret + +PartError:      push    ax              ; Fehlercode retten +                pushf +                PrMsg   NewLine +                popf +                pop     ax +                mov     ah,[MomDrive]   ; Fehlermeldung ausgeben +                call    WrErrorCode +                jmp     End + +ConfirmMsg:     db      "ACHTUNG! Alle bisherigen Partitionen auf der",CR,LF +                db      "Festplatte werden gel”scht! Fortfahren? $" + +                endp + +;---------------------------------------------------------------------------- + +                proc    FormatPart + +                pusha + +                mov     ax,ds           ; wir arbeiten nur im Datensegment +                mov     es,ax + +                PrMsg   ConfirmMsg      ; vorher nachfragen +                call    YesNo +                ljc     Ende + +                mov     al,[MomDrive]   ; Laufwerk rekalibrieren +                call    Recalibrate +                ljc     LFormError + +; Schritt 1: MBR lesen + +                mov     al,[MomDrive]   ; MBR auslesen, um Partitions- +                mov     ah,0            ; daten zu bekommen +                mov     bx,0 +                mov     cx,0101h +                lea     di,[SectorBuffer] +                call    ReadSectors +                ljc     LFormError + +; Schritt 2: Partitionsdaten in BPB kopieren + +                lea     di,[SectorBuffer+ParTab_Offset] ; auf Partitionsdaten +                mov     al,[di+ParTab_Type] ; muá prim„re Partition sein +                cmp     al,1            ; DOS 2.x FAT12? +                je      ParTypeOK +                cmp     al,4            ; DOS 3.x FAT16? +                je      ParTypeOK +                cmp     al,6            ; DOS 4.x BIGDOS? +                je      ParTypeOK +                PrMsg   InvParTypeMsg   ; nichts dergleichen: Abbruch +                jmp     Ende +ParTypeOK:      mov     word ptr[BPB_SysID],'AF' ; FAT-Kennung in BPB eintragen +                mov     word ptr[BPB_SysID+2],'1T' ; FAT12/FAT16 +                mov     word ptr[BPB_SysID+5],'  ' +                mov     ah,'2'          ; Annahme FAT12 +                cmp     al,1 +                je      ParIsFAT12      ; wenn Typ=1, OK +                mov     ah,'6'          ; ansonsten FAT16 +ParIsFAT12:     mov     byte ptr[BPB_SysID+4],ah +                mov     ax,[di+ParTab_NSecs] ; Sektorzahl in BPB schreiben +                mov     dx,[di+ParTab_NSecs+2] +                mov     word ptr[BPB_NumSecs32],ax +                mov     word ptr[BPB_NumSecs32+2],dx +                or      dx,dx           ; falls < 64K Sektoren, +                jz      ParIsNotBig     ; Gr”áe auch unten eintragen, +                sub     ax,ax           ; ansonsten 0 +ParIsNotBig:    mov     [BPB_NumSecs16],ax +                mov     ax,word ptr[di+ParTab_LinSec] ; Startsektor umkopieren +                mov     dx,word ptr[di+ParTab_LinSec+2] +                mov     word ptr[BPB_LinStart],ax +                mov     word ptr[BPB_LinStart+2],dx + +; Schritt 3: Partitionsdaten in Partitionstabelle kopieren, damit wir die +; linearen Schreib/Lesefunktionen nutzen k”nnen + +                mov     [DrCnt],1       ; nur ein Laufwerk belegt +                mov     ah,[di+ParTab_FHead] ; Startkoordinate ablegen +                mov     bx,[di+ParTab_FSecCyl] +                call    UnpackCoordinate +                mov     [DrTab+DrTab_StartHead],ah +                mov     word ptr [DrTab+DrTab_StartCyl],bx +                mov     [DrTab+DrTab_StartSec],al +                mov     ax,[di+ParTab_LinSec] +                mov     word ptr [DrTab+DrTab_LinStart],ax +                mov     ax,[di+ParTab_LinSec+2] +                mov     word ptr [DrTab+DrTab_LinStart+2],ax +                mov     ax,[di+ParTab_NSecs] +                mov     word ptr [DrTab+DrTab_SecCnt],ax +                mov     ax,[di+ParTab_NSecs+2] +                mov     word ptr [DrTab+DrTab_SecCnt+2],ax +                mov     al,[MomDrive]   ; Laufwerk einschreiben +                mov     [DrTab+DrTab_Drive],al +                mov     byte ptr[DrTab+DrTab_BPB],0 ; kein BPB + +; Schritt 4: konstante Felder in BPB eintragen + +                mov     [BPB_SecSize],SecSize ; Sektorgr”áe konstant 512 Byte +                mov     [BPB_ResvdSecs],1 ; nur Bootsektor reserviert +                mov     [BPB_NumFATs],2 ; 2 FATs ist DOS-Standard +                mov     [BPB_MediaID],0f8h ; Media-Byte fr Platten konstant +                mov     al,[MomDrive] +                call    GetPTabAdr +                mov     ah,0 +                mov     al,[di+DrPar_NSecs]; Plattenzylinder und -k”pfe +                mov     [BPB_SecsPerTrk],ax +                mov     al,[di+DrPar_Heads] +                mov     [BPB_Heads],ax +                mov     al,[MomDrive]   ; Plattennummer+80h +                add     al,80h +                mov     [BPB_PhysNo],ax +                mov     [BPB_ExtID],29h ; Erkennung, daá erw. BPB gltig +                mov     ah,0            ; Seriennummer=Uhrzeit +                int     INT_Clock +                mov     word ptr[BPB_SerialNo],cx +                mov     word ptr[BPB_SerialNo+2],dx +                lea     di,[BPB_Name]   ; Name ist leer +                mov     cx,11 +                mov     al,' ' +                cld +                rep     stosb + +; Schritt 5: einige Sachen vom Anwender erfragen + +DirEntLoop:     mov     ax,1024         ; mehr ist wohl kaum sinnvoll +                lea     di,[DirEntriesMsg] +                call    ReadNumber +                cmp     ax,SecSize/32   ; weniger als ein Sektor ergibt +                jb      DirEntLoop      ; keinen Sinn +                mov     [BPB_DirLen],ax ; Anzahl in BPB eintragen +                mov     dx,0            ; Directory-Sektorzahl berechnen +                mov     bx,SecSize/32 +                div     bx +                or      dx,dx           ; ggfs. aufrunden +                jz      DirLenEven +                inc     ax +DirLenEven:     mov     [DirLen],ax + +; Schritt 6: Clusterl„nge berechnen + +                mov     ax,word ptr[BPB_NumSecs32]  ; # Sektoren in Datenfeld +                mov     dx,word ptr[BPB_NumSecs32+2] ; und FATs berechnen +                sub     ax,[BPB_ResvdSecs] +                sbb     dx,0 +                sub     ax,[DirLen] +                sbb     dx,0 +                mov     bl,1 ; Annahme: m”glichst wenig Sektoren pro Cluster +ClusterLoop:    or      dx,dx           ; wenn noch mehr als 64K Cluster, +                jnz     ClusterNxtLoop  ; auf jeden Fall zu groá +                cmp     ax,4080         ; bei weniger als 4K Clustern +                jb      ClusterEndLoop  ; auf jeden Fall OK +                cmp     [BPB_SysID+4],'2' ; sonst bei FAT12 +                je      ClusterNxtLoop  ; auf jeden Fall zu viel +                cmp     ax,65510        ; bei FAT16 Vergleich auf 64K +                jb      ClusterEndLoop +ClusterNxtLoop: shl     bl,1            ; zu viel: Cluster verdoppeln +                js      ClusterEndLoop  ; bei 128 Sektoren/Cluster abbrechen +                shr     dx,1            ; Clusterzahl halbiert sich +                rcr     ax,1 +                jmp     ClusterLoop +ClusterEndLoop: mov     [BPB_SecsPerClust],bl ; Ergebnis einschreiben +                add     ax,2            ; Dummy-Eintr„ge in FAT +                adc     dx,0 +                mov     bx,341          ; Anzahl FAT-Sektoren berechnen +                cmp     [BPB_SysID+4],'2' +                jz      Cluster12 +                mov     bx,256 +Cluster12:      div     bx +                or      dx,dx           ; Sektorzahl aufrunden +                jz      FATLenEven +                inc     ax +FATLenEven:     mov     [BPB_SecsPerFAT],ax ; Anzahl FAT-Sektoren einschreiben + +; Schritt 7: Bootsektor aufbauen + +                PrMsg   WrBootSectMsg +                lea     di,[SectorBuffer] +                cld +                mov     al,0ebh         ; Dummy-Sprung einschreiben +                stosb +                mov     al,0feh +                stosb +                mov     al,90h +                stosb +                mov     ax,'ES'         ; OEM-ID einschreiben +                stosw +                mov     ax,'DC' +                stosw +                mov     ax,'IR' +                stosw +                mov     ax,'EV' +                stosw +                lea     si,[BPBBuffer]  ; BPB einschreiben +                mov     cx,BPB_Length +                rep     movsb +                mov     cx,SectorBuffer+SecSize ; Rest vom Bootsektor nullen +                sub     cx,di +                mov     al,0 +                rep     stosb +                mov     ax,0            ; Bootsektor ist log. Sektor 0 +                mov     dx,ax +                mov     bl,0            ; Partition 0 +                call    TranslateParams +                mov     cl,1            ; nur ein Sektor +                lea     si,[SectorBuffer] +                call    WriteSectors +                ljc     LFormError + +; Schritt 8: Directory & FATs ausnullen + +                lea     di,[SectorBuffer] ; Sektorpuffer wird benutzt +                mov     cx,SecSize/2 +                cld +                sub     ax,ax +                rep     stosw +                PrMsg   WrFATMsg +                mov     ax,[BPB_ResvdSecs] ; Startsektor FATs holen +                sub     dx,dx +                lea     si,[SectorBuffer] +                mov     cx,[BPB_SecsPerFAT] +                add     cx,cx           ; beide FATs nullen +FATZeroLoop:    push    ax              ; Sektornummer und -zahl retten +                push    cx +                push    dx +                mov     bl,0 +                call    TranslateParams +                mov     cl,1 +                call    WriteSectors +                pop     dx +                pop     cx +                pop     ax +                ljc     LFormError +                add     ax,1            ; n„chster Sektor +                adc     dx,0 +                loop    FATZeroLoop +                push    ax              ; !!! PrMsg zerst”rt AX-Register +                PrMsg   WrDirMsg +                pop     ax +                mov     cx,[DirLen]     ; dito fr Directory +DirZeroLoop:    push    ax               +                push    cx +                push    dx +                mov     bl,0 +                call    TranslateParams +                mov     cl,1 +                call    WriteSectors +                pop     dx +                pop     cx +                pop     ax +                ljc     LFormError +                add     ax,1            ; n„chster Sektor +                adc     dx,0 +                loop    DirZeroLoop + +; Schritt 9: Sektoren testen und FAT initialisieren + +                mov     ax,[BPB_ResvdSecs] ; Datensektorbeginn berechnen +                sub     dx,dx +                mov     [FAT1Pos],ax    ; Beginn 1. FAT hinter Bootsektor +                mov     [FAT1Pos+2],dx +                add     ax,[BPB_SecsPerFAT] ; Beginn 2. FAT hinter 1. FAT +                adc     dx,0 +                mov     [FAT2Pos],ax +                mov     [FAT2Pos+2],dx +                add     ax,[BPB_SecsPerFAT] +                adc     dx,0 +                add     ax,[DirLen]     ; Datenbeginn hinter Directory +                adc     dx,0 +                mov     [DataPos],ax    ; diesen Startsektor retten +                mov     [DataPos+2],dx + +                mov     ax,word ptr[BPB_NumSecs32] ; Anzahl Cluster berechnen +                mov     dx,word ptr[BPB_NumSecs32+2] +                sub     ax,[DataPos] +                sbb     dx,[DataPos+2] +                mov     bl,[BPB_SecsPerClust]      ; / SecsPerCluster +                mov     bh,0 +                div     bx +                mov     [ClusterCnt],ax + +                call    ClearFATBuffer  ; erste Elemente in FAT schreiben +                mov     ah,0ffh +                mov     al,[BPB_MediaID] +                call    WriteFAT +                mov     al,0ffh +                call    WriteFAT +                PrMsg   ESCMsg +                mov     ax,[DataPos]    ; Schleifenvorbereitung +                mov     dx,[DataPos+2] +                mov     cx,[ClusterCnt] +VerifyLoop:     push    ax              ; Z„hler retten +                mov     bp,cx +                push    dx +                mov     bl,0            ; immer Laufwerk 0 +                call    TranslateParams ; Cluster testlesen +                mov     cl,[BPB_SecsPerClust] +                test    bp,15           ; nur alle 16 Cluster schreiben +                jnz     NoWriteVeri +                push    ax              ; Clusternummer ausgeben +                push    cx +                PrMsg   ClusterMsg +                mov     ax,[ClusterCnt] +                sub     ax,bp +                add     ax,2            ; erster Datencluster hat Nummer 2 +                mov     cl,5 +                call    WriteDec +                PrChar  CR +                pop     cx +                pop     ax +NoWriteVeri:    call    VeriSectors +                mov     ax,0            ; Annahme OK (SUB wrde C l”schen...) +                jnc     Verify_OK +                mov     ax,0fff7h +Verify_OK:      call    WriteFAT +                pop     dx              ; Z„hler zurck +                mov     cx,bp +                pop     ax +                add     al,[BPB_SecsPerClust] +                adc     ah,0 +                adc     dx,0 +                call    BreakOnESC      ; Abbruch durch Benutzer ? +                jc      Ende +                loop    VerifyLoop +                cmp     [FATBufferFill],0 ; Puffer rausschreiben +                je      NoFATFlush +                call    FlushFATBuffer +NoFATFlush: + +Ende:           PrMsg   NewLine +                mov     [DrCnt],0       ; sonst kommt jemand ins Schleudern... +                popa +                ret + +LFormError:     push    ax              ; Fehlercode retten +                pushf +                PrMsg   NewLine +                popf +                pop     ax +                mov     ah,[MomDrive]   ; Fehlermeldung ausgeben +                call    WrErrorCode +                jmp     Ende + +WriteFAT:       push    bx              ; einen FAT-Eintrag schreiben +                mov     bx,ax +                call    WriteFATNibble  ; Bit 0..3 schreiben +                mov     al,bl           ; Bit 4..7 schreiben +                shr     al,4 +                call    WriteFATNIbble +                mov     al,bh           ; Bit 8..11 schreiben +                call    WriteFATNibble +                cmp     [BPB_SysID+4],'2' ; evtl. Bit 12..15 schreiben +                je      WriteFAT12 +                mov     al,bh +                shr     al,4 +                call    WriteFATNibble +WriteFAT12:     pop     bx +                ret + +WriteFATNibble: push    bx +                and     al,15           ; Bit 0..3 ausmaskieren +                jz      SkipWriteNibble ; Nullen brauchen wir nicht schreiben +                mov     [MustFlushFAT],1 ; vermerken, daá Puffer nicht genullt ist +                mov     bx,[FATBufferFill]  ; Bit 1.. enthalten Adresse +                shr     bx,1 +                jnc     WriteFATLower   ; oben oder unten schreiben +                shl     al,4 +WriteFATLower:  or      FATBuffer[bx],al +SkipWriteNibble:inc     [FATBufferFill] +                cmp     [FATBufferFill],SecSize*2 ; Sektor voll ? +                jne     WriteFAT_NFlush +                call    FlushFATBuffer +WriteFAT_NFlush:pop     bx +                ret + +FlushFATBuffer: push    bx +                push    cx +                push    dx +                push    si +                cmp     [MustFlushFAT],0 ; nix zu tun ? +                je      SkipFlushDisk +                mov     ax,[FAT1Pos]    ; erste FAT schreiben +                mov     dx,[FAT1Pos+2] +                mov     bl,0 +                call    TranslateParams +                mov     cl,1 +                lea     si,[FATBuffer] +                call    WriteSectors +                mov     ax,[FAT2Pos]    ; zweite FAT schreiben +                mov     dx,[FAT2Pos+2] +                mov     bl,0 +                call    TranslateParams +                mov     cl,1 +                lea     si,[FATBuffer] +                call    WriteSectors +SkipFlushDisk:  call    ClearFATBuffer  ; Zeiger wieder auf 0 +                add     [FAT1Pos],1     ; FAT-Sektornummern weiterz„hlen +                adc     [FAT1Pos+2],0 +                add     [FAT2Pos],1 +                adc     [FAT2Pos+2],0 +                pop     si +                pop     dx +                pop     cx +                pop     bx +                ret + + +ClearFATBuffer: push    cx +                push    di +                cld +                lea     di,[FATBuffer] +                mov     cx,SecSize/2 +                sub     ax,ax +                rep     stosw +                pop     di +                pop     cx +                mov     [FATBufferFill],ax +                mov     [MustFlushFAT],al +                ret + +ConfirmMsg      db      "ACHTUNG! Alle Daten gehen verloren! Fortfahren? $" +InvParTypeMsg   db      CR,LF,"Partition 1 hat ungltigen Typ oder ist undefiniert!",CR,LF,'$' +DirEntriesMsg   db      "Anzahl Eintr„ge im Wurzelverzeichnis (16..1024) : $" +WrBootSectMsg   db      "Schreibe Boot-Sektor...",CR,LF,'$' +WrFATMsg        db      "Initialisiere FATs...",CR,LF,'$' +WrDirMsg        db      "Initialisiere Wurzelverzeichnis...",CR,LF,'$' +ESCMsg          db      "Abbruch mit <ESC>",CR,LF,'$' +ClusterMsg      db      "Teste Cluster $" + +DirLen          dw      ?               ; # Directory-Sektoren +ClusterCnt      dw      ? +FAT1Pos         dw      2 dup (?)       ; speichern Sektorz„hler w„hrend Test +FAT2Pos         dw      2 dup (?) +DataPos         dw      2 dup (?) + +BPBBuffer:                              ; Zwischenspeicher fr BPB +BPB_SecSize     dw      ?               ; Sektorgr”áe in Bytes +BPB_SecsPerClust db     ?               ; Sektoren pro Cluster +BPB_ResvdSecs   dw      ?               ; reservierte Sektoren (Bootsektor) +BPB_NumFATs     db      ?               ; Anzahl FATs +BPB_DirLen      dw      ?               ; Anzahl Eintr„ge im Directory +BPB_NumSecs16   dw      ?               ; Anzahl Sektoren, falls <32 MByte +BPB_MediaID     db      ?               ; Media-Erkennungsbyte +BPB_SecsPerFAT  dw      ?               ; Sektoren pro FAT +BPB_SecsPerTrk  dw      ?               ; Sektoren pro Spur +BPB_Heads       dw      ?               ; Anzahl K”pfe +BPB_LinStart    dd      ?               ; linearer Startsektor auf Laufwerk +BPB_NumSecs32   dd      ?               ; Anzahl Sektoren, falls >=32 MByte +BPB_PhysNo      dw      ?               ; physikalische Laufwerks-Nummer +BPB_ExtID       db      ?               ; Erkennung, daá es ein erweiterter Boot-Record ist +BPB_SerialNo    dd      ?               ; Seriennummer +BPB_Name        db      11 dup (?)      ; Name +BPB_SysID       db      7 dup (?)       ; Systemerkennung +BPB_Length      equ     $-BPBBuffer     ; L„nge BPB + +FATBuffer       db      SecSize dup (?) ; Puffer, um FATs aufzubauen +MustFlushFAT    db      ?               ; Flag, ob FAT-Puffer geschrieben werden muá +FATBufferFill   dw      ?               ; Anzahl Nibbles in FAT-Puffer + +                endp + +;---------------------------------------------------------------------------- + +                globproc DiskMenu + +                push    ax              ; Register retten +                push    cx +                push    di + +                mov     [spsave],sp     ; Stack umschalten +                mov     [sssave],ss +                mov     ax,cs +                mov     ss,ax +                lea     sp,[Stack] + +MenuLoop:       mov     al,[MomDrive]   ; Festplatten-Nr. in Kopfmeldung einschreiben +                add     al,'1' +                cmp     al,'0' +                jnz     DrivePresent    ; falls Laufwerk noch undefiniert, - ausgeben +                mov     al,'-' +DrivePresent:   mov     [MenuMsg_Drv],al +                PrMsg   MenuMsg +                mov     al,[MomDrive] +                cmp     al,-1           ; falls <>-1, Geometrie ausgeben +                je      NoDrivePresent +                call    GetPTabAdr      ; dazu Tabelle holen +                mov     ax,[di+DrPar_Cyls] +                mov     cl,5 +                call    WriteDec +                PrMsg   CylMsg +                mov     al,[di+DrPar_Heads] +                mov     ah,0 +                mov     cl,3 +                call    WriteDec +                PrMsg   HeadMsg +                mov     al,[di+DrPar_NSecs] +                mov     ah,0 +                mov     cl,3 +                call    WriteDec +                PrMsg   SecMsg +NoDrivePresent: +                PrMsg   MenuList +                mov     ah,DOS_RdChar +                int     INT_DOS +                push    ax +                PrChar  al +                PrMsg   TwoLines +                pop     ax + +                cmp     al,'0'          ; 0 = Men verlassen +                lje     MenuEnd + +                cmp     al,'1'          ; 1 = Platte wechseln +                jne     NoSelectDisk +                mov     ah,1            ; Rckschreiben erlaubt +                call    SelectDisk +                jmp     MenuLoop +NoSelectDisk: +                cmp     al,'2'          ; 2 = Geometrie wechseln +                jne     NoChangeGeometry +                call    ChangeGeometry +                jmp     MenuLoop +NoChangeGeometry: +                cmp     [MomDrive],-1   ; fr alles weitere muá Platte gesetzt sein +                jne     DiskIsSelected +                push    ax +                shl     ax,8            ; Annahme: Geometrie nicht zurckschreiben +                cmp     ah,'3' +                je      NoWriteBack +                inc     al              ; fr alles auáer low-level schon +NoWriteBack:    call    SelectDisk      ; implizit Laufwerk erfragen +                PrMsg   NewLine +                pop     ax +                cmp     [MomDrive],-1 +                lje     MenuLoop        ; wenn immer noch nicht gesetzt, Abbruch +DiskIsSelected: +                cmp     al,'3'          ; 3 = Platte low-leveln +                jne     NoFormatDisk +                call    FormatDisk +                jmp     MenuLoop +NoFormatDisk: +                cmp     al,'4'          ; 4 = Spur formatieren +                jne     NoFormTrack +                call    FormTrack +                jmp     MenuLoop +NoFormTrack: +                cmp     al,'5'          ; 5 = Platte prflesen +                jne     NoBadTrack +                call    BadTrack +                jmp     MenuLoop +NoBadTrack: +                cmp     al,'6'          ; 6 = Platte verifizieren +                jne     NoVerifyDisk +                call    VerifyDisk +                jmp     MenuLoop +NoVerifyDisk: +                cmp     al,'7'          ; 7 = Partition anlegen +                jne     NoMakePart +                call    MakePart +                jmp     MenuLoop +NoMakePart: +                cmp     al,'8'          ; 8 = Partition formatieren +                jne     NoFormatPart +                call    FormatPart +                jmp     MenuLoop +NoFormatPart:   PrChar  BEL             ; alle anderen Angaben anmeckern +                jmp     MenuLoop +MenuEnd:        mov     ss,[sssave]     ; Stack zurck +                mov     sp,[spsave] + +                pop     di +                pop     cx +                pop     ax              ; Register zurck + +                ret + +MenuMsg         db      CR,LF,"SECDRIVE Men      Platte:" +MenuMsg_Drv     db      '-',CR,LF,'$' +CylMsg          db      " Zylinder,$" +HeadMsg         db      " K”pfe,$" +SecMsg          db      " Sektoren",CR,LF,'$' +MenuList        db      CR,LF +                db      "1 = Platte wechseln",CR,LF +                db      "2 = Geometrie neu definieren",CR,LF +                db      "3 = Platte formatieren",CR,LF +                db      "4 = Spur formatieren",CR,LF +                db      "5 = Defekte Spuren markieren",CR,LF +                db      "6 = Platte verifizieren",CR,LF +                db      "7 = Partition erstellen",CR,LF +                db      "8 = Partition log. formatieren",CR,LF +                db      "------------------------",CR,LF +                db      "0 = Men verlassen",CR,LF,'$' +spsave          dw      ? +sssave          dw      ? + +                db      1024 dup (?)    ; Programmstack +Stack: + +                endp + +MomDrive        db      -1 +TwoLines:       db      CR,LF +NewLine:        db      CR,LF,'$' + +                endsection 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 diff --git a/tests/t_secdrive/t_secdrive.doc b/tests/t_secdrive/t_secdrive.doc new file mode 100644 index 0000000..0aece08 --- /dev/null +++ b/tests/t_secdrive/t_secdrive.doc @@ -0,0 +1,9 @@ ++----------------------- Test Application SECDRIVE --------------------------+ +|                                                                            | +|   YUCK!  8086/MSDOS-Code ;-)                                               | +|   This is a MSDOS driver for a secondary MFM/RLL/ESDI/IDE controller I     | +|   wrote a few years ago - just to get another 40MB of storage (which was   | +|   a lot at that time...)                                                   | +|   This app also demonstrates the usage of the newly introduced structures. | +|                                                                            | ++----------------------------------------------------------------------------+ diff --git a/tests/t_secdrive/t_secdrive.ori b/tests/t_secdrive/t_secdrive.oriBinary files differ new file mode 100755 index 0000000..0538002 --- /dev/null +++ b/tests/t_secdrive/t_secdrive.ori diff --git a/tests/t_secdrive/wd1002xt.inc b/tests/t_secdrive/wd1002xt.inc new file mode 100644 index 0000000..7dd1268 --- /dev/null +++ b/tests/t_secdrive/wd1002xt.inc @@ -0,0 +1,773 @@ +;****************************************************************************** +;*                                                                            * +;*  Includedatei fr SECMAIN.ASM                                              * +;*  liefert low-level-Routinen fr SecMain                                    * +;*  Version hier fr WD1002XT-kompatible Kontroller:                          * +;*  MFM, RLL (?)                                                              * +;*                                                                            * +;*  Historie: 28.12.1994                                                      * +;*            26. 3.1994 Formatierroutinen                                    * +;*             8. 4.1994 defekte Spuren markieren                             * +;*                                                                            * +;****************************************************************************** + +                section wd1002xt + +;------------------------------------------------------------------------------ +; Portadressen + +Port_Base       equ     320h            ; prim„re Basisadresse +Port_Data       equ     Port_Base+0     ; Datenregister (R+W) +Port_Status     equ     Port_Base+1     ; Statusregister (R) +Port_Reset      equ     Port_Base+1     ; Reset ausl”sen (W) +Port_Config     equ     Port_Base+2     ; Jumper auslesen (R) +Port_Select     equ     Port_Base+2     ; Kontroller selektieren (W) +Port_IRQDRQ     equ     Port_Base+3     ; IRQ/DRQ-Leitungen freigeben (W) + +;------------------------------------------------------------------------------ +; Kommandocodes + +Cmd_Diagnose    equ     0e4h            ; Kommando: Kontroller-Selbsttest +Cmd_GetStatus   equ     003h            ; Status letzter Operation lesen +Cmd_TestReady   equ     000h            ; Test, ob Laufwerk bereit +Cmd_Restore     equ     001h            ; Laufwerk rekalibrieren +Cmd_SetParams   equ     00ch            ; Laufwerksparameter setzen +Cmd_Seek        equ     00bh            ; Spur anfahren +Cmd_Read        equ     008h            ; Sektoren lesen +Cmd_Write       equ     00ah            ; Sektoren schreiben +Cmd_Verify      equ     005h            ; Sektoren auf Lesbarkeit prfen +Cmd_WriteBuffer equ     00fh            ; Sektorpuffer beschreiben +Cmd_FormatDisk  equ     004h            ; Laufwerk formatieren +Cmd_FormatTrack equ     006h            ; Spur formatieren +Cmd_FormatBad   equ     007h            ; Spur als defekt markieren + +;------------------------------------------------------------------------------ +; I/O-Bremse + +IODelay         macro +                jmp     $+2 +                endm + +;------------------------------------------------------------------------------ +; Puffer + +CmdBufSize      equ     6               ; enth„lt Kommandoblock fr WD1002 +CmdBuf          db      CmdBufSize dup (0) + +StatBufSize     equ     4               ; enth„lt Statusinfo vom WD1002 +StatBuf         db      StatBufSize dup (0) + +GeomBufSize     equ     8               ; enth„lt Parametertabelle fr Laufwerk +GeomBuf         db      GeomBufSize dup (0) + +;****************************************************************************** +;* Kommandopuffer initialisieren                                              * +;****************************************************************************** + +                proc    InitCmdBuf + +                push    ax              ; Register retten + +                sub     ax,ax           ; mit Nullen initialisieren +                mov     word ptr[CmdBuf],ax +                mov     word ptr[CmdBuf+2],ax +                mov     ah,45h          ; Retry on, 70us Steprate +                mov     word ptr[CmdBuf+4],ax + +                pop     ax              ; Register zurck + +                ret + +                endp + +;****************************************************************************** +;* einen Datenblock an den Kontroller schicken                                * +;*              In  :   ES:SI = Datenblock                                    * +;*                      CX = Anzahl Bytes                                     * +;*              Out :   C=1 bei Protokollfehler                               * +;****************************************************************************** + +                proc    SendBlock + +                push    ax              ; Register retten +                push    cx +                push    dx +                push    si + +                mov     dx,Port_Status +                jcxz    ZeroLoop        ; Nullschleife abfangen +                cld                     ; !!! +OutLoop:        in      al,dx           ; Status lesen +                btst    al,0            ; warten, bis REQ-Bit auf 1 +                jz      OutLoop +                btst    al,1            ; IO-Bit muá 0 sein +                stc +                jnz     ErrEnd +                mov     dl,Lo(Port_Data); ein Byte auf Datenport ausgeben +                seges +                outsb +                mov     dl,Lo(Port_Status) ; zurck fr n„chsten Durchlauf +                loop    OutLoop +ZeroLoop:       clc                     ; Ende ohne Fehler +ErrEnd: +                pop     si              ; Register zurck +                pop     dx +                pop     cx +                pop     ax + +                ret + +                endp + +;****************************************************************************** +;* einen Datenblock vom Kontroller lesen                                      * +;*              In  :   ES:DI = Datenblock                                    * +;*                      CX = Anzahl Bytes                                     * +;*              Out :   C=1 bei Protokollfehler                               * +;****************************************************************************** + +                proc    RecvBlock + +                push    ax              ; Register retten +                push    cx +                push    dx +                push    di + +                mov     dx,Port_Status +                jcxz    ZeroLoop        ; Nullschleife abfangen +                cld                     ; !!! +InLoop:         in      al,dx           ; Status lesen +                btst    al,0            ; warten, bis REQ-Bit auf 1 +                jz      InLoop +                btst    al,1            ; IO-Bit muá 1 sein +                stc +                jz      ErrEnd +                mov     dl,Lo(Port_Data); ein Byte von Datenport einlesen +                insb +                mov     dl,Lo(Port_Status) ; zurck fr n„chsten Durchlauf +                loop    InLoop +ZeroLoop:       clc                     ; Ende ohne Fehler +ErrEnd: +                pop     di              ; Register zurck +                pop     dx +                pop     cx +                pop     ax + +                ret + +                endp + +;****************************************************************************** +;* Status bilden                                                              * +;*              Out : C+AX = Status                                           *  +;****************************************************************************** + +                proc    BuildStatus + +                push    dx              ; Register retten + +                mov     dx,Port_Status  ; auf Datum warten +Loop:           in      al,dx +                btst    al,0            ; bis REQ=1 +                jz      Loop +                btst    al,1            ; und IO=1 +                jz      Loop +                mov     dl,Lo(Port_Data); CCB auslesen +                in      al,dx +                mov     ah,al           ; retten fr Fehlerabfrage +                and     al,2            ; Bit 1 ausmaskieren +                clc +                ljz      End             ; wenn = 0, kein Fehler und AL=0 + +                push    cx              ; zus„tzliche Register retten +                push    si +                push    di +                push    es + +                call    InitCmdBuf      ; ansonsten Kommando absetzen, um +                mov     [CmdBuf],Cmd_GetStatus ; Status zu lesen +                and     ah,20h          ; Status fr korr. Laufwerk abfragen +                mov     [CmdBuf+1],ah +                mov     dx,Port_Status +WaitNBusy:      in      al,dx +                btst    al,3 +                jnz     WaitNBusy +                mov     ax,ds           ; NICHT ExecCmd benutzen, da sonst +                mov     es,ax           ; Rekursion ! +                lea     si,[CmdBuf] +                mov     cx,CmdBufSize +                mov     dl,Lo(Port_Select) +                out     dx,al +                call    SendBlock +                lea     di,[StatBuf]    ; 4 Statusbytes auslesen +                mov     cx,StatBufSize +                call    RecvBlock +                mov     dl,Lo(Port_Status); CCB nicht vergessen!! +Loop2:          in      al,dx +                btst    al,0            ; bis REQ=1 +                jz      Loop2 +                btst    al,1            ; und IO=1 +                jz      Loop2 +                mov     dl,Lo(Port_Data) +                in      al,dx +                mov     al,[StatBuf]    ; Fehlercode = 1.Byte, +                and     al,7fh          ; Bit 0..6 +                stc                     ; Carry signalisiert Fehler +                pop     es              ; zus„tzliche Register zurck +                pop     di +                pop     si +                pop     cx + +End:            mov     ah,0            ; MSB ohne Bedeutung +                pop     dx              ; Register zurck +                ret + +                endp + +;****************************************************************************** +;* XT- in AT-Fehlerkode umsetzen                                              * +;* Eingabe:     AL = XT-Fehlerkode                                            * +;* Ausgabe:     C+AX = AT-Fehlerstatus                                        * +;****************************************************************************** + +                proc    TranslateStatus + +                push    bx +                push    si + +                mov     bl,al          ; alten Status sichern +                mov     bh,-1 +                lea     si,[TransTable] +                cld +TransLoop:      lodsw                   ; einen Eintrag laden +                cmp     al,bh           ; Tabellenende? +                je      TransEnd +                cmp     al,bl           ; Treffer? +                jne     TransLoop       ; nein, weitersuchen +                mov     al,ah           ; bersetzten Code laden +                cmp     al,0            ; Code fr kein Fehler? +                clc +                je      Ende            ; ja, C=0 +                jmp     TransErr        ; ansonsten C=1 +TransEnd:       mov     al,04h          ; Aborted Command annehmen +TransErr:       stc                     ; Fehlerflag setzen + +Ende:           pop     si              ; Register zurck +                pop     bx + +                ret + +TransTable:     db      00h,00h         ; kein Fehler +                db      02h,02h         ; kein Seek Complete-Signal +                db      03h,04h         ; Write Fault +                db      04h,04h         ; Laufwerk nicht bereit +                db      06h,02h         ; Spur 0 nicht gefunden +                db      08h,02h         ; Laufwerk positioniert noch +                db      11h,40h         ; unkorrigierbarer Datenfehler +                db      12h,01h         ; Adreámarke nicht gefunden +                db      15h,10h         ; Positionierfehler +                db      18h,00h         ; korrigierbarer Fehler (ignoriert) +                db      19h,80h         ; Spur als defekt markiert +                db      -1,-1           ; Tabellenende + +                endp + +;****************************************************************************** +;* ein Kommando ausfhren                                                     * +;*              In  :   AL = Kommando                                         * +;****************************************************************************** + +                proc    ExecCmd + +                push    cx              ; Register retten +                push    ax +                push    dx +                push    si +                push    es + +                mov     [CmdBuf],al     ; Kommandokode in Datenblock einschreiben +                mov     dx,Port_Status  ; warten, bis Kontroller frei +WaitNBusy:      in      al,dx +                btst    al,3 +                jnz     WaitNBusy +                mov     dx,Port_Select  ; Kontroller selektieren +                out     dx,al +                mov     ax,ds           ; Adresse Kommandoblock +                mov     es,ax +                lea     si,[CmdBuf] +                mov     cx,CmdBufSize   ; L„nge Kommandoblock +                call    SendBlock       ; Kommandoblock abschicken + +                pop     es              ; Register zurck +                pop     si +                pop     dx +                pop     ax +                pop     cx + +                ret + +                endp + +;****************************************************************************** +;* Laufwerk und Sonderwerte in Kommandoblock einprogrammieren                 * +;*              In  :   AL = Laufwerk                                         * +;*                      AH = Kopf                                             * +;****************************************************************************** + +                proc    SetDriveEnv + +                push    ax              ; Register retten + +  +                shl     al,5            ; Laufwerksbit an Stelle 5 +                or      al,ah +                mov     [CmdBuf+1],al   ; als 2. Byte im Kommandopuffer schreiben + +                pop     ax              ; Register zurck + +                ret + +                endp + +;****************************************************************************** +;* Zylinder- und Sektorparameter an Kontroller ausgeben                       * +;*              In  :   BX = Startzylinder                                    * +;*                      CL = Sektorzahl/Interleave                            * +;*                      CH = Startsektor                                      * +;****************************************************************************** + +                proc    SetTransParams + +                push    ax              ; Register retten + +                mov     [CmdBuf+3],bl   ; LSB Startzylinder +                mov     al,bh           ; MSB Startzylinder +                shl     al,6            ; in Bit 6..7 schieben +                add     al,ch           ; Sektor dazu +                dec     al              ; !!! Sektoren ab 0 +                mov     [CmdBuf+2],al +                mov     [CmdBuf+4],cl   ; Sektorzahl + +                pop     ax             ; Register zurck +                ret + +                endp + +;****************************************************************************** +;* Begráungsmeldung ausgeben:                                                * +;****************************************************************************** + +                globproc LowLevelIdent + +                push    ax              ; Register retten + +                PrMsg   IdentMsg + +                pop     ax + +                ret + +IdentMsg        db      "Low-Level-Routinen fr WD1002S-WX2 und kompatible Controller",CR,LF,'$' + +                endp + +;****************************************************************************** +;* Controller-Diagnose:                                                       * +;*              Out :  AL = Diagnosecode                                      * +;****************************************************************************** + +                globproc ContDiag + +                push    cx              ; Register retten +                push    bx +                push    dx + +                sub     cx,cx +                mov     dx,Port_Status  ; auf Status +BWait:          in      al,dx +                btst    al,3            ; 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:          call    InitCmdBuf      ; Kommando Selbsttest ausfhren +                mov     al,Cmd_Diagnose +                call    ExecCmd +                call    BuildStatus     ; Status holen + +                cmp     al,5            ; WD1002 definiert nur Code 0..5 +                jb      DoTrans +                mov     al,7            ; "undefinierter Code" +                jmp     End +DoTrans:        lea     bx,[TransTbl]   ; ansonsten umsetzen +                xlat + +End:            pop     dx              ; Register zurck +                pop     bx +                pop     cx +                ret + +TransTbl:       db      Diag_NoError    ; Code 0: kein Fehler +                db      Diag_ContError  ; Code 1: WD1010 fehlerhaft +                db      Diag_ECCError   ; Code 2: WD11C00 fehlerhaft +                db      Diag_SBufError  ; Code 3: Sektorpuffer defekt +                db      Diag_ProcError  ; Code 4: WD1015 RAM defekt +                db      Diag_ProcError  ; Code 5: WD1015 ROM defekt + +  +                endp + +;****************************************************************************** +;* Laufwerk rekalibrieren, gleichzeitig Test, ob vorhanden                    * +;*              In  :  AL = Laufwerk                                          * +;*              Out :  C + AX = Status                                        * +;****************************************************************************** + +  +                globproc Recalibrate + +                push    ax              ; Register retten +                push    cx + +                call    InitCmdBuf      ; testen, ob Laufwerk bereit +                mov     ah,0            ; Kopf dafr unwichtig +                call    SetDriveEnv +                mov     dl,al           ; Laufwerksnummer retten, gleichzeitig +                mov     dh,0            ; Kopf auf 0 setzen +                mov     al,Cmd_TestReady +                call    ExecCmd +                call    BuildStatus +                jc      TotEnde         ; C=1 --> Ende mit Fehler + +                call    InitCmdBuf      ; sanfte Tour: Spur 0 mit Seek anfahren +                mov     ax,dx +                call    SetDriveEnv +                mov     al,0            ; Zylinder lo=0 +                mov     [CmdBuf+3],al +                inc     al              ; Zylinder Hi=0, Startsektor=1 +                mov     [CmdBuf+2],al +                mov     al,Cmd_Seek +                call    ExecCmd +                call    BuildStatus +                jnc     TotEnde         ; kein Fehler, alles in Butter + +                call    InitCmdBuf      ; ansonsten echtes Restore versuchen +                mov     ax,dx +                call    SetDriveEnv +                mov     al,Cmd_Restore +                call    ExecCmd +                call    BuildStatus +                call    TranslateStatus + +TotEnde:        pop     dx              ; Register zurck +                pop     ax + +                ret + +                endp + +;****************************************************************************** +;* Dem Kontroller die Laufwerksgeometrie mitteilen                            * +;*              In  :   AL = Laufwerk                                         * +;*              Out :   C  = 1-->Fehler                                       * +;****************************************************************************** + +                globproc SetDriveParams + +                push    cx              ; Register retten +                push    si +                push    es + +                call    GetPTabAdr      ; Adresse Parametertabelle holen +                call    InitCmdBuf      ; Kommando anstoáen +                call    SetDriveEnv +                mov     al,Cmd_SetParams +                call    ExecCmd + +  +                mov     ax,[di+DrPar_Cyls] ; Parametertabelle aufbauen +                xchg    ah,al +                mov     word ptr [GeomBuf],ax +                mov     al,[di+DrPar_Heads] +                mov     byte ptr[GeomBuf+2],al +                mov     ax,[di+DrPar_RedWr] +                xchg    ah,al +                mov     word ptr[GeomBuf+3],ax +                mov     ax,[di+DrPar_PrComp] +                xchg    ah,al +                mov     word ptr[GeomBuf+5],ax +                mov     al,[di+DrPar_ECCLen] +                mov     byte ptr[GeomBuf+7],al +                lea     si,[GeomBuf]    ; Block abschicken +                mov     cx,GeomBufSize +                mov     ax,ds +                mov     es,ax +                call    SendBlock +                call    BuildStatus +                call    TranslateStatus + +                pop     es              ; Register zurck +                pop     si +                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    bx              ; Register retten +                push    cx +                push    dx +                push    di +                push    es + +                call    InitCmdBuf      ; Puffer initialisieren +                call    SetDriveEnv +                call    SetTransParams +                mov     al,Cmd_Read     ; Lesen triggern +                PrChar  '1' +                call    ExecCmd +                PrChar  '2' + +SecLoop:        mov     dx,Port_Status  ; warten, bis Request-Bit gesetzt +RLoop:          in      al,dx +                btst    al,0 +                jz      RLoop +                btst    al,2            ; Daten oder Status ? +                jnz     ErrEnd          ; wenn jetzt Status, ist etwas schief gelaufen +                push    cx              ; ansonsten Sektor auslesen +                mov     cx,SecSize +                PrChar  '3' +                call    RecvBlock +                PrChar  '4' +                pop     cx +                dec     cl +                add     di,SecSize +                jnz     RLoop           ; und n„chsten Sektor verarbeiten + +ErrEnd:         PrChar  '5' +                call    BuildStatus +                PrChar  '6' +                call    TranslateStatus + +                pop     es              ; Register zurck +                pop     di +                pop     dx +                pop     cx +                pop     bx + +                ret + +                endp + +;****************************************************************************** +;* Sektor(en) verifizieren                                                    * +;*              In  :  AL = Laufwerk                                          * +;*                     AH = Startkopf                                         * +;*                     BX = Startzylinder                                     * +;*                     CL = Sektorzahl                                        * +;*                     CH = Startsektor                                       * +;*              Out :  C+AX = Fehlerstatus                                    * +;****************************************************************************** + +                globproc VeriSectors + +                push    bx              ; Register retten +                push    cx +                push    dx + +                call    InitCmdBuf      ; Puffer initialisieren +                call    SetDriveEnv +                call    SetTransParams +                mov     al,Cmd_Verify   ; Verifikation triggern +                call    ExecCmd + +                call    BuildStatus +                call    TranslateStatus + +                pop     dx              ; Register zurck +                pop     cx +                pop     bx + +                ret + +                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    bx              ; Register retten +                push    cx +                push    dx +                push    si +                push    es + +  +                call    InitCmdBuf      ; Puffer initialisieren +                call    SetDriveEnv +                call    SetTransParams +                mov     al,Cmd_Write    ; Lesen triggern +                call    ExecCmd + +SecLoop:        mov     dx,Port_Status  ; warten, bis Request-Bit gesetzt +WLoop:          in      al,dx +                btst    al,0 +                jz      WLoop +                btst    al,2            ; Daten oder Status ? +                jnz     ErrEnd          ; wenn jetzt Status, ist etwas schief gelaufen +                push    cx              ; ansonsten Sektor auslesen +                mov     cx,SecSize +                call    SendBlock +                pop     cx +                dec     cl +                add     si,SecSize +                jnz     WLoop           ; und n„chsten Sektor verarbeiten + +ErrEnd:         call    BuildStatus +                call    TranslateStatus + +                pop     es              ; Register zurck +                pop     si +                pop     dx +                pop     cx +                pop     bx + +                ret + +                endp + +;****************************************************************************** +;* Laufwerk formatieren                                                       * +;*              In  :  AL = Laufwerk                                          * +;*                     AH = Interleave                                        * +;*              Out :  C+AX = Fehlerstatus                                    * +;****************************************************************************** + +                globproc FormatUnit + +                push    bx              ; Register retten +                push    cx +                push    dx +                push    si +                push    di +                push    es +  +                mov     bx,ax           ; Interleave & Laufwerk retten +                 +                mov     ax,ds           ; vorher noch den Sektorpuffer im +                mov     es,ax           ; Controller ausnullen +                lea     di,[SectorBuffer] +                mov     cx,SecSize/2 +                sub     ax,ax +                rep     stosw +                call    InitCmdBuf +                mov     al,Cmd_WriteBuffer +                call    ExecCmd +                lea     si,[SectorBuffer] +                mov     cx,SecSize +                call    SendBlock +                call    BuildStatus +                jc      End             ; unwahrscheinlich, aber... + +                call    InitCmdBuf      ; Puffer initialisieren +                mov     al,bl           ; Laufwerk wieder zurck +                mov     ah,0            ; Startkopf ist 0 +                call    SetDriveEnv +                mov     [CmdBuf+4],bh   ; Interleave einschreiben +                mov     al,Cmd_FormatDisk ; Formatieren triggern +                call    ExecCmd + +ErrEnd:         call    BuildStatus +End:            call    TranslateStatus + +                pop     es              ; Register zurck +                pop     di +                pop     si +                pop     dx +                pop     cx +                pop     bx + +                ret + +                endp + +;****************************************************************************** +;* Spur formatieren                                                           * +;*              In  :  AL = Laufwerk                                          * +;*                     AH = Kopf                                              * +;*                     BX = Zylinder                                          * +;*                     CL = Interleave                                        * +;*              Out :  C+AX = Fehlerstatus                                    * +;****************************************************************************** + +                globproc FormatTrack + +                push    bx +                push    cx + +                call    InitCmdBuf      ; Parameter einschreiben +                call    SetDriveEnv +                mov     ch,1            ; Sektorinformation muá nur gltig sein +                call    SetTransParams +                mov     al,Cmd_FormatTrack +                call    ExecCmd +                call    BuildStatus + +                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 +                push    cx + +                call    InitCmdBuf      ; Parameter einschreiben +                call    SetDriveEnv +                mov     cx,0103h        ; Sektorinformation muá nur gltig sein +                call    SetTransParams +                mov     al,Cmd_FormatBad +                call    ExecCmd +                call    BuildStatus + +                pop     cx +                pop     bx +                ret + +                endp + +                endsection 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 | 
