[BACK]Return to azalia_codec.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/azalia_codec.c, Revision 1.1.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