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