Added DMA and SoundBlaster emulation.
[wine] / dlls / winedos / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "windef.h"
24 #include "dosexe.h"
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(dma);
28
29 /* Internal registers of the 2 DMA chips wich control 8 DMA channels */
30 static DWORD DMA_BaseAddress[8];
31 static WORD  DMA_ByteCount[8];
32 static DWORD DMA_CurrentBaseAddress[8];
33 static WORD  DMA_CurrentByteCount[8];
34 static BYTE  DMA_Command[8];
35 static BYTE  DMA_Mask[2]={0x0F,0x0F};
36 static BYTE  DMA_Status[2]={0x00,0x00};
37 static BOOL  DMA_Toggle[2]={FALSE,FALSE};
38
39 /*
40  * DMA_Transfer : Try to perform a transfer of reqlen elements (8 or 16 bits)
41  * on the specified channel and return the elements transferred
42  */
43 int DMA_Transfer(int channel,int reqlen,void* buffer)
44 {
45     int i,size,ret=0;
46     int opmode,increment,autoinit,trmode,dmachip;
47     int regmode = DMA_Command[channel];
48     char *p,*dmabuf;
49
50     dmabuf = buffer;
51     dmachip = (channel<4) ? 0 : 1;
52
53     TRACE("DMA_Command = %x reqlen=%d\n",regmode,reqlen);
54
55     /* Exit if channel is masked */
56     if (DMA_Mask[dmachip]&(1<<(channel&3)))
57         return 0;
58
59     opmode = (regmode & 0xC0) >> 6;
60     increment = !(regmode & 0x20);
61     autoinit = regmode & 0x10;
62     trmode = (regmode & 0x0C) >> 2;
63
64     /* Transfer size : 8 bits for channels 0..3, 16 bits for channels 4..7 */
65     size = (channel<4) ? 1 : 2;
66
67     /* Process operating mode */
68     switch(opmode)
69     {
70     case 0:
71         /* Request mode */
72         FIXME("Request Mode - Not Implemented\n");
73         return 0;
74     case 1:
75         /* Single Mode */
76         break;
77     case 2:
78         /* Request mode */
79         FIXME("Block Mode - Not Implemented\n");
80         return 0;
81     case 3:
82         /* Cascade Mode */
83         ERR("Cascade Mode should not be used by regular apps\n");
84         return 0;
85     }
86
87     /* Perform one the 4 transfer modes */
88     if (trmode == 4) {
89         /* Illegal */
90         ERR("DMA Transfer Type Illegal\n");
91         return 0;
92     }
93
94     ret = min(DMA_CurrentByteCount[channel],reqlen);
95
96     /* Update DMA registers */
97     DMA_CurrentByteCount[channel]-=ret;
98     if (increment)
99         DMA_CurrentBaseAddress[channel] += ret * size;
100     else
101         DMA_CurrentBaseAddress[channel] -= ret * size;
102
103     switch(trmode)
104     {
105     case 0:
106         /* Verification (no real transfer)*/
107         TRACE("Verification DMA operation\n");
108         break;
109     case 1:
110         /* Write */
111         TRACE("Perform Write transfer of %d bytes at %lx with count %x\n",ret,
112             DMA_CurrentBaseAddress[channel],DMA_CurrentByteCount[channel]);
113         if (increment)
114             memcpy((void*)DMA_CurrentBaseAddress[channel],dmabuf,ret*size);
115         else
116             for(i=0,p=(char*)DMA_CurrentBaseAddress[channel];i<ret*size;i++)
117                 /* FIXME: possible endianness issue for 16 bits DMA */
118                 *(p-i) = dmabuf[i];
119         break;
120     case 2:
121         /* Read */
122         TRACE("Perform Read transfer of %d bytes at %lx with count %x\n",ret,
123             DMA_CurrentBaseAddress[channel],DMA_CurrentByteCount[channel]);
124         if (increment)
125             memcpy(dmabuf,(void*)DMA_CurrentBaseAddress[channel],ret*size);
126         else
127             for(i=0,p=(char*)DMA_CurrentBaseAddress[channel];i<ret*size;i++)
128                 /* FIXME: possible endianness issue for 16 bits DMA */
129                 dmabuf[i] = *(p-i);
130         break;
131     }
132
133     /* Check for end of transfer */
134     if (DMA_CurrentByteCount[channel]==0) {
135         TRACE("DMA buffer empty\n");
136
137         /* Update status register of the DMA chip corresponding to the channel */
138         DMA_Status[dmachip] |= 1 << (channel & 0x3); /* Mark transfer as finished */
139         DMA_Status[dmachip] &= ~(1 << ((channel & 0x3) + 4)); /* Reset soft request if any */
140
141         if (autoinit) {
142             /* Reload Current* register to their initial values */
143             DMA_CurrentBaseAddress[channel] = DMA_BaseAddress[channel];
144             DMA_CurrentByteCount[channel] = DMA_ByteCount[channel];
145         }
146     }
147
148     return ret;
149 }
150
151
152 void DMA_ioport_out( WORD port, BYTE val )
153 {
154     int channel,dmachip;
155
156     switch(port)
157     {
158     case 0x00:
159     case 0x02:
160     case 0x04:
161     case 0x06:
162     case 0xC0:
163     case 0xC4:
164     case 0xC8:
165     case 0xCC:
166         /* Base Address*/
167         channel = (port&0xC0)?((port-0xC0)>>2):(port>>1);
168         dmachip = (channel<4) ? 0 : 1;
169         if (!DMA_Toggle[dmachip])
170             DMA_BaseAddress[channel]=(DMA_BaseAddress[channel] & ~0xFF)|(val & 0xFF);
171         else {
172             DMA_BaseAddress[channel]=(DMA_BaseAddress[channel] & (~(0xFF << 8)))|((val & 0xFF) << 8);
173             DMA_CurrentBaseAddress[channel] = DMA_BaseAddress[channel];
174             TRACE("Write Base Address = %lx\n",DMA_BaseAddress[channel]);
175         }
176         DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
177         break;
178
179     case 0x01:
180     case 0x03:
181     case 0x05:
182     case 0x07:
183     case 0xC2:
184     case 0xC6:
185     case 0xCA:
186     case 0xCE:
187         /* Count*/
188         channel = ((port-1)&0xC0)?(((port-1)-0xC0)>>2):(port>>1);
189         dmachip = (channel<4) ? 0 : 1;
190         if (!DMA_Toggle[dmachip])
191             DMA_ByteCount[channel]=(DMA_ByteCount[channel] & ~0xFF)|((val+1) & 0xFF);
192         else {
193             DMA_ByteCount[channel]=(DMA_ByteCount[channel] & (~(0xFF << 8)))|(((val+1) & 0xFF) << 8);
194             DMA_CurrentByteCount[channel] = DMA_ByteCount[channel];
195             TRACE("Write Count = %x.\n",DMA_ByteCount[channel]);
196         }
197         DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
198         break;
199
200     /* Low Page Base Address */
201     case 0x87: DMA_BaseAddress[0]=(DMA_BaseAddress[0] & (~0xFF << 16))|((val & 0xFF) << 16); break;
202     case 0x83: DMA_BaseAddress[1]=(DMA_BaseAddress[1] & (~0xFF << 16))|((val & 0xFF) << 16); break;
203     case 0x81: DMA_BaseAddress[2]=(DMA_BaseAddress[2] & (~0xFF << 16))|((val & 0xFF) << 16); break;
204     case 0x82: DMA_BaseAddress[3]=(DMA_BaseAddress[3] & (~0xFF << 16))|((val & 0xFF) << 16); break;
205     case 0x8B: DMA_BaseAddress[5]=(DMA_BaseAddress[5] & (~0xFF << 16))|((val & 0xFF) << 16); break;
206     case 0x89: DMA_BaseAddress[6]=(DMA_BaseAddress[6] & (~0xFF << 16))|((val & 0xFF) << 16); break;
207     case 0x8A: DMA_BaseAddress[7]=(DMA_BaseAddress[7] & (~0xFF << 16))|((val & 0xFF) << 16); break;
208
209     /* Low Page Base Address (only 4 lower bits are significant) */
210     case 0x487: DMA_BaseAddress[0]=(DMA_BaseAddress[0] & (~0xFF << 24))|((val & 0x0F) << 24); break;
211     case 0x483: DMA_BaseAddress[1]=(DMA_BaseAddress[1] & (~0xFF << 24))|((val & 0x0F) << 24); break;
212     case 0x481: DMA_BaseAddress[2]=(DMA_BaseAddress[2] & (~0xFF << 24))|((val & 0x0F) << 24); break;
213     case 0x482: DMA_BaseAddress[3]=(DMA_BaseAddress[3] & (~0xFF << 24))|((val & 0x0F) << 24); break;
214     case 0x48B: DMA_BaseAddress[5]=(DMA_BaseAddress[5] & (~0xFF << 24))|((val & 0x0F) << 24); break;
215     case 0x489: DMA_BaseAddress[6]=(DMA_BaseAddress[6] & (~0xFF << 24))|((val & 0x0F) << 24); break;
216     case 0x48A: DMA_BaseAddress[7]=(DMA_BaseAddress[7] & (~0xFF << 24))|((val & 0x0F) << 24); break;
217
218     case 0x08:
219     case 0xD0:
220         /* Command */
221         FIXME("Write Command (%x) - Not Implemented\n",val);
222         break;
223
224     case 0x0B:
225     case 0xD6:
226         /* Mode */
227         TRACE("Write Mode (%x)\n",val);
228         DMA_Command[((port==0xD6)?4:0)+(val&0x3)]=val;
229         switch(val>>6)
230         {
231         case 0:
232             /* Request mode */
233             FIXME("Request Mode - Not Implemented\n");
234             break;
235         case 1:
236             /* Single Mode */
237             break;
238         case 2:
239             /* Block mode */
240             FIXME("Block Mode - Not Implemented\n");
241             break;
242         case 3:
243             /* Cascade Mode */
244             ERR("Cascade Mode should not be used by regular apps\n");
245             break;
246         }
247         break;
248
249     case 0x0A:
250     case 0xD4:
251         /* Write Single Mask Bit */
252         TRACE("Write Single Mask Bit (%x)\n",val);
253         dmachip = (port==0x0A) ? 0 : 1;
254         if (val&4)
255             DMA_Mask[dmachip] |= 1<<(val&3);
256         else
257             DMA_Mask[dmachip] &= ~(1<<(val&3));
258         break;
259
260     case 0x0F:
261     case 0xDE:
262         /* Write All Mask Bits (only 4 lower bits are significant */
263         FIXME("Write All Mask Bits (%x)\n",val);
264         dmachip = (port==0x0F) ? 0 : 1;
265         DMA_Mask[dmachip] = val & 0x0F;
266         break;
267
268     case 0x09:
269     case 0xD2:
270         /* Software DRQx Request */
271         FIXME("Software DRQx Request (%x) - Not Implemented\n",val);
272         break;
273
274     case 0x0C:
275     case 0xD8:
276         /* Reset DMA Pointer Flip-Flop */
277         TRACE("Reset Flip-Flop\n");
278         DMA_Toggle[port==0xD8]=FALSE;
279         break;
280
281     case 0x0D:
282     case 0xDA:
283         /* Master Reset */
284         TRACE("Master Reset\n");
285         dmachip = (port==0x0D) ? 0 : 1;
286         /* Reset DMA Pointer Flip-Flop */
287         DMA_Toggle[dmachip]=FALSE;
288         /* Mask all channels */
289         DMA_Mask[dmachip] = 0x0F;
290         break;
291
292     case 0x0E:
293     case 0xDC:
294         /* Reset Mask Register */
295         FIXME("Reset Mask Register\n");
296         dmachip = (port==0x0E) ? 0 : 1;
297         /* Unmask all channels */
298         DMA_Mask[dmachip] = 0x00;
299         break;
300     }
301 }
302
303 BYTE DMA_ioport_in( WORD port )
304 {
305     int channel,dmachip;
306     BYTE res = 0;
307
308     switch(port)
309     {
310     case 0x00:
311     case 0x02:
312     case 0x04:
313     case 0x06:
314     case 0xC0:
315     case 0xC4:
316     case 0xC8:
317     case 0xCC:
318         /* Base Address*/
319         channel = (port&0xC0)?((port-0xC0)>>2):(port>>1);
320         dmachip = (channel<4) ? 0 : 1;
321         if (!DMA_Toggle[dmachip])
322             res = DMA_CurrentBaseAddress[channel] & 0xFF;
323         else {
324             res = (DMA_CurrentBaseAddress[channel] & (0xFF << 8))>>8;
325             TRACE("Read Current Base Address = %lx\n",DMA_CurrentBaseAddress[channel]);
326         }
327         DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
328         break;
329
330     case 0x01:
331     case 0x03:
332     case 0x05:
333     case 0x07:
334     case 0xC2:
335     case 0xC6:
336     case 0xCA:
337     case 0xCE:
338         /* Count*/
339         channel = ((port-1)&0xC0)?(((port-1)-0xC0)>>2):(port>>1);
340         dmachip = (channel<4) ? 0 : 1;
341         if (!DMA_Toggle[dmachip])
342             res = DMA_CurrentByteCount[channel] & 0xFF;
343         else {
344             res = (DMA_CurrentByteCount[channel] & (0xFF << 8))>>8;
345             TRACE("Read Current Count = %x.\n",DMA_CurrentByteCount[channel]);
346         }
347         DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
348         break;
349
350     /* Low Page Base Address */
351     case 0x87: res = (DMA_BaseAddress[0]&(0xFF<<16))>>16; break;
352     case 0x83: res = (DMA_BaseAddress[1]&(0xFF<<16))>>16; break;
353     case 0x81: res = (DMA_BaseAddress[2]&(0xFF<<16))>>16; break;
354     case 0x82: res = (DMA_BaseAddress[3]&(0xFF<<16))>>16; break;
355     case 0x8B: res = (DMA_BaseAddress[5]&(0xFF<<16))>>16; break;
356     case 0x89: res = (DMA_BaseAddress[6]&(0xFF<<16))>>16; break;
357     case 0x8A: res = (DMA_BaseAddress[7]&(0xFF<<16))>>16; break;
358
359     /* High Page Base Address */
360     case 0x487: res = (DMA_BaseAddress[0]&(0xFF<<24))>>24; break;
361     case 0x483: res = (DMA_BaseAddress[1]&(0xFF<<24))>>24; break;
362     case 0x481: res = (DMA_BaseAddress[2]&(0xFF<<24))>>24; break;
363     case 0x482: res = (DMA_BaseAddress[3]&(0xFF<<24))>>24; break;
364     case 0x48B: res = (DMA_BaseAddress[5]&(0xFF<<24))>>24; break;
365     case 0x489: res = (DMA_BaseAddress[6]&(0xFF<<24))>>24; break;
366     case 0x48A: res = (DMA_BaseAddress[7]&(0xFF<<24))>>24; break;
367
368     case 0x08:
369     case 0xD0:
370         /* Status */
371         TRACE("Status Register Read\n");
372         res = DMA_Status[(port==0x08)?0:1];
373
374     case 0x0D:
375     case 0xDA:
376         /* Temporary */
377         FIXME("Temporary Register Read- Not Implemented\n");
378         break;
379     }
380     return res;
381 }