3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
10 * By Shawn Hargreaves,
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.
21 * See readme.txt for copyright information.
26 #error This file should only be used by the djgpp version of Allegro
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 */
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 */
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 */
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 */
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 */
103 static DMA_ENTRY mydma[] =
106 { 0x04, 0x00, DMA0_PAGE, DMA0_ADDR, DMA0_CNT,
107 DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x48, 0x44 },
110 { 0x05, 0x01, DMA1_PAGE, DMA1_ADDR, DMA1_CNT,
111 DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x49,0x45 },
114 { 0x06, 0x02, DMA2_PAGE, DMA2_ADDR, DMA2_CNT,
115 DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x4A, 0x46 },
118 { 0x07, 0x03, DMA3_PAGE, DMA3_ADDR, DMA3_CNT,
119 DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x4B, 0x47 },
122 { 0x04, 0x00, DMA4_PAGE, DMA4_ADDR, DMA4_CNT,
123 DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x48, 0x44 },
126 { 0x05, 0x01, DMA5_PAGE, DMA5_ADDR, DMA5_CNT,
127 DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x49, 0x45 },
130 { 0x06, 0x02, DMA6_PAGE, DMA6_ADDR, DMA6_CNT,
131 DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x4A, 0x46 },
134 { 0x07, 0x03, DMA7_PAGE, DMA7_ADDR, DMA7_CNT,
135 DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x4B, 0x47 }
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.
147 int _dma_allocate_mem(int bytes, int *sel, unsigned long *phys)
151 /* allocate twice as much memory as we really need */
152 seg = __dpmi_allocate_dos_memory((bytes*2 + 15) >> 4, sel);
162 /* if it crosses a page boundary, use the second half of the block */
163 if ((*phys>>16) != ((*phys+bytes)>>16))
169 END_OF_FUNCTION(_dma_allocate_mem);
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.
178 void _dma_start(int channel, unsigned long addr, int size, int auto_init)
181 unsigned long page, offset;
184 tdma = &mydma[channel];
187 if (channel >= 4) { /* 16 bit data is halved */
192 offset = addr & 0xFFFF;
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 */
211 END_OF_FUNCTION(_dma_start);
216 * Disables the specified DMA channel.
218 void _dma_stop(int channel)
220 DMA_ENTRY *tdma = &mydma[channel];
221 outportb(tdma->single, tdma->dma_disable);
224 END_OF_FUNCTION(_dma_stop);
229 * Returns the current position in a dma transfer. Interrupts should be
230 * disabled before calling this function.
232 unsigned long _dma_todo(int channel)
235 DMA_ENTRY *tdma = &mydma[channel];
237 outportb(tdma->clear_ff, 0xff);
240 val1 = inportb(tdma->count);
241 val1 |= inportb(tdma->count) << 8;
242 val2 = inportb(tdma->count);
243 val2 |= inportb(tdma->count) << 8;
246 } while (val1 > 0x40);
254 END_OF_FUNCTION(_dma_todo);
259 * Locks the memory used by the dma routines.
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);