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

Obsah / Ovladače / IRQ / Funkce interface ovladače řadiče IRQ

Zdrojový kód: DRIVERS\SYSTEM\IRQ.ASM


Funkce interface ovladače řadiče IRQ


IRQDevName:	CTEXTDATA 'irq'
IRQDevShort:	CTEXTDATA 'Interrupt 8259A'

IRQDevFull:	LANGTEXTSTR IRQDevFullEN,LANG_ENGLISH,SUBLANG_DEFAULT,2
 		LANGTEXTSTR IRQDevFullCZ,LANG_CZECH,  SUBLANG_DEFAULT,0

IRQDevFullEN:	CTEXTDATA 'Programmable interrupt controller 8259A'
IRQDevFullCZ:	CTEXTDATA 'Programovateln',0c3h,0bdh,' ',0c5h,99h,'adi',\
			0c4h,8dh,' p',0c5h,99h,'eru',0c5h,0a1h,'en',0c3h,0adh,\
			' 8259A'

IRQDevInt:	dd	DEV_GEN_ID
		dd	DEV_IRQ_ID
		dd	DEV_NUL_ID

IRQDevRes1Name:	CTEXTDATA 'cascade'
IRQDevRes2Name:	CTEXTDATA 'ctrl#1'
IRQDevResNName:	CTEXTDATA 'ctrl#2'

; ------------- IRQ device descriptor

IRQDevice:	dd	IRQDev			; current IRQ device descriptor

; ------------- Interrupt controller 8259A

%define		IRQDevVendor  DefaultVendor

IRQDev:		DEVICEIRQ 0,DEV_STATIC,1,0,0,IRQ_CHANNELS,IRQDev

IRQDev:		DEVICEIRQ 0,DEV_STATIC,1,0,0,IRQ_CHANNELS,IRQDev

IRQDevRes1:	DEVRESOURCE IRQDevRes2,IRQDevRes0,IRQ_CASCADE,IRQ_CASCADE, \
			DEVRES_IRQ,DEVRES_STATIC,IRQDevRes1Name
IRQDevRes2:	DEVRESOURCE IRQDevResN,IRQDevRes1,IRQ1_BASE,IRQ1_BASE+1, \
			DEVRES_PORT,DEVRES_STATIC,IRQDevRes2Name
IRQDevResN:	DEVRESOURCE IRQDevRes0,IRQDevRes2,IRQ2_BASE,IRQ2_BASE+1, \
			DEVRES_PORT,DEVRES_STATIC,IRQDevResNName

IRQDev je struktura popisovače standardního ovladače řadiče IRQ. V proměnné IRQDevice je uložen ukazatel na aktuální ovladač řadiče IRQ - při instalaci nového ovladače je tento ukazatel přepsán novým ukazatelem.


; -----------------------------------------------------------------------------
;                           Install IRQ device
; -----------------------------------------------------------------------------
; OUTPUT:	CY = error
; -----------------------------------------------------------------------------

; ------------- Push registers

IRQInstall:	push	ebx		; push EBX
		push	ecx		; push ECX

; ------------- Register IRQ device

		mov	ebx,IRQDev	; EBX <- device descriptor
		xor	ecx,ecx		; ECX <- 0, no parent device
		call	DevRegister	; register device

; ------------- Pop registers

		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
		ret

Funkce IRQInstall nainstaluje standardní ovladač řadiče IRQ - zaregistruje ovladač do systému. V případě chyby je navrácen příznak chyby CY.


; -----------------------------------------------------------------------------
;                           Uninstall IRQ device
; -----------------------------------------------------------------------------
; OUTPUT:	CY = error
; -----------------------------------------------------------------------------

; ------------- Push registers

IRQUninstall:	push	ebx		; push EBX

; ------------- Unregister IRQ device

		mov	ebx,IRQDev	; EBX <- device descriptor
		call	DevUnregister	; unregister device

; ------------- Pop registers

		pop	ebx		; pop EBX
		ret

Funkce IRQUninstall odinstaluje standardní ovladač řadiče IRQ - odregistruje ovladač ze systému. V případě chyby je navrácen příznak chyby CY. Funkce nezajistí instalaci náhradního ovladače řadiče IRQ.


; -----------------------------------------------------------------------------
;               Driver function: Remap base interrupt address
; -----------------------------------------------------------------------------
; INPUT:	EAX = new base interrupt (0 to 248, must be multiple of 8)
;		EBX = device descriptor DEVIRQ
; OUTPUT:	CY = error (invalid base interrupt)
; NOTES:	All interrupts should be disabled first.
; -----------------------------------------------------------------------------

; ------------- Push registers

IRQDevRemap:	push	eax		; push EAX

; ------------- Check base interrupt (0 to 255, must be multiple of 8)

		test	eax,~0f8h	; check valid bits
		stc			; set error flag
		jnz	IRQDevRemap9	; invalid base interrupt
		mov	[ebx+DEVIRQ_Base],eax ; set new base interrupt
		mov	ah,al		; AH <- push base interrupt

; ------------- Initialize flags

		mov	byte [ebx+DEVIRQ_Flags],0 ; not in-service

; ------------- Disable all interrupts

		mov	al,0ffh		; AL <- interrupt mask
		out	IRQ2_IMR,al	; disable all interrupts on SLAVE
		out	IRQ1_IMR,al	; disable all interrupts on MASTER

; ------------- Set MASTER control word ICW1
; ICW4 needed, cascade mode, interval of 8, edge triggered, A5..A7=0

		mov	al,B0+B4	; ICW1: ICW1 and ICW4 flags
		out	IRQ1_CMD,al	; set ICW1

; ------------- Set MASTER control word ICW2 (base interrupt address)

		mov	al,ah		; ICW2: base interrupt address
		out	IRQ1_IMR,al	; set ICW2

; ------------- Set MASTER control word ICW3 (cascade mask)

		mov	al,(1 << IRQ_CASCADE) ; ICW3: slave attached to line 2
		out	IRQ1_IMR,al	; set ICW3

; ------------- Set MASTER control word ICW4
; 8086 mode, normal EOI (not auto), non-buffered mode, not fully nested mode

		mov	al,B0		; ICW4: x86 mode, normal EOI
		out	IRQ1_IMR,al	; set ICW4

; ------------- Set MASTER control word OCW3
; Read interrupt request register, no pool command, no special mask

		mov	al,B3+2		; switch to interrupt request register
		out	IRQ1_CMD,al	; set OCW3 (IRR register)

; ------------- Set SLAVE control word ICW1
; ICW4 needed, cascade mode, interval of 8, edge triggered, A5..A7=0

		mov	al,B0+B4	; ICW1: ICW1 and ICW4 flags
		out	IRQ2_CMD,al	; set ICW1

; ------------- Set SLAVE control word ICW2 (base interrupt address)

		mov	al,ah		; ICW2: base interrupt address
		add	al,IRQ_CHANNEL2	; ICW2: base interrupt address
		out	IRQ2_IMR,al	; set ICW2

; ------------- Set SLAVE control word ICW3 (cascade number)

		mov	al,IRQ_CASCADE	; ICW3: it is slave on line 2
		out	IRQ2_IMR,al	; set ICW3

; ------------- Set SLAVE control word ICW4
; 8086 mode, normal EOI (not auto), non-buffered mode, not fully nested mode

		mov	al,B0		; ICW4: x86 mode, normal EOI
		out	IRQ2_IMR,al	; set ICW4

; ------------- Set SLAVE control word OCW3
; Read interrupt request register, no pool command, no special mask

		mov	al,B3+2		; switch to interrupt request register
		out	IRQ2_CMD,al	; set OCW3 (IRR register)

; ------------- Restore current interrupt mask

		mov	eax,[ebx+DEVIRQ_Cache] ; AX <- current master mask
		out	IRQ1_IMR,al	; set master mask
		mov	al,ah		; AL <- slave mask
		out	IRQ2_IMR,al	; set slave mask

; ------------- Acknowledge all interrupts (set OCW2)

		mov	al,B5		; AL <- non-specific EOI
		out	IRQ1_CMD,al	; acknowledge interrupts on slave
		out	IRQ2_CMD,al	; acknowledge interrupts on master

; ------------- Pop registers

		clc			; clear error flag
IRQDevRemap9:	pop	eax		; pop EAX
		ret

Funkce IRQDevRemap přemapuje základní vektor přerušení. Na vstupu funkce obsahuje registr EAX nový základní vektor přerušení. Číslo základního vektoru přerušení musí být násobkem čísla 8 a je v rozsahu 0 až 248. Registr EBX obsahuje popisovač zařízení. Před voláním funkce se doporučuje všechna přerušení zakázat. V případě chyby (neplatný vektor přerušení) navrátí funkce příznak chyby CY.

Funkce na začátku zkontroluje platnost vektoru přerušení. Inicializuje příznaky a zakáže všechna přerušení. Nastaví řídicí slova pro první i druhý řadič přerušení - druhý řadič přerušení (slave) je připojen k prvnímu (master) kaskádově přes signál IRQ2. Nakonec nastaví původní masku přerušení a potvrzením ukončí všechny případné požadavky o přerušení.


; -----------------------------------------------------------------------------
;                   Driver function: Initialize IRQ device
; -----------------------------------------------------------------------------
; INPUT:	EBX = device descriptor DEVIRQ
; OUTPUT:	CY = error
; NOTES:	Base interrupt is validated into valid value.
; -----------------------------------------------------------------------------

; ------------- Push registers

IRQDevInit:	push	eax		; push EAX
		push	ecx		; push ECX

; ------------- Clear mask

		mov	dword [ebx+DEVIRQ_Cache],~(1 << IRQ_CASCADE)

; ------------- Initialize controllers (and remap base interrupt)

		mov	eax,[ebx+DEVIRQ_Base] ; EAX <- current base interrupt
		and	eax,0f8h	; validate base inteerrupt
		call	IRQDevRemap	; remap base interrupt

; ------------- Pop registers (here should be NC)

		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

Funkce IRQDevInit inicializuje řadič přerušení. Na vstupu funkce obsahuje registr EBX popisovač zařízení. Funkce nastaví základní vektor přerušení na hodnotu uchovanou v popisovači zařízení, jen provede její opravu pro případ neplatné hodnoty. Všechna přerušení se zakáží.


; -----------------------------------------------------------------------------
;                   Driver function: Deinitialize IRQ device
; -----------------------------------------------------------------------------
; INPUT:	EBX = device descriptor DEVIRQ
; OUTPUT:	CY = error
; -----------------------------------------------------------------------------

; ------------- Push registers

IRQDevDeinit:	push	eax		; push EAX

; ------------- Disable all interrupts

		mov	al,0ffh		; AL <- interrupt mask
		out	IRQ2_IMR,al	; disable all interrupts on SLAVE
		out	IRQ1_IMR,al	; disable all interrupts on MASTER

; ------------- Acknowledge all interrupts (set OCW2)

		mov	al,B5		; AL <- non-specific EOI
		out	IRQ1_CMD,al	; acknowledge interrupts on slave
		out	IRQ2_CMD,al	; acknowledge interrupts on master

; ------------- Pop registers

		clc			; clear error flag
		pop	eax		; pop EAX
		ret

Funkce IRQDevDeinit deinicializuje ovladač řadiče IRQ, jehož popisovač je funkci předán v registru EBX. V případě chyby navrátí funkce příznak chyby CY. Funkce zajistí zákaz a potvrzení všech přerušení.


; -----------------------------------------------------------------------------
;                    Driver function: Get IRQ channel info
; -----------------------------------------------------------------------------
; INPUT:	EAX = IRQ channel number
;		EBX = device descriptor DEVIRQ
; OUTPUT:	ECX = number of channels
;		EDX = flags (see Channel info flags), 0=invalid channel
;		ESI = base interrupt
;		CY = invalid channel number (ECX and ESI are valid)
; -----------------------------------------------------------------------------

; ------------- Prepare default parameters

IRQDevInfo:	mov	ecx,IRQ_CHANNELS ; ECX <- number of IRQ channels
		xor	edx,edx		; EDX <- 0, invalid channel
		mov	esi,[ebx+DEVIRQ_Base] ; ESI <- base interrupt

; ------------- Check IRQ channel number

		cmp	eax,ecx		; check IRQ channel number
		cmc			; set error flag
		jc	IRQDevInfo8	; invalid channel number

; ------------- Disable cascade IRQ

		cmp	al,IRQ_CASCADE	; cascade IRQ ?
		stc			; set error flag
		je	IRQDevInfo8	; cascade IRQ is invalid
		mov	dl,IRQINFO_VALID ; EDX <- channel is valid

; ------------- Check if channel is enabled

		bt	dword [ebx+DEVIRQ_Cache],eax ; is channel enabled?
		jc	IRQDevInfo4	; channel is disabled
		or	dl,IRQINFO_ENABLED ; set enabled flag
IRQDevInfo4:	clc			; clear error flag
IRQDevInfo8:	ret

Funkce IRQDevInfo slouží ke zjištění informací o IRQ kanálu. Na vstupu funkce obsahuje registr EAX číslo kanálu IRQ, pro který mají být informace zjištěny. Registr EBX obsahuje popisovač zařízení. Na výstupu z funkce je navrácen v registru ECX počet kanálů IRQ, v registru ESI číslo základního vektoru přerušení a v registru EDX příznaky (nebo jejich kombinace) s těmito hodnotami: IRQINFO_VALID kanál je platný, IRQINFO_ENABLED kanál je povolen (může nastat přerušení). V případě neplatného čísla IRQ kanálu navrátí funkce příznak CY a obsah registru EDX je nulový. Počet kanálů navrácený v registru ECX a bázový vektor v registru ESI jsou i v případě chyby platné. Funkce vyžaduje uzamknutí pomocí rychlého zámku.


; -----------------------------------------------------------------------------
;                    Driver function: Enable IRQ channel
; -----------------------------------------------------------------------------
; INPUT:	EAX = IRQ channel number
;		EBX = device descriptor DEVIRQ
; OUTPUT:	CY = invalid channel number or channel is already enabled
; -----------------------------------------------------------------------------

; ------------- Check channel number

IRQDevEnable:	cmp	eax,IRQ_CHANNELS ; check IRQ channel number
		jae	short IRQDevPending8 ; invalid channel number

; ------------- Check if channel is already enabled

		bt	dword [ebx+DEVIRQ_Cache],eax ; is channel enabled?
		jnc	short IRQDevPending8 ; channel is already enabled

; ------------- Enable IRQ channel

		call	IRQDev0Enable	; enable IRQ channel
		clc			; clear error flag
		ret

Funkce IRQDevEnable slouží k povolení IRQ kanálu. Na vstupu funkce obsahuje registr EAX číslo kanálu IRQ, který má být povolen. Registr EBX obsahuje popisovač zařízení. V případě chyby (zadáno neplatné číslo kanálu nebo kanál je již povolen) navrátí funkce příznak chyby CY. Funkce vyžaduje uzamknutí pomocí rychlého zámku.


; -----------------------------------------------------------------------------
;                    Driver function: Disable IRQ channel
; -----------------------------------------------------------------------------
; INPUT:	EAX = IRQ channel number
;		EBX = device descriptor DEVIRQ
; OUTPUT:	CY = invalid channel number or channel is already disabled
; -----------------------------------------------------------------------------

; ------------- Check channel number

IRQDevDisable:	cmp	eax,IRQ_CHANNELS ; check IRQ channel number
		jae	short IRQDevPending8 ; invalid channel number

; ------------- Cannot disable reserved cascade channel

		cmp	al,IRQ_CASCADE	; cascade IRQ channel ?
		je	short IRQDevPending8 ; cascade IRQ is reserved

; ------------- Check if channel is already disabled

		bt	dword [ebx+DEVIRQ_Cache],eax ; is channel disabled?
		jc	IRQDevDisable9	; channel is already disabled

; ------------- Disable IRQ channel

		call	IRQDev0Disable	; disable IRQ channel
		clc			; clear error flag
IRQDevDisable9:	ret

Funkce IRQDevDisable slouží k zakázání IRQ kanálu. Na vstupu funkce obsahuje registr EAX číslo kanálu IRQ, který má být zakázán. Registr EBX obsahuje popisovač zařízení. V případě chyby (zadáno neplatné číslo kanálu nebo kanál je již zakázaný nebo se jedná o rezervovaný kaskádový kanál) navrátí funkce příznak chyby CY. Funkce vyžaduje uzamknutí pomocí rychlého zámku.


; -----------------------------------------------------------------------------
;                 Driver function: Check if interrupt is pending
; -----------------------------------------------------------------------------
; INPUT:	EAX = IRQ channel number
;		EBX = device descriptor DEVIRQ
; OUTPUT:	CY = interrupt is pending or invalid channel number
; -----------------------------------------------------------------------------

IRQDevPending:	cmp	eax,IRQ_CHANNELS ; check IRQ channel number
		jb	IRQDev0Pending	; channel is OK, check pending
IRQDevPending8:	stc			; set error flag
		ret

Funkce IRQDevPending slouží ke zjištění, zda je připravený požadavek přerušení od IRQ kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Registr EBX obsahuje popisovač zařízení. Na výstupu funkce je navrácen příznak CY, pokud je požadavek přerušení připraven nebo pokud bylo zadáno neplatné číslo kanálu. Funkce vyžaduje uzamknutí pomocí rychlého zámku.


; -----------------------------------------------------------------------------
;               Driver function: Check if interrupt is in-service
; -----------------------------------------------------------------------------
; INPUT:	EAX = IRQ channel number
;		EBX = device descriptor DEVIRQ
; OUTPUT:	CY = interrupt is in-service or invalid channel number
; -----------------------------------------------------------------------------

IRQDevInServ:	cmp	eax,IRQ_CHANNELS ; check IRQ channel number
		jb	IRQDev0InServ	; channel is OK, check in-service
		stc			; set error flag
		ret

Funkce IRQDevInServ slouží ke zjištění, zda probíhá obsluha přerušení od IRQ kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Registr EBX obsahuje popisovač zařízení. Na výstupu funkce je navrácen příznak CY, pokud probíhá obsluha přerušení od IRQ kanálu nebo pokud bylo zadáno neplatné číslo kanálu. Funkce vyžaduje uzamknutí pomocí rychlého zámku.


; -----------------------------------------------------------------------------
;                   Driver function: Acknowledge interrupt
; -----------------------------------------------------------------------------
; INPUT:	EAX = IRQ channel number
;		EBX = device descriptor DEVIRQ
; OUTPUT:	CY = invalid channel number
; -----------------------------------------------------------------------------

; ------------- Check channel number

IRQDevAck:	cmp	eax,IRQ_CHANNELS ; check IRQ channel number
		jae	short IRQDevPending8 ; invalid channel number

; ------------- Acknowledge interrupt

		call	IRQDev0Ack	; acknowledge interrupt
		clc			; clear error flag
		ret

Funkce IRQDevAck slouží k potvrzení požadavku přerušení od IRQ kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Registr EBX obsahuje popisovač zařízení. V případě chyby (zadáno neplatné číslo kanálu) navrátí funkce příznak chyby CY. Funkce vyžaduje uzamknutí pomocí rychlého zámku.


Obsah / Ovladače / IRQ / Funkce interface ovladače řadiče IRQ