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

Obsah / Ovladače / DMA / Interní funkce ovladače řadiče DMA

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


Interní funkce ovladače řadiče DMA

Definice konstant řadiče DMA:


DMA_CHANNELS	EQU	8		; number of DMA channels
DMA_CASCADE	EQU	4		; channel 4 is reserved (cascade)

; ------------- DMA modes

DMAMODE_VERIFY	EQU	B6		; DMA verify (verify,increment,single)
DMAMODE_READ	EQU	B2+B6		; DMA read (read, increment, single)
DMAMODE_WRITE	EQU	B3+B6		; DMA write (write, increment, single)
DMAMODE_CASCADE	EQU	B6+B7		; DMA cascade
DMAMODE_INIT	EQU	B4		; DMA autoinit

; ------------- Ports - controller 1

DMA1_BASE	EQU	0		; base port of controller 1 (8-bit)

DMA1_CMD	EQU	DMA1_BASE+8	; command register WRITE (controller 1)
DMA1_STAT	EQU	DMA1_BASE+8	; status register READ (controller 1)
DMA1_REQ	EQU	DMA1_BASE+9	; request register WRITE (controller 1)
DMA1_MASK	EQU	DMA1_BASE+10	; single-channel mask WRITE (ctrl 1)
DMA1_MODE	EQU	DMA1_BASE+11	; mode register WRITE (controller 1)
DMA1_CLRFF	EQU	DMA1_BASE+12	; clear flip-flop WRITE (controller 1)
DMA1_RESET	EQU	DMA1_BASE+13	; master clear WRITE (controller 1)
DMA1_TEMP	EQU	DMA1_BASE+13	; temporary register READ (ctrl 1)
DMA1_CMASK	EQU	DMA1_BASE+14	; clear mask (controller 1)
DMA1_AMASK	EQU	DMA1_BASE+15	; all-channels mask WRITE (ctrl 1)

; ------------- Ports - controller 2

DMA2_BASE	EQU	0c0h		; base port of controller 2 (16-bit)

DMA2_CMD	EQU	DMA2_BASE+2*8	; command register WRITE (controller 2)
DMA2_STAT	EQU	DMA2_BASE+2*8	; status register READ (controller 2)
DMA2_REQ	EQU	DMA2_BASE+2*9	; request register WRITE (controller 2)
DMA2_MASK	EQU	DMA2_BASE+2*10	; single-channel mask WRITE (ctrl 2)
DMA2_MODE	EQU	DMA2_BASE+2*11	; mode register WRITE (controller 2)
DMA2_CLRFF	EQU	DMA2_BASE+2*12	; clear flip-flop WRITE (controller 2)
DMA2_RESET	EQU	DMA2_BASE+2*13	; master clear WRITE (controller 2)
DMA2_TEMP	EQU	DMA2_BASE+2*13	; temporary register READ (ctrl 2)
DMA2_CMASK	EQU	DMA2_BASE+2*14	; clear mask (controller 2)
DMA2_AMASK	EQU	DMA2_BASE+2*15	; all-channels mask WRITE (ctrl 2)

; ------------- Ports - address registers

DMA_ADDR0	EQU	DMA1_BASE+0	; channel 0 address
DMA_ADDR1	EQU	DMA1_BASE+2	; channel 1 address
DMA_ADDR2	EQU	DMA1_BASE+4	; channel 2 address
DMA_ADDR3	EQU	DMA1_BASE+6	; channel 3 address
DMA_ADDR4	EQU	DMA2_BASE+2*0	; channel 4 address
DMA_ADDR5	EQU	DMA2_BASE+2*2	; channel 5 address
DMA_ADDR6	EQU	DMA2_BASE+2*4	; channel 6 address
DMA_ADDR7	EQU	DMA2_BASE+2*6	; channel 7 address

; ------------- Ports - address registers

DMA_COUNT0	EQU	DMA1_BASE+1	; channel 0 count
DMA_COUNT1	EQU	DMA1_BASE+3	; channel 1 count
DMA_COUNT2	EQU	DMA1_BASE+5	; channel 2 count
DMA_COUNT3	EQU	DMA1_BASE+7	; channel 3 count
DMA_COUNT4	EQU	DMA2_BASE+2*1	; channel 4 count
DMA_COUNT5	EQU	DMA2_BASE+2*3	; channel 5 count
DMA_COUNT6	EQU	DMA2_BASE+2*5	; channel 6 count
DMA_COUNT7	EQU	DMA2_BASE+2*7	; channel 7 count

; ------------- Ports - page registers

DMA_PAGE_BASE	EQU	80h		; base port of page registers

DMA_PAGE0	EQU	DMA_PAGE_BASE+7	; page 0
DMA_PAGE1	EQU	DMA_PAGE_BASE+3	; page 1
DMA_PAGE2	EQU	DMA_PAGE_BASE+1	; page 2
DMA_PAGE3	EQU	DMA_PAGE_BASE+2	; page 3
DMA_PAGE4	EQU	DMA_PAGE_BASE+15; page 4
DMA_PAGE5	EQU	DMA_PAGE_BASE+11; page 5
DMA_PAGE6	EQU	DMA_PAGE_BASE+9	; page 6
DMA_PAGE7	EQU	DMA_PAGE_BASE+10; page 7

DMA_CHANNELS udává počet kanálů řadiče DMA. Pro jednoduchost se započítává i DMA4 (kaskáda), ale je označen jako použitý. DMA_CASCADE je číslo DMA pro kaskádové připojení prvního řadiče k druhému.

Konstanty DMAMODE_VERIFY, DMAMODE_READ, DMAMODE_WRITE, DMAMODE_CASCADE a DMAMODE_INIT jsou řídicí slova pro nastavení módu práce řadiče DMA.

Ve výše uvedeném seznamu dále následují adresy portů prvního a druhého řadiče. DMA1_BASE je bázový port prvního řadiče a DMA2_BASE je bázový port druhého řadiče. DMA_ADDR0..7 jsou porty pro nastavení adresy přenosu jednotlivých kanálů. DMA_COUNT0..7 jsou porty čítačů dat k přenosu. DMA_PAGE_BASE je bázová adresa obvodu stránkových registrů. DMA_PAGE0..7 jsou adresy stránkových registrů pro jednotlivé kanály.


; -----------------------------------------------------------------------------
;                   Internal function: Enable DMA channel
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
; NOTES:	EAX not checked for validity.
; -----------------------------------------------------------------------------

; ------------- Check if it is controller 2

DMADevEnable:	cmp	al,4		; is it controller 2?
		jae	DMADevEnable2	; it is controller 2

; ------------- Enable DMA channel on controller 1

		out	DMA1_MASK,al	; enable DMA channel on controller 1
		ret

; ------------- Enable DMA channel on controller 2

DMADevEnable2:	sub	al,4		; Al <- relative DMA channel number
		out	DMA2_MASK,al	; enable DMA channel on controller 2
		add	al,4		; AL <- return DMA channel number
		ret

DMADevEnable je interní funkce řadiče DMA. Povolí DMA kanál, jehož číslo obsahuje na vstupu funkce registr EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7.


; -----------------------------------------------------------------------------
;                   Internal function: Disable DMA channel
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
; NOTES:	EAX not checked for validity.
; -----------------------------------------------------------------------------

; ------------- Check if it is controller 2

DMADevDisable:	cmp	al,4		; is it controller 2?
		jae	DMADevDisable2	; it is controller 2

; ------------- Disable DMA channel on controller 1

		add	al,B2		; set disable flag
		out	DMA1_MASK,al	; disable DMA channel on controller 1
		sub	al,B2		; return DMA channel number
		ret

; ------------- Disable DMA channel on controller 2 (bit 2 is set)

DMADevDisable2:	out	DMA2_MASK,al	; disable DMA channel on controller 2
		ret

DMADevDisable je interní funkce řadiče DMA. Zakáže DMA kanál, jehož číslo obsahuje na vstupu funkce registr EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7.


; -----------------------------------------------------------------------------
;                Internal function: Clear DMA channel flip-flop
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
; NOTES:	EAX not checked for validity.
; -----------------------------------------------------------------------------

; ------------- Check if it is controller 2

DMADevClearFF:	cmp	al,4		; is it controller 2?
		jae	DMADevClearFF2	; controller 2

; ------------- Clear DMA channel flip-flop on controller 1

		out	DMA1_CLRFF,al	; clear DMA channel flip-flop on ctrl 1
		ret

; ------------- Clear DMA channel flip-flop on controller 2

DMADevClearFF2:	out	DMA2_CLRFF,al	; clear DMA channel flip-flop on ctrl 2
		ret

DMADevClearFF je interní funkce řadiče DMA. Nuluje flip-flop příznak řadiče DMA v závislosti na čisle DMA kanálu obsaženém na vstupu funkce v registru EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7.


; -----------------------------------------------------------------------------
;                    Internal function: Set DMA channel mode
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
;		BL = DMA channel mode
;			B0-B1: must be 0
;			B2-B3: transfer mode
;				00=verify
;				01=read from device (write to memory)
;				10=write to device (read from memory)
;			B4: 1=autoinitialisation enabled
;			B5: 0=increment address, 1=decrement address
;			B6-B7:	00=demand mode
;				01=single mode
;				10=block transfer
;				11=cascade mode
;			preset modes:	DMAMODE_VERIFY - verify
;					DMAMODE_READ - DMA read from device
;					DMAMODE_WRITE - DMA write to device
;					DMAMODE_CASCADE - DMA cascade
;					DMAMODE_INIT - DMA autoinit
; NOTES:	EAX not checked for validity.
; -----------------------------------------------------------------------------

; ------------- Check if it is controller 2

DMADevSetMode:	push	eax		; push EAX
		cmp	al,4		; is it controller 2?
		jae	DMADevSetMode2	; controller 2

; ------------- Set DMA channel mode on controller 1

		or	al,bl		; AL <- channel + mode
		out	DMA1_MODE,al	; set DMA mode on controller 1
		pop	eax		; pop EAX
		ret

; ------------- Set DMA channel mode on controller 2

DMADevSetMode2:	sub	al,4		; AL <- relative DMA channel number
		or	al,bl		; AL <- channel + mode
		out	DMA2_MODE,al	; set DMA mode on controller 2
		pop	eax		; pop EAX
		ret

DMADevSetMode je interní funkce řadiče DMA. Nastaví mód DMA kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7. Registr BL obsahuje řídicí slovo pro nastavení módu kanálu - lze použít předdefinované konstanty DMAMODE_VERIFY .. DMAMODE_INIT.


; -----------------------------------------------------------------------------
;                      Internal function: Set DMA channel page
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
;		EDX = DMA address (physical address)
; NOTES:	EAX not checked for validity.
;		Only address bits 16-23 (DMA0-3) or 17-23 (DMA4-7) are used.
; -----------------------------------------------------------------------------

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

DMADevSetPage:	push	eax		; push EAX
		push	edx		; push EDX

; ------------- Prepare DMA address
	
		shr	edx,16		; DL <- page number
		cmp	al,4		; is it controller 1?
		jb	DMADevSetPage2	; it is controller 1
		and	dl,~B0		; clear bit 16 for controller 2

; ------------- Prepare port address

DMADevSetPage2:	mov	al,[eax+DMAPagePort] ; AL <- address (here AH = 0)

; ------------- Set DMA channel page

		xchg	eax,edx		; DX <- port, AL <- page
		out	dx,al		; set DMA channel page

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

		pop	edx		; pop EDX
		pop	eax		; pop EAX
		ret

; ------------- DMA page ports

DMAPagePort:	db	DMA_PAGE0	; DMA 0
		db	DMA_PAGE1	; DMA 1
		db	DMA_PAGE2	; DMA 2
		db	DMA_PAGE3	; DMA 3
		db	DMA_PAGE4	; DMA 4
		db	DMA_PAGE5	; DMA 5
		db	DMA_PAGE6	; DMA 6
		db	DMA_PAGE7	; DMA 7

DMADevSetPage je interní funkce řadiče DMA. Nastaví stránkový registr DMA kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7. Registr EDX obsahuje adresu ve fyzické paměti - jsou použity pouze bity 16..23 (pro DMA0..3) nebo 17..23 (pro DMA4..7), ostatní adresové bity jsou ignorovány.


; -----------------------------------------------------------------------------
;          Internal function: Set DMA transfer address (offset and page)
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
;		EDX = DMA address (physical address, only bits 0-23 are used)
; NOTES:	EAX not checked for validity.
;		DMA transfer cannot cross 64K (or 128K for DMA4-7) boundary.
;		DMA5 to DMA7 address must be word aligned.
;		Transfers are limited to lower 16 MB of physical memory.
;		DMADevClearFF should be caled first.
; -----------------------------------------------------------------------------

; ------------- Set DMA channel page

DMADevSetAddr:	call	DMADevSetPage	; set DMA channel page

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

		push	eax		; push EAX
		push	edx		; push EDX

; ------------- Prepare port for controller 1 (00h, 02h, 04h, 06h)

		shl	eax,1		; AX <- channel number*2
		cmp	al,DMA1_BASE+4*2 ; is it DMA0..DMA3?
		jb	DMADevSetAddr2	; it is DMA0..DMA3

; ------------- Prepare port for controller 2 (0C0h, 0C4h, 0C8h, 0CCh)

		shl	eax,1		; AX <- channel number*4
                add	al,DMA2_BASE-DMA1_BASE-4*4 ; AL <- port
		shr	edx,1		; convert address to words

; ------------- Set transfer address

DMADevSetAddr2:	xchg	eax,edx		; DX <- port, EAX <- address
		out	dx,al		; set transfer address LOW
		mov	al,ah		; AL <- transfer address HIGH
		jmp	short DMADevSetAddr4 ; short delay
DMADevSetAddr4:	out	dx,al		; set transfer address HIGH

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

		pop	edx		; pop EDX
		pop	eax		; pop EAX
		ret

DMADevSetAddr je interní funkce řadiče DMA. Nastaví adresu k přenosu dat DMA kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7. Registr EDX obsahuje adresu ve fyzické paměti - jsou použity pouze bity 0..23, ostatní adresové bity jsou ignorovány. Před voláním funkce by měl být resetován flip-flop příznak pomocí funkce DMADevClearFF.


; -----------------------------------------------------------------------------
;                     Internal function: Set DMA transfer size
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
;		ECX = DMA transfer size (cannot be 0; B0 is ignored for DMA4-7)
; NOTES:	EAX not checked for validity.
;		DMA transfer cannot cross 64K (or 128K for DMA4-7) boundary.
;		Maximal transfer size is 64K for DMA0-3 and 128K for DMA4-7.
;		DMADevClearFF should be caled first.
; -----------------------------------------------------------------------------

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

DMADevSetSize:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Prepare port for controller 1 (01h, 03h, 05h, 07h)

		shl	eax,1		; AX <- channel number*2
		inc	eax		; EAX <- channel number*2 + 1
		cmp	al,DMA1_BASE+4*2+1 ; is it DMA0..DMA3?
		jb	DMADevSetSize2	; it is DMA0..DMA3

; ------------- Prepare port for controller 2 (0C2h, 0C6h, 0CAh, 0CEh)

		shl	eax,1		; AX <- channel number*4 + 2
                add	al,DMA2_BASE-DMA1_BASE-4*4 ; AL <- port
		shr	ecx,1		; convert size to words

; ------------- Set transfer size

DMADevSetSize2:	dec	ecx		; correct size (=last transfered item)
		xchg	eax,edx		; DX <- port
		xchg	eax,ecx		; AX <- size
		out	dx,al		; set transfer size LOW
		mov	al,ah		; AL <- transfer size HIGH
		jmp	short DMADevSetSize4 ; short delay
DMADevSetSize4:	out	dx,al		; set transfer size HIGH

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

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

DMADevSetSize je interní funkce řadiče DMA. Nastaví velikost přenášených dat DMA kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7. Registr ECX obsahuje počet bajtů dat k přenosu (nesmí být hodnota 0). Před voláním funkce by měl být resetován flip-flop příznak pomocí funkce DMADevClearFF.


; -----------------------------------------------------------------------------
;               Internal function: Get DMA remaining transfer size
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
; OUTPUT:	ECX = remaining bytes to transfer (0 if transfer finished)
; NOTES:	EAX not checked for validity.
;		If called before the channel has been used, it may return 1
;		(or 2 on DMA4..DMA7).
;		DMADevClearFF should be caled first.
; -----------------------------------------------------------------------------

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

DMADevGetSize:	push	eax		; push EAX
		push	edx		; push EDX

; ------------- Prepare port for controller 1 (01h, 03h, 05h, 07h)

		shl	eax,1		; EAX <- channel number*2
		inc	eax		; EAX <- channel number*2 + 1
		cmp	al,DMA1_BASE+4*2+1 ; is it DMA0..DMA3?
		jb	DMADevGetSize2	; it is DMA0..DMA3

; ------------- Prepare port for controller 2 (0C2h, 0C6h, 0CAh, 0CEh)

		shl	eax,1		; EAX <- channel number*4 + 2
                add	al,DMA2_BASE-DMA1_BASE-4*4 ; AL <- port

; ------------- Get transfer size

DMADevGetSize2:	xchg	eax,edx		; DX <- port
		xor	eax,eax		; EAX <- 0
		in	al,dx		; get transfer size LOW
		xchg	eax,ecx		; ECX <- transfer size LOW
		jmp	short DMADevGetSize4 ; short delay
DMADevGetSize4:	in	al,dx		; get transfer size HIGH
		mov	ch,al		; CH <- transfer size HIGH
		inc	ecx		; correction

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

		pop	edx		; pop EDX
		pop	eax		; pop EAX

; ------------- Convert to words for DMA4 - DMA7

		cmp	al,4		; is it DMA4..DMA7?
		jb	DMADevGetSize8	; it is DMA0..DMA3
		shl	ecx,1		; convert to words
DMADevGetSize8:	ret

DMADevGetSize je interní funkce řadiče DMA. Slouží ke zjištění zbývajících dat k přenosu DMA kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7. Na výstupu funkce je v registru ECX navrácen zbývající počet bajtů dat k přenosu. Hodnota 0 indikuje ukončení přenosu. Při prvním volání (pokud kanál nebyl dosud inicializován) může být navrácena hodnota 1 (nebo 2 u DMA4..DMA7). Před voláním funkce by měl být resetován flip-flop příznak pomocí funkce DMADevClearFF.


; -----------------------------------------------------------------------------
;               Internal function: Check if transfer is still running
; -----------------------------------------------------------------------------
; INPUT:	EAX = DMA channel number (0 to 7)
; OUTPUT:	CY = transfer is not running
; NOTES:	EAX not checked for validity.
;		If called before the channel has been used, it may return NC.
;		It may be faster than DMADevGetSize.
; -----------------------------------------------------------------------------

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

DMADevRunning:	push	eax		; push EAX
		push	edx		; push EDX

; ------------- Prepare port for controller 1 (01h, 03h, 05h, 07h)

		shl	eax,1		; EAX <- channel number*2
		inc	eax		; EAX <- channel number*2 + 1
		cmp	al,DMA1_BASE+4*2+1 ; is it DMA0..DMA3?
		jb	DMADevRunning2	; it is DMA0..DMA3

; ------------- Prepare port for controller 2 (0C2h, 0C6h, 0CAh, 0CEh)

		shl	eax,1		; EAX <- channel number*4 + 2
                add	al,DMA2_BASE-DMA1_BASE-4*4 ; AL <- port

; ------------- Get transfer size

DMADevRunning2:	xchg	eax,edx		; DX <- port
		in	al,dx		; get transfer size 1
		cmp	al,0ffh		; is transfer still running?
		jne	DMADevRunning6	; transfer is still running
		jmp	short DMADevRunning4 ; short delay
DMADevRunning4:	in	al,dx		; get transfer size 2
		cmp	al,0ffh		; is transfer still running?
DMADevRunning6:	cmc			; NC = transfer is still running

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

		pop	edx		; pop EDX
		pop	eax		; pop EAX
		ret

DMADevRunning je interní funkce řadiče DMA. Slouží ke zjištění, zda dosud probíhá přenos dat na DMA kanálu, jehož číslo obsahuje na vstupu funkce registr EAX. Hodnota registru EAX není kontrolovaná na platnost a musí být v rozsahu 0 až 7. Na výstupu funkce je navrácen příznak CY, pokud přenos dat neprobíhá. Při prvním volání (pokud kanál nebyl dosud inicializován) může být navrácen příznak probíhajícího přenosu (NC). Funkce se používá jako rychlejší varianta k testu přenosu než DMADevGetSize.


Obsah / Ovladače / DMA / Interní funkce ovladače řadiče DMA