-
Notifications
You must be signed in to change notification settings - Fork 1
/
DMA.c
239 lines (212 loc) · 10.2 KB
/
DMA.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/****************************************************************************/
/** **/
/** DMA.c **/
/** **/
/** DMA memory allocation and I/O routines **/
/** Based on Allegro's code. Allegro is a library for DJGPP written by **/
/** Shawn Hargreaves. Allegro is available at **/
/** ftp://x2ftp.oulu.fi/pub/msdos/programming/djgpp2 **/
/** **/
/** Copyright (C) Marcel de Kogel 1996 **/
/** You are not allowed to distribute this software commercially **/
/** Please, notify me, if you make any changes to this file **/
/****************************************************************************/
#include "DMA.h"
#include "Asm.h"
#include <stdlib.h>
#include <dos.h>
#include <go32.h>
#include <dpmi.h>
/* DMA Controler #1 (8-bit controller) */
#define DMA1_STAT 0x08 /* read status register */
#define DMA1_WCMD 0x08 /* write command register */
#define DMA1_WREQ 0x09 /* write request register */
#define DMA1_SNGL 0x0A /* write single bit register */
#define DMA1_MODE 0x0B /* write mode register */
#define DMA1_CLRFF 0x0C /* clear byte ptr flip/flop */
#define DMA1_MCLR 0x0D /* master clear register */
#define DMA1_CLRM 0x0E /* clear mask register */
#define DMA1_WRTALL 0x0F /* write all mask register */
/* DMA Controler #2 (16-bit controller) */
#define DMA2_STAT 0xD0 /* read status register */
#define DMA2_WCMD 0xD0 /* write command register */
#define DMA2_WREQ 0xD2 /* write request register */
#define DMA2_SNGL 0xD4 /* write single bit register */
#define DMA2_MODE 0xD6 /* write mode register */
#define DMA2_CLRFF 0xD8 /* clear byte ptr flip/flop */
#define DMA2_MCLR 0xDA /* master clear register */
#define DMA2_CLRM 0xDC /* clear mask register */
#define DMA2_WRTALL 0xDE /* write all mask register */
/* stuff for each DMA channel */
#define DMA0_ADDR 0x00 /* chan 0 base adddress */
#define DMA0_CNT 0x01 /* chan 0 base count */
#define DMA1_ADDR 0x02 /* chan 1 base adddress */
#define DMA1_CNT 0x03 /* chan 1 base count */
#define DMA2_ADDR 0x04 /* chan 2 base adddress */
#define DMA2_CNT 0x05 /* chan 2 base count */
#define DMA3_ADDR 0x06 /* chan 3 base adddress */
#define DMA3_CNT 0x07 /* chan 3 base count */
#define DMA4_ADDR 0xC0 /* chan 4 base adddress */
#define DMA4_CNT 0xC2 /* chan 4 base count */
#define DMA5_ADDR 0xC4 /* chan 5 base adddress */
#define DMA5_CNT 0xC6 /* chan 5 base count */
#define DMA6_ADDR 0xC8 /* chan 6 base adddress */
#define DMA6_CNT 0xCA /* chan 6 base count */
#define DMA7_ADDR 0xCC /* chan 7 base adddress */
#define DMA7_CNT 0xCE /* chan 7 base count */
#define DMA0_PAGE 0x87 /* chan 0 page register (refresh) */
#define DMA1_PAGE 0x83 /* chan 1 page register */
#define DMA2_PAGE 0x81 /* chan 2 page register */
#define DMA3_PAGE 0x82 /* chan 3 page register */
#define DMA4_PAGE 0x8F /* chan 4 page register (unuseable) */
#define DMA5_PAGE 0x8B /* chan 5 page register */
#define DMA6_PAGE 0x89 /* chan 6 page register */
#define DMA7_PAGE 0x8A /* chan 7 page register */
typedef struct {
unsigned char dma_disable; /* bits to disable dma channel */
unsigned char dma_enable; /* bits to enable dma channel */
unsigned short page; /* page port location */
unsigned short addr; /* addr port location */
unsigned short count; /* count port location */
unsigned short single; /* single mode port location */
unsigned short mode; /* mode port location */
unsigned short clear_ff; /* clear flip-flop port location */
unsigned char write; /* bits for write transfer */
unsigned char read; /* bits for read transfer */
} DMA_ENTRY;
static DMA_ENTRY mydma[] =
{
/* channel 0 */
{ 0x04, 0x00, DMA0_PAGE, DMA0_ADDR, DMA0_CNT,
DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x48, 0x44 },
/* channel 1 */
{ 0x05, 0x01, DMA1_PAGE, DMA1_ADDR, DMA1_CNT,
DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x49,0x45 },
/* channel 2 */
{ 0x06, 0x02, DMA2_PAGE, DMA2_ADDR, DMA2_CNT,
DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x4A, 0x46 },
/* channel 3 */
{ 0x07, 0x03, DMA3_PAGE, DMA3_ADDR, DMA3_CNT,
DMA1_SNGL, DMA1_MODE, DMA1_CLRFF, 0x4B, 0x47 },
/* channel 4 */
{ 0x04, 0x00, DMA4_PAGE, DMA4_ADDR, DMA4_CNT,
DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x48, 0x44 },
/* channel 5 */
{ 0x05, 0x01, DMA5_PAGE, DMA5_ADDR, DMA5_CNT,
DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x49, 0x45 },
/* channel 6 */
{ 0x06, 0x02, DMA6_PAGE, DMA6_ADDR, DMA6_CNT,
DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x4A, 0x46 },
/* channel 7 */
{ 0x07, 0x03, DMA7_PAGE, DMA7_ADDR, DMA7_CNT,
DMA2_SNGL, DMA2_MODE, DMA2_CLRFF, 0x4B, 0x47 }
};
/* _dma_free_mem() **********************************************************/
/* Frees DOS memory allocated by _dma_allocate_mem() */
/****************************************************************************/
int _dma_free_mem (unsigned sel)
{
return __dpmi_free_dos_memory(sel);
}
/* _dma_allocate_mem() ******************************************************/
/* Allocates the specified amount of conventional memory, ensuring that */
/* the returned block doesn't cross a page boundary. Sel will be set to */
/* the protected mode segment that should be used to free the block, and */
/* phys to the linear address of the block. On error, returns non-zero */
/* and sets sel and phys to 0 */
/****************************************************************************/
int _dma_allocate_mem(unsigned bytes,unsigned *sel,
unsigned *offs,unsigned *phys)
{
int tmp,size;
size=(bytes*2+15)>>4;
tmp=__dpmi_allocate_dos_memory(size, sel);
if (tmp==-1)
return 0;
*phys=tmp<<4;
*offs=0;
if ((*phys>>16)!=((*phys+bytes)>>16))
{
*phys+=bytes;
*offs+=bytes;
}
return 1;
}
/* dma_start() **************************************************************/
/* Starts the DMA controller for the specified channel, transferring */
/* size bytes from addr (the block must not cross a page boundary). */
/* If auto_init is set, it will use the endless repeat DMA mode */
/****************************************************************************/
void _dma_start(unsigned channel,unsigned addr,unsigned size,int auto_init)
{
DMA_ENTRY *tdma;
unsigned long page, offset;
int mode;
tdma = &mydma[channel];
page = addr >> 16;
/* 16 bit data is halved */
if (channel >= 4) {
addr >>= 1;
size >>= 1;
}
offset = addr & 0xFFFF;
size--;
mode = tdma->write;
if (auto_init)
mode |= 0x10;
__disable ();
outportb(tdma->single, tdma->dma_disable); /* disable channel */
nofunc ();
outportb(tdma->clear_ff, 0); /* clear flip-flop */
nofunc ();
outportb(tdma->addr, offset & 0xFF); /* address LSB */
nofunc ();
outportb(tdma->addr, offset >> 8); /* address MSB */
nofunc ();
outportb(tdma->count, size & 0xFF); /* count LSB */
nofunc ();
outportb(tdma->count, size >> 8); /* count MSB */
nofunc ();
outportb(tdma->page, page); /* page number */
nofunc ();
outportb(tdma->mode, mode); /* set mode */
nofunc ();
outportb(tdma->single, tdma->dma_enable); /* enable channel */
__enable ();
}
/* dma_stop() ***************************************************************/
/* Disables the specified DMA channel */
/****************************************************************************/
void _dma_stop(unsigned channel)
{
DMA_ENTRY *tdma = &mydma[channel];
outportb(tdma->single, tdma->dma_disable);
nofunc ();
outportb(tdma->clear_ff, 0); /* clear flip-flop */
}
/* dma_todo() ***************************************************************/
/* Returns the current position in a dma transfer */
/****************************************************************************/
unsigned _dma_todo(unsigned channel)
{
int val1, val2;
DMA_ENTRY *tdma = &mydma[channel];
__disable ();
outportb(tdma->clear_ff, 0xff);
nofunc ();
do {
val1 = inportb(tdma->count);
nofunc ();
val1 |= inportb(tdma->count) << 8;
nofunc ();
val2 = inportb(tdma->count);
nofunc ();
val2 |= inportb(tdma->count) << 8;
nofunc ();
val1 -= val2;
} while (val1 > 0x40);
__enable ();
if (channel > 3)
val2 <<= 1;
return val2;
}