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