shdocvw/tests: Make sure to use return value (LLVM/Clang).
[wine] / dlls / krnl386.exe16 / dma.c
1 /*
2  * DMA Emulation
3  *
4  * Copyright 2002 Christian Costa
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "dosexe.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(dma);
31
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};
41
42 /*
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
45  */
46 int DMA_Transfer(int channel,int reqlen,void* buffer)
47 {
48     int i,size,ret=0;
49     int opmode,increment,autoinit,trmode,dmachip;
50     int regmode = DMA_Command[channel];
51     char *p,*dmabuf;
52
53     dmabuf = buffer;
54     dmachip = (channel<4) ? 0 : 1;
55
56     TRACE("DMA_Command = %x reqlen=%d\n",regmode,reqlen);
57
58     /* Exit if channel is masked */
59     if (DMA_Mask[dmachip]&(1<<(channel&3)))
60         return 0;
61
62     opmode = (regmode & 0xC0) >> 6;
63     increment = !(regmode & 0x20);
64     autoinit = regmode & 0x10;
65     trmode = (regmode & 0x0C) >> 2;
66
67     /* Transfer size : 8 bits for channels 0..3, 16 bits for channels 4..7 */
68     size = (channel<4) ? 1 : 2;
69
70     /* Process operating mode */
71     switch(opmode)
72     {
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;
88     }
89
90     /* Perform one the 4 transfer modes */
91     if (trmode == 4) {
92         /* Illegal */
93         ERR("DMA Transfer Type Illegal\n");
94         return 0;
95     }
96
97     ret = min(DMA_CurrentByteCount[channel],reqlen);
98
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;
105
106     switch(trmode)
107     {
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;
134     }
135
136     /* Check for end of transfer */
137     if (DMA_CurrentByteCount[channel]==0) {
138         TRACE("DMA buffer empty\n");
139
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 */
143
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];
148         }
149     }
150
151     return ret;
152 }
153
154
155 void DMA_ioport_out( WORD port, BYTE val )
156 {
157     int channel,dmachip;
158
159     switch(port)
160     {
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]);
178         }
179         DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
180         break;
181
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]);
199         }
200         DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
201         break;
202
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;
211
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;
220
221     case 0x08:
222     case 0xD0:
223         /* Command */
224         FIXME("Write Command (%x) - Not Implemented\n",val);
225         break;
226
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)
233         {
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;
249         }
250         break;
251
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;
262
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;
270
271     case 0x09:
272     case 0xD2:
273         /* Software DRQx Request */
274         FIXME("Software DRQx Request (%x) - Not Implemented\n",val);
275         break;
276
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;
283
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;
294
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;
303     }
304 }
305
306 BYTE DMA_ioport_in( WORD port )
307 {
308     int channel,dmachip;
309     BYTE res = 0;
310
311     switch(port)
312     {
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]);
329         }
330         DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
331         break;
332
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]);
349         }
350         DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
351         break;
352
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;
361
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;
370
371     case 0x08:
372     case 0xD0:
373         /* Status */
374         TRACE("Status Register Read\n");
375         res = DMA_Status[(port==0x08)?0:1];
376
377     case 0x0D:
378     case 0xDA:
379         /* Temporary */
380         FIXME("Temporary Register Read- Not Implemented\n");
381         break;
382     }
383     return res;
384 }