Reine Verständigungsfrage - Diskettenwechsel erzwingen

In Assembler und C: Wie Sie das Betriebssystem zu einem Diskettenwechsel zwingen.

Bei Schreibzugriffen auf Sektoren und bei direkter Controller-Programmierung sind Sie als Programmierer immer wieder auf BIOS-und XBIOS-Routinen angewiesen. Das Problematische bei Diskzugriffen über diese Routinen ist, daß das GEMDOS die FATs (File Allocation Tables) und Inhaltsverzeichnisse der angeschlossenen Laufwerke und Partitionen ständig in seinem internen Speicher hält. Greifen Sie nun über das BIOS oder XBIOS auf ein Speichermedium zu, so verändern Sie möglicherweise den physikalischen Inhalt der FAT oder der Inhaltsverzeichnisse. GEMDOS behält aber weiterhin seine Tabellen im Speicher. Erfolgt später ein Zugriff über das GEMDOS, so ist dieses noch nicht über die Veränderungen informiert und produziert bestenfalls eine Fehlermeldung, meistens jedoch Datenmüll. Das führt unter Umständen dazu, daß der Inhalt einer Diskette nicht mehr lesbar ist. Oder die Festplattenpartition ist so verstümmelt, daß sie sich nur noch durch vollständiges Löschen zur Mitarbeit überreden läßt. Aus diesem Grund fordern viele Programme, wie beispielsweise das Festplatten-Hilfsprogramm HDX, nach einer Datenmanipulation zum erneuten Booten auf. Das funktioniert zwar, ist allerdings nicht besonders elegant.

Seit im August letzten Jahres die »Rainbow-TOS Release Notes« für das TOS 1.4 erschienen, gibt es ein offiziell von Atari dokumentiertes Verfahren, das Abhilfe schafft [1]. Die vorgeschlagene Methode bedient sich dabei des Media-Change-Vektors. Denn bevor das GEMDOS auf ein Speichermedium zugreift, fragt es zunächst ab, ob zwischenzeitlich der Datenträger gewechselt wurde. Dieses Verfahren stammt noch aus der Zeit, in der keine Festplatte für den ST zu haben war. Es sollte verhindern, daß das GEMDOS bei einem Diskettenwechsel seine in den Speicher eingelesene FAT der alten Diskette für die neue benutzt. Sobald das GEMDOS feststellt, daß ein Mediawechsel stattgefunden hat, löscht es seine alten internen FATs im »OS-Pool« (Arbeitsspeicher des GEM-DOS) und liest die neuen ein.

Eine Festplatte läßt sich allerdings nicht so einfach auswechseln, deshalb gibt eine »MediaChange«-Abfrage auf eine Festplatten-Partition immer den Wert 0 zurück. Dieses Ergebnis weist darauf hin, daß das Speichermedium nicht gewechselt wurde. Die hier vorgestellte Routine gaukelt dem GEMDOS vor, es habe ein Wechsel stattgefunden. Dazu führen wir einen GEMDOS-Aufruf auf dem angegebenen Laufwerk durch und sorgen dafür, daß das GEMDOS bei einer provozierten Media-Change-Abfrage den Status 2 (Medium gewechselt) erhält. Nun wirft das GEMDOS seine internen Tabellen über Bord und liest die neuen ein, bevor es das Kommando ausführt.

Einbindung in C

Die Routine entstammt ursprünglich den »Release Notes«, enthält jedoch einige entscheidende Verbesserungen. Zunächst einmal wählte Atari für seine Assembler-Routine den Namen »mediach«. Das treibt manchen C-Compiler zur Verzweiflung, denn es existiert ja bereits eine gleichnamige Funktion: BIOS 9. Vielleicht ist der »Doppelname« auch nur ein Druckfehler in den »Release Notes«, denn im Listing beginnt der Name der Routine mit einem Unterstrich (»_«). Es ist also nicht ganz sicher, ob sich Ataris Programmierer irrten oder der Drucker versagte. Übernehmen Sie den Namen »mediach« in eine eigene Bibliothek, so produziert beispielsweise Turbo-C einen Fehler, den es zwar nicht anzeigt, der aber zum Absturz Ihrer Programme führt. Unsere Routine deklariert sich global als »fmediach«, wobei das »f« für »Forced« (zu deutsch »zwangsweise«) steht.

Ein weiteres Problem entsteht, wenn Sie das Media-Change ausnahmsweise statt auf einer Festplatte auf einer Diskette ausführen lassen, und der Anwender diese gerade entnommen hat. In diesem Fall erscheint unpassenderweise eine Dialogbox. Sie weist den Anwender darauf hin, daß sein Disketten-Laufwerk momentan nicht ansprechbar ist, und fordert ihn zum Einlegen einer Diskette auf. Dabei ist eine solche Meldung im Falle des Media-Changes völlig unnötig. Denn egal ob der Anwender mit »OK« oder »Abbruch« bestätigt, die RAM-FAT ist in jedem Fall gelöscht.

Deshalb installiert unsere Routine ein eigenes Unterprogramm, das in Aktion tritt, sobald ein Fehler auftritt. Zunächst einmal prüft es, welches Laufwerk den Fehler verursacht hat. Handelt es sich um das Laufwerk, das den Media-Change durchführen soll, so liefert die Routine intern einen Fehlerwert zurück. Davon merkt der Benutzer nichts, und es erscheint auch keine Dialogbox. Tritt der Fehler allerdings auf einem anderen Laufwerk auf, so verfährt der Computer wie üblich und gibt eine Fehlermeldung aus. Dieser Fall sollte aber bei keiner der bisherigen TOS-Versionen auftreten.

Weitere Verbesserungen betreffen den Programm-Code und die Ausführungsgeschwindigkeit. Wir haben bei unserem Programm bewußt auf das XBRA-Protokoll verzichtet, weil wir seine Vorzüge nicht benötigen. Die Installation ist nur kurzzeitig, das Programm deinstalliert sich vor seinem Ende selbst, und GEMDOS-Aufrufe sind im Interrupt ohnehin unmöglich. Wir stellen Ihnen zwei Programmversionen vor. In Listing 1 finden Sie unsere Routine in Assembler formuliert. Sie ist dazu vorbereitet, als Objekt-Datei assembliert und in eine C-Bibliothek aufgenommen zu werden. Ein Beispiel für den Aufruf der Bibliotheksfunktion in C finden Sie im Listing 2. Die Routine bietet Ihnen Gelegenheit für Erweiterungen. Zum Beispiel läßt sich das Programm so umschreiben, daß es resident im Speicher bleibt und für ein logisches Gerät - beispielsweise ihre wertvollste Plattenpartition - ständig einen Media-Change anzeigt. Das schützt zwar vor Programmen, die die Richtlinien nicht beachten und BIOS-und XBIOS-Routinen zur Ein- und Ausgabe verwenden, ohne einen ordnungsgemäßen Forced Media Change durchzuführen. Dafür verlangsamt sich allerdings der Zugriff auf diese Partition enorm. (ba)

Literaturverzeichnis:
[1] Atari Corporation, »Rainbow-TOS Release Note« Seiten 52ff, Atari Corp., 1196 Borregas Avenue, Sunnyvale, CA 94086.

Listing 1: Mit diesem Assembier-Programm erzwingen Sie einen Medie-Change auf einem logischen Laufwerk. Das Listing ist auch als Bibliotheks-Rouline für C verwendbar

; *****************************************************************
; * fmediach erzwingt Media-change auf einem logischen Gerät      *
; * C-Anpassung mit Parameterübergabe auf dem Stack!              *
; *                                                               *
; * Ursprünglich aus den „Atari Rainbow TOS Release Notes“,       *
; * überarbeitet von Laurenz Prüßner am 12/13.11.1989 © PP‘89     *
; *                                                               *
; *    Benutzung in C: ercode = fmediach(devno);                  *
: *                                                               *
; * Sprache: 68000-Assembler (Omikron- bzw. Turbo-Ass)            *
; *****************************************************************

hdv_bpb:    EQU $0472
hdv_rw: EQU $0476
hdv_mediach:    EQU $047E
etv-critic: EQU $0404       ; der etv_critic-Handler für MB

GLOBAL  fmediach

fmediach:
    movem.l d7/a2-a3, regsav    ; Register, die gemäß den C-Konventionen nicht
            ; „zum Abschuß freigegeben“ sind.
    move.w  4(sp), d7
    clr.l   -(sp)   ; Super
    move.w  #$20, -(sp)
    trap    #1
    addq.l  #6, sp
    move.l  d0, -(sp)
    move.w  #$20, -(sp)

    move.l  etv critic.w, etv_merk
    move.l  #etv_ersetzt, etv_critic.w

    move.w  d7, mydev
    add.b   #‘A‘, d7
    move.b  d7, fspec

    movem.l hdv_bpb.w, a0-a3    ; 4 Longs verschieben
    movem.l a0-a3, oldgetbpb

    ; Eines von den vier Longs ist überflüssig, das macht aber nichts, die Routine ist
    ; immer noch schneller als die von Atari! Jetzt müßten eigentlich XBRA-Verfahren
    ; benutzt werden, aber da die Verschiebung sowieso nur temporär ist,
    ; sparen wir an Zeit und Platz!

    move.l  #newgetbpb, hdv_bpb.w
    move.l  #newrwabs, hdv_rw.w
    move.l  #newmediach, hdv_mediach.w clr.w   -(sp)
    pea fspec
    move.w  #$3d, -(sp)
    trap    #1
    addq.l  #8, sp

    tst.l   d0
    bmi.s   noclose
    move.w  d0, -(sp)
    move.w  #$3e,-(sp)
    trap    #1
    addq.l  #4, sp

noclose:
    moveq   #0, d7
    cmpi.l  #newgetbpb, hdv_bpb.w
    bne.s   done

    moveq   #1, d7
    movem.l oldgetbpb, a0-a3    ; Hier kopiert der ST
    movem.l a0-a3, hdv_bpb.w    ; die 4 Longs zurück.

done:
    move.l  etv_merk, etv_critic.w  ; Freigabe
    trap    #1
    add.l   #6, d0
    move.l  d7, d0
    movem.l regsav, d7/a2-a3
    rts

newgetbpb:
    move.w  mydev, d0
    cmp.w   4(sp), d0
    bne.s   dooldg

    movem.l oldgetbpb, a0-a3
    movem.l a0-a3, hdv_bpb.w

dooldg:
    movea.l oldgetbpb, a0
    jmp (a0)

newmediach:
    move.w  mydev, d0
    cmp.w   4(sp), d0
    bne.s   dooldm
    moveq   #2, d0
    rts

dooldm:
    movea.l oldmediach, a0
    jmp (a0)

newrwabs:
    move.w  mydev, d0
    cmp.w   14(sp), d0
    bne.s   dooldr
    moveq   #-$0e, d0
    rtsdooldr:
    movea.l oldmediach, a0
    jmp (a0)

    ; Hier der neue evt_critic-Treiber

etversetzt:
    move.w  6(sp), d0   ; Ist der Fehler auf
    cmp.w   mydev, d0   ; unserem Laufwerk?
    beq.s   disk_flipped    ; Ja, dann abbrechen!
    movea.l etv_merk, a0    ; ansonsten normale
    jmp (a0)    ; Fehlerabfertigung

disk_flipped:
    move.w  4(sp), d0   ; Fehler zurückmelden,
    rts     ; Box abfangen!

DATA
fspec:
    dc.b    ‚X:\\X‘, 0
mydev:
    ds.w    1
oldgetbpb:
    ds.l    3   ; Das überflüssige Long landet hier!
oldmediach:
    ds.l    1
regsav:
    ds.l    3
etv_merk:
    ds.l    1

END

Listing 2: Haben Sie die Routine aus Listing 1 in Ihre C-Bibliolbek aufgenommen, So Steht Sie Ihnen auch als externe C-Funktion zur Verfügung

/* fmediach (gehört in jede gute Library)

   Einbindung der Assemblerroutine in C
   Geschrieben am 20.10.1989 von Laurenz Prüssner

   ...warum sagt mir das denn keiner???

   Aufruf: errcode = fmediach (devno)
                     int errcode, devno

   Parameterübergabe auf dem Stack */

#include <stdio.h>
#include <ext.h>

int errcode, devno, eh;

extern int cdecl fmediach (int);

main()
{
    puts („Forced Media Change“);
    puts („Geschrieben von Laurenz Prüssner“);
    puts(„\nLaufwerk (A-P)?“);

    do
    {
        ch = getch();
        devno = ch - ‚A‘;
    } while (devno > 15 || devno < 0);

    putch (ch);

    errcode = fmediach (devno);

    if (errcode == 0)
        puts(„\nOK.“);
    else
        puts(„\nFehler!“);  /* Ein Fehler darf eigentlich nie vorkommen !*/

    return 0;
}<br>**Laurenz Prüßner**

Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]