1 /* $OpenBSD: auvia.c,v 1.9 2001/06/12 15:40:30 niklas Exp $ */ 2 /* $NetBSD: auvia.c,v 1.7 2000/11/15 21:06:33 jdolecek Exp $ */ 3 4 /*- 5 * Copyright (c) 2000 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Tyler C. Sarna 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 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * VIA Technologies VT82C686A Southbridge Audio Driver 42 * 43 * Documentation links: 44 * 45 * ftp://ftp.alsa-project.org/pub/manuals/via/686a.pdf 46 * ftp://ftp.alsa-project.org/pub/manuals/general/ac97r21.pdf 47 * ftp://ftp.alsa-project.org/pub/manuals/ad/AD1881_0.pdf (example AC'97 codec) 48 */ 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/malloc.h> 53 #include <sys/device.h> 54 #include <sys/audioio.h> 55 56 #include <vm/vm.h> 57 58 #include <dev/pci/pcidevs.h> 59 #include <dev/pci/pcivar.h> 60 61 #include <dev/audio_if.h> 62 #include <dev/mulaw.h> 63 #include <dev/auconv.h> 64 65 #include <dev/ic/ac97.h> 66 67 #include <dev/pci/auviavar.h> 68 69 struct auvia_dma { 70 struct auvia_dma *next; 71 caddr_t addr; 72 size_t size; 73 bus_dmamap_t map; 74 bus_dma_segment_t seg; 75 }; 76 77 struct auvia_dma_op { 78 u_int32_t ptr; 79 u_int32_t flags; 80 #define AUVIA_DMAOP_EOL 0x80000000 81 #define AUVIA_DMAOP_FLAG 0x40000000 82 #define AUVIA_DMAOP_STOP 0x20000000 83 #define AUVIA_DMAOP_COUNT(x) ((x)&0x00FFFFFF) 84 }; 85 86 /* rev. H and later seem to support only fixed rate 44.1 kHz */ 87 #define AUVIA_FIXED_RATE 44100 88 89 int auvia_match(struct device *, void *, void *); 90 void auvia_attach(struct device *, struct device *, void *); 91 int auvia_open(void *, int); 92 void auvia_close(void *); 93 int auvia_query_encoding(void *addr, struct audio_encoding *fp); 94 int auvia_set_params(void *, int, int, struct audio_params *, 95 struct audio_params *); 96 int auvia_round_blocksize(void *, int); 97 int auvia_halt_output(void *); 98 int auvia_halt_input(void *); 99 int auvia_getdev(void *, struct audio_device *); 100 int auvia_set_port(void *, mixer_ctrl_t *); 101 int auvia_get_port(void *, mixer_ctrl_t *); 102 int auvia_query_devinfo(void *, mixer_devinfo_t *); 103 void * auvia_malloc(void *, int, size_t, int, int); 104 void auvia_free(void *, void *, int); 105 size_t auvia_round_buffersize(void *, int, size_t); 106 int auvia_mappage(void *, void *, int, int); 107 int auvia_get_props(void *); 108 int auvia_build_dma_ops(struct auvia_softc *, struct auvia_softc_chan *, 109 struct auvia_dma *, void *, void *, int); 110 int auvia_trigger_output(void *, void *, void *, int, void (*)(void *), 111 void *, struct audio_params *); 112 int auvia_trigger_input(void *, void *, void *, int, void (*)(void *), 113 void *, struct audio_params *); 114 115 int auvia_intr __P((void *)); 116 117 struct cfdriver auvia_cd = { 118 NULL, "auvia", DV_DULL 119 }; 120 121 struct cfattach auvia_ca = { 122 sizeof (struct auvia_softc), auvia_match, auvia_attach 123 }; 124 125 #define AUVIA_PCICONF_JUNK 0x40 126 #define AUVIA_PCICONF_ENABLES 0x00FF0000 /* reg 42 mask */ 127 #define AUVIA_PCICONF_ACLINKENAB 0x00008000 /* ac link enab */ 128 #define AUVIA_PCICONF_ACNOTRST 0x00004000 /* ~(ac reset) */ 129 #define AUVIA_PCICONF_ACSYNC 0x00002000 /* ac sync */ 130 #define AUVIA_PCICONF_ACVSR 0x00000800 /* var. samp. rate */ 131 #define AUVIA_PCICONF_ACSGD 0x00000400 /* SGD enab */ 132 #define AUVIA_PCICONF_ACFM 0x00000200 /* FM enab */ 133 #define AUVIA_PCICONF_ACSB 0x00000100 /* SB enab */ 134 135 #define AUVIA_PLAY_STAT 0x00 136 #define AUVIA_RECORD_STAT 0x10 137 #define AUVIA_RPSTAT_INTR 0x03 138 #define AUVIA_PLAY_CONTROL 0x01 139 #define AUVIA_RECORD_CONTROL 0x11 140 #define AUVIA_RPCTRL_START 0x80 141 #define AUVIA_RPCTRL_TERMINATE 0x40 142 #define AUVIA_PLAY_MODE 0x02 143 #define AUVIA_RECORD_MODE 0x12 144 #define AUVIA_RPMODE_INTR_FLAG 0x01 145 #define AUVIA_RPMODE_INTR_EOL 0x02 146 #define AUVIA_RPMODE_STEREO 0x10 147 #define AUVIA_RPMODE_16BIT 0x20 148 #define AUVIA_RPMODE_AUTOSTART 0x80 149 #define AUVIA_PLAY_DMAOPS_BASE 0x04 150 #define AUVIA_RECORD_DMAOPS_BASE 0x14 151 152 #define AUVIA_CODEC_CTL 0x80 153 #define AUVIA_CODEC_READ 0x00800000 154 #define AUVIA_CODEC_BUSY 0x01000000 155 #define AUVIA_CODEC_PRIVALID 0x02000000 156 #define AUVIA_CODEC_INDEX(x) ((x)<<16) 157 158 #define TIMEOUT 50 159 160 struct audio_hw_if auvia_hw_if = { 161 auvia_open, 162 auvia_close, 163 NULL, /* drain */ 164 auvia_query_encoding, 165 auvia_set_params, 166 auvia_round_blocksize, 167 NULL, /* commit_settings */ 168 NULL, /* init_output */ 169 NULL, /* init_input */ 170 NULL, /* start_output */ 171 NULL, /* start_input */ 172 auvia_halt_output, 173 auvia_halt_input, 174 NULL, /* speaker_ctl */ 175 auvia_getdev, 176 NULL, /* setfd */ 177 auvia_set_port, 178 auvia_get_port, 179 auvia_query_devinfo, 180 NULL, 181 auvia_free, 182 NULL, 183 auvia_mappage, 184 auvia_get_props, 185 auvia_trigger_output, 186 auvia_trigger_input, 187 auvia_malloc, 188 auvia_round_buffersize, 189 }; 190 191 int auvia_attach_codec(void *, struct ac97_codec_if *); 192 int auvia_write_codec(void *, u_int8_t, u_int16_t); 193 int auvia_read_codec(void *, u_int8_t, u_int16_t *); 194 void auvia_reset_codec(void *); 195 int auvia_waitready_codec(struct auvia_softc *sc); 196 int auvia_waitvalid_codec(struct auvia_softc *sc); 197 198 199 int 200 auvia_match(struct device *parent, void *match, void *aux) 201 { 202 struct pci_attach_args *pa = (struct pci_attach_args *) aux; 203 204 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH) 205 return 0; 206 if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_VT82C686A_AC97) 207 return 0; 208 209 return 1; 210 } 211 212 213 void 214 auvia_attach(struct device *parent, struct device *self, void *aux) 215 { 216 struct pci_attach_args *pa = aux; 217 struct auvia_softc *sc = (struct auvia_softc *) self; 218 const char *intrstr = NULL; 219 struct mixer_ctrl ctl; 220 pci_chipset_tag_t pc = pa->pa_pc; 221 pcitag_t pt = pa->pa_tag; 222 pci_intr_handle_t ih; 223 pcireg_t pr; 224 u_int16_t v; 225 int r, i; 226 227 if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, pa->pa_intrline, 228 &ih)) { 229 printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); 230 return; 231 } 232 intrstr = pci_intr_string(pc, ih); 233 234 sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auvia_intr, sc, 235 sc->sc_dev.dv_xname); 236 if (sc->sc_ih == NULL) { 237 printf(": couldn't establish interrupt"); 238 if (intrstr != NULL) 239 printf(" at %s", intrstr); 240 printf("\n"); 241 return; 242 } 243 244 sc->sc_dmat = pa->pa_dmat; 245 sc->sc_pc = pc; 246 sc->sc_pt = pt; 247 248 printf(": %s\n", intrstr); 249 250 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot, 251 &sc->sc_ioh, &sc->sc_ioaddr, &sc->sc_iosize, 0)) { 252 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); 253 return; 254 } 255 256 /* disable SBPro compat & others */ 257 pr = pci_conf_read(pc, pt, AUVIA_PCICONF_JUNK); 258 259 pr &= ~AUVIA_PCICONF_ENABLES; /* clear compat function enables */ 260 /* XXX what to do about MIDI, FM, joystick? */ 261 262 pr |= (AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST 263 | AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD); 264 265 pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB); 266 267 pci_conf_write(pc, pt, AUVIA_PCICONF_JUNK, pr); 268 269 sc->host_if.arg = sc; 270 sc->host_if.attach = auvia_attach_codec; 271 sc->host_if.read = auvia_read_codec; 272 sc->host_if.write = auvia_write_codec; 273 sc->host_if.reset = auvia_reset_codec; 274 275 if ((r = ac97_attach(&sc->host_if)) != 0) { 276 printf("%s: can't attach codec (error 0x%X)\n", 277 sc->sc_dev.dv_xname, r); 278 return; 279 } 280 281 /* 282 * Print a warning if the codec doesn't support hardware variable 283 * rate audio. 284 */ 285 if (auvia_read_codec(sc, AC97_REG_EXT_AUDIO_ID, &v) 286 || !(v & AC97_EXT_AUDIO_VRA)) { 287 printf("%s: warning: codec doesn't support hardware AC'97 2.0 Variable Rate Audio\n", 288 sc->sc_dev.dv_xname); 289 sc->sc_fixed_rate = AUVIA_FIXED_RATE; 290 } else { 291 /* enable VRA */ 292 auvia_write_codec(sc, AC97_REG_EXT_AUDIO_CTRL, 293 AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM); 294 sc->sc_fixed_rate = 0; 295 } 296 297 /* disable mutes */ 298 for (i = 0; i < 4; i++) { 299 static struct { 300 char *class, *device; 301 } d[] = { 302 { AudioCoutputs, AudioNmaster}, 303 { AudioCinputs, AudioNdac}, 304 { AudioCinputs, AudioNcd}, 305 { AudioCrecord, AudioNvolume}, 306 }; 307 308 ctl.type = AUDIO_MIXER_ENUM; 309 ctl.un.ord = 0; 310 311 ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if, 312 d[i].class, d[i].device, AudioNmute); 313 auvia_set_port(sc, &ctl); 314 } 315 316 /* set a reasonable default volume */ 317 318 ctl.type = AUDIO_MIXER_VALUE; 319 ctl.un.value.num_channels = 2; 320 ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \ 321 ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 199; 322 323 ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if, 324 AudioCoutputs, AudioNmaster, NULL); 325 auvia_set_port(sc, &ctl); 326 327 audio_attach_mi(&auvia_hw_if, sc, &sc->sc_dev); 328 } 329 330 331 int 332 auvia_attach_codec(void *addr, struct ac97_codec_if *cif) 333 { 334 struct auvia_softc *sc = addr; 335 336 sc->codec_if = cif; 337 338 return 0; 339 } 340 341 342 void 343 auvia_reset_codec(void *addr) 344 { 345 #ifdef notyet /* XXX seems to make codec become unready... ??? */ 346 struct auvia_softc *sc = addr; 347 pcireg_t r; 348 349 /* perform a codec cold reset */ 350 351 r = pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK); 352 353 r &= ~AUVIA_PCICONF_ACNOTRST; /* enable RESET (active low) */ 354 pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r); 355 delay(2); 356 357 r |= AUVIA_PCICONF_ACNOTRST; /* disable RESET (inactive high) */ 358 pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r); 359 delay(200); 360 361 auvia_waitready_codec(sc); 362 #endif 363 } 364 365 366 int 367 auvia_waitready_codec(struct auvia_softc *sc) 368 { 369 int i; 370 371 /* poll until codec not busy */ 372 for (i = 0; (i < TIMEOUT) && (bus_space_read_4(sc->sc_iot, sc->sc_ioh, 373 AUVIA_CODEC_CTL) & AUVIA_CODEC_BUSY); i++) 374 delay(1); 375 if (i >= TIMEOUT) { 376 printf("%s: codec busy\n", sc->sc_dev.dv_xname); 377 return 1; 378 } 379 380 return 0; 381 } 382 383 384 int 385 auvia_waitvalid_codec(struct auvia_softc *sc) 386 { 387 int i; 388 389 /* poll until codec valid */ 390 for (i = 0; (i < TIMEOUT) && !(bus_space_read_4(sc->sc_iot, sc->sc_ioh, 391 AUVIA_CODEC_CTL) & AUVIA_CODEC_PRIVALID); i++) 392 delay(1); 393 if (i >= TIMEOUT) { 394 printf("%s: codec invalid\n", sc->sc_dev.dv_xname); 395 return 1; 396 } 397 398 return 0; 399 } 400 401 402 int 403 auvia_write_codec(void *addr, u_int8_t reg, u_int16_t val) 404 { 405 struct auvia_softc *sc = addr; 406 407 if (auvia_waitready_codec(sc)) 408 return 1; 409 410 bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL, 411 AUVIA_CODEC_PRIVALID | AUVIA_CODEC_INDEX(reg) | val); 412 413 return 0; 414 } 415 416 417 int 418 auvia_read_codec(void *addr, u_int8_t reg, u_int16_t *val) 419 { 420 struct auvia_softc *sc = addr; 421 422 if (auvia_waitready_codec(sc)) 423 return 1; 424 425 bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL, 426 AUVIA_CODEC_PRIVALID | AUVIA_CODEC_READ | AUVIA_CODEC_INDEX(reg)); 427 428 if (auvia_waitready_codec(sc)) 429 return 1; 430 431 if (auvia_waitvalid_codec(sc)) 432 return 1; 433 434 *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL); 435 436 return 0; 437 } 438 439 440 int 441 auvia_open(void *addr, int flags) 442 { 443 return 0; 444 } 445 446 447 void 448 auvia_close(void *addr) 449 { 450 struct auvia_softc *sc = addr; 451 452 auvia_halt_output(sc); 453 auvia_halt_input(sc); 454 455 sc->sc_play.sc_intr = NULL; 456 sc->sc_record.sc_intr = NULL; 457 } 458 459 460 int 461 auvia_query_encoding(void *addr, struct audio_encoding *fp) 462 { 463 switch (fp->index) { 464 case 0: 465 strcpy(fp->name, AudioEulinear); 466 fp->encoding = AUDIO_ENCODING_ULINEAR; 467 fp->precision = 8; 468 fp->flags = 0; 469 return (0); 470 case 1: 471 strcpy(fp->name, AudioEmulaw); 472 fp->encoding = AUDIO_ENCODING_ULAW; 473 fp->precision = 8; 474 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 475 return (0); 476 case 2: 477 strcpy(fp->name, AudioEalaw); 478 fp->encoding = AUDIO_ENCODING_ALAW; 479 fp->precision = 8; 480 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 481 return (0); 482 case 3: 483 strcpy(fp->name, AudioEslinear); 484 fp->encoding = AUDIO_ENCODING_SLINEAR; 485 fp->precision = 8; 486 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 487 return (0); 488 case 4: 489 strcpy(fp->name, AudioEslinear_le); 490 fp->encoding = AUDIO_ENCODING_SLINEAR_LE; 491 fp->precision = 16; 492 fp->flags = 0; 493 return (0); 494 case 5: 495 strcpy(fp->name, AudioEulinear_le); 496 fp->encoding = AUDIO_ENCODING_ULINEAR_LE; 497 fp->precision = 16; 498 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 499 return (0); 500 case 6: 501 strcpy(fp->name, AudioEslinear_be); 502 fp->encoding = AUDIO_ENCODING_SLINEAR_BE; 503 fp->precision = 16; 504 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 505 return (0); 506 case 7: 507 strcpy(fp->name, AudioEulinear_be); 508 fp->encoding = AUDIO_ENCODING_ULINEAR_BE; 509 fp->precision = 16; 510 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 511 return (0); 512 default: 513 return (EINVAL); 514 } 515 } 516 517 518 int 519 auvia_set_params(void *addr, int setmode, int usemode, 520 struct audio_params *play, struct audio_params *rec) 521 { 522 struct auvia_softc *sc = addr; 523 struct audio_params *p; 524 u_int16_t regval; 525 int reg, mode; 526 527 /* for mode in (RECORD, PLAY) */ 528 for (mode = AUMODE_RECORD; mode != -1; 529 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 530 if ((setmode & mode) == 0) 531 continue; 532 533 p = mode == AUMODE_PLAY ? play : rec; 534 535 if (p->sample_rate < 4000 || p->sample_rate > 48000 || 536 (p->precision != 8 && p->precision != 16) || 537 (p->channels != 1 && p->channels != 2)) 538 return (EINVAL); 539 540 reg = mode == AUMODE_PLAY ? 541 AC97_REG_FRONT_DAC_RATE : AC97_REG_PCM_ADC_RATE; 542 543 if (!sc->sc_fixed_rate) { 544 auvia_write_codec(sc, reg, (u_int16_t) p->sample_rate); 545 auvia_read_codec(sc, reg, ®val); 546 p->sample_rate = regval; 547 } else 548 p->sample_rate = sc->sc_fixed_rate; 549 550 p->factor = 1; 551 p->sw_code = 0; 552 switch (p->encoding) { 553 case AUDIO_ENCODING_SLINEAR_BE: 554 if (p->precision == 16) 555 p->sw_code = swap_bytes; 556 else 557 p->sw_code = change_sign8; 558 break; 559 case AUDIO_ENCODING_SLINEAR_LE: 560 if (p->precision != 16) 561 p->sw_code = change_sign8; 562 break; 563 case AUDIO_ENCODING_ULINEAR_BE: 564 if (p->precision == 16) { 565 if (mode == AUMODE_PLAY) 566 p->sw_code = swap_bytes_change_sign16_le; 567 else 568 p->sw_code = change_sign16_swap_bytes_le; 569 } 570 break; 571 case AUDIO_ENCODING_ULINEAR_LE: 572 if (p->precision == 16) 573 p->sw_code = change_sign16_le; 574 break; 575 case AUDIO_ENCODING_ULAW: 576 if (mode == AUMODE_PLAY) { 577 p->factor = 2; 578 p->sw_code = mulaw_to_slinear16_le; 579 } else 580 p->sw_code = ulinear8_to_mulaw; 581 break; 582 case AUDIO_ENCODING_ALAW: 583 if (mode == AUMODE_PLAY) { 584 p->factor = 2; 585 p->sw_code = alaw_to_slinear16_le; 586 } else 587 p->sw_code = ulinear8_to_alaw; 588 break; 589 default: 590 return (EINVAL); 591 } 592 593 regval = (p->channels == 2 ? AUVIA_RPMODE_STEREO : 0) 594 | (p->precision * p->factor == 16 ? 595 AUVIA_RPMODE_16BIT : 0) 596 | AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL 597 | AUVIA_RPMODE_AUTOSTART; 598 599 if (mode == AUMODE_PLAY) { 600 sc->sc_play.sc_reg = regval; 601 } else { 602 sc->sc_record.sc_reg = regval; 603 } 604 } 605 606 return 0; 607 } 608 609 610 int 611 auvia_round_blocksize(void *addr, int blk) 612 { 613 return (blk & -32); 614 } 615 616 617 int 618 auvia_halt_output(void *addr) 619 { 620 struct auvia_softc *sc = addr; 621 622 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_CONTROL, 623 AUVIA_RPCTRL_TERMINATE); 624 625 return 0; 626 } 627 628 629 int 630 auvia_halt_input(void *addr) 631 { 632 struct auvia_softc *sc = addr; 633 634 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_CONTROL, 635 AUVIA_RPCTRL_TERMINATE); 636 637 return 0; 638 } 639 640 641 int 642 auvia_getdev(void *addr, struct audio_device *retp) 643 { 644 struct auvia_softc *sc = addr; 645 646 if (retp) { 647 strncpy(retp->name, "VIA VT82C686A", sizeof(retp->name)); 648 strncpy(retp->version, sc->sc_revision, sizeof(retp->version)); 649 strncpy(retp->config, "auvia", sizeof(retp->config)); 650 } 651 652 return 0; 653 } 654 655 656 int 657 auvia_set_port(void *addr, mixer_ctrl_t *cp) 658 { 659 struct auvia_softc *sc = addr; 660 661 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp)); 662 } 663 664 665 int 666 auvia_get_port(void *addr, mixer_ctrl_t *cp) 667 { 668 struct auvia_softc *sc = addr; 669 670 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp)); 671 } 672 673 674 int 675 auvia_query_devinfo(void *addr, mixer_devinfo_t *dip) 676 { 677 struct auvia_softc *sc = addr; 678 679 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip)); 680 } 681 682 683 void * 684 auvia_malloc(void *addr, int direction, size_t size, int pool, int flags) 685 { 686 struct auvia_softc *sc = addr; 687 struct auvia_dma *p; 688 int error; 689 int rseg; 690 691 p = malloc(sizeof(*p), pool, flags); 692 if (!p) 693 return 0; 694 695 p->size = size; 696 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg, 697 1, &rseg, BUS_DMA_NOWAIT)) != 0) { 698 printf("%s: unable to allocate dma, error = %d\n", 699 sc->sc_dev.dv_xname, error); 700 goto fail_alloc; 701 } 702 703 if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr, 704 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 705 printf("%s: unable to map dma, error = %d\n", 706 sc->sc_dev.dv_xname, error); 707 goto fail_map; 708 } 709 710 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 711 BUS_DMA_NOWAIT, &p->map)) != 0) { 712 printf("%s: unable to create dma map, error = %d\n", 713 sc->sc_dev.dv_xname, error); 714 goto fail_create; 715 } 716 717 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL, 718 BUS_DMA_NOWAIT)) != 0) { 719 printf("%s: unable to load dma map, error = %d\n", 720 sc->sc_dev.dv_xname, error); 721 goto fail_load; 722 } 723 724 p->next = sc->sc_dmas; 725 sc->sc_dmas = p; 726 727 return p->addr; 728 729 730 fail_load: 731 bus_dmamap_destroy(sc->sc_dmat, p->map); 732 fail_create: 733 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 734 fail_map: 735 bus_dmamem_free(sc->sc_dmat, &p->seg, 1); 736 fail_alloc: 737 free(p, pool); 738 return 0; 739 } 740 741 742 void 743 auvia_free(void *addr, void *ptr, int pool) 744 { 745 struct auvia_softc *sc = addr; 746 struct auvia_dma **pp, *p; 747 748 for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next) 749 if (p->addr == ptr) { 750 bus_dmamap_unload(sc->sc_dmat, p->map); 751 bus_dmamap_destroy(sc->sc_dmat, p->map); 752 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 753 bus_dmamem_free(sc->sc_dmat, &p->seg, 1); 754 755 *pp = p->next; 756 free(p, pool); 757 return; 758 } 759 760 panic("auvia_free: trying to free unallocated memory"); 761 } 762 763 764 size_t 765 auvia_round_buffersize(void *addr, int direction, size_t size) 766 { 767 return size; 768 } 769 770 771 int 772 auvia_mappage(void *addr, void *mem, int off, int prot) 773 { 774 struct auvia_softc *sc = addr; 775 struct auvia_dma *p; 776 777 if (off < 0) 778 return -1; 779 780 for (p = sc->sc_dmas; p && p->addr != mem; p = p->next) 781 ; 782 783 if (!p) 784 return -1; 785 786 return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot, 787 BUS_DMA_WAITOK); 788 } 789 790 791 int 792 auvia_get_props(void *addr) 793 { 794 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT 795 | AUDIO_PROP_FULLDUPLEX; 796 } 797 798 799 int 800 auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch, 801 struct auvia_dma *p, void *start, void *end, int blksize) 802 { 803 struct auvia_dma_op *op; 804 struct auvia_dma *dp; 805 bus_addr_t s, e; 806 size_t l; 807 int segs; 808 809 s = p->map->dm_segs[0].ds_addr; 810 l = ((char *)end - (char *)start); 811 e = s + l; 812 segs = (l + blksize - 1) / blksize; 813 814 if (segs > (ch->sc_dma_op_count)) { 815 /* if old list was too small, free it */ 816 if (ch->sc_dma_ops) { 817 auvia_free(sc, ch->sc_dma_ops, M_DEVBUF); 818 } 819 820 ch->sc_dma_ops = auvia_malloc(sc, 0, 821 sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK); 822 823 for (dp = sc->sc_dmas; 824 dp && dp->addr != (void *)(ch->sc_dma_ops); 825 dp = dp->next) 826 ; 827 828 if (!dp) 829 panic("%s: build_dma_ops: where'd my memory go??? " 830 "address (%p)\n", sc->sc_dev.dv_xname, 831 ch->sc_dma_ops); 832 833 ch->sc_dma_op_count = segs; 834 ch->sc_dma_ops_dma = dp; 835 } 836 837 dp = ch->sc_dma_ops_dma; 838 op = ch->sc_dma_ops; 839 840 while (l) { 841 op->ptr = s; 842 l = l - blksize; 843 if (!l) { 844 /* if last block */ 845 op->flags = AUVIA_DMAOP_EOL | blksize; 846 } else { 847 op->flags = AUVIA_DMAOP_FLAG | blksize; 848 } 849 s += blksize; 850 op++; 851 } 852 853 return 0; 854 } 855 856 857 int 858 auvia_trigger_output(void *addr, void *start, void *end, 859 int blksize, void (*intr)(void *), void *arg, 860 struct audio_params *param) 861 { 862 struct auvia_softc *sc = addr; 863 struct auvia_softc_chan *ch = &(sc->sc_play); 864 struct auvia_dma *p; 865 866 for (p = sc->sc_dmas; p && p->addr != start; p = p->next) 867 ; 868 869 if (!p) 870 panic("auvia_trigger_output: request with bad start " 871 "address (%p)\n", start); 872 873 if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) { 874 return 1; 875 } 876 877 ch->sc_intr = intr; 878 ch->sc_arg = arg; 879 880 bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_DMAOPS_BASE, 881 ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr); 882 883 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_MODE, 884 ch->sc_reg); 885 886 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_CONTROL, 887 AUVIA_RPCTRL_START); 888 889 return 0; 890 } 891 892 893 int 894 auvia_trigger_input(void *addr, void *start, void *end, 895 int blksize, void (*intr)(void *), void *arg, 896 struct audio_params *param) 897 { 898 struct auvia_softc *sc = addr; 899 struct auvia_softc_chan *ch = &(sc->sc_record); 900 struct auvia_dma *p; 901 902 for (p = sc->sc_dmas; p && p->addr != start; p = p->next) 903 ; 904 905 if (!p) 906 panic("auvia_trigger_input: request with bad start " 907 "address (%p)\n", start); 908 909 if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) { 910 return 1; 911 } 912 913 ch->sc_intr = intr; 914 ch->sc_arg = arg; 915 916 bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_DMAOPS_BASE, 917 ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr); 918 919 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_MODE, 920 ch->sc_reg); 921 922 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_CONTROL, 923 AUVIA_RPCTRL_START); 924 925 return 0; 926 } 927 928 929 int 930 auvia_intr(void *arg) 931 { 932 struct auvia_softc *sc = arg; 933 u_int8_t r; 934 int i = 0; 935 936 r = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_STAT); 937 if (r & AUVIA_RPSTAT_INTR) { 938 if (sc->sc_record.sc_intr) 939 sc->sc_record.sc_intr(sc->sc_record.sc_arg); 940 941 /* clear interrupts */ 942 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_STAT, 943 AUVIA_RPSTAT_INTR); 944 945 i++; 946 } 947 r = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_STAT); 948 if (r & AUVIA_RPSTAT_INTR) { 949 if (sc->sc_play.sc_intr) 950 sc->sc_play.sc_intr(sc->sc_play.sc_arg); 951 952 /* clear interrupts */ 953 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_STAT, 954 AUVIA_RPSTAT_INTR); 955 956 i++; 957 } 958 959 return (i? 1 : 0); 960 } 961