1 /* $Header: /sys/linux-0.97/include/asm/RCS/dma.h,v 1.4 1992/09/21 03:15:46 root Exp root $ 2 * linux/include/asm/dma.h: Defines for using and allocating dma channels. 3 * Written by Hennus Bergman, 1992. 4 */ 5
6 #ifndef_ASM_DMA_H 7 #define_ASM_DMA_H 8
9 #include <asm/io.h> /* need byte IO */ 10 #include <linux/kernel.h> /* need panic() [FIXME] */ 11
12
13 #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
14 #defineoutboutb_p 15 #endif 16
17 /* FIXME: better fix this code for dma channels>3!!!!!!! */ 18
19 /* 20 * The routines below should in most cases (with optimizing on) result 21 * in equal or better code than similar code using macros. 22 * 23 * NOTE about DMA transfers: The DMA controller cannot handle transfers 24 * that cross a 64k boundary. When the address reaches 0xNffff, it will wrap 25 * around to 0xN0000, rather than increment to 0x(N+1)0000 ! 26 * Make sure you align your buffers properly! Runtime check recommended. 27 * 28 * NOTE2: DMA1..3 can only use the lower 1MB of physical memory. DMA4..7 29 * can access the lower 16MB. There are people with >16MB, so beware! 30 */ 31
32
33 #defineMAX_DMA_CHANNELS 8
34
35 /* SOMEBODY should check the following: 36 * Channels 0..3 are on the first DMA controller, channels 4..7 are 37 * on the second. Channel 0 is for refresh, 4 is for cascading. 38 * The first DMA controller uses bytes, the second words. 39 * 40 * Where are the page regs for the second DMA controller????? 41 */ 42
43
44 /* 8237 DMA controllers */ 45 #defineIO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ 46 #defineIO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ 47
48 /* DMA controller registers */ 49 #define DMA1_CMD_REG 0x08 /* DMA command register */ 50 #define DMA1_STAT_REG 0x08 /* DMA status register */ 51 #defineDMA1_MASK_REG 0x0A /* mask individual channels */ 52 #defineDMA1_MODE_REG 0x0B /* set modes for individual channels */ 53 #defineDMA1_CLEAR_FF_REG 0x0C /* Write 0 for LSB, 1 for MSB */ 54 #define DMA1_RESET_REG 0x0D /* Write here to reset DMA controller */ 55 /* don't have much info on the second DMA controller... */ 56 #defineDMA2_MASK_REG 0xD4
57 #defineDMA2_MODE_REG 0xD6
58 /* #define DMA2_CLEAR_FF_REG 0xD8 -- pure guessing.... */ 59
60 /************* #error This needs more work!!!!!!!*************/ 61
62 #defineDMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ 63 #defineDMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ 64 #defineDMA_MODE_CASCADE 0xC0 /* cascade mode (for DMA2 controller only) */ 65
66
67 /* enable/disable a specific DMA channel */ 68 static__inline__voidenable_dma(unsignedintdmanr)
/* */ 69 { 70 if (dmanr<=3)
71 outb(dmanr, DMA1_MASK_REG);
72 else 73 outb(dmanr & 3, DMA2_MASK_REG);
74 } 75
76 static__inline__voiddisable_dma(unsignedintdmanr)
/* */ 77 { 78 if (dmanr<=3)
79 outb(dmanr | 4, DMA1_MASK_REG);
80 else 81 outb((dmanr & 3) | 4, DMA2_MASK_REG);
82 } 83
84 /* Clear the 'DMA Pointer Flip Flop'. 85 * Write 0 for LSB/MSB, 1 for MSB/LSB access. 86 * Use this once to initialize the FF to a know state. 87 * After that, keep track of it. :-) In order to do that, 88 * dma_set_addr() and dma_set_count() should only be used wile 89 * interrupts are disbled. 90 */ 91 static__inline__voidclear_dma_ff(unsignedintdmanr)
/* */ 92 { 93 if (dmanr<=3)
94 outb(0, DMA1_CLEAR_FF_REG);
95 else 96 #ifdefDMA2_CLEAR_FF_REG 97 outb(0, DMA2_CLEAR_FF_REG);
98 #else 99 panic("dma.h: Don't have CLEAR_FF for high dma channels!\n");
100 #endif 101 } 102
103 /* set mode (above) for a specific DMA channel */ 104 static__inline__voidset_dma_mode(unsignedintdmanr, charmode)
/* */ 105 { 106 if (dmanr<=3)
107 outb(mode | dmanr, DMA1_MODE_REG);
108 else 109 outb(DMA_MODE_CASCADE | mode | (dmanr&3), DMA2_MODE_REG);
110 } 111
112 /* Set only the page register bits of the transfer address. 113 * This is used for successive transfers when we know the contents of 114 * the lower 16 bits of the DMA current address register, but a 64k boundary 115 * may have been crossed. 116 */ 117 static__inline__voidset_dma_page(unsignedintdmanr, charpagenr)
/* */ 118 { 119 switch(dmanr) { 120 case 0:
121 outb(pagenr, 0x80);
122 break;
123 case 1:
124 outb(pagenr, 0x83);
125 break;
126 case 2:
127 outb(pagenr, 0x81);
128 break;
129 case 3:
130 outb(pagenr, 0x82);
131 break;
132 case 4:
133 case 5:
134 case 6:
135 case 7:
136 panic("dma.h: don't know how to set DMA page regs for channels>3");
137 break;
138 } 139 } 140
141
142 /* Set transfer address & page bits for specific DMA channel. 143 * Assumes dma flipflop is clear. 144 */ 145 static__inline__voidset_dma_addr(unsignedintdmanr, unsignedinta)
/* */ 146 { 147 unsignedintio_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
148
149 set_dma_page(dmanr, a>>16);
150 outb(a & 0xff, ((dmanr&3)<<1) + io_base);
151 outb((a>>8) & 0xff, ((dmanr&3)<<1) + io_base);
152 } 153
154
155 /* Set transfer size (max 64k) for a specific DMA channel. 156 * You must ensure the parameters are valid. 157 * NOTE: from a manual: "the number of transfers is one more 158 * than the initial word count"! This is taken into account. 159 * Assumes dma flip-flop is clear. 160 */ 161 static__inline__voidset_dma_count(unsignedintdmanr, unsignedintcount)
/* */ 162 { 163 unsignedintdc = count - 1;
164 unsignedintio_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
165
166 outb(dc & 0xff, ((dmanr&3)<<1) + 1 + io_base);
167 outb((dc>>8) & 0xff, ((dmanr&3)<<1) + 1 + io_base);
168 } 169
170
171 /* Get DMA residue count. After a DMA transfer, this 172 * should return zero. Reading this while a DMA transfer is 173 * still in progress will return unpredictable results. 174 * If called before the channel has been used, it may return 1. 175 * Otherwise, it returns the number of bytes left to transfer, 176 * minus 1, modulo 64k. 177 * Assumes DMA flip-flop is clear. 178 */ 179 static__inline__shortint get_dma_residue(unsignedintdmanr)
/* */ 180 { 181 unsignedintio_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
182
183 return 1 + inb( ((dmanr&3)<<1) + 1 + io_base ) +
184 ( inb( ((dmanr&3)<<1) + 1 + io_base ) << 8 );
185 } 186
187 /* These are in kernel/dma.c: */ 188 externintrequest_dma(unsignedintdmanr); /* reserve a DMA channel */ 189 externvoidfree_dma(unsignedintdmanr); /* release it again */ 190
191
192 #endif/* _ASM_DMA_H */