1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
;****************************************************************************
;*
;* SciTech OS Portability Manager Library
;*
;* ========================================================================
;*
;* The contents of this file are subject to the SciTech MGL Public
;* License Version 1.0 (the "License"); you may not use this file
;* except in compliance with the License. You may obtain a copy of
;* the License at http://www.scitechsoft.com/mgl-license.txt
;*
;* Software distributed under the License is distributed on an
;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
;* implied. See the License for the specific language governing
;* rights and limitations under the License.
;*
;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
;*
;* The Initial Developer of the Original Code is SciTech Software, Inc.
;* All Rights Reserved.
;*
;* ========================================================================
;*
;* Language: 80386 Assembler, TASM 4.0 or NASM
;* Environment: 16/32 bit Ring 0 device driver
;*
;* Description: Assembler support routines for ISA DMA controller.
;*
;****************************************************************************
IDEAL
include "scitech.mac" ; Memory model macros
header _dma ; Set up memory model
begdataseg _dma ; Start of data segment
cpublic _PM_DMADataStart
; DMA register I/O addresses for channels 0-7 (except 4)
DMAC_page db 087h,083h,081h,082h, -1,08Bh,089h,08Ah
DMAC_addr db 000h,002h,004h,006h, -1,0C4h,0C8h,0CCh
DMAC_cnt db 001h,003h,005h,007h, -1,0C6h,0CAh,0CEh
DMAC_mask db 00Ah,00Ah,00Ah,00Ah, -1,0D4h,0D4h,0D4h
DMAC_mode db 00Bh,00Bh,00Bh,00Bh, -1,0D6h,0D6h,0D6h
DMAC_FF db 00Ch,00Ch,00Ch,00Ch, -1,0D8h,0D8h,0D8h
cpublic _PM_DMADataEnd
enddataseg _dma
begcodeseg _dma ; Start of code segment
ifdef flatmodel
cpublic _PM_DMACodeStart
;----------------------------------------------------------------------------
; void PM_DMACDisable(int channel);
;----------------------------------------------------------------------------
; Masks DMA channel, inhibiting DMA transfers
;----------------------------------------------------------------------------
cprocstart PM_DMACDisable
ARG channel:UINT
push ebp
mov ebp,esp
mov ecx,[channel] ; ECX indexes DMAC register tables
mov dh,0 ; DH = 0 for DMAC register port access
mov al,cl
and al,11b
or al,100b ; AL = (channel & 3) | "set mask bit"
mov dl,[DMAC_mask+ecx]
out dx,al
pop ebp
ret
cprocend
;----------------------------------------------------------------------------
; void PM_DMACEnable(int channel);
;----------------------------------------------------------------------------
; Unmasks DMA channel, enabling DMA transfers
;----------------------------------------------------------------------------
cprocstart PM_DMACEnable
ARG channel:UINT
push ebp
mov ebp,esp
mov ecx,[channel] ; ECX indexes DMAC register tables
mov dh,0 ; DH = 0 for DMAC register port access
mov al,cl
and al,11b ; AL = (channel & 3), "set mask bit"=0
mov dl,[DMAC_mask+ecx]
out dx,al
pop ebp
ret
cprocend
;----------------------------------------------------------------------------
; void PM_DMACProgram(int channel,int mode,ulong bufferPhys,int count);
;----------------------------------------------------------------------------
; Purpose: Program DMA controller to perform transfer from first 16MB
; based on previously selected mode and channel. DMA transfer may be enabled
; by subsequent call to PM_DMACEnable.
;
; Entry: channel - DMA channel in use (0-7)
; mode - Selected DMAMODE type for transfer
; buffer - 32-bit physical address of DMA buffer
; count - DMA byte count (1-65536 bytes)
;----------------------------------------------------------------------------
cprocstart PM_DMACProgram
ARG channel:UINT, mode:UINT, bufferPhys:ULONG, count:UINT
enter_c
pushfd
cli ; Disable interrupts
; Mask DMA channel to disable it
mov ebx,[channel] ; EBX indexes DMAC register tables
mov dh,0 ; DH = 0 for DMAC register port access
mov al,bl
and al,11b
or al,100b ; AL = (channel & 3) | "set mask bit"
mov dl,[DMAC_mask+ebx]
out dx,al
; Generate IOW to clear FF toggle state
mov al,0
mov dl,[DMAC_FF+ebx]
out dx,al
; Compute buffer address to program
mov eax,[bufferPhys] ; AX := DMA address offset
mov ecx,eax
shr ecx,16 ; CL := bufferPhys >> 16 (DMA page)
mov esi,[count] ; ESI = # of bytes to transfer
cmp ebx,4 ; 16-bit channel?
jb @@WriteDMAC ; No, program DMAC
shr eax,1 ; Yes, convert address and count
shr esi,1 ; to 16-bit, 128K/page format
; Set the DMA address word (bits 0-15)
@@WriteDMAC:
mov dl,[DMAC_addr+ebx]
out dx,al
mov al,ah
out dx,al
; Set DMA transfer count
mov eax,esi
dec eax ; ESI = # of bytes to transfer - 1
mov dl,[DMAC_cnt+ebx]
out dx,al
mov al,ah
out dx,al
; Set DMA page byte (bits 16-23)
mov al,cl
mov dl,[DMAC_page+ebx]
out dx,al
; Set the DMA channel mode
mov al,bl
and al,11b
or al,[BYTE mode] ; EAX = (channel & 3) | mode
mov dl,[DMAC_mode+ebx]
out dx,al
pop eax ; SMP safe interrupt state restore!
test eax,200h
jz @@1
sti
@@1: leave_c
ret
cprocend
;----------------------------------------------------------------------------
; ulong PMAPI PM_DMACPosition(int channel);
;----------------------------------------------------------------------------
; Returns the current position in a dma transfer. Interrupts should be
; disabled before calling this function.
;----------------------------------------------------------------------------
cprocstart PM_DMACPosition
ARG channel:UINT
enter_c
mov ecx,[channel] ; ECX indexes DMAC register tables
mov dh,0 ; DH = 0 for DMAC register port access
; Generate IOW to clear FF toggle state
mov al,0
mov dl,[DMAC_FF+ebx]
out dx,al
xor eax,eax
xor ecx,ecx
; Now read the current position for the channel
@@ReadLoop:
mov dl,[DMAC_cnt+ebx]
out dx,al
in al,dx
mov cl,al
in al,dx
mov ch,al ; ECX := first count read
in al,dx
mov ah,al
in al,dx
xchg al,ah ; EAX := second count read
sub ecx,eax
cmp ecx,40h
jg @@ReadLoop
cmp ebx,4 ; 16-bit channel?
jb @@Exit ; No, we are done
shl eax,1 ; Yes, adjust to byte address
@@Exit: leave_c
ret
cprocend
cpublic _PM_DMACodeEnd
endif
endcodeseg _dma
END ; End of module
|