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