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