1 /* $OpenBSD: isadma.c,v 1.22 1999/01/11 01:49:00 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 <vm/vm.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 __P((struct device *, void *, void *)); 94 void isadmaattach __P((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 __P((struct isa_softc *, int)); 142 static inline void isa_dmamask __P((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, BUS_DMASYNC_PREREAD); 356 sc->sc_dmareads |= (1 << chan); 357 } else { 358 bus_dmamap_sync(sc->sc_dmat, dmam, BUS_DMASYNC_PREWRITE); 359 sc->sc_dmareads &= ~(1 << chan); 360 } 361 362 dmaaddr = dmam->dm_segs[0].ds_addr; 363 364 #ifdef ISADMA_DEBUG 365 printf(" dmaaddr 0x%lx\n", dmaaddr); 366 367 __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:"); 368 #endif 369 370 sc->sc_dmalength[chan] = nbytes; 371 372 isa_dmamask(sc, chan); 373 sc->sc_dmafinished &= ~(1 << chan); 374 375 if ((chan & 4) == 0) { 376 /* set dma channel mode */ 377 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, DMA1_MODE, 378 ochan | dmamode[flags]); 379 380 /* send start address */ 381 waport = DMA1_CHN(ochan); 382 bus_space_write_1(sc->sc_iot, sc->sc_dmapgh, 383 dmapageport[0][ochan], (dmaaddr >> 16) & 0xff); 384 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport, 385 dmaaddr & 0xff); 386 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport, 387 (dmaaddr >> 8) & 0xff); 388 389 /* send count */ 390 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1, 391 (--nbytes) & 0xff); 392 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1, 393 (nbytes >> 8) & 0xff); 394 } else { 395 /* set dma channel mode */ 396 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, DMA2_MODE, 397 ochan | dmamode[flags]); 398 399 /* send start address */ 400 waport = DMA2_CHN(ochan); 401 bus_space_write_1(sc->sc_iot, sc->sc_dmapgh, 402 dmapageport[1][ochan], (dmaaddr >> 16) & 0xff); 403 dmaaddr >>= 1; 404 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport, 405 dmaaddr & 0xff); 406 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport, 407 (dmaaddr >> 8) & 0xff); 408 409 /* send count */ 410 nbytes >>= 1; 411 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2, 412 (--nbytes) & 0xff); 413 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2, 414 (nbytes >> 8) & 0xff); 415 } 416 417 isa_dmaunmask(sc, chan); 418 return (0); 419 420 lose: 421 panic("isa_dmastart"); 422 } 423 424 void 425 isa_dmaabort(isadev, chan) 426 struct device *isadev; 427 int chan; 428 { 429 struct isa_softc *sc = (struct isa_softc *)isadev; 430 431 if (chan < 0 || chan > 7) { 432 panic("isa_dmaabort: %s: bogus drq %d", sc->sc_dev.dv_xname, 433 chan); 434 } 435 436 isa_dmamask(sc, chan); 437 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamaps[chan]); 438 sc->sc_dmareads &= ~(1 << chan); 439 } 440 441 bus_size_t 442 isa_dmacount(isadev, chan) 443 struct device *isadev; 444 int chan; 445 { 446 struct isa_softc *sc = (struct isa_softc *)isadev; 447 int waport; 448 bus_size_t nbytes; 449 int ochan = chan & 3; 450 451 if (chan < 0 || chan > 7) { 452 panic("isa_dmacount: %s: bogus drq %d", sc->sc_dev.dv_xname, 453 chan); 454 } 455 456 isa_dmamask(sc, chan); 457 458 /* 459 * We have to shift the byte count by 1. If we're in auto-initialize 460 * mode, the count may have wrapped around to the initial value. We 461 * can't use the TC bit to check for this case, so instead we compare 462 * against the original byte count. 463 * If we're not in auto-initialize mode, then the count will wrap to 464 * -1, so we also handle that case. 465 */ 466 if ((chan & 4) == 0) { 467 waport = DMA1_CHN(ochan); 468 nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma1h, 469 waport + 1) + 1; 470 nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma1h, 471 waport + 1) << 8; 472 nbytes &= 0xffff; 473 } else { 474 waport = DMA2_CHN(ochan); 475 nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma2h, 476 waport + 2) + 1; 477 nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma2h, 478 waport + 2) << 8; 479 nbytes <<= 1; 480 nbytes &= 0x1ffff; 481 } 482 483 if (nbytes == sc->sc_dmalength[chan]) 484 nbytes = 0; 485 486 isa_dmaunmask(sc, chan); 487 return (nbytes); 488 } 489 490 int 491 isa_dmafinished(isadev, chan) 492 struct device *isadev; 493 int chan; 494 { 495 struct isa_softc *sc = (struct isa_softc *)isadev; 496 497 if (chan < 0 || chan > 7) { 498 panic("isa_dmafinished: %s: bogus drq %d", sc->sc_dev.dv_xname, 499 chan); 500 } 501 502 /* check that the terminal count was reached */ 503 if ((chan & 4) == 0) 504 sc->sc_dmafinished |= bus_space_read_1(sc->sc_iot, 505 sc->sc_dma1h, DMA1_SR) & 0x0f; 506 else 507 sc->sc_dmafinished |= (bus_space_read_1(sc->sc_iot, 508 sc->sc_dma2h, DMA2_SR) & 0x0f) << 4; 509 510 return ((sc->sc_dmafinished & (1 << chan)) != 0); 511 } 512 513 void 514 isa_dmadone(isadev, chan) 515 struct device *isadev; 516 int chan; 517 { 518 struct isa_softc *sc = (struct isa_softc *)isadev; 519 bus_dmamap_t dmam; 520 521 if (chan < 0 || chan > 7) { 522 panic("isa_dmadone: %s: bogus drq %d", sc->sc_dev.dv_xname, 523 chan); 524 } 525 526 dmam = sc->sc_dmamaps[chan]; 527 528 isa_dmamask(sc, chan); 529 530 if (isa_dmafinished(isadev, chan) == 0) 531 printf("%s: isa_dmadone: channel %d not finished\n", 532 sc->sc_dev.dv_xname, chan); 533 534 bus_dmamap_sync(sc->sc_dmat, dmam, 535 (sc->sc_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD : 536 BUS_DMASYNC_POSTWRITE); 537 538 bus_dmamap_unload(sc->sc_dmat, dmam); 539 sc->sc_dmareads &= ~(1 << chan); 540 } 541 542 int 543 isa_dmamem_alloc(isadev, chan, size, addrp, flags) 544 struct device *isadev; 545 int chan; 546 bus_size_t size; 547 bus_addr_t *addrp; 548 int flags; 549 { 550 struct isa_softc *sc = (struct isa_softc *)isadev; 551 bus_dma_segment_t seg; 552 int error, boundary, rsegs; 553 554 if (chan < 0 || chan > 7) { 555 panic("isa_dmamem_alloc: %s: bogus drq %d", 556 sc->sc_dev.dv_xname, chan); 557 } 558 559 boundary = (chan & 4) ? (1 << 17) : (1 << 16); 560 561 size = round_page(size); 562 563 error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, boundary, 564 &seg, 1, &rsegs, flags); 565 if (error) 566 return (error); 567 568 *addrp = seg.ds_addr; 569 return (0); 570 } 571 572 void 573 isa_dmamem_free(isadev, chan, addr, size) 574 struct device *isadev; 575 int chan; 576 bus_addr_t addr; 577 bus_size_t size; 578 { 579 struct isa_softc *sc = (struct isa_softc *)isadev; 580 bus_dma_segment_t seg; 581 582 if (chan < 0 || chan > 7) { 583 panic("isa_dmamem_free: %s: bogus drq %d", 584 sc->sc_dev.dv_xname, chan); 585 } 586 587 seg.ds_addr = addr; 588 seg.ds_len = size; 589 590 bus_dmamem_free(sc->sc_dmat, &seg, 1); 591 } 592 593 int 594 isa_dmamem_map(isadev, chan, addr, size, kvap, flags) 595 struct device *isadev; 596 int chan; 597 bus_addr_t addr; 598 bus_size_t size; 599 caddr_t *kvap; 600 int flags; 601 { 602 struct isa_softc *sc = (struct isa_softc *)isadev; 603 bus_dma_segment_t seg; 604 605 if (chan < 0 || chan > 7) { 606 panic("isa_dmamem_map: %s: bogus drq %d", sc->sc_dev.dv_xname, 607 chan); 608 } 609 610 seg.ds_addr = addr; 611 seg.ds_len = size; 612 613 return (bus_dmamem_map(sc->sc_dmat, &seg, 1, size, kvap, flags)); 614 } 615 616 void 617 isa_dmamem_unmap(isadev, chan, kva, size) 618 struct device *isadev; 619 int chan; 620 caddr_t kva; 621 size_t size; 622 { 623 struct isa_softc *sc = (struct isa_softc *)isadev; 624 625 if (chan < 0 || chan > 7) { 626 panic("isa_dmamem_unmap: %s: bogus drq %d", 627 sc->sc_dev.dv_xname, chan); 628 } 629 630 bus_dmamem_unmap(sc->sc_dmat, kva, size); 631 } 632 633 int 634 isa_dmamem_mmap(isadev, chan, addr, size, off, prot, flags) 635 struct device *isadev; 636 int chan; 637 bus_addr_t addr; 638 bus_size_t size; 639 int off, prot, flags; 640 { 641 struct isa_softc *sc = (struct isa_softc *)isadev; 642 bus_dma_segment_t seg; 643 644 if (chan < 0 || chan > 7) { 645 panic("isa_dmamem_mmap: %s: bogus drq %d", sc->sc_dev.dv_xname, 646 chan); 647 } 648 649 if (off < 0) 650 return (-1); 651 652 seg.ds_addr = addr; 653 seg.ds_len = size; 654 655 return (bus_dmamem_mmap(sc->sc_dmat, &seg, 1, off, prot, flags)); 656 } 657 658 int 659 isa_drq_isfree(isadev, chan) 660 struct device *isadev; 661 int chan; 662 { 663 struct isa_softc *sc = (struct isa_softc *)isadev; 664 if (chan < 0 || chan > 7) { 665 panic("isa_drq_isfree: %s: bogus drq %d", sc->sc_dev.dv_xname, 666 chan); 667 } 668 return ISA_DRQ_ISFREE(sc, chan); 669 } 670 671 void * 672 isa_malloc(isadev, chan, size, pool, flags) 673 struct device *isadev; 674 int chan; 675 size_t size; 676 int pool; 677 int flags; 678 { 679 bus_addr_t addr; 680 caddr_t kva; 681 int bflags; 682 struct isa_mem *m; 683 684 bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT; 685 686 if (isa_dmamem_alloc(isadev, chan, size, &addr, bflags)) 687 return 0; 688 if (isa_dmamem_map(isadev, chan, addr, size, &kva, bflags)) { 689 isa_dmamem_free(isadev, chan, addr, size); 690 return 0; 691 } 692 m = malloc(sizeof(*m), pool, flags); 693 if (m == 0) { 694 isa_dmamem_unmap(isadev, chan, kva, size); 695 isa_dmamem_free(isadev, chan, addr, size); 696 return 0; 697 } 698 m->isadev = isadev; 699 m->chan = chan; 700 m->size = size; 701 m->addr = addr; 702 m->kva = kva; 703 m->next = isa_mem_head; 704 isa_mem_head = m; 705 return (void *)kva; 706 } 707 708 void 709 isa_free(addr, pool) 710 void *addr; 711 int pool; 712 { 713 struct isa_mem **mp, *m; 714 caddr_t kva = (caddr_t)addr; 715 716 for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next) 717 ; 718 m = *mp; 719 if (!m) { 720 printf("isa_free: freeing unallocted memory\n"); 721 return; 722 } 723 *mp = m->next; 724 isa_dmamem_unmap(m->isadev, m->chan, kva, m->size); 725 isa_dmamem_free(m->isadev, m->chan, m->addr, m->size); 726 free(m, pool); 727 } 728 729 int 730 isa_mappage(mem, off, prot) 731 void *mem; 732 int off; 733 int prot; 734 { 735 struct isa_mem *m; 736 737 for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next) 738 ; 739 if (!m) { 740 printf("isa_mappage: mapping unallocted memory\n"); 741 return -1; 742 } 743 return (isa_dmamem_mmap(m->isadev, m->chan, m->addr, m->size, off, 744 prot, BUS_DMA_WAITOK)); 745 } 746