root/dev/pci/azalia_codec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. azalia_codec_init_vtbl
  2. azalia_generic_codec_init_dacgroup
  3. azalia_generic_codec_add_dacgroup
  4. azalia_generic_codec_find_pin
  5. azalia_generic_codec_find_dac
  6. azalia_generic_mixer_init
  7. azalia_generic_mixer_ensure_capacity
  8. azalia_generic_mixer_fix_indexes
  9. azalia_generic_mixer_default
  10. azalia_generic_mixer_delete
  11. azalia_generic_mixer_get
  12. azalia_generic_mixer_set
  13. azalia_generic_mixer_pinctrl
  14. azalia_generic_mixer_from_device_value
  15. azalia_generic_mixer_to_device_value
  16. azalia_generic_mixer_max
  17. azalia_generic_mixer_validate_value
  18. azalia_generic_set_port
  19. azalia_generic_get_port
  20. azalia_alc260_mixer_init
  21. azalia_alc260_init_dacgroup
  22. azalia_alc260_set_port
  23. azalia_alc880_init_dacgroup
  24. azalia_alc882_mixer_init
  25. azalia_alc882_init_dacgroup
  26. azalia_alc882_set_port
  27. azalia_alc882_get_port
  28. azalia_alc883_init_dacgroup
  29. azalia_alc883_mixer_init
  30. azalia_ad1981hd_init_widget
  31. azalia_ad1981hd_mixer_init
  32. azalia_cmi9880_mixer_init
  33. azalia_cmi9880_init_dacgroup
  34. azalia_stac9221_init_dacgroup
  35. azalia_stac9200_mixer_init
  36. azalia_stac9200_unsol_event
  37. azalia_stac9221_apple_init_dacgroup
  38. azalia_stac9221_apple_mixer_init
  39. azalia_stac9221_gpio_unmute
  40. azalia_stac7661_init_dacgroup
  41. azalia_stac7661_mixer_init
  42. azalia_stac7661_set_port
  43. azalia_stac7661_get_port

    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 }

/* [<][>][^][v][top][bottom][index][help] */