1 /* $OpenBSD: isadma.c,v 1.26 2002/03/14 01:26:56 millert Exp $ */ 2 /* $NetBSD: isadma.c,v 1.32 1997/09/05 01:48:33 thorpej Exp $ */ 3 4 /*- 5 * Copyright (c) 1997 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * Device driver for the ISA on-board DMA controller. 43 */ 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/proc.h> 48 #include <sys/device.h> 49 50 #include <uvm/uvm_extern.h> 51 52 #include <machine/bus.h> 53 54 #include <dev/isa/isareg.h> 55 #include <dev/isa/isavar.h> 56 #include <dev/isa/isadmavar.h> 57 #include <dev/isa/isadmareg.h> 58 59 #ifdef __ISADMA_COMPAT 60 /* XXX ugly, but will go away soon... */ 61 struct device *isa_dev; 62 63 bus_dmamap_t isadma_dmam[8]; 64 #endif 65 66 /* Used by isa_malloc() */ 67 #include <sys/malloc.h> 68 struct isa_mem { 69 struct device *isadev; 70 int chan; 71 bus_size_t size; 72 bus_addr_t addr; 73 caddr_t kva; 74 struct isa_mem *next; 75 } *isa_mem_head = 0; 76 77 /* 78 * High byte of DMA address is stored in this DMAPG register for 79 * the Nth DMA channel. 80 */ 81 static int dmapageport[2][4] = { 82 {0x7, 0x3, 0x1, 0x2}, 83 {0xf, 0xb, 0x9, 0xa} 84 }; 85 86 static u_int8_t dmamode[4] = { 87 DMA37MD_READ | DMA37MD_SINGLE, 88 DMA37MD_WRITE | DMA37MD_SINGLE, 89 DMA37MD_READ | DMA37MD_SINGLE | DMA37MD_LOOP, 90 DMA37MD_WRITE | DMA37MD_SINGLE | DMA37MD_LOOP 91 }; 92 93 int isadmamatch(struct device *, void *, void *); 94 void isadmaattach(struct device *, struct device *, void *); 95 96 struct cfattach isadma_ca = { 97 sizeof(struct device), isadmamatch, isadmaattach 98 }; 99 100 struct cfdriver isadma_cd = { 101 NULL, "isadma", DV_DULL, 1 102 }; 103 104 int 105 isadmamatch(parent, match, aux) 106 struct device *parent; 107 void *match, *aux; 108 { 109 struct isa_attach_args *ia = aux; 110 111 /* Sure we exist */ 112 ia->ia_iosize = 0; 113 return (1); 114 } 115 116 void 117 isadmaattach(parent, self, aux) 118 struct device *parent, *self; 119 void *aux; 120 { 121 #ifdef __ISADMA_COMPAT 122 int i, sz; 123 struct isa_softc *sc = (struct isa_softc *)parent; 124 125 /* XXX ugly, but will go away soon... */ 126 isa_dev = parent; 127 128 for (i = 0; i < 8; i++) { 129 sz = (i & 4) ? 1 << 17 : 1 << 16; 130 if ((bus_dmamap_create(sc->sc_dmat, sz, 1, sz, sz, 131 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &isadma_dmam[i])) != 0) 132 panic("isadmaattach: can not create DMA map"); 133 } 134 #endif 135 136 /* XXX I'd like to map the DMA ports here, see isa.c why not... */ 137 138 printf("\n"); 139 } 140 141 static inline void isa_dmaunmask(struct isa_softc *, int); 142 static inline void isa_dmamask(struct isa_softc *, int); 143 144 static inline void 145 isa_dmaunmask(sc, chan) 146 struct isa_softc *sc; 147 int chan; 148 { 149 int ochan = chan & 3; 150 151 /* set dma channel mode, and set dma channel mode */ 152 if ((chan & 4) == 0) 153 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, 154 DMA1_SMSK, ochan | DMA37SM_CLEAR); 155 else 156 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, 157 DMA2_SMSK, ochan | DMA37SM_CLEAR); 158 } 159 160 static inline void 161 isa_dmamask(sc, chan) 162 struct isa_softc *sc; 163 int chan; 164 { 165 int ochan = chan & 3; 166 167 /* set dma channel mode, and set dma channel mode */ 168 if ((chan & 4) == 0) { 169 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, 170 DMA1_SMSK, ochan | DMA37SM_SET); 171 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, 172 DMA1_FFC, 0); 173 } else { 174 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, 175 DMA2_SMSK, ochan | DMA37SM_SET); 176 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, 177 DMA2_FFC, 0); 178 } 179 } 180 181 /* 182 * isa_dmacascade(): program 8237 DMA controller channel to accept 183 * external dma control by a board. 184 */ 185 void 186 isa_dmacascade(isadev, chan) 187 struct device *isadev; 188 int chan; 189 { 190 struct isa_softc *sc = (struct isa_softc *)isadev; 191 int ochan = chan & 3; 192 193 if (chan < 0 || chan > 7) { 194 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan); 195 goto lose; 196 } 197 198 if (ISA_DRQ_ISFREE(sc, chan) == 0) { 199 printf("%s: DRQ %d is not free\n", sc->sc_dev.dv_xname, chan); 200 goto lose; 201 } 202 203 ISA_DRQ_ALLOC(sc, chan); 204 205 /* set dma channel mode, and set dma channel mode */ 206 if ((chan & 4) == 0) 207 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, 208 DMA1_MODE, ochan | DMA37MD_CASCADE); 209 else 210 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, 211 DMA2_MODE, ochan | DMA37MD_CASCADE); 212 213 isa_dmaunmask(sc, chan); 214 return; 215 216 lose: 217 panic("isa_dmacascade"); 218 } 219 220 int 221 isa_dmamap_create(isadev, chan, size, flags) 222 struct device *isadev; 223 int chan; 224 bus_size_t size; 225 int flags; 226 { 227 struct isa_softc *sc = (struct isa_softc *)isadev; 228 bus_size_t maxsize; 229 230 if (chan < 0 || chan > 7) { 231 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan); 232 goto lose; 233 } 234 235 if (chan & 4) 236 maxsize = (1 << 17); 237 else 238 maxsize = (1 << 16); 239 240 if (size > maxsize) 241 return (EINVAL); 242 243 if (ISA_DRQ_ISFREE(sc, chan) == 0) { 244 printf("%s: drq %d is not free\n", sc->sc_dev.dv_xname, chan); 245 goto lose; 246 } 247 248 ISA_DRQ_ALLOC(sc, chan); 249 250 return (bus_dmamap_create(sc->sc_dmat, size, 1, size, maxsize, 251 flags, &sc->sc_dmamaps[chan])); 252 253 lose: 254 panic("isa_dmamap_create"); 255 } 256 257 void 258 isa_dmamap_destroy(isadev, chan) 259 struct device *isadev; 260 int chan; 261 { 262 struct isa_softc *sc = (struct isa_softc *)isadev; 263 264 if (chan < 0 || chan > 7) { 265 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan); 266 goto lose; 267 } 268 269 if (ISA_DRQ_ISFREE(sc, chan)) { 270 printf("%s: drq %d is already free\n", 271 sc->sc_dev.dv_xname, chan); 272 goto lose; 273 } 274 275 ISA_DRQ_FREE(sc, chan); 276 277 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamaps[chan]); 278 return; 279 280 lose: 281 panic("isa_dmamap_destroy"); 282 } 283 284 /* 285 * isa_dmastart(): program 8237 DMA controller channel and set it 286 * in motion. 287 */ 288 int 289 isa_dmastart(isadev, chan, addr, nbytes, p, flags, busdmaflags) 290 struct device *isadev; 291 int chan; 292 void *addr; 293 bus_size_t nbytes; 294 struct proc *p; 295 int flags; 296 int busdmaflags; 297 { 298 struct isa_softc *sc = (struct isa_softc *)isadev; 299 bus_dmamap_t dmam; 300 bus_addr_t dmaaddr; 301 int waport; 302 int ochan = chan & 3; 303 int error; 304 #ifdef __ISADMA_COMPAT 305 int compat = busdmaflags & BUS_DMA_BUS1; 306 307 busdmaflags &= ~BUS_DMA_BUS1; 308 #endif /* __ISADMA_COMPAT */ 309 310 if (chan < 0 || chan > 7) { 311 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan); 312 goto lose; 313 } 314 315 #ifdef ISADMA_DEBUG 316 printf("isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, " 317 "flags 0x%x, dmaflags 0x%x\n", 318 chan, addr, nbytes, p, flags, busdmaflags); 319 #endif 320 321 if (chan & 4) { 322 if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) { 323 printf("%s: drq %d, nbytes 0x%lx, addr %p\n", 324 sc->sc_dev.dv_xname, chan, nbytes, addr); 325 goto lose; 326 } 327 } else { 328 if (nbytes > (1 << 16)) { 329 printf("%s: drq %d, nbytes 0x%lx\n", 330 sc->sc_dev.dv_xname, chan, nbytes); 331 goto lose; 332 } 333 } 334 335 dmam = sc->sc_dmamaps[chan]; 336 if (dmam == NULL) { 337 #ifdef __ISADMA_COMPAT 338 if (compat) 339 dmam = sc->sc_dmamaps[chan] = isadma_dmam[chan]; 340 else 341 #endif /* __ISADMA_COMPAT */ 342 panic("isa_dmastart: no DMA map for chan %d", chan); 343 } 344 345 error = bus_dmamap_load(sc->sc_dmat, dmam, addr, nbytes, p, 346 busdmaflags); 347 if (error) 348 return (error); 349 350 #ifdef ISADMA_DEBUG 351 __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:"); 352 #endif 353 354 if (flags & DMAMODE_READ) { 355 bus_dmamap_sync(sc->sc_dmat, dmam, 0, 356 dmam->dm_mapsize, 357 BUS_DMASYNC_PREREAD); 358 sc->sc_dmareads |= (1 << chan); 359 } else { 360 bus_dmamap_sync(sc->sc_dmat, dmam, 0, 361 dmam->dm_mapsize, 362 BUS_DMASYNC_PREWRITE); 363 sc->sc_dmareads &= ~(1 << chan); 364 } 365 366 dmaaddr = dmam->dm_segs[0].ds_addr; 367 368 #ifdef ISADMA_DEBUG 369 printf(" dmaaddr 0x%lx\n", dmaaddr); 370 371 __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:"); 372 #endif 373 374 sc->sc_dmalength[chan] = nbytes; 375 376 isa_dmamask(sc, chan); 377 sc->sc_dmafinished &= ~(1 << chan); 378 379 if ((chan & 4) == 0) { 380 /* set dma channel mode */ 381 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, DMA1_MODE, 382 ochan | dmamode[flags]); 383 384 /* send start address */ 385 waport = DMA1_CHN(ochan); 386 bus_space_write_1(sc->sc_iot, sc->sc_dmapgh, 387 dmapageport[0][ochan], (dmaaddr >> 16) & 0xff); 388 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport, 389 dmaaddr & 0xff); 390 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport, 391 (dmaaddr >> 8) & 0xff); 392 393 /* send count */ 394 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1, 395 (--nbytes) & 0xff); 396 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1, 397 (nbytes >> 8) & 0xff); 398 } else { 399 /* set dma channel mode */ 400 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, DMA2_MODE, 401 ochan | dmamode[flags]); 402 403 /* send start address */ 404 waport = DMA2_CHN(ochan); 405 bus_space_write_1(sc->sc_iot, sc->sc_dmapgh, 406 dmapageport[1][ochan], (dmaaddr >> 16) & 0xff); 407 dmaaddr >>= 1; 408 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport, 409 dmaaddr & 0xff); 410 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport, 411 (dmaaddr >> 8) & 0xff); 412 413 /* send count */ 414 nbytes >>= 1; 415 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2, 416 (--nbytes) & 0xff); 417 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2, 418 (nbytes >> 8) & 0xff); 419 } 420 421 isa_dmaunmask(sc, chan); 422 return (0); 423 424 lose: 425 panic("isa_dmastart"); 426 } 427 428 void 429 isa_dmaabort(isadev, chan) 430 struct device *isadev; 431 int chan; 432 { 433 struct isa_softc *sc = (struct isa_softc *)isadev; 434 435 if (chan < 0 || chan > 7) { 436 panic("isa_dmaabort: %s: bogus drq %d", sc->sc_dev.dv_xname, 437 chan); 438 } 439 440 isa_dmamask(sc, chan); 441 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamaps[chan]); 442 sc->sc_dmareads &= ~(1 << chan); 443 } 444 445 bus_size_t 446 isa_dmacount(isadev, chan) 447 struct device *isadev; 448 int chan; 449 { 450 struct isa_softc *sc = (struct isa_softc *)isadev; 451 int waport; 452 bus_size_t nbytes; 453 int ochan = chan & 3; 454 455 if (chan < 0 || chan > 7) { 456 panic("isa_dmacount: %s: bogus drq %d", sc->sc_dev.dv_xname, 457 chan); 458 } 459 460 isa_dmamask(sc, chan); 461 462 /* 463 * We have to shift the byte count by 1. If we're in auto-initialize 464 * mode, the count may have wrapped around to the initial value. We 465 * can't use the TC bit to check for this case, so instead we compare 466 * against the original byte count. 467 * If we're not in auto-initialize mode, then the count will wrap to 468 * -1, so we also handle that case. 469 */ 470 if ((chan & 4) == 0) { 471 waport = DMA1_CHN(ochan); 472 nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma1h, 473 waport + 1) + 1; 474 nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma1h, 475 waport + 1) << 8; 476 nbytes &= 0xffff; 477 } else { 478 waport = DMA2_CHN(ochan); 479 nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma2h, 480 waport + 2) + 1; 481 nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma2h, 482 waport + 2) << 8; 483 nbytes <<= 1; 484 nbytes &= 0x1ffff; 485 } 486 487 if (nbytes == sc->sc_dmalength[chan]) 488 nbytes = 0; 489 490 isa_dmaunmask(sc, chan); 491 return (nbytes); 492 } 493 494 int 495 isa_dmafinished(isadev, chan) 496 struct device *isadev; 497 int chan; 498 { 499 struct isa_softc *sc = (struct isa_softc *)isadev; 500 501 if (chan < 0 || chan > 7) { 502 panic("isa_dmafinished: %s: bogus drq %d", sc->sc_dev.dv_xname, 503 chan); 504 } 505 506 /* check that the terminal count was reached */ 507 if ((chan & 4) == 0) 508 sc->sc_dmafinished |= bus_space_read_1(sc->sc_iot, 509 sc->sc_dma1h, DMA1_SR) & 0x0f; 510 else 511 sc->sc_dmafinished |= (bus_space_read_1(sc->sc_iot, 512 sc->sc_dma2h, DMA2_SR) & 0x0f) << 4; 513 514 return ((sc->sc_dmafinished & (1 << chan)) != 0); 515 } 516 517 void 518 isa_dmadone(isadev, chan) 519 struct device *isadev; 520 int chan; 521 { 522 struct isa_softc *sc = (struct isa_softc *)isadev; 523 bus_dmamap_t dmam; 524 525 if (chan < 0 || chan > 7) { 526 panic("isa_dmadone: %s: bogus drq %d", sc->sc_dev.dv_xname, 527 chan); 528 } 529 530 dmam = sc->sc_dmamaps[chan]; 531 532 isa_dmamask(sc, chan); 533 534 if (isa_dmafinished(isadev, chan) == 0) 535 printf("%s: isa_dmadone: channel %d not finished\n", 536 sc->sc_dev.dv_xname, chan); 537 538 bus_dmamap_sync(sc->sc_dmat, dmam, 0, 539 dmam->dm_mapsize, 540 (sc->sc_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD : 541 BUS_DMASYNC_POSTWRITE); 542 543 bus_dmamap_unload(sc->sc_dmat, dmam); 544 sc->sc_dmareads &= ~(1 << chan); 545 } 546 547 int 548 isa_dmamem_alloc(isadev, chan, size, addrp, flags) 549 struct device *isadev; 550 int chan; 551 bus_size_t size; 552 bus_addr_t *addrp; 553 int flags; 554 { 555 struct isa_softc *sc = (struct isa_softc *)isadev; 556 bus_dma_segment_t seg; 557 int error, boundary, rsegs; 558 559 if (chan < 0 || chan > 7) { 560 panic("isa_dmamem_alloc: %s: bogus drq %d", 561 sc->sc_dev.dv_xname, chan); 562 } 563 564 boundary = (chan & 4) ? (1 << 17) : (1 << 16); 565 566 size = round_page(size); 567 568 error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, boundary, 569 &seg, 1, &rsegs, flags); 570 if (error) 571 return (error); 572 573 *addrp = seg.ds_addr; 574 return (0); 575 } 576 577 void 578 isa_dmamem_free(isadev, chan, addr, size) 579 struct device *isadev; 580 int chan; 581 bus_addr_t addr; 582 bus_size_t size; 583 { 584 struct isa_softc *sc = (struct isa_softc *)isadev; 585 bus_dma_segment_t seg; 586 587 if (chan < 0 || chan > 7) { 588 panic("isa_dmamem_free: %s: bogus drq %d", 589 sc->sc_dev.dv_xname, chan); 590 } 591 592 seg.ds_addr = addr; 593 seg.ds_len = size; 594 595 bus_dmamem_free(sc->sc_dmat, &seg, 1); 596 } 597 598 int 599 isa_dmamem_map(isadev, chan, addr, size, kvap, flags) 600 struct device *isadev; 601 int chan; 602 bus_addr_t addr; 603 bus_size_t size; 604 caddr_t *kvap; 605 int flags; 606 { 607 struct isa_softc *sc = (struct isa_softc *)isadev; 608 bus_dma_segment_t seg; 609 610 if (chan < 0 || chan > 7) { 611 panic("isa_dmamem_map: %s: bogus drq %d", sc->sc_dev.dv_xname, 612 chan); 613 } 614 615 seg.ds_addr = addr; 616 seg.ds_len = size; 617 618 return (bus_dmamem_map(sc->sc_dmat, &seg, 1, size, kvap, flags)); 619 } 620 621 void 622 isa_dmamem_unmap(isadev, chan, kva, size) 623 struct device *isadev; 624 int chan; 625 caddr_t kva; 626 size_t size; 627 { 628 struct isa_softc *sc = (struct isa_softc *)isadev; 629 630 if (chan < 0 || chan > 7) { 631 panic("isa_dmamem_unmap: %s: bogus drq %d", 632 sc->sc_dev.dv_xname, chan); 633 } 634 635 bus_dmamem_unmap(sc->sc_dmat, kva, size); 636 } 637 638 int 639 isa_dmamem_mmap(isadev, chan, addr, size, off, prot, flags) 640 struct device *isadev; 641 int chan; 642 bus_addr_t addr; 643 bus_size_t size; 644 int off, prot, flags; 645 { 646 struct isa_softc *sc = (struct isa_softc *)isadev; 647 bus_dma_segment_t seg; 648 649 if (chan < 0 || chan > 7) { 650 panic("isa_dmamem_mmap: %s: bogus drq %d", sc->sc_dev.dv_xname, 651 chan); 652 } 653 654 if (off < 0) 655 return (-1); 656 657 seg.ds_addr = addr; 658 seg.ds_len = size; 659 660 return (bus_dmamem_mmap(sc->sc_dmat, &seg, 1, off, prot, flags)); 661 } 662 663 int 664 isa_drq_isfree(isadev, chan) 665 struct device *isadev; 666 int chan; 667 { 668 struct isa_softc *sc = (struct isa_softc *)isadev; 669 if (chan < 0 || chan > 7) { 670 panic("isa_drq_isfree: %s: bogus drq %d", sc->sc_dev.dv_xname, 671 chan); 672 } 673 return ISA_DRQ_ISFREE(sc, chan); 674 } 675 676 void * 677 isa_malloc(isadev, chan, size, pool, flags) 678 struct device *isadev; 679 int chan; 680 size_t size; 681 int pool; 682 int flags; 683 { 684 bus_addr_t addr; 685 caddr_t kva; 686 int bflags; 687 struct isa_mem *m; 688 689 bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT; 690 691 if (isa_dmamem_alloc(isadev, chan, size, &addr, bflags)) 692 return 0; 693 if (isa_dmamem_map(isadev, chan, addr, size, &kva, bflags)) { 694 isa_dmamem_free(isadev, chan, addr, size); 695 return 0; 696 } 697 m = malloc(sizeof(*m), pool, flags); 698 if (m == 0) { 699 isa_dmamem_unmap(isadev, chan, kva, size); 700 isa_dmamem_free(isadev, chan, addr, size); 701 return 0; 702 } 703 m->isadev = isadev; 704 m->chan = chan; 705 m->size = size; 706 m->addr = addr; 707 m->kva = kva; 708 m->next = isa_mem_head; 709 isa_mem_head = m; 710 return (void *)kva; 711 } 712 713 void 714 isa_free(addr, pool) 715 void *addr; 716 int pool; 717 { 718 struct isa_mem **mp, *m; 719 caddr_t kva = (caddr_t)addr; 720 721 for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next) 722 ; 723 m = *mp; 724 if (!m) { 725 printf("isa_free: freeing unallocted memory\n"); 726 return; 727 } 728 *mp = m->next; 729 isa_dmamem_unmap(m->isadev, m->chan, kva, m->size); 730 isa_dmamem_free(m->isadev, m->chan, m->addr, m->size); 731 free(m, pool); 732 } 733 734 paddr_t 735 isa_mappage(mem, off, prot) 736 void *mem; 737 off_t off; 738 int prot; 739 { 740 struct isa_mem *m; 741 742 for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next) 743 ; 744 if (!m) { 745 printf("isa_mappage: mapping unallocted memory\n"); 746 return -1; 747 } 748 return (isa_dmamem_mmap(m->isadev, m->chan, m->addr, m->size, off, 749 prot, BUS_DMA_WAITOK)); 750 } 751