Created an ACM MS ADPCM codec.
[wine/wine-kai.git] / dlls / winedos / dma.c
blobe02954c26d7b85e04b892e375b0734f5c6d04fff
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include "windef.h"
24 #include "dosexe.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(dma);
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};
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
43 int DMA_Transfer(int channel,int reqlen,void* buffer)
45 int i,size,ret=0;
46 int opmode,increment,autoinit,trmode,dmachip;
47 int regmode = DMA_Command[channel];
48 char *p,*dmabuf;
50 dmabuf = buffer;
51 dmachip = (channel<4) ? 0 : 1;
53 TRACE("DMA_Command = %x reqlen=%d\n",regmode,reqlen);
55 /* Exit if channel is masked */
56 if (DMA_Mask[dmachip]&(1<<(channel&3)))
57 return 0;
59 opmode = (regmode & 0xC0) >> 6;
60 increment = !(regmode & 0x20);
61 autoinit = regmode & 0x10;
62 trmode = (regmode & 0x0C) >> 2;
64 /* Transfer size : 8 bits for channels 0..3, 16 bits for channels 4..7 */
65 size = (channel<4) ? 1 : 2;
67 /* Process operating mode */
68 switch(opmode)
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;
87 /* Perform one the 4 transfer modes */
88 if (trmode == 4) {
89 /* Illegal */
90 ERR("DMA Transfer Type Illegal\n");
91 return 0;
94 ret = min(DMA_CurrentByteCount[channel],reqlen);
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;
103 switch(trmode)
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;
133 /* Check for end of transfer */
134 if (DMA_CurrentByteCount[channel]==0) {
135 TRACE("DMA buffer empty\n");
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 */
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];
148 return ret;
152 void DMA_ioport_out( WORD port, BYTE val )
154 int channel,dmachip;
156 switch(port)
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]);
176 DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
177 break;
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]);
197 DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
198 break;
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;
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;
218 case 0x08:
219 case 0xD0:
220 /* Command */
221 FIXME("Write Command (%x) - Not Implemented\n",val);
222 break;
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)
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;
247 break;
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;
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;
268 case 0x09:
269 case 0xD2:
270 /* Software DRQx Request */
271 FIXME("Software DRQx Request (%x) - Not Implemented\n",val);
272 break;
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;
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;
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;
303 BYTE DMA_ioport_in( WORD port )
305 int channel,dmachip;
306 BYTE res = 0;
308 switch(port)
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]);
327 DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
328 break;
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]);
347 DMA_Toggle[dmachip] = !DMA_Toggle[dmachip];
348 break;
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;
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;
368 case 0x08:
369 case 0xD0:
370 /* Status */
371 TRACE("Status Register Read\n");
372 res = DMA_Status[(port==0x08)?0:1];
374 case 0x0D:
375 case 0xDA:
376 /* Temporary */
377 FIXME("Temporary Register Read- Not Implemented\n");
378 break;
380 return res;