|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/dev/dma/i8237.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.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 * i8237.c - Intel 8237 DMA 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 79 #include <sys/cdefs.h> 80 #include <driver.h> 81 #include <cpufunc.h> 82 83 #ifdef DEBUG 84 #define DPRINTF(a) printf a 85 #else 86 #define DPRINTF(a) 87 #endif 88 89 #define NR_DMAS 8 90 91 #define DMA_MAX (1024 * 64) 92 #define DMA_MASK (DMA_MAX-1) 93 #define DMA_ALIGN(n) ((((paddr_t)(n)) + DMA_MASK) & ~DMA_MASK) 94 95 void dma_stop(dma_t handle); 96 static int dma_init(struct driver *self); 97 98 99 /* 100 * DMA descriptor 101 */ 102 struct dma { 103 int chan; /* dma channel */ 104 int in_use; /* true if used */ 105 }; 106 107 /* 108 * DMA i/o port 109 */ 110 struct dma_port { 111 int mask; 112 int mode; 113 int clear; 114 int addr; 115 int count; 116 int page; 117 }; 118 119 static const struct dma_port dma_regs[] = { 120 /* mask, mode, clear, addr, count, page */ 121 {0x0a, 0x0b, 0x0c, 0x00, 0x01, 0x87}, /* Channel 0 */ 122 {0x0a, 0x0b, 0x0c, 0x02, 0x03, 0x83}, /* Channel 1 */ 123 {0x0a, 0x0b, 0x0c, 0x04, 0x05, 0x81}, /* Channel 2 */ 124 {0x0a, 0x0b, 0x0c, 0x06, 0x07, 0x82}, /* Channel 3 */ 125 {0xd4, 0xd6, 0xd8, 0xc0, 0xc2, 0x8f}, /* Channel 4 (n/a) */ 126 {0xd4, 0xd6, 0xd8, 0xc4, 0xc6, 0x8b}, /* Channel 5 */ 127 {0xd4, 0xd6, 0xd8, 0xc8, 0xca, 0x89}, /* Channel 6 */ 128 {0xd4, 0xd6, 0xd8, 0xcc, 0xce, 0x8a}, /* Channel 7 */ 129 }; 130 131 static struct dma dma_table[NR_DMAS]; 132 133 struct driver i8237_driver = { 134 /* name */ "dma", 135 /* devsops */ NULL, 136 /* devsz */ 0, 137 /* flags */ 0, 138 /* probe */ NULL, 139 /* init */ dma_init, 140 /* shutdown */ NULL, 141 }; 142 143 144 /* 145 * Attach dma. 146 * Return dma handle on success, or panic on failure. 147 * DMA4 can not be used with pc. 148 */ 149 dma_t 150 dma_attach(int chan) 151 { 152 struct dma *dma; 153 int s; 154 155 ASSERT(chan >= 0 && chan < NR_DMAS); 156 ASSERT(chan != 4); 157 DPRINTF(("DMA%d attached\n", chan)); 158 159 s = splhigh(); 160 dma = &dma_table[chan]; 161 if (dma->in_use) { 162 panic("dma_attach"); 163 } else { 164 dma->chan = chan; 165 dma->in_use = 1; 166 } 167 dma_stop((dma_t)dma); 168 splx(s); 169 return (dma_t)dma; 170 } 171 172 /* 173 * Detach dma. 174 */ 175 void 176 dma_detach(dma_t handle) 177 { 178 struct dma *dma = (struct dma *)handle; 179 int s; 180 181 ASSERT(dma->in_use); 182 DPRINTF(("DMA%d detached\n", dma->chan)); 183 184 s = splhigh(); 185 dma->in_use = 0; 186 splx(s); 187 } 188 189 void 190 dma_setup(dma_t handle, void *addr, u_long count, int read) 191 { 192 struct dma *dma = (struct dma *)handle; 193 const struct dma_port *regs; 194 u_int chan, bits, mode; 195 paddr_t paddr; 196 int s; 197 198 ASSERT(handle); 199 paddr = kvtop(addr); 200 201 /* dma address must be under 16M. */ 202 ASSERT(paddr < 0xffffff); 203 204 s = splhigh(); 205 206 chan = (u_int)dma->chan; 207 regs = &dma_regs[chan]; 208 bits = (chan < 4) ? chan : chan >> 2; 209 mode = read ? 0x44U : 0x48U; 210 count--; 211 212 bus_write_8(regs->mask, bits | 0x04); /* Disable channel */ 213 bus_write_8(regs->clear, 0x00); /* Clear byte pointer flip-flop */ 214 bus_write_8(regs->mode, bits | mode); /* Set mode */ 215 bus_write_8(regs->addr, (u_char)((paddr >> 0) & 0xff)); /* Address low */ 216 bus_write_8(regs->addr, (u_char)((paddr >> 8) & 0xff)); /* Address high */ 217 bus_write_8(regs->page, (u_char)((paddr >> 16) & 0xff)); /* Page address */ 218 bus_write_8(regs->clear, 0x00); /* Clear byte pointer flip-flop */ 219 bus_write_8(regs->count, (u_char)((count >> 0) & 0xff)); /* Count low */ 220 bus_write_8(regs->count, (u_char)((count >> 8) & 0xff)); /* Count high */ 221 bus_write_8(regs->mask, bits); /* Enable channel */ 222 223 splx(s); 224 } 225 226 void 227 dma_stop(dma_t handle) 228 { 229 struct dma *dma = (struct dma *)handle; 230 u_int chan; 231 u_int bits; 232 int s; 233 234 ASSERT(handle); 235 s = splhigh(); 236 chan = (u_int)dma->chan; 237 238 bits = (chan < 4) ? chan : chan >> 2; 239 bus_write_8(dma_regs[chan].mask, bits | 0x04); /* Disable channel */ 240 splx(s); 241 } 242 243 /* 244 * Allocate DMA buffer 245 * 246 * Return page address in 64K byte boundary. 247 * The caller must deallocate the pages by using page_free(). 248 */ 249 void * 250 dma_alloc(size_t size) 251 { 252 paddr_t tmp, base; 253 254 if (size > DMA_MAX) 255 return NULL; 256 257 sched_lock(); 258 259 /* 260 * Try to allocate temporary buffer for enough size (64K + size). 261 */ 262 size = round_page(size); 263 tmp = page_alloc((size_t)(DMA_MAX + size)); 264 if (tmp == 0) { 265 sched_unlock(); 266 return NULL; 267 } 268 page_free(tmp, (size_t)(DMA_MAX + size)); 269 270 /* 271 * Now, we know the free address with 64k boundary. 272 */ 273 base = DMA_ALIGN(tmp); 274 page_reserve(base, size); 275 276 sched_unlock(); 277 return ptokv(base); 278 } 279 280 static int 281 dma_init(struct driver *self) 282 { 283 284 return 0; 285 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |