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