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