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