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