1 /*
2     Interface for DMA routines on DOS
3     Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Library General Public
7     License as published by the Free Software Foundation; either
8     version 2 of the License, or (at your option) any later version.
9 
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Library General Public License for more details.
14 
15     You should have received a copy of the GNU Library General Public
16     License along with this library; if not, write to the Free
17     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 
20 #ifndef __DOSDMA_H__
21 #define __DOSDMA_H__
22 
23 #include <pc.h>
24 
25 #define DMA1_BASE		0x00	/* 8 bit slave DMA, channels 0..3 */
26 #define DMA2_BASE		0xC0	/* 16 bit master DMA, ch 4(=slave input)..7 */
27 
28 #define DMA1_CMD_REG		0x08	/* command register (w) */
29 #define DMA1_STAT_REG		0x08	/* status register (r) */
30 #define DMA1_REQ_REG		0x09	/* request register (w) */
31 #define DMA1_MASK_REG		0x0A	/* single-channel mask (w) */
32 #define DMA1_MODE_REG		0x0B	/* mode register (w) */
33 #define DMA1_CLEAR_FF_REG	0x0C	/* clear pointer flip-flop (w) */
34 #define DMA1_TEMP_REG		0x0D	/* Temporary Register (r) */
35 #define DMA1_RESET_REG		0x0D	/* Master Clear (w) */
36 #define DMA1_CLR_MASK_REG	0x0E	/* Clear Mask */
37 #define DMA1_MASK_ALL_REG	0x0F	/* all-channels mask (w) */
38 
39 #define DMA2_CMD_REG		0xD0	/* command register (w) */
40 #define DMA2_STAT_REG		0xD0	/* status register (r) */
41 #define DMA2_REQ_REG		0xD2	/* request register (w) */
42 #define DMA2_MASK_REG		0xD4	/* single-channel mask (w) */
43 #define DMA2_MODE_REG		0xD6	/* mode register (w) */
44 #define DMA2_CLEAR_FF_REG	0xD8	/* clear pointer flip-flop (w) */
45 #define DMA2_TEMP_REG		0xDA	/* Temporary Register (r) */
46 #define DMA2_RESET_REG		0xDA	/* Master Clear (w) */
47 #define DMA2_CLR_MASK_REG	0xDC	/* Clear Mask */
48 #define DMA2_MASK_ALL_REG	0xDE	/* all-channels mask (w) */
49 
50 #define DMA_ADDR_0      0x00	/* DMA address registers */
51 #define DMA_ADDR_1      0x02
52 #define DMA_ADDR_2      0x04
53 #define DMA_ADDR_3      0x06
54 #define DMA_ADDR_4      0xC0
55 #define DMA_ADDR_5      0xC4
56 #define DMA_ADDR_6      0xC8
57 #define DMA_ADDR_7      0xCC
58 
59 #define DMA_SIZE_0		0x01	/* DMA transfer size registers */
60 #define DMA_SIZE_1		0x03
61 #define DMA_SIZE_2		0x05
62 #define DMA_SIZE_3		0x07
63 #define DMA_SIZE_4		0xC2
64 #define DMA_SIZE_5		0xC6
65 #define DMA_SIZE_6		0xCA
66 #define DMA_SIZE_7		0xCE
67 
68 #define DMA_PAGE_0      0x87	/* DMA page registers */
69 #define DMA_PAGE_1      0x83
70 #define DMA_PAGE_2      0x81
71 #define DMA_PAGE_3      0x82
72 #define DMA_PAGE_5      0x8B
73 #define DMA_PAGE_6      0x89
74 #define DMA_PAGE_7      0x8A
75 
76 #define DMA_MODE_AUTOINIT	0x10	/* Auto-init mode bit */
77 #define DMA_MODE_READ		0x44	/* I/O to memory, no autoinit, increment, single mode */
78 #define DMA_MODE_WRITE		0x48	/* memory to I/O, no autoinit, increment, single mode */
79 #define DMA_MODE_CASCADE	0xC0	/* pass thru DREQ->HRQ, DACK<-HLDA only */
80 
81 /* Indexable specific DMA registers */
82 typedef struct __dma_regs_s {
83 	unsigned char addr;			/* DMA transfer address register */
84 	unsigned char page;			/* DMA page register */
85 	unsigned char size;			/* DMA transfer size register */
86 	unsigned char mask;			/* DMA mask/unmask register */
87 	unsigned char flip;			/* DMA flip-flop reset register */
88 	unsigned char mode;			/* DMA mode register */
89 } __dma_regs;
90 
91 extern __dma_regs dma[8];
92 
93 /* Enable a specific DMA channel */
dma_enable(unsigned int channel)94 static inline void dma_enable(unsigned int channel)
95 {
96 	outportb(dma[channel].mask, channel & 3);
97 }
98 
99 /* Disable a specific DMA channel */
dma_disable(unsigned int channel)100 static inline void dma_disable(unsigned int channel)
101 {
102 	outportb(dma[channel].mask, (channel & 3) | 0x04);
103 }
104 
105 /* Clear the 'DMA Flip Flop' flag */
dma_clear_ff(unsigned int channel)106 static inline void dma_clear_ff(unsigned int channel)
107 {
108 	outportb(dma[channel].flip, 0);
109 }
110 
111 /* Set mode for a specific DMA channel */
dma_set_mode(unsigned int channel,char mode)112 static inline void dma_set_mode(unsigned int channel, char mode)
113 {
114 	outportb(dma[channel].mode, mode | (channel & 3));
115 }
116 
117 /* Set DMA page register */
dma_set_page(unsigned int channel,char page)118 static inline void dma_set_page(unsigned int channel, char page)
119 {
120 	if (channel > 3)
121 		page &= 0xfe;
122 	outportb(dma[channel].page, page);
123 }
124 
125 /*
126   Set transfer address & page bits for specific DMA channel.
127   Assumes dma flipflop is clear.
128 */
dma_set_addr(unsigned int channel,unsigned int address)129 static inline void dma_set_addr(unsigned int channel, unsigned int address)
130 {
131 	unsigned char dma_reg = dma[channel].addr;
132 	dma_set_page(channel, address >> 16);
133 	if (channel <= 3) {
134 		outportb(dma_reg, (address) & 0xff);
135 		outportb(dma_reg, (address >> 8) & 0xff);
136 	} else {
137 		outportb(dma_reg, (address >> 1) & 0xff);
138 		outportb(dma_reg, (address >> 9) & 0xff);
139 	}
140 }
141 
142 /*
143   Set transfer size for a specific DMA channel.
144   Assumes dma flip-flop is clear.
145 */
dma_set_count(unsigned int channel,unsigned int count)146 static inline void dma_set_count(unsigned int channel, unsigned int count)
147 {
148 	unsigned char dma_reg = dma[channel].size;
149 	count--;					/* number of DMA transfers is bigger by one */
150 	if (channel > 3)
151 		count >>= 1;
152 	outportb(dma_reg, (count) & 0xff);
153 	outportb(dma_reg, (count >> 8) & 0xff);
154 }
155 
156 /*
157   Query the number of bytes left to transfer.
158   Assumes DMA flip-flop is clear.
159 */
dma_get_count(unsigned int channel)160 static inline int dma_get_count(unsigned int channel)
161 {
162 	unsigned char dma_reg = dma[channel].size;
163 
164 	/* using short to get 16-bit wrap around */
165 	unsigned short count;
166 	count = inportb(dma_reg);
167 	count |= inportb(dma_reg) << 8;
168 	count++;
169 	return (channel <= 3) ? count : (count << 1);
170 }
171 
172 typedef struct dma_buffer_s {
173 	unsigned char *linear;		/* Linear address */
174 	unsigned long physical;		/* Physical address */
175 	unsigned long size;			/* Buffer size */
176 	unsigned short selector;	/* The selector assigned to this memory */
177 	unsigned char channel;		/* The DMA channel */
178 } dma_buffer;
179 
180 /* Allocate a block of memory suitable for using as a DMA buffer */
181 extern dma_buffer *dma_allocate(unsigned int channel, unsigned int size);
182 /* Deallocate a DMA buffer */
183 extern void dma_free(dma_buffer * buffer);
184 /* Start DMA transfer to or from given buffer */
185 extern void dma_start(dma_buffer * buffer, unsigned long count,
186 					  unsigned char mode);
187 
188 #endif /* __DOSDMA_H__ */
189 
190 /* ex:set ts=4: */
191