;   a20gate.inc, Copyright (c) 1997-1998 by Lukas Ruf,
;   Swiss Federal Institute of Technology,
;   Computer Engineering and Networks Laboratory.
;
;   TOPSY -- A Teachable Operating System.
;            Implementation of a tiny and simple
;            micro kernel for teaching purposes.
;
;   For further information, please visit http://www.tik.ee.ethz.ch/~topsy
;
;   This software is provided under the terms of the GNU General Public Licence.
;   A full copy of the GNU GPL is provided in the file COPYING found in the 
;   development root of Topsy.
;
;       This copyright notice supercedes all originally or previously used 
;       copyrights being used within the source code.
;       
;       Author: Lukas Ruf, lr@lpr.ch


;Topsy i386                                            Lukas Ruf, November  1997
;-------------------------------------------------------------------------------
; Enabling Gate A20


BIT20_ON         = 0x0DF                ;
BIT20_OFF        = 0x0DD                ;
KBC_CTR          = 0x060                ;
KBC_STAT         = 0x064                ;
KBC_CMD          = 0x0ED                ;

;Enable_A20    PROC
Enable_A20:
         PUSH   AX                     ; AX sichern
         MOV    AH,#BIT20_ON            ; Bit 20 am Gate bitte einschalten
         CALL   GATE_20                ; Funktion aufrufen
         OR     AL,AL                  ; Alles OK ?
         JZ     A20_OKP                ; Ja -> zum Ende
         STC                           ; Carry setzen -> Fehler
A20_OKP: POP    AX                     ; AX zurück
         ; Newly, we do not check for AL == 0
         CLC
         RET                           ; exit
;Enable_A20    ENDP

;GATE_20 PROC
GATE_20:
         cli
         call   empty_8042
         mov    al,#0xD1
         out    #0x64,al
         call   empty_8042
         mov    al,#0xDF                ! A20 on
         out    #0x60,al
         call   empty_8042
 
! wait until a20 really *is* enabled; it can take a fair amount of
! time on certain systems; Toshiba Tecras are known to have this
! problem.  The memory location used here is the int 0x1f vector,
! which should be safe to use; any *unused* memory location < 0xfff0
! should work here.  

TEST_ADDR  = 0x7c

        push    ds
        xor     ax,ax                   ! segment 0x0000
        mov     ds,ax
        dec     ax                      ! segment 0xffff (HMA)
        mov     gs,ax
        mov     bx,[TEST_ADDR]          ! we want to restore the value later
a20_wait:
        inc     ax
        mov     [TEST_ADDR],ax
        seg     gs
        cmp     ax,[TEST_ADDR+0x10]
        je      a20_wait                ! loop until no longer aliased
        mov     [TEST_ADDR],bx          ! restore original value
        pop     ds
                
        ret

! This routine checks that the keyboard command queue is empty
! (after emptying the output buffers)
!
! Some machines have delusions that the keyboard buffer is always full
! with no keyboard attached...

empty_8042:
       push    ecx
       mov     ecx,#0xFFFFFF

empty_8042_loop:
       dec     ecx
       jz      empty_8042_end_loop

        call    delay
        in      al,#0x64        ! 8042 status port
        test    al,#1           ! output buffer?
        jz      no_output
        call    delay
        in      al,#0x60        ! read it
        jmp     empty_8042_loop
no_output:
        test    al,#2           ! is input buffer full?
        jnz     empty_8042_loop ! yes - loop
empty_8042_end_loop:
        pop     ecx
        ret


;
;         CLI                           ; Interrupts ausschalten
;         CALL   EMPTY_8042             ; warten, bis der Eingabepuffer leer ist
;         JNZ    FAILure                ; Fehler aufgetreten
;         OUTW   #KBC_CMD,AX            ;
;         MOV    AL,#0x0D1              ; schreibe Ausgabeport
;         OUTB   #KBC_STAT,AL           ; an Kontroller senden
;         CALL   EMPTY_8042             ; warten, bis der Eingabepuffer leer ist
;         JNZ    FAILure                ; Fehler aufgetreten
;         MOV    AL,AH                  ; auszugebener Wert nach AL
;         OUTB   #KBC_CTR,AL            ; und ausgeben
;         CALL   EMPTY_8042             ; warten, bis der Eingabepuffer leer ist
;         PUSH   CX                     ; CX sichern
;         MOV    CX,#0x14               ;
;DLY:     OUTW   #KBC_CMD,AX            ; Warte solange, bis Kontroller fertig ist
;         LOOP   DLY                    ;
;         POP    CX                     ; CX zurück
;FAILure: RET                           ; zurück zum Aufrufer
;;GATE_20 ENDP
;
;;EMPTY_8042 PROC
;EMPTY_8042:
;         PUSH   CX                     ; CX sichern
;         XOR    CX,CX                  ; löschen
;TRY_KBC: OUT    #KBC_CMD,AX            ; warte-Kommando
;         INB    AL,#KBC_STAT           ; Status des Kontrollers lesen
;         AND    AL,#2                  ; testen, ob Eingabepuffer leer ist
;         LOOPNZ TRY_KBC                ; solange, bis leer, oder CX = 0
;         POP    CX                     ; CX zurück
;         RET                           ; zurück zum Aufrufer
;;EMPTY_8042 ENDP
;
;
