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