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