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