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