Annotation of prex/dev/i386/pc/dma.c, Revision 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