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