1 /* $OpenBSD: azalia_codec.c,v 1.139 2009/11/03 17:31:30 jakemsr Exp $ */ 2 /* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */ 3 4 /*- 5 * Copyright (c) 2005 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by TAMURA Kent 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 #include <sys/param.h> 34 #include <sys/device.h> 35 #include <sys/malloc.h> 36 #include <sys/systm.h> 37 #include <uvm/uvm_param.h> 38 #include <dev/pci/azalia.h> 39 40 #define XNAME(co) (((struct device *)co->az)->dv_xname) 41 #define MIXER_DELTA(n) (AUDIO_MAX_GAIN / (n)) 42 43 int azalia_add_convgroup(codec_t *, convgroupset_t *, 44 struct io_pin *, int, nid_t *, int, uint32_t, uint32_t); 45 46 int azalia_mixer_fix_indexes(codec_t *); 47 int azalia_mixer_default(codec_t *); 48 int azalia_mixer_ensure_capacity(codec_t *, size_t); 49 u_char azalia_mixer_from_device_value(const codec_t *, nid_t, int, uint32_t ); 50 uint32_t azalia_mixer_to_device_value(const codec_t *, nid_t, int, u_char); 51 52 void azalia_devinfo_offon(mixer_devinfo_t *); 53 void azalia_pin_config_ov(widget_t *, int, int); 54 void azalia_ampcap_ov(widget_t *, int, int, int, int, int, int); 55 int azalia_gpio_unmute(codec_t *, int); 56 57 58 int 59 azalia_codec_init_vtbl(codec_t *this) 60 { 61 /** 62 * We can refer this->vid and this->subid. 63 */ 64 this->name = NULL; 65 this->qrks = AZ_QRK_NONE; 66 switch (this->vid) { 67 case 0x10ec0260: 68 this->name = "Realtek ALC260"; 69 break; 70 case 0x10ec0262: 71 this->name = "Realtek ALC262"; 72 this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D; 73 break; 74 case 0x10ec0268: 75 this->name = "Realtek ALC268"; 76 this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D; 77 break; 78 case 0x10ec0269: 79 this->name = "Realtek ALC269"; 80 break; 81 case 0x10ec0272: 82 this->name = "Realtek ALC272"; 83 break; 84 case 0x10ec0660: 85 this->name = "Realtek ALC660"; 86 if (this->subid == 0x13391043) { /* ASUS_G2K */ 87 this->qrks |= AZ_QRK_GPIO_UNMUTE_0; 88 } 89 break; 90 case 0x10ec0662: 91 this->name = "Realtek ALC662"; 92 this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D; 93 break; 94 case 0x10ec0663: 95 this->name = "Realtek ALC663"; 96 break; 97 case 0x10ec0861: 98 this->name = "Realtek ALC861"; 99 break; 100 case 0x10ec0880: 101 this->name = "Realtek ALC880"; 102 this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D; 103 if (this->subid == 0x19931043 || /* ASUS_M5200 */ 104 this->subid == 0x13231043) { /* ASUS_A7M */ 105 this->qrks |= AZ_QRK_GPIO_UNMUTE_0; 106 } 107 if (this->subid == 0x203d161f) { /* MEDION_MD95257 */ 108 this->qrks |= AZ_QRK_GPIO_UNMUTE_1; 109 } 110 break; 111 case 0x10ec0882: 112 this->name = "Realtek ALC882"; 113 this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D; 114 if (this->subid == 0x13c21043 || /* ASUS_A7T */ 115 this->subid == 0x19711043) { /* ASUS_W2J */ 116 this->qrks |= AZ_QRK_GPIO_UNMUTE_0; 117 } 118 break; 119 case 0x10ec0883: 120 this->name = "Realtek ALC883"; 121 this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D; 122 if (this->subid == 0x00981025) { /* ACER_ID */ 123 this->qrks |= AZ_QRK_GPIO_UNMUTE_0 | 124 AZ_QRK_GPIO_UNMUTE_1; 125 } 126 break; 127 case 0x10ec0885: 128 this->name = "Realtek ALC885"; 129 this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D; 130 if (this->subid == 0x00a1106b || /* APPLE_MB3 */ 131 this->subid == 0x00a0106b || /* APPLE_MB3_1 */ 132 this->subid == 0x00a3106b) { /* APPLE_MB4 */ 133 this->qrks |= AZ_QRK_GPIO_UNMUTE_0; 134 } 135 if (this->subid == 0x00a0106b) 136 this->qrks |= AZ_QRK_WID_OVREF50; 137 break; 138 case 0x10ec0888: 139 this->name = "Realtek ALC888"; 140 this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D; 141 break; 142 case 0x11060398: 143 case 0x11061398: 144 case 0x11062398: 145 case 0x11063398: 146 case 0x11064398: 147 case 0x11065398: 148 case 0x11066398: 149 case 0x11067398: 150 this->name = "VIA VT1702"; 151 break; 152 case 0x111d7603: 153 this->name = "IDT 92HD75B3/4"; 154 break; 155 case 0x111d7604: 156 this->name = "IDT 92HD83C1X"; 157 break; 158 case 0x111d7605: 159 this->name = "IDT 92HD81B1X"; 160 break; 161 case 0x111d7608: 162 this->name = "IDT 92HD75B1/2"; 163 break; 164 case 0x111d7674: 165 this->name = "IDT 92HD73D1"; 166 break; 167 case 0x111d7675: 168 this->name = "IDT 92HD73C1"; /* aka 92HDW74C1 */ 169 break; 170 case 0x111d7676: 171 this->name = "IDT 92HD73E1"; /* aka 92HDW74E1 */ 172 break; 173 case 0x111d76b0: 174 this->name = "IDT 92HD71B8"; 175 break; 176 case 0x111d76b2: 177 this->name = "IDT 92HD71B7"; 178 if (this->subid == 0x02631028 || /* DELL_E5500 */ 179 this->subid == 0x02501028 || /* DELL_M4400 */ 180 this->subid == 0x02331028 || /* DELL_E6400 */ 181 this->subid == 0x024f1028) { /* DELL_E6500 */ 182 this->qrks |= AZ_QRK_GPIO_UNMUTE_0; 183 } 184 break; 185 case 0x111d76b6: 186 this->name = "IDT 92HD71B5"; 187 break; 188 case 0x111d76d4: 189 this->name = "IDT 92HD83C1C"; 190 break; 191 case 0x111d76d5: 192 this->name = "IDT 92HD81B1C"; 193 break; 194 case 0x11d4184a: 195 this->name = "Analog Devices AD1884A"; 196 break; 197 case 0x11d41882: 198 this->name = "Analog Devices AD1882"; 199 break; 200 case 0x11d41883: 201 this->name = "Analog Devices AD1883"; 202 break; 203 case 0x11d41884: 204 this->name = "Analog Devices AD1884"; 205 break; 206 case 0x11d4194a: 207 this->name = "Analog Devices AD1984A"; 208 break; 209 case 0x11d41981: 210 this->name = "Analog Devices AD1981HD"; 211 this->qrks |= AZ_QRK_WID_AD1981_OAMP; 212 break; 213 case 0x11d41983: 214 this->name = "Analog Devices AD1983"; 215 break; 216 case 0x11d41984: 217 this->name = "Analog Devices AD1984"; 218 break; 219 case 0x11d41988: 220 this->name = "Analog Devices AD1988A"; 221 break; 222 case 0x11d4198b: 223 this->name = "Analog Devices AD1988B"; 224 break; 225 case 0x11d4882a: 226 this->name = "Analog Devices AD1882A"; 227 break; 228 case 0x11d4989a: 229 this->name = "Analog Devices AD1989A"; 230 break; 231 case 0x11d4989b: 232 this->name = "Analog Devices AD1989B"; 233 break; 234 case 0x14f15045: 235 this->name = "Conexant CX20549"; /* Venice */ 236 break; 237 case 0x14f15047: 238 this->name = "Conexant CX20551"; /* Waikiki */ 239 break; 240 case 0x14f15051: 241 this->name = "Conexant CX20561"; /* Hermosa */ 242 break; 243 case 0x434d4980: 244 this->name = "CMedia CMI9880"; 245 break; 246 case 0x83847612: 247 this->name = "Sigmatel STAC9230X"; 248 break; 249 case 0x83847613: 250 this->name = "Sigmatel STAC9230D"; 251 break; 252 case 0x83847614: 253 this->name = "Sigmatel STAC9229X"; 254 break; 255 case 0x83847615: 256 this->name = "Sigmatel STAC9229D"; 257 break; 258 case 0x83847616: 259 this->name = "Sigmatel STAC9228X"; 260 if (this->subid == 0x02271028 || /* DELL_V1400 */ 261 this->subid == 0x01f31028) { /* DELL_I1400 */ 262 this->qrks |= AZ_QRK_GPIO_UNMUTE_2; 263 } 264 break; 265 case 0x83847617: 266 this->name = "Sigmatel STAC9228D"; 267 break; 268 case 0x83847618: 269 this->name = "Sigmatel STAC9227X"; 270 break; 271 case 0x83847619: 272 this->name = "Sigmatel STAC9227D"; 273 break; 274 case 0x83847620: 275 this->name = "Sigmatel STAC9274"; 276 break; 277 case 0x83847621: 278 this->name = "Sigmatel STAC9274D"; 279 break; 280 case 0x83847626: 281 this->name = "Sigmatel STAC9271X"; 282 break; 283 case 0x83847627: 284 this->name = "Sigmatel STAC9271D"; 285 break; 286 case 0x83847632: 287 this->name = "Sigmatel STAC9202"; 288 break; 289 case 0x83847634: 290 this->name = "Sigmatel STAC9250"; 291 break; 292 case 0x83847636: 293 this->name = "Sigmatel STAC9251"; 294 break; 295 case 0x83847638: 296 this->name = "IDT 92HD700X"; 297 break; 298 case 0x83847639: 299 this->name = "IDT 92HD700D"; 300 break; 301 case 0x83847645: 302 this->name = "IDT 92HD206X"; 303 break; 304 case 0x83847646: 305 this->name = "IDT 92HD206D"; 306 break; 307 case 0x83847661: 308 /* FALLTHROUGH */ 309 case 0x83847662: 310 this->name = "Sigmatel STAC9225"; 311 break; 312 case 0x83847680: 313 this->name = "Sigmatel STAC9220/1"; 314 if (this->subid == 0x76808384) { /* APPLE_ID */ 315 this->qrks |= AZ_QRK_GPIO_POL_0 | AZ_QRK_GPIO_UNMUTE_0 | 316 AZ_QRK_GPIO_UNMUTE_1; 317 } 318 break; 319 case 0x83847682: 320 /* FALLTHROUGH */ 321 case 0x83847683: 322 this->name = "Sigmatel STAC9221D"; /* aka IDT 92HD202 */ 323 break; 324 case 0x83847690: 325 this->name = "Sigmatel STAC9200"; /* aka IDT 92HD001 */ 326 break; 327 case 0x83847691: 328 this->name = "Sigmatel STAC9200D"; 329 break; 330 case 0x83847698: 331 this->name = "IDT 92HD005"; 332 break; 333 case 0x83847699: 334 this->name = "IDT 92HD005D"; 335 break; 336 case 0x838476a0: 337 this->name = "Sigmatel STAC9205X"; 338 if (this->subid == 0x01f91028 || /* DELL_D630 */ 339 this->subid == 0x02281028) { /* DELL_V1500 */ 340 this->qrks |= AZ_QRK_GPIO_UNMUTE_0; 341 } 342 break; 343 case 0x838476a1: 344 this->name = "Sigmatel STAC9205D"; 345 break; 346 case 0x838476a2: 347 this->name = "Sigmatel STAC9204X"; 348 break; 349 case 0x838476a3: 350 this->name = "Sigmatel STAC9204D"; 351 break; 352 } 353 return 0; 354 } 355 356 /* ---------------------------------------------------------------- 357 * functions for generic codecs 358 * ---------------------------------------------------------------- */ 359 360 int 361 azalia_widget_enabled(const codec_t *this, nid_t nid) 362 { 363 if (!VALID_WIDGET_NID(nid, this) || !this->w[nid].enable) 364 return 0; 365 return 1; 366 } 367 368 int 369 azalia_init_dacgroup(codec_t *this) 370 { 371 this->dacs.ngroups = 0; 372 if (this->na_dacs > 0) 373 azalia_add_convgroup(this, &this->dacs, 374 this->opins, this->nopins, 375 this->a_dacs, this->na_dacs, 376 COP_AWTYPE_AUDIO_OUTPUT, 0); 377 if (this->na_dacs_d > 0) 378 azalia_add_convgroup(this, &this->dacs, 379 this->opins_d, this->nopins_d, 380 this->a_dacs_d, this->na_dacs_d, 381 COP_AWTYPE_AUDIO_OUTPUT, COP_AWCAP_DIGITAL); 382 this->dacs.cur = 0; 383 384 this->adcs.ngroups = 0; 385 if (this->na_adcs > 0) 386 azalia_add_convgroup(this, &this->adcs, 387 this->ipins, this->nipins, 388 this->a_adcs, this->na_adcs, 389 COP_AWTYPE_AUDIO_INPUT, 0); 390 if (this->na_adcs_d > 0) 391 azalia_add_convgroup(this, &this->adcs, 392 this->ipins_d, this->nipins_d, 393 this->a_adcs_d, this->na_adcs_d, 394 COP_AWTYPE_AUDIO_INPUT, COP_AWCAP_DIGITAL); 395 this->adcs.cur = 0; 396 397 return 0; 398 } 399 400 int 401 azalia_add_convgroup(codec_t *this, convgroupset_t *group, 402 struct io_pin *pins, int npins, nid_t *all_convs, int nall_convs, 403 uint32_t type, uint32_t digital) 404 { 405 nid_t convs[HDA_MAX_CHANNELS]; 406 int nconvs; 407 nid_t conv; 408 int i, j, k; 409 410 nconvs = 0; 411 412 /* default pin connections */ 413 for (i = 0; i < npins; i++) { 414 conv = pins[i].conv; 415 if (conv < 0) 416 continue; 417 for (j = 0; j < nconvs; j++) { 418 if (convs[j] == conv) 419 break; 420 } 421 if (j < nconvs) 422 continue; 423 convs[nconvs++] = conv; 424 if (nconvs >= nall_convs) { 425 goto done; 426 } 427 } 428 /* non-default connections */ 429 for (i = 0; i < npins; i++) { 430 for (j = 0; j < nall_convs; j++) { 431 conv = all_convs[j]; 432 for (k = 0; k < nconvs; k++) { 433 if (convs[k] == conv) 434 break; 435 } 436 if (k < nconvs) 437 continue; 438 if (type == COP_AWTYPE_AUDIO_OUTPUT) { 439 k = azalia_codec_fnode(this, conv, 440 pins[i].nid, 0); 441 if (k < 0) 442 continue; 443 } else { 444 if (!azalia_widget_enabled(this, conv)) 445 continue; 446 k = azalia_codec_fnode(this, pins[i].nid, 447 conv, 0); 448 if (k < 0) 449 continue; 450 } 451 convs[nconvs++] = conv; 452 if (nconvs >= nall_convs) { 453 goto done; 454 } 455 } 456 } 457 /* Make sure the speaker dac is part of the analog output convgroup 458 * or it won't get connected by azalia_codec_connect_stream(). 459 */ 460 if (type == COP_AWTYPE_AUDIO_OUTPUT && !digital && 461 nconvs < nall_convs && this->spkr_dac != -1) { 462 for (i = 0; i < nconvs; i++) 463 if (convs[i] == this->spkr_dac) 464 break; 465 if (i == nconvs) 466 convs[nconvs++] = this->spkr_dac; 467 } 468 done: 469 for (i = 0; i < nconvs; i++) 470 group->groups[group->ngroups].conv[i] = convs[i]; 471 if (nconvs > 0) { 472 group->groups[group->ngroups].nconv = i; 473 group->ngroups++; 474 } 475 476 /* Disable converters that aren't in a convgroup. */ 477 for (i = 0; i < nall_convs; i++) { 478 conv = all_convs[i]; 479 for (j = 0; j < nconvs; j++) 480 if (convs[j] == conv) 481 break; 482 if (j == nconvs) 483 this->w[conv].enable = 0; 484 } 485 486 return 0; 487 } 488 489 int 490 azalia_codec_fnode(codec_t *this, nid_t node, int index, int depth) 491 { 492 const widget_t *w; 493 int i, ret; 494 495 w = &this->w[index]; 496 if (w->nid == node) { 497 return index; 498 } 499 /* back at the beginning or a bad end */ 500 if (depth > 0 && 501 (w->type == COP_AWTYPE_PIN_COMPLEX || 502 w->type == COP_AWTYPE_BEEP_GENERATOR || 503 w->type == COP_AWTYPE_AUDIO_OUTPUT || 504 w->type == COP_AWTYPE_AUDIO_INPUT)) 505 return -1; 506 if (++depth >= 10) 507 return -1; 508 for (i = 0; i < w->nconnections; i++) { 509 if (!azalia_widget_enabled(this, w->connections[i])) 510 continue; 511 ret = azalia_codec_fnode(this, node, w->connections[i], depth); 512 if (ret >= 0) 513 return ret; 514 } 515 return -1; 516 } 517 518 int 519 azalia_unsol_event(codec_t *this, int tag) 520 { 521 mixer_ctrl_t mc; 522 uint32_t result; 523 int i, err, vol, vol2; 524 525 err = 0; 526 tag = CORB_UNSOL_TAG(tag); 527 switch (tag) { 528 case AZ_TAG_SPKR: 529 mc.type = AUDIO_MIXER_ENUM; 530 vol = 0; 531 for (i = 0; err == 0 && i < this->nsense_pins; i++) { 532 if (!(this->spkr_muters & (1 << i))) 533 continue; 534 err = azalia_comresp(this, this->sense_pins[i], 535 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 536 if (err || !(result & CORB_PWC_OUTPUT)) 537 continue; 538 err = azalia_comresp(this, this->sense_pins[i], 539 CORB_GET_PIN_SENSE, 0, &result); 540 if (!err && (result & CORB_PS_PRESENCE)) 541 vol = 1; 542 } 543 if (err) 544 break; 545 switch(this->spkr_mute_method) { 546 case AZ_SPKR_MUTE_SPKR_MUTE: 547 mc.un.ord = vol; 548 err = azalia_mixer_set(this, this->speaker, 549 MI_TARGET_OUTAMP, &mc); 550 break; 551 case AZ_SPKR_MUTE_SPKR_DIR: 552 mc.un.ord = vol ? 0 : 1; 553 err = azalia_mixer_set(this, this->speaker, 554 MI_TARGET_PINDIR, &mc); 555 break; 556 case AZ_SPKR_MUTE_DAC_MUTE: 557 mc.un.ord = vol; 558 err = azalia_mixer_set(this, this->spkr_dac, 559 MI_TARGET_OUTAMP, &mc); 560 break; 561 } 562 break; 563 564 case AZ_TAG_PLAYVOL: 565 if (this->playvols.master == this->audiofunc) 566 return EINVAL; 567 err = azalia_comresp(this, this->playvols.master, 568 CORB_GET_VOLUME_KNOB, 0, &result); 569 if (err) 570 return err; 571 572 vol = CORB_VKNOB_VOLUME(result) - this->playvols.hw_step; 573 vol2 = vol * (AUDIO_MAX_GAIN / this->playvols.hw_nsteps); 574 this->playvols.hw_step = CORB_VKNOB_VOLUME(result); 575 576 vol = vol2 + this->playvols.vol_l; 577 if (vol < 0) 578 vol = 0; 579 else if (vol > AUDIO_MAX_GAIN) 580 vol = AUDIO_MAX_GAIN; 581 this->playvols.vol_l = vol; 582 583 vol = vol2 + this->playvols.vol_r; 584 if (vol < 0) 585 vol = 0; 586 else if (vol > AUDIO_MAX_GAIN) 587 vol = AUDIO_MAX_GAIN; 588 this->playvols.vol_r = vol; 589 590 mc.type = AUDIO_MIXER_VALUE; 591 mc.un.value.num_channels = 2; 592 mc.un.value.level[0] = this->playvols.vol_l; 593 mc.un.value.level[1] = this->playvols.vol_r; 594 err = azalia_mixer_set(this, this->playvols.master, 595 MI_TARGET_PLAYVOL, &mc); 596 break; 597 598 default: 599 DPRINTF(("%s: unknown tag %d\n", __func__, tag)); 600 break; 601 } 602 603 return err; 604 } 605 606 607 /* ---------------------------------------------------------------- 608 * Generic mixer functions 609 * ---------------------------------------------------------------- */ 610 611 int 612 azalia_mixer_init(codec_t *this) 613 { 614 /* 615 * pin "<color>%2.2x" 616 * audio output "dac%2.2x" 617 * audio input "adc%2.2x" 618 * mixer "mixer%2.2x" 619 * selector "sel%2.2x" 620 */ 621 const widget_t *w, *ww; 622 mixer_item_t *m; 623 int err, i, j, k, bits; 624 625 this->maxmixers = 10; 626 this->nmixers = 0; 627 this->mixers = malloc(sizeof(mixer_item_t) * this->maxmixers, 628 M_DEVBUF, M_NOWAIT | M_ZERO); 629 if (this->mixers == NULL) { 630 printf("%s: out of memory in %s\n", XNAME(this), __func__); 631 return ENOMEM; 632 } 633 634 /* register classes */ 635 m = &this->mixers[AZ_CLASS_INPUT]; 636 m->devinfo.index = AZ_CLASS_INPUT; 637 strlcpy(m->devinfo.label.name, AudioCinputs, 638 sizeof(m->devinfo.label.name)); 639 m->devinfo.type = AUDIO_MIXER_CLASS; 640 m->devinfo.mixer_class = AZ_CLASS_INPUT; 641 m->devinfo.next = AUDIO_MIXER_LAST; 642 m->devinfo.prev = AUDIO_MIXER_LAST; 643 m->nid = 0; 644 645 m = &this->mixers[AZ_CLASS_OUTPUT]; 646 m->devinfo.index = AZ_CLASS_OUTPUT; 647 strlcpy(m->devinfo.label.name, AudioCoutputs, 648 sizeof(m->devinfo.label.name)); 649 m->devinfo.type = AUDIO_MIXER_CLASS; 650 m->devinfo.mixer_class = AZ_CLASS_OUTPUT; 651 m->devinfo.next = AUDIO_MIXER_LAST; 652 m->devinfo.prev = AUDIO_MIXER_LAST; 653 m->nid = 0; 654 655 m = &this->mixers[AZ_CLASS_RECORD]; 656 m->devinfo.index = AZ_CLASS_RECORD; 657 strlcpy(m->devinfo.label.name, AudioCrecord, 658 sizeof(m->devinfo.label.name)); 659 m->devinfo.type = AUDIO_MIXER_CLASS; 660 m->devinfo.mixer_class = AZ_CLASS_RECORD; 661 m->devinfo.next = AUDIO_MIXER_LAST; 662 m->devinfo.prev = AUDIO_MIXER_LAST; 663 m->nid = 0; 664 665 this->nmixers = AZ_CLASS_RECORD + 1; 666 667 #define MIXER_REG_PROLOG \ 668 mixer_devinfo_t *d; \ 669 err = azalia_mixer_ensure_capacity(this, this->nmixers + 1); \ 670 if (err) \ 671 return err; \ 672 m = &this->mixers[this->nmixers]; \ 673 d = &m->devinfo; \ 674 m->nid = i 675 676 FOR_EACH_WIDGET(this, i) { 677 678 w = &this->w[i]; 679 if (!w->enable) 680 continue; 681 682 /* selector */ 683 if (w->nconnections > 0 && w->type != COP_AWTYPE_AUDIO_MIXER && 684 !(w->nconnections == 1 && 685 azalia_widget_enabled(this, w->connections[0]) && 686 strcmp(w->name, this->w[w->connections[0]].name) == 0) && 687 w->nid != this->mic) { 688 MIXER_REG_PROLOG; 689 snprintf(d->label.name, sizeof(d->label.name), 690 "%s_source", w->name); 691 d->type = AUDIO_MIXER_ENUM; 692 if (w->mixer_class >= 0) 693 d->mixer_class = w->mixer_class; 694 else { 695 if (w->type == COP_AWTYPE_AUDIO_SELECTOR) 696 d->mixer_class = AZ_CLASS_INPUT; 697 else 698 d->mixer_class = AZ_CLASS_OUTPUT; 699 } 700 m->target = MI_TARGET_CONNLIST; 701 for (j = 0, k = 0; j < w->nconnections && k < 32; j++) { 702 if (!azalia_widget_enabled(this, 703 w->connections[j])) 704 continue; 705 d->un.e.member[k].ord = j; 706 strlcpy(d->un.e.member[k].label.name, 707 this->w[w->connections[j]].name, 708 MAX_AUDIO_DEV_LEN); 709 k++; 710 } 711 d->un.e.num_mem = k; 712 this->nmixers++; 713 } 714 715 /* output mute */ 716 if (w->widgetcap & COP_AWCAP_OUTAMP && 717 w->outamp_cap & COP_AMPCAP_MUTE && 718 w->nid != this->mic) { 719 MIXER_REG_PROLOG; 720 snprintf(d->label.name, sizeof(d->label.name), 721 "%s_mute", w->name); 722 if (w->mixer_class >= 0) 723 d->mixer_class = w->mixer_class; 724 else { 725 if (w->type == COP_AWTYPE_AUDIO_MIXER || 726 w->type == COP_AWTYPE_AUDIO_SELECTOR || 727 w->type == COP_AWTYPE_PIN_COMPLEX) 728 d->mixer_class = AZ_CLASS_OUTPUT; 729 else 730 d->mixer_class = AZ_CLASS_INPUT; 731 } 732 m->target = MI_TARGET_OUTAMP; 733 azalia_devinfo_offon(d); 734 this->nmixers++; 735 } 736 737 /* output gain */ 738 if (w->widgetcap & COP_AWCAP_OUTAMP && 739 COP_AMPCAP_NUMSTEPS(w->outamp_cap) && 740 w->nid != this->mic) { 741 MIXER_REG_PROLOG; 742 snprintf(d->label.name, sizeof(d->label.name), 743 "%s", w->name); 744 d->type = AUDIO_MIXER_VALUE; 745 if (w->mixer_class >= 0) 746 d->mixer_class = w->mixer_class; 747 else { 748 if (w->type == COP_AWTYPE_AUDIO_MIXER || 749 w->type == COP_AWTYPE_AUDIO_SELECTOR || 750 w->type == COP_AWTYPE_PIN_COMPLEX) 751 d->mixer_class = AZ_CLASS_OUTPUT; 752 else 753 d->mixer_class = AZ_CLASS_INPUT; 754 } 755 m->target = MI_TARGET_OUTAMP; 756 d->un.v.num_channels = WIDGET_CHANNELS(w); 757 d->un.v.units.name[0] = 0; 758 d->un.v.delta = 759 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->outamp_cap)); 760 this->nmixers++; 761 } 762 763 /* input mute */ 764 if (w->widgetcap & COP_AWCAP_INAMP && 765 w->inamp_cap & COP_AMPCAP_MUTE && 766 w->nid != this->speaker) { 767 if (w->type != COP_AWTYPE_AUDIO_MIXER) { 768 MIXER_REG_PROLOG; 769 snprintf(d->label.name, sizeof(d->label.name), 770 "%s_mute", w->name); 771 if (w->mixer_class >= 0) 772 d->mixer_class = w->mixer_class; 773 else 774 d->mixer_class = AZ_CLASS_INPUT; 775 m->target = 0; 776 azalia_devinfo_offon(d); 777 this->nmixers++; 778 } else { 779 MIXER_REG_PROLOG; 780 snprintf(d->label.name, sizeof(d->label.name), 781 "%s_source", w->name); 782 m->target = MI_TARGET_MUTESET; 783 d->type = AUDIO_MIXER_SET; 784 if (w->mixer_class >= 0) 785 d->mixer_class = w->mixer_class; 786 else 787 d->mixer_class = AZ_CLASS_INPUT; 788 for (j = 0, k = 0; 789 j < w->nconnections && k < 32; j++) { 790 if (!azalia_widget_enabled(this, 791 w->connections[j])) 792 continue; 793 if (w->connections[j] == this->speaker) 794 continue; 795 d->un.s.member[k].mask = 1 << j; 796 strlcpy(d->un.s.member[k].label.name, 797 this->w[w->connections[j]].name, 798 MAX_AUDIO_DEV_LEN); 799 k++; 800 } 801 d->un.s.num_mem = k; 802 if (k != 0) 803 this->nmixers++; 804 } 805 } 806 807 /* input gain */ 808 if (w->widgetcap & COP_AWCAP_INAMP && 809 COP_AMPCAP_NUMSTEPS(w->inamp_cap) && 810 w->nid != this->speaker) { 811 if (w->type != COP_AWTYPE_AUDIO_SELECTOR && 812 w->type != COP_AWTYPE_AUDIO_MIXER) { 813 MIXER_REG_PROLOG; 814 snprintf(d->label.name, sizeof(d->label.name), 815 "%s", w->name); 816 d->type = AUDIO_MIXER_VALUE; 817 if (w->mixer_class >= 0) 818 d->mixer_class = w->mixer_class; 819 else 820 d->mixer_class = AZ_CLASS_INPUT; 821 m->target = 0; 822 d->un.v.num_channels = WIDGET_CHANNELS(w); 823 d->un.v.units.name[0] = 0; 824 d->un.v.delta = 825 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap)); 826 this->nmixers++; 827 } else { 828 for (j = 0; j < w->nconnections; j++) { 829 if (!azalia_widget_enabled(this, 830 w->connections[j])) 831 continue; 832 if (w->connections[j] == this->speaker) 833 continue; 834 MIXER_REG_PROLOG; 835 snprintf(d->label.name, 836 sizeof(d->label.name), "%s_%s", 837 w->name, 838 this->w[w->connections[j]].name); 839 d->type = AUDIO_MIXER_VALUE; 840 if (w->mixer_class >= 0) 841 d->mixer_class = w->mixer_class; 842 else 843 d->mixer_class = AZ_CLASS_INPUT; 844 m->target = j; 845 d->un.v.num_channels = WIDGET_CHANNELS(w); 846 d->un.v.units.name[0] = 0; 847 d->un.v.delta = 848 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap)); 849 this->nmixers++; 850 } 851 } 852 } 853 854 /* hardcoded mixer inputs */ 855 if (w->type == COP_AWTYPE_AUDIO_MIXER && 856 !(w->widgetcap & COP_AWCAP_INAMP)) { 857 MIXER_REG_PROLOG; 858 snprintf(d->label.name, sizeof(d->label.name), 859 "%s_source", w->name); 860 m->target = MI_TARGET_MIXERSET; 861 d->type = AUDIO_MIXER_SET; 862 if (w->mixer_class >= 0) 863 d->mixer_class = w->mixer_class; 864 else 865 d->mixer_class = AZ_CLASS_INPUT; 866 for (j = 0, k = 0; 867 j < w->nconnections && k < 32; j++) { 868 if (!azalia_widget_enabled(this, 869 w->connections[j])) 870 continue; 871 if (w->connections[j] == this->speaker) 872 continue; 873 d->un.s.member[k].mask = 1 << j; 874 strlcpy(d->un.s.member[k].label.name, 875 this->w[w->connections[j]].name, 876 MAX_AUDIO_DEV_LEN); 877 k++; 878 } 879 d->un.s.num_mem = k; 880 if (k != 0) 881 this->nmixers++; 882 } 883 884 /* pin direction */ 885 if (w->type == COP_AWTYPE_PIN_COMPLEX && 886 ((w->d.pin.cap & COP_PINCAP_OUTPUT && 887 w->d.pin.cap & COP_PINCAP_INPUT) || 888 COP_PINCAP_VREF(w->d.pin.cap) > 1)) { 889 890 MIXER_REG_PROLOG; 891 snprintf(d->label.name, sizeof(d->label.name), 892 "%s_dir", w->name); 893 d->type = AUDIO_MIXER_ENUM; 894 d->mixer_class = AZ_CLASS_OUTPUT; 895 m->target = MI_TARGET_PINDIR; 896 897 k = 0; 898 d->un.e.member[k].ord = 0; 899 strlcpy(d->un.e.member[k].label.name, "none", 900 MAX_AUDIO_DEV_LEN); 901 k++; 902 903 if (w->d.pin.cap & COP_PINCAP_OUTPUT) { 904 d->un.e.member[k].ord = 1; 905 strlcpy(d->un.e.member[k].label.name, 906 AudioNoutput, MAX_AUDIO_DEV_LEN); 907 k++; 908 } 909 910 if (w->d.pin.cap & COP_PINCAP_INPUT) { 911 d->un.e.member[k].ord = 2; 912 strlcpy(d->un.e.member[k].label.name, 913 AudioNinput, MAX_AUDIO_DEV_LEN); 914 k++; 915 916 for (j = 0; j < 4; j++) { 917 if (j == 0) { 918 bits = (1 << CORB_PWC_VREF_GND); 919 strlcpy(d->un.e.member[k].label.name, 920 AudioNinput "-vr0", 921 MAX_AUDIO_DEV_LEN); 922 } else if (j == 1) { 923 bits = (1 << CORB_PWC_VREF_50); 924 strlcpy(d->un.e.member[k].label.name, 925 AudioNinput "-vr50", 926 MAX_AUDIO_DEV_LEN); 927 } else if (j == 2) { 928 bits = (1 << CORB_PWC_VREF_80); 929 strlcpy(d->un.e.member[k].label.name, 930 AudioNinput "-vr80", 931 MAX_AUDIO_DEV_LEN); 932 } else if (j == 3) { 933 bits = (1 << CORB_PWC_VREF_100); 934 strlcpy(d->un.e.member[k].label.name, 935 AudioNinput "-vr100", 936 MAX_AUDIO_DEV_LEN); 937 } 938 if ((COP_PINCAP_VREF(w->d.pin.cap) & 939 bits) == bits) { 940 d->un.e.member[k].ord = j + 3; 941 k++; 942 } 943 } 944 } 945 d->un.e.num_mem = k; 946 this->nmixers++; 947 } 948 949 /* pin headphone-boost */ 950 if (w->type == COP_AWTYPE_PIN_COMPLEX && 951 w->d.pin.cap & COP_PINCAP_HEADPHONE && 952 w->nid != this->mic) { 953 MIXER_REG_PROLOG; 954 snprintf(d->label.name, sizeof(d->label.name), 955 "%s_boost", w->name); 956 d->mixer_class = AZ_CLASS_OUTPUT; 957 m->target = MI_TARGET_PINBOOST; 958 azalia_devinfo_offon(d); 959 this->nmixers++; 960 } 961 962 if (w->type == COP_AWTYPE_PIN_COMPLEX && 963 w->d.pin.cap & COP_PINCAP_EAPD) { 964 MIXER_REG_PROLOG; 965 snprintf(d->label.name, sizeof(d->label.name), 966 "%s_eapd", w->name); 967 d->mixer_class = AZ_CLASS_OUTPUT; 968 m->target = MI_TARGET_EAPD; 969 azalia_devinfo_offon(d); 970 this->nmixers++; 971 } 972 } 973 974 /* sense pins */ 975 for (i = 0; i < this->nsense_pins; i++) { 976 if (!azalia_widget_enabled(this, this->sense_pins[i])) { 977 DPRINTF(("%s: sense pin %2.2x not found\n", 978 __func__, this->sense_pins[i])); 979 continue; 980 } 981 982 MIXER_REG_PROLOG; 983 m->nid = this->w[this->sense_pins[i]].nid; 984 snprintf(d->label.name, sizeof(d->label.name), "%s_sense", 985 this->w[this->sense_pins[i]].name); 986 d->type = AUDIO_MIXER_ENUM; 987 d->mixer_class = AZ_CLASS_OUTPUT; 988 m->target = MI_TARGET_PINSENSE; 989 d->un.e.num_mem = 2; 990 d->un.e.member[0].ord = 0; 991 strlcpy(d->un.e.member[0].label.name, "unplugged", 992 MAX_AUDIO_DEV_LEN); 993 d->un.e.member[1].ord = 1; 994 strlcpy(d->un.e.member[1].label.name, "plugged", 995 MAX_AUDIO_DEV_LEN); 996 this->nmixers++; 997 } 998 999 /* spkr mute by jack sense */ 1000 this->spkr_mute_method = AZ_SPKR_MUTE_NONE; 1001 if (this->speaker != -1 && this->spkr_dac != -1 && this->nsense_pins > 0) { 1002 w = &this->w[this->speaker]; 1003 if ((w->widgetcap & COP_AWCAP_OUTAMP) && 1004 (w->outamp_cap & COP_AMPCAP_MUTE)) 1005 this->spkr_mute_method = AZ_SPKR_MUTE_SPKR_MUTE; 1006 else if ((w->d.pin.cap & COP_PINCAP_OUTPUT) && 1007 (w->d.pin.cap & COP_PINCAP_INPUT)) 1008 this->spkr_mute_method = AZ_SPKR_MUTE_SPKR_DIR; 1009 else { 1010 w = &this->w[this->spkr_dac]; 1011 if (w->nid != this->dacs.groups[0].conv[0] && 1012 (w->widgetcap & COP_AWCAP_OUTAMP) && 1013 (w->outamp_cap & COP_AMPCAP_MUTE)) 1014 this->spkr_mute_method = AZ_SPKR_MUTE_DAC_MUTE; 1015 } 1016 } 1017 if (this->spkr_mute_method != AZ_SPKR_MUTE_NONE) { 1018 w = &this->w[this->speaker]; 1019 MIXER_REG_PROLOG; 1020 m->nid = w->nid; 1021 snprintf(d->label.name, sizeof(d->label.name), 1022 "%s_muters", w->name); 1023 m->target = MI_TARGET_SENSESET; 1024 d->type = AUDIO_MIXER_SET; 1025 d->mixer_class = AZ_CLASS_OUTPUT; 1026 this->spkr_muters = 0; 1027 for (i = 0, j = 0; i < this->nsense_pins; i++) { 1028 ww = &this->w[this->sense_pins[i]]; 1029 if (!(w->d.pin.cap & COP_PINCAP_OUTPUT)) 1030 continue; 1031 if (!(w->widgetcap & COP_AWCAP_UNSOL)) 1032 continue; 1033 d->un.s.member[j].mask = 1 << i; 1034 this->spkr_muters |= (1 << i); 1035 strlcpy(d->un.s.member[j++].label.name, ww->name, 1036 MAX_AUDIO_DEV_LEN); 1037 } 1038 d->un.s.num_mem = j; 1039 if (j != 0) 1040 this->nmixers++; 1041 } 1042 1043 /* playback volume group */ 1044 if (this->playvols.nslaves > 0) { 1045 mixer_devinfo_t *d; 1046 err = azalia_mixer_ensure_capacity(this, 1047 this->nmixers + 3); 1048 1049 /* volume */ 1050 m = &this->mixers[this->nmixers]; 1051 m->nid = this->playvols.master; 1052 m->target = MI_TARGET_PLAYVOL; 1053 d = &m->devinfo; 1054 d->mixer_class = AZ_CLASS_OUTPUT; 1055 snprintf(d->label.name, sizeof(d->label.name), 1056 "%s", AudioNmaster); 1057 d->type = AUDIO_MIXER_VALUE; 1058 d->un.v.num_channels = 2; 1059 d->un.v.delta = 8; 1060 this->nmixers++; 1061 d->next = this->nmixers; 1062 1063 /* mute */ 1064 m = &this->mixers[this->nmixers]; 1065 m->nid = this->playvols.master; 1066 m->target = MI_TARGET_PLAYVOL; 1067 d = &m->devinfo; 1068 d->prev = this->nmixers - 1; 1069 d->mixer_class = AZ_CLASS_OUTPUT; 1070 snprintf(d->label.name, sizeof(d->label.name), 1071 "%s", AudioNmute); 1072 azalia_devinfo_offon(d); 1073 this->nmixers++; 1074 d->next = this->nmixers; 1075 1076 /* slaves */ 1077 m = &this->mixers[this->nmixers]; 1078 m->nid = this->playvols.master; 1079 m->target = MI_TARGET_PLAYVOL; 1080 d = &m->devinfo; 1081 d->prev = this->nmixers - 1; 1082 d->mixer_class = AZ_CLASS_OUTPUT; 1083 snprintf(d->label.name, sizeof(d->label.name), 1084 "%s", "slaves"); 1085 d->type = AUDIO_MIXER_SET; 1086 for (i = 0, j = 0; i < this->playvols.nslaves; i++) { 1087 ww = &this->w[this->playvols.slaves[i]]; 1088 d->un.s.member[j].mask = (1 << i); 1089 strlcpy(d->un.s.member[j++].label.name, ww->name, 1090 MAX_AUDIO_DEV_LEN); 1091 } 1092 d->un.s.num_mem = j; 1093 this->nmixers++; 1094 } 1095 1096 /* recording volume group */ 1097 if (this->recvols.nslaves > 0) { 1098 mixer_devinfo_t *d; 1099 err = azalia_mixer_ensure_capacity(this, 1100 this->nmixers + 3); 1101 1102 /* volume */ 1103 m = &this->mixers[this->nmixers]; 1104 m->nid = this->recvols.master; 1105 m->target = MI_TARGET_RECVOL; 1106 d = &m->devinfo; 1107 d->mixer_class = AZ_CLASS_RECORD; 1108 snprintf(d->label.name, sizeof(d->label.name), 1109 "%s", AudioNvolume); 1110 d->type = AUDIO_MIXER_VALUE; 1111 d->un.v.num_channels = 2; 1112 d->un.v.delta = 8; 1113 this->nmixers++; 1114 d->next = this->nmixers; 1115 1116 /* mute */ 1117 m = &this->mixers[this->nmixers]; 1118 m->nid = this->recvols.master; 1119 m->target = MI_TARGET_RECVOL; 1120 d = &m->devinfo; 1121 d->prev = this->nmixers - 1; 1122 d->mixer_class = AZ_CLASS_RECORD; 1123 snprintf(d->label.name, sizeof(d->label.name), 1124 "%s", AudioNmute); 1125 azalia_devinfo_offon(d); 1126 this->nmixers++; 1127 d->next = this->nmixers; 1128 1129 /* slaves */ 1130 m = &this->mixers[this->nmixers]; 1131 m->nid = this->recvols.master; 1132 m->target = MI_TARGET_RECVOL; 1133 d = &m->devinfo; 1134 d->prev = this->nmixers - 1; 1135 d->mixer_class = AZ_CLASS_RECORD; 1136 snprintf(d->label.name, sizeof(d->label.name), 1137 "%s", "slaves"); 1138 d->type = AUDIO_MIXER_SET; 1139 for (i = 0, j = 0; i < this->recvols.nslaves; i++) { 1140 ww = &this->w[this->recvols.slaves[i]]; 1141 d->un.s.member[j].mask = (1 << i); 1142 strlcpy(d->un.s.member[j++].label.name, ww->name, 1143 MAX_AUDIO_DEV_LEN); 1144 } 1145 d->un.s.num_mem = j; 1146 this->nmixers++; 1147 } 1148 1149 /* if the codec has more than one DAC group, the first is analog 1150 * and the second is digital. 1151 */ 1152 if (this->dacs.ngroups > 1) { 1153 MIXER_REG_PROLOG; 1154 strlcpy(d->label.name, AudioNmode, sizeof(d->label.name)); 1155 d->type = AUDIO_MIXER_ENUM; 1156 d->mixer_class = AZ_CLASS_OUTPUT; 1157 m->target = MI_TARGET_DAC; 1158 m->nid = this->audiofunc; 1159 d->un.e.member[0].ord = 0; 1160 strlcpy(d->un.e.member[0].label.name, "analog", 1161 MAX_AUDIO_DEV_LEN); 1162 d->un.e.member[1].ord = 1; 1163 strlcpy(d->un.e.member[1].label.name, "digital", 1164 MAX_AUDIO_DEV_LEN); 1165 d->un.e.num_mem = 2; 1166 this->nmixers++; 1167 } 1168 1169 /* if the codec has more than one ADC group, the first is analog 1170 * and the second is digital. 1171 */ 1172 if (this->adcs.ngroups > 1) { 1173 MIXER_REG_PROLOG; 1174 strlcpy(d->label.name, AudioNmode, sizeof(d->label.name)); 1175 d->type = AUDIO_MIXER_ENUM; 1176 d->mixer_class = AZ_CLASS_RECORD; 1177 m->target = MI_TARGET_ADC; 1178 m->nid = this->audiofunc; 1179 d->un.e.member[0].ord = 0; 1180 strlcpy(d->un.e.member[0].label.name, "analog", 1181 MAX_AUDIO_DEV_LEN); 1182 d->un.e.member[1].ord = 1; 1183 strlcpy(d->un.e.member[1].label.name, "digital", 1184 MAX_AUDIO_DEV_LEN); 1185 d->un.e.num_mem = 2; 1186 this->nmixers++; 1187 } 1188 1189 azalia_mixer_fix_indexes(this); 1190 azalia_mixer_default(this); 1191 return 0; 1192 } 1193 1194 void 1195 azalia_devinfo_offon(mixer_devinfo_t *d) 1196 { 1197 d->type = AUDIO_MIXER_ENUM; 1198 d->un.e.num_mem = 2; 1199 d->un.e.member[0].ord = 0; 1200 strlcpy(d->un.e.member[0].label.name, AudioNoff, MAX_AUDIO_DEV_LEN); 1201 d->un.e.member[1].ord = 1; 1202 strlcpy(d->un.e.member[1].label.name, AudioNon, MAX_AUDIO_DEV_LEN); 1203 } 1204 1205 int 1206 azalia_mixer_ensure_capacity(codec_t *this, size_t newsize) 1207 { 1208 size_t newmax; 1209 void *newbuf; 1210 1211 if (this->maxmixers >= newsize) 1212 return 0; 1213 newmax = this->maxmixers + 10; 1214 if (newmax < newsize) 1215 newmax = newsize; 1216 newbuf = malloc(sizeof(mixer_item_t) * newmax, M_DEVBUF, M_NOWAIT | M_ZERO); 1217 if (newbuf == NULL) { 1218 printf("%s: out of memory in %s\n", XNAME(this), __func__); 1219 return ENOMEM; 1220 } 1221 bcopy(this->mixers, newbuf, this->maxmixers * sizeof(mixer_item_t)); 1222 free(this->mixers, M_DEVBUF); 1223 this->mixers = newbuf; 1224 this->maxmixers = newmax; 1225 return 0; 1226 } 1227 1228 int 1229 azalia_mixer_fix_indexes(codec_t *this) 1230 { 1231 int i; 1232 mixer_devinfo_t *d; 1233 1234 for (i = 0; i < this->nmixers; i++) { 1235 d = &this->mixers[i].devinfo; 1236 #ifdef DIAGNOSTIC 1237 if (d->index != 0 && d->index != i) 1238 printf("%s: index mismatch %d %d\n", __func__, 1239 d->index, i); 1240 #endif 1241 d->index = i; 1242 if (d->prev == 0) 1243 d->prev = AUDIO_MIXER_LAST; 1244 if (d->next == 0) 1245 d->next = AUDIO_MIXER_LAST; 1246 } 1247 return 0; 1248 } 1249 1250 int 1251 azalia_mixer_default(codec_t *this) 1252 { 1253 widget_t *w; 1254 mixer_item_t *m; 1255 mixer_ctrl_t mc; 1256 int i, j, tgt, cap, err; 1257 1258 /* unmute all */ 1259 for (i = 0; i < this->nmixers; i++) { 1260 m = &this->mixers[i]; 1261 if (!IS_MI_TARGET_INAMP(m->target) && 1262 m->target != MI_TARGET_OUTAMP) 1263 continue; 1264 if (m->devinfo.type != AUDIO_MIXER_ENUM) 1265 continue; 1266 bzero(&mc, sizeof(mc)); 1267 mc.dev = i; 1268 mc.type = AUDIO_MIXER_ENUM; 1269 azalia_mixer_set(this, m->nid, m->target, &mc); 1270 } 1271 1272 /* set unextreme volume */ 1273 for (i = 0; i < this->nmixers; i++) { 1274 m = &this->mixers[i]; 1275 if (!IS_MI_TARGET_INAMP(m->target) && 1276 m->target != MI_TARGET_OUTAMP) 1277 continue; 1278 if (m->devinfo.type != AUDIO_MIXER_VALUE) 1279 continue; 1280 bzero(&mc, sizeof(mc)); 1281 mc.dev = i; 1282 mc.type = AUDIO_MIXER_VALUE; 1283 mc.un.value.num_channels = 1; 1284 mc.un.value.level[0] = AUDIO_MAX_GAIN / 2; 1285 if (WIDGET_CHANNELS(&this->w[m->nid]) == 2) { 1286 mc.un.value.num_channels = 2; 1287 mc.un.value.level[1] = mc.un.value.level[0]; 1288 } 1289 azalia_mixer_set(this, m->nid, m->target, &mc); 1290 } 1291 1292 /* unmute all */ 1293 for (i = 0; i < this->nmixers; i++) { 1294 m = &this->mixers[i]; 1295 if (m->target != MI_TARGET_MUTESET) 1296 continue; 1297 if (m->devinfo.type != AUDIO_MIXER_SET) 1298 continue; 1299 bzero(&mc, sizeof(mc)); 1300 mc.dev = i; 1301 mc.type = AUDIO_MIXER_SET; 1302 if (!azalia_widget_enabled(this, m->nid)) { 1303 DPRINTF(("%s: invalid set nid\n", __func__)); 1304 return EINVAL; 1305 } 1306 w = &this->w[m->nid]; 1307 for (j = 0; j < w->nconnections; j++) { 1308 if (!azalia_widget_enabled(this, w->connections[j])) 1309 continue; 1310 if (w->nid == this->input_mixer && 1311 w->connections[j] == this->mic) 1312 continue; 1313 mc.un.mask |= 1 << j; 1314 } 1315 azalia_mixer_set(this, m->nid, m->target, &mc); 1316 } 1317 1318 /* get default value for play group master */ 1319 for (i = 0; i < this->playvols.nslaves; i++) { 1320 if (!(this->playvols.cur & (1 << i))) 1321 continue; 1322 w = &this->w[this->playvols.slaves[i]]; 1323 if (!(COP_AMPCAP_NUMSTEPS(w->outamp_cap))) 1324 continue; 1325 mc.type = AUDIO_MIXER_VALUE; 1326 tgt = MI_TARGET_OUTAMP; 1327 azalia_mixer_get(this, w->nid, tgt, &mc); 1328 this->playvols.vol_l = mc.un.value.level[0]; 1329 this->playvols.vol_r = mc.un.value.level[0]; 1330 break; 1331 } 1332 this->playvols.mute = 0; 1333 1334 /* get default value for record group master */ 1335 for (i = 0; i < this->recvols.nslaves; i++) { 1336 if (!(this->recvols.cur & (1 << i))) 1337 continue; 1338 w = &this->w[this->recvols.slaves[i]]; 1339 mc.type = AUDIO_MIXER_VALUE; 1340 tgt = MI_TARGET_OUTAMP; 1341 cap = w->outamp_cap; 1342 if (w->type == COP_AWTYPE_PIN_COMPLEX || 1343 w->type == COP_AWTYPE_AUDIO_INPUT) { 1344 tgt = 0; 1345 cap = w->inamp_cap; 1346 } 1347 if (!(COP_AMPCAP_NUMSTEPS(cap))) 1348 continue; 1349 azalia_mixer_get(this, w->nid, tgt, &mc); 1350 this->recvols.vol_l = mc.un.value.level[0]; 1351 this->recvols.vol_r = mc.un.value.level[0]; 1352 break; 1353 } 1354 this->recvols.mute = 0; 1355 1356 err = azalia_codec_enable_unsol(this); 1357 if (err) 1358 return(err); 1359 1360 return 0; 1361 } 1362 1363 int 1364 azalia_codec_enable_unsol(codec_t *this) 1365 { 1366 widget_t *w; 1367 uint32_t result; 1368 int i, err; 1369 1370 /* jack sense */ 1371 for (i = 0; i < this->nsense_pins; i++) { 1372 if (this->spkr_muters & (1 << i)) { 1373 azalia_comresp(this, this->sense_pins[i], 1374 CORB_SET_UNSOLICITED_RESPONSE, 1375 CORB_UNSOL_ENABLE | AZ_TAG_SPKR, NULL); 1376 } 1377 } 1378 if (this->spkr_muters != 0) 1379 azalia_unsol_event(this, AZ_TAG_SPKR); 1380 1381 /* volume knob */ 1382 if (this->playvols.master != this->audiofunc) { 1383 1384 w = &this->w[this->playvols.master]; 1385 err = azalia_comresp(this, w->nid, CORB_GET_VOLUME_KNOB, 1386 0, &result); 1387 if (err) 1388 return err; 1389 1390 /* current level */ 1391 this->playvols.hw_step = CORB_VKNOB_VOLUME(result); 1392 this->playvols.hw_nsteps = COP_VKCAP_NUMSTEPS(w->d.volume.cap); 1393 1394 /* indirect mode */ 1395 result &= ~(CORB_VKNOB_DIRECT); 1396 err = azalia_comresp(this, w->nid, CORB_SET_VOLUME_KNOB, 1397 result, NULL); 1398 if (err) 1399 return err; 1400 1401 /* enable unsolicited responses */ 1402 result = CORB_UNSOL_ENABLE | AZ_TAG_PLAYVOL; 1403 err = azalia_comresp(this, w->nid, 1404 CORB_SET_UNSOLICITED_RESPONSE, result, NULL); 1405 if (err) 1406 return err; 1407 } 1408 1409 return 0; 1410 } 1411 1412 int 1413 azalia_mixer_delete(codec_t *this) 1414 { 1415 if (this->mixers != NULL) { 1416 free(this->mixers, M_DEVBUF); 1417 this->mixers = NULL; 1418 } 1419 return 0; 1420 } 1421 1422 /** 1423 * @param mc mc->type must be set by the caller before the call 1424 */ 1425 int 1426 azalia_mixer_get(const codec_t *this, nid_t nid, int target, 1427 mixer_ctrl_t *mc) 1428 { 1429 uint32_t result, cap, value; 1430 nid_t n; 1431 int i, err; 1432 1433 if (mc->type == AUDIO_MIXER_CLASS) { 1434 return(0); 1435 } 1436 1437 /* inamp mute */ 1438 else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) { 1439 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1440 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 1441 MI_TARGET_INAMP(target), &result); 1442 if (err) 1443 return err; 1444 mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0; 1445 } 1446 1447 /* inamp gain */ 1448 else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) { 1449 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1450 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 1451 MI_TARGET_INAMP(target), &result); 1452 if (err) 1453 return err; 1454 mc->un.value.level[0] = azalia_mixer_from_device_value(this, 1455 nid, target, CORB_GAGM_GAIN(result)); 1456 if (this->w[nid].type == COP_AWTYPE_AUDIO_SELECTOR || 1457 this->w[nid].type == COP_AWTYPE_AUDIO_MIXER) { 1458 n = this->w[nid].connections[MI_TARGET_INAMP(target)]; 1459 if (!azalia_widget_enabled(this, n)) { 1460 DPRINTF(("%s: nid %2.2x invalid index %d\n", 1461 __func__, nid, MI_TARGET_INAMP(target))); 1462 n = nid; 1463 } 1464 } else 1465 n = nid; 1466 mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[n]); 1467 if (mc->un.value.num_channels == 2) { 1468 err = azalia_comresp(this, nid, 1469 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT | 1470 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target), 1471 &result); 1472 if (err) 1473 return err; 1474 mc->un.value.level[1] = azalia_mixer_from_device_value 1475 (this, nid, target, CORB_GAGM_GAIN(result)); 1476 } 1477 } 1478 1479 /* outamp mute */ 1480 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) { 1481 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1482 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result); 1483 if (err) 1484 return err; 1485 mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0; 1486 } 1487 1488 /* outamp gain */ 1489 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) { 1490 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1491 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result); 1492 if (err) 1493 return err; 1494 mc->un.value.level[0] = azalia_mixer_from_device_value(this, 1495 nid, target, CORB_GAGM_GAIN(result)); 1496 mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[nid]); 1497 if (mc->un.value.num_channels == 2) { 1498 err = azalia_comresp(this, nid, 1499 CORB_GET_AMPLIFIER_GAIN_MUTE, 1500 CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT | 0, &result); 1501 if (err) 1502 return err; 1503 mc->un.value.level[1] = azalia_mixer_from_device_value 1504 (this, nid, target, CORB_GAGM_GAIN(result)); 1505 } 1506 } 1507 1508 /* selection */ 1509 else if (target == MI_TARGET_CONNLIST) { 1510 err = azalia_comresp(this, nid, 1511 CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result); 1512 if (err) 1513 return err; 1514 result = CORB_CSC_INDEX(result); 1515 if (!azalia_widget_enabled(this, 1516 this->w[nid].connections[result])) 1517 mc->un.ord = -1; 1518 else 1519 mc->un.ord = result; 1520 } 1521 1522 /* pin I/O */ 1523 else if (target == MI_TARGET_PINDIR) { 1524 err = azalia_comresp(this, nid, 1525 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 1526 if (err) 1527 return err; 1528 1529 value = result; 1530 if (!(result & (CORB_PWC_INPUT | CORB_PWC_OUTPUT))) 1531 mc->un.ord = 0; 1532 else if (result & CORB_PWC_OUTPUT) 1533 mc->un.ord = 1; 1534 else { 1535 cap = COP_PINCAP_VREF(this->w[nid].d.pin.cap); 1536 result &= CORB_PWC_VREF_MASK; 1537 if (result == CORB_PWC_VREF_GND) 1538 mc->un.ord = 3; 1539 else if (result == CORB_PWC_VREF_50) 1540 mc->un.ord = 4; 1541 else if (result == CORB_PWC_VREF_80) 1542 mc->un.ord = 5; 1543 else if (result == CORB_PWC_VREF_100) 1544 mc->un.ord = 6; 1545 else 1546 mc->un.ord = 2; 1547 } 1548 } 1549 1550 /* pin headphone-boost */ 1551 else if (target == MI_TARGET_PINBOOST) { 1552 err = azalia_comresp(this, nid, 1553 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 1554 if (err) 1555 return err; 1556 mc->un.ord = result & CORB_PWC_HEADPHONE ? 1 : 0; 1557 } 1558 1559 /* DAC group selection */ 1560 else if (target == MI_TARGET_DAC) { 1561 mc->un.ord = this->dacs.cur; 1562 } 1563 1564 /* ADC selection */ 1565 else if (target == MI_TARGET_ADC) { 1566 mc->un.ord = this->adcs.cur; 1567 } 1568 1569 /* S/PDIF */ 1570 else if (target == MI_TARGET_SPDIF) { 1571 err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL, 1572 0, &result); 1573 if (err) 1574 return err; 1575 mc->un.mask = result & 0xff & ~(CORB_DCC_DIGEN | CORB_DCC_NAUDIO); 1576 } else if (target == MI_TARGET_SPDIF_CC) { 1577 err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL, 1578 0, &result); 1579 if (err) 1580 return err; 1581 mc->un.value.num_channels = 1; 1582 mc->un.value.level[0] = CORB_DCC_CC(result); 1583 } 1584 1585 /* EAPD */ 1586 else if (target == MI_TARGET_EAPD) { 1587 err = azalia_comresp(this, nid, CORB_GET_EAPD_BTL_ENABLE, 1588 0, &result); 1589 if (err) 1590 return err; 1591 mc->un.ord = result & CORB_EAPD_EAPD ? 1 : 0; 1592 } 1593 1594 /* sense pin */ 1595 else if (target == MI_TARGET_PINSENSE) { 1596 err = azalia_comresp(this, nid, CORB_GET_PIN_SENSE, 1597 0, &result); 1598 if (err) 1599 return err; 1600 mc->un.ord = result & CORB_PS_PRESENCE ? 1 : 0; 1601 } 1602 1603 /* mute set */ 1604 else if (target == MI_TARGET_MUTESET && mc->type == AUDIO_MIXER_SET) { 1605 const widget_t *w; 1606 1607 if (!azalia_widget_enabled(this, nid)) { 1608 DPRINTF(("%s: invalid muteset nid\n")); 1609 return EINVAL; 1610 } 1611 w = &this->w[nid]; 1612 mc->un.mask = 0; 1613 for (i = 0; i < w->nconnections; i++) { 1614 if (!azalia_widget_enabled(this, w->connections[i])) 1615 continue; 1616 err = azalia_comresp(this, nid, 1617 CORB_GET_AMPLIFIER_GAIN_MUTE, 1618 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 1619 MI_TARGET_INAMP(i), &result); 1620 if (err) 1621 return err; 1622 mc->un.mask |= (result & CORB_GAGM_MUTE) ? 0 : (1 << i); 1623 } 1624 } 1625 1626 /* mixer set - show all connections */ 1627 else if (target == MI_TARGET_MIXERSET && mc->type == AUDIO_MIXER_SET) { 1628 const widget_t *w; 1629 1630 if (!azalia_widget_enabled(this, nid)) { 1631 DPRINTF(("%s: invalid mixerset nid\n")); 1632 return EINVAL; 1633 } 1634 w = &this->w[nid]; 1635 mc->un.mask = 0; 1636 for (i = 0; i < w->nconnections; i++) { 1637 if (!azalia_widget_enabled(this, w->connections[i])) 1638 continue; 1639 mc->un.mask |= (1 << i); 1640 } 1641 } 1642 1643 else if (target == MI_TARGET_SENSESET && mc->type == AUDIO_MIXER_SET) { 1644 1645 if (nid == this->speaker) { 1646 mc->un.mask = this->spkr_muters; 1647 } else { 1648 DPRINTF(("%s: invalid senseset nid\n")); 1649 return EINVAL; 1650 } 1651 } 1652 1653 else if (target == MI_TARGET_PLAYVOL) { 1654 1655 if (mc->type == AUDIO_MIXER_VALUE) { 1656 mc->un.value.num_channels = 2; 1657 mc->un.value.level[0] = this->playvols.vol_l; 1658 mc->un.value.level[1] = this->playvols.vol_r; 1659 1660 } else if (mc->type == AUDIO_MIXER_ENUM) { 1661 mc->un.ord = this->playvols.mute; 1662 1663 } else if (mc->type == AUDIO_MIXER_SET) { 1664 mc->un.mask = this->playvols.cur; 1665 1666 } else { 1667 DPRINTF(("%s: invalid outmaster mixer type\n")); 1668 return EINVAL; 1669 } 1670 } 1671 1672 else if (target == MI_TARGET_RECVOL) { 1673 1674 if (mc->type == AUDIO_MIXER_VALUE) { 1675 mc->un.value.num_channels = 2; 1676 mc->un.value.level[0] = this->recvols.vol_l; 1677 mc->un.value.level[1] = this->recvols.vol_r; 1678 1679 } else if (mc->type == AUDIO_MIXER_ENUM) { 1680 mc->un.ord = this->recvols.mute; 1681 1682 } else if (mc->type == AUDIO_MIXER_SET) { 1683 mc->un.mask = this->recvols.cur; 1684 1685 } else { 1686 DPRINTF(("%s: invalid inmaster mixer type\n")); 1687 return EINVAL; 1688 } 1689 } 1690 1691 else { 1692 printf("%s: internal error in %s: target=%x\n", 1693 XNAME(this), __func__, target); 1694 return -1; 1695 } 1696 return 0; 1697 } 1698 1699 int 1700 azalia_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc) 1701 { 1702 uint32_t result, value; 1703 int i, err; 1704 1705 if (mc->type == AUDIO_MIXER_CLASS) { 1706 return(0); 1707 } 1708 1709 /* inamp mute */ 1710 else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) { 1711 /* set stereo mute separately to keep each gain value */ 1712 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1713 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 1714 MI_TARGET_INAMP(target), &result); 1715 if (err) 1716 return err; 1717 value = CORB_AGM_INPUT | CORB_AGM_LEFT | 1718 (target << CORB_AGM_INDEX_SHIFT) | 1719 CORB_GAGM_GAIN(result); 1720 if (mc->un.ord) 1721 value |= CORB_AGM_MUTE; 1722 err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE, 1723 value, &result); 1724 if (err) 1725 return err; 1726 if (WIDGET_CHANNELS(&this->w[nid]) == 2) { 1727 err = azalia_comresp(this, nid, 1728 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT | 1729 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target), 1730 &result); 1731 if (err) 1732 return err; 1733 value = CORB_AGM_INPUT | CORB_AGM_RIGHT | 1734 (target << CORB_AGM_INDEX_SHIFT) | 1735 CORB_GAGM_GAIN(result); 1736 if (mc->un.ord) 1737 value |= CORB_AGM_MUTE; 1738 err = azalia_comresp(this, nid, 1739 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 1740 if (err) 1741 return err; 1742 } 1743 } 1744 1745 /* inamp gain */ 1746 else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) { 1747 if (mc->un.value.num_channels < 1) 1748 return EINVAL; 1749 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1750 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 1751 MI_TARGET_INAMP(target), &result); 1752 if (err) 1753 return err; 1754 value = azalia_mixer_to_device_value(this, nid, target, 1755 mc->un.value.level[0]); 1756 value = CORB_AGM_INPUT | CORB_AGM_LEFT | 1757 (target << CORB_AGM_INDEX_SHIFT) | 1758 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) | 1759 (value & CORB_AGM_GAIN_MASK); 1760 err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE, 1761 value, &result); 1762 if (err) 1763 return err; 1764 if (mc->un.value.num_channels >= 2 && 1765 WIDGET_CHANNELS(&this->w[nid]) == 2) { 1766 err = azalia_comresp(this, nid, 1767 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT | 1768 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target), 1769 &result); 1770 if (err) 1771 return err; 1772 value = azalia_mixer_to_device_value(this, nid, target, 1773 mc->un.value.level[1]); 1774 value = CORB_AGM_INPUT | CORB_AGM_RIGHT | 1775 (target << CORB_AGM_INDEX_SHIFT) | 1776 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) | 1777 (value & CORB_AGM_GAIN_MASK); 1778 err = azalia_comresp(this, nid, 1779 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 1780 if (err) 1781 return err; 1782 } 1783 } 1784 1785 /* outamp mute */ 1786 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) { 1787 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1788 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result); 1789 if (err) 1790 return err; 1791 value = CORB_AGM_OUTPUT | CORB_AGM_LEFT | CORB_GAGM_GAIN(result); 1792 if (mc->un.ord) 1793 value |= CORB_AGM_MUTE; 1794 err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE, 1795 value, &result); 1796 if (err) 1797 return err; 1798 if (WIDGET_CHANNELS(&this->w[nid]) == 2) { 1799 err = azalia_comresp(this, nid, 1800 CORB_GET_AMPLIFIER_GAIN_MUTE, 1801 CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT, &result); 1802 if (err) 1803 return err; 1804 value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT | 1805 CORB_GAGM_GAIN(result); 1806 if (mc->un.ord) 1807 value |= CORB_AGM_MUTE; 1808 err = azalia_comresp(this, nid, 1809 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 1810 if (err) 1811 return err; 1812 } 1813 } 1814 1815 /* outamp gain */ 1816 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) { 1817 if (mc->un.value.num_channels < 1) 1818 return EINVAL; 1819 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1820 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result); 1821 if (err) 1822 return err; 1823 value = azalia_mixer_to_device_value(this, nid, target, 1824 mc->un.value.level[0]); 1825 value = CORB_AGM_OUTPUT | CORB_AGM_LEFT | 1826 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) | 1827 (value & CORB_AGM_GAIN_MASK); 1828 err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE, 1829 value, &result); 1830 if (err) 1831 return err; 1832 if (mc->un.value.num_channels >= 2 && 1833 WIDGET_CHANNELS(&this->w[nid]) == 2) { 1834 err = azalia_comresp(this, nid, 1835 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_OUTPUT | 1836 CORB_GAGM_RIGHT, &result); 1837 if (err) 1838 return err; 1839 value = azalia_mixer_to_device_value(this, nid, target, 1840 mc->un.value.level[1]); 1841 value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT | 1842 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) | 1843 (value & CORB_AGM_GAIN_MASK); 1844 err = azalia_comresp(this, nid, 1845 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 1846 if (err) 1847 return err; 1848 } 1849 } 1850 1851 /* selection */ 1852 else if (target == MI_TARGET_CONNLIST) { 1853 if (mc->un.ord < 0 || 1854 mc->un.ord >= this->w[nid].nconnections || 1855 !azalia_widget_enabled(this, 1856 this->w[nid].connections[mc->un.ord])) 1857 return EINVAL; 1858 err = azalia_comresp(this, nid, 1859 CORB_SET_CONNECTION_SELECT_CONTROL, mc->un.ord, &result); 1860 if (err) 1861 return err; 1862 } 1863 1864 /* pin I/O */ 1865 else if (target == MI_TARGET_PINDIR) { 1866 1867 err = azalia_comresp(this, nid, 1868 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 1869 if (err) 1870 return err; 1871 1872 value = result; 1873 value &= ~(CORB_PWC_VREF_MASK); 1874 if (mc->un.ord == 0) { 1875 value &= ~(CORB_PWC_OUTPUT | CORB_PWC_INPUT); 1876 } else if (mc->un.ord == 1) { 1877 value &= ~CORB_PWC_INPUT; 1878 value |= CORB_PWC_OUTPUT; 1879 if (this->qrks & AZ_QRK_WID_OVREF50) 1880 value |= CORB_PWC_VREF_50; 1881 } else { 1882 value &= ~CORB_PWC_OUTPUT; 1883 value |= CORB_PWC_INPUT; 1884 1885 if (mc->un.ord == 3) 1886 value |= CORB_PWC_VREF_GND; 1887 if (mc->un.ord == 4) 1888 value |= CORB_PWC_VREF_50; 1889 if (mc->un.ord == 5) 1890 value |= CORB_PWC_VREF_80; 1891 if (mc->un.ord == 6) 1892 value |= CORB_PWC_VREF_100; 1893 } 1894 err = azalia_comresp(this, nid, 1895 CORB_SET_PIN_WIDGET_CONTROL, value, &result); 1896 if (err) 1897 return err; 1898 1899 /* Run the unsolicited response handler for speaker mute 1900 * since it depends on pin direction. 1901 */ 1902 for (i = 0; i < this->nsense_pins; i++) { 1903 if (this->sense_pins[i] == nid) 1904 break; 1905 } 1906 if (i < this->nsense_pins) { 1907 azalia_unsol_event(this, AZ_TAG_SPKR); 1908 } 1909 } 1910 1911 /* pin headphone-boost */ 1912 else if (target == MI_TARGET_PINBOOST) { 1913 if (mc->un.ord >= 2) 1914 return EINVAL; 1915 err = azalia_comresp(this, nid, 1916 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 1917 if (err) 1918 return err; 1919 if (mc->un.ord == 0) { 1920 result &= ~CORB_PWC_HEADPHONE; 1921 } else { 1922 result |= CORB_PWC_HEADPHONE; 1923 } 1924 err = azalia_comresp(this, nid, 1925 CORB_SET_PIN_WIDGET_CONTROL, result, &result); 1926 if (err) 1927 return err; 1928 } 1929 1930 /* DAC group selection */ 1931 else if (target == MI_TARGET_DAC) { 1932 if (this->running) 1933 return EBUSY; 1934 if (mc->un.ord >= this->dacs.ngroups) 1935 return EINVAL; 1936 if (mc->un.ord != this->dacs.cur) 1937 return azalia_codec_construct_format(this, 1938 mc->un.ord, this->adcs.cur); 1939 else 1940 return 0; 1941 } 1942 1943 /* ADC selection */ 1944 else if (target == MI_TARGET_ADC) { 1945 if (this->running) 1946 return EBUSY; 1947 if (mc->un.ord >= this->adcs.ngroups) 1948 return EINVAL; 1949 if (mc->un.ord != this->adcs.cur) 1950 return azalia_codec_construct_format(this, 1951 this->dacs.cur, mc->un.ord); 1952 else 1953 return 0; 1954 } 1955 1956 /* S/PDIF */ 1957 else if (target == MI_TARGET_SPDIF) { 1958 err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL, 1959 0, &result); 1960 result &= CORB_DCC_DIGEN | CORB_DCC_NAUDIO; 1961 result |= mc->un.mask & 0xff & ~CORB_DCC_DIGEN; 1962 err = azalia_comresp(this, nid, CORB_SET_DIGITAL_CONTROL_L, 1963 result, NULL); 1964 if (err) 1965 return err; 1966 } else if (target == MI_TARGET_SPDIF_CC) { 1967 if (mc->un.value.num_channels != 1) 1968 return EINVAL; 1969 if (mc->un.value.level[0] > 127) 1970 return EINVAL; 1971 err = azalia_comresp(this, nid, CORB_SET_DIGITAL_CONTROL_H, 1972 mc->un.value.level[0], NULL); 1973 if (err) 1974 return err; 1975 } 1976 1977 /* EAPD */ 1978 else if (target == MI_TARGET_EAPD) { 1979 if (mc->un.ord >= 2) 1980 return EINVAL; 1981 err = azalia_comresp(this, nid, 1982 CORB_GET_EAPD_BTL_ENABLE, 0, &result); 1983 if (err) 1984 return err; 1985 result &= 0xff; 1986 if (mc->un.ord == 0) { 1987 result &= ~CORB_EAPD_EAPD; 1988 } else { 1989 result |= CORB_EAPD_EAPD; 1990 } 1991 err = azalia_comresp(this, nid, 1992 CORB_SET_EAPD_BTL_ENABLE, result, &result); 1993 if (err) 1994 return err; 1995 } 1996 1997 else if (target == MI_TARGET_PINSENSE) { 1998 /* do nothing, control is read only */ 1999 } 2000 2001 else if (target == MI_TARGET_MUTESET && mc->type == AUDIO_MIXER_SET) { 2002 const widget_t *w; 2003 2004 if (!azalia_widget_enabled(this, nid)) { 2005 DPRINTF(("%s: invalid muteset nid\n")); 2006 return EINVAL; 2007 } 2008 w = &this->w[nid]; 2009 for (i = 0; i < w->nconnections; i++) { 2010 if (!azalia_widget_enabled(this, w->connections[i])) 2011 continue; 2012 2013 /* We have to set stereo mute separately 2014 * to keep each gain value. 2015 */ 2016 err = azalia_comresp(this, nid, 2017 CORB_GET_AMPLIFIER_GAIN_MUTE, 2018 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 2019 MI_TARGET_INAMP(i), &result); 2020 if (err) 2021 return err; 2022 value = CORB_AGM_INPUT | CORB_AGM_LEFT | 2023 (i << CORB_AGM_INDEX_SHIFT) | 2024 CORB_GAGM_GAIN(result); 2025 if ((mc->un.mask & (1 << i)) == 0) 2026 value |= CORB_AGM_MUTE; 2027 err = azalia_comresp(this, nid, 2028 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 2029 if (err) 2030 return err; 2031 2032 if (WIDGET_CHANNELS(w) == 2) { 2033 err = azalia_comresp(this, nid, 2034 CORB_GET_AMPLIFIER_GAIN_MUTE, 2035 CORB_GAGM_INPUT | CORB_GAGM_RIGHT | 2036 MI_TARGET_INAMP(i), &result); 2037 if (err) 2038 return err; 2039 value = CORB_AGM_INPUT | CORB_AGM_RIGHT | 2040 (i << CORB_AGM_INDEX_SHIFT) | 2041 CORB_GAGM_GAIN(result); 2042 if ((mc->un.mask & (1 << i)) == 0) 2043 value |= CORB_AGM_MUTE; 2044 err = azalia_comresp(this, nid, 2045 CORB_SET_AMPLIFIER_GAIN_MUTE, 2046 value, &result); 2047 if (err) 2048 return err; 2049 } 2050 } 2051 } 2052 2053 else if (target == MI_TARGET_MIXERSET && mc->type == AUDIO_MIXER_SET) { 2054 /* do nothing, control is read only */ 2055 } 2056 2057 else if (target == MI_TARGET_SENSESET && mc->type == AUDIO_MIXER_SET) { 2058 2059 if (nid == this->speaker) { 2060 this->spkr_muters = mc->un.mask; 2061 azalia_unsol_event(this, AZ_TAG_SPKR); 2062 } else { 2063 DPRINTF(("%s: invalid senseset nid\n")); 2064 return EINVAL; 2065 } 2066 } 2067 2068 else if (target == MI_TARGET_PLAYVOL) { 2069 2070 const widget_t *w; 2071 mixer_ctrl_t mc2; 2072 2073 if (mc->type == AUDIO_MIXER_VALUE) { 2074 if (mc->un.value.num_channels != 2) 2075 return EINVAL; 2076 this->playvols.vol_l = mc->un.value.level[0]; 2077 this->playvols.vol_r = mc->un.value.level[1]; 2078 for (i = 0; i < this->playvols.nslaves; i++) { 2079 if (!(this->playvols.cur & (1 << i))) 2080 continue; 2081 w = &this->w[this->playvols.slaves[i]]; 2082 if (!(COP_AMPCAP_NUMSTEPS(w->outamp_cap))) 2083 continue; 2084 2085 /* don't change volume if muted */ 2086 if (w->outamp_cap & COP_AMPCAP_MUTE) { 2087 mc2.type = AUDIO_MIXER_ENUM; 2088 azalia_mixer_get(this, w->nid, 2089 MI_TARGET_OUTAMP, &mc2); 2090 if (mc2.un.ord) 2091 continue; 2092 } 2093 mc2.type = AUDIO_MIXER_VALUE; 2094 mc2.un.value.num_channels = WIDGET_CHANNELS(w); 2095 mc2.un.value.level[0] = this->playvols.vol_l; 2096 mc2.un.value.level[1] = this->playvols.vol_r; 2097 err = azalia_mixer_set(this, w->nid, 2098 MI_TARGET_OUTAMP, &mc2); 2099 if (err) { 2100 DPRINTF(("%s: out slave %2.2x vol\n", 2101 __func__, w->nid)); 2102 return err; 2103 } 2104 } 2105 } else if (mc->type == AUDIO_MIXER_ENUM) { 2106 if (mc->un.ord != 0 && mc->un.ord != 1) 2107 return EINVAL; 2108 this->playvols.mute = mc->un.ord; 2109 for (i = 0; i < this->playvols.nslaves; i++) { 2110 if (!(this->playvols.cur & (1 << i))) 2111 continue; 2112 w = &this->w[this->playvols.slaves[i]]; 2113 if (!(w->outamp_cap & COP_AMPCAP_MUTE)) 2114 continue; 2115 mc2.type = AUDIO_MIXER_ENUM; 2116 mc2.un.ord = this->playvols.mute; 2117 err = azalia_mixer_set(this, w->nid, 2118 MI_TARGET_OUTAMP, &mc2); 2119 if (err) { 2120 DPRINTF(("%s: out slave %2.2x mute\n", 2121 __func__, w->nid)); 2122 return err; 2123 } 2124 } 2125 2126 } else if (mc->type == AUDIO_MIXER_SET) { 2127 this->playvols.cur = 2128 (mc->un.mask & this->playvols.mask); 2129 2130 } else { 2131 DPRINTF(("%s: invalid output master mixer type\n")); 2132 return EINVAL; 2133 } 2134 } 2135 2136 else if (target == MI_TARGET_RECVOL) { 2137 2138 const widget_t *w; 2139 mixer_ctrl_t mc2; 2140 uint32_t cap; 2141 int tgt; 2142 2143 if (mc->type == AUDIO_MIXER_VALUE) { 2144 if (mc->un.value.num_channels != 2) 2145 return EINVAL; 2146 this->recvols.vol_l = mc->un.value.level[0]; 2147 this->recvols.vol_r = mc->un.value.level[1]; 2148 for (i = 0; i < this->recvols.nslaves; i++) { 2149 if (!(this->recvols.cur & (1 << i))) 2150 continue; 2151 w = &this->w[this->recvols.slaves[i]]; 2152 tgt = MI_TARGET_OUTAMP; 2153 cap = w->outamp_cap; 2154 if (w->type == COP_AWTYPE_AUDIO_INPUT || 2155 w->type == COP_AWTYPE_PIN_COMPLEX) { 2156 tgt = 0; 2157 cap = w->inamp_cap; 2158 } 2159 if (!(COP_AMPCAP_NUMSTEPS(cap))) 2160 continue; 2161 mc2.type = AUDIO_MIXER_VALUE; 2162 mc2.un.value.num_channels = WIDGET_CHANNELS(w); 2163 mc2.un.value.level[0] = this->recvols.vol_l; 2164 mc2.un.value.level[1] = this->recvols.vol_r; 2165 err = azalia_mixer_set(this, w->nid, 2166 tgt, &mc2); 2167 if (err) { 2168 DPRINTF(("%s: in slave %2.2x vol\n", 2169 __func__, w->nid)); 2170 return err; 2171 } 2172 } 2173 } else if (mc->type == AUDIO_MIXER_ENUM) { 2174 if (mc->un.ord != 0 && mc->un.ord != 1) 2175 return EINVAL; 2176 this->recvols.mute = mc->un.ord; 2177 for (i = 0; i < this->recvols.nslaves; i++) { 2178 if (!(this->recvols.cur & (1 << i))) 2179 continue; 2180 w = &this->w[this->recvols.slaves[i]]; 2181 tgt = MI_TARGET_OUTAMP; 2182 cap = w->outamp_cap; 2183 if (w->type == COP_AWTYPE_AUDIO_INPUT || 2184 w->type == COP_AWTYPE_PIN_COMPLEX) { 2185 tgt = 0; 2186 cap = w->inamp_cap; 2187 } 2188 if (!(cap & COP_AMPCAP_MUTE)) 2189 continue; 2190 mc2.type = AUDIO_MIXER_ENUM; 2191 mc2.un.ord = this->recvols.mute; 2192 err = azalia_mixer_set(this, w->nid, 2193 tgt, &mc2); 2194 if (err) { 2195 DPRINTF(("%s: out slave %2.2x mute\n", 2196 __func__, w->nid)); 2197 return err; 2198 } 2199 } 2200 2201 } else if (mc->type == AUDIO_MIXER_SET) { 2202 this->recvols.cur = (mc->un.mask & this->recvols.mask); 2203 2204 } else { 2205 DPRINTF(("%s: invalid input master mixer type\n")); 2206 return EINVAL; 2207 } 2208 } 2209 2210 else { 2211 printf("%s: internal error in %s: target=%x\n", 2212 XNAME(this), __func__, target); 2213 return -1; 2214 } 2215 return 0; 2216 } 2217 2218 u_char 2219 azalia_mixer_from_device_value(const codec_t *this, nid_t nid, int target, 2220 uint32_t dv) 2221 { 2222 uint32_t steps; 2223 int max_gain, ctloff; 2224 2225 if (IS_MI_TARGET_INAMP(target)) { 2226 steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); 2227 ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap); 2228 } else if (target == MI_TARGET_OUTAMP) { 2229 steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); 2230 ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap); 2231 } else { 2232 printf("%s: unknown target: %d\n", __func__, target); 2233 steps = 255; 2234 } 2235 dv -= ctloff; 2236 if (dv <= 0 || steps == 0) 2237 return(AUDIO_MIN_GAIN); 2238 max_gain = AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % steps; 2239 if (dv >= steps) 2240 return(max_gain); 2241 return(dv * max_gain / steps); 2242 } 2243 2244 uint32_t 2245 azalia_mixer_to_device_value(const codec_t *this, nid_t nid, int target, 2246 u_char uv) 2247 { 2248 uint32_t steps; 2249 int max_gain, ctloff; 2250 2251 if (IS_MI_TARGET_INAMP(target)) { 2252 steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); 2253 ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap); 2254 } else if (target == MI_TARGET_OUTAMP) { 2255 steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); 2256 ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap); 2257 } else { 2258 printf("%s: unknown target: %d\n", __func__, target); 2259 steps = 255; 2260 } 2261 if (uv <= AUDIO_MIN_GAIN || steps == 0) 2262 return(ctloff); 2263 max_gain = AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % steps; 2264 if (uv >= max_gain) 2265 return(steps + ctloff); 2266 return(uv * steps / max_gain + ctloff); 2267 } 2268 2269 int 2270 azalia_gpio_unmute(codec_t *this, int pin) 2271 { 2272 uint32_t data, mask, dir; 2273 2274 azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_DATA, 0, &data); 2275 azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_ENABLE_MASK, 0, &mask); 2276 azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_DIRECTION, 0, &dir); 2277 2278 data |= 1 << pin; 2279 mask |= 1 << pin; 2280 dir |= 1 << pin; 2281 2282 azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_ENABLE_MASK, mask, NULL); 2283 azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_DIRECTION, dir, NULL); 2284 DELAY(1000); 2285 azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_DATA, data, NULL); 2286 2287 return 0; 2288 } 2289 2290 void 2291 azalia_ampcap_ov(widget_t *w, int type, int offset, int steps, int size, 2292 int ctloff, int mute) 2293 { 2294 uint32_t cap; 2295 2296 cap = (offset & 0x7f) | ((steps & 0x7f) << 8) | 2297 ((size & 0x7f) << 16) | ((ctloff & 0x7f) << 24) | 2298 (mute ? COP_AMPCAP_MUTE : 0); 2299 2300 if (type == COP_OUTPUT_AMPCAP) { 2301 w->outamp_cap = cap; 2302 } else if (type == COP_INPUT_AMPCAP) { 2303 w->inamp_cap = cap; 2304 } 2305 } 2306 2307 void 2308 azalia_pin_config_ov(widget_t *w, int mask, int val) 2309 { 2310 int bits, offset; 2311 2312 switch (mask) { 2313 case CORB_CD_DEVICE_MASK: 2314 bits = CORB_CD_DEVICE_BITS; 2315 offset = CORB_CD_DEVICE_OFFSET; 2316 break; 2317 case CORB_CD_PORT_MASK: 2318 bits = CORB_CD_PORT_BITS; 2319 offset = CORB_CD_PORT_OFFSET; 2320 break; 2321 default: 2322 return; 2323 } 2324 val &= bits; 2325 w->d.pin.config &= ~(mask); 2326 w->d.pin.config |= val << offset; 2327 if (mask == CORB_CD_DEVICE_MASK) 2328 w->d.pin.device = val; 2329 } 2330 2331 int 2332 azalia_codec_gpio_quirks(codec_t *this) 2333 { 2334 if (this->qrks & AZ_QRK_GPIO_POL_0) { 2335 azalia_comresp(this, this->audiofunc, 2336 CORB_SET_GPIO_POLARITY, 0, NULL); 2337 } 2338 if (this->qrks & AZ_QRK_GPIO_UNMUTE_0) { 2339 azalia_gpio_unmute(this, 0); 2340 } 2341 if (this->qrks & AZ_QRK_GPIO_UNMUTE_1) { 2342 azalia_gpio_unmute(this, 1); 2343 } 2344 if (this->qrks & AZ_QRK_GPIO_UNMUTE_2) { 2345 azalia_gpio_unmute(this, 2); 2346 } 2347 2348 return(0); 2349 } 2350 2351 int 2352 azalia_codec_widget_quirks(codec_t *this, nid_t nid) 2353 { 2354 widget_t *w; 2355 2356 w = &this->w[nid]; 2357 2358 if (this->qrks & AZ_QRK_WID_BEEP_1D && 2359 nid == 0x1d && w->enable == 0) { 2360 azalia_pin_config_ov(w, CORB_CD_DEVICE_MASK, CORB_CD_BEEP); 2361 azalia_pin_config_ov(w, CORB_CD_PORT_MASK, CORB_CD_FIXED); 2362 w->widgetcap |= COP_AWCAP_STEREO; 2363 w->enable = 1; 2364 } 2365 2366 if (this->qrks & AZ_QRK_WID_CDIN_1C && 2367 nid == 0x1c && w->enable == 0 && w->d.pin.device == CORB_CD_CD) { 2368 azalia_pin_config_ov(w, CORB_CD_PORT_MASK, CORB_CD_FIXED); 2369 w->widgetcap |= COP_AWCAP_STEREO; 2370 w->enable = 1; 2371 } 2372 2373 if ((this->qrks & AZ_QRK_WID_AD1981_OAMP) && 2374 ((nid == 0x05) || (nid == 0x06) || (nid == 0x07) || 2375 (nid == 0x09) || (nid == 0x18))) { 2376 azalia_ampcap_ov(w, COP_OUTPUT_AMPCAP, 31, 33, 6, 30, 1); 2377 } 2378 2379 return(0); 2380 } 2381