Annotation of sys/dev/pci/azalia_codec.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: azalia_codec.c,v 1.29 2007/07/31 17:06:25 deanna 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: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/cdefs.h>
! 41: #ifdef NETBSD_GOOP
! 42: __KERNEL_RCSID(0, "$NetBSD: azalia_codec.c,v 1.3 2005/09/29 04:14:03 kent Exp $");
! 43: #endif
! 44:
! 45: #include <sys/param.h>
! 46: #include <sys/device.h>
! 47: #include <sys/malloc.h>
! 48: #include <sys/systm.h>
! 49: #include <uvm/uvm_param.h>
! 50: #include <dev/pci/azalia.h>
! 51:
! 52: #define XNAME(co) (((struct device *)co->az)->dv_xname)
! 53: #ifdef MAX_VOLUME_255
! 54: # define MIXER_DELTA(n) (AUDIO_MAX_GAIN / (n))
! 55: #else
! 56: # define MIXER_DELTA(n) (1)
! 57: #endif
! 58: #define AZ_CLASS_INPUT 0
! 59: #define AZ_CLASS_OUTPUT 1
! 60: #define AZ_CLASS_RECORD 2
! 61: #define ENUM_OFFON .un.e={2, {{{AudioNoff}, 0}, {{AudioNon}, 1}}}
! 62: #define ENUM_IO .un.e={2, {{{"input"}, 0}, {{"output"}, 1}}}
! 63: #define AzaliaNfront "front"
! 64: #define AzaliaNclfe "clfe"
! 65: #define AzaliaNside "side"
! 66:
! 67:
! 68: int azalia_generic_codec_init_dacgroup(codec_t *);
! 69: int azalia_generic_codec_add_dacgroup(codec_t *, int, uint32_t);
! 70: int azalia_generic_codec_find_pin(const codec_t *, int, int, uint32_t);
! 71: int azalia_generic_codec_find_dac(const codec_t *, int, int);
! 72:
! 73: int azalia_generic_mixer_init(codec_t *);
! 74: int azalia_generic_mixer_fix_indexes(codec_t *);
! 75: int azalia_generic_mixer_default(codec_t *);
! 76: int azalia_generic_mixer_delete(codec_t *);
! 77: int azalia_generic_mixer_ensure_capacity(codec_t *, size_t);
! 78: int azalia_generic_mixer_get(const codec_t *, nid_t, int, mixer_ctrl_t *);
! 79: int azalia_generic_mixer_set(codec_t *, nid_t, int, const mixer_ctrl_t *);
! 80: int azalia_generic_mixer_pinctrl(codec_t *, nid_t, uint32_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: uint32_t azalia_generic_mixer_max(const codec_t *, nid_t, int);
! 86: boolean_t azalia_generic_mixer_validate_value
! 87: (const codec_t *, nid_t, int, u_char);
! 88: int azalia_generic_set_port(codec_t *, mixer_ctrl_t *);
! 89: int azalia_generic_get_port(codec_t *, mixer_ctrl_t *);
! 90:
! 91: int azalia_alc260_init_dacgroup(codec_t *);
! 92: int azalia_alc260_mixer_init(codec_t *);
! 93: int azalia_alc260_set_port(codec_t *, mixer_ctrl_t *);
! 94: int azalia_alc880_init_dacgroup(codec_t *);
! 95: int azalia_alc882_init_dacgroup(codec_t *);
! 96: int azalia_alc882_mixer_init(codec_t *);
! 97: int azalia_alc882_set_port(codec_t *, mixer_ctrl_t *);
! 98: int azalia_alc882_get_port(codec_t *, mixer_ctrl_t *);
! 99: int azalia_alc883_init_dacgroup(codec_t *);
! 100: int azalia_alc883_mixer_init(codec_t *);
! 101: int azalia_ad1981hd_init_widget(const codec_t *, widget_t *, nid_t);
! 102: int azalia_ad1981hd_mixer_init(codec_t *);
! 103: int azalia_cmi9880_init_dacgroup(codec_t *);
! 104: int azalia_cmi9880_mixer_init(codec_t *);
! 105: int azalia_stac9221_init_dacgroup(codec_t *);
! 106: int azalia_stac9200_mixer_init(codec_t *);
! 107: int azalia_stac9200_unsol_event(codec_t *, int);
! 108: int azalia_stac9221_apple_mixer_init(codec_t *);
! 109: int azalia_stac9221_apple_init_dacgroup(codec_t *);
! 110: int azalia_stac9221_gpio_unmute(codec_t *, int);
! 111: int azalia_stac7661_init_dacgroup(codec_t *);
! 112: int azalia_stac7661_mixer_init(codec_t *);
! 113: int azalia_stac7661_set_port(codec_t *, mixer_ctrl_t *);
! 114: int azalia_stac7661_get_port(codec_t *, mixer_ctrl_t *);
! 115:
! 116: int
! 117: azalia_codec_init_vtbl(codec_t *this)
! 118: {
! 119: /**
! 120: * We can refer this->vid and this->subid.
! 121: */
! 122: DPRINTF(("%s: vid=%08x subid=%08x\n", __func__, this->vid, this->subid));
! 123: this->name = NULL;
! 124: this->init_dacgroup = azalia_generic_codec_init_dacgroup;
! 125: this->mixer_init = azalia_generic_mixer_init;
! 126: this->mixer_delete = azalia_generic_mixer_delete;
! 127: this->set_port = azalia_generic_set_port;
! 128: this->get_port = azalia_generic_get_port;
! 129: switch (this->vid) {
! 130: case 0x10ec0260:
! 131: this->name = "Realtek ALC260";
! 132: this->mixer_init = azalia_alc260_mixer_init;
! 133: this->init_dacgroup = azalia_alc260_init_dacgroup;
! 134: this->set_port = azalia_alc260_set_port;
! 135: break;
! 136: case 0x10ec0880:
! 137: this->name = "Realtek ALC880";
! 138: this->init_dacgroup = azalia_alc880_init_dacgroup;
! 139: break;
! 140: case 0x10ec0882:
! 141: this->name = "Realtek ALC882";
! 142: this->init_dacgroup = azalia_alc882_init_dacgroup;
! 143: this->mixer_init = azalia_alc882_mixer_init;
! 144: this->get_port = azalia_alc882_get_port;
! 145: this->set_port = azalia_alc882_set_port;
! 146: break;
! 147: case 0x10ec0883:
! 148: /* ftp://209.216.61.149/pc/audio/ALC883_DataSheet_1.3.pdf */
! 149: this->name = "Realtek ALC883";
! 150: this->init_dacgroup = azalia_alc883_init_dacgroup;
! 151: this->mixer_init = azalia_alc883_mixer_init;
! 152: this->get_port = azalia_alc882_get_port;
! 153: this->set_port = azalia_alc882_set_port;
! 154: break;
! 155: case 0x11d41981:
! 156: /* http://www.analog.com/en/prod/0,2877,AD1981HD,00.html */
! 157: this->name = "Analog Devices AD1981HD";
! 158: this->init_widget = azalia_ad1981hd_init_widget;
! 159: this->mixer_init = azalia_ad1981hd_mixer_init;
! 160: break;
! 161: case 0x11d41983:
! 162: /* http://www.analog.com/en/prod/0,2877,AD1983,00.html */
! 163: this->name = "Analog Devices AD1983";
! 164: break;
! 165: case 0x434d4980:
! 166: this->name = "CMedia CMI9880";
! 167: this->init_dacgroup = azalia_cmi9880_init_dacgroup;
! 168: this->mixer_init = azalia_cmi9880_mixer_init;
! 169: break;
! 170: case 0x83847680:
! 171: this->name = "Sigmatel STAC9221";
! 172: this->init_dacgroup = azalia_stac9221_init_dacgroup;
! 173: if (this->subid == 0x76808384) {
! 174: this->init_dacgroup =
! 175: azalia_stac9221_apple_init_dacgroup;
! 176: this->mixer_init =
! 177: azalia_stac9221_apple_mixer_init;
! 178: break;
! 179: }
! 180: break;
! 181: case 0x83847683:
! 182: this->name = "Sigmatel STAC9221D";
! 183: this->init_dacgroup = azalia_stac9221_init_dacgroup;
! 184: break;
! 185: case 0x83847690:
! 186: /* http://www.idt.com/products/getDoc.cfm?docID=17812077 */
! 187: this->name = "Sigmatel STAC9200";
! 188: this->mixer_init = azalia_stac9200_mixer_init;
! 189: this->unsol_event = azalia_stac9200_unsol_event;
! 190: break;
! 191: case 0x83847691:
! 192: this->name = "Sigmatel STAC9200D";
! 193: break;
! 194: case 0x83847661:
! 195: this->name = "Sigmatel 83847661";
! 196: this->init_dacgroup = azalia_stac7661_init_dacgroup;
! 197: this->mixer_init = azalia_stac7661_mixer_init;
! 198: this->get_port = azalia_stac7661_get_port;
! 199: this->set_port = azalia_stac7661_set_port;
! 200: break;
! 201: }
! 202: return 0;
! 203: }
! 204:
! 205: /* ----------------------------------------------------------------
! 206: * functions for generic codecs
! 207: * ---------------------------------------------------------------- */
! 208:
! 209: int
! 210: azalia_generic_codec_init_dacgroup(codec_t *this)
! 211: {
! 212: int i, j, assoc, group;
! 213:
! 214: /*
! 215: * grouping DACs
! 216: * [0] the lowest assoc DACs
! 217: * [1] the lowest assoc digital outputs
! 218: * [2] the 2nd assoc DACs
! 219: * :
! 220: */
! 221: this->dacs.ngroups = 0;
! 222: for (assoc = 0; assoc < CORB_CD_ASSOCIATION_MAX; assoc++) {
! 223: azalia_generic_codec_add_dacgroup(this, assoc, 0);
! 224: azalia_generic_codec_add_dacgroup(this, assoc, COP_AWCAP_DIGITAL);
! 225: }
! 226:
! 227: /* find DACs which do not connect with any pins by default */
! 228: DPRINTF(("%s: find non-connected DACs\n", __func__));
! 229: FOR_EACH_WIDGET(this, i) {
! 230: boolean_t found;
! 231:
! 232: if (this->w[i].type != COP_AWTYPE_AUDIO_OUTPUT)
! 233: continue;
! 234: found = FALSE;
! 235: for (group = 0; group < this->dacs.ngroups; group++) {
! 236: for (j = 0; j < this->dacs.groups[group].nconv; j++) {
! 237: if (i == this->dacs.groups[group].conv[j]) {
! 238: found = TRUE;
! 239: group = this->dacs.ngroups;
! 240: break;
! 241: }
! 242: }
! 243: }
! 244: if (found)
! 245: continue;
! 246: if (this->dacs.ngroups >= 32)
! 247: break;
! 248: this->dacs.groups[this->dacs.ngroups].nconv = 1;
! 249: this->dacs.groups[this->dacs.ngroups].conv[0] = i;
! 250: this->dacs.ngroups++;
! 251: }
! 252: this->dacs.cur = 0;
! 253:
! 254: /* enumerate ADCs */
! 255: this->adcs.ngroups = 0;
! 256: FOR_EACH_WIDGET(this, i) {
! 257: if (this->w[i].type != COP_AWTYPE_AUDIO_INPUT)
! 258: continue;
! 259: this->adcs.groups[this->adcs.ngroups].nconv = 1;
! 260: this->adcs.groups[this->adcs.ngroups].conv[0] = i;
! 261: this->adcs.ngroups++;
! 262: if (this->adcs.ngroups >= 32)
! 263: break;
! 264: }
! 265: this->adcs.cur = 0;
! 266: return 0;
! 267: }
! 268:
! 269: int
! 270: azalia_generic_codec_add_dacgroup(codec_t *this, int assoc, uint32_t digital)
! 271: {
! 272: int i, j, n, dac, seq;
! 273:
! 274: n = 0;
! 275: for (seq = 0 ; seq < CORB_CD_SEQUENCE_MAX; seq++) {
! 276: i = azalia_generic_codec_find_pin(this, assoc, seq, digital);
! 277: if (i < 0)
! 278: continue;
! 279: dac = azalia_generic_codec_find_dac(this, i, 0);
! 280: if (dac < 0)
! 281: continue;
! 282: /* duplication check */
! 283: for (j = 0; j < n; j++) {
! 284: if (this->dacs.groups[this->dacs.ngroups].conv[j] == dac)
! 285: break;
! 286: }
! 287: if (j < n) /* this group already has <dac> */
! 288: continue;
! 289: this->dacs.groups[this->dacs.ngroups].conv[n++] = dac;
! 290: DPRINTF(("%s: assoc=%d seq=%d ==> g=%d n=%d\n",
! 291: __func__, assoc, seq, this->dacs.ngroups, n-1));
! 292: }
! 293: if (n <= 0) /* no such DACs */
! 294: return 0;
! 295: this->dacs.groups[this->dacs.ngroups].nconv = n;
! 296:
! 297: /* check if the same combination is already registered */
! 298: for (i = 0; i < this->dacs.ngroups; i++) {
! 299: if (n != this->dacs.groups[i].nconv)
! 300: continue;
! 301: for (j = 0; j < n; j++) {
! 302: if (this->dacs.groups[this->dacs.ngroups].conv[j] !=
! 303: this->dacs.groups[i].conv[j])
! 304: break;
! 305: }
! 306: if (j >= n) /* matched */
! 307: return 0;
! 308: }
! 309: /* found no equivalent group */
! 310: this->dacs.ngroups++;
! 311: return 0;
! 312: }
! 313:
! 314: int
! 315: azalia_generic_codec_find_pin(const codec_t *this, int assoc, int seq, uint32_t digital)
! 316: {
! 317: int i;
! 318:
! 319: FOR_EACH_WIDGET(this, i) {
! 320: if (this->w[i].type != COP_AWTYPE_PIN_COMPLEX)
! 321: continue;
! 322: if ((this->w[i].d.pin.cap & COP_PINCAP_OUTPUT) == 0)
! 323: continue;
! 324: if ((this->w[i].widgetcap & COP_AWCAP_DIGITAL) != digital)
! 325: continue;
! 326: if (this->w[i].d.pin.association != assoc)
! 327: continue;
! 328: if (this->w[i].d.pin.sequence == seq) {
! 329: return i;
! 330: }
! 331: }
! 332: return -1;
! 333: }
! 334:
! 335: int
! 336: azalia_generic_codec_find_dac(const codec_t *this, int index, int depth)
! 337: {
! 338: const widget_t *w;
! 339: int i, j, ret;
! 340:
! 341: w = &this->w[index];
! 342: if (w->type == COP_AWTYPE_AUDIO_OUTPUT) {
! 343: DPRINTF(("%s: DAC: nid=0x%x index=%d\n",
! 344: __func__, w->nid, index));
! 345: return index;
! 346: }
! 347: if (++depth > 50) {
! 348: return -1;
! 349: }
! 350: if (w->selected >= 0) {
! 351: j = w->connections[w->selected];
! 352: if (VALID_WIDGET_NID(j, this)) {
! 353: ret = azalia_generic_codec_find_dac(this, j, depth);
! 354: if (ret >= 0) {
! 355: DPRINTF(("%s: DAC path: nid=0x%x index=%d\n",
! 356: __func__, w->nid, index));
! 357: return ret;
! 358: }
! 359: }
! 360: }
! 361: for (i = 0; i < w->nconnections; i++) {
! 362: j = w->connections[i];
! 363: if (!VALID_WIDGET_NID(j, this))
! 364: continue;
! 365: ret = azalia_generic_codec_find_dac(this, j, depth);
! 366: if (ret >= 0) {
! 367: DPRINTF(("%s: DAC path: nid=0x%x index=%d\n",
! 368: __func__, w->nid, index));
! 369: return ret;
! 370: }
! 371: }
! 372: return -1;
! 373: }
! 374:
! 375: /* ----------------------------------------------------------------
! 376: * Generic mixer functions
! 377: * ---------------------------------------------------------------- */
! 378:
! 379: int
! 380: azalia_generic_mixer_init(codec_t *this)
! 381: {
! 382: /*
! 383: * pin "<color>%2.2x"
! 384: * audio output "dac%2.2x"
! 385: * audio input "adc%2.2x"
! 386: * mixer "mixer%2.2x"
! 387: * selector "sel%2.2x"
! 388: */
! 389: mixer_item_t *m;
! 390: int err, i, j, k;
! 391:
! 392: this->maxmixers = 10;
! 393: this->nmixers = 0;
! 394: this->mixers = malloc(sizeof(mixer_item_t) * this->maxmixers,
! 395: M_DEVBUF, M_NOWAIT);
! 396: if (this->mixers == NULL) {
! 397: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 398: return ENOMEM;
! 399: }
! 400: bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
! 401:
! 402: /* register classes */
! 403: DPRINTF(("%s: register classes\n", __func__));
! 404: m = &this->mixers[AZ_CLASS_INPUT];
! 405: m->devinfo.index = AZ_CLASS_INPUT;
! 406: strlcpy(m->devinfo.label.name, AudioCinputs,
! 407: sizeof(m->devinfo.label.name));
! 408: m->devinfo.type = AUDIO_MIXER_CLASS;
! 409: m->devinfo.mixer_class = AZ_CLASS_INPUT;
! 410: m->devinfo.next = AUDIO_MIXER_LAST;
! 411: m->devinfo.prev = AUDIO_MIXER_LAST;
! 412: m->nid = 0;
! 413:
! 414: m = &this->mixers[AZ_CLASS_OUTPUT];
! 415: m->devinfo.index = AZ_CLASS_OUTPUT;
! 416: strlcpy(m->devinfo.label.name, AudioCoutputs,
! 417: sizeof(m->devinfo.label.name));
! 418: m->devinfo.type = AUDIO_MIXER_CLASS;
! 419: m->devinfo.mixer_class = AZ_CLASS_OUTPUT;
! 420: m->devinfo.next = AUDIO_MIXER_LAST;
! 421: m->devinfo.prev = AUDIO_MIXER_LAST;
! 422: m->nid = 0;
! 423:
! 424: m = &this->mixers[AZ_CLASS_RECORD];
! 425: m->devinfo.index = AZ_CLASS_RECORD;
! 426: strlcpy(m->devinfo.label.name, AudioCrecord,
! 427: sizeof(m->devinfo.label.name));
! 428: m->devinfo.type = AUDIO_MIXER_CLASS;
! 429: m->devinfo.mixer_class = AZ_CLASS_RECORD;
! 430: m->devinfo.next = AUDIO_MIXER_LAST;
! 431: m->devinfo.prev = AUDIO_MIXER_LAST;
! 432: m->nid = 0;
! 433:
! 434: this->nmixers = AZ_CLASS_RECORD + 1;
! 435:
! 436: #define MIXER_REG_PROLOG \
! 437: mixer_devinfo_t *d; \
! 438: err = azalia_generic_mixer_ensure_capacity(this, this->nmixers + 1); \
! 439: if (err) \
! 440: return err; \
! 441: m = &this->mixers[this->nmixers]; \
! 442: d = &m->devinfo; \
! 443: m->nid = i
! 444:
! 445: FOR_EACH_WIDGET(this, i) {
! 446: const widget_t *w;
! 447:
! 448: w = &this->w[i];
! 449:
! 450: /* selector */
! 451: if (w->type != COP_AWTYPE_AUDIO_MIXER && w->nconnections >= 2) {
! 452: MIXER_REG_PROLOG;
! 453: DPRINTF(("%s: selector %s\n", __func__, w->name));
! 454: snprintf(d->label.name, sizeof(d->label.name),
! 455: "%s.source", w->name);
! 456: d->type = AUDIO_MIXER_ENUM;
! 457: if (w->type == COP_AWTYPE_AUDIO_MIXER)
! 458: d->mixer_class = AZ_CLASS_RECORD;
! 459: else if (w->type == COP_AWTYPE_AUDIO_SELECTOR)
! 460: d->mixer_class = AZ_CLASS_INPUT;
! 461: else
! 462: d->mixer_class = AZ_CLASS_OUTPUT;
! 463: m->target = MI_TARGET_CONNLIST;
! 464: for (j = 0, k = 0; j < w->nconnections && k < 32; j++) {
! 465: if (!VALID_WIDGET_NID(w->connections[j], this))
! 466: continue;
! 467: DPRINTF(("%s: selector %d=%s\n", __func__, j,
! 468: this->w[w->connections[j]].name));
! 469: d->un.e.member[k].ord = j;
! 470: strlcpy(d->un.e.member[k].label.name,
! 471: this->w[w->connections[j]].name,
! 472: MAX_AUDIO_DEV_LEN);
! 473: k++;
! 474: }
! 475: d->un.e.num_mem = k;
! 476: this->nmixers++;
! 477: }
! 478:
! 479: /* output mute */
! 480: if (w->widgetcap & COP_AWCAP_OUTAMP &&
! 481: w->outamp_cap & COP_AMPCAP_MUTE) {
! 482: MIXER_REG_PROLOG;
! 483: DPRINTF(("%s: output mute %s\n", __func__, w->name));
! 484: snprintf(d->label.name, sizeof(d->label.name),
! 485: "%s.mute", w->name);
! 486: d->type = AUDIO_MIXER_ENUM;
! 487: if (w->type == COP_AWTYPE_AUDIO_MIXER)
! 488: d->mixer_class = AZ_CLASS_OUTPUT;
! 489: else if (w->type == COP_AWTYPE_AUDIO_SELECTOR)
! 490: d->mixer_class = AZ_CLASS_OUTPUT;
! 491: else if (w->type == COP_AWTYPE_PIN_COMPLEX)
! 492: d->mixer_class = AZ_CLASS_OUTPUT;
! 493: else
! 494: d->mixer_class = AZ_CLASS_INPUT;
! 495: m->target = MI_TARGET_OUTAMP;
! 496: d->un.e.num_mem = 2;
! 497: d->un.e.member[0].ord = 0;
! 498: strlcpy(d->un.e.member[0].label.name, AudioNoff,
! 499: MAX_AUDIO_DEV_LEN);
! 500: d->un.e.member[1].ord = 1;
! 501: strlcpy(d->un.e.member[1].label.name, AudioNon,
! 502: MAX_AUDIO_DEV_LEN);
! 503: this->nmixers++;
! 504: }
! 505:
! 506: /* output gain */
! 507: if (w->widgetcap & COP_AWCAP_OUTAMP
! 508: && COP_AMPCAP_NUMSTEPS(w->outamp_cap)) {
! 509: MIXER_REG_PROLOG;
! 510: DPRINTF(("%s: output gain %s\n", __func__, w->name));
! 511: snprintf(d->label.name, sizeof(d->label.name),
! 512: "%s", w->name);
! 513: d->type = AUDIO_MIXER_VALUE;
! 514: if (w->type == COP_AWTYPE_AUDIO_MIXER)
! 515: d->mixer_class = AZ_CLASS_OUTPUT;
! 516: else if (w->type == COP_AWTYPE_AUDIO_SELECTOR)
! 517: d->mixer_class = AZ_CLASS_OUTPUT;
! 518: else if (w->type == COP_AWTYPE_PIN_COMPLEX)
! 519: d->mixer_class = AZ_CLASS_OUTPUT;
! 520: else
! 521: d->mixer_class = AZ_CLASS_INPUT;
! 522: m->target = MI_TARGET_OUTAMP;
! 523: d->un.v.num_channels = WIDGET_CHANNELS(w);
! 524: #ifdef MAX_VOLUME_255
! 525: d->un.v.units.name[0] = 0;
! 526: #else
! 527: snprintf(d->un.v.units.name, sizeof(d->un.v.units.name),
! 528: "0.25x%ddB", COP_AMPCAP_STEPSIZE(w->outamp_cap)+1);
! 529: #endif
! 530: d->un.v.delta =
! 531: MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->outamp_cap));
! 532: this->nmixers++;
! 533: }
! 534:
! 535: /* input mute */
! 536: if (w->widgetcap & COP_AWCAP_INAMP &&
! 537: w->inamp_cap & COP_AMPCAP_MUTE) {
! 538: DPRINTF(("%s: input mute %s\n", __func__, w->name));
! 539: if (w->type != COP_AWTYPE_AUDIO_SELECTOR &&
! 540: w->type != COP_AWTYPE_AUDIO_MIXER) {
! 541: MIXER_REG_PROLOG;
! 542: snprintf(d->label.name, sizeof(d->label.name),
! 543: "%s.mute", w->name);
! 544: d->type = AUDIO_MIXER_ENUM;
! 545: if (w->type == COP_AWTYPE_PIN_COMPLEX)
! 546: d->mixer_class = AZ_CLASS_OUTPUT;
! 547: else if (w->type == COP_AWTYPE_AUDIO_INPUT)
! 548: d->mixer_class = AZ_CLASS_RECORD;
! 549: else
! 550: d->mixer_class = AZ_CLASS_INPUT;
! 551: m->target = 0;
! 552: d->un.e.num_mem = 2;
! 553: d->un.e.member[0].ord = 0;
! 554: strlcpy(d->un.e.member[0].label.name,
! 555: AudioNoff, MAX_AUDIO_DEV_LEN);
! 556: d->un.e.member[1].ord = 1;
! 557: strlcpy(d->un.e.member[1].label.name,
! 558: AudioNon, MAX_AUDIO_DEV_LEN);
! 559: this->nmixers++;
! 560: } else {
! 561: for (j = 0; j < w->nconnections; j++) {
! 562: MIXER_REG_PROLOG;
! 563: if (!VALID_WIDGET_NID(w->connections[j], this))
! 564: continue;
! 565: DPRINTF(("%s: input mute %s.%s\n", __func__,
! 566: w->name, this->w[w->connections[j]].name));
! 567: snprintf(d->label.name, sizeof(d->label.name),
! 568: "%s.%s.mute", w->name,
! 569: this->w[w->connections[j]].name);
! 570: d->type = AUDIO_MIXER_ENUM;
! 571: if (w->type == COP_AWTYPE_PIN_COMPLEX)
! 572: d->mixer_class = AZ_CLASS_OUTPUT;
! 573: else if (w->type == COP_AWTYPE_AUDIO_INPUT)
! 574: d->mixer_class = AZ_CLASS_RECORD;
! 575: else
! 576: d->mixer_class = AZ_CLASS_INPUT;
! 577: m->target = j;
! 578: d->un.e.num_mem = 2;
! 579: d->un.e.member[0].ord = 0;
! 580: strlcpy(d->un.e.member[0].label.name,
! 581: AudioNoff, MAX_AUDIO_DEV_LEN);
! 582: d->un.e.member[1].ord = 1;
! 583: strlcpy(d->un.e.member[1].label.name,
! 584: AudioNon, MAX_AUDIO_DEV_LEN);
! 585: this->nmixers++;
! 586: }
! 587: }
! 588: }
! 589:
! 590: /* input gain */
! 591: if (w->widgetcap & COP_AWCAP_INAMP
! 592: && COP_AMPCAP_NUMSTEPS(w->inamp_cap)) {
! 593: DPRINTF(("%s: input gain %s\n", __func__, w->name));
! 594: if (w->type != COP_AWTYPE_AUDIO_SELECTOR &&
! 595: w->type != COP_AWTYPE_AUDIO_MIXER) {
! 596: MIXER_REG_PROLOG;
! 597: snprintf(d->label.name, sizeof(d->label.name),
! 598: "%s", w->name);
! 599: d->type = AUDIO_MIXER_VALUE;
! 600: if (w->type == COP_AWTYPE_PIN_COMPLEX)
! 601: d->mixer_class = AZ_CLASS_OUTPUT;
! 602: else if (w->type == COP_AWTYPE_AUDIO_INPUT)
! 603: d->mixer_class = AZ_CLASS_RECORD;
! 604: else
! 605: d->mixer_class = AZ_CLASS_INPUT;
! 606: m->target = 0;
! 607: d->un.v.num_channels = WIDGET_CHANNELS(w);
! 608: #ifdef MAX_VOLUME_255
! 609: d->un.v.units.name[0] = 0;
! 610: #else
! 611: snprintf(d->un.v.units.name,
! 612: sizeof(d->un.v.units.name), "0.25x%ddB",
! 613: COP_AMPCAP_STEPSIZE(w->inamp_cap)+1);
! 614: #endif
! 615: d->un.v.delta =
! 616: MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap));
! 617: this->nmixers++;
! 618: } else {
! 619: for (j = 0; j < w->nconnections; j++) {
! 620: MIXER_REG_PROLOG;
! 621: if (!VALID_WIDGET_NID(w->connections[j], this))
! 622: continue;
! 623: DPRINTF(("%s: input gain %s.%s\n", __func__,
! 624: w->name, this->w[w->connections[j]].name));
! 625: snprintf(d->label.name, sizeof(d->label.name),
! 626: "%s.%s", w->name,
! 627: this->w[w->connections[j]].name);
! 628: d->type = AUDIO_MIXER_VALUE;
! 629: if (w->type == COP_AWTYPE_PIN_COMPLEX)
! 630: d->mixer_class = AZ_CLASS_OUTPUT;
! 631: else if (w->type == COP_AWTYPE_AUDIO_INPUT)
! 632: d->mixer_class = AZ_CLASS_RECORD;
! 633: else
! 634: d->mixer_class = AZ_CLASS_INPUT;
! 635: m->target = j;
! 636: d->un.v.num_channels = WIDGET_CHANNELS(w);
! 637: #ifdef MAX_VOLUME_255
! 638: d->un.v.units.name[0] = 0;
! 639: #else
! 640: snprintf(d->un.v.units.name,
! 641: sizeof(d->un.v.units.name), "0.25x%ddB",
! 642: COP_AMPCAP_STEPSIZE(w->inamp_cap)+1);
! 643: #endif
! 644: d->un.v.delta =
! 645: MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap));
! 646: this->nmixers++;
! 647: }
! 648: }
! 649: }
! 650:
! 651: /* pin direction */
! 652: if (w->type == COP_AWTYPE_PIN_COMPLEX &&
! 653: w->d.pin.cap & COP_PINCAP_OUTPUT &&
! 654: w->d.pin.cap & COP_PINCAP_INPUT) {
! 655: MIXER_REG_PROLOG;
! 656: DPRINTF(("%s: pin dir %s\n", __func__, w->name));
! 657: snprintf(d->label.name, sizeof(d->label.name),
! 658: "%s.dir", w->name);
! 659: d->type = AUDIO_MIXER_ENUM;
! 660: d->mixer_class = AZ_CLASS_OUTPUT;
! 661: m->target = MI_TARGET_PINDIR;
! 662: d->un.e.num_mem = 2;
! 663: d->un.e.member[0].ord = 0;
! 664: strlcpy(d->un.e.member[0].label.name, AudioNinput,
! 665: MAX_AUDIO_DEV_LEN);
! 666: d->un.e.member[1].ord = 1;
! 667: strlcpy(d->un.e.member[1].label.name, AudioNoutput,
! 668: MAX_AUDIO_DEV_LEN);
! 669: this->nmixers++;
! 670: }
! 671:
! 672: /* pin headphone-boost */
! 673: if (w->type == COP_AWTYPE_PIN_COMPLEX &&
! 674: w->d.pin.cap & COP_PINCAP_HEADPHONE) {
! 675: MIXER_REG_PROLOG;
! 676: DPRINTF(("%s: hpboost %s\n", __func__, w->name));
! 677: snprintf(d->label.name, sizeof(d->label.name),
! 678: "%s.boost", w->name);
! 679: d->type = AUDIO_MIXER_ENUM;
! 680: d->mixer_class = AZ_CLASS_OUTPUT;
! 681: m->target = MI_TARGET_PINBOOST;
! 682: d->un.e.num_mem = 2;
! 683: d->un.e.member[0].ord = 0;
! 684: strlcpy(d->un.e.member[0].label.name, AudioNoff,
! 685: MAX_AUDIO_DEV_LEN);
! 686: d->un.e.member[1].ord = 1;
! 687: strlcpy(d->un.e.member[1].label.name, AudioNon,
! 688: MAX_AUDIO_DEV_LEN);
! 689: this->nmixers++;
! 690: }
! 691:
! 692: /* volume knob */
! 693: if (w->type == COP_AWTYPE_VOLUME_KNOB &&
! 694: w->d.volume.cap & COP_VKCAP_DELTA) {
! 695: MIXER_REG_PROLOG;
! 696: DPRINTF(("%s: volume knob %s\n", __func__, w->name));
! 697: strlcpy(d->label.name, w->name, sizeof(d->label.name));
! 698: d->type = AUDIO_MIXER_VALUE;
! 699: d->mixer_class = AZ_CLASS_OUTPUT;
! 700: m->target = MI_TARGET_VOLUME;
! 701: d->un.v.num_channels = 1;
! 702: d->un.v.units.name[0] = 0;
! 703: d->un.v.delta =
! 704: MIXER_DELTA(COP_VKCAP_NUMSTEPS(w->d.volume.cap));
! 705: this->nmixers++;
! 706: }
! 707: }
! 708:
! 709: /* if the codec has multiple DAC groups, create "inputs.usingdac" */
! 710: if (this->dacs.ngroups > 1) {
! 711: MIXER_REG_PROLOG;
! 712: DPRINTF(("%s: create inputs.usingdac\n", __func__));
! 713: strlcpy(d->label.name, "usingdac", sizeof(d->label.name));
! 714: d->type = AUDIO_MIXER_ENUM;
! 715: d->mixer_class = AZ_CLASS_INPUT;
! 716: m->target = MI_TARGET_DAC;
! 717: for (i = 0; i < this->dacs.ngroups && i < 32; i++) {
! 718: d->un.e.member[i].ord = i;
! 719: for (j = 0; j < this->dacs.groups[i].nconv; j++) {
! 720: if (j * 2 >= MAX_AUDIO_DEV_LEN)
! 721: break;
! 722: snprintf(d->un.e.member[i].label.name + j*2,
! 723: MAX_AUDIO_DEV_LEN - j*2, "%2.2x",
! 724: this->dacs.groups[i].conv[j]);
! 725: }
! 726: }
! 727: d->un.e.num_mem = i;
! 728: this->nmixers++;
! 729: }
! 730:
! 731: /* if the codec has multiple ADC groups, create "record.usingadc" */
! 732: if (this->adcs.ngroups > 1) {
! 733: MIXER_REG_PROLOG;
! 734: DPRINTF(("%s: create inputs.usingadc\n", __func__));
! 735: strlcpy(d->label.name, "usingadc", sizeof(d->label.name));
! 736: d->type = AUDIO_MIXER_ENUM;
! 737: d->mixer_class = AZ_CLASS_RECORD;
! 738: m->target = MI_TARGET_ADC;
! 739: for (i = 0; i < this->adcs.ngroups && i < 32; i++) {
! 740: d->un.e.member[i].ord = i;
! 741: for (j = 0; j < this->adcs.groups[i].nconv; j++) {
! 742: if (j * 2 >= MAX_AUDIO_DEV_LEN)
! 743: break;
! 744: snprintf(d->un.e.member[i].label.name + j*2,
! 745: MAX_AUDIO_DEV_LEN - j*2, "%2.2x",
! 746: this->adcs.groups[i].conv[j]);
! 747: }
! 748: }
! 749: d->un.e.num_mem = i;
! 750: this->nmixers++;
! 751: }
! 752:
! 753: azalia_generic_mixer_fix_indexes(this);
! 754: azalia_generic_mixer_default(this);
! 755: return 0;
! 756: }
! 757:
! 758: int
! 759: azalia_generic_mixer_ensure_capacity(codec_t *this, size_t newsize)
! 760: {
! 761: size_t newmax;
! 762: void *newbuf;
! 763:
! 764: if (this->maxmixers >= newsize)
! 765: return 0;
! 766: newmax = this->maxmixers + 10;
! 767: if (newmax < newsize)
! 768: newmax = newsize;
! 769: newbuf = malloc(sizeof(mixer_item_t) * newmax, M_DEVBUF, M_NOWAIT);
! 770: if (newbuf == NULL) {
! 771: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 772: return ENOMEM;
! 773: }
! 774: bzero(newbuf, sizeof(mixer_item_t) * newmax);
! 775: bcopy(this->mixers, newbuf, this->maxmixers * sizeof(mixer_item_t));
! 776: free(this->mixers, M_DEVBUF);
! 777: this->mixers = newbuf;
! 778: this->maxmixers = newmax;
! 779: return 0;
! 780: }
! 781:
! 782: int
! 783: azalia_generic_mixer_fix_indexes(codec_t *this)
! 784: {
! 785: int i;
! 786: mixer_devinfo_t *d;
! 787:
! 788: for (i = 0; i < this->nmixers; i++) {
! 789: d = &this->mixers[i].devinfo;
! 790: #ifdef DIAGNOSTIC
! 791: if (d->index != 0 && d->index != i)
! 792: printf("%s: index mismatch %d %d\n", __func__,
! 793: d->index, i);
! 794: #endif
! 795: d->index = i;
! 796: if (d->prev == 0)
! 797: d->prev = AUDIO_MIXER_LAST;
! 798: if (d->next == 0)
! 799: d->next = AUDIO_MIXER_LAST;
! 800: }
! 801: return 0;
! 802: }
! 803:
! 804: int
! 805: azalia_generic_mixer_default(codec_t *this)
! 806: {
! 807: int i;
! 808: mixer_item_t *m;
! 809: /* unmute all */
! 810: DPRINTF(("%s: unmute\n", __func__));
! 811: for (i = 0; i < this->nmixers; i++) {
! 812: mixer_ctrl_t mc;
! 813:
! 814: m = &this->mixers[i];
! 815: if (!IS_MI_TARGET_INAMP(m->target) &&
! 816: m->target != MI_TARGET_OUTAMP)
! 817: continue;
! 818: if (m->devinfo.type != AUDIO_MIXER_ENUM)
! 819: continue;
! 820: mc.dev = i;
! 821: mc.type = AUDIO_MIXER_ENUM;
! 822: mc.un.ord = 0;
! 823: azalia_generic_mixer_set(this, m->nid, m->target, &mc);
! 824: }
! 825:
! 826: /*
! 827: * For bidirectional pins,
! 828: * Output: lineout, speaker, headphone, spdifout, digitalout, other
! 829: * Input: others
! 830: */
! 831: DPRINTF(("%s: process bidirectional pins\n", __func__));
! 832: for (i = 0; i < this->nmixers; i++) {
! 833: mixer_ctrl_t mc;
! 834:
! 835: m = &this->mixers[i];
! 836: if (m->target != MI_TARGET_PINDIR)
! 837: continue;
! 838: mc.dev = i;
! 839: mc.type = AUDIO_MIXER_ENUM;
! 840: switch (this->w[m->nid].d.pin.device) {
! 841: case CORB_CD_LINEOUT:
! 842: case CORB_CD_SPEAKER:
! 843: case CORB_CD_HEADPHONE:
! 844: case CORB_CD_SPDIFOUT:
! 845: case CORB_CD_DIGITALOUT:
! 846: case CORB_CD_DEVICE_OTHER:
! 847: mc.un.ord = 1;
! 848: break;
! 849: default:
! 850: mc.un.ord = 0;
! 851: }
! 852: azalia_generic_mixer_set(this, m->nid, m->target, &mc);
! 853: }
! 854:
! 855: /* set unextreme volume */
! 856: DPRINTF(("%s: set volume\n", __func__));
! 857: for (i = 0; i < this->nmixers; i++) {
! 858: mixer_ctrl_t mc;
! 859:
! 860: m = &this->mixers[i];
! 861: if (!IS_MI_TARGET_INAMP(m->target) &&
! 862: m->target != MI_TARGET_OUTAMP &&
! 863: m->target != MI_TARGET_VOLUME)
! 864: continue;
! 865: if (m->devinfo.type != AUDIO_MIXER_VALUE)
! 866: continue;
! 867: mc.dev = i;
! 868: mc.type = AUDIO_MIXER_VALUE;
! 869: mc.un.value.num_channels = 1;
! 870: mc.un.value.level[0] = AUDIO_MAX_GAIN / 2;
! 871: if (m->target != MI_TARGET_VOLUME &&
! 872: WIDGET_CHANNELS(&this->w[m->nid]) == 2) {
! 873: mc.un.value.num_channels = 2;
! 874: mc.un.value.level[1] = AUDIO_MAX_GAIN / 2;
! 875: }
! 876: azalia_generic_mixer_set(this, m->nid, m->target, &mc);
! 877: }
! 878:
! 879: return 0;
! 880: }
! 881:
! 882: int
! 883: azalia_generic_mixer_delete(codec_t *this)
! 884: {
! 885: if (this->mixers == NULL)
! 886: return 0;
! 887: free(this->mixers, M_DEVBUF);
! 888: this->mixers = NULL;
! 889: return 0;
! 890: }
! 891:
! 892: /**
! 893: * @param mc mc->type must be set by the caller before the call
! 894: */
! 895: int
! 896: azalia_generic_mixer_get(const codec_t *this, nid_t nid, int target, mixer_ctrl_t *mc)
! 897: {
! 898: uint32_t result;
! 899: nid_t n;
! 900: int err;
! 901:
! 902: /* inamp mute */
! 903: if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) {
! 904: err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 905: CORB_GAGM_INPUT | CORB_GAGM_LEFT |
! 906: MI_TARGET_INAMP(target), &result);
! 907: if (err)
! 908: return err;
! 909: mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0;
! 910: }
! 911:
! 912: /* inamp gain */
! 913: else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) {
! 914: err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 915: CORB_GAGM_INPUT | CORB_GAGM_LEFT |
! 916: MI_TARGET_INAMP(target), &result);
! 917: if (err)
! 918: return err;
! 919: mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this,
! 920: nid, target, CORB_GAGM_GAIN(result));
! 921: if (this->w[nid].type == COP_AWTYPE_AUDIO_SELECTOR ||
! 922: this->w[nid].type == COP_AWTYPE_AUDIO_MIXER) {
! 923: n = this->w[nid].connections[MI_TARGET_INAMP(target)];
! 924: #ifdef AZALIA_DEBUG
! 925: if (!VALID_WIDGET_NID(n, this)) {
! 926: DPRINTF(("%s: invalid target: nid=%d nconn=%d index=%d\n",
! 927: __func__, nid, this->w[nid].nconnections,
! 928: MI_TARGET_INAMP(target)));
! 929: return EINVAL;
! 930: }
! 931: #endif
! 932: } else
! 933: n = nid;
! 934: mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[n]);
! 935: if (mc->un.value.num_channels == 2) {
! 936: err = this->comresp(this, nid,
! 937: CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
! 938: CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
! 939: &result);
! 940: if (err)
! 941: return err;
! 942: mc->un.value.level[1] = azalia_generic_mixer_from_device_value
! 943: (this, nid, target, CORB_GAGM_GAIN(result));
! 944: }
! 945: }
! 946:
! 947: /* outamp mute */
! 948: else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
! 949: err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 950: CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result);
! 951: if (err)
! 952: return err;
! 953: mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0;
! 954: }
! 955:
! 956: /* outamp gain */
! 957: else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) {
! 958: err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 959: CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result);
! 960: if (err)
! 961: return err;
! 962: mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this,
! 963: nid, target, CORB_GAGM_GAIN(result));
! 964: mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[nid]);
! 965: if (mc->un.value.num_channels == 2) {
! 966: err = this->comresp(this, nid,
! 967: CORB_GET_AMPLIFIER_GAIN_MUTE,
! 968: CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT | 0, &result);
! 969: if (err)
! 970: return err;
! 971: mc->un.value.level[1] = azalia_generic_mixer_from_device_value
! 972: (this, nid, target, CORB_GAGM_GAIN(result));
! 973: }
! 974: }
! 975:
! 976: /* selection */
! 977: else if (target == MI_TARGET_CONNLIST) {
! 978: err = this->comresp(this, nid,
! 979: CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result);
! 980: if (err)
! 981: return err;
! 982: result = CORB_CSC_INDEX(result);
! 983: if (!VALID_WIDGET_NID(this->w[nid].connections[result], this))
! 984: mc->un.ord = -1;
! 985: else
! 986: mc->un.ord = result;
! 987: }
! 988:
! 989: /* pin I/O */
! 990: else if (target == MI_TARGET_PINDIR) {
! 991: err = this->comresp(this, nid,
! 992: CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
! 993: if (err)
! 994: return err;
! 995: mc->un.ord = result & CORB_PWC_OUTPUT ? 1 : 0;
! 996: }
! 997:
! 998: /* pin headphone-boost */
! 999: else if (target == MI_TARGET_PINBOOST) {
! 1000: err = this->comresp(this, nid,
! 1001: CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
! 1002: if (err)
! 1003: return err;
! 1004: mc->un.ord = result & CORB_PWC_HEADPHONE ? 1 : 0;
! 1005: }
! 1006:
! 1007: /* DAC group selection */
! 1008: else if (target == MI_TARGET_DAC) {
! 1009: mc->un.ord = this->dacs.cur;
! 1010: }
! 1011:
! 1012: /* ADC selection */
! 1013: else if (target == MI_TARGET_ADC) {
! 1014: mc->un.ord = this->adcs.cur;
! 1015: }
! 1016:
! 1017: /* Volume knob */
! 1018: else if (target == MI_TARGET_VOLUME) {
! 1019: err = this->comresp(this, nid, CORB_GET_VOLUME_KNOB,
! 1020: 0, &result);
! 1021: if (err)
! 1022: return err;
! 1023: mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this,
! 1024: nid, target, CORB_VKNOB_VOLUME(result));
! 1025: mc->un.value.num_channels = 1;
! 1026: }
! 1027:
! 1028: else {
! 1029: printf("%s: internal error in %s: target=%x\n",
! 1030: XNAME(this), __func__, target);
! 1031: return -1;
! 1032: }
! 1033: return 0;
! 1034: }
! 1035:
! 1036: int
! 1037: azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc)
! 1038: {
! 1039: uint32_t result, value;
! 1040: int err;
! 1041:
! 1042: /* inamp mute */
! 1043: if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) {
! 1044: /* We have to set stereo mute separately to keep each gain value. */
! 1045: err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 1046: CORB_GAGM_INPUT | CORB_GAGM_LEFT |
! 1047: MI_TARGET_INAMP(target), &result);
! 1048: if (err)
! 1049: return err;
! 1050: value = CORB_AGM_INPUT | CORB_AGM_LEFT |
! 1051: (target << CORB_AGM_INDEX_SHIFT) |
! 1052: CORB_GAGM_GAIN(result);
! 1053: if (mc->un.ord)
! 1054: value |= CORB_AGM_MUTE;
! 1055: err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
! 1056: value, &result);
! 1057: if (err)
! 1058: return err;
! 1059: if (WIDGET_CHANNELS(&this->w[nid]) == 2) {
! 1060: err = this->comresp(this, nid,
! 1061: CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
! 1062: CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
! 1063: &result);
! 1064: if (err)
! 1065: return err;
! 1066: value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
! 1067: (target << CORB_AGM_INDEX_SHIFT) |
! 1068: CORB_GAGM_GAIN(result);
! 1069: if (mc->un.ord)
! 1070: value |= CORB_AGM_MUTE;
! 1071: err = this->comresp(this, nid,
! 1072: CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
! 1073: if (err)
! 1074: return err;
! 1075: }
! 1076: }
! 1077:
! 1078: /* inamp gain */
! 1079: else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) {
! 1080: if (mc->un.value.num_channels < 1)
! 1081: return EINVAL;
! 1082: if (!azalia_generic_mixer_validate_value(this, nid, target,
! 1083: mc->un.value.level[0]))
! 1084: return EINVAL;
! 1085: err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 1086: CORB_GAGM_INPUT | CORB_GAGM_LEFT |
! 1087: MI_TARGET_INAMP(target), &result);
! 1088: if (err)
! 1089: return err;
! 1090: value = azalia_generic_mixer_to_device_value(this, nid, target,
! 1091: mc->un.value.level[0]);
! 1092: value = CORB_AGM_INPUT | CORB_AGM_LEFT |
! 1093: (target << CORB_AGM_INDEX_SHIFT) |
! 1094: (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
! 1095: (value & CORB_AGM_GAIN_MASK);
! 1096: err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
! 1097: value, &result);
! 1098: if (err)
! 1099: return err;
! 1100: if (mc->un.value.num_channels >= 2 &&
! 1101: WIDGET_CHANNELS(&this->w[nid]) == 2) {
! 1102: if (!azalia_generic_mixer_validate_value(this, nid, target,
! 1103: mc->un.value.level[1]))
! 1104: return EINVAL;
! 1105: err = this->comresp(this, nid,
! 1106: CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
! 1107: CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
! 1108: &result);
! 1109: if (err)
! 1110: return err;
! 1111: value = azalia_generic_mixer_to_device_value(this, nid, target,
! 1112: mc->un.value.level[1]);
! 1113: value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
! 1114: (target << CORB_AGM_INDEX_SHIFT) |
! 1115: (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
! 1116: (value & CORB_AGM_GAIN_MASK);
! 1117: err = this->comresp(this, nid,
! 1118: CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
! 1119: if (err)
! 1120: return err;
! 1121: }
! 1122: }
! 1123:
! 1124: /* outamp mute */
! 1125: else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
! 1126: err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 1127: CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result);
! 1128: if (err)
! 1129: return err;
! 1130: value = CORB_AGM_OUTPUT | CORB_AGM_LEFT | CORB_GAGM_GAIN(result);
! 1131: if (mc->un.ord)
! 1132: value |= CORB_AGM_MUTE;
! 1133: err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
! 1134: value, &result);
! 1135: if (err)
! 1136: return err;
! 1137: if (WIDGET_CHANNELS(&this->w[nid]) == 2) {
! 1138: err = this->comresp(this, nid,
! 1139: CORB_GET_AMPLIFIER_GAIN_MUTE,
! 1140: CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT, &result);
! 1141: if (err)
! 1142: return err;
! 1143: value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT |
! 1144: CORB_GAGM_GAIN(result);
! 1145: if (mc->un.ord)
! 1146: value |= CORB_AGM_MUTE;
! 1147: err = this->comresp(this, nid,
! 1148: CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
! 1149: if (err)
! 1150: return err;
! 1151: }
! 1152: }
! 1153:
! 1154: /* outamp gain */
! 1155: else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) {
! 1156: if (mc->un.value.num_channels < 1)
! 1157: return EINVAL;
! 1158: if (!azalia_generic_mixer_validate_value(this, nid, target,
! 1159: mc->un.value.level[0]))
! 1160: return EINVAL;
! 1161: err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 1162: CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result);
! 1163: if (err)
! 1164: return err;
! 1165: value = azalia_generic_mixer_to_device_value(this, nid, target,
! 1166: mc->un.value.level[0]);
! 1167: value = CORB_AGM_OUTPUT | CORB_AGM_LEFT |
! 1168: (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
! 1169: (value & CORB_AGM_GAIN_MASK);
! 1170: err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
! 1171: value, &result);
! 1172: if (err)
! 1173: return err;
! 1174: if (mc->un.value.num_channels >= 2 &&
! 1175: WIDGET_CHANNELS(&this->w[nid]) == 2) {
! 1176: if (!azalia_generic_mixer_validate_value(this, nid, target,
! 1177: mc->un.value.level[1]))
! 1178: return EINVAL;
! 1179: err = this->comresp(this, nid,
! 1180: CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_OUTPUT |
! 1181: CORB_GAGM_RIGHT, &result);
! 1182: if (err)
! 1183: return err;
! 1184: value = azalia_generic_mixer_to_device_value(this, nid, target,
! 1185: mc->un.value.level[1]);
! 1186: value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT |
! 1187: (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
! 1188: (value & CORB_AGM_GAIN_MASK);
! 1189: err = this->comresp(this, nid,
! 1190: CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
! 1191: if (err)
! 1192: return err;
! 1193: }
! 1194: }
! 1195:
! 1196: /* selection */
! 1197: else if (target == MI_TARGET_CONNLIST) {
! 1198: if (mc->un.ord < 0 ||
! 1199: mc->un.ord >= this->w[nid].nconnections ||
! 1200: !VALID_WIDGET_NID(this->w[nid].connections[mc->un.ord], this))
! 1201: return EINVAL;
! 1202: err = this->comresp(this, nid,
! 1203: CORB_SET_CONNECTION_SELECT_CONTROL, mc->un.ord, &result);
! 1204: if (err)
! 1205: return err;
! 1206: }
! 1207:
! 1208: /* pin I/O */
! 1209: else if (target == MI_TARGET_PINDIR) {
! 1210: if (mc->un.ord >= 2)
! 1211: return EINVAL;
! 1212: err = this->comresp(this, nid,
! 1213: CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
! 1214: if (err)
! 1215: return err;
! 1216: if (mc->un.ord == 0) {
! 1217: result &= ~CORB_PWC_OUTPUT;
! 1218: result |= CORB_PWC_INPUT;
! 1219: } else {
! 1220: result &= ~CORB_PWC_INPUT;
! 1221: result |= CORB_PWC_OUTPUT;
! 1222: }
! 1223: err = this->comresp(this, nid,
! 1224: CORB_SET_PIN_WIDGET_CONTROL, result, &result);
! 1225: if (err)
! 1226: return err;
! 1227: }
! 1228:
! 1229: /* pin headphone-boost */
! 1230: else if (target == MI_TARGET_PINBOOST) {
! 1231: if (mc->un.ord >= 2)
! 1232: return EINVAL;
! 1233: err = this->comresp(this, nid,
! 1234: CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
! 1235: if (err)
! 1236: return err;
! 1237: if (mc->un.ord == 0) {
! 1238: result &= ~CORB_PWC_HEADPHONE;
! 1239: } else {
! 1240: result |= CORB_PWC_HEADPHONE;
! 1241: }
! 1242: err = this->comresp(this, nid,
! 1243: CORB_SET_PIN_WIDGET_CONTROL, result, &result);
! 1244: if (err)
! 1245: return err;
! 1246: }
! 1247:
! 1248: /* DAC group selection */
! 1249: else if (target == MI_TARGET_DAC) {
! 1250: if (this->running)
! 1251: return EBUSY;
! 1252: if (mc->un.ord >= this->dacs.ngroups)
! 1253: return EINVAL;
! 1254: return azalia_codec_construct_format(this,
! 1255: mc->un.ord, this->adcs.cur);
! 1256: }
! 1257:
! 1258: /* ADC selection */
! 1259: else if (target == MI_TARGET_ADC) {
! 1260: if (this->running)
! 1261: return EBUSY;
! 1262: if (mc->un.ord >= this->adcs.ngroups)
! 1263: return EINVAL;
! 1264: return azalia_codec_construct_format(this,
! 1265: this->dacs.cur, mc->un.ord);
! 1266: }
! 1267:
! 1268: /* Volume knob */
! 1269: else if (target == MI_TARGET_VOLUME) {
! 1270: if (mc->un.value.num_channels != 1)
! 1271: return EINVAL;
! 1272: if (!azalia_generic_mixer_validate_value(this, nid,
! 1273: target, mc->un.value.level[0]))
! 1274: return EINVAL;
! 1275: value = azalia_generic_mixer_to_device_value(this, nid, target,
! 1276: mc->un.value.level[0]) | CORB_VKNOB_DIRECT;
! 1277: err = this->comresp(this, nid, CORB_SET_VOLUME_KNOB,
! 1278: value, &result);
! 1279: if (err)
! 1280: return err;
! 1281: }
! 1282:
! 1283: else {
! 1284: printf("%s: internal error in %s: target=%x\n",
! 1285: XNAME(this), __func__, target);
! 1286: return -1;
! 1287: }
! 1288: return 0;
! 1289: }
! 1290:
! 1291: int
! 1292: azalia_generic_mixer_pinctrl(codec_t *this, nid_t nid, uint32_t value)
! 1293: {
! 1294: int err;
! 1295: uint32_t result;
! 1296:
! 1297: err = this->comresp(this, nid, CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
! 1298: if (err)
! 1299: return err;
! 1300: result &= ~(CORB_PWC_OUTPUT | CORB_PWC_INPUT);
! 1301: result |= value & (CORB_PWC_OUTPUT | CORB_PWC_INPUT);
! 1302: return this->comresp(this, nid,
! 1303: CORB_SET_PIN_WIDGET_CONTROL, result, NULL);
! 1304: }
! 1305:
! 1306: u_char
! 1307: azalia_generic_mixer_from_device_value(const codec_t *this, nid_t nid, int target,
! 1308: uint32_t dv)
! 1309: {
! 1310: #ifdef MAX_VOLUME_255
! 1311: uint32_t dmax;
! 1312:
! 1313: if (IS_MI_TARGET_INAMP(target))
! 1314: dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
! 1315: else if (target == MI_TARGET_OUTAMP)
! 1316: dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
! 1317: else if (target == MI_TARGET_VOLUME)
! 1318: dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap);
! 1319: else {
! 1320: printf("unknown target: %d\n", target);
! 1321: dmax = 255;
! 1322: }
! 1323: if (dv <= 0 || dmax == 0)
! 1324: return AUDIO_MIN_GAIN;
! 1325: if (dv >= dmax)
! 1326: return AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax;
! 1327: return dv * (AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax) / dmax;
! 1328: #else
! 1329: return dv;
! 1330: #endif
! 1331: }
! 1332:
! 1333: uint32_t
! 1334: azalia_generic_mixer_to_device_value(const codec_t *this, nid_t nid, int target,
! 1335: u_char uv)
! 1336: {
! 1337: #ifdef MAX_VOLUME_255
! 1338: uint32_t dmax;
! 1339:
! 1340: if (IS_MI_TARGET_INAMP(target))
! 1341: dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
! 1342: else if (target == MI_TARGET_OUTAMP)
! 1343: dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
! 1344: else if (target == MI_TARGET_VOLUME)
! 1345: dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap);
! 1346: else {
! 1347: printf("unknown target: %d\n", target);
! 1348: dmax = 255;
! 1349: }
! 1350: if (uv <= AUDIO_MIN_GAIN || dmax == 0)
! 1351: return 0;
! 1352: if (uv >= AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax)
! 1353: return dmax;
! 1354: return uv * dmax / (AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax);
! 1355: #else
! 1356: return uv;
! 1357: #endif
! 1358: }
! 1359:
! 1360: uint32_t
! 1361: azalia_generic_mixer_max(const codec_t *this, nid_t nid, int target)
! 1362: {
! 1363: #ifdef MAX_VOLUME_255
! 1364: return AUDIO_MAX_GAIN;
! 1365: #else
! 1366: uint32_t dmax;
! 1367:
! 1368: if (IS_MI_TARGET_INAMP(target))
! 1369: dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
! 1370: else if (target == MI_TARGET_OUTAMP)
! 1371: dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
! 1372: else if (target == MI_TARGET_VOLUME)
! 1373: dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap);
! 1374: return dmax;
! 1375: #endif
! 1376: }
! 1377:
! 1378: boolean_t
! 1379: azalia_generic_mixer_validate_value(const codec_t *this, nid_t nid, int target,
! 1380: u_char uv)
! 1381: {
! 1382: #ifdef MAX_VOLUME_255
! 1383: return TRUE;
! 1384: #else
! 1385: return uv <= generic_mixer_max(this, nid, target);
! 1386: #endif
! 1387: }
! 1388:
! 1389: int
! 1390: azalia_generic_set_port(codec_t *this, mixer_ctrl_t *mc)
! 1391: {
! 1392: const mixer_item_t *m;
! 1393:
! 1394: if (mc->dev >= this->nmixers)
! 1395: return ENXIO;
! 1396: m = &this->mixers[mc->dev];
! 1397: if (mc->type != m->devinfo.type)
! 1398: return EINVAL;
! 1399: if (mc->type == AUDIO_MIXER_CLASS)
! 1400: return 0; /* nothing to do */
! 1401: return azalia_generic_mixer_set(this, m->nid, m->target, mc);
! 1402: }
! 1403:
! 1404: int
! 1405: azalia_generic_get_port(codec_t *this, mixer_ctrl_t *mc)
! 1406: {
! 1407: const mixer_item_t *m;
! 1408:
! 1409: if (mc->dev >= this->nmixers)
! 1410: return ENXIO;
! 1411: m = &this->mixers[mc->dev];
! 1412: mc->type = m->devinfo.type;
! 1413: if (mc->type == AUDIO_MIXER_CLASS)
! 1414: return 0; /* nothing to do */
! 1415: return azalia_generic_mixer_get(this, m->nid, m->target, mc);
! 1416: }
! 1417:
! 1418:
! 1419: /* ----------------------------------------------------------------
! 1420: * Realtek ALC260
! 1421: *
! 1422: * Fujitsu LOOX T70M/T
! 1423: * Internal Speaker: 0x10
! 1424: * Front Headphone: 0x14
! 1425: * Front mic: 0x12
! 1426: * ---------------------------------------------------------------- */
! 1427:
! 1428: #define ALC260_FUJITSU_ID 0x132610cf
! 1429: static const mixer_item_t alc260_mixer_items[] = {
! 1430: {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
! 1431: {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
! 1432: {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
! 1433:
! 1434: {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 1435: 0, 0, .un.v={{""}, 2, 3}}, 0x08, MI_TARGET_OUTAMP}, /* and 0x09, 0x0a(mono) */
! 1436: {{0, {AudioNmaster".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1437: 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_OUTAMP},
! 1438: {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1439: 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_OUTAMP},
! 1440: {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1441: 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_PINBOOST},
! 1442: {{0, {AudioNmono".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1443: 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_OUTAMP},
! 1444: {{0, {"mic1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1445: 0, 0, ENUM_OFFON}, 0x12, MI_TARGET_OUTAMP},
! 1446: {{0, {"mic1"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1447: 0, 0, ENUM_IO}, 0x12, MI_TARGET_PINDIR},
! 1448: {{0, {"mic2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1449: 0, 0, ENUM_OFFON}, 0x13, MI_TARGET_OUTAMP},
! 1450: {{0, {"mic2"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1451: 0, 0, ENUM_IO}, 0x13, MI_TARGET_PINDIR},
! 1452: {{0, {"line1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1453: 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
! 1454: {{0, {"line1"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1455: 0, 0, ENUM_IO}, 0x14, MI_TARGET_PINDIR},
! 1456: {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1457: 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP},
! 1458: {{0, {"line2"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1459: 0, 0, ENUM_IO}, 0x15, MI_TARGET_PINDIR},
! 1460:
! 1461: {{0, {AudioNdac".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1462: 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)}, /* and 0x09, 0x0a(mono) */
! 1463: {{0, {"mic1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1464: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)},
! 1465: {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1466: 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)},
! 1467: {{0, {"mic2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1468: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(1)},
! 1469: {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1470: 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(1)},
! 1471: {{0, {"line1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1472: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(2)},
! 1473: {{0, {"line1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1474: 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(2)},
! 1475: {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1476: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(3)},
! 1477: {{0, {"line2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1478: 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(3)},
! 1479: {{0, {AudioNcd".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1480: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(4)},
! 1481: {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1482: 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)},
! 1483: {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1484: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(5)},
! 1485: {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1486: 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)},
! 1487:
! 1488: {{0, {"adc04.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1489: .un.e={5, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{"line1"}, 2},
! 1490: {{"line2"}, 3}, {{AudioNcd}, 4}}}},
! 1491: 0x04, MI_TARGET_CONNLIST},
! 1492: {{0, {"adc04.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1493: ENUM_OFFON}, 0x04, MI_TARGET_INAMP(0)},
! 1494: {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
! 1495: .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)},
! 1496: {{0, {"adc05.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1497: .un.e={6, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{"line1"}, 2},
! 1498: {{"line2"}, 3}, {{AudioNcd}, 4}, {{AudioNmixerout}, 5}}}},
! 1499: 0x05, MI_TARGET_CONNLIST},
! 1500: {{0, {"adc05.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1501: ENUM_OFFON}, 0x05, MI_TARGET_INAMP(0)},
! 1502: {{0, {"adc05"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
! 1503: .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)},
! 1504:
! 1505: {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0,
! 1506: .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC},
! 1507: {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1508: .un.e={3, {{{"adc04"}, 0}, {{"adc05"}, 1}, {{"digital"}, 2}}}}, 0, MI_TARGET_ADC},
! 1509: };
! 1510:
! 1511: static const mixer_item_t alc260_loox_mixer_items[] = {
! 1512: {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
! 1513: {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
! 1514: {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
! 1515:
! 1516: {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 1517: 0, 0, .un.v={{""}, 2, 3}}, 0x08, MI_TARGET_OUTAMP}, /* and 0x09, 0x0a(mono) */
! 1518: {{0, {AudioNmaster".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1519: 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_OUTAMP},
! 1520: {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1521: 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_PINBOOST},
! 1522: {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1523: 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
! 1524: {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1525: 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST},
! 1526:
! 1527: {{0, {AudioNdac".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1528: 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)}, /* and 0x09, 0x0a(mono) */
! 1529: {{0, {AudioNmicrophone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1530: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)},
! 1531: {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1532: 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)},
! 1533: {{0, {AudioNcd".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1534: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(4)},
! 1535: {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1536: 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)},
! 1537: {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1538: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(5)},
! 1539: {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1540: 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)},
! 1541:
! 1542: {{0, {"adc04.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1543: .un.e={2, {{{AudioNmicrophone}, 0}, {{AudioNcd}, 4}}}}, 0x04, MI_TARGET_CONNLIST},
! 1544: {{0, {"adc04.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1545: ENUM_OFFON}, 0x04, MI_TARGET_INAMP(0)},
! 1546: {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
! 1547: .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)},
! 1548: {{0, {"adc05.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1549: .un.e={3, {{{AudioNmicrophone}, 0}, {{AudioNcd}, 4}, {{AudioNmixerout}, 5}}}},
! 1550: 0x05, MI_TARGET_CONNLIST},
! 1551: {{0, {"adc05.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1552: ENUM_OFFON}, 0x05, MI_TARGET_INAMP(0)},
! 1553: {{0, {"adc05"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
! 1554: .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)},
! 1555:
! 1556: {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0,
! 1557: .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC},
! 1558: {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1559: .un.e={3, {{{"adc04"}, 0}, {{"adc05"}, 1}, {{"digital"}, 2}}}}, 0, MI_TARGET_ADC},
! 1560: };
! 1561:
! 1562: int
! 1563: azalia_alc260_mixer_init(codec_t *this)
! 1564: {
! 1565: const mixer_item_t *mi;
! 1566: mixer_ctrl_t mc;
! 1567:
! 1568: switch (this->subid) {
! 1569: case ALC260_FUJITSU_ID:
! 1570: this->nmixers = sizeof(alc260_loox_mixer_items) / sizeof(mixer_item_t);
! 1571: mi = alc260_loox_mixer_items;
! 1572: break;
! 1573: default:
! 1574: this->nmixers = sizeof(alc260_mixer_items) / sizeof(mixer_item_t);
! 1575: mi = alc260_mixer_items;
! 1576: }
! 1577: this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
! 1578: M_DEVBUF, M_NOWAIT);
! 1579: if (this->mixers == NULL) {
! 1580: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 1581: return ENOMEM;
! 1582: }
! 1583: bzero(this->mixers, sizeof(mixer_item_t) * this->nmixers);
! 1584: memcpy(this->mixers, mi, sizeof(mixer_item_t) * this->nmixers);
! 1585: azalia_generic_mixer_fix_indexes(this);
! 1586: azalia_generic_mixer_default(this);
! 1587:
! 1588: mc.dev = -1; /* no need for generic_mixer_set() */
! 1589: mc.type = AUDIO_MIXER_ENUM;
! 1590: mc.un.ord = 1; /* pindir: output */
! 1591: azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); /* lineout */
! 1592: azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc); /* headphones */
! 1593: mc.un.ord = 0; /* pindir: input */
! 1594: azalia_generic_mixer_set(this, 0x12, MI_TARGET_PINDIR, &mc); /* mic1 */
! 1595: azalia_generic_mixer_set(this, 0x13, MI_TARGET_PINDIR, &mc); /* mic2 */
! 1596: azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc); /* line1 */
! 1597: azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc); /* line2 */
! 1598: mc.un.ord = 0; /* mute: off */
! 1599: azalia_generic_mixer_set(this, 0x08, MI_TARGET_INAMP(0), &mc);
! 1600: azalia_generic_mixer_set(this, 0x08, MI_TARGET_INAMP(1), &mc);
! 1601: azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(0), &mc);
! 1602: azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(1), &mc);
! 1603: azalia_generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(0), &mc);
! 1604: azalia_generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(1), &mc);
! 1605: if (this->subid == ALC260_FUJITSU_ID) {
! 1606: mc.un.ord = 1; /* pindir: output */
! 1607: azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc); /* line1 */
! 1608: mc.un.ord = 4; /* connlist: cd */
! 1609: azalia_generic_mixer_set(this, 0x05, MI_TARGET_CONNLIST, &mc);
! 1610: }
! 1611: return 0;
! 1612: }
! 1613:
! 1614: int
! 1615: azalia_alc260_init_dacgroup(codec_t *this)
! 1616: {
! 1617: static const convgroupset_t dacs = {
! 1618: -1, 2,
! 1619: {{1, {0x02}}, /* analog 2ch */
! 1620: {1, {0x03}}}}; /* digital */
! 1621: static const convgroupset_t adcs = {
! 1622: -1, 3,
! 1623: {{1, {0x04}}, /* analog 2ch */
! 1624: {1, {0x05}}, /* analog 2ch */
! 1625: {1, {0x06}}}}; /* digital */
! 1626:
! 1627: this->dacs = dacs;
! 1628: this->adcs = adcs;
! 1629: return 0;
! 1630: }
! 1631:
! 1632: int
! 1633: azalia_alc260_set_port(codec_t *this, mixer_ctrl_t *mc)
! 1634: {
! 1635: const mixer_item_t *m;
! 1636: mixer_ctrl_t mc2;
! 1637: int err;
! 1638:
! 1639: if (mc->dev >= this->nmixers)
! 1640: return ENXIO;
! 1641: m = &this->mixers[mc->dev];
! 1642: if (mc->type != m->devinfo.type)
! 1643: return EINVAL;
! 1644: if (mc->type == AUDIO_MIXER_CLASS)
! 1645: return 0;
! 1646: if (m->nid == 0x08 && m->target == MI_TARGET_OUTAMP) {
! 1647: DPRINTF(("%s: hook for outputs.master\n", __func__));
! 1648: err = azalia_generic_mixer_set(this, m->nid, m->target, mc);
! 1649: if (!err) {
! 1650: azalia_generic_mixer_set(this, 0x09, m->target, mc);
! 1651: mc2 = *mc;
! 1652: mc2.un.value.num_channels = 1;
! 1653: mc2.un.value.level[0] = (mc2.un.value.level[0]
! 1654: + mc2.un.value.level[1]) / 2;
! 1655: azalia_generic_mixer_set(this, 0x0a, m->target, &mc2);
! 1656: }
! 1657: return err;
! 1658: } else if (m->nid == 0x08 && m->target == MI_TARGET_INAMP(0)) {
! 1659: DPRINTF(("%s: hook for inputs.dac.mute\n", __func__));
! 1660: err = azalia_generic_mixer_set(this, m->nid, m->target, mc);
! 1661: if (!err) {
! 1662: azalia_generic_mixer_set(this, 0x09, m->target, mc);
! 1663: azalia_generic_mixer_set(this, 0x0a, m->target, mc);
! 1664: }
! 1665: return err;
! 1666: } else if (m->nid == 0x04 &&
! 1667: m->target == MI_TARGET_CONNLIST &&
! 1668: m->devinfo.un.e.num_mem == 2) {
! 1669: if (1 <= mc->un.ord && mc->un.ord <= 3)
! 1670: return EINVAL;
! 1671: } else if (m->nid == 0x05 &&
! 1672: m->target == MI_TARGET_CONNLIST &&
! 1673: m->devinfo.un.e.num_mem == 3) {
! 1674: if (1 <= mc->un.ord && mc->un.ord <= 3)
! 1675: return EINVAL;
! 1676: }
! 1677: return azalia_generic_mixer_set(this, m->nid, m->target, mc);
! 1678: }
! 1679:
! 1680: /* ----------------------------------------------------------------
! 1681: * Realtek ALC880
! 1682: * ---------------------------------------------------------------- */
! 1683:
! 1684: int
! 1685: azalia_alc880_init_dacgroup(codec_t *this)
! 1686: {
! 1687: static const convgroupset_t dacs = {
! 1688: -1, 2,
! 1689: {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
! 1690: {1, {0x06}}}}; /* digital */
! 1691: static const convgroupset_t adcs = {
! 1692: -1, 2,
! 1693: {{2, {0x08, 0x09}}, /* analog 4ch */
! 1694: {1, {0x0a}}}}; /* digital */
! 1695:
! 1696: this->dacs = dacs;
! 1697: this->adcs = adcs;
! 1698: return 0;
! 1699: }
! 1700:
! 1701: /* ----------------------------------------------------------------
! 1702: * Realtek ALC882
! 1703: * ---------------------------------------------------------------- */
! 1704:
! 1705: static const mixer_item_t alc882_mixer_items[] = {
! 1706: {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
! 1707: {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
! 1708: {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
! 1709:
! 1710: /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17 */
! 1711: {{0, {"mic1."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1712: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(0)},
! 1713: {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1714: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(0)},
! 1715: {{0, {"mic2."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1716: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(1)},
! 1717: {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1718: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(1)},
! 1719: {{0, {AudioNline"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1720: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(2)},
! 1721: {{0, {AudioNline}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1722: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(2)},
! 1723: {{0, {AudioNcd"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1724: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(4)},
! 1725: {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1726: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(4)},
! 1727: {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1728: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(5)},
! 1729: {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1730: 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(5)},
! 1731:
! 1732: {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 1733: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0c, MI_TARGET_OUTAMP},
! 1734: {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1735: 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
! 1736: {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1737: 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST},
! 1738: {{0, {AudioNheadphone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1739: 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_OUTAMP},
! 1740: {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1741: 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_PINBOOST},
! 1742: {{0, {AzaliaNfront".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1743: 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(0)},
! 1744: {{0, {AzaliaNfront".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1745: 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(1)},
! 1746:
! 1747: {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 1748: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0d, MI_TARGET_OUTAMP},
! 1749: {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1750: 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP},
! 1751: {{0, {AudioNsurround".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1752: 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_PINBOOST},
! 1753: {{0, {AudioNsurround".dac.mut"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1754: 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(0)},
! 1755: {{0, {AudioNsurround".mixer.m"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1756: 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(1)},
! 1757:
! 1758: {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 1759: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0e, MI_TARGET_OUTAMP},
! 1760: {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1761: 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_OUTAMP},
! 1762: {{0, {AzaliaNclfe".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1763: 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_PINBOOST},
! 1764: {{0, {AzaliaNclfe".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1765: 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(0)},
! 1766: {{0, {AzaliaNclfe".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1767: 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(1)},
! 1768:
! 1769: {{0, {AzaliaNside}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 1770: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0f, MI_TARGET_OUTAMP},
! 1771: {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1772: 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_OUTAMP},
! 1773: {{0, {AzaliaNside".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 1774: 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_PINBOOST},
! 1775: {{0, {AzaliaNside".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1776: 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(0)},
! 1777: {{0, {AzaliaNside".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1778: 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(1)},
! 1779:
! 1780: /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17,0xb */
! 1781: #define ALC882_MIC1 0x001
! 1782: #define ALC882_MIC2 0x002
! 1783: #define ALC882_LINE 0x004
! 1784: #define ALC882_CD 0x010
! 1785: #define ALC882_BEEP 0x020
! 1786: #define ALC882_MIX 0x400
! 1787: #define ALC882_MASK 0x437
! 1788: {{0, {AzaliaNfront"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 1789: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)},
! 1790: {{0, {AzaliaNfront}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
! 1791: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x07, MI_TARGET_INAMP(0)},
! 1792: {{0, {AzaliaNfront"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
! 1793: 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
! 1794: {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
! 1795: {{AudioNspeaker}, ALC882_BEEP},
! 1796: {{AudioNmixerout}, ALC882_MIX}}}}, 0x24, -1},
! 1797: {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 1798: 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)},
! 1799: {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
! 1800: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x08, MI_TARGET_INAMP(0)},
! 1801: {{0, {AudioNsurround"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
! 1802: 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
! 1803: {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
! 1804: {{AudioNspeaker}, ALC882_BEEP},
! 1805: {{AudioNmixerout}, ALC882_MIX}}}}, 0x23, -1},
! 1806: {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 1807: 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)},
! 1808: {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
! 1809: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x09, MI_TARGET_INAMP(0)},
! 1810: {{0, {AzaliaNclfe"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
! 1811: 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
! 1812: {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
! 1813: {{AudioNspeaker}, ALC882_BEEP},
! 1814: {{AudioNmixerout}, ALC882_MIX}}}}, 0x22, -1},
! 1815:
! 1816: {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0,
! 1817: .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC},
! 1818: {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 1819: .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_ADC},
! 1820: };
! 1821:
! 1822: int
! 1823: azalia_alc882_mixer_init(codec_t *this)
! 1824: {
! 1825: mixer_ctrl_t mc;
! 1826:
! 1827: this->nmixers = sizeof(alc882_mixer_items) / sizeof(mixer_item_t);
! 1828: this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
! 1829: M_DEVBUF, M_NOWAIT);
! 1830: if (this->mixers == NULL) {
! 1831: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 1832: return ENOMEM;
! 1833: }
! 1834: bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
! 1835: memcpy(this->mixers, alc882_mixer_items,
! 1836: sizeof(mixer_item_t) * this->nmixers);
! 1837: azalia_generic_mixer_fix_indexes(this);
! 1838: azalia_generic_mixer_default(this);
! 1839:
! 1840: mc.dev = -1;
! 1841: mc.type = AUDIO_MIXER_ENUM;
! 1842: mc.un.ord = 1; /* pindir: output */
! 1843: azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc);
! 1844: azalia_generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR, &mc);
! 1845: azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc);
! 1846: azalia_generic_mixer_set(this, 0x16, MI_TARGET_PINDIR, &mc);
! 1847: azalia_generic_mixer_set(this, 0x17, MI_TARGET_PINDIR, &mc);
! 1848: mc.un.ord = 0; /* [0] 0x0c */
! 1849: azalia_generic_mixer_set(this, 0x14, MI_TARGET_CONNLIST, &mc);
! 1850: azalia_generic_mixer_set(this, 0x1b, MI_TARGET_CONNLIST, &mc);
! 1851: mc.un.ord = 1; /* [1] 0x0d */
! 1852: azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc);
! 1853: mc.un.ord = 2; /* [2] 0x0e */
! 1854: azalia_generic_mixer_set(this, 0x16, MI_TARGET_CONNLIST, &mc);
! 1855: mc.un.ord = 2; /* [3] 0x0fb */
! 1856: azalia_generic_mixer_set(this, 0x17, MI_TARGET_CONNLIST, &mc);
! 1857:
! 1858: mc.un.ord = 0; /* pindir: input */
! 1859: azalia_generic_mixer_set(this, 0x18, MI_TARGET_PINDIR, &mc);
! 1860: azalia_generic_mixer_set(this, 0x19, MI_TARGET_PINDIR, &mc);
! 1861: azalia_generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR, &mc);
! 1862: /* XXX: inamp for 18/19/1a */
! 1863:
! 1864: mc.un.ord = 0; /* unmute */
! 1865: azalia_generic_mixer_set(this, 0x24, MI_TARGET_INAMP(0), &mc);
! 1866: azalia_generic_mixer_set(this, 0x23, MI_TARGET_INAMP(1), &mc);
! 1867: azalia_generic_mixer_set(this, 0x22, MI_TARGET_INAMP(2), &mc);
! 1868: return 0;
! 1869: }
! 1870:
! 1871: int
! 1872: azalia_alc882_init_dacgroup(codec_t *this)
! 1873: {
! 1874: #if 0
! 1875: static const convgroupset_t dacs = {
! 1876: -1, 3,
! 1877: {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
! 1878: {1, {0x06}}, /* digital */
! 1879: {1, {0x25}}}}; /* another analog */
! 1880: #else
! 1881: static const convgroupset_t dacs = {
! 1882: -1, 2,
! 1883: {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
! 1884: {1, {0x06}}}}; /* digital */
! 1885: #endif
! 1886: static const convgroupset_t adcs = {
! 1887: -1, 2,
! 1888: {{3, {0x07, 0x08, 0x09}}, /* analog 6ch */
! 1889: {1, {0x0a}}}}; /* digital */
! 1890:
! 1891: this->dacs = dacs;
! 1892: this->adcs = adcs;
! 1893: return 0;
! 1894: }
! 1895:
! 1896: int
! 1897: azalia_alc882_set_port(codec_t *this, mixer_ctrl_t *mc)
! 1898: {
! 1899: const mixer_item_t *m;
! 1900: mixer_ctrl_t mc2;
! 1901: uint32_t mask, bit;
! 1902: int i, err;
! 1903:
! 1904: if (mc->dev >= this->nmixers)
! 1905: return ENXIO;
! 1906: m = &this->mixers[mc->dev];
! 1907: if (mc->type != m->devinfo.type)
! 1908: return EINVAL;
! 1909: if (mc->type == AUDIO_MIXER_CLASS)
! 1910: return 0;
! 1911: if ((m->nid == 0x22 || m->nid == 0x23 || m->nid == 0x24)
! 1912: && m->target == -1) {
! 1913: DPRINTF(("%s: hook for record.*.source\n", __func__));
! 1914: mc2.dev = -1;
! 1915: mc2.type = AUDIO_MIXER_ENUM;
! 1916: bit = 1;
! 1917: mask = mc->un.mask & ALC882_MASK;
! 1918: for (i = 0; i < this->w[m->nid].nconnections && i < 32; i++) {
! 1919: mc2.un.ord = (mask & bit) ? 0 : 1;
! 1920: err = azalia_generic_mixer_set(this, m->nid,
! 1921: MI_TARGET_INAMP(i), &mc2);
! 1922: if (err)
! 1923: return err;
! 1924: bit = bit << 1;
! 1925: }
! 1926: return 0;
! 1927: }
! 1928: return azalia_generic_mixer_set(this, m->nid, m->target, mc);
! 1929: }
! 1930:
! 1931: int
! 1932: azalia_alc882_get_port(codec_t *this, mixer_ctrl_t *mc)
! 1933: {
! 1934: const mixer_item_t *m;
! 1935: uint32_t mask, bit, result;
! 1936: int i, err;
! 1937:
! 1938: if (mc->dev >= this->nmixers)
! 1939: return ENXIO;
! 1940: m = &this->mixers[mc->dev];
! 1941: mc->type = m->devinfo.type;
! 1942: if (mc->type == AUDIO_MIXER_CLASS)
! 1943: return 0;
! 1944: if ((m->nid == 0x22 || m->nid == 0x23 || m->nid == 0x24)
! 1945: && m->target == -1) {
! 1946: DPRINTF(("%s: hook for record.*.source\n", __func__));
! 1947: mask = 0;
! 1948: bit = 1;
! 1949: for (i = 0; i < this->w[m->nid].nconnections && i < 32; i++) {
! 1950: err = this->comresp(this, m->nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
! 1951: CORB_GAGM_INPUT | CORB_GAGM_LEFT |
! 1952: i, &result);
! 1953: if (err)
! 1954: return err;
! 1955: if ((result & CORB_GAGM_MUTE) == 0)
! 1956: mask |= bit;
! 1957: bit = bit << 1;
! 1958: }
! 1959: mc->un.mask = mask & ALC882_MASK;
! 1960: return 0;
! 1961: }
! 1962: return azalia_generic_mixer_get(this, m->nid, m->target, mc);
! 1963: }
! 1964:
! 1965: /* ----------------------------------------------------------------
! 1966: * Realtek ALC883
! 1967: * ALC882 without adc07 and mix24.
! 1968: * ---------------------------------------------------------------- */
! 1969:
! 1970: int
! 1971: azalia_alc883_init_dacgroup(codec_t *this)
! 1972: {
! 1973: static const convgroupset_t dacs = {
! 1974: -1, 2,
! 1975: {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
! 1976: {1, {0x06}}}}; /* digital */
! 1977:
! 1978: static const convgroupset_t adcs = {
! 1979: -1, 2,
! 1980: {{2, {0x08, 0x09}}, /* analog 4ch */
! 1981: {1, {0x0a}}}}; /* digital */
! 1982:
! 1983: this->dacs = dacs;
! 1984: this->adcs = adcs;
! 1985: return 0;
! 1986: }
! 1987:
! 1988: static const mixer_item_t alc883_mixer_items[] = {
! 1989: {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
! 1990: {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
! 1991: {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
! 1992:
! 1993: /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17 */
! 1994: {{0, {"mic1."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1995: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(0)},
! 1996: {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 1997: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(0)},
! 1998: {{0, {"mic2."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 1999: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(1)},
! 2000: {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 2001: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(1)},
! 2002: {{0, {AudioNline"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2003: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(2)},
! 2004: {{0, {AudioNline}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 2005: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(2)},
! 2006: {{0, {AudioNcd"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2007: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(4)},
! 2008: {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 2009: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(4)},
! 2010: {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2011: 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(5)},
! 2012: {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 2013: 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(5)},
! 2014:
! 2015: {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2016: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0c, MI_TARGET_OUTAMP},
! 2017: {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2018: 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
! 2019: {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2020: 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST},
! 2021: {{0, {AudioNheadphone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2022: 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_OUTAMP},
! 2023: {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2024: 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_PINBOOST},
! 2025: {{0, {AzaliaNfront".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2026: 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(0)},
! 2027: {{0, {AzaliaNfront".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2028: 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(1)},
! 2029: {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2030: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0d, MI_TARGET_OUTAMP},
! 2031: {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2032: 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP},
! 2033: {{0, {AudioNsurround".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2034: 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_PINBOOST},
! 2035: {{0, {AudioNsurround".dac.mut"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2036: 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(0)},
! 2037: {{0, {AudioNsurround".mixer.m"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2038: 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(1)},
! 2039:
! 2040: {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2041: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0e, MI_TARGET_OUTAMP},
! 2042: {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2043: 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_OUTAMP},
! 2044: {{0, {AzaliaNclfe".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2045: 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_PINBOOST},
! 2046: {{0, {AzaliaNclfe".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2047: 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(0)},
! 2048: {{0, {AzaliaNclfe".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2049: 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(1)},
! 2050:
! 2051: {{0, {AzaliaNside}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2052: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0f, MI_TARGET_OUTAMP},
! 2053: {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2054: 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_OUTAMP},
! 2055: {{0, {AzaliaNside".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2056: 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_PINBOOST},
! 2057: {{0, {AzaliaNside".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2058: 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(0)},
! 2059: {{0, {AzaliaNside".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2060: 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(1)},
! 2061:
! 2062: {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2063: 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)},
! 2064: {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
! 2065: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x08, MI_TARGET_INAMP(0)},
! 2066: {{0, {AudioNsurround"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
! 2067: 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
! 2068: {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
! 2069: {{AudioNspeaker}, ALC882_BEEP},
! 2070: {{AudioNmixerout}, ALC882_MIX}}}}, 0x23, -1},
! 2071:
! 2072: {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2073: 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)},
! 2074: {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
! 2075: 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x09, MI_TARGET_INAMP(0)},
! 2076: {{0, {AzaliaNclfe"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
! 2077: 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
! 2078: {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
! 2079: {{AudioNspeaker}, ALC882_BEEP},
! 2080: {{AudioNmixerout}, ALC882_MIX}}}}, 0x22, -1},
! 2081:
! 2082: {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0,
! 2083: .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC},
! 2084: {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 2085: .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_ADC},
! 2086: };
! 2087:
! 2088: int
! 2089: azalia_alc883_mixer_init(codec_t *this)
! 2090: {
! 2091: mixer_ctrl_t mc;
! 2092:
! 2093: this->nmixers = sizeof(alc883_mixer_items) / sizeof(mixer_item_t);
! 2094: this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
! 2095: M_DEVBUF, M_NOWAIT);
! 2096: if (this->mixers == NULL) {
! 2097: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 2098: return ENOMEM;
! 2099: }
! 2100: bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
! 2101: memcpy(this->mixers, alc883_mixer_items,
! 2102: sizeof(mixer_item_t) * this->nmixers);
! 2103: azalia_generic_mixer_fix_indexes(this);
! 2104: azalia_generic_mixer_default(this);
! 2105:
! 2106: mc.dev = -1;
! 2107: mc.type = AUDIO_MIXER_ENUM;
! 2108: mc.un.ord = 1; /* pindir: output */
! 2109: azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc);
! 2110: azalia_generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR, &mc);
! 2111: azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc);
! 2112: azalia_generic_mixer_set(this, 0x16, MI_TARGET_PINDIR, &mc);
! 2113: azalia_generic_mixer_set(this, 0x17, MI_TARGET_PINDIR, &mc);
! 2114: mc.un.ord = 0; /* [0] 0x0c */
! 2115: azalia_generic_mixer_set(this, 0x14, MI_TARGET_CONNLIST, &mc);
! 2116: azalia_generic_mixer_set(this, 0x1b, MI_TARGET_CONNLIST, &mc);
! 2117: mc.un.ord = 1; /* [1] 0x0d */
! 2118: azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc);
! 2119: mc.un.ord = 2; /* [2] 0x0e */
! 2120: azalia_generic_mixer_set(this, 0x16, MI_TARGET_CONNLIST, &mc);
! 2121: mc.un.ord = 2; /* [3] 0x0fb */
! 2122: azalia_generic_mixer_set(this, 0x17, MI_TARGET_CONNLIST, &mc);
! 2123:
! 2124: mc.un.ord = 0; /* pindir: input */
! 2125: azalia_generic_mixer_set(this, 0x18, MI_TARGET_PINDIR, &mc);
! 2126: azalia_generic_mixer_set(this, 0x19, MI_TARGET_PINDIR, &mc);
! 2127: azalia_generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR, &mc);
! 2128: /* XXX: inamp for 18/19/1a */
! 2129:
! 2130: mc.un.ord = 0; /* unmute */
! 2131: azalia_generic_mixer_set(this, 0x23, MI_TARGET_INAMP(1), &mc);
! 2132: azalia_generic_mixer_set(this, 0x22, MI_TARGET_INAMP(2), &mc);
! 2133: return 0;
! 2134: }
! 2135:
! 2136:
! 2137: /* ----------------------------------------------------------------
! 2138: * Analog Devices AD1981HD
! 2139: * ---------------------------------------------------------------- */
! 2140:
! 2141: #define AD1981HD_THINKPAD 0x201017aa
! 2142:
! 2143: int
! 2144: azalia_ad1981hd_init_widget(const codec_t *this, widget_t *w, nid_t nid)
! 2145: {
! 2146: switch (nid) {
! 2147: case 0x05:
! 2148: strlcpy(w->name, AudioNline "out", sizeof(w->name));
! 2149: break;
! 2150: case 0x06:
! 2151: strlcpy(w->name, "hp", sizeof(w->name));
! 2152: break;
! 2153: case 0x07:
! 2154: strlcpy(w->name, AudioNmono, sizeof(w->name));
! 2155: break;
! 2156: case 0x08:
! 2157: strlcpy(w->name, AudioNmicrophone, sizeof(w->name));
! 2158: break;
! 2159: case 0x09:
! 2160: strlcpy(w->name, AudioNline "in", sizeof(w->name));
! 2161: break;
! 2162: case 0x0d:
! 2163: strlcpy(w->name, "beep", sizeof(w->name));
! 2164: break;
! 2165: case 0x17:
! 2166: strlcpy(w->name, AudioNaux, sizeof(w->name));
! 2167: break;
! 2168: case 0x18:
! 2169: strlcpy(w->name, AudioNmicrophone "2", sizeof(w->name));
! 2170: break;
! 2171: case 0x19:
! 2172: strlcpy(w->name, AudioNcd, sizeof(w->name));
! 2173: break;
! 2174: case 0x1d:
! 2175: strlcpy(w->name, AudioNspeaker, sizeof(w->name));
! 2176: break;
! 2177: }
! 2178: return 0;
! 2179: }
! 2180:
! 2181: int
! 2182: azalia_ad1981hd_mixer_init(codec_t *this)
! 2183: {
! 2184: mixer_ctrl_t mc;
! 2185: int err;
! 2186:
! 2187: err = azalia_generic_mixer_init(this);
! 2188: if (err)
! 2189: return err;
! 2190: if (this->subid == AD1981HD_THINKPAD) {
! 2191: mc.dev = -1;
! 2192: mc.type = AUDIO_MIXER_ENUM;
! 2193: mc.un.ord = 1;
! 2194: azalia_generic_mixer_set(this, 0x09, MI_TARGET_PINDIR, &mc);
! 2195: }
! 2196: return 0;
! 2197: }
! 2198:
! 2199: /* ----------------------------------------------------------------
! 2200: * CMedia CMI9880
! 2201: * ---------------------------------------------------------------- */
! 2202:
! 2203: static const mixer_item_t cmi9880_mixer_items[] = {
! 2204: {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
! 2205: {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
! 2206: {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
! 2207:
! 2208: {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2209: 0, 0, ENUM_OFFON}, 0x03, MI_TARGET_OUTAMP},
! 2210: {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2211: 0, 0, ENUM_OFFON}, 0x04, MI_TARGET_OUTAMP},
! 2212: {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2213: 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP},
! 2214: {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2215: 0, 0, ENUM_OFFON}, 0x06, MI_TARGET_OUTAMP},
! 2216: {{0, {"digital."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2217: 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_OUTAMP},
! 2218:
! 2219: {{0, {AzaliaNfront"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2220: 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)},
! 2221: {{0, {AzaliaNfront}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
! 2222: 0, 0, .un.v={{""}, 2, MIXER_DELTA(30)}}, 0x08, MI_TARGET_INAMP(0)},
! 2223: {{0, {AzaliaNfront"."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2224: 0, 0, .un.e={4, {{{AudioNmicrophone}, 5}, {{AudioNcd}, 6},
! 2225: {{"line1"}, 7}, {{"line2"}, 8}}}},
! 2226: 0x08, MI_TARGET_CONNLIST},
! 2227: {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2228: 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)},
! 2229: {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
! 2230: 0, 0, .un.v={{""}, 2, MIXER_DELTA(30)}}, 0x09, MI_TARGET_INAMP(0)},
! 2231: {{0, {AudioNsurround"."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2232: 0, 0, .un.e={4, {{{AudioNmicrophone}, 5}, {{AudioNcd}, 6},
! 2233: {{"line1"}, 7}, {{"line2"}, 8}}}},
! 2234: 0x09, MI_TARGET_CONNLIST},
! 2235:
! 2236: {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2237: 0, 0, ENUM_OFFON}, 0x23, MI_TARGET_OUTAMP},
! 2238: {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 2239: 0, 0, .un.v={{""}, 1, MIXER_DELTA(15)}}, 0x23, MI_TARGET_OUTAMP}
! 2240: };
! 2241:
! 2242: int
! 2243: azalia_cmi9880_mixer_init(codec_t *this)
! 2244: {
! 2245: mixer_ctrl_t mc;
! 2246:
! 2247: this->nmixers = sizeof(cmi9880_mixer_items) / sizeof(mixer_item_t);
! 2248: this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
! 2249: M_DEVBUF, M_NOWAIT);
! 2250: if (this->mixers == NULL) {
! 2251: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 2252: return ENOMEM;
! 2253: }
! 2254: bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
! 2255: memcpy(this->mixers, cmi9880_mixer_items,
! 2256: sizeof(mixer_item_t) * this->nmixers);
! 2257: azalia_generic_mixer_fix_indexes(this);
! 2258: azalia_generic_mixer_default(this);
! 2259:
! 2260: mc.dev = -1;
! 2261: mc.type = AUDIO_MIXER_ENUM;
! 2262: mc.un.ord = 5; /* record.front.source=mic */
! 2263: azalia_generic_mixer_set(this, 0x08, MI_TARGET_CONNLIST, &mc);
! 2264: mc.un.ord = 7; /* record.surround.source=line1 */
! 2265: azalia_generic_mixer_set(this, 0x09, MI_TARGET_CONNLIST, &mc);
! 2266: mc.un.ord = 1; /* pindir: output */
! 2267: azalia_generic_mixer_set(this, 0x0b, MI_TARGET_PINDIR, &mc);
! 2268: azalia_generic_mixer_set(this, 0x0c, MI_TARGET_PINDIR, &mc);
! 2269: azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc);
! 2270: azalia_generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR, &mc);
! 2271: azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc);
! 2272: mc.un.ord = 0; /* front DAC -> headphones */
! 2273: azalia_generic_mixer_set(this, 0x0f, MI_TARGET_CONNLIST, &mc);
! 2274: mc.un.ord = 0; /* pindir: input */
! 2275: azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc); /* mic */
! 2276: azalia_generic_mixer_set(this, 0x13, MI_TARGET_PINDIR, &mc); /* SPDIF-in */
! 2277: azalia_generic_mixer_set(this, 0x1f, MI_TARGET_PINDIR, &mc); /* line1 */
! 2278: azalia_generic_mixer_set(this, 0x20, MI_TARGET_PINDIR, &mc); /* line2 */
! 2279: return 0;
! 2280: }
! 2281:
! 2282: int
! 2283: azalia_cmi9880_init_dacgroup(codec_t *this)
! 2284: {
! 2285: static const convgroupset_t dacs = {
! 2286: -1, 2,
! 2287: {{4, {0x03, 0x04, 0x05, 0x06}}, /* analog 8ch */
! 2288: {1, {0x07}}}}; /* digital */
! 2289: static const convgroupset_t adcs = {
! 2290: -1, 2,
! 2291: {{2, {0x08, 0x09}}, /* analog 4ch */
! 2292: {1, {0x0a}}}}; /* digital */
! 2293:
! 2294: this->dacs = dacs;
! 2295: this->adcs = adcs;
! 2296: return 0;
! 2297: }
! 2298:
! 2299: /* ----------------------------------------------------------------
! 2300: * Sigmatel STAC9221 and STAC9221D
! 2301: * ---------------------------------------------------------------- */
! 2302:
! 2303: int
! 2304: azalia_stac9221_init_dacgroup(codec_t *this)
! 2305: {
! 2306: static const convgroupset_t dacs = {
! 2307: -1, 3,
! 2308: {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
! 2309: {1, {0x08}}, /* digital */
! 2310: {1, {0x1a}}}}; /* another digital? */
! 2311: static const convgroupset_t adcs = {
! 2312: -1, 2,
! 2313: {{2, {0x06, 0x07}}, /* analog 4ch */
! 2314: {1, {0x09}}}}; /* digital */
! 2315:
! 2316: this->dacs = dacs;
! 2317: this->adcs = adcs;
! 2318: return 0;
! 2319: }
! 2320:
! 2321: /* ----------------------------------------------------------------
! 2322: * Sigmatel STAC9200
! 2323: * ---------------------------------------------------------------- */
! 2324:
! 2325: static const mixer_item_t stac9200_mixer_items[] = {
! 2326: {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
! 2327: {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
! 2328: {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
! 2329:
! 2330: {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2331: 4, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_OUTAMP},
! 2332: {{0, {AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2333: 0, 3, ENUM_OFFON}, 0x0b, MI_TARGET_OUTAMP},
! 2334: {{0, {AudioNvolume}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
! 2335: 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x0a, MI_TARGET_OUTAMP},
! 2336: {{0, {AudioNvolume"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2337: 0, 0, ENUM_OFFON}, 0x0a, MI_TARGET_OUTAMP},
! 2338: {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2339: 0, 0, .un.e={5, {{{AudioNline}, 0}, {{AudioNmicrophone}, 1},
! 2340: {{AudioNline"2"}, 2}, {{AudioNline"3"}, 3},
! 2341: {{AudioNcd}, 4}}}},
! 2342: 0x0c, MI_TARGET_CONNLIST},
! 2343: {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
! 2344: 0, 0, .un.v={{""}, 2, MIXER_DELTA(4)}}, 0x0c, MI_TARGET_OUTAMP},
! 2345: {{0, {AudioNmicrophone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2346: 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_OUTAMP},
! 2347: {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2348: 0, 0, .un.e={3, {{{AudioNdac}, 0}, {{"digital-in"}, 1}, {{"selector"}, 2}}}},
! 2349: 0x07, MI_TARGET_CONNLIST},
! 2350: {{0, {"digital."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2351: 0, 0, .un.e={2, {{{AudioNdac}, 0}, {{"selector"}, 1}}}},
! 2352: 0x09, MI_TARGET_CONNLIST}, /* AudioNdac is not accurate name */
! 2353: {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2354: 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_PINBOOST},
! 2355: {{0, {AudioNspeaker".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2356: 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_PINBOOST},
! 2357: {{0, {AudioNmono"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2358: 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_OUTAMP},
! 2359: {{0, {AudioNmono}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2360: 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x11, MI_TARGET_OUTAMP},
! 2361: {{0, {"beep."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2362: 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
! 2363: {{0, {"beep"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2364: 0, 0, .un.v={{""}, 1, MIXER_DELTA(3)}}, 0x14, MI_TARGET_OUTAMP},
! 2365: {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
! 2366: 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}},
! 2367: 0, MI_TARGET_DAC},
! 2368: {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2369: 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}},
! 2370: 0, MI_TARGET_ADC},
! 2371: };
! 2372:
! 2373: int
! 2374: azalia_stac9200_mixer_init(codec_t *this)
! 2375: {
! 2376: mixer_ctrl_t mc;
! 2377:
! 2378: this->nmixers = sizeof(stac9200_mixer_items) / sizeof(mixer_item_t);
! 2379: this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
! 2380: M_DEVBUF, M_NOWAIT);
! 2381: if (this->mixers == NULL) {
! 2382: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 2383: return ENOMEM;
! 2384: }
! 2385: bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
! 2386: memcpy(this->mixers, stac9200_mixer_items,
! 2387: sizeof(mixer_item_t) * this->nmixers);
! 2388: azalia_generic_mixer_fix_indexes(this);
! 2389: azalia_generic_mixer_default(this);
! 2390:
! 2391: mc.dev = -1; /* no need for generic_mixer_set() */
! 2392: mc.type = AUDIO_MIXER_ENUM;
! 2393: mc.un.ord = 1; /* pindir: output */
! 2394: azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc); /* headphones */
! 2395: azalia_generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR, &mc); /* speaker */
! 2396: mc.un.ord = 0; /* pindir: input */
! 2397: azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); /* mic2 */
! 2398: azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc); /* mic1 */
! 2399: mc.type = AUDIO_MIXER_VALUE;
! 2400: mc.un.value.num_channels = 2;
! 2401: mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x0c, MI_TARGET_OUTAMP);
! 2402: mc.un.value.level[1] = mc.un.value.level[0];
! 2403: azalia_generic_mixer_set(this, 0x0c, MI_TARGET_OUTAMP, &mc);
! 2404:
! 2405: #define STAC9200_EVENT_HP 0
! 2406: #define STAC9200_NID_HP 0x0d
! 2407: #define STAC9200_NID_SPEAKER 0x0e
! 2408:
! 2409: /* register hp unsolicited event */
! 2410: this->comresp(this, STAC9200_NID_HP,
! 2411: CORB_SET_UNSOLICITED_RESPONSE,
! 2412: CORB_UNSOL_ENABLE | STAC9200_EVENT_HP, NULL);
! 2413:
! 2414: azalia_stac9200_unsol_event(this, STAC9200_EVENT_HP);
! 2415:
! 2416: return 0;
! 2417: }
! 2418: int
! 2419: azalia_stac9200_unsol_event(codec_t *this, int tag)
! 2420: {
! 2421: int err;
! 2422: uint32_t value;
! 2423:
! 2424: switch (tag) {
! 2425: case STAC9200_EVENT_HP:
! 2426: err = this->comresp(this, STAC9200_NID_HP,
! 2427: CORB_GET_PIN_SENSE, 0, &value);
! 2428: if (err)
! 2429: break;
! 2430: if (value & CORB_PS_PRESENCE) {
! 2431: DPRINTF(("%s: headphone inserted\n", __func__));
! 2432: azalia_generic_mixer_pinctrl(this,
! 2433: STAC9200_NID_SPEAKER, 0);
! 2434: } else {
! 2435: DPRINTF(("%s: headphone pulled\n", __func__));
! 2436: azalia_generic_mixer_pinctrl(this,
! 2437: STAC9200_NID_SPEAKER, CORB_PWC_OUTPUT);
! 2438: }
! 2439: break;
! 2440: default:
! 2441: DPRINTF(("%s: unknown tag: %d\n", __func__, tag));
! 2442: }
! 2443: return 0;
! 2444: }
! 2445:
! 2446: int
! 2447: azalia_stac9221_apple_init_dacgroup(codec_t *this)
! 2448: {
! 2449: static const convgroupset_t dacs = {
! 2450: -1, 1,
! 2451: {{4, {0x02, 0x03, 0x04, 0x05}}}};
! 2452:
! 2453: static const convgroupset_t adcs = {
! 2454: -1, 2,
! 2455: {{2, {0x06, 0x07}},
! 2456: {1, {0x09}}}};
! 2457:
! 2458: this->dacs = dacs;
! 2459: this->adcs = adcs;
! 2460: return 0;
! 2461: }
! 2462:
! 2463: static const mixer_item_t stac9221_apple_mixer_items[] = {
! 2464: {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
! 2465: {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
! 2466: {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
! 2467:
! 2468: {{0, {AudioNheadphone}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2469: 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x02, MI_TARGET_OUTAMP},
! 2470: {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2471: 0, 0, ENUM_OFFON}, 0x02, MI_TARGET_OUTAMP},
! 2472:
! 2473: {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2474: 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x03, MI_TARGET_OUTAMP},
! 2475: {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2476: 0, 0, ENUM_OFFON}, 0x03, MI_TARGET_OUTAMP},
! 2477:
! 2478: {{0, {"line"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2479: 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x04, MI_TARGET_OUTAMP},
! 2480: {{0, {"line.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2481: 0, 0, ENUM_OFFON}, 0x04, MI_TARGET_OUTAMP},
! 2482:
! 2483: {{0, {"line2"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2484: 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x05, MI_TARGET_OUTAMP},
! 2485: {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2486: 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP},
! 2487:
! 2488: {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2489: 0, 0, .un.v={{""}, 1, MIXER_DELTA(15)}}, 0x16, MI_TARGET_VOLUME},
! 2490: };
! 2491:
! 2492: int
! 2493: azalia_stac9221_apple_mixer_init(codec_t *this)
! 2494: {
! 2495: mixer_ctrl_t mc;
! 2496:
! 2497: this->nmixers = sizeof(stac9221_apple_mixer_items) / sizeof(mixer_item_t);
! 2498: this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
! 2499: M_DEVBUF, M_NOWAIT);
! 2500: if (this->mixers == NULL) {
! 2501: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 2502: return ENOMEM;
! 2503: }
! 2504: bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
! 2505: memcpy(this->mixers, stac9221_apple_mixer_items,
! 2506: sizeof(mixer_item_t) * this->nmixers);
! 2507: azalia_generic_mixer_fix_indexes(this);
! 2508: azalia_generic_mixer_default(this);
! 2509:
! 2510: mc.dev = -1;
! 2511: mc.type = AUDIO_MIXER_ENUM;
! 2512: mc.un.ord = 1; /* pindir: output */
! 2513: azalia_generic_mixer_set(this, 0x0a, MI_TARGET_PINDIR, &mc); /* headphones */
! 2514: azalia_generic_mixer_set(this, 0x0b, MI_TARGET_PINDIR, &mc); /* mic, set to output */
! 2515: azalia_generic_mixer_set(this, 0x0c, MI_TARGET_PINDIR, &mc); /* speaker */
! 2516: azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc); /* line out */
! 2517: azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); /* another line out */
! 2518:
! 2519: /* max all volumes except master */
! 2520: mc.type = AUDIO_MIXER_VALUE;
! 2521: mc.un.value.num_channels = 2;
! 2522: mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x02, MI_TARGET_OUTAMP);
! 2523: mc.un.value.level[1] = mc.un.value.level[0];
! 2524: azalia_generic_mixer_set(this, 0x02, MI_TARGET_OUTAMP, &mc);
! 2525:
! 2526: mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x03, MI_TARGET_OUTAMP);
! 2527: mc.un.value.level[1] = mc.un.value.level[0];
! 2528: azalia_generic_mixer_set(this, 0x03, MI_TARGET_OUTAMP, &mc);
! 2529:
! 2530: mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x04, MI_TARGET_OUTAMP);
! 2531: mc.un.value.level[1] = mc.un.value.level[0];
! 2532: azalia_generic_mixer_set(this, 0x04, MI_TARGET_OUTAMP, &mc);
! 2533:
! 2534: mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x05, MI_TARGET_OUTAMP);
! 2535: mc.un.value.level[1] = mc.un.value.level[0];
! 2536: azalia_generic_mixer_set(this, 0x05, MI_TARGET_OUTAMP, &mc);
! 2537:
! 2538: azalia_stac9221_gpio_unmute(this, 0);
! 2539: azalia_stac9221_gpio_unmute(this, 1);
! 2540:
! 2541: return 0;
! 2542: }
! 2543:
! 2544: int
! 2545: azalia_stac9221_gpio_unmute(codec_t *this, int pin)
! 2546: {
! 2547: uint32_t data, mask, dir;
! 2548:
! 2549: this->comresp(this, this->audiofunc, CORB_GET_GPIO_DATA, 0, &data);
! 2550: this->comresp(this, this->audiofunc, CORB_GET_GPIO_ENABLE_MASK, 0, &mask);
! 2551: this->comresp(this, this->audiofunc, CORB_GET_GPIO_DIRECTION, 0, &dir);
! 2552:
! 2553: data |= 1 << pin;
! 2554: mask |= 1 << pin;
! 2555: dir |= 1 << pin;
! 2556:
! 2557: this->comresp(this, this->audiofunc, 0x7e7, 0, NULL);
! 2558: this->comresp(this, this->audiofunc, CORB_SET_GPIO_ENABLE_MASK, mask, NULL);
! 2559: this->comresp(this, this->audiofunc, CORB_SET_GPIO_DIRECTION, dir, NULL);
! 2560: DELAY(1000);
! 2561: this->comresp(this, this->audiofunc, CORB_SET_GPIO_DATA, data, NULL);
! 2562:
! 2563: return 0;
! 2564: }
! 2565:
! 2566: /* ----------------------------------------------------------------
! 2567: * Sony VAIO FE and SZ
! 2568: * ---------------------------------------------------------------- */
! 2569:
! 2570: int
! 2571: azalia_stac7661_init_dacgroup(codec_t *this)
! 2572: {
! 2573: static const convgroupset_t dacs = {
! 2574: -1, 1,
! 2575: {{2, {0x02, 0x05}}}};
! 2576:
! 2577: static const convgroupset_t adcs = {
! 2578: -1, 1,
! 2579: {{1, {0x08}}}};
! 2580:
! 2581: this->dacs = dacs;
! 2582: this->adcs = adcs;
! 2583:
! 2584: return 0;
! 2585: }
! 2586:
! 2587: static const mixer_item_t stac7661_mixer_items[] = {
! 2588: {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
! 2589: {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
! 2590: {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
! 2591:
! 2592: #define STAC7661_DAC_HP 0x02
! 2593: #define STAC7661_DAC_SPEAKER 0x05
! 2594: #define STAC7661_TARGET_MASTER -1
! 2595:
! 2596: {{0, {AudioNvolume"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
! 2597: ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)},
! 2598: {{0, {AudioNvolume}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
! 2599: .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x09, MI_TARGET_INAMP(0)},
! 2600: {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
! 2601: 0, 0, .un.e={3, {{{AudioNmicrophone}, 1}, {{AudioNmicrophone"2"}, 2},
! 2602: {{AudioNdac}, 3}}}},
! 2603: 0x15, MI_TARGET_CONNLIST},
! 2604: {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2605: 0, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x02, STAC7661_TARGET_MASTER},
! 2606: {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2607: 0, 0, ENUM_OFFON}, 0x02, STAC7661_TARGET_MASTER},
! 2608: {{0, {AudioNvolume".knob"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2609: 0, 0, .un.v={{""}, 1, MIXER_DELTA(15)}}, 0x17, MI_TARGET_VOLUME},
! 2610: {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2611: 0, 0, ENUM_OFFON}, 0x02, MI_TARGET_OUTAMP},
! 2612: {{0, {AudioNheadphone}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2613: 0, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x02, MI_TARGET_OUTAMP},
! 2614: {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
! 2615: 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP},
! 2616: {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
! 2617: 0, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x05, MI_TARGET_OUTAMP}
! 2618: };
! 2619:
! 2620: int
! 2621: azalia_stac7661_mixer_init(codec_t *this)
! 2622: {
! 2623: mixer_ctrl_t mc;
! 2624:
! 2625: this->nmixers = sizeof(stac7661_mixer_items) / sizeof(mixer_item_t);
! 2626: this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
! 2627: M_DEVBUF, M_NOWAIT);
! 2628: if (this->mixers == NULL) {
! 2629: printf("%s: out of memory in %s\n", XNAME(this), __func__);
! 2630: return ENOMEM;
! 2631: }
! 2632: bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
! 2633: memcpy(this->mixers, stac7661_mixer_items,
! 2634: sizeof(mixer_item_t) * this->nmixers);
! 2635: azalia_generic_mixer_fix_indexes(this);
! 2636: azalia_generic_mixer_default(this);
! 2637: mc.dev = -1;
! 2638: mc.type = AUDIO_MIXER_ENUM;
! 2639: mc.un.ord = 1;
! 2640: azalia_generic_mixer_set(this, 0x0a, MI_TARGET_PINDIR, &mc); /* headphones */
! 2641: azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); /* speaker */
! 2642: azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(0), &mc); /* mute input */
! 2643: mc.un.ord = 0;
! 2644: azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc); /* mic */
! 2645: azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc); /* internal mic */
! 2646: mc.un.ord = 2; /* select internal mic for recording */
! 2647: azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc);
! 2648: mc.type = AUDIO_MIXER_VALUE;
! 2649: mc.un.value.num_channels = 1;
! 2650: mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x17, MI_TARGET_VOLUME);
! 2651: azalia_generic_mixer_set(this, 0x17, MI_TARGET_VOLUME, &mc);
! 2652:
! 2653: return 0;
! 2654: }
! 2655:
! 2656: int
! 2657: azalia_stac7661_set_port(codec_t *this, mixer_ctrl_t *mc)
! 2658: {
! 2659: const mixer_item_t *m;
! 2660: int err;
! 2661:
! 2662: if (mc->dev >= this->nmixers)
! 2663: return ENXIO;
! 2664: m = &this->mixers[mc->dev];
! 2665: if (mc->type != m->devinfo.type)
! 2666: return EINVAL;
! 2667: if (mc->type == AUDIO_MIXER_CLASS)
! 2668: return 0;
! 2669: if (m->target == STAC7661_TARGET_MASTER) {
! 2670: err = azalia_generic_mixer_set(this, STAC7661_DAC_HP,
! 2671: MI_TARGET_OUTAMP, mc);
! 2672: err = azalia_generic_mixer_set(this, STAC7661_DAC_SPEAKER,
! 2673: MI_TARGET_OUTAMP, mc);
! 2674: return err;
! 2675: }
! 2676: return azalia_generic_mixer_set(this, m->nid, m->target, mc);
! 2677: }
! 2678: int
! 2679: azalia_stac7661_get_port(codec_t *this, mixer_ctrl_t *mc)
! 2680: {
! 2681: const mixer_item_t *m;
! 2682:
! 2683: if (mc->dev >= this->nmixers)
! 2684: return ENXIO;
! 2685: m = &this->mixers[mc->dev];
! 2686: mc->type = m->devinfo.type;
! 2687: if (mc->type == AUDIO_MIXER_CLASS)
! 2688: return 0;
! 2689: if (m->target == STAC7661_TARGET_MASTER)
! 2690: return azalia_generic_mixer_get(this, m->nid,
! 2691: MI_TARGET_OUTAMP, mc);
! 2692: return azalia_generic_mixer_get(this, m->nid, m->target, mc);
! 2693: }
CVSweb