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