Annotation of prex/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: */
78: #include <driver.h>
79: #include <cpufunc.h>
80: #include "dma.h"
81:
82: #ifdef DEBUG
83: #define DPRINTF(a) printf a
84: #else
85: #define DPRINTF(a)
86: #endif
87:
88: #define NR_DMAS 8
89:
90: #define DMA_MAX (1024 * 64)
91: #define DMA_MASK (DMA_MAX-1)
92: #define DMA_ALIGN(n) ((((paddr_t)(n)) + DMA_MASK) & ~DMA_MASK)
93:
94: void dma_stop(int handle);
95:
96: /*
97: * DMA descriptor
98: */
99: struct dma {
100: int chan; /* dma channel */
101: int in_use; /* true if used */
102: };
103:
104: /*
105: * DMA i/o port
106: */
107: struct dma_port {
108: int mask;
109: int mode;
110: int clear;
111: int addr;
112: int count;
113: int page;
114: };
115:
116: static const struct dma_port dma_regs[] = {
117: /* mask, mode, clear, addr, count, page */
118: {0x0a, 0x0b, 0x0c, 0x00, 0x01, 0x87}, /* Channel 0 */
119: {0x0a, 0x0b, 0x0c, 0x02, 0x03, 0x83}, /* Channel 1 */
120: {0x0a, 0x0b, 0x0c, 0x04, 0x05, 0x81}, /* Channel 2 */
121: {0x0a, 0x0b, 0x0c, 0x06, 0x07, 0x82}, /* Channel 3 */
122: {0xd4, 0xd6, 0xd8, 0xc0, 0xc2, 0x8f}, /* Channel 4 (n/a) */
123: {0xd4, 0xd6, 0xd8, 0xc4, 0xc6, 0x8b}, /* Channel 5 */
124: {0xd4, 0xd6, 0xd8, 0xc8, 0xca, 0x89}, /* Channel 6 */
125: {0xd4, 0xd6, 0xd8, 0xcc, 0xce, 0x8a}, /* Channel 7 */
126: };
127:
128: static struct dma dma_table[NR_DMAS];
129:
130: /*
131: * Attach dma.
132: * Return dma handle on success, or -1 on failure.
133: * DMA4 can not be used with pc.
134: */
135: int
136: dma_attach(int chan)
137: {
138: struct dma *dma;
139:
140: ASSERT(chan >= 0 && chan < NR_DMAS);
141: ASSERT(chan != 4);
142: DPRINTF(("DMA%d attached\n", chan));
143:
144: irq_lock();
145: dma = &dma_table[chan];
146: if (dma->in_use) {
147: irq_unlock();
148: return -1;
149: } else {
150: dma->chan = chan;
151: dma->in_use = 1;
152: }
153: dma_stop((int)dma);
154: irq_unlock();
155: return (int)dma;
156: }
157:
158: /*
159: * Detach dma.
160: */
161: void
162: dma_detach(int handle)
163: {
164: struct dma *dma = (struct dma *)handle;
165:
166: ASSERT(dma->in_use);
167: DPRINTF(("DMA%d detached\n", dma->chan));
168:
169: irq_lock();
170: dma->in_use = 0;
171: irq_unlock();
172: }
173:
174: void
175: dma_setup(int handle, void *addr, u_long count, int read)
176: {
177: struct dma *dma = (struct dma *)handle;
178: const struct dma_port *regs;
179: u_int chan, bits, mode;
180: paddr_t paddr;
181:
182: ASSERT(handle);
183: paddr = (paddr_t)virt_to_phys(addr);
184:
185: /* dma address must be under 16M. */
186: ASSERT(paddr < 0xffffff);
187:
188: irq_lock();
189:
190: chan = (u_int)dma->chan;
191: regs = &dma_regs[chan];
192: bits = (chan < 4) ? chan : chan >> 2;
193: mode = read ? 0x44 : 0x48;
194: count--;
195:
196: outb_p(bits | 0x04, regs->mask); /* Disable channel */
197: outb_p(0x00, regs->clear); /* Clear byte pointer flip-flop */
198: outb_p(bits | mode, regs->mode); /* Set mode */
199: outb_p(paddr >> 0, regs->addr); /* Address low */
200: outb_p(paddr >> 8, regs->addr); /* Address high */
201: outb_p(paddr >> 16, regs->page); /* Page address */
202: outb_p(0x00, regs->clear); /* Clear byte pointer flip-flop */
203: outb_p(count >> 0, regs->count); /* Count low */
204: outb_p(count >> 8, regs->count); /* Count high */
205: outb_p(bits, regs->mask); /* Enable channel */
206:
207: irq_unlock();
208: }
209:
210: void
211: dma_stop(int handle)
212: {
213: struct dma *dma = (struct dma *)handle;
214: u_int chan;
215: u_int bits;
216:
217: ASSERT(handle);
218: irq_lock();
219: chan = (u_int)dma->chan;
220:
221: bits = (chan < 4) ? chan : chan >> 2;
222: outb_p(bits | 0x04, dma_regs[chan].mask); /* Disable channel */
223: irq_unlock();
224: }
225:
226: /*
227: * Allocate DMA buffer
228: *
229: * Return page address in 64K byte boundary.
230: * The caller must deallocate the pages by using page_free().
231: */
232: void *
233: dma_alloc(size_t size)
234: {
235: void *tmp, *base;
236:
237: if (size > DMA_MAX)
238: return NULL;
239:
240: /* Disable interrupts */
241: irq_lock();
242:
243: /*
244: * Try to allocate temporary buffer for enough size (64K + size).
245: */
246: size = (size_t)PAGE_ALIGN(size);
247: tmp = page_alloc((size_t)(DMA_MAX + size));
248: if (!tmp) {
249: irq_unlock();
250: return NULL;
251: }
252: page_free(tmp, (size_t)(DMA_MAX + size));
253:
254: /*
255: * Now, we know the free address with 64k boundary.
256: */
257: base = (void *)DMA_ALIGN((paddr_t)tmp);
258: page_reserve(base, size);
259:
260: /* Restore interrupts */
261: irq_unlock();
262: return phys_to_virt(base);
263: }
CVSweb