Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

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