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