Annotation of prex-old/dev/i386/pc/dma.c, Revision 1.1.1.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005, Kohsuke Ohtani
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * dma.c - DMA management routines for intel 8237 controller
32: */
33:
34: /** ==================================================================
35: * Memo:
36: *
37: * [Mode Register]
38: *
39: * Bits Function
40: * -------- Mode Selection
41: * 00 Demand Mode
42: * 01 Single Mode
43: * 10 Block Mode
44: * 11 Cascade Mode
45: * -------- Address Increment/Decrement
46: * 1 Address Decrement
47: * 0 Address Increment
48: * -------- Auto-Initialization Enable
49: * 1 Auto-Initialization DMA
50: * 0 Single-Cycle DMA
51: * -------- Transfer Type
52: * 00 Verify
53: * 01 Write
54: * 10 Read
55: * 11 Illegal
56: * -------- Channel Selection
57: * 00 Channel 0 (4)
58: * 01 Channel 1 (5)
59: * 10 Channel 2 (6)
60: * 11 Channel 3 (7)
61: *
62: * [Single Mask Register]
63: *
64: * Bits Function
65: * --------
66: * 00000 Unused, Set to 0
67: * -------- Set/Clear Mask
68: * 1 Set (Disable Channel)
69: * 0 Clear (Enable Channel)
70: * -------- Channel Selection
71: * 00 Channel 0 (4)
72: * 01 Channel 1 (5)
73: * 10 Channel 2 (6)
74: * 11 Channel 3 (7)
75: *
76: * ================================================================== */
77: #include <driver.h>
78: #include <cpu.h>
79:
80: #define NR_DMAS 8
81:
82: #define DMA_MAX (1024 * 64)
83: #define DMA_MASK (DMA_MAX-1)
84: #define DMA_ALIGN(n) ((((u_long)(n)) + DMA_MASK) & ~DMA_MASK)
85:
86: void dma_stop(int handle);
87:
88: /*
89: * DMA descriptor
90: */
91: struct dma {
92: int chan; /* dma channel */
93: int in_use; /* true if used */
94: };
95:
96: /*
97: * DMA i/o port
98: */
99: struct dma_port {
100: int mask;
101: int mode;
102: int clear;
103: int addr;
104: int count;
105: int page;
106: };
107:
108: static const struct dma_port dma_regs[] = {
109: /* mask, mode, clear, addr, count, page */
110: {0x0a, 0x0b, 0x0c, 0x00, 0x01, 0x87}, /* Channel 0 */
111: {0x0a, 0x0b, 0x0c, 0x02, 0x03, 0x83}, /* Channel 1 */
112: {0x0a, 0x0b, 0x0c, 0x04, 0x05, 0x81}, /* Channel 2 */
113: {0x0a, 0x0b, 0x0c, 0x06, 0x07, 0x82}, /* Channel 3 */
114: {0xd4, 0xd6, 0xd8, 0xc0, 0xc2, 0x8f}, /* Channel 4 (n/a) */
115: {0xd4, 0xd6, 0xd8, 0xc4, 0xc6, 0x8b}, /* Channel 5 */
116: {0xd4, 0xd6, 0xd8, 0xc8, 0xca, 0x89}, /* Channel 6 */
117: {0xd4, 0xd6, 0xd8, 0xcc, 0xce, 0x8a}, /* Channel 7 */
118: };
119:
120: static struct dma dma_table[NR_DMAS];
121:
122: /*
123: * Attach dma.
124: * Return dma handle on success, or -1 on failure.
125: * DMA4 can not be used with pc.
126: */
127: int
128: dma_attach(int chan)
129: {
130: struct dma *dma;
131:
132: ASSERT(chan >= 0 && chan < NR_DMAS);
133: ASSERT(chan != 4);
134: printk("DMA%d attached\n", chan);
135:
136: irq_lock();
137: dma = &dma_table[chan];
138: if (dma->in_use) {
139: irq_unlock();
140: return -1;
141: } else {
142: dma->chan = chan;
143: dma->in_use = 1;
144: }
145: dma_stop((int)dma);
146: irq_unlock();
147: return (int)dma;
148: }
149:
150: /*
151: * Detach dma.
152: */
153: void
154: dma_detach(int handle)
155: {
156: struct dma *dma = (struct dma *)handle;
157:
158: ASSERT(dma->in_use);
159: printk("DMA%d detached\n", dma->chan);
160:
161: irq_lock();
162: dma->in_use = 0;
163: irq_unlock();
164: }
165:
166: void
167: dma_setup(int handle, u_long addr, u_long count, int read)
168: {
169: struct dma *dma = (struct dma *)handle;
170: const struct dma_port *regs;
171: u_int chan, bits, mode;
172:
173: ASSERT(handle);
174: addr = (u_long)virt_to_phys((void *)addr);
175:
176: /* dma address must be under 16M. */
177: ASSERT(addr < 0xffffff);
178:
179: irq_lock();
180:
181: chan = (u_int)dma->chan;
182: regs = &dma_regs[chan];
183: bits = (chan < 4) ? chan : chan >> 2;
184: mode = read ? 0x44 : 0x48;
185: count--;
186:
187: outb_p(bits | 0x04, regs->mask); /* Disable channel */
188: outb_p(0x00, regs->clear); /* Clear byte pointer flip-flop */
189: outb_p(bits | mode, regs->mode); /* Set mode */
190: outb_p(addr >> 0, regs->addr); /* Address low */
191: outb_p(addr >> 8, regs->addr); /* Address high */
192: outb_p(addr >> 16, regs->page); /* Page address */
193: outb_p(0x00, regs->clear); /* Clear byte pointer flip-flop */
194: outb_p(count >> 0, regs->count); /* Count low */
195: outb_p(count >> 8, regs->count); /* Count high */
196: outb_p(bits, regs->mask); /* Enable channel */
197:
198: irq_unlock();
199: }
200:
201: void
202: dma_stop(int handle)
203: {
204: struct dma *dma = (struct dma *)handle;
205: u_int chan;
206: u_int bits;
207:
208: ASSERT(handle);
209: irq_lock();
210: chan = dma->chan;
211:
212: bits = (chan < 4) ? chan : chan >> 2;
213: outb_p(bits | 0x04, dma_regs[chan].mask); /* Disable channel */
214: irq_unlock();
215: }
216:
217: /*
218: * Allocate DMA buffer
219: *
220: * Return page address in 64K byte boundary.
221: * The caller must deallocate the pages by using page_free().
222: */
223: void *
224: dma_alloc(size_t size)
225: {
226: void *tmp, *base;
227:
228: if (size > DMA_MAX)
229: return NULL;
230:
231: /* Disable interrupts */
232: irq_lock();
233:
234: /*
235: * Try to allocate temporary buffer for enough size (64K + size).
236: */
237: size = (size_t)PAGE_ALIGN(size);
238: tmp = page_alloc(DMA_MAX + size);
239: if (!tmp) {
240: irq_unlock();
241: return NULL;
242: }
243: page_free(tmp, DMA_MAX + size);
244:
245: /*
246: * Now, we know the free address with 64k boundary.
247: */
248: base = (void *)DMA_ALIGN((u_long)tmp);
249: page_reserve(base, size);
250:
251: /* Restore interrupts */
252: irq_unlock();
253: return phys_to_virt(base);
254: }
CVSweb