[BACK]Return to dma.c CVS log [TXT][DIR] Up to [local] / prex / dev / i386 / pc

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