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