Beschreibung der Festplattentreiber-Funktionen von MagiC 3.00
#############################################################

Andreas Kromke
Hannover, den 8.2.95


Treiber-Installation
====================

Fr Festplattentreiber existiert in MagiC die Dcntl-Funktion KER_DOSLIMITS.
Sie liefert Informationen ber die Kapazitt des internen FAT-Dateisystem-
Treibers, d.h. wieviele Cluster usw. bearbeitet werden knnen. Nheres
siehe MGX_DOS.TXT und MGX_XFS.H.

MagiC bentigt einen AHDI-kompatiblen Festplattentreiber. Nach dem Start
des Festplattentreibers mu MagiC seine interne Pufferliste umstrukturieren
und bentigt dafr die Information, wie gro die vom Treiber installierten
Sektorpuffer sind. Wenn diese Information falsch ist, gibt es einen bsen
Absturz. MagiC ermittelt den Zeiger pun_ptr. Ist dieser NULL, wird davon
ausgegangen, da keine Puffer installiert wurden (MagiC verwendet dann
seine 2+2 Puffer mit je 512 Bytes), ansonsten wird ber pun_msectsize
(als UWORD) die Gre der neuen Puffer ermittelt. Ist diese grer als
die von MagiC bisher installierten, werden die alten Puffer freigegeben,
d.h. in internen DOS-Speicher verwandelt. Anschlieend werden die neuen
Puffer installiert und _bufl[0] und _bufl[1] wieder auf NULL gesetzt.


I Konzepte
==========

Das gesamte DOS einschlielich der Zugriffe auf DOS- Dateisysteme ist
reentrant und luft im Hintergrund ab. So ist es mglich, auf Laufwerk A:
Dateien zu bearbeiten, ohne den Rechner bei den Diskettenzugriffen merklich
zu bremsen. Voraussetzung sind Disketten- und Festplattenroutinen, die im
Hintergrund arbeiten.

Die in dieser Datei enthaltenen Auszge aus dem BIOS dienen nur zur
Information, wie das ganze funktioniert. Die Routinen knnen sich jederzeit
ndern.

Damit der Plattentreiber diese Funktion nicht zur Verfgung zu stellen
braucht, enthlt das BIOS von MagiC alle notwendigen Funktionen. Dazu wurde
die Struktur

typedef struct
     {
     long    config_status;
     DOSVARS *dosvars;
     AESVARS *aesvars;
     } MAGX_COOKIE;

erweitert auf

typedef struct
     {
     long    config_status;
     DOSVARS *dosvars;
     AESVARS *aesvars;
     void    *reserved;
     HDFUNCS *hdf;
     } MAGX_COOKIE;

typedef struct
     {
     long      dma_begin ( void );
     long      dma_end   ( void );
     long      dma_wait  ( d0 = long ticks_200hz );
     long      ncr_begin ( void );
     long      ncr_end   ( void );
     long      ncr_wait  ( d0 = long ticks_200hz );
     } HDFUNCS;

Direkt vor der Struktur (2 Bytes vorher) liegt ein WORD, das die
Tabellenlnge angibt, in diesem Fall 6. Alle 6 Zeiger liegen im
Systemvariablenbereich und drfen notfalls verndert werden. Die internen
Funktionen fr die Floppy springen ebenfalls ber die 6 Zeiger. Der Zeiger
<hdf> im Cookie darf nicht verndert werden.

Die Versionsnummer von MagiC, die das Vorhandensein dieses erweiterten
Cookies enthlt, lt sich dummerweise nicht ber AESVARS abfragen, weil
dieser Zeiger auf die AES- Variablen zur Bootzeit noch NULL ist.
Glcklicherweise gelangt man an den Zeiger auch ber den TOS- Systemheader,
dieser Zeiger ist immer gltig. Zur Bootzeit ist das premptive Multitasking
abgeschaltet (eigentlich ist auch das Multitasking abgeschaltet), aber
jedenfalls funktionieren die Routinen auch vor Installation des AES, wobei
die Warteroutinen dann ein "busy waiting" machen (wie auch beim Abschalten
des premptiven Multitasking), und die Semaphorenroutine machen einfach
nichts (bis auf das Setzen und Lschen von flock).

Die Routinen acsi_xxx sind gleichzeitig fr ACSI und FDC, d.h. dma_begin
setzt flock, dma_end lscht es wieder.
Die Routinen ncr_xxx sind fr TT-SCSI.

Die Funktionen xxx_begin reservieren die jeweilige Semaphore. Rckgabwert 0
heit "OK", -1 heit "Semaphore gehrte mir schon". Die Routinen verndern
kein Register auer d0. Es gibt keinen Timeout, die Semaphore wird bei
Terminierung der Applikation aber freigegeben.

Die Funktionen xxx_end geben die Semaphore wieder frei, kein Register wird
verndert.

dma_wait wartet auf einen Interrupt des ACSI-DMA-Controllers bzw. des FDC,
ncr_wait ist fr den SCSI-Bus des TT.
Rckgabe von xxx_wait: 0 = OK, -1 = Timeout, -2 = Busfehler (Interrupt vom
TT-SCSI),

Semaphoren werden bei Programmterminierung freigegeben (exakt: bei
Applikations-Terminierung), auch die mit dem DOS- Aufruf Psemaphore belegten
(Im Gegensatz zu MiNT!!!!).
Psemaphore() untersttzt nur die Modi 2 und 3. Setzt man mit Psemaphore die
Semaphore _DMA, darf man nicht vergessen, nach Erhalt der Semaphore flock zu
setzen und nach Freigeben der Semaphore wieder freizugeben.

System- Semaphoren:

     _SCR      AES-Bildschirm (wind_update)
     _DMA      ACSI und FDC
     _NCR      TT-SCSI

#####################################################
####### Auszug aus dem BIOS : ACSI ##################
#####################################################


* Interruptsteuerung:
*
* Alles geht ber den Eingang I5 des ST-MFP, hat den Interrupt #7
* (aktiviert mit Bit 7 von ierb)
* Polling ber Bit 5 von gpip
* 1. aer fr Bit 5 mu 0 sein, d.h. Interrupt wird ausgelst beim
*    bergang von 1 auf 0
* 2. Interrupt _mfpint (7) aktivieren und Vektor setzen (Adr. $11c)
*

**********************************************************************
*
* Sperre den FDC/ACSI-DMA
* und gib ihn wieder frei.
* Kein Register (auer d0 bei dma_end) wird verndert
*
* Fr die Zeit, in der AES noch nicht initialisiert ist, kann evnt_sem
* nicht sperren, weil act_appl immer NULL ist.
*

dma_begin:
 movem.l  d1-d2/a0-a2,-(sp)
 lea      dma_sem,a0
 moveq    #0,d1               ; kein Timeout
 moveq    #SEM_SET,d0
 jsr      evnt_sem
 st       flock
 movem.l  (sp)+,d1-d2/a0-a2
 rts

dma_end:
 movem.l  d0-d2/a0-a2,-(sp)
 lea      dma_sem,a0
 moveq    #SEM_FREE,d0
 jsr      evnt_sem
 clr.w    flock
 movem.l  (sp)+,d0-d2/a0-a2
 rts


**********************************************************************
*
* long wait_ACSI( d0 = long ticks_200hz )
*
* Rckgabe:    0    OK
*             -1    TimeOut
*             -2    Busfehler
*

wait_ACSI:
 movem.l  d1-d2/a0-a2,-(sp)
 tst.w    pe_slice            ; premptiv ?
 bmi.b    wdma_no_yield       ; nein, busy waiting
 move.l   act_appl,d2
 ble.b    wdma_no_yield       ; aktuelle Applikation ungltig

* neue Routine ber evnt_IO und MFP- Interrupt

 lsr.l    #2,d0               ; AES: 50Hz statt 200Hz
wdma_neu:
 move     sr,d1
 ori      #$700,sr
 btst     #5,gpip             ; schon fertig ?
 beq.b    wdma_ok2            ; ja, enable interrupt
; Interrupt aufsetzen
 pea      int_mfp7_unsel(pc)
 move.l   d2,imfp7_appl       ; act_appl
 move.l   sp,imfp7_unsel
; Interrupt freigeben
 move.w   d1,sr
; Auf Interrupt warten
 move.l   sp,a0
;move.w   d0,d0               ; TimeOut in 50Hz- Ticks
 jsr      evnt_IO
 addq.l   #4,sp
wdma_ende:
 movem.l  (sp)+,d1-d2/a0-a2
 rts

* alte Routine mit busy waiting ber _hz_200

wdma_no_yield:
 add.l    _hz_200,d0
wdma_loop:
 btst     #5,gpip
 beq.b    wdma_ok
 cmp.l    _hz_200,d0
 bcc.b    wdma_loop
wdma_timeout:
 moveq    #-1,d0              ; Timeout
 bra.b    wdma_ende
wdma_ok2:
 move.w   d1,sr
wdma_ok:
 moveq    #0,d0               ; OK
 bra.b    wdma_ende


**********************************************************************
*
* Interruptroutine fr MFP, Interruptkanal #7 = I/O-Port 5
* (DMA/FDC busy)
*
* Rckgabewert 0 (OK)
*

int_mfp7:
 tst.l    imfp7_unsel                   ; Interrupt aktiviert ?
 beq.b    imfp7_ende                    ; nein, weiter
 movem.l  d0-d2/a0-a2,-(sp)

 move.l   imfp7_unsel,a0
 clr.l    imfp7_unsel                   ; Interrupt deaktivieren
 clr.l    (a0)                          ; als eingetroffen markieren

 move.l   imfp7_appl,a0
 jsr      appl_IOcomplete               ; wartende APP aufwecken
 movem.l  (sp)+,d0-d2/a0-a2
imfp7_ende:
 move.b   #$7f,isrb                     ; service- Bit lschen
 rte


**********************************************************************
*
* void int_mfp7_unsel( a0 = long *unselect, a1 = APPL *ap );
*
* Deaktiviert den Interrupt wieder, wenn er nicht eingetroffen ist
* Rckgabewert -1 (Timeout)
*

int_mfp7_unsel:
 clr.l    imfp7_unsel                   ; Interrupt deaktivieren
 moveq    #-1,d0
 move.l   d0,(a0)                       ; nicht eingetroffen
 rts



#####################################################
####### Auszug aus dem BIOS : SCSI ##################
#####################################################


* Interruptsteuerung:
*
* SCSI-DMA-Busfehler: Eingang I5 des TT-MFP
* 1. aer fr Bit 5 mu 0 sein, d.h. Interrupt wird ausgelst beim
*    bergang von 1 auf 0
* Polling ber Bit 5 von gpip
* Interrupt #7 des TT-MFP (Adresse $15c)

* SCSI: Eingang I7 des TT-MFP
* 1. aer fr Bit 7 mu 1 sein, d.h. Interrupt wird ausgelst beim
*    bergang von 0 auf 1
* Polling ber Bit 7 von gpip
* Interrupt #15 des TT-MFP (Adresse $17c)

* Whrend der bertragung mu offenbar im Betriebsartenregister
* $fff785 des ncr 5380 das Bit 3 (enable process interrupt)
* gesetzt sein.

**********************************************************************
*
* Interruptroutine fr TT-MFP, Interruptkanal #7 = I/O-Port 5
* (SCSI-DMA Busfehler)
*
* Rckgabewert -2
*

int_scsidma:
 tst.l    ncrdma_unsel                  ; Interrupt aktiviert ?
 beq.b    incrdma_ende                  ; nein, weiter
 movem.l  d0-d2/a0-a2,-(sp)

 moveq    #-2,d0                        ; eingetroffen (Fehler)
 move.l   ncrdma_unsel,a0
 clr.l    ncrdma_unsel                  ; Interrupt deaktivieren
 move.l   d0,(a0)                       ; als eingetroffen markieren

 move.l   ncrdma_appl,a0
 jsr      appl_IOcomplete               ; wartende APP aufwecken
 movem.l  (sp)+,d0-d2/a0-a2
incrdma_ende:
 move.b   #$7f,isrb+$80                 ; service- Bit lschen (TT-MFP)
 rte


**********************************************************************
*
* Interruptroutine fr TT-MFP, Interruptkanal #15 = I/O-Port 7
* (SCSI)
*
* Rckgabewert 0
*

int_ncr:
 tst.l    ncrdma_unsel                  ; Interrupt aktiviert ?
 beq.b    incr_ende                     ; nein, weiter
 movem.l  d0-d2/a0-a2,-(sp)

 move.l   ncrdma_unsel,a0
 clr.l    ncrdma_unsel                  ; Interrupt deaktivieren
 clr.l    (a0)                          ; als eingetroffen markieren

 move.l   ncrdma_appl,a0
 jsr      appl_IOcomplete               ; wartende APP aufwecken
 movem.l  (sp)+,d0-d2/a0-a2
incr_ende:
 move.b   #$7f,isra+$80                 ; service- Bit lschen (TT-MFP)
 rte


**********************************************************************
*
* void incrdma_unsel( a0 = long *unselect, a1 = APPL *ap );
*
* Deaktiviert den Interrupt wieder, wenn er nicht eingetroffen ist.
* (Rckgabewert -1)
*

incrdma_unsel:
 clr.l    ncrdma_unsel                  ; Interrupt deaktivieren
 moveq    #-1,d0                        ; Timeout
 move.l   d0,(a0)                       ; nicht eingetroffen
 rts


**********************************************************************
*
* long wait_NCR( d0 = long ticks_200hz )
*
* Rckgabe:    0    OK
*             -2    Busfehler
*             -1    TimeOut
*
* kein Register auer d0 wird verndert
*

wait_NCR:
 movem.l  d1-d2/a0-a2,-(sp)
 tst.w    pe_slice            ; premptiv ?
 bmi.b    wncr_no_yield       ; nein, busy waiting
 move.l   act_appl,d2
 ble.b    wncr_no_yield       ; aktuelle Applikation ungltig

* neue Routine ber evnt_IO und MFP- Interrupt

 lsr.l    #2,d0               ; AES: 50Hz statt 200Hz
wncr_neu:
 move     sr,d1
 ori      #$700,sr
 btst     #5,gpip+$80         ; DMA- Busfehler ?
 beq.b    wncr_err2           ; ja, return(-2)
 btst     #7,gpip+$80         ; schon fertig ?
 bne.b    wncr_ok2            ; ja, enable interrupt, return(0)
; Interrupt aufsetzen
 pea      incrdma_unsel(pc)
 move.l   d2,ncrdma_appl      ; act_appl
 move.l   sp,ncrdma_unsel
; Interrupt freigeben
 move.w   d1,sr
; Auf Interrupt warten
 move.l   sp,a0
;move.w   d0,d0               ; TimeOut in 50Hz- Ticks
 jsr      evnt_IO
 addq.l   #4,sp
wncr_ende:
 movem.l  (sp)+,d1-d2/a0-a2
 rts

* alte Routine mit busy waiting ber _hz_200

wncr_no_yield:
 add.l    _hz_200,d0
wncr_loop:
 btst     #5,gpip+$80
 beq.b    wncr_err
 btst     #7,gpip+$80
 bne.b    wncr_ok
 cmp.l    _hz_200,d0
 bcc.b    wncr_loop
 moveq    #-1,d0                   ; Timeout
 bra.b    wncr_ende
wncr_ok2:
 move.w   d1,sr
wncr_ok:
 moveq    #0,d0
 bra.b    wncr_ende
wncr_err2:
 move.w   d1,sr
wncr_err:
 moveq    #-2,d0
 bra.b    wncr_ende


**********************************************************************
*
* Sperre den NCR-SCSI
*
* kein Register auer d0 wird verndert
*
* und gib ihn wieder frei.
*
* Kein Register wird verndert
*
* Fr die Zeit, in der AES noch nicht initialisiert ist, kann evnt_sem
* nicht sperren, weil act_appl immer NULL ist.
*

ncr_begin:
 movem.l  d1-d2/a0-a2,-(sp)
 lea      ncr_sem,a0
 moveq    #0,d1               ; kein Timeout
 moveq    #SEM_SET,d0
 jsr      evnt_sem
 movem.l  (sp)+,d1-d2/a0-a2
 rts

ncr_end:
 movem.l  d0-d2/a0-a2,-(sp)
 lea      ncr_sem,a0
 moveq    #SEM_FREE,d0
 jsr      evnt_sem
 movem.l  (sp)+,d0-d2/a0-a2
 rts

