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