Obsah / Ovladače / IRQ / Interní funkce ovladače řadiče IRQ
Zdrojový kód:
DRIVERS\SYSTEM\IRQ.ASM
Interní
funkce ovladače řadiče IRQ
Definice konstant
řadiče IRQ:
IRQ_CHANNELS EQU 16 ; number of IRQ channels
IRQ_CHANNEL2 EQU 8 ; first channel of slave controller
IRQ_CASCADE EQU 2 ; cascade IRQ channel (on controller 1)
; ------------- Ports - controller 1 (master)
IRQ1_BASE EQU 20h ; base port of controller 1
IRQ1_CMD EQU IRQ1_BASE+0 ; command register WRITE (controller 1)
IRQ1_REQ EQU IRQ1_BASE+0 ; request register READ (controller 1)
IRQ1_IMR EQU IRQ1_BASE+1 ; interrupt mask register (contr. 1)
; ------------- Ports - controller 2 (slave)
IRQ2_BASE EQU 0a0h ; base port of controller 2
IRQ2_CMD EQU IRQ2_BASE+0 ; command register WRITE (controller 2)
IRQ2_REQ EQU IRQ2_BASE+0 ; request register READ (controller 2)
IRQ2_IMR EQU IRQ2_BASE+1 ; interrupt mask register (contr. 2)
|
IRQ_CHANNELS udává
počet kanálů řadiče IRQ. Pro jednoduchost se započítává
i IRQ2 (kaskáda), ale je natvrdo povolený a nelze ho zakázat.
IRQ_CHANNEL2 je číslo prvního kanálu druhého řadiče.
IRQ_CASCADE je číslo IRQ pro kaskádové připojení druhého
řadiče k prvnímu.
IRQ1_BASE je bázová
adresa prvního řadiče přerušení. IRQ1_CMD je zápisový
port povelů, IRQ1_REQ je čtecí port požadavků a IRQ1_IMR je
registr masky přerušení prvního řadiče přerušení.
Analogické hodnoty platí i pro druhý řadič.
; -----------------------------------------------------------------------------
; Internal function: Enable IRQ channel
; -----------------------------------------------------------------------------
; INPUT: EAX = IRQ channel number (0 to 15)
; EBX = device descriptor DEVIRQ
; NOTES: EAX not checked for validity
; IRQ device must be locked.
; -----------------------------------------------------------------------------
; ------------- Clear IRQ bit
IRQDev0Enable: btr dword [ebx+DEVIRQ_Cache],eax ; reset IRQ bit (=enable)
jnc IRQDev0Enable8 ; IRQ is already enabled
; ------------- Push registers
IRQDev0Enable2: push eax ; push EAX
; ------------- Check if use controller 2
cmp al,IRQ_CHANNEL2 ; use controller 2?
mov eax,[ebx+DEVIRQ_Cache] ; EAX <- current mask
jae IRQDev0Enable4 ; use controller 2
; ------------- Send mask to controller 1 (MASTER)
out IRQ1_IMR,al ; send interrupt mask 1
; ------------- Pop registers
pop eax ; pop EAX
ret
; ------------- Send mask to controller 2 (SLAVE)
IRQDev0Enable4: mov al,ah ; AL <- interrupt mask 2
out IRQ2_IMR,al ; send interrupt mask 2
; ------------- Pop registers
pop eax ; pop EAX
IRQDev0Enable8: ret
; -----------------------------------------------------------------------------
; Internal function: Disable IRQ channel
; -----------------------------------------------------------------------------
; INPUT: EAX = IRQ channel number (0 to 15)
; EBX = device descriptor DEVIRQ
; NOTES: EAX not checked for validity
; IRQ device must be locked.
; -----------------------------------------------------------------------------
; ------------- Set IRQ bit
IRQDev0Disable: bts dword [ebx+DEVIRQ_Cache],eax ; set IRQ bit (=disable)
jnc short IRQDev0Enable2 ; disable IRQ
ret
|
IRQDev0Enable
je interní funkce řadiče IRQ. Povolí IRQ kanál, jehož
číslo obsahuje na vstupu funkce registr EAX. V registru EBX je
ukazatel na popisovač ovladače řadiče přerušení. Hodnota
registru EAX není kontrolovaná na platnost a musí být v
rozsahu 0 až 15. Funkce IRQDev0Disable zakáže
IRQ kanál.
; -----------------------------------------------------------------------------
; Internal function: Check if interrupt is pending
; -----------------------------------------------------------------------------
; INPUT: EAX = IRQ channel number (0 to 15)
; EBX = device descriptor DEVIRQ
; OUTPUT: CY = interrupt is pending
; NOTES: EAX not checked for validity
; IRQ device must be locked.
; -----------------------------------------------------------------------------
; ------------- Push registers
IRQDev0Pending: push ecx ; push ECX
; ------------- Check if use controller 2
cmp al,IRQ_CHANNEL2 ; use controller 2?
xchg eax,ecx ; ECX <- push IRQ number
mov al,B3+2 ; OCW3: read request register
jae IRQDev0Pending5 ; use controller 2
; ------------- Get request mask from controller 1 (MASTER)
btr dword [ebx+DEVIRQ_Flags],DEVIRQ_InSrv1_b ; reset flag
jc IRQDev0Pending3 ; register is in-service mode
IRQDev0Pending2:in al,IRQ1_REQ ; get request mask 1
jmp short IRQDev0Pending8
; ------------- Set pending mode
IRQDev0Pending3:out IRQ1_CMD,al ; switch to request register
jmp short IRQDev0Pending2 ; short delay
IRQDev0Pending4:out IRQ2_CMD,al ; switch to request register
jmp short IRQDev0Pending6 ; short delay
; ------------- Get request mask from controller 2 (SLAVE)
IRQDev0Pending5:btr dword [ebx+DEVIRQ_Flags],DEVIRQ_InSrv2_b ; reset flag
jc IRQDev0Pending4 ; register is in-service mode
IRQDev0Pending6:in al,IRQ2_REQ ; get request mask 2
mov ah,al ; AH <- request mask 2
; ------------- Check if IRQ is pending
IRQDev0Pending8:bt eax,ecx ; check if IRQ is pending
; ------------- Pop registers
xchg eax,ecx ; pop EAX
pop ecx ; pop ECX
ret
|
IRQDev0Pending
je interní funkce řadiče IRQ sloužící k testu, zda je
připraven požadavek přerušení od kanálu IRQ, jehož číslo
obsahuje na vstupu funkce registr EAX. V registru EBX je ukazatel
na popisovač ovladače řadiče přerušení. Hodnota registru
EAX není kontrolovaná na platnost a musí být v rozsahu 0 až
15. Funkce navrátí příznak CY v případě, že je připraven
požadavek přerušení.
; -----------------------------------------------------------------------------
; Internal function: Check if interrupt is in-service
; -----------------------------------------------------------------------------
; INPUT: EAX = IRQ channel number (0 to 15)
; EBX = device descriptor DEVIRQ
; OUTPUT: CY = interrupt is in-service
; NOTES: EAX not checked for validity
; IRQ device must be locked.
; -----------------------------------------------------------------------------
; ------------- Push registers
IRQDev0InServ: push ecx ; push ECX
; ------------- Check if use controller 2
cmp al,IRQ_CHANNEL2 ; use controller 2?
xchg eax,ecx ; ECX <- push IRQ number
mov al,B3+3 ; OCW3: read in-service register
jae IRQDev0InServ5 ; use controller 2
; ------------- Get in-service mask from controller 1 (MASTER)
bts dword [ebx+DEVIRQ_Flags],DEVIRQ_InSrv1_b ; set flag
jnc IRQDev0InServ3 ; register is not in-service mode
IRQDev0InServ2: in al,IRQ1_REQ ; get in-service mask 1
jmp short IRQDev0InServ8
; ------------- Set in-service mode
IRQDev0InServ3: out IRQ1_CMD,al ; switch to in-service register
jmp short IRQDev0InServ2 ; short delay
IRQDev0InServ4: out IRQ2_CMD,al ; switch to in-service register
jmp short IRQDev0InServ6 ; short delay
; ------------- Get in-service mask from controller 2 (SLAVE)
IRQDev0InServ5: bts dword [ebx+DEVIRQ_Flags],DEVIRQ_InSrv2_b ; set flag
jnc IRQDev0InServ4 ; register is not in-service mode
IRQDev0InServ6: in al,IRQ2_REQ ; get in-service mask 2
mov ah,al ; AH <- in-service mask 2
; ------------- Check if IRQ is in-service
IRQDev0InServ8: bt eax,ecx ; check if IRQ is in-service
; ------------- Pop registers
xchg eax,ecx ; pop EAX
pop ecx ; pop ECX
ret
|
IRQDev0InServ
je interní funkce řadiče IRQ sloužící k testu, zda
probíhá obsluha požadavku přerušení od kanálu IRQ, jehož
číslo obsahuje na vstupu funkce registr EAX. V registru EBX je
ukazatel na popisovač ovladače řadiče přerušení. Hodnota
registru EAX není kontrolovaná na platnost a musí být v
rozsahu 0 až 15. Funkce navrátí příznak CY v případě, že
probíhá obsluha požadavku přerušení.
; -----------------------------------------------------------------------------
; Internal function: Acknowledge interrupt
; -----------------------------------------------------------------------------
; INPUT: EAX = IRQ channel number (0 to 15)
; EBX = device descriptor DEVIRQ (currently not used)
; NOTES: EAX not checked for validity
; Interrupt should be disabled first.
; IRQ device must be locked.
; -----------------------------------------------------------------------------
; ------------- Push registers
IRQDev0Ack: push eax ; push EAX
; ------------- Check if use controller 2 (SLAVE)
cmp al,IRQ_CHANNEL2 ; use controller 2?
jb IRQDev0Ack4 ; use controller 1 (MASTER)
; ------------- Acknowledge interrupt to controller 2 (using specific EOI)
add al,(3 << 5) - IRQ_CHANNEL2 ; AL <- OCW2 command 60h
out IRQ2_CMD,al ; acknowledge interrupt to SLAVE
; ------------- Acknowledge interrupt to controller 1 (using specific EOI)
mov al,IRQ_CASCADE ; AL <- IRQ 2 (cascade)
IRQDev0Ack4: add al,(3 << 5) ; AL <- OCW2 command 60h
out IRQ1_CMD,al ; acknowledge interrupt to MASTER
; ------------- Pop registers
pop eax ; pop EAX
ret
|
IRQDev0Ack
je interní funkce řadiče IRQ sloužící k potvrzení
požadavku přerušení od kanálu IRQ, jehož číslo obsahuje
na vstupu funkce registr EAX. V registru EBX je ukazatel na
popisovač ovladače řadiče přerušení. Hodnota registru EAX
není kontrolovaná na platnost a musí být v rozsahu 0 až 15.
Obsah / Ovladače / IRQ / Interní funkce ovladače řadiče IRQ