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

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