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