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