appwiz.cpl: Fix compilation on systems that don't support nameless unions.
[wine.git] / dlls / winedos / dma.c
blobc356ac9140d398a67be96e552c6da59969c65283
1 /*
2 * DMA Emulation
4 * Copyright 2002 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "dosexe.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(dma);
32 /* Internal registers of the 2 DMA chips which control 8 DMA channels */
33 static DWORD DMA_BaseAddress[8];
34 static WORD DMA_ByteCount[8];
35 static DWORD DMA_CurrentBaseAddress[8];
36 static WORD DMA_CurrentByteCount[8];
37 static BYTE DMA_Command[8];
38 static BYTE DMA_Mask[2]={0x0F,0x0F};
39 static BYTE DMA_Status[2]={0x00,0x00};
40 static BOOL DMA_Toggle[2]={FALSE,FALSE};
43 * DMA_Transfer : Try to perform a transfer of reqlen elements (8 or 16 bits)
44 * on the specified channel and return the elements transferred
46 int DMA_Transfer(int channel,int reqlen,void* buffer)
48 int i,size,ret=0;
49 int opmode,increment,autoinit,trmode,dmachip;
50 int regmode = DMA_Command[channel];
51 char *p,*dmabuf;
53 dmabuf = buffer;
54 dmachip = (channel<4) ? 0 : 1;
56 TRACE("DMA_Command = %x reqlen=%d\n",regmode,reqlen);
58 /* Exit if channel is masked */
59 if (DMA_Mask[dmachip]&(1<<(channel&3)))
60 return 0;
62 opmode = (regmode & 0xC0) >> 6;
63 increment = !(regmode & 0x20);
64 autoinit = regmode & 0x10;
65 trmode = (regmode & 0x0C) >> 2;
67 /* Transfer size : 8 bits for channels 0..3, 16 bits for channels 4..7 */
68 size = (channel<4) ? 1 : 2;
70 /* Process operating mode */
71 switch(opmode)
73 case 0:
74 /* Request mode */
75 FIXME("Request Mode - Not Implemented\n");
76 return 0;
77 case 1:
78 /* Single Mode */
79 break;
80 case 2:
81 /* Request mode */
82 FIXME("Block Mode - Not Implemented\n");
83 return 0;
84 case 3:
85 /* Cascade Mode */
86 ERR("Cascade Mode should not be used by regular apps\n");
87 return 0;
90 /* Perform one the 4 transfer modes */
91 if (trmode == 4) {
92 /* Illegal */
93 ERR("DMA Transfer Type Illegal\n");
94 return 0;
97 ret = min(DMA_CurrentByteCount[channel],reqlen);
99 /* Update DMA registers */
100 DMA_CurrentByteCount[channel]-=ret;
101 if (increment)
102 DMA_CurrentBaseAddress[channel] += ret * size;
103 else
104 DMA_CurrentBaseAddress[channel] -= ret * size;
106 switch(trmode)
108 case 0:
109 /* Verification (no real transfer)*/
110 TRACE("Verification DMA operation\n");
111 break;
112 case 1:
113 /* Write */
114 TRACE("Perform Write transfer of %d bytes at %x with count %x\n",ret,
115 DMA_CurrentBaseAddress[channel],DMA_CurrentByteCount[channel]);
116 if (increment)
117 memcpy((void*)DMA_CurrentBaseAddress[channel],dmabuf,ret*size);
118 else
119 for(i=0,p=(char*)DMA_CurrentBaseAddress[channel];i<ret*size;i++)
120 /* FIXME: possible endianness issue for 16 bits DMA */
121 *(p-i) = dmabuf[i];
122 break;
123 case 2:
124 /* Read */
125 TRACE("Perform Read transfer of %d bytes at %x with count %x\n",ret,
126 DMA_CurrentBaseAddress[channel],DMA_CurrentByteCount[channel]);
127 if (increment)
128 memcpy(dmabuf,(void*)DMA_CurrentBaseAddress[channel],ret*size);
129 else
130 for(i=0,p=(char*)DMA_CurrentBaseAddress[channel];i<ret*size;i++)
131 /* FIXME: possible endianness issue for 16 bits DMA */
132 dmabuf[i] = *(p-i);
133 break;
136 /* Check for end of transfer */
137 if (DMA_CurrentByteCount[channel]==0) {
138 TRACE("DMA buffer empty\n");
140 /* Update status register of the DMA chip corresponding to the channel */
141 DMA_Status[dmachip] |= 1 << (channel & 0x3); /* Mark transfer as finished */
142 DMA_Status[dmachip] &= ~(1 << ((channel & 0x3) + 4)); /* Reset soft request if any */
144 if (autoinit) {
145 /* Reload Current* register to their initial values */
146 DMA_CurrentBaseAddress[channel] = DMA_BaseAddress[channel];
147 DMA_CurrentByteCount[channel] = DMA_ByteCount[channel];
151 return ret;
155 void DMA_ioport_out( WORD port, BYTE val )
157 int channel,dmachip;
159 switch(port)
161 case 0x00:
162 case 0x02:
163 case 0x04:
164 case 0x06:
165 case 0xC0:
166 case 0xC4:
167 case 0xC8:
168 case 0xCC:
169 /* Base Address*/
170 channel = (port&0xC0)?((port-0xC0)>>2):(port>>1);
171 dmachip = (channel<4) ? 0 : 1;
172 if (!DMA_Toggle[dmachip])
173 DMA_BaseAddress[channel]=(DMA_BaseAddress[channel] & ~0xFF)|(val & 0xFF);
174 else {
175 DMA_BaseAddress[channel]=(DMA_BaseAddress[channel] & (~(0xFF << 8)))|((val & 0xFF) << 8);
176 DMA_CurrentBaseAddress[channel] = DMA_BaseAddress[channel];
177 TRACE("Write Base Address = %x\n",DMA_BaseAddress[channel]);
179 DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
180 break;
182 case 0x01:
183 case 0x03:
184 case 0x05:
185 case 0x07:
186 case 0xC2:
187 case 0xC6:
188 case 0xCA:
189 case 0xCE:
190 /* Count*/
191 channel = ((port-1)&0xC0)?(((port-1)-0xC0)>>2):(port>>1);
192 dmachip = (channel<4) ? 0 : 1;
193 if (!DMA_Toggle[dmachip])
194 DMA_ByteCount[channel]=(DMA_ByteCount[channel] & ~0xFF)|((val+1) & 0xFF);
195 else {
196 DMA_ByteCount[channel]=(DMA_ByteCount[channel] & (~(0xFF << 8)))|(((val+1) & 0xFF) << 8);
197 DMA_CurrentByteCount[channel] = DMA_ByteCount[channel];
198 TRACE("Write Count = %x.\n",DMA_ByteCount[channel]);
200 DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
201 break;
203 /* Low Page Base Address */
204 case 0x87: DMA_BaseAddress[0]=(DMA_BaseAddress[0] & (~0xFF << 16))|((val & 0xFF) << 16); break;
205 case 0x83: DMA_BaseAddress[1]=(DMA_BaseAddress[1] & (~0xFF << 16))|((val & 0xFF) << 16); break;
206 case 0x81: DMA_BaseAddress[2]=(DMA_BaseAddress[2] & (~0xFF << 16))|((val & 0xFF) << 16); break;
207 case 0x82: DMA_BaseAddress[3]=(DMA_BaseAddress[3] & (~0xFF << 16))|((val & 0xFF) << 16); break;
208 case 0x8B: DMA_BaseAddress[5]=(DMA_BaseAddress[5] & (~0xFF << 16))|((val & 0xFF) << 16); break;
209 case 0x89: DMA_BaseAddress[6]=(DMA_BaseAddress[6] & (~0xFF << 16))|((val & 0xFF) << 16); break;
210 case 0x8A: DMA_BaseAddress[7]=(DMA_BaseAddress[7] & (~0xFF << 16))|((val & 0xFF) << 16); break;
212 /* Low Page Base Address (only 4 lower bits are significant) */
213 case 0x487: DMA_BaseAddress[0]=(DMA_BaseAddress[0] & (~0xFF << 24))|((val & 0x0F) << 24); break;
214 case 0x483: DMA_BaseAddress[1]=(DMA_BaseAddress[1] & (~0xFF << 24))|((val & 0x0F) << 24); break;
215 case 0x481: DMA_BaseAddress[2]=(DMA_BaseAddress[2] & (~0xFF << 24))|((val & 0x0F) << 24); break;
216 case 0x482: DMA_BaseAddress[3]=(DMA_BaseAddress[3] & (~0xFF << 24))|((val & 0x0F) << 24); break;
217 case 0x48B: DMA_BaseAddress[5]=(DMA_BaseAddress[5] & (~0xFF << 24))|((val & 0x0F) << 24); break;
218 case 0x489: DMA_BaseAddress[6]=(DMA_BaseAddress[6] & (~0xFF << 24))|((val & 0x0F) << 24); break;
219 case 0x48A: DMA_BaseAddress[7]=(DMA_BaseAddress[7] & (~0xFF << 24))|((val & 0x0F) << 24); break;
221 case 0x08:
222 case 0xD0:
223 /* Command */
224 FIXME("Write Command (%x) - Not Implemented\n",val);
225 break;
227 case 0x0B:
228 case 0xD6:
229 /* Mode */
230 TRACE("Write Mode (%x)\n",val);
231 DMA_Command[((port==0xD6)?4:0)+(val&0x3)]=val;
232 switch(val>>6)
234 case 0:
235 /* Request mode */
236 FIXME("Request Mode - Not Implemented\n");
237 break;
238 case 1:
239 /* Single Mode */
240 break;
241 case 2:
242 /* Block mode */
243 FIXME("Block Mode - Not Implemented\n");
244 break;
245 case 3:
246 /* Cascade Mode */
247 ERR("Cascade Mode should not be used by regular apps\n");
248 break;
250 break;
252 case 0x0A:
253 case 0xD4:
254 /* Write Single Mask Bit */
255 TRACE("Write Single Mask Bit (%x)\n",val);
256 dmachip = (port==0x0A) ? 0 : 1;
257 if (val&4)
258 DMA_Mask[dmachip] |= 1<<(val&3);
259 else
260 DMA_Mask[dmachip] &= ~(1<<(val&3));
261 break;
263 case 0x0F:
264 case 0xDE:
265 /* Write All Mask Bits (only 4 lower bits are significant */
266 FIXME("Write All Mask Bits (%x)\n",val);
267 dmachip = (port==0x0F) ? 0 : 1;
268 DMA_Mask[dmachip] = val & 0x0F;
269 break;
271 case 0x09:
272 case 0xD2:
273 /* Software DRQx Request */
274 FIXME("Software DRQx Request (%x) - Not Implemented\n",val);
275 break;
277 case 0x0C:
278 case 0xD8:
279 /* Reset DMA Pointer Flip-Flop */
280 TRACE("Reset Flip-Flop\n");
281 DMA_Toggle[port==0xD8]=FALSE;
282 break;
284 case 0x0D:
285 case 0xDA:
286 /* Master Reset */
287 TRACE("Master Reset\n");
288 dmachip = (port==0x0D) ? 0 : 1;
289 /* Reset DMA Pointer Flip-Flop */
290 DMA_Toggle[dmachip]=FALSE;
291 /* Mask all channels */
292 DMA_Mask[dmachip] = 0x0F;
293 break;
295 case 0x0E:
296 case 0xDC:
297 /* Reset Mask Register */
298 FIXME("Reset Mask Register\n");
299 dmachip = (port==0x0E) ? 0 : 1;
300 /* Unmask all channels */
301 DMA_Mask[dmachip] = 0x00;
302 break;
306 BYTE DMA_ioport_in( WORD port )
308 int channel,dmachip;
309 BYTE res = 0;
311 switch(port)
313 case 0x00:
314 case 0x02:
315 case 0x04:
316 case 0x06:
317 case 0xC0:
318 case 0xC4:
319 case 0xC8:
320 case 0xCC:
321 /* Base Address*/
322 channel = (port&0xC0)?((port-0xC0)>>2):(port>>1);
323 dmachip = (channel<4) ? 0 : 1;
324 if (!DMA_Toggle[dmachip])
325 res = DMA_CurrentBaseAddress[channel] & 0xFF;
326 else {
327 res = (DMA_CurrentBaseAddress[channel] & (0xFF << 8))>>8;
328 TRACE("Read Current Base Address = %x\n",DMA_CurrentBaseAddress[channel]);
330 DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
331 break;
333 case 0x01:
334 case 0x03:
335 case 0x05:
336 case 0x07:
337 case 0xC2:
338 case 0xC6:
339 case 0xCA:
340 case 0xCE:
341 /* Count*/
342 channel = ((port-1)&0xC0)?(((port-1)-0xC0)>>2):(port>>1);
343 dmachip = (channel<4) ? 0 : 1;
344 if (!DMA_Toggle[dmachip])
345 res = DMA_CurrentByteCount[channel] & 0xFF;
346 else {
347 res = (DMA_CurrentByteCount[channel] & (0xFF << 8))>>8;
348 TRACE("Read Current Count = %x.\n",DMA_CurrentByteCount[channel]);
350 DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
351 break;
353 /* Low Page Base Address */
354 case 0x87: res = (DMA_BaseAddress[0]&(0xFF<<16))>>16; break;
355 case 0x83: res = (DMA_BaseAddress[1]&(0xFF<<16))>>16; break;
356 case 0x81: res = (DMA_BaseAddress[2]&(0xFF<<16))>>16; break;
357 case 0x82: res = (DMA_BaseAddress[3]&(0xFF<<16))>>16; break;
358 case 0x8B: res = (DMA_BaseAddress[5]&(0xFF<<16))>>16; break;
359 case 0x89: res = (DMA_BaseAddress[6]&(0xFF<<16))>>16; break;
360 case 0x8A: res = (DMA_BaseAddress[7]&(0xFF<<16))>>16; break;
362 /* High Page Base Address */
363 case 0x487: res = (DMA_BaseAddress[0]&(0xFF<<24))>>24; break;
364 case 0x483: res = (DMA_BaseAddress[1]&(0xFF<<24))>>24; break;
365 case 0x481: res = (DMA_BaseAddress[2]&(0xFF<<24))>>24; break;
366 case 0x482: res = (DMA_BaseAddress[3]&(0xFF<<24))>>24; break;
367 case 0x48B: res = (DMA_BaseAddress[5]&(0xFF<<24))>>24; break;
368 case 0x489: res = (DMA_BaseAddress[6]&(0xFF<<24))>>24; break;
369 case 0x48A: res = (DMA_BaseAddress[7]&(0xFF<<24))>>24; break;
371 case 0x08:
372 case 0xD0:
373 /* Status */
374 TRACE("Status Register Read\n");
375 res = DMA_Status[(port==0x08)?0:1];
377 case 0x0D:
378 case 0xDA:
379 /* Temporary */
380 FIXME("Temporary Register Read- Not Implemented\n");
381 break;
383 return res;