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