1 /* $OpenBSD: fms.c,v 1.27 2015/05/11 06:46:22 ratchov Exp $ */ 2 /* $NetBSD: fms.c,v 1.5.4.1 2000/06/30 16:27:50 simonb Exp $ */ 3 4 /*- 5 * Copyright (c) 1999 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Witold J. Wnuk. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Forte Media FM801 Audio Device Driver 35 */ 36 37 #include "radio.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/malloc.h> 43 #include <sys/device.h> 44 #include <sys/audioio.h> 45 46 #include <machine/bus.h> 47 #include <machine/cpu.h> 48 49 #include <dev/pci/pcidevs.h> 50 #include <dev/pci/pcivar.h> 51 52 #include <dev/audio_if.h> 53 #include <dev/ic/ac97.h> 54 #if 0 55 #include <dev/ic/mpuvar.h> 56 #endif 57 58 #include <dev/pci/fmsreg.h> 59 #include <dev/pci/fmsvar.h> 60 61 62 struct fms_dma { 63 struct fms_dma *next; 64 caddr_t addr; 65 size_t size; 66 bus_dmamap_t map; 67 bus_dma_segment_t seg; 68 }; 69 70 71 72 int fms_match(struct device *, void *, void *); 73 void fms_attach(struct device *, struct device *, void *); 74 int fms_intr(void *); 75 76 int fms_open(void *, int); 77 void fms_close(void *); 78 int fms_query_encoding(void *, struct audio_encoding *); 79 int fms_set_params(void *, int, int, struct audio_params *, 80 struct audio_params *); 81 void fms_get_default_params(void *, int, struct audio_params *); 82 int fms_round_blocksize(void *, int); 83 int fms_halt_output(void *); 84 int fms_halt_input(void *); 85 int fms_getdev(void *, struct audio_device *); 86 int fms_set_port(void *, mixer_ctrl_t *); 87 int fms_get_port(void *, mixer_ctrl_t *); 88 int fms_query_devinfo(void *, mixer_devinfo_t *); 89 void *fms_malloc(void *, int, size_t, int, int); 90 void fms_free(void *, void *, int); 91 paddr_t fms_mappage(void *, void *, off_t, int); 92 int fms_get_props(void *); 93 int fms_trigger_output(void *, void *, void *, int, void (*)(void *), 94 void *, struct audio_params *); 95 int fms_trigger_input(void *, void *, void *, int, void (*)(void *), 96 void *, struct audio_params *); 97 98 struct cfdriver fms_cd = { 99 NULL, "fms", DV_DULL 100 }; 101 102 struct cfattach fms_ca = { 103 sizeof (struct fms_softc), fms_match, fms_attach 104 }; 105 106 struct audio_device fms_device = { 107 "Forte Media 801", 108 "1.0", 109 "fms" 110 }; 111 112 113 struct audio_hw_if fms_hw_if = { 114 fms_open, 115 fms_close, 116 NULL, 117 fms_query_encoding, 118 fms_set_params, 119 fms_round_blocksize, 120 NULL, 121 NULL, 122 NULL, 123 NULL, 124 NULL, 125 fms_halt_output, 126 fms_halt_input, 127 NULL, 128 fms_getdev, 129 NULL, 130 fms_set_port, 131 fms_get_port, 132 fms_query_devinfo, 133 fms_malloc, 134 fms_free, 135 NULL, 136 fms_mappage, 137 fms_get_props, 138 fms_trigger_output, 139 fms_trigger_input, 140 fms_get_default_params 141 }; 142 143 int fms_attach_codec(void *, struct ac97_codec_if *); 144 int fms_read_codec(void *, u_int8_t, u_int16_t *); 145 int fms_write_codec(void *, u_int8_t, u_int16_t); 146 void fms_reset_codec(void *); 147 148 int fms_allocmem(struct fms_softc *, size_t, size_t, 149 struct fms_dma *); 150 int fms_freemem(struct fms_softc *, struct fms_dma *); 151 152 int 153 fms_match(struct device *parent, void *match, void *aux) 154 { 155 struct pci_attach_args *pa = (struct pci_attach_args *) aux; 156 157 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FORTEMEDIA && 158 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FORTEMEDIA_FM801) 159 return (1); 160 return (0); 161 } 162 163 void 164 fms_attach(struct device *parent, struct device *self, void *aux) 165 { 166 struct pci_attach_args *pa = aux; 167 struct fms_softc *sc = (struct fms_softc *) self; 168 struct audio_attach_args aa; 169 pci_chipset_tag_t pc = pa->pa_pc; 170 pcitag_t pt = pa->pa_tag; 171 pci_intr_handle_t ih; 172 bus_size_t iosize; 173 const char *intrstr; 174 u_int16_t k1; 175 int i; 176 177 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot, 178 &sc->sc_ioh, NULL, &iosize, 0)) { 179 printf(": can't map i/o space\n"); 180 return; 181 } 182 183 if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2, 184 &sc->sc_mpu_ioh)) { 185 printf(": can't get mpu subregion handle\n"); 186 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 187 return; 188 } 189 190 if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4, 191 &sc->sc_opl_ioh)) { 192 printf(": can't get opl subregion handle\n"); 193 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 194 return; 195 } 196 197 if (pci_intr_map(pa, &ih)) { 198 printf(": couldn't map interrupt\n"); 199 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 200 return; 201 } 202 intrstr = pci_intr_string(pc, ih); 203 204 sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE, 205 fms_intr, sc, sc->sc_dev.dv_xname); 206 if (sc->sc_ih == NULL) { 207 printf(": couldn't establish interrupt"); 208 if (intrstr != NULL) 209 printf(" at %s", intrstr); 210 printf("\n"); 211 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 212 return; 213 } 214 215 printf(": %s\n", intrstr); 216 217 sc->sc_dmat = pa->pa_dmat; 218 219 /* Disable legacy audio (SBPro compatibility) */ 220 pci_conf_write(pc, pt, 0x40, 0); 221 222 /* Reset codec and AC'97 */ 223 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020); 224 delay(2); /* > 1us according to AC'97 documentation */ 225 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000); 226 delay(1); /* > 168.2ns according to AC'97 documentation */ 227 228 /* Set up volume */ 229 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PCM_VOLUME, 0x0808); 230 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_FM_VOLUME, 0x0808); 231 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_I2S_VOLUME, 0x0808); 232 233 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_RECORD_SOURCE, 0x0000); 234 235 /* Unmask playback, record and mpu interrupts, mask the rest */ 236 k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK); 237 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK, 238 (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) | 239 FM_INTMASK_VOL); 240 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS, 241 FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU | 242 FM_INTSTATUS_VOL); 243 244 #if NRADIO > 0 245 fmsradio_attach(sc); 246 #endif /* NRADIO > 0 */ 247 248 sc->host_if.arg = sc; 249 sc->host_if.attach = fms_attach_codec; 250 sc->host_if.read = fms_read_codec; 251 sc->host_if.write = fms_write_codec; 252 sc->host_if.reset = fms_reset_codec; 253 254 if (ac97_attach(&sc->host_if) != 0) 255 return; 256 257 /* Turn mute off */ 258 for (i = 0; i < 3; i++) { 259 static struct { 260 char *class, *device; 261 } d[] = { 262 { AudioCoutputs, AudioNmaster }, 263 { AudioCinputs, AudioNdac }, 264 { AudioCrecord, AudioNvolume } 265 }; 266 struct mixer_ctrl ctl; 267 268 ctl.type = AUDIO_MIXER_ENUM; 269 ctl.un.ord = 0; 270 ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if, 271 d[i].class, d[i].device, AudioNmute); 272 fms_set_port(sc, &ctl); 273 } 274 275 audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev); 276 277 aa.type = AUDIODEV_TYPE_OPL; 278 aa.hwif = NULL; 279 aa.hdl = NULL; 280 config_found(&sc->sc_dev, &aa, audioprint); 281 282 aa.type = AUDIODEV_TYPE_MPU; 283 aa.hwif = NULL; 284 aa.hdl = NULL; 285 sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint); 286 } 287 288 /* 289 * Each AC-link frame takes 20.8us, data should be ready in next frame, 290 * we allow more than two. 291 */ 292 #define TIMO 50 293 int 294 fms_read_codec(void *addr, u_int8_t reg, u_int16_t *val) 295 { 296 struct fms_softc *sc = addr; 297 int i; 298 299 /* Poll until codec is ready */ 300 for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh, 301 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++) 302 delay(1); 303 if (i >= TIMO) { 304 printf("fms: codec busy\n"); 305 return 1; 306 } 307 308 /* Write register index, read access */ 309 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, 310 reg | FM_CODEC_CMD_READ); 311 312 /* Poll until we have valid data */ 313 for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh, 314 FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++) 315 delay(1); 316 if (i >= TIMO) { 317 printf("fms: no data from codec\n"); 318 return 1; 319 } 320 321 /* Read data */ 322 *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA); 323 return 0; 324 } 325 326 int 327 fms_write_codec(void *addr, u_int8_t reg, u_int16_t val) 328 { 329 struct fms_softc *sc = addr; 330 int i; 331 332 /* Poll until codec is ready */ 333 for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh, 334 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++) 335 delay(1); 336 if (i >= TIMO) { 337 printf("fms: codec busy\n"); 338 return 1; 339 } 340 341 /* Write data */ 342 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val); 343 /* Write index register, write access */ 344 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg); 345 return 0; 346 } 347 #undef TIMO 348 349 int 350 fms_attach_codec(void *addr, struct ac97_codec_if *cif) 351 { 352 struct fms_softc *sc = addr; 353 354 sc->codec_if = cif; 355 return 0; 356 } 357 358 /* Cold Reset */ 359 void 360 fms_reset_codec(void *addr) 361 { 362 struct fms_softc *sc = addr; 363 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020); 364 delay(2); 365 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000); 366 delay(1); 367 } 368 369 int 370 fms_intr(void *arg) 371 { 372 struct fms_softc *sc = arg; 373 u_int16_t istat; 374 375 mtx_enter(&audio_lock); 376 istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS); 377 378 if (istat & FM_INTSTATUS_PLAY) { 379 if ((sc->sc_play_nextblk += sc->sc_play_blksize) >= 380 sc->sc_play_end) 381 sc->sc_play_nextblk = sc->sc_play_start; 382 383 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 384 sc->sc_play_flip++ & 1 ? 385 FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk); 386 387 if (sc->sc_pintr) 388 sc->sc_pintr(sc->sc_parg); 389 else 390 printf("unexpected play intr\n"); 391 } 392 393 if (istat & FM_INTSTATUS_REC) { 394 if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >= 395 sc->sc_rec_end) 396 sc->sc_rec_nextblk = sc->sc_rec_start; 397 398 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 399 sc->sc_rec_flip++ & 1 ? 400 FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk); 401 402 if (sc->sc_rintr) 403 sc->sc_rintr(sc->sc_rarg); 404 else 405 printf("unexpected rec intr\n"); 406 } 407 408 #if 0 409 if (istat & FM_INTSTATUS_MPU) 410 mpu_intr(sc->sc_mpu_dev); 411 #endif 412 413 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS, 414 istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC)); 415 mtx_leave(&audio_lock); 416 return 1; 417 } 418 419 int 420 fms_open(void *addr, int flags) 421 { 422 /* UNUSED struct fms_softc *sc = addr;*/ 423 424 return 0; 425 } 426 427 void 428 fms_close(void *addr) 429 { 430 /* UNUSED struct fms_softc *sc = addr;*/ 431 } 432 433 int 434 fms_query_encoding(void *addr, struct audio_encoding *fp) 435 { 436 437 switch (fp->index) { 438 case 0: 439 strlcpy(fp->name, AudioEslinear_le, sizeof fp->name); 440 fp->encoding = AUDIO_ENCODING_SLINEAR_LE; 441 fp->precision = 16; 442 fp->flags = 0; 443 break; 444 case 1: 445 strlcpy(fp->name, AudioEulinear, sizeof fp->name); 446 fp->encoding = AUDIO_ENCODING_ULINEAR; 447 fp->precision = 8; 448 fp->flags = 0; 449 break; 450 default: 451 return EINVAL; 452 } 453 fp->bps = AUDIO_BPS(fp->precision); 454 fp->msb = 1; 455 456 return 0; 457 } 458 459 void 460 fms_get_default_params(void *addr, int mode, struct audio_params *params) 461 { 462 ac97_get_default_params(params); 463 } 464 465 /* 466 * Range below -limit- is set to -rate- 467 * What a pity FM801 does not have 24000 468 * 24000 -> 22050 sounds rather poor 469 */ 470 struct { 471 int limit; 472 int rate; 473 } fms_rates[11] = { 474 { 6600, 5500 }, 475 { 8750, 8000 }, 476 { 10250, 9600 }, 477 { 13200, 11025 }, 478 { 17500, 16000 }, 479 { 20500, 19200 }, 480 { 26500, 22050 }, 481 { 35000, 32000 }, 482 { 41000, 38400 }, 483 { 46000, 44100 }, 484 { 48000, 48000 }, 485 /* anything above -> 48000 */ 486 }; 487 488 int 489 fms_set_params(void *addr, int setmode, int usemode, struct audio_params *play, 490 struct audio_params *rec) 491 { 492 struct fms_softc *sc = addr; 493 int i; 494 495 if (setmode & AUMODE_PLAY) { 496 switch(play->encoding) { 497 case AUDIO_ENCODING_SLINEAR_LE: 498 if (play->precision != 16) 499 return EINVAL; 500 break; 501 case AUDIO_ENCODING_ULINEAR_LE: 502 case AUDIO_ENCODING_ULINEAR_BE: 503 if (play->precision != 8) 504 return EINVAL; 505 break; 506 default: 507 return EINVAL; 508 } 509 play->bps = AUDIO_BPS(play->precision); 510 play->msb = 1; 511 512 for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit; 513 i++) 514 ; 515 play->sample_rate = fms_rates[i].rate; 516 sc->sc_play_reg = (play->channels == 2 ? FM_PLAY_STEREO : 0) | 517 (play->precision == 16 ? FM_PLAY_16BIT : 0) | 518 (i << 8); 519 } 520 521 if (setmode & AUMODE_RECORD) { 522 523 switch(rec->encoding) { 524 case AUDIO_ENCODING_SLINEAR_LE: 525 if (rec->precision != 16) 526 return EINVAL; 527 break; 528 case AUDIO_ENCODING_ULINEAR_LE: 529 case AUDIO_ENCODING_ULINEAR_BE: 530 if (rec->precision != 8) 531 return EINVAL; 532 break; 533 default: 534 return EINVAL; 535 } 536 rec->bps = AUDIO_BPS(rec->precision); 537 rec->msb = 1; 538 539 for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit; 540 i++) 541 ; 542 rec->sample_rate = fms_rates[i].rate; 543 sc->sc_rec_reg = 544 (rec->channels == 2 ? FM_REC_STEREO : 0) | 545 (rec->precision == 16 ? FM_REC_16BIT : 0) | 546 (i << 8); 547 } 548 549 return 0; 550 } 551 552 int 553 fms_round_blocksize(void *addr, int blk) 554 { 555 return (blk + 0xf) & ~0xf; 556 } 557 558 int 559 fms_halt_output(void *addr) 560 { 561 struct fms_softc *sc = addr; 562 u_int16_t k1; 563 564 mtx_enter(&audio_lock); 565 k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL); 566 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL, 567 (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) | 568 FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST); 569 mtx_leave(&audio_lock); 570 return 0; 571 } 572 573 int 574 fms_halt_input(void *addr) 575 { 576 struct fms_softc *sc = addr; 577 u_int16_t k1; 578 579 mtx_enter(&audio_lock); 580 k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL); 581 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL, 582 (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) | 583 FM_REC_BUF1_LAST | FM_REC_BUF2_LAST); 584 mtx_leave(&audio_lock); 585 return 0; 586 } 587 588 int 589 fms_getdev(void *addr, struct audio_device *retp) 590 { 591 *retp = fms_device; 592 return 0; 593 } 594 595 int 596 fms_set_port(void *addr, mixer_ctrl_t *cp) 597 { 598 struct fms_softc *sc = addr; 599 600 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp)); 601 } 602 603 int 604 fms_get_port(void *addr, mixer_ctrl_t *cp) 605 { 606 struct fms_softc *sc = addr; 607 608 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp)); 609 } 610 611 void * 612 fms_malloc(void *addr, int direction, size_t size, int pool, int flags) 613 { 614 struct fms_softc *sc = addr; 615 struct fms_dma *p; 616 int error; 617 int rseg; 618 619 p = malloc(sizeof(*p), pool, flags); 620 if (!p) 621 return 0; 622 623 p->size = size; 624 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &p->seg, 1, 625 &rseg, BUS_DMA_NOWAIT)) != 0) { 626 printf("%s: unable to allocate dma, error = %d\n", 627 sc->sc_dev.dv_xname, error); 628 goto fail_alloc; 629 } 630 631 if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr, 632 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 633 printf("%s: unable to map dma, error = %d\n", 634 sc->sc_dev.dv_xname, error); 635 goto fail_map; 636 } 637 638 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 639 BUS_DMA_NOWAIT, &p->map)) != 0) { 640 printf("%s: unable to create dma map, error = %d\n", 641 sc->sc_dev.dv_xname, error); 642 goto fail_create; 643 } 644 645 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL, 646 BUS_DMA_NOWAIT)) != 0) { 647 printf("%s: unable to load dma map, error = %d\n", 648 sc->sc_dev.dv_xname, error); 649 goto fail_load; 650 } 651 652 p->next = sc->sc_dmas; 653 sc->sc_dmas = p; 654 655 return p->addr; 656 657 658 fail_load: 659 bus_dmamap_destroy(sc->sc_dmat, p->map); 660 fail_create: 661 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 662 fail_map: 663 bus_dmamem_free(sc->sc_dmat, &p->seg, 1); 664 fail_alloc: 665 free(p, pool, 0); 666 return 0; 667 } 668 669 void 670 fms_free(void *addr, void *ptr, int pool) 671 { 672 struct fms_softc *sc = addr; 673 struct fms_dma **pp, *p; 674 675 for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next) 676 if (p->addr == ptr) { 677 bus_dmamap_unload(sc->sc_dmat, p->map); 678 bus_dmamap_destroy(sc->sc_dmat, p->map); 679 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 680 bus_dmamem_free(sc->sc_dmat, &p->seg, 1); 681 682 *pp = p->next; 683 free(p, pool, 0); 684 return; 685 } 686 687 panic("fms_free: trying to free unallocated memory"); 688 } 689 690 paddr_t 691 fms_mappage(void *addr, void *mem, off_t off, int prot) 692 { 693 struct fms_softc *sc = addr; 694 struct fms_dma *p; 695 696 if (off < 0) 697 return -1; 698 699 for (p = sc->sc_dmas; p && p->addr != mem; p = p->next) 700 ; 701 if (!p) 702 return -1; 703 704 return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot, 705 BUS_DMA_WAITOK); 706 } 707 708 int 709 fms_get_props(void *addr) 710 { 711 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | 712 AUDIO_PROP_FULLDUPLEX; 713 } 714 715 int 716 fms_query_devinfo(void *addr, mixer_devinfo_t *dip) 717 { 718 struct fms_softc *sc = addr; 719 720 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip)); 721 } 722 723 int 724 fms_trigger_output(void *addr, void *start, void *end, int blksize, 725 void (*intr)(void *), void *arg, struct audio_params *param) 726 { 727 struct fms_softc *sc = addr; 728 struct fms_dma *p; 729 730 sc->sc_pintr = intr; 731 sc->sc_parg = arg; 732 733 for (p = sc->sc_dmas; p && p->addr != start; p = p->next) 734 ; 735 736 if (!p) 737 panic("fms_trigger_output: request with bad start " 738 "address (%p)", start); 739 740 sc->sc_play_start = p->map->dm_segs[0].ds_addr; 741 sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start); 742 sc->sc_play_blksize = blksize; 743 sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize; 744 sc->sc_play_flip = 0; 745 mtx_enter(&audio_lock); 746 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1); 747 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1, 748 sc->sc_play_start); 749 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2, 750 sc->sc_play_nextblk); 751 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL, 752 FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg); 753 mtx_leave(&audio_lock); 754 return 0; 755 } 756 757 758 int 759 fms_trigger_input(void *addr, void *start, void *end, int blksize, 760 void (*intr)(void *), void *arg, struct audio_params *param) 761 { 762 struct fms_softc *sc = addr; 763 struct fms_dma *p; 764 765 sc->sc_rintr = intr; 766 sc->sc_rarg = arg; 767 768 for (p = sc->sc_dmas; p && p->addr != start; p = p->next) 769 ; 770 771 if (!p) 772 panic("fms_trigger_input: request with bad start " 773 "address (%p)", start); 774 775 sc->sc_rec_start = p->map->dm_segs[0].ds_addr; 776 sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start); 777 sc->sc_rec_blksize = blksize; 778 sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize; 779 sc->sc_rec_flip = 0; 780 mtx_enter(&audio_lock); 781 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1); 782 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1, 783 sc->sc_rec_start); 784 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2, 785 sc->sc_rec_nextblk); 786 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL, 787 FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg); 788 mtx_leave(&audio_lock); 789 return 0; 790 } 791