| Commit | Line | Data |
|---|---|---|
| d7510ae6 MD |
1 | /*- |
| 2 | * Copyright (c) 1991 The Regents of the University of California. | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * This code is derived from software contributed to Berkeley by | |
| 6 | * William Jolitz. | |
| 7 | * | |
| 8 | * Redistribution and use in source and binary forms, with or without | |
| 9 | * modification, are permitted provided that the following conditions | |
| 10 | * are met: | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in the | |
| 15 | * documentation and/or other materials provided with the distribution. | |
| 16 | * 3. All advertising materials mentioning features or use of this software | |
| 17 | * must display the following acknowledgement: | |
| 18 | * This product includes software developed by the University of | |
| 19 | * California, Berkeley and its contributors. | |
| 20 | * 4. Neither the name of the University nor the names of its contributors | |
| 21 | * may be used to endorse or promote products derived from this software | |
| 22 | * without specific prior written permission. | |
| 23 | * | |
| 24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 34 | * SUCH DAMAGE. | |
| 35 | * | |
| 36 | * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 | |
| 37 | * $FreeBSD: src/sys/i386/isa/isa_dma.c,v 1.4.2.1 2000/08/08 19:49:53 peter Exp $ | |
| d7510ae6 MD |
38 | */ |
| 39 | ||
| 40 | /* | |
| 41 | * code to manage AT bus | |
| 42 | * | |
| 43 | * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): | |
| 44 | * Fixed uninitialized variable problem and added code to deal | |
| 45 | * with DMA page boundaries in isa_dmarangecheck(). Fixed word | |
| 46 | * mode DMA count compution and reorganized DMA setup code in | |
| 47 | * isa_dmastart() | |
| 48 | */ | |
| 49 | ||
| 50 | #include <sys/param.h> | |
| 51 | #include <sys/systm.h> | |
| 52 | #include <sys/bus.h> | |
| 53 | #include <sys/kernel.h> | |
| 54 | #include <sys/malloc.h> | |
| 55 | #include <sys/buf.h> | |
| 56 | #include <vm/vm.h> | |
| 57 | #include <vm/vm_param.h> | |
| 58 | #include <vm/pmap.h> | |
| 59 | #include "isa.h" | |
| 60 | #include <machine_base/isa/ic/i8237.h> | |
| 61 | #include <machine/pmap.h> | |
| 62 | #include <bus/isa/isavar.h> | |
| 63 | ||
| 64 | /* | |
| 65 | ** Register definitions for DMA controller 1 (channels 0..3): | |
| 66 | */ | |
| 67 | #define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ | |
| 68 | #define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ | |
| 69 | #define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ | |
| 70 | #define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ | |
| 71 | ||
| 72 | /* | |
| 73 | ** Register definitions for DMA controller 2 (channels 4..7): | |
| 74 | */ | |
| 75 | #define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */ | |
| 76 | #define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ | |
| 77 | #define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ | |
| 78 | #define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ | |
| 79 | ||
| 80 | static int isa_dmarangecheck (caddr_t va, u_int length, int chan); | |
| 81 | ||
| 82 | static caddr_t dma_bouncebuf[8]; | |
| 83 | static u_int dma_bouncebufsize[8]; | |
| 84 | static u_int8_t dma_bounced = 0; | |
| 85 | static u_int8_t dma_busy = 0; /* Used in isa_dmastart() */ | |
| 86 | static u_int8_t dma_inuse = 0; /* User for acquire/release */ | |
| 87 | static u_int8_t dma_auto_mode = 0; | |
| 88 | ||
| 89 | #define VALID_DMA_MASK (7) | |
| 90 | ||
| 91 | /* high byte of address is stored in this port for i-th dma channel */ | |
| 92 | static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; | |
| 93 | ||
| 94 | /* | |
| 95 | * Setup a DMA channel's bounce buffer. | |
| 96 | */ | |
| 97 | void | |
| 98 | isa_dmainit(int chan, u_int bouncebufsize) | |
| 99 | { | |
| 100 | void *buf; | |
| 101 | ||
| 102 | #ifdef DIAGNOSTIC | |
| 103 | if (chan & ~VALID_DMA_MASK) | |
| 104 | panic("isa_dmainit: channel out of range"); | |
| 105 | ||
| 106 | if (dma_bouncebuf[chan] != NULL) | |
| 107 | panic("isa_dmainit: impossible request"); | |
| 108 | #endif | |
| 109 | ||
| 110 | dma_bouncebufsize[chan] = bouncebufsize; | |
| 111 | ||
| 112 | /* Try malloc() first. It works better if it works. */ | |
| 113 | buf = kmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT); | |
| 114 | if (buf != NULL) { | |
| 115 | if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) { | |
| 116 | dma_bouncebuf[chan] = buf; | |
| 117 | return; | |
| 118 | } | |
| 119 | kfree(buf, M_DEVBUF); | |
| 120 | } | |
| 121 | buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful, | |
| 122 | 1ul, chan & 4 ? 0x20000ul : 0x10000ul); | |
| 123 | if (buf == NULL) | |
| 124 | kprintf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize); | |
| 125 | else | |
| 126 | dma_bouncebuf[chan] = buf; | |
| 127 | } | |
| 128 | ||
| 129 | /* | |
| 130 | * Register a DMA channel's usage. Usually called from a device driver | |
| 131 | * in open() or during its initialization. | |
| 132 | */ | |
| 133 | int | |
| 134 | isa_dma_acquire(int chan) | |
| 135 | { | |
| 136 | #ifdef DIAGNOSTIC | |
| 137 | if (chan & ~VALID_DMA_MASK) | |
| 138 | panic("isa_dma_acquire: channel out of range"); | |
| 139 | #endif | |
| 140 | ||
| 141 | if (dma_inuse & (1 << chan)) { | |
| 142 | kprintf("isa_dma_acquire: channel %d already in use\n", chan); | |
| 143 | return (EBUSY); | |
| 144 | } | |
| 145 | dma_inuse |= (1 << chan); | |
| 146 | dma_auto_mode &= ~(1 << chan); | |
| 147 | ||
| 148 | return (0); | |
| 149 | } | |
| 150 | ||
| 151 | /* | |
| 152 | * Unregister a DMA channel's usage. Usually called from a device driver | |
| 153 | * during close() or during its shutdown. | |
| 154 | */ | |
| 155 | void | |
| 156 | isa_dma_release(int chan) | |
| 157 | { | |
| 158 | #ifdef DIAGNOSTIC | |
| 159 | if (chan & ~VALID_DMA_MASK) | |
| 160 | panic("isa_dma_release: channel out of range"); | |
| 161 | ||
| 162 | if ((dma_inuse & (1 << chan)) == 0) | |
| 163 | kprintf("isa_dma_release: channel %d not in use\n", chan); | |
| 164 | #endif | |
| 165 | ||
| 166 | if (dma_busy & (1 << chan)) { | |
| 167 | dma_busy &= ~(1 << chan); | |
| 168 | /* | |
| 169 | * XXX We should also do "dma_bounced &= (1 << chan);" | |
| 170 | * because we are acting on behalf of isa_dmadone() which | |
| 171 | * was not called to end the last DMA operation. This does | |
| 172 | * not matter now, but it may in the future. | |
| 173 | */ | |
| 174 | } | |
| 175 | ||
| 176 | dma_inuse &= ~(1 << chan); | |
| 177 | dma_auto_mode &= ~(1 << chan); | |
| 178 | } | |
| 179 | ||
| 180 | /* | |
| 181 | * isa_dmacascade(): program 8237 DMA controller channel to accept | |
| 182 | * external dma control by a board. | |
| 183 | */ | |
| 184 | void | |
| 185 | isa_dmacascade(int chan) | |
| 186 | { | |
| 187 | #ifdef DIAGNOSTIC | |
| 188 | if (chan & ~VALID_DMA_MASK) | |
| 189 | panic("isa_dmacascade: channel out of range"); | |
| 190 | #endif | |
| 191 | ||
| 192 | /* set dma channel mode, and set dma channel mode */ | |
| 193 | if ((chan & 4) == 0) { | |
| 194 | outb(DMA1_MODE, DMA37MD_CASCADE | chan); | |
| 195 | outb(DMA1_SMSK, chan); | |
| 196 | } else { | |
| 197 | outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); | |
| 198 | outb(DMA2_SMSK, chan & 3); | |
| 199 | } | |
| 200 | } | |
| 201 | ||
| 202 | /* | |
| 203 | * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment | |
| 204 | * problems by using a bounce buffer. | |
| 205 | */ | |
| 206 | void | |
| 207 | isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan) | |
| 208 | { | |
| 209 | vm_paddr_t phys; | |
| 210 | int waport; | |
| 211 | caddr_t newaddr; | |
| 212 | ||
| 213 | #ifdef DIAGNOSTIC | |
| 214 | if (chan & ~VALID_DMA_MASK) | |
| 215 | panic("isa_dmastart: channel out of range"); | |
| 216 | ||
| 217 | if ((chan < 4 && nbytes > (1<<16)) | |
| 218 | || (chan >= 4 && (nbytes > (1<<17) || (u_int)(uintptr_t)addr & 1))) | |
| 219 | panic("isa_dmastart: impossible request"); | |
| 220 | ||
| 221 | if ((dma_inuse & (1 << chan)) == 0) | |
| 222 | kprintf("isa_dmastart: channel %d not acquired\n", chan); | |
| 223 | #endif | |
| 224 | ||
| 225 | #if 0 | |
| 226 | /* | |
| 227 | * XXX This should be checked, but drivers like ad1848 only call | |
| 228 | * isa_dmastart() once because they use Auto DMA mode. If we | |
| 229 | * leave this in, drivers that do this will print this continuously. | |
| 230 | */ | |
| 231 | if (dma_busy & (1 << chan)) | |
| 232 | kprintf("isa_dmastart: channel %d busy\n", chan); | |
| 233 | #endif | |
| 234 | ||
| 235 | dma_busy |= (1 << chan); | |
| 236 | ||
| 237 | if (isa_dmarangecheck(addr, nbytes, chan)) { | |
| 238 | if (dma_bouncebuf[chan] == NULL | |
| 239 | || dma_bouncebufsize[chan] < nbytes) | |
| 240 | panic("isa_dmastart: bad bounce buffer"); | |
| 241 | dma_bounced |= (1 << chan); | |
| 242 | newaddr = dma_bouncebuf[chan]; | |
| 243 | ||
| 244 | /* copy bounce buffer on write */ | |
| 245 | if (flags & ISADMA_WRITE) | |
| 246 | bcopy(addr, newaddr, nbytes); | |
| 247 | addr = newaddr; | |
| 248 | } | |
| 249 | ||
| 250 | /* translate to physical */ | |
| 251 | phys = pmap_extract(&kernel_pmap, (vm_offset_t)addr); | |
| 252 | ||
| 253 | if (flags & ISADMA_RAW) { | |
| 254 | dma_auto_mode |= (1 << chan); | |
| 255 | } else { | |
| 256 | dma_auto_mode &= ~(1 << chan); | |
| 257 | } | |
| 258 | ||
| 259 | if ((chan & 4) == 0) { | |
| 260 | /* | |
| 261 | * Program one of DMA channels 0..3. These are | |
| 262 | * byte mode channels. | |
| 263 | */ | |
| 264 | /* set dma channel mode, and reset address ff */ | |
| 265 | ||
| 266 | /* If ISADMA_RAW flag is set, then use autoinitialise mode */ | |
| 267 | if (flags & ISADMA_RAW) { | |
| 268 | if (flags & ISADMA_READ) | |
| 269 | outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan); | |
| 270 | else | |
| 271 | outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan); | |
| 272 | } | |
| 273 | else | |
| 274 | if (flags & ISADMA_READ) | |
| 275 | outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); | |
| 276 | else | |
| 277 | outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); | |
| 278 | outb(DMA1_FFC, 0); | |
| 279 | ||
| 280 | /* send start address */ | |
| 281 | waport = DMA1_CHN(chan); | |
| 282 | outb(waport, phys); | |
| 283 | outb(waport, phys>>8); | |
| 284 | outb(dmapageport[chan], phys>>16); | |
| 285 | ||
| 286 | /* send count */ | |
| 287 | outb(waport + 1, --nbytes); | |
| 288 | outb(waport + 1, nbytes>>8); | |
| 289 | ||
| 290 | /* unmask channel */ | |
| 291 | outb(DMA1_SMSK, chan); | |
| 292 | } else { | |
| 293 | /* | |
| 294 | * Program one of DMA channels 4..7. These are | |
| 295 | * word mode channels. | |
| 296 | */ | |
| 297 | /* set dma channel mode, and reset address ff */ | |
| 298 | ||
| 299 | /* If ISADMA_RAW flag is set, then use autoinitialise mode */ | |
| 300 | if (flags & ISADMA_RAW) { | |
| 301 | if (flags & ISADMA_READ) | |
| 302 | outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_WRITE|(chan&3)); | |
| 303 | else | |
| 304 | outb(DMA2_MODE, DMA37MD_AUTO|DMA37MD_READ|(chan&3)); | |
| 305 | } | |
| 306 | else | |
| 307 | if (flags & ISADMA_READ) | |
| 308 | outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); | |
| 309 | else | |
| 310 | outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); | |
| 311 | outb(DMA2_FFC, 0); | |
| 312 | ||
| 313 | /* send start address */ | |
| 314 | waport = DMA2_CHN(chan - 4); | |
| 315 | outb(waport, phys>>1); | |
| 316 | outb(waport, phys>>9); | |
| 317 | outb(dmapageport[chan], phys>>16); | |
| 318 | ||
| 319 | /* send count */ | |
| 320 | nbytes >>= 1; | |
| 321 | outb(waport + 2, --nbytes); | |
| 322 | outb(waport + 2, nbytes>>8); | |
| 323 | ||
| 324 | /* unmask channel */ | |
| 325 | outb(DMA2_SMSK, chan & 3); | |
| 326 | } | |
| 327 | } | |
| 328 | ||
| 329 | void | |
| 330 | isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) | |
| 331 | { | |
| 332 | #ifdef DIAGNOSTIC | |
| 333 | if (chan & ~VALID_DMA_MASK) | |
| 334 | panic("isa_dmadone: channel out of range"); | |
| 335 | ||
| 336 | if ((dma_inuse & (1 << chan)) == 0) | |
| 337 | kprintf("isa_dmadone: channel %d not acquired\n", chan); | |
| 338 | #endif | |
| 339 | ||
| 340 | if (((dma_busy & (1 << chan)) == 0) && | |
| 341 | (dma_auto_mode & (1 << chan)) == 0 ) | |
| 342 | kprintf("isa_dmadone: channel %d not busy\n", chan); | |
| 343 | ||
| 344 | if ((dma_auto_mode & (1 << chan)) == 0) | |
| 345 | outb(chan & 4 ? DMA2_SMSK : DMA1_SMSK, (chan & 3) | 4); | |
| 346 | ||
| 347 | if (dma_bounced & (1 << chan)) { | |
| 348 | /* copy bounce buffer on read */ | |
| 349 | if (flags & ISADMA_READ) | |
| 350 | bcopy(dma_bouncebuf[chan], addr, nbytes); | |
| 351 | ||
| 352 | dma_bounced &= ~(1 << chan); | |
| 353 | } | |
| 354 | dma_busy &= ~(1 << chan); | |
| 355 | } | |
| 356 | ||
| 357 | /* | |
| 358 | * Check for problems with the address range of a DMA transfer | |
| 359 | * (non-contiguous physical pages, outside of bus address space, | |
| 360 | * crossing DMA page boundaries). | |
| 361 | * Return true if special handling needed. | |
| 362 | */ | |
| 363 | ||
| 364 | static int | |
| 365 | isa_dmarangecheck(caddr_t va, u_int length, int chan) | |
| 366 | { | |
| 367 | vm_paddr_t phys, priorpage = 0; | |
| 368 | vm_offset_t endva; | |
| 369 | u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); | |
| 370 | ||
| 371 | endva = (vm_offset_t)round_page((vm_offset_t)va + length); | |
| 372 | for (; va < (caddr_t) endva ; va += PAGE_SIZE) { | |
| 373 | phys = trunc_page(pmap_extract(&kernel_pmap, (vm_offset_t)va)); | |
| 374 | #define ISARAM_END RAM_END | |
| 375 | if (phys == 0) | |
| 376 | panic("isa_dmacheck: no physical page present"); | |
| 377 | if (phys >= ISARAM_END) | |
| 378 | return (1); | |
| 379 | if (priorpage) { | |
| 380 | if (priorpage + PAGE_SIZE != phys) | |
| 381 | return (1); | |
| 382 | /* check if crossing a DMA page boundary */ | |
| 383 | if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) | |
| 384 | return (1); | |
| 385 | } | |
| 386 | priorpage = phys; | |
| 387 | } | |
| 388 | return (0); | |
| 389 | } | |
| 390 | ||
| 391 | /* | |
| 392 | * Query the progress of a transfer on a DMA channel. | |
| 393 | * | |
| 394 | * To avoid having to interrupt a transfer in progress, we sample | |
| 395 | * each of the high and low databytes twice, and apply the following | |
| 396 | * logic to determine the correct count. | |
| 397 | * | |
| 398 | * Reads are performed with interrupts disabled, thus it is to be | |
| 399 | * expected that the time between reads is very small. At most | |
| 400 | * one rollover in the low count byte can be expected within the | |
| 401 | * four reads that are performed. | |
| 402 | * | |
| 403 | * There are three gaps in which a rollover can occur : | |
| 404 | * | |
| 405 | * - read low1 | |
| 406 | * gap1 | |
| 407 | * - read high1 | |
| 408 | * gap2 | |
| 409 | * - read low2 | |
| 410 | * gap3 | |
| 411 | * - read high2 | |
| 412 | * | |
| 413 | * If a rollover occurs in gap1 or gap2, the low2 value will be | |
| 414 | * greater than the low1 value. In this case, low2 and high2 are a | |
| 415 | * corresponding pair. | |
| 416 | * | |
| 417 | * In any other case, low1 and high1 can be considered to be correct. | |
| 418 | * | |
| 419 | * The function returns the number of bytes remaining in the transfer, | |
| 420 | * or -1 if the channel requested is not active. | |
| 421 | * | |
| 422 | */ | |
| 423 | int | |
| 424 | isa_dmastatus(int chan) | |
| 425 | { | |
| 426 | u_long cnt = 0; | |
| 427 | int ffport, waport; | |
| 428 | u_long low1, high1, low2, high2; | |
| 429 | ||
| 430 | /* channel active? */ | |
| 431 | if ((dma_inuse & (1 << chan)) == 0) { | |
| 432 | kprintf("isa_dmastatus: channel %d not active\n", chan); | |
| 433 | return(-1); | |
| 434 | } | |
| 435 | /* channel busy? */ | |
| 436 | ||
| 437 | if (((dma_busy & (1 << chan)) == 0) && | |
| 438 | (dma_auto_mode & (1 << chan)) == 0 ) { | |
| 439 | kprintf("chan %d not busy\n", chan); | |
| 440 | return -2 ; | |
| 441 | } | |
| 442 | if (chan < 4) { /* low DMA controller */ | |
| 443 | ffport = DMA1_FFC; | |
| 444 | waport = DMA1_CHN(chan) + 1; | |
| 445 | } else { /* high DMA controller */ | |
| 446 | ffport = DMA2_FFC; | |
| 447 | waport = DMA2_CHN(chan - 4) + 2; | |
| 448 | } | |
| 449 | ||
| 450 | cpu_disable_intr(); /* YYY *//* no interrupts Mr Jones! */ | |
| 451 | outb(ffport, 0); /* clear register LSB flipflop */ | |
| 452 | low1 = inb(waport); | |
| 453 | high1 = inb(waport); | |
| 454 | outb(ffport, 0); /* clear again */ | |
| 455 | low2 = inb(waport); | |
| 456 | high2 = inb(waport); | |
| 457 | cpu_enable_intr(); /* enable interrupts again */ | |
| 458 | ||
| 459 | /* | |
| 460 | * Now decide if a wrap has tried to skew our results. | |
| 461 | * Note that after TC, the count will read 0xffff, while we want | |
| 462 | * to return zero, so we add and then mask to compensate. | |
| 463 | */ | |
| 464 | if (low1 >= low2) { | |
| 465 | cnt = (low1 + (high1 << 8) + 1) & 0xffff; | |
| 466 | } else { | |
| 467 | cnt = (low2 + (high2 << 8) + 1) & 0xffff; | |
| 468 | } | |
| 469 | ||
| 470 | if (chan >= 4) /* high channels move words */ | |
| 471 | cnt *= 2; | |
| 472 | return(cnt); | |
| 473 | } | |
| 474 | ||
| 475 | /* | |
| 476 | * Stop a DMA transfer currently in progress. | |
| 477 | */ | |
| 478 | int | |
| 479 | isa_dmastop(int chan) | |
| 480 | { | |
| 481 | if ((dma_inuse & (1 << chan)) == 0) | |
| 482 | kprintf("isa_dmastop: channel %d not acquired\n", chan); | |
| 483 | ||
| 484 | if (((dma_busy & (1 << chan)) == 0) && | |
| 485 | ((dma_auto_mode & (1 << chan)) == 0)) { | |
| 486 | kprintf("chan %d not busy\n", chan); | |
| 487 | return -2 ; | |
| 488 | } | |
| 489 | ||
| 490 | if ((chan & 4) == 0) { | |
| 491 | outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */); | |
| 492 | } else { | |
| 493 | outb(DMA2_SMSK, (chan & 3) | 4 /* disable mask */); | |
| 494 | } | |
| 495 | return(isa_dmastatus(chan)); | |
| 496 | } | |
| 497 | ||
| 498 | unsigned | |
| 499 | isa_dmabp(struct buf *bp) | |
| 500 | { | |
| 501 | unsigned flags = 0; | |
| 502 | ||
| 503 | KKASSERT(bp->b_cmd != BUF_CMD_DONE); | |
| 504 | if (bp->b_flags & B_RAW) | |
| 505 | flags |= ISADMA_RAW; | |
| 506 | if (bp->b_cmd == BUF_CMD_READ) { | |
| 507 | flags |= ISADMA_READ; | |
| 508 | } else { | |
| 509 | /* BUF_CMD_WRITE, BUF_CMD_FORMAT */ | |
| 510 | flags |= ISADMA_WRITE; | |
| 511 | } | |
| 512 | return(flags); | |
| 513 | } | |
| 514 |