TITLE 'Listing 12.1'
NAME VREGA
PAGE 55,132
;
; Nom : VREGA
;
; Fonction: Routine d'interruption verticale pour EGA et VGA
;
; Appelant: Microsoft C:
;
; int EnableISR0A (); /* retourne 0 si bien installée */
;
; void DisableISR0A ();
;
; Une carte VGA PnP peut se voir attribuer une ligne IRQ autre que 2/9 :
IRQ EQU 2 ; le PC/AT redirige la ligne IRQ2 sur 9.
if IRQ lt 2 or IRQ eq 6 or IRQ eq 8 or IRQ eq 13 ; PIT/KBD/FDC/RTC/FPU
if1
%out Ligne IRQ réservée !
%out Assemblage interromptu.
endif
else
CRT_MODE EQU 49h ; adresses de la zone des informations
ADDR_6845 EQU 63h ; vidéo du BIOS
DGROUP GROUP _DATA
_TEXT SEGMENT byte public 'CODE'
ASSUME cs:_TEXT,ds:DGROUP
ISR0A PROC far ; handler d'interruption pour l'INT 0Ah
push ax ; préservation registres
push dx
push ds
mov ax,seg DGROUP
mov ds,ax ; DS -> DGROUP
if IRQ ge 8 and IRQ ne 9
mov al,20h
out 0A0h,al ; EOI au PIC esclave du PC/AT
endif
; Voir si c'est bien une interruption verticale
mov dx,3C2h ; DX := port d'E/S pour le
; registre 0 d'état des entrées
in al,dx
test al,80h ; tester le bit 7 du reg. d'état
jnz L10 ; saut si interruption verticale
; Ce n'est pas une interruption verticale. On chaîne donc le traitement
; vers l'ancien handler
if IRQ lt 8 and IRQ ne 2
mov al,20h
out 20h,al ; EOI au PIC maître du PC/AT
endif
pushf ; simuler une INT
call ds:PrevISR0A ; vers l'ancien handler de l'Int 0Ah
jmp short Lexit
; Traiter une interruption verticale
L10: mov dx,Port3x4 ; DX := 3B4h or 3D4h
in al,dx ; AL := valeur du reg. adresse du CRTC
push ax ; la sauvegarder
mov ax,DefaultVREnd ; AH := valeur par défaut pour reg. VR End
; AL := 11h (numéro du registre)
and ah,11101111b ; AH bit 4 := 0 (RAZ latch d'interruption)
out dx,ax ; modifier le registre VR End
jmp $+2 ; laisser un peu de temps au CRTC
sti ; activer les interruptions
; Faire quelque chose d'utile...
inc word ptr _VRcount ; incrémenter un compteur
; Envoyer un signal de fin d'interruption au PIC Intel 8259A pour
; autoriser les interruptions sur IRQ2 suivantes
cli ; désactiver les interruptions
mov al,20h ; port du 8259A
out 20h,al ; envoyer un EOI non spécifique au 8259A
jmp $+2 ; attendre sa réponse
; Permettre au CRTC de produire d'autres interruptions
mov ax,DefaultVREnd ; AH := valeur par défaut pour le reg. VR End
; AL := 11h (numéro du registre)
and ah,11011111b ; AH bit 5 := 0 (autoriser int. verticale)
or ah,00010000b ; AH bit 4 := 1 (activer le latch
out dx,ax ; d'interruption)
jmp $+2
pop ax
out dx,al ; restaurer précédente adresse registre
Lexit: pop ds ; restauration registres et retour
pop dx
pop ax
iret
ISR0A ENDP
;
; EnableISR0A -- Activer un handler d'Interruption
;
PUBLIC _EnableISR0A
_EnableISR0A PROC near
push bp ; préservation registres
mov bp,sp
push si
push di
mov ax,40h
mov es,ax ; ES -> zone des infos vidéo du BIOS
; Sauver les valeurs des registres du CRTC
mov dx,es:[ADDR_6845] ; DX := adresse du port CRTC
mov Port3x4,dx ; sauvegarder l'adresse
mov ax,1A00h ; AH := 1AH (numéro fonction INT 10H)
; AL := 0 (lire combinaison d'affichage)
int 10h ; AL := 1AH si fonction 1AH supportée
; BL := sous-système vidéo actif
cmp al,1Ah
jne L20 ; saut si pas VGA
cmp bl,7
je L21 ; saut si VGA
cmp bl,8
je L21 ; saut si VGA
mov ax,0FFFFh ; renvoyer 0FFFFh si ni EGA ni VGA
jmp short L23
; Obtenir la valeur par défaut pour le registre EGA Vertical Retrace End
L20: mov al,es:[CRT_MODE] ; AL := numéro du mode video du BIOS
mov bx,offset DGROUP:EGADefaultVals
xlat ; AL := valeur par défaut pour le reg. VR End
jmp short L22
; Obtenir la valeur par défaut pour le registre VGA Vertical Retrace End
L21: mov al,VREndReg ; AL := numéro du registre VR End
out dx,al
inc dx ; DX := 3B5H or 3D5H
in al,dx ; AL := valeur courante de ce registre
L22: mov VREndValue,al ; la sauvegarder
; Sauvegarder l'ancien vecteur d'interruption 0Ah
if IRQ eq 9
mov ax,350Ah ; AH := 35H (numéro de la fonction INT 21h)
; AL := 0AH (numéro de l'interruption)
else
if IRQ ge 8
mov ax,3570h+IRQ-8
else
mov ax,3508h+IRQ
endif
endif
int 21h ; ES:BX := précédent vecteur de l'Int 0AH
mov word ptr PrevISR0A,bx
mov word ptr PrevISR0A+2,es ; le sauvegarder
; Modifier le vecteur d'interruption avec l'adresse du présent handler
push ds ; préserver DS
mov dx,offset ISR0A
push cs
pop ds ; DS:DX -> ISR0A
if IRQ eq 9
mov ax,250Ah ; AH := 25H (numéro de fonction de l'Int 21H)
; AL := 0AH (numéro interruption)
else
if IRQ ge 8
mov ax,2570h+IRQ-8
else
mov ax,2508h+IRQ
endif
endif
int 21h ; modifier le vecteur d'interruption Int 0AH
pop ds ; restaurer DS
; Réactiver IRQ2 en mettant à 0 le bit 2 du registre de masque du 8259A
cli ; verrouiller les interruptions
if IRQ eq 9
mov dx,21h ; DX := registre de masque du 8259A
in al,dx ; AL := valeur présente
and al,11111011b ; RAZ bit 2
else
if IRQ ge 8
mov dx,0A1h
in al,dx
and al,not(1 shl (IRQ-8))
else
mov dx,21h
in al,dx
and al,not(1 shl IRQ)
endif
endif
out dx,al
; Réactiver les interruptions verticales
mov dx,Port3x4 ; DX := 3B4H or 3D4H
mov ax,DefaultVREnd
and ah,11001111b
out dx,ax ; RAZ bits 4 et 5 du registre VR End
jmp $+2 ; laisser le temps au CRTC
or ah,00010000b
out dx,ax ; mise à 1 du bit 4
jmp $+2
sti ; réactiver les interruptions
xor ax,ax ; AX := 0 (valeur de retour)
L23: pop di ; restauration registres et retour
pop si
mov sp,bp
pop bp
ret
_EnableISR0A ENDP
;
; DisableISR0A -- Désactiver le handler d'interruptions verticales
;
PUBLIC _DisableISR0A
_DisableISR0A PROC near
push bp
mov bp,sp
push si
push di
push ds
; Désactiver les interruptions verticales
cli ; verrouiller les interruptions
mov dx,Port3x4
mov ax,DefaultVREnd
out dx,ax ; restaurer le reg. Vertical Retrace End
jmp $+2
sti ; réactiver les interruptions
; Restaurer le précédent handler du vecteur d'interruption 0Ah
lds dx,PrevISR0A ; DS:DX := précédent vecteur Int 0AH
if IRQ eq 9
mov ax,250Ah ; AH := 25H (numéro fonction INT 21H)
; AL := 0AH (numéro interruption)
else
if IRQ ge 8
mov ax,2570h+IRQ-8
else
mov ax,2508h+IRQ
endif
endif
int 21h
pop ds ; restauration registres et retour
pop di
pop si
mov sp,bp
pop bp
ret
_DisableISR0A ENDP
_TEXT ENDS
_DATA SEGMENT word public 'DATA'
EXTRN _VRcount:word ; déclaré dans le pgm C qui appelle
PrevISR0A DD ? ; zone de sauvegarde pour l'ancien
; vecteur d'interruption 0Ah
Port3x4 DW ? ; 3B4h ou 3D4h
DefaultVREnd LABEL word
VREndReg DB 11h ; numéro registre Vertical Retrace End
VREndValue DB ? ; valeur par défaut pour reg.VR End
EGADefaultVals DB 2Bh,2Bh,2Bh,2Bh,24h,24h,23h,2Eh ; valeur par défaut
DB 00h,00h,00h,00h,00h,24h,23h,2Eh ; pour registre EGA
DB 2Bh ; EGA VR End
_DATA ENDS
endif
END