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