]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/allg_snd/sound/drv/dma.c
This commit was generated by cvs2svn to compensate for changes in r2,
[btb/d2x.git] / arch / dos / allg_snd / sound / drv / dma.c
1 /*         ______   ___    ___ 
2  *        /\  _  \ /\_ \  /\_ \ 
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *      By Shawn Hargreaves,
11  *      1 Salisbury Road,
12  *      Market Drayton,
13  *      Shropshire,
14  *      England, TF9 1AJ.
15  *
16  *      DMA routines for the sound code. I used to feel slightly guilty 
17  *      because I pinched this code from MikMod, but then I looked at 
18  *      the GUS SDK and realised that Jean Paul Mikkers took it from 
19  *      there, so I think that justifies me in using it.
20  *
21  *      See readme.txt for copyright information.
22  */
23
24
25 #ifndef DJGPP
26 #error This file should only be used by the djgpp version of Allegro
27 #endif
28
29 #include <stdlib.h>
30 #include <dos.h>
31 #include <go32.h>
32 #include <dpmi.h>
33
34 #include "allegro.h"
35 #include "internal.h"
36
37
38 /* DMA Controler #1 (8-bit controller) */
39 #define DMA1_STAT       0x08            /* read status register */
40 #define DMA1_WCMD       0x08            /* write command register */
41 #define DMA1_WREQ       0x09            /* write request register */
42 #define DMA1_SNGL       0x0A            /* write single bit register */
43 #define DMA1_MODE       0x0B            /* write mode register */
44 #define DMA1_CLRFF      0x0C            /* clear byte ptr flip/flop */
45 #define DMA1_MCLR       0x0D            /* master clear register */
46 #define DMA1_CLRM       0x0E            /* clear mask register */
47 #define DMA1_WRTALL     0x0F            /* write all mask register */
48
49 /* DMA Controler #2 (16-bit controller) */
50 #define DMA2_STAT       0xD0            /* read status register */
51 #define DMA2_WCMD       0xD0            /* write command register */
52 #define DMA2_WREQ       0xD2            /* write request register */
53 #define DMA2_SNGL       0xD4            /* write single bit register */
54 #define DMA2_MODE       0xD6            /* write mode register */
55 #define DMA2_CLRFF      0xD8            /* clear byte ptr flip/flop */
56 #define DMA2_MCLR       0xDA            /* master clear register */
57 #define DMA2_CLRM       0xDC            /* clear mask register */
58 #define DMA2_WRTALL     0xDE            /* write all mask register */
59
60 /* stuff for each DMA channel */
61 #define DMA0_ADDR       0x00            /* chan 0 base adddress */
62 #define DMA0_CNT        0x01            /* chan 0 base count */
63 #define DMA1_ADDR       0x02            /* chan 1 base adddress */
64 #define DMA1_CNT        0x03            /* chan 1 base count */
65 #define DMA2_ADDR       0x04            /* chan 2 base adddress */
66 #define DMA2_CNT        0x05            /* chan 2 base count */
67 #define DMA3_ADDR       0x06            /* chan 3 base adddress */
68 #define DMA3_CNT        0x07            /* chan 3 base count */
69 #define DMA4_ADDR       0xC0            /* chan 4 base adddress */
70 #define DMA4_CNT        0xC2            /* chan 4 base count */
71 #define DMA5_ADDR       0xC4            /* chan 5 base adddress */
72 #define DMA5_CNT        0xC6            /* chan 5 base count */
73 #define DMA6_ADDR       0xC8            /* chan 6 base adddress */
74 #define DMA6_CNT        0xCA            /* chan 6 base count */
75 #define DMA7_ADDR       0xCC            /* chan 7 base adddress */
76 #define DMA7_CNT        0xCE            /* chan 7 base count */
77
78 #define DMA0_PAGE       0x87            /* chan 0 page register (refresh) */
79 #define DMA1_PAGE       0x83            /* chan 1 page register */
80 #define DMA2_PAGE       0x81            /* chan 2 page register */
81 #define DMA3_PAGE       0x82            /* chan 3 page register */
82 #define DMA4_PAGE       0x8F            /* chan 4 page register (unuseable) */
83 #define DMA5_PAGE       0x8B            /* chan 5 page register */
84 #define DMA6_PAGE       0x89            /* chan 6 page register */
85 #define DMA7_PAGE       0x8A            /* chan 7 page register */
86
87
88 typedef struct {
89    unsigned char dma_disable;           /* bits to disable dma channel */
90    unsigned char dma_enable;            /* bits to enable dma channel */
91    unsigned short page;                 /* page port location */
92    unsigned short addr;                 /* addr port location */
93    unsigned short count;                /* count port location */
94    unsigned short single;               /* single mode port location */
95    unsigned short mode;                 /* mode port location */
96    unsigned short clear_ff;             /* clear flip-flop port location */
97    unsigned char write;                 /* bits for write transfer */
98    unsigned char read;                  /* bits for read transfer */
99 } DMA_ENTRY;
100
101
102
103 static DMA_ENTRY mydma[] =
104 {
105    /* channel 0 */
106    { 0x04, 0x00, DMA0_PAGE, DMA0_ADDR, DMA0_CNT,
107      DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x48, 0x44 },
108
109    /* channel 1 */
110    { 0x05, 0x01, DMA1_PAGE, DMA1_ADDR, DMA1_CNT,
111      DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x49,0x45 },
112
113    /* channel 2 */
114    { 0x06, 0x02, DMA2_PAGE, DMA2_ADDR, DMA2_CNT,
115      DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x4A, 0x46 },
116
117    /* channel 3 */
118    { 0x07, 0x03, DMA3_PAGE, DMA3_ADDR, DMA3_CNT,
119      DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x4B, 0x47 },
120
121    /* channel 4 */
122    { 0x04, 0x00, DMA4_PAGE, DMA4_ADDR, DMA4_CNT,
123      DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x48, 0x44 },
124
125    /* channel 5 */
126    { 0x05, 0x01, DMA5_PAGE, DMA5_ADDR, DMA5_CNT,
127      DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x49, 0x45 },
128
129    /* channel 6 */
130    { 0x06, 0x02, DMA6_PAGE, DMA6_ADDR, DMA6_CNT,
131      DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x4A, 0x46 },
132
133    /* channel 7 */
134    { 0x07, 0x03, DMA7_PAGE, DMA7_ADDR, DMA7_CNT,
135      DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x4B, 0x47 }
136 };
137
138
139
140 /* _dma_allocate_mem:
141  *  Allocates the specified amount of conventional memory, ensuring that
142  *  the returned block doesn't cross a page boundary. Sel will be set to
143  *  the protected mode segment that should be used to free the block, and
144  *  phys to the linear address of the block. On error, returns non-zero
145  *  and sets sel and phys to 0.
146  */
147 int _dma_allocate_mem(int bytes, int *sel, unsigned long *phys)
148 {
149    int seg;
150
151    /* allocate twice as much memory as we really need */
152    seg = __dpmi_allocate_dos_memory((bytes*2 + 15) >> 4, sel);
153
154    if (seg < 0) {
155       *sel = 0;
156       *phys = 0;
157       return -1;
158    }
159
160    *phys = seg << 4;
161
162    /* if it crosses a page boundary, use the second half of the block */
163    if ((*phys>>16) != ((*phys+bytes)>>16))
164       *phys += bytes;
165
166    return 0;
167 }
168
169 END_OF_FUNCTION(_dma_allocate_mem);
170
171
172
173 /* dma_start:
174  *  Starts the DMA controller for the specified channel, transferring
175  *  size bytes from addr (the block must not cross a page boundary).
176  *  If auto_init is set, it will use the endless repeat DMA mode.
177  */
178 void _dma_start(int channel, unsigned long addr, int size, int auto_init)
179 {
180    DMA_ENTRY *tdma;
181    unsigned long page, offset;
182    int mode;
183
184    tdma = &mydma[channel]; 
185    page = addr >> 16;
186
187    if (channel >= 4) {          /* 16 bit data is halved */
188       addr >>= 1;
189       size >>= 1;
190    }
191
192    offset = addr & 0xFFFF;
193    size--;
194
195    mode = tdma->write;
196    if (auto_init)
197       mode |= 0x10;
198
199    outportb(tdma->single, tdma->dma_disable);      /* disable channel */
200    outportb(tdma->mode, mode);                     /* set mode */
201    outportb(tdma->clear_ff, 0);                    /* clear flip-flop */
202    outportb(tdma->addr, offset & 0xFF);            /* address LSB */
203    outportb(tdma->addr, offset >> 8);              /* address MSB */
204    outportb(tdma->page, page);                     /* page number */
205    outportb(tdma->clear_ff, 0);                    /* clear flip-flop */
206    outportb(tdma->count, size & 0xFF);             /* count LSB */
207    outportb(tdma->count, size >> 8);               /* count MSB */
208    outportb(tdma->single, tdma->dma_enable);       /* enable channel */
209 }
210
211 END_OF_FUNCTION(_dma_start);
212
213
214
215 /* dma_stop:
216  *  Disables the specified DMA channel.
217  */
218 void _dma_stop(int channel)
219 {
220    DMA_ENTRY *tdma = &mydma[channel];
221    outportb(tdma->single, tdma->dma_disable);
222 }
223
224 END_OF_FUNCTION(_dma_stop);
225
226
227
228 /* dma_todo:
229  *  Returns the current position in a dma transfer. Interrupts should be
230  *  disabled before calling this function.
231  */
232 unsigned long _dma_todo(int channel)
233 {
234    int val1, val2;
235    DMA_ENTRY *tdma = &mydma[channel];
236
237    outportb(tdma->clear_ff, 0xff);
238
239    do {
240       val1 = inportb(tdma->count);
241       val1 |= inportb(tdma->count) << 8;
242       val2 = inportb(tdma->count);
243       val2 |= inportb(tdma->count) << 8;
244
245       val1 -= val2;
246    } while (val1 > 0x40);
247
248    if (channel > 3)
249       val2 <<= 1;
250
251    return val2;
252 }
253
254 END_OF_FUNCTION(_dma_todo);
255
256
257
258 /* _dma_lock_mem:
259  *  Locks the memory used by the dma routines.
260  */
261 void _dma_lock_mem()
262 {
263    LOCK_VARIABLE(mydma);
264    LOCK_FUNCTION(_dma_allocate_mem);
265    LOCK_FUNCTION(_dma_start);
266    LOCK_FUNCTION(_dma_stop);
267    LOCK_FUNCTION(_dma_todo);
268 }
269