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