1 /* $OpenBSD: fms.c,v 1.30 2016/12/20 15:31:00 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_set_params(void *, int, int, struct audio_params *, 79 struct audio_params *); 80 int fms_round_blocksize(void *, int); 81 int fms_halt_output(void *); 82 int fms_halt_input(void *); 83 int fms_set_port(void *, mixer_ctrl_t *); 84 int fms_get_port(void *, mixer_ctrl_t *); 85 int fms_query_devinfo(void *, mixer_devinfo_t *); 86 void *fms_malloc(void *, int, size_t, int, int); 87 void fms_free(void *, void *, int); 88 int fms_get_props(void *); 89 int fms_trigger_output(void *, void *, void *, int, void (*)(void *), 90 void *, struct audio_params *); 91 int fms_trigger_input(void *, void *, void *, int, void (*)(void *), 92 void *, struct audio_params *); 93 94 struct cfdriver fms_cd = { 95 NULL, "fms", DV_DULL 96 }; 97 98 struct cfattach fms_ca = { 99 sizeof (struct fms_softc), fms_match, fms_attach 100 }; 101 102 struct audio_hw_if fms_hw_if = { 103 fms_open, 104 fms_close, 105 fms_set_params, 106 fms_round_blocksize, 107 NULL, 108 NULL, 109 NULL, 110 NULL, 111 NULL, 112 fms_halt_output, 113 fms_halt_input, 114 NULL, 115 NULL, 116 fms_set_port, 117 fms_get_port, 118 fms_query_devinfo, 119 fms_malloc, 120 fms_free, 121 NULL, 122 fms_get_props, 123 fms_trigger_output, 124 fms_trigger_input 125 }; 126 127 int fms_attach_codec(void *, struct ac97_codec_if *); 128 int fms_read_codec(void *, u_int8_t, u_int16_t *); 129 int fms_write_codec(void *, u_int8_t, u_int16_t); 130 void fms_reset_codec(void *); 131 132 int fms_allocmem(struct fms_softc *, size_t, size_t, 133 struct fms_dma *); 134 int fms_freemem(struct fms_softc *, struct fms_dma *); 135 136 int 137 fms_match(struct device *parent, void *match, void *aux) 138 { 139 struct pci_attach_args *pa = (struct pci_attach_args *) aux; 140 141 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FORTEMEDIA && 142 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FORTEMEDIA_FM801) 143 return (1); 144 return (0); 145 } 146 147 void 148 fms_attach(struct device *parent, struct device *self, void *aux) 149 { 150 struct pci_attach_args *pa = aux; 151 struct fms_softc *sc = (struct fms_softc *) self; 152 struct audio_attach_args aa; 153 pci_chipset_tag_t pc = pa->pa_pc; 154 pcitag_t pt = pa->pa_tag; 155 pci_intr_handle_t ih; 156 bus_size_t iosize; 157 const char *intrstr; 158 u_int16_t k1; 159 int i; 160 161 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot, 162 &sc->sc_ioh, NULL, &iosize, 0)) { 163 printf(": can't map i/o space\n"); 164 return; 165 } 166 167 if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2, 168 &sc->sc_mpu_ioh)) { 169 printf(": can't get mpu subregion handle\n"); 170 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 171 return; 172 } 173 174 if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4, 175 &sc->sc_opl_ioh)) { 176 printf(": can't get opl subregion handle\n"); 177 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 178 return; 179 } 180 181 if (pci_intr_map(pa, &ih)) { 182 printf(": couldn't map interrupt\n"); 183 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 184 return; 185 } 186 intrstr = pci_intr_string(pc, ih); 187 188 sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE, 189 fms_intr, sc, sc->sc_dev.dv_xname); 190 if (sc->sc_ih == NULL) { 191 printf(": couldn't establish interrupt"); 192 if (intrstr != NULL) 193 printf(" at %s", intrstr); 194 printf("\n"); 195 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 196 return; 197 } 198 199 printf(": %s\n", intrstr); 200 201 sc->sc_dmat = pa->pa_dmat; 202 203 /* Disable legacy audio (SBPro compatibility) */ 204 pci_conf_write(pc, pt, 0x40, 0); 205 206 /* Reset codec and AC'97 */ 207 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020); 208 delay(2); /* > 1us according to AC'97 documentation */ 209 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000); 210 delay(1); /* > 168.2ns according to AC'97 documentation */ 211 212 /* Set up volume */ 213 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PCM_VOLUME, 0x0808); 214 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_FM_VOLUME, 0x0808); 215 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_I2S_VOLUME, 0x0808); 216 217 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_RECORD_SOURCE, 0x0000); 218 219 /* Unmask playback, record and mpu interrupts, mask the rest */ 220 k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK); 221 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK, 222 (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) | 223 FM_INTMASK_VOL); 224 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS, 225 FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU | 226 FM_INTSTATUS_VOL); 227 228 #if NRADIO > 0 229 fmsradio_attach(sc); 230 #endif /* NRADIO > 0 */ 231 232 sc->host_if.arg = sc; 233 sc->host_if.attach = fms_attach_codec; 234 sc->host_if.read = fms_read_codec; 235 sc->host_if.write = fms_write_codec; 236 sc->host_if.reset = fms_reset_codec; 237 238 if (ac97_attach(&sc->host_if) != 0) 239 return; 240 241 /* Turn mute off */ 242 for (i = 0; i < 3; i++) { 243 static struct { 244 char *class, *device; 245 } d[] = { 246 { AudioCoutputs, AudioNmaster }, 247 { AudioCinputs, AudioNdac }, 248 { AudioCrecord, AudioNvolume } 249 }; 250 struct mixer_ctrl ctl; 251 252 ctl.type = AUDIO_MIXER_ENUM; 253 ctl.un.ord = 0; 254 ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if, 255 d[i].class, d[i].device, AudioNmute); 256 fms_set_port(sc, &ctl); 257 } 258 259 audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev); 260 261 aa.type = AUDIODEV_TYPE_OPL; 262 aa.hwif = NULL; 263 aa.hdl = NULL; 264 config_found(&sc->sc_dev, &aa, audioprint); 265 266 aa.type = AUDIODEV_TYPE_MPU; 267 aa.hwif = NULL; 268 aa.hdl = NULL; 269 sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint); 270 } 271 272 /* 273 * Each AC-link frame takes 20.8us, data should be ready in next frame, 274 * we allow more than two. 275 */ 276 #define TIMO 50 277 int 278 fms_read_codec(void *addr, u_int8_t reg, u_int16_t *val) 279 { 280 struct fms_softc *sc = addr; 281 int i; 282 283 /* Poll until codec is ready */ 284 for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh, 285 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++) 286 delay(1); 287 if (i >= TIMO) { 288 printf("fms: codec busy\n"); 289 return 1; 290 } 291 292 /* Write register index, read access */ 293 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, 294 reg | FM_CODEC_CMD_READ); 295 296 /* Poll until we have valid data */ 297 for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh, 298 FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++) 299 delay(1); 300 if (i >= TIMO) { 301 printf("fms: no data from codec\n"); 302 return 1; 303 } 304 305 /* Read data */ 306 *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA); 307 return 0; 308 } 309 310 int 311 fms_write_codec(void *addr, u_int8_t reg, u_int16_t val) 312 { 313 struct fms_softc *sc = addr; 314 int i; 315 316 /* Poll until codec is ready */ 317 for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh, 318 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++) 319 delay(1); 320 if (i >= TIMO) { 321 printf("fms: codec busy\n"); 322 return 1; 323 } 324 325 /* Write data */ 326 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val); 327 /* Write index register, write access */ 328 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg); 329 return 0; 330 } 331 #undef TIMO 332 333 int 334 fms_attach_codec(void *addr, struct ac97_codec_if *cif) 335 { 336 struct fms_softc *sc = addr; 337 338 sc->codec_if = cif; 339 return 0; 340 } 341 342 /* Cold Reset */ 343 void 344 fms_reset_codec(void *addr) 345 { 346 struct fms_softc *sc = addr; 347 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020); 348 delay(2); 349 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000); 350 delay(1); 351 } 352 353 int 354 fms_intr(void *arg) 355 { 356 struct fms_softc *sc = arg; 357 u_int16_t istat; 358 359 mtx_enter(&audio_lock); 360 istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS); 361 362 if (istat & FM_INTSTATUS_PLAY) { 363 if ((sc->sc_play_nextblk += sc->sc_play_blksize) >= 364 sc->sc_play_end) 365 sc->sc_play_nextblk = sc->sc_play_start; 366 367 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 368 sc->sc_play_flip++ & 1 ? 369 FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk); 370 371 if (sc->sc_pintr) 372 sc->sc_pintr(sc->sc_parg); 373 else 374 printf("unexpected play intr\n"); 375 } 376 377 if (istat & FM_INTSTATUS_REC) { 378 if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >= 379 sc->sc_rec_end) 380 sc->sc_rec_nextblk = sc->sc_rec_start; 381 382 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 383 sc->sc_rec_flip++ & 1 ? 384 FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk); 385 386 if (sc->sc_rintr) 387 sc->sc_rintr(sc->sc_rarg); 388 else 389 printf("unexpected rec intr\n"); 390 } 391 392 #if 0 393 if (istat & FM_INTSTATUS_MPU) 394 mpu_intr(sc->sc_mpu_dev); 395 #endif 396 397 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS, 398 istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC)); 399 mtx_leave(&audio_lock); 400 return 1; 401 } 402 403 int 404 fms_open(void *addr, int flags) 405 { 406 /* UNUSED struct fms_softc *sc = addr;*/ 407 408 return 0; 409 } 410 411 void 412 fms_close(void *addr) 413 { 414 /* UNUSED struct fms_softc *sc = addr;*/ 415 } 416 417 /* 418 * Range below -limit- is set to -rate- 419 * What a pity FM801 does not have 24000 420 * 24000 -> 22050 sounds rather poor 421 */ 422 struct { 423 int limit; 424 int rate; 425 } fms_rates[11] = { 426 { 6600, 5500 }, 427 { 8750, 8000 }, 428 { 10250, 9600 }, 429 { 13200, 11025 }, 430 { 17500, 16000 }, 431 { 20500, 19200 }, 432 { 26500, 22050 }, 433 { 35000, 32000 }, 434 { 41000, 38400 }, 435 { 46000, 44100 }, 436 { 48000, 48000 }, 437 /* anything above -> 48000 */ 438 }; 439 440 int 441 fms_set_params(void *addr, int setmode, int usemode, struct audio_params *play, 442 struct audio_params *rec) 443 { 444 struct fms_softc *sc = addr; 445 int i; 446 447 if (setmode & AUMODE_PLAY) { 448 switch(play->encoding) { 449 case AUDIO_ENCODING_SLINEAR_LE: 450 if (play->precision != 16) 451 return EINVAL; 452 break; 453 case AUDIO_ENCODING_ULINEAR_LE: 454 case AUDIO_ENCODING_ULINEAR_BE: 455 if (play->precision != 8) 456 return EINVAL; 457 break; 458 default: 459 return EINVAL; 460 } 461 play->bps = AUDIO_BPS(play->precision); 462 play->msb = 1; 463 464 for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit; 465 i++) 466 ; 467 play->sample_rate = fms_rates[i].rate; 468 sc->sc_play_reg = (play->channels == 2 ? FM_PLAY_STEREO : 0) | 469 (play->precision == 16 ? FM_PLAY_16BIT : 0) | 470 (i << 8); 471 } 472 473 if (setmode & AUMODE_RECORD) { 474 475 switch(rec->encoding) { 476 case AUDIO_ENCODING_SLINEAR_LE: 477 if (rec->precision != 16) 478 return EINVAL; 479 break; 480 case AUDIO_ENCODING_ULINEAR_LE: 481 case AUDIO_ENCODING_ULINEAR_BE: 482 if (rec->precision != 8) 483 return EINVAL; 484 break; 485 default: 486 return EINVAL; 487 } 488 rec->bps = AUDIO_BPS(rec->precision); 489 rec->msb = 1; 490 491 for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit; 492 i++) 493 ; 494 rec->sample_rate = fms_rates[i].rate; 495 sc->sc_rec_reg = 496 (rec->channels == 2 ? FM_REC_STEREO : 0) | 497 (rec->precision == 16 ? FM_REC_16BIT : 0) | 498 (i << 8); 499 } 500 501 return 0; 502 } 503 504 int 505 fms_round_blocksize(void *addr, int blk) 506 { 507 return (blk + 0xf) & ~0xf; 508 } 509 510 int 511 fms_halt_output(void *addr) 512 { 513 struct fms_softc *sc = addr; 514 u_int16_t k1; 515 516 mtx_enter(&audio_lock); 517 k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL); 518 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL, 519 (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) | 520 FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST); 521 mtx_leave(&audio_lock); 522 return 0; 523 } 524 525 int 526 fms_halt_input(void *addr) 527 { 528 struct fms_softc *sc = addr; 529 u_int16_t k1; 530 531 mtx_enter(&audio_lock); 532 k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL); 533 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL, 534 (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) | 535 FM_REC_BUF1_LAST | FM_REC_BUF2_LAST); 536 mtx_leave(&audio_lock); 537 return 0; 538 } 539 540 int 541 fms_set_port(void *addr, mixer_ctrl_t *cp) 542 { 543 struct fms_softc *sc = addr; 544 545 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp)); 546 } 547 548 int 549 fms_get_port(void *addr, mixer_ctrl_t *cp) 550 { 551 struct fms_softc *sc = addr; 552 553 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp)); 554 } 555 556 void * 557 fms_malloc(void *addr, int direction, size_t size, int pool, int flags) 558 { 559 struct fms_softc *sc = addr; 560 struct fms_dma *p; 561 int error; 562 int rseg; 563 564 p = malloc(sizeof(*p), pool, flags); 565 if (!p) 566 return 0; 567 568 p->size = size; 569 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &p->seg, 1, 570 &rseg, BUS_DMA_NOWAIT)) != 0) { 571 printf("%s: unable to allocate dma, error = %d\n", 572 sc->sc_dev.dv_xname, error); 573 goto fail_alloc; 574 } 575 576 if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr, 577 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 578 printf("%s: unable to map dma, error = %d\n", 579 sc->sc_dev.dv_xname, error); 580 goto fail_map; 581 } 582 583 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 584 BUS_DMA_NOWAIT, &p->map)) != 0) { 585 printf("%s: unable to create dma map, error = %d\n", 586 sc->sc_dev.dv_xname, error); 587 goto fail_create; 588 } 589 590 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL, 591 BUS_DMA_NOWAIT)) != 0) { 592 printf("%s: unable to load dma map, error = %d\n", 593 sc->sc_dev.dv_xname, error); 594 goto fail_load; 595 } 596 597 p->next = sc->sc_dmas; 598 sc->sc_dmas = p; 599 600 return p->addr; 601 602 603 fail_load: 604 bus_dmamap_destroy(sc->sc_dmat, p->map); 605 fail_create: 606 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 607 fail_map: 608 bus_dmamem_free(sc->sc_dmat, &p->seg, 1); 609 fail_alloc: 610 free(p, pool, sizeof(*p)); 611 return 0; 612 } 613 614 void 615 fms_free(void *addr, void *ptr, int pool) 616 { 617 struct fms_softc *sc = addr; 618 struct fms_dma **pp, *p; 619 620 for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next) 621 if (p->addr == ptr) { 622 bus_dmamap_unload(sc->sc_dmat, p->map); 623 bus_dmamap_destroy(sc->sc_dmat, p->map); 624 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 625 bus_dmamem_free(sc->sc_dmat, &p->seg, 1); 626 627 *pp = p->next; 628 free(p, pool, sizeof(*p)); 629 return; 630 } 631 632 panic("fms_free: trying to free unallocated memory"); 633 } 634 635 int 636 fms_get_props(void *addr) 637 { 638 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | 639 AUDIO_PROP_FULLDUPLEX; 640 } 641 642 int 643 fms_query_devinfo(void *addr, mixer_devinfo_t *dip) 644 { 645 struct fms_softc *sc = addr; 646 647 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip)); 648 } 649 650 int 651 fms_trigger_output(void *addr, void *start, void *end, int blksize, 652 void (*intr)(void *), void *arg, struct audio_params *param) 653 { 654 struct fms_softc *sc = addr; 655 struct fms_dma *p; 656 657 sc->sc_pintr = intr; 658 sc->sc_parg = arg; 659 660 for (p = sc->sc_dmas; p && p->addr != start; p = p->next) 661 ; 662 663 if (!p) 664 panic("fms_trigger_output: request with bad start " 665 "address (%p)", start); 666 667 sc->sc_play_start = p->map->dm_segs[0].ds_addr; 668 sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start); 669 sc->sc_play_blksize = blksize; 670 sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize; 671 sc->sc_play_flip = 0; 672 mtx_enter(&audio_lock); 673 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1); 674 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1, 675 sc->sc_play_start); 676 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2, 677 sc->sc_play_nextblk); 678 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL, 679 FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg); 680 mtx_leave(&audio_lock); 681 return 0; 682 } 683 684 685 int 686 fms_trigger_input(void *addr, void *start, void *end, int blksize, 687 void (*intr)(void *), void *arg, struct audio_params *param) 688 { 689 struct fms_softc *sc = addr; 690 struct fms_dma *p; 691 692 sc->sc_rintr = intr; 693 sc->sc_rarg = arg; 694 695 for (p = sc->sc_dmas; p && p->addr != start; p = p->next) 696 ; 697 698 if (!p) 699 panic("fms_trigger_input: request with bad start " 700 "address (%p)", start); 701 702 sc->sc_rec_start = p->map->dm_segs[0].ds_addr; 703 sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start); 704 sc->sc_rec_blksize = blksize; 705 sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize; 706 sc->sc_rec_flip = 0; 707 mtx_enter(&audio_lock); 708 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1); 709 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1, 710 sc->sc_rec_start); 711 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2, 712 sc->sc_rec_nextblk); 713 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL, 714 FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg); 715 mtx_leave(&audio_lock); 716 return 0; 717 } 718