The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/ac97.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ac97.c,v 1.100 2020/10/18 11:51:08 rin Exp $ */
    2 /*      $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $       */
    3 
    4 /*
    5  * Copyright (c) 1999, 2000 Constantine Sapuntzakis
    6  *
    7  * Author:        Constantine Sapuntzakis <csapuntz@stanford.edu>
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. The name of the author may not be used to endorse or promote
   18  *    products derived from this software without specific prior written
   19  *    permission.
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
   21  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
   24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
   26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
   30  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
   31  * DAMAGE
   32  */
   33 
   34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
   35    the following copyright */
   36 
   37 /*
   38  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
   39  * All rights reserved.
   40  *
   41  * Redistribution and use in source and binary forms, with or without
   42  * modification, are permitted provided that the following conditions
   43  * are met:
   44  * 1. Redistributions of source code must retain the above copyright
   45  *    notice, this list of conditions and the following disclaimer.
   46  * 2. Redistributions in binary form must reproduce the above copyright
   47  *    notice, this list of conditions and the following disclaimer in the
   48  *    documentation and/or other materials provided with the distribution.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  *
   62  * $FreeBSD$
   63  */
   64 
   65 #include <sys/cdefs.h>
   66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.100 2020/10/18 11:51:08 rin Exp $");
   67 
   68 #include <sys/param.h>
   69 #include <sys/systm.h>
   70 #include <sys/kernel.h>
   71 #include <sys/malloc.h>
   72 #include <sys/device.h>
   73 #include <sys/sysctl.h>
   74 
   75 #include <sys/audioio.h>
   76 #include <dev/audio/audio_if.h>
   77 
   78 #include <dev/ic/ac97reg.h>
   79 #include <dev/ic/ac97var.h>
   80 
   81 struct ac97_softc;
   82 struct ac97_source_info;
   83 static int      ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
   84 static int      ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
   85 static void     ac97_detach(struct ac97_codec_if *);
   86 static void     ac97_lock(struct ac97_codec_if *);
   87 static void     ac97_unlock(struct ac97_codec_if *);
   88 static int      ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
   89 static int      ac97_get_portnum_by_name(struct ac97_codec_if *, const char *,
   90                                          const char *, const char *);
   91 static void     ac97_restore_shadow(struct ac97_codec_if *);
   92 static int      ac97_set_rate(struct ac97_codec_if *, int, u_int *);
   93 static void     ac97_set_clock(struct ac97_codec_if *, unsigned int);
   94 static uint16_t ac97_get_extcaps(struct ac97_codec_if *);
   95 static int      ac97_add_port(struct ac97_softc *,
   96                               const struct ac97_source_info *);
   97 static int      ac97_str_equal(const char *, const char *);
   98 static int      ac97_check_capability(struct ac97_softc *, int);
   99 static void     ac97_setup_source_info(struct ac97_softc *);
  100 static void     ac97_read(struct ac97_softc *, uint8_t, uint16_t *);
  101 static void     ac97_setup_defaults(struct ac97_softc *);
  102 static int      ac97_write(struct ac97_softc *, uint8_t, uint16_t);
  103 
  104 static void     ac97_ad198x_init(struct ac97_softc *);
  105 static void     ac97_alc650_init(struct ac97_softc *);
  106 static void     ac97_ucb1400_init(struct ac97_softc *);
  107 static void     ac97_vt1616_init(struct ac97_softc *);
  108 
  109 static int      ac97_modem_offhook_set(struct ac97_softc *, int, int);
  110 static int      ac97_sysctl_verify(SYSCTLFN_ARGS);
  111 
  112 #define Ac97Nphone      "phone"
  113 #define Ac97Nline1      "line1"
  114 #define Ac97Nline2      "line2"
  115 #define Ac97Nhandset    "handset"
  116 
  117 static const struct audio_mixer_enum
  118 ac97_on_off = { 2, { { { AudioNoff, 0 } , 0 },
  119                      { { AudioNon, 0 }  , 1 },
  120                      { { "", 0 }        , 0 },
  121                      { { "", 0 }        , 0 },
  122                      { { "", 0 }        , 0 },
  123                      { { "", 0 }        , 0 },
  124                      { { "", 0 }        , 0 },
  125                      { { "", 0 }        , 0 },
  126                      { { "", 0 }        , 0 },
  127                      { { "", 0 }        , 0 },
  128                      { { "", 0 }        , 0 },
  129                      { { "", 0 }        , 0 },
  130                      { { "", 0 }        , 0 },
  131                      { { "", 0 }        , 0 },
  132                      { { "", 0 }        , 0 },
  133                      { { "", 0 }        , 0 },
  134                      { { "", 0 }        , 0 },
  135                      { { "", 0 }        , 0 },
  136                      { { "", 0 }        , 0 },
  137                      { { "", 0 }        , 0 },
  138                      { { "", 0 }        , 0 },
  139                      { { "", 0 }        , 0 },
  140                      { { "", 0 }        , 0 },
  141                      { { "", 0 }        , 0 },
  142                      { { "", 0 }        , 0 },
  143                      { { "", 0 }        , 0 },
  144                      { { "", 0 }        , 0 },
  145                      { { "", 0 }        , 0 },
  146                      { { "", 0 }        , 0 },
  147                      { { "", 0 }        , 0 },
  148                      { { "", 0 }        , 0 },
  149                      { { "", 0 }        , 0 }, } };
  150 
  151 static const struct audio_mixer_enum
  152 ac97_mic_select = { 2, { { { AudioNmicrophone "", 0  }, 0 },
  153                          { { AudioNmicrophone "1", 0  }, 1 },
  154                          { { "", 0 }    , 0 },
  155                          { { "", 0 }    , 0 },
  156                          { { "", 0 }    , 0 },
  157                          { { "", 0 }    , 0 },
  158                          { { "", 0 }    , 0 },
  159                          { { "", 0 }    , 0 },
  160                          { { "", 0 }    , 0 },
  161                          { { "", 0 }    , 0 },
  162                          { { "", 0 }    , 0 },
  163                          { { "", 0 }    , 0 },
  164                          { { "", 0 }    , 0 },
  165                          { { "", 0 }    , 0 },
  166                          { { "", 0 }    , 0 },
  167                          { { "", 0 }    , 0 },
  168                          { { "", 0 }    , 0 },
  169                          { { "", 0 }    , 0 },
  170                          { { "", 0 }    , 0 },
  171                          { { "", 0 }    , 0 },
  172                          { { "", 0 }    , 0 },
  173                          { { "", 0 }    , 0 },
  174                          { { "", 0 }    , 0 },
  175                          { { "", 0 }    , 0 },
  176                          { { "", 0 }    , 0 },
  177                          { { "", 0 }    , 0 },
  178                          { { "", 0 }    , 0 },
  179                          { { "", 0 }    , 0 },
  180                          { { "", 0 }    , 0 },
  181                          { { "", 0 }    , 0 },
  182                          { { "", 0 }    , 0 },
  183                          { { "", 0 }    , 0 }, } };
  184 
  185 static const struct audio_mixer_enum
  186 ac97_mono_select = { 2, { { { AudioNmixerout, 0  }, 0 },
  187                           { { AudioNmicrophone, 0  }, 1 },
  188                           { { "", 0 }   , 0 },
  189                           { { "", 0 }   , 0 },
  190                           { { "", 0 }   , 0 },
  191                           { { "", 0 }   , 0 },
  192                           { { "", 0 }   , 0 },
  193                           { { "", 0 }   , 0 },
  194                           { { "", 0 }   , 0 },
  195                           { { "", 0 }   , 0 },
  196                           { { "", 0 }   , 0 },
  197                           { { "", 0 }   , 0 },
  198                           { { "", 0 }   , 0 },
  199                           { { "", 0 }   , 0 },
  200                           { { "", 0 }   , 0 },
  201                           { { "", 0 }   , 0 },
  202                           { { "", 0 }   , 0 },
  203                           { { "", 0 }   , 0 },
  204                           { { "", 0 }   , 0 },
  205                           { { "", 0 }   , 0 },
  206                           { { "", 0 }   , 0 },
  207                           { { "", 0 }   , 0 },
  208                           { { "", 0 }   , 0 },
  209                           { { "", 0 }   , 0 },
  210                           { { "", 0 }   , 0 },
  211                           { { "", 0 }   , 0 },
  212                           { { "", 0 }   , 0 },
  213                           { { "", 0 }   , 0 },
  214                           { { "", 0 }   , 0 },
  215                           { { "", 0 }   , 0 },
  216                           { { "", 0 }   , 0 },
  217                           { { "", 0 }   , 0 }, } };
  218 
  219 static const struct audio_mixer_enum
  220 ac97_source = { 8, { { { AudioNmicrophone, 0  } , 0 },
  221                      { { AudioNcd, 0 }, 1 },
  222                      { { AudioNvideo, 0 }, 2 },
  223                      { { AudioNaux, 0 }, 3 },
  224                      { { AudioNline, 0 }, 4 },
  225                      { { AudioNmixerout, 0 }, 5 },
  226                      { { AudioNmixerout AudioNmono, 0 }, 6 },
  227                      { { Ac97Nphone, 0 }, 7 },
  228                      { { "", 0 }        , 0 },
  229                      { { "", 0 }        , 0 },
  230                      { { "", 0 }        , 0 },
  231                      { { "", 0 }        , 0 },
  232                      { { "", 0 }        , 0 },
  233                      { { "", 0 }        , 0 },
  234                      { { "", 0 }        , 0 },
  235                      { { "", 0 }        , 0 },
  236                      { { "", 0 }        , 0 },
  237                      { { "", 0 }        , 0 },
  238                      { { "", 0 }        , 0 },
  239                      { { "", 0 }        , 0 },
  240                      { { "", 0 }        , 0 },
  241                      { { "", 0 }        , 0 },
  242                      { { "", 0 }        , 0 },
  243                      { { "", 0 }        , 0 },
  244                      { { "", 0 }        , 0 },
  245                      { { "", 0 }        , 0 },
  246                      { { "", 0 }        , 0 },
  247                      { { "", 0 }        , 0 },
  248                      { { "", 0 }        , 0 },
  249                      { { "", 0 }        , 0 },
  250                      { { "", 0 }        , 0 },
  251                      { { "", 0 }        , 0 }, } };
  252 
  253 /*
  254  * Due to different values for each source that uses these structures,
  255  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
  256  * ac97_source_info.bits.
  257  */
  258 static const struct audio_mixer_value
  259 ac97_volume_stereo = { { AudioNvolume, 0 }, 2, 0 };
  260 
  261 static const struct audio_mixer_value
  262 ac97_volume_mono = { { AudioNvolume, 0 }, 1, 0 };
  263 
  264 #define WRAP(a)  &a, sizeof(a)
  265 
  266 struct ac97_source_info {
  267         const char *class;
  268         const char *device;
  269         const char *qualifier;
  270 
  271         int  type;
  272         const void *info;
  273         int  info_size;
  274 
  275         uint8_t  reg;
  276         int32_t  default_value;
  277         unsigned bits:3;
  278         unsigned ofs:4;
  279         unsigned mute:1;
  280         unsigned polarity:1;   /* Does 0 == MAX or MIN */
  281         unsigned checkbits:1;
  282         enum {
  283                 CHECK_NONE = 0,
  284                 CHECK_SURROUND,
  285                 CHECK_CENTER,
  286                 CHECK_LFE,
  287                 CHECK_HEADPHONES,
  288                 CHECK_TONE,
  289                 CHECK_MIC,
  290                 CHECK_LOUDNESS,
  291                 CHECK_3D,
  292                 CHECK_LINE1,
  293                 CHECK_LINE2,
  294                 CHECK_HANDSET,
  295                 CHECK_SPDIF
  296         } req_feature;
  297 
  298         int  prev;
  299         int  next;
  300         int  mixer_class;
  301 };
  302 
  303 static const struct ac97_source_info audio_source_info[] = {
  304         { AudioCinputs,         NULL,           NULL,
  305           AUDIO_MIXER_CLASS,    NULL,           0,
  306           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
  307         { AudioCoutputs,        NULL,           0,
  308           AUDIO_MIXER_CLASS,    NULL,           0,
  309           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
  310         { AudioCrecord,         NULL,           0,
  311           AUDIO_MIXER_CLASS,    NULL,           0,
  312           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
  313         /* Stereo master volume*/
  314         { AudioCoutputs,        AudioNmaster,   0,
  315           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  316           AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1, 0, 1, 0, 0, 0, 0,
  317         },
  318         /* Mono volume */
  319         { AudioCoutputs,        AudioNmono,     NULL,
  320           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  321           AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1, 0, 1, 0, 0, 0, 0,
  322         },
  323         { AudioCoutputs,        AudioNmono,     AudioNsource,
  324           AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
  325           AC97_REG_GP, 0x0000, 1, 9, 0, 0, 0, 0, 0, 0, 0,
  326         },
  327         /* Headphone volume */
  328         { AudioCoutputs,        AudioNheadphone, NULL,
  329           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  330           AC97_REG_HEADPHONE_VOLUME, 0x8000, 5, 0, 1, 0, 1, CHECK_HEADPHONES, 0, 0, 0,
  331         },
  332         /* Surround volume - logic hard coded for mute */
  333         { AudioCoutputs,        AudioNsurround, NULL,
  334           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  335           AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, 1, CHECK_SURROUND, 0, 0, 0
  336         },
  337         /* Center volume*/
  338         { AudioCoutputs,        AudioNcenter,   NULL,
  339           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  340           AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, 1, CHECK_CENTER, 0, 0, 0
  341         },
  342         { AudioCoutputs,        AudioNcenter,   AudioNmute,
  343           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  344           AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, 0, CHECK_CENTER, 0, 0, 0
  345         },
  346         /* LFE volume*/
  347         { AudioCoutputs,        AudioNlfe,      NULL,
  348           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  349           AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, 1, CHECK_LFE, 0, 0, 0
  350         },
  351         { AudioCoutputs,        AudioNlfe,      AudioNmute,
  352           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  353           AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, 0, CHECK_LFE, 0, 0, 0
  354         },
  355         /* Tone - bass */
  356         { AudioCoutputs,        AudioNbass,     NULL,
  357           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  358           AC97_REG_MASTER_TONE, 0x0f0f, 4, 8, 0, 0, 0, CHECK_TONE, 0, 0, 0
  359         },
  360         /* Tone - treble */
  361         { AudioCoutputs,        AudioNtreble,   NULL,
  362           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  363           AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, 0, CHECK_TONE, 0, 0, 0
  364         },
  365         /* PC Beep Volume */
  366         { AudioCinputs,         AudioNspeaker,  NULL,
  367           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  368           AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1, 0, 0, 0, 0, 0, 0,
  369         },
  370 
  371         /* Phone */
  372         { AudioCinputs,         Ac97Nphone,     NULL,
  373           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  374           AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0,
  375         },
  376         /* Mic Volume */
  377         { AudioCinputs,         AudioNmicrophone, NULL,
  378           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  379           AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0,
  380         },
  381         { AudioCinputs,         AudioNmicrophone, AudioNpreamp,
  382           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  383           AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0, 0, 0, 0, 0, 0, 0,
  384         },
  385         { AudioCinputs,         AudioNmicrophone, AudioNsource,
  386           AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
  387           AC97_REG_GP, 0x0000, 1, 8, 0, 0, 0, 0, 0, 0, 0,
  388         },
  389         /* Line in Volume */
  390         { AudioCinputs,         AudioNline,     NULL,
  391           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  392           AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
  393         },
  394         /* CD Volume */
  395         { AudioCinputs,         AudioNcd,       NULL,
  396           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  397           AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
  398         },
  399         /* Video Volume */
  400         { AudioCinputs,         AudioNvideo,    NULL,
  401           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  402           AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
  403         },
  404         /* AUX volume */
  405         { AudioCinputs,         AudioNaux,      NULL,
  406           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  407           AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
  408         },
  409         /* PCM out volume */
  410         { AudioCinputs,         AudioNdac,      NULL,
  411           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  412           AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
  413         },
  414         /* Record Source - some logic for this is hard coded - see below */
  415         { AudioCrecord,         AudioNsource,   NULL,
  416           AUDIO_MIXER_ENUM, WRAP(ac97_source),
  417           AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0, 0, 0, 0, 0, 0, 0,
  418         },
  419         /* Record Gain */
  420         { AudioCrecord,         AudioNvolume,   NULL,
  421           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  422           AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 1, 0, 0, 0, 0, 0,
  423         },
  424         /* Record Gain mic */
  425         { AudioCrecord,         AudioNmicrophone, NULL,
  426           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  427           AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, 0, CHECK_MIC, 0, 0, 0
  428         },
  429         /* */
  430         { AudioCoutputs,        AudioNloudness, NULL,
  431           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  432           AC97_REG_GP, 0x0000, 1, 12, 0, 0, 0, CHECK_LOUDNESS, 0, 0, 0
  433         },
  434         { AudioCoutputs,        AudioNspatial,  NULL,
  435           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  436           AC97_REG_GP, 0x0000, 1, 13, 0, 1, 0, CHECK_3D, 0, 0, 0
  437         },
  438         { AudioCoutputs,        AudioNspatial,  "center",
  439           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  440           AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, 0, CHECK_3D, 0, 0, 0
  441         },
  442         { AudioCoutputs,        AudioNspatial,  "depth",
  443           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  444           AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, 0, CHECK_3D, 0, 0, 0
  445         },
  446 
  447         /* SPDIF */
  448         { "spdif", NULL, NULL,
  449           AUDIO_MIXER_CLASS, NULL, 0,
  450           0, 0, 0, 0, 0, 0, 0, CHECK_SPDIF, 0, 0, 0
  451         },
  452         { "spdif", "enable", NULL,
  453           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  454           AC97_REG_EXT_AUDIO_CTRL, -1, 1, 2, 0, 0, 0, CHECK_SPDIF, 0, 0, 0
  455         },
  456 
  457         /* Missing features: Simulated Stereo, POP, Loopback mode */
  458 };
  459 
  460 static const struct ac97_source_info modem_source_info[] = {
  461         /* Classes */
  462         { AudioCinputs,         NULL,           NULL,
  463           AUDIO_MIXER_CLASS,    NULL,           0,
  464           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
  465         { AudioCoutputs,        NULL,           NULL,
  466           AUDIO_MIXER_CLASS,    NULL,           0,
  467           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
  468         { AudioCinputs,         Ac97Nline1,     NULL,
  469           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  470           AC97_REG_LINE1_LEVEL, 0x8080, 4, 0, 0, 1, 0, CHECK_LINE1, 0, 0, 0
  471         },
  472         { AudioCoutputs,        Ac97Nline1,     NULL,
  473           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  474           AC97_REG_LINE1_LEVEL, 0x8080, 4, 8, 0, 1, 0, CHECK_LINE1, 0, 0, 0
  475         },
  476         { AudioCinputs,         Ac97Nline1,     AudioNmute,
  477           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  478           AC97_REG_LINE1_LEVEL, 0x8080, 1, 7, 0, 0, 0, CHECK_LINE1, 0, 0, 0
  479         },
  480         { AudioCoutputs,        Ac97Nline1,     AudioNmute,
  481           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  482           AC97_REG_LINE1_LEVEL, 0x8080, 1, 15, 0, 0, 0, CHECK_LINE1, 0, 0, 0
  483         },
  484 };
  485 
  486 #define AUDIO_SOURCE_INFO_SIZE \
  487                 (sizeof(audio_source_info)/sizeof(audio_source_info[0]))
  488 #define MODEM_SOURCE_INFO_SIZE \
  489                 (sizeof(modem_source_info)/sizeof(modem_source_info[0]))
  490 #define SOURCE_INFO_SIZE(as) ((as)->type == AC97_CODEC_TYPE_MODEM ? \
  491                 MODEM_SOURCE_INFO_SIZE : AUDIO_SOURCE_INFO_SIZE)
  492 
  493 /*
  494  * Check out http://www.intel.com/support/motherboards/desktop/sb/cs-025406.htm for
  495  * AC'97 Component Specification
  496  */
  497 
  498 struct ac97_softc {
  499         /* ac97_codec_if must be at the first of ac97_softc. */
  500         struct ac97_codec_if codec_if;
  501 
  502         struct ac97_host_if *host_if;
  503 
  504         kmutex_t *lock;
  505 
  506 #define AUDIO_MAX_SOURCES       (2 * AUDIO_SOURCE_INFO_SIZE)
  507 #define MODEM_MAX_SOURCES       (2 * MODEM_SOURCE_INFO_SIZE)
  508         struct ac97_source_info audio_source_info[AUDIO_MAX_SOURCES];
  509         struct ac97_source_info modem_source_info[MODEM_MAX_SOURCES];
  510         struct ac97_source_info *source_info;
  511         int num_source_info;
  512 
  513         enum ac97_host_flags host_flags;
  514         unsigned int ac97_clock; /* usually 48000 */
  515 #define AC97_STANDARD_CLOCK     48000U
  516         uint16_t power_all;
  517         uint16_t power_reg;     /* -> AC97_REG_POWER */
  518         uint16_t caps;          /* -> AC97_REG_RESET */
  519         uint16_t ext_id;        /* -> AC97_REG_EXT_AUDIO_ID */
  520         uint16_t ext_mid;       /* -> AC97_REG_EXT_MODEM_ID */
  521         uint16_t shadow_reg[128];
  522 
  523         int lock_counter;
  524         int type;
  525 
  526         /* sysctl */
  527         struct sysctllog *log;
  528         int offhook_line1_mib;
  529         int offhook_line2_mib;
  530         int offhook_line1;
  531         int offhook_line2;
  532 };
  533 
  534 static struct ac97_codec_if_vtbl ac97civ = {
  535         ac97_mixer_get_port,
  536         ac97_mixer_set_port,
  537         ac97_query_devinfo,
  538         ac97_get_portnum_by_name,
  539         ac97_restore_shadow,
  540         ac97_get_extcaps,
  541         ac97_set_rate,
  542         ac97_set_clock,
  543         ac97_detach,
  544         ac97_lock,
  545         ac97_unlock,
  546 };
  547 
  548 static const struct ac97_codecid {
  549         uint32_t id;
  550         uint32_t mask;
  551         const char *name;
  552         void (*init)(struct ac97_softc *);
  553 } ac97codecid[] = {
  554         /*
  555          * Analog Devices SoundMAX
  556          * http://www.soundmax.com/products/information/codecs.html
  557          * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf
  558          * http://www.analog.com/productSelection/pdf/AD1885_0.pdf
  559          * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf
  560          * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf
  561          * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf
  562          * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf
  563          */
  564         { AC97_CODEC_ID('A', 'D', 'S', 3),
  565           0xffffffff,                   "Analog Devices AD1819B", NULL, },
  566         { AC97_CODEC_ID('A', 'D', 'S', 0x40),
  567           0xffffffff,                   "Analog Devices AD1881", NULL, },
  568         { AC97_CODEC_ID('A', 'D', 'S', 0x48),
  569           0xffffffff,                   "Analog Devices AD1881A", NULL, },
  570         { AC97_CODEC_ID('A', 'D', 'S', 0x60),
  571           0xffffffff,                   "Analog Devices AD1885", NULL, },
  572         { AC97_CODEC_ID('A', 'D', 'S', 0x61),
  573           0xffffffff,                   "Analog Devices AD1886", NULL, },
  574         { AC97_CODEC_ID('A', 'D', 'S', 0x63),
  575           0xffffffff,                   "Analog Devices AD1886A", NULL, },
  576         { AC97_CODEC_ID('A', 'D', 'S', 0x68),
  577           0xffffffff,                   "Analog Devices AD1888", ac97_ad198x_init },
  578         { AC97_CODEC_ID('A', 'D', 'S', 0x70),
  579           0xffffffff,                   "Analog Devices AD1980", ac97_ad198x_init },
  580         { AC97_CODEC_ID('A', 'D', 'S', 0x72),
  581           0xffffffff,                   "Analog Devices AD1981A", NULL, },
  582         { AC97_CODEC_ID('A', 'D', 'S', 0x74),
  583           0xffffffff,                   "Analog Devices AD1981B", NULL, },
  584         { AC97_CODEC_ID('A', 'D', 'S', 0x75),
  585           0xffffffff,                   "Analog Devices AD1985", ac97_ad198x_init },
  586         { AC97_CODEC_ID('A', 'D', 'S', 0),
  587           AC97_VENDOR_ID_MASK,          "Analog Devices unknown", NULL, },
  588 
  589         /*
  590          * Datasheets:
  591          *      http://www.asahi-kasei.co.jp/akm/japanese/product/ak4543/ek4543.pdf
  592          *      http://www.asahi-kasei.co.jp/akm/japanese/product/ak4544a/ek4544a.pdf
  593          *      http://www.asahi-kasei.co.jp/akm/japanese/product/ak4545/ak4545_f00e.pdf
  594          */
  595         { AC97_CODEC_ID('A', 'K', 'M', 0),
  596           0xffffffff,                   "Asahi Kasei AK4540", NULL,     },
  597         { AC97_CODEC_ID('A', 'K', 'M', 1),
  598           0xffffffff,                   "Asahi Kasei AK4542", NULL,     },
  599         { AC97_CODEC_ID('A', 'K', 'M', 2),
  600           0xffffffff,                   "Asahi Kasei AK4541/AK4543", NULL, },
  601         { AC97_CODEC_ID('A', 'K', 'M', 5),
  602           0xffffffff,                   "Asahi Kasei AK4544", NULL, },
  603         { AC97_CODEC_ID('A', 'K', 'M', 6),
  604           0xffffffff,                   "Asahi Kasei AK4544A", NULL, },
  605         { AC97_CODEC_ID('A', 'K', 'M', 7),
  606           0xffffffff,                   "Asahi Kasei AK4545", NULL, },
  607         { AC97_CODEC_ID('A', 'K', 'M', 0),
  608           AC97_VENDOR_ID_MASK,          "Asahi Kasei unknown", NULL, },
  609 
  610         /*
  611          * Realtek & Avance Logic
  612          *      http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
  613          *
  614          * ALC650 and ALC658 support VRA, but it supports only 8000, 11025,
  615          * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz.
  616          */
  617         { AC97_CODEC_ID('A', 'L', 'C', 0x00),
  618           0xfffffff0,                   "Realtek RL5306", NULL, },
  619         { AC97_CODEC_ID('A', 'L', 'C', 0x10),
  620           0xfffffff0,                   "Realtek RL5382", NULL, },
  621         { AC97_CODEC_ID('A', 'L', 'C', 0x20),
  622           0xfffffff0,                   "Realtek RL5383/RL5522/ALC100", NULL,   },
  623         { AC97_CODEC_ID('A', 'L', 'G', 0x10),
  624           0xffffffff,                   "Avance Logic ALC200/ALC201", NULL,     },
  625         { AC97_CODEC_ID('A', 'L', 'G', 0x20),
  626           0xfffffff0,                   "Avance Logic ALC650", ac97_alc650_init },
  627         { AC97_CODEC_ID('A', 'L', 'G', 0x30),
  628           0xffffffff,                   "Avance Logic ALC101", NULL,    },
  629         { AC97_CODEC_ID('A', 'L', 'G', 0x40),
  630           0xffffffff,                   "Avance Logic ALC202", NULL,    },
  631         { AC97_CODEC_ID('A', 'L', 'G', 0x50),
  632           0xffffffff,                   "Avance Logic ALC250", NULL,    },
  633         { AC97_CODEC_ID('A', 'L', 'G', 0x60),
  634           0xfffffff0,                   "Avance Logic ALC655", NULL,    },
  635         { AC97_CODEC_ID('A', 'L', 'G', 0x70),
  636           0xffffffff,                   "Avance Logic ALC203", NULL,    },
  637         { AC97_CODEC_ID('A', 'L', 'G', 0x80),
  638           0xfffffff0,                   "Avance Logic ALC658", NULL,    },
  639         { AC97_CODEC_ID('A', 'L', 'G', 0x90),
  640           0xfffffff0,                   "Avance Logic ALC850", NULL,    },
  641         { AC97_CODEC_ID('A', 'L', 'C', 0),
  642           AC97_VENDOR_ID_MASK,          "Realtek unknown", NULL,        },
  643         { AC97_CODEC_ID('A', 'L', 'G', 0),
  644           AC97_VENDOR_ID_MASK,          "Avance Logic unknown", NULL,   },
  645 
  646         /**
  647          * C-Media Electronics Inc.
  648          * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf
  649          */
  650         { AC97_CODEC_ID('C', 'M', 'I', 0x61),
  651           0xffffffff,                   "C-Media CMI9739", NULL,        },
  652         { AC97_CODEC_ID('C', 'M', 'I', 0),
  653           AC97_VENDOR_ID_MASK,          "C-Media unknown", NULL,        },
  654 
  655         /* Cirrus Logic, Crystal series:
  656          *  'C' 'R' 'Y' 0x0[0-7]  - CS4297
  657          *              0x1[0-7]  - CS4297A
  658          *              0x2[0-7]  - CS4298
  659          *              0x2[8-f]  - CS4294
  660          *              0x3[0-7]  - CS4299
  661          *              0x4[8-f]  - CS4201
  662          *              0x5[8-f]  - CS4205
  663          *              0x6[0-7]  - CS4291
  664          *              0x7[0-7]  - CS4202
  665          * Datasheets:
  666          *      http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
  667          *      http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
  668          *      http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
  669          *      http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
  670          *      http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
  671          *      http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
  672          */
  673         { AC97_CODEC_ID('C', 'R', 'Y', 0x00),
  674           0xfffffff8,                   "Crystal CS4297", NULL, },
  675         { AC97_CODEC_ID('C', 'R', 'Y', 0x10),
  676           0xfffffff8,                   "Crystal CS4297A", NULL,        },
  677         { AC97_CODEC_ID('C', 'R', 'Y', 0x20),
  678           0xfffffff8,                   "Crystal CS4298", NULL, },
  679         { AC97_CODEC_ID('C', 'R', 'Y', 0x28),
  680           0xfffffff8,                   "Crystal CS4294", NULL, },
  681         { AC97_CODEC_ID('C', 'R', 'Y', 0x30),
  682           0xfffffff8,                   "Crystal CS4299", NULL, },
  683         { AC97_CODEC_ID('C', 'R', 'Y', 0x48),
  684           0xfffffff8,                   "Crystal CS4201", NULL, },
  685         { AC97_CODEC_ID('C', 'R', 'Y', 0x58),
  686           0xfffffff8,                   "Crystal CS4205", NULL, },
  687         { AC97_CODEC_ID('C', 'R', 'Y', 0x60),
  688           0xfffffff8,                   "Crystal CS4291", NULL, },
  689         { AC97_CODEC_ID('C', 'R', 'Y', 0x70),
  690           0xfffffff8,                   "Crystal CS4202", NULL, },
  691         { AC97_CODEC_ID('C', 'R', 'Y', 0),
  692           AC97_VENDOR_ID_MASK,          "Cirrus Logic unknown", NULL,   },
  693 
  694         { 0x45838308, 0xffffffff,       "ESS Technology ES1921", NULL, },
  695         { 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", NULL, },
  696 
  697         { AC97_CODEC_ID('H', 'R', 'S', 0),
  698           0xffffffff,                   "Intersil HMP9701", NULL,       },
  699         { AC97_CODEC_ID('H', 'R', 'S', 0),
  700           AC97_VENDOR_ID_MASK,          "Intersil unknown", NULL,       },
  701 
  702         /*
  703          * IC Ensemble (VIA)
  704          *      http://www.viatech.com/en/datasheet/DS1616.pdf
  705          */
  706         { AC97_CODEC_ID('I', 'C', 'E', 0x01),
  707           0xffffffff,                   "ICEnsemble ICE1230/VT1611", NULL,      },
  708         { AC97_CODEC_ID('I', 'C', 'E', 0x11),
  709           0xffffffff,                   "ICEnsemble ICE1232/VT1611A", NULL,     },
  710         { AC97_CODEC_ID('I', 'C', 'E', 0x14),
  711           0xffffffff,                   "ICEnsemble ICE1232A", NULL,    },
  712         { AC97_CODEC_ID('I', 'C', 'E', 0x51),
  713           0xffffffff,                   "VIA Technologies VT1616", ac97_vt1616_init },
  714         { AC97_CODEC_ID('I', 'C', 'E', 0x52),
  715           0xffffffff,                   "VIA Technologies VT1616i", ac97_vt1616_init },
  716         { AC97_CODEC_ID('I', 'C', 'E', 0),
  717           AC97_VENDOR_ID_MASK,          "ICEnsemble/VIA unknown", NULL, },
  718 
  719         { AC97_CODEC_ID('N', 'S', 'C', 0),
  720           0xffffffff,                   "National Semiconductor LM454[03568]", NULL, },
  721         { AC97_CODEC_ID('N', 'S', 'C', 49),
  722           0xffffffff,                   "National Semiconductor LM4549", NULL, },
  723         { AC97_CODEC_ID('N', 'S', 'C', 0),
  724           AC97_VENDOR_ID_MASK,          "National Semiconductor unknown", NULL, },
  725 
  726         { AC97_CODEC_ID('P', 'S', 'C', 4),
  727           0xffffffff,                   "Philips Semiconductor UCB1400", ac97_ucb1400_init, },
  728         { AC97_CODEC_ID('P', 'S', 'C', 0),
  729           AC97_VENDOR_ID_MASK,          "Philips Semiconductor unknown", NULL, },
  730 
  731         { AC97_CODEC_ID('S', 'I', 'L', 34),
  732           0xffffffff,                   "Silicon Laboratory Si3036", NULL, },
  733         { AC97_CODEC_ID('S', 'I', 'L', 35),
  734           0xffffffff,                   "Silicon Laboratory Si3038", NULL, },
  735         { AC97_CODEC_ID('S', 'I', 'L', 0),
  736           AC97_VENDOR_ID_MASK,          "Silicon Laboratory unknown", NULL, },
  737 
  738         { AC97_CODEC_ID('T', 'R', 'A', 2),
  739           0xffffffff,                   "TriTech TR28022", NULL,        },
  740         { AC97_CODEC_ID('T', 'R', 'A', 3),
  741           0xffffffff,                   "TriTech TR28023", NULL,        },
  742         { AC97_CODEC_ID('T', 'R', 'A', 6),
  743           0xffffffff,                   "TriTech TR28026", NULL,        },
  744         { AC97_CODEC_ID('T', 'R', 'A', 8),
  745           0xffffffff,                   "TriTech TR28028", NULL,        },
  746         { AC97_CODEC_ID('T', 'R', 'A', 35),
  747           0xffffffff,                   "TriTech TR28602", NULL,        },
  748         { AC97_CODEC_ID('T', 'R', 'A', 0),
  749           AC97_VENDOR_ID_MASK,          "TriTech unknown", NULL,        },
  750 
  751         { AC97_CODEC_ID('T', 'X', 'N', 0x20),
  752           0xffffffff,                   "Texas Instruments TLC320AD9xC", NULL, },
  753         { AC97_CODEC_ID('T', 'X', 'N', 0),
  754           AC97_VENDOR_ID_MASK,          "Texas Instruments unknown", NULL, },
  755 
  756         /*
  757          * VIA
  758          * http://www.viatech.com/en/multimedia/audio.jsp
  759          */
  760         { AC97_CODEC_ID('V', 'I', 'A', 0x61),
  761           0xffffffff,                   "VIA Technologies VT1612A", NULL, },
  762         { AC97_CODEC_ID('V', 'I', 'A', 0),
  763           AC97_VENDOR_ID_MASK,          "VIA Technologies unknown", NULL, },
  764 
  765         { AC97_CODEC_ID('W', 'E', 'C', 1),
  766           0xffffffff,                   "Winbond W83971D", NULL,        },
  767         { AC97_CODEC_ID('W', 'E', 'C', 0),
  768           AC97_VENDOR_ID_MASK,          "Winbond unknown", NULL,        },
  769 
  770         /*
  771          * http://www.wolfsonmicro.com/product_list.asp?cid=64
  772          *      http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
  773          *      http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf  - 03
  774          *      http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
  775          *      http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
  776          *      http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
  777          *      http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf  - 03
  778          *      http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
  779          *      http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
  780          */
  781         { AC97_CODEC_ID('W', 'M', 'L', 0),
  782           0xffffffff,                   "Wolfson WM9701A", NULL,        },
  783         { AC97_CODEC_ID('W', 'M', 'L', 3),
  784           0xffffffff,                   "Wolfson WM9703/WM9707/WM9708", NULL,   },
  785         { AC97_CODEC_ID('W', 'M', 'L', 4),
  786           0xffffffff,                   "Wolfson WM9704", NULL, },
  787         { AC97_CODEC_ID('W', 'M', 'L', 5),
  788           0xffffffff,                   "Wolfson WM9705/WM9710", NULL, },
  789         { AC97_CODEC_ID('W', 'M', 'L', 0),
  790           AC97_VENDOR_ID_MASK,          "Wolfson unknown", NULL,        },
  791 
  792         /*
  793          * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
  794          * Datasheets:
  795          *      http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
  796          *      http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
  797          */
  798         { AC97_CODEC_ID('Y', 'M', 'H', 0),
  799           0xffffffff,                   "Yamaha YMF743-S", NULL,        },
  800         { AC97_CODEC_ID('Y', 'M', 'H', 3),
  801           0xffffffff,                   "Yamaha YMF753-S", NULL,        },
  802         { AC97_CODEC_ID('Y', 'M', 'H', 0),
  803           AC97_VENDOR_ID_MASK,          "Yamaha unknown", NULL, },
  804 
  805         /*
  806          * http://www.sigmatel.com/products/technical_docs.htm
  807          * and
  808          * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf
  809          */
  810         { 0x83847600, 0xffffffff,       "SigmaTel STAC9700",    NULL, },
  811         { 0x83847604, 0xffffffff,       "SigmaTel STAC9701/3/4/5", NULL, },
  812         { 0x83847605, 0xffffffff,       "SigmaTel STAC9704",    NULL, },
  813         { 0x83847608, 0xffffffff,       "SigmaTel STAC9708",    NULL, },
  814         { 0x83847609, 0xffffffff,       "SigmaTel STAC9721/23", NULL, },
  815         { 0x83847644, 0xffffffff,       "SigmaTel STAC9744/45", NULL, },
  816         { 0x83847650, 0xffffffff,       "SigmaTel STAC9750/51", NULL, },
  817         { 0x83847652, 0xffffffff,       "SigmaTel STAC9752/53", NULL, },
  818         { 0x83847656, 0xffffffff,       "SigmaTel STAC9756/57", NULL, },
  819         { 0x83847658, 0xffffffff,       "SigmaTel STAC9758/59", NULL, },
  820         { 0x83847666, 0xffffffff,       "SigmaTel STAC9766/67", NULL, },
  821         { 0x83847684, 0xffffffff,       "SigmaTel STAC9783/84", NULL, },
  822         { 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown",  NULL, },
  823 
  824         /* Conexant AC'97 modems -- good luck finding datasheets! */
  825         { AC97_CODEC_ID('C', 'X', 'T', 33),
  826           0xffffffff,                   "Conexant HSD11246", NULL, },
  827         { AC97_CODEC_ID('C', 'X', 'T', 34),
  828           0xffffffff,                   "Conexant D480 MDC V.92 Modem", NULL, },
  829         { AC97_CODEC_ID('C', 'X', 'T', 48),
  830           0xffffffff,                   "Conexant CXT48", NULL, },
  831         { AC97_CODEC_ID('C', 'X', 'T', 0),
  832           AC97_VENDOR_ID_MASK,          "Conexant unknown", NULL, },
  833 
  834         { 0,
  835           0,                    NULL,   NULL,           },
  836 };
  837 
  838 static const char * const ac97enhancement[] = {
  839         "no 3D stereo",
  840         "Analog Devices Phat Stereo",
  841         "Creative",
  842         "National Semi 3D",
  843         "Yamaha Ymersion",
  844         "BBE 3D",
  845         "Crystal Semi 3D",
  846         "Qsound QXpander",
  847         "Spatializer 3D",
  848         "SRS 3D",
  849         "Platform Tech 3D",
  850         "AKM 3D",
  851         "Aureal",
  852         "AZTECH 3D",
  853         "Binaura 3D",
  854         "ESS Technology",
  855         "Harman International VMAx",
  856         "Nvidea 3D",
  857         "Philips Incredible Sound",
  858         "Texas Instruments' 3D",
  859         "VLSI Technology 3D",
  860         "TriTech 3D",
  861         "Realtek 3D",
  862         "Samsung 3D",
  863         "Wolfson Microelectronics 3D",
  864         "Delta Integration 3D",
  865         "SigmaTel 3D",
  866         "KS Waves 3D",
  867         "Rockwell 3D",
  868         "Unknown 3D",
  869         "Unknown 3D",
  870         "Unknown 3D",
  871 };
  872 
  873 static const char * const ac97feature[] = {
  874         "dedicated mic channel",
  875         "reserved",
  876         "tone",
  877         "simulated stereo",
  878         "headphone",
  879         "bass boost",
  880         "18 bit DAC",
  881         "20 bit DAC",
  882         "18 bit ADC",
  883         "20 bit ADC"
  884 };
  885 
  886 
  887 /* #define AC97_DEBUG 10 */
  888 /* #define AC97_IO_DEBUG */
  889 
  890 #ifdef AUDIO_DEBUG
  891 #define DPRINTF(x)      if (ac97debug) printf x
  892 #define DPRINTFN(n,x)   if (ac97debug>(n)) printf x
  893 #ifdef AC97_DEBUG
  894 int     ac97debug = AC97_DEBUG;
  895 #else
  896 int     ac97debug = 0;
  897 #endif
  898 #else
  899 #define DPRINTF(x)
  900 #define DPRINTFN(n,x)
  901 #endif
  902 
  903 #ifdef AC97_IO_DEBUG
  904 static const char *ac97_register_names[0x80 / 2] = {
  905         "RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO",
  906         "MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME",
  907         "LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME",
  908         "PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC",
  909         "GP", "3D_CONTROL", "AUDIO_INT", "POWER",
  910         "EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE",
  911         "PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER",
  912         "SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL",
  913         "LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL",
  914         "LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY",
  915         "GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL",
  916         "0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E",
  917         "0x60", "0x62", "0x64", "0x66",
  918         "0x68", "0x6a", "0x6c", "0x6e",
  919         "VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76",
  920         "VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2"
  921 };
  922 #endif
  923 
  924 /*
  925  * XXX Some cards have an inverted AC97_POWER_EAMP bit.
  926  * These cards will produce no sound unless AC97_HOST_INVERTED_EAMP is set.
  927  */
  928 
  929 #define POWER_EAMP_ON(as)  ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
  930                             ? AC97_POWER_EAMP : 0)
  931 #define POWER_EAMP_OFF(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
  932                             ? 0 : AC97_POWER_EAMP)
  933 
  934 static void
  935 ac97_read(struct ac97_softc *as, uint8_t reg, uint16_t *val)
  936 {
  937         KASSERT(mutex_owned(as->lock));
  938 
  939         if (as->host_flags & AC97_HOST_DONT_READ &&
  940             (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
  941              reg != AC97_REG_RESET)) {
  942                 *val = as->shadow_reg[reg >> 1];
  943                 return;
  944         }
  945 
  946         if (as->host_if->read(as->host_if->arg, reg, val)) {
  947                 *val = as->shadow_reg[reg >> 1];
  948         }
  949 }
  950 
  951 static int
  952 ac97_write(struct ac97_softc *as, uint8_t reg, uint16_t val)
  953 {
  954         KASSERT(mutex_owned(as->lock));
  955 
  956 #ifndef AC97_IO_DEBUG
  957         as->shadow_reg[reg >> 1] = val;
  958         return as->host_if->write(as->host_if->arg, reg, val);
  959 #else
  960         int ret;
  961         uint16_t actual;
  962 
  963         as->shadow_reg[reg >> 1] = val;
  964         ret = as->host_if->write(as->host_if->arg, reg, val);
  965         as->host_if->read(as->host_if->arg, reg, &actual);
  966         if (val != actual && reg < 0x80) {
  967                 printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n",
  968                        ac97_register_names[reg / 2], val, actual);
  969         }
  970         return ret;
  971 #endif
  972 }
  973 
  974 static void
  975 ac97_setup_defaults(struct ac97_softc *as)
  976 {
  977         int idx;
  978         const struct ac97_source_info *si;
  979 
  980         KASSERT(mutex_owned(as->lock));
  981 
  982         memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
  983 
  984         for (idx = 0; idx < AUDIO_SOURCE_INFO_SIZE; idx++) {
  985                 si = &audio_source_info[idx];
  986                 if (si->default_value >= 0)
  987                         ac97_write(as, si->reg, si->default_value);
  988         }
  989         for (idx = 0; idx < MODEM_SOURCE_INFO_SIZE; idx++) {
  990                 si = &modem_source_info[idx];
  991                 if (si->default_value >= 0)
  992                         ac97_write(as, si->reg, si->default_value);
  993         }
  994 }
  995 
  996 static void
  997 ac97_restore_shadow(struct ac97_codec_if *codec_if)
  998 {
  999         struct ac97_softc *as;
 1000         const struct ac97_source_info *si;
 1001         int idx;
 1002         uint16_t val;
 1003 
 1004         as = (struct ac97_softc *)codec_if;
 1005 
 1006         KASSERT(mutex_owned(as->lock));
 1007 
 1008         if (as->type == AC97_CODEC_TYPE_AUDIO) {
 1009                 /* restore AC97_REG_POWER */
 1010                 ac97_write(as, AC97_REG_POWER, as->power_reg);
 1011                 /* make sure chip is fully operational */
 1012                 for (idx = 50000; idx >= 0; idx--) {
 1013                         ac97_read(as, AC97_REG_POWER, &val);
 1014                         if ((val & as->power_all) == as->power_all)
 1015                                 break;
 1016                         DELAY(10);
 1017                 }
 1018 
 1019                 /*
 1020                  * actually try changing a value!
 1021                  * The default value of AC97_REG_MASTER_VOLUME is 0x8000.
 1022                  */
 1023                 for (idx = 50000; idx >= 0; idx--) {
 1024                         ac97_write(as, AC97_REG_MASTER_VOLUME, 0x1010);
 1025                         ac97_read(as, AC97_REG_MASTER_VOLUME, &val);
 1026                         if (val == 0x1010)
 1027                                 break;
 1028                         DELAY(10);
 1029                 }
 1030         }
 1031 
 1032        for (idx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
 1033                 if (as->type == AC97_CODEC_TYPE_MODEM)
 1034                         si = &modem_source_info[idx];
 1035                 else
 1036                         si = &audio_source_info[idx];
 1037                 /* don't "restore" to the reset reg! */
 1038                 if (si->reg != AC97_REG_RESET)
 1039                         ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
 1040         }
 1041 
 1042         if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
 1043                           | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
 1044                           | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
 1045                           | AC97_EXT_AUDIO_LDAC)) {
 1046                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
 1047                     as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]);
 1048         }
 1049         if (as->ext_mid & (AC97_EXT_MODEM_LINE1 | AC97_EXT_MODEM_LINE2
 1050                           | AC97_EXT_MODEM_HANDSET | AC97_EXT_MODEM_CID1
 1051                           | AC97_EXT_MODEM_CID2 | AC97_EXT_MODEM_ID0
 1052                           | AC97_EXT_MODEM_ID1)) {
 1053                 ac97_write(as, AC97_REG_EXT_MODEM_CTRL,
 1054                     as->shadow_reg[AC97_REG_EXT_MODEM_CTRL >> 1]);
 1055         }
 1056 }
 1057 
 1058 static int
 1059 ac97_str_equal(const char *a, const char *b)
 1060 {
 1061         return (a == b) || (a && b && (!strcmp(a, b)));
 1062 }
 1063 
 1064 static int
 1065 ac97_check_capability(struct ac97_softc *as, int check)
 1066 {
 1067         switch (check) {
 1068         case CHECK_NONE:
 1069                 return 1;
 1070         case CHECK_SURROUND:
 1071                 return as->ext_id & AC97_EXT_AUDIO_SDAC;
 1072         case CHECK_CENTER:
 1073                 return as->ext_id & AC97_EXT_AUDIO_CDAC;
 1074         case CHECK_LFE:
 1075                 return as->ext_id & AC97_EXT_AUDIO_LDAC;
 1076         case CHECK_SPDIF:
 1077                 return as->ext_id & AC97_EXT_AUDIO_SPDIF;
 1078         case CHECK_HEADPHONES:
 1079                 return as->caps & AC97_CAPS_HEADPHONES;
 1080         case CHECK_TONE:
 1081                 return as->caps & AC97_CAPS_TONECTRL;
 1082         case CHECK_MIC:
 1083                 return as->caps & AC97_CAPS_MICIN;
 1084         case CHECK_LOUDNESS:
 1085                 return as->caps & AC97_CAPS_LOUDNESS;
 1086         case CHECK_3D:
 1087                 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
 1088         case CHECK_LINE1:
 1089                 return as->ext_mid & AC97_EXT_MODEM_LINE1;
 1090         case CHECK_LINE2:
 1091                 return as->ext_mid & AC97_EXT_MODEM_LINE2;
 1092         case CHECK_HANDSET:
 1093                 return as->ext_mid & AC97_EXT_MODEM_HANDSET;
 1094         default:
 1095                 printf("%s: internal error: feature=%d\n", __func__, check);
 1096                 return 0;
 1097         }
 1098 }
 1099 
 1100 static void
 1101 ac97_setup_source_info(struct ac97_softc *as)
 1102 {
 1103         int idx, ouridx;
 1104         struct ac97_source_info *si, *si2;
 1105         uint16_t value1, value2, value3;
 1106 
 1107         KASSERT(mutex_owned(as->lock));
 1108 
 1109         for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
 1110                 si = &as->source_info[ouridx];
 1111                 if (as->type == AC97_CODEC_TYPE_MODEM) {
 1112                         memcpy(si, &modem_source_info[idx], sizeof(*si));
 1113                 } else {
 1114                         memcpy(si, &audio_source_info[idx], sizeof(*si));
 1115                 }
 1116                 if (!ac97_check_capability(as, si->req_feature))
 1117                         continue;
 1118                 if (si->checkbits) {
 1119                         /* read the register value */
 1120                         ac97_read(as, si->reg, &value1);
 1121                         /* write 0b100000 */
 1122                         value2 = value1 & 0xffc0;
 1123                         value2 |= 0x20;
 1124                         ac97_write(as, si->reg, value2);
 1125                         /* verify */
 1126                         ac97_read(as, si->reg, &value3);
 1127                         if (value2 == value3) {
 1128                                 si->bits = 6;
 1129                         } else {
 1130                                 si->bits = 5;
 1131                         }
 1132                         DPRINTF(("%s: register=%02x bits=%d\n",
 1133                             __func__, si->reg, si->bits));
 1134                         ac97_write(as, si->reg, value1);
 1135                 }
 1136 
 1137                 switch (si->type) {
 1138                 case AUDIO_MIXER_CLASS:
 1139                         si->mixer_class = ouridx;
 1140                         ouridx++;
 1141                         break;
 1142                 case AUDIO_MIXER_VALUE:
 1143                         /* Todo - Test to see if it works */
 1144                         ouridx++;
 1145 
 1146                         /* Add an entry for mute, if necessary */
 1147                         if (si->mute) {
 1148                                 si = &as->source_info[ouridx];
 1149                                 if (as->type == AC97_CODEC_TYPE_MODEM)
 1150                                         memcpy(si, &modem_source_info[idx],
 1151                                             sizeof(*si));
 1152                                 else
 1153                                         memcpy(si, &audio_source_info[idx],
 1154                                             sizeof(*si));
 1155                                 si->qualifier = AudioNmute;
 1156                                 si->type = AUDIO_MIXER_ENUM;
 1157                                 si->info = &ac97_on_off;
 1158                                 si->info_size = sizeof(ac97_on_off);
 1159                                 si->bits = 1;
 1160                                 si->ofs = 15;
 1161                                 si->mute = 0;
 1162                                 si->polarity = 0;
 1163                                 ouridx++;
 1164                         }
 1165                         break;
 1166                 case AUDIO_MIXER_ENUM:
 1167                         /* Todo - Test to see if it works */
 1168                         ouridx++;
 1169                         break;
 1170                 default:
 1171                         aprint_error ("ac97: shouldn't get here\n");
 1172                         break;
 1173                 }
 1174         }
 1175 
 1176         as->num_source_info = ouridx;
 1177 
 1178         for (idx = 0; idx < as->num_source_info; idx++) {
 1179                 int idx2, previdx;
 1180 
 1181                 si = &as->source_info[idx];
 1182 
 1183                 /* Find mixer class */
 1184                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
 1185                         si2 = &as->source_info[idx2];
 1186 
 1187                         if (si2->type == AUDIO_MIXER_CLASS &&
 1188                             ac97_str_equal(si->class,
 1189                                            si2->class)) {
 1190                                 si->mixer_class = idx2;
 1191                         }
 1192                 }
 1193 
 1194 
 1195                 /* Setup prev and next pointers */
 1196                 if (si->prev != 0)
 1197                         continue;
 1198 
 1199                 if (si->qualifier)
 1200                         continue;
 1201 
 1202                 si->prev = AUDIO_MIXER_LAST;
 1203                 previdx = idx;
 1204 
 1205                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
 1206                         if (idx2 == idx)
 1207                                 continue;
 1208 
 1209                         si2 = &as->source_info[idx2];
 1210 
 1211                         if (!si2->prev &&
 1212                             ac97_str_equal(si->class, si2->class) &&
 1213                             ac97_str_equal(si->device, si2->device)) {
 1214                                 as->source_info[previdx].next = idx2;
 1215                                 as->source_info[idx2].prev = previdx;
 1216 
 1217                                 previdx = idx2;
 1218                         }
 1219                 }
 1220 
 1221                 as->source_info[previdx].next = AUDIO_MIXER_LAST;
 1222         }
 1223 }
 1224 
 1225 /* backward compatibility */
 1226 int
 1227 ac97_attach(struct ac97_host_if *host_if, device_t sc_dev, kmutex_t *lk)
 1228 {
 1229         return ac97_attach_type(host_if, sc_dev, AC97_CODEC_TYPE_AUDIO, lk);
 1230 }
 1231 
 1232 int
 1233 ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type, kmutex_t *lk)
 1234 {
 1235         struct ac97_softc *as;
 1236         int error, i, j;
 1237         uint32_t id;
 1238         uint16_t id1, id2;
 1239         uint16_t extstat, rate;
 1240         uint16_t val;
 1241         mixer_ctrl_t ctl;
 1242         void (*initfunc)(struct ac97_softc *);
 1243 #define FLAGBUFLEN      140
 1244         char flagbuf[FLAGBUFLEN];
 1245 
 1246         initfunc = NULL;
 1247         as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
 1248 
 1249         if (as == NULL)
 1250                 return ENOMEM;
 1251 
 1252         as->codec_if.vtbl = &ac97civ;
 1253         as->host_if = host_if;
 1254         as->type = type;
 1255         as->lock = lk;
 1256 
 1257         if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
 1258                 free(as, M_DEVBUF);
 1259                 return error;
 1260         }
 1261 
 1262         mutex_enter(as->lock);
 1263 
 1264         if (host_if->reset != NULL) {
 1265                 if ((error = host_if->reset(host_if->arg))) {
 1266                         mutex_exit(as->lock);
 1267                         free(as, M_DEVBUF);
 1268                         return error;
 1269                 }
 1270         }
 1271 
 1272         if (host_if->flags)
 1273                 as->host_flags = host_if->flags(host_if->arg);
 1274 
 1275         /*
 1276          * Assume codec has all four power bits.
 1277          * XXXSCW: what to do for modems?
 1278          */
 1279         as->power_all = AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC |
 1280             AC97_POWER_ADC;
 1281         if (as->type == AC97_CODEC_TYPE_AUDIO) {
 1282                 host_if->write(host_if->arg, AC97_REG_RESET, 0);
 1283 
 1284                 /*
 1285                  * Power-up everything except the analogue mixer.
 1286                  * If this codec doesn't support analogue mixer power-down,
 1287                  * AC97_POWER_MIXER will read back as zero.
 1288                  */
 1289                 host_if->write(host_if->arg, AC97_REG_POWER, AC97_POWER_MIXER);
 1290                 ac97_read(as, AC97_REG_POWER, &val);
 1291                 if ((val & AC97_POWER_MIXER) == 0) {
 1292                         /* Codec doesn't support analogue mixer power-down */
 1293                         as->power_all &= ~AC97_POWER_ANL;
 1294                 }
 1295                 host_if->write(host_if->arg, AC97_REG_POWER, POWER_EAMP_ON(as));
 1296 
 1297                 for (i = 500000; i >= 0; i--) {
 1298                         ac97_read(as, AC97_REG_POWER, &val);
 1299                         if ((val & as->power_all) == as->power_all)
 1300                                break;
 1301                         DELAY(1);
 1302                 }
 1303 
 1304                 /* save AC97_REG_POWER so that we can restore it later */
 1305                 ac97_read(as, AC97_REG_POWER, &as->power_reg);
 1306         } else if (as->type == AC97_CODEC_TYPE_MODEM) {
 1307                 host_if->write(host_if->arg, AC97_REG_EXT_MODEM_ID, 0);
 1308         }
 1309 
 1310         ac97_setup_defaults(as);
 1311         if (as->type == AC97_CODEC_TYPE_AUDIO)
 1312                 ac97_read(as, AC97_REG_RESET, &as->caps);
 1313         ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
 1314         ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
 1315 
 1316         mutex_exit(as->lock);
 1317 
 1318         id = ((uint32_t)id1 << 16) | id2;
 1319         aprint_normal_dev(sc_dev, "ac97: ");
 1320 
 1321         for (i = 0; ; i++) {
 1322                 if (ac97codecid[i].id == 0) {
 1323                         char pnp[4];
 1324 
 1325                         AC97_GET_CODEC_ID(id, pnp);
 1326 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
 1327                         if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
 1328                             ISASCII(pnp[2]))
 1329                                 aprint_normal("%c%c%c%d",
 1330                                     pnp[0], pnp[1], pnp[2], pnp[3]);
 1331                         else
 1332                                 aprint_normal("unknown (0x%08x)", id);
 1333                         break;
 1334                 }
 1335                 if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
 1336                         aprint_normal("%s", ac97codecid[i].name);
 1337                         if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
 1338                                 aprint_normal(" (0x%08x)", id);
 1339                         }
 1340                         initfunc = ac97codecid[i].init;
 1341                         break;
 1342                 }
 1343         }
 1344         aprint_normal(" codec; ");
 1345         for (i = j = 0; i < 10; i++) {
 1346                 if (as->caps & (1 << i)) {
 1347                         aprint_normal("%s%s", j ? ", " : "", ac97feature[i]);
 1348                         j++;
 1349                 }
 1350         }
 1351         aprint_normal("%s%s\n", j ? ", " : "",
 1352                ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
 1353 
 1354         as->ac97_clock = AC97_STANDARD_CLOCK;
 1355 
 1356         mutex_enter(as->lock);
 1357 
 1358         if (as->type == AC97_CODEC_TYPE_AUDIO) {
 1359                 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
 1360                 if (as->ext_id != 0) {
 1361                         mutex_exit(as->lock);
 1362 
 1363                         /* Print capabilities */
 1364                         snprintb(flagbuf, sizeof(flagbuf),
 1365                              "\2\20SECONDARY10\17SECONDARY01"
 1366                              "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
 1367                              "\7CDAC\4VRM\3SPDIF\2DRA\1VRA", as->ext_id);
 1368                         aprint_normal_dev(sc_dev, "ac97: ext id %s\n",
 1369                                       flagbuf);
 1370 
 1371                         /* Print unusual settings */
 1372                         if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
 1373                                 aprint_normal_dev(sc_dev, "ac97: Slot assignment: ");
 1374                                 switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
 1375                                 case AC97_EXT_AUDIO_DSA01:
 1376                                         aprint_normal("7&8, 6&9, 10&11.\n");
 1377                                         break;
 1378                                 case AC97_EXT_AUDIO_DSA10:
 1379                                         aprint_normal("6&9, 10&11, 3&4.\n");
 1380                                         break;
 1381                                 case AC97_EXT_AUDIO_DSA11:
 1382                                         aprint_normal("10&11, 3&4, 7&8.\n");
 1383                                         break;
 1384                                 }
 1385                         }
 1386                         if (as->host_flags & AC97_HOST_INVERTED_EAMP) {
 1387                                 aprint_normal_dev(sc_dev, "ac97: using inverted "
 1388                                               "AC97_POWER_EAMP bit\n");
 1389                         }
 1390 
 1391                         mutex_enter(as->lock);
 1392 
 1393                         /* Enable and disable features */
 1394                         ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
 1395                         extstat &= ~AC97_EXT_AUDIO_DRA;
 1396                         if (as->ext_id & AC97_EXT_AUDIO_LDAC)
 1397                                 extstat |= AC97_EXT_AUDIO_LDAC;
 1398                         if (as->ext_id & AC97_EXT_AUDIO_SDAC)
 1399                                 extstat |= AC97_EXT_AUDIO_SDAC;
 1400                         if (as->ext_id & AC97_EXT_AUDIO_CDAC)
 1401                                 extstat |= AC97_EXT_AUDIO_CDAC;
 1402                         if (as->ext_id & AC97_EXT_AUDIO_VRM)
 1403                                 extstat |= AC97_EXT_AUDIO_VRM;
 1404                         if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
 1405                                 /* Output the same data as DAC to SPDIF output */
 1406                                 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
 1407                                 extstat |= AC97_EXT_AUDIO_SPSA34;
 1408                                 ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
 1409                                 val = (val & ~AC97_SPDIF_SPSR_MASK)
 1410                                     | AC97_SPDIF_SPSR_48K;
 1411                                 ac97_write(as, AC97_REG_SPDIF_CTRL, val);
 1412                         }
 1413                         if (as->ext_id & AC97_EXT_AUDIO_VRA)
 1414                                 extstat |= AC97_EXT_AUDIO_VRA;
 1415                         ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
 1416                         if (as->ext_id & AC97_EXT_AUDIO_VRA) {
 1417                                 /* VRA should be enabled. */
 1418                                 /* so it claims to do variable rate, let's make sure */
 1419                                 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
 1420                                            44100);
 1421                                 ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE,
 1422                                           &rate);
 1423                                 if (rate != 44100) {
 1424                                         /* We can't believe ext_id */
 1425                                         as->ext_id = 0;
 1426                                         aprint_normal_dev(sc_dev,
 1427                                             "Ignore these capabilities.\n");
 1428                                 }
 1429                                 /* restore the default value */
 1430                                 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
 1431                                            AC97_SINGLE_RATE);
 1432                         }
 1433                 }
 1434         } else if (as->type == AC97_CODEC_TYPE_MODEM) {
 1435                 const struct sysctlnode *node;
 1436                 const struct sysctlnode *node_line1;
 1437                 const struct sysctlnode *node_line2;
 1438                 uint16_t xrate = 8000;
 1439                 uint16_t xval, reg;
 1440                 int err;
 1441 
 1442                 ac97_read(as, AC97_REG_EXT_MODEM_ID, &as->ext_mid);
 1443                 mutex_exit(as->lock);
 1444 
 1445                 if (as->ext_mid == 0 || as->ext_mid == 0xffff) {
 1446                         aprint_normal_dev(sc_dev, "no modem codec found\n");
 1447                         free(as, M_DEVBUF);
 1448                         return ENXIO;
 1449                 }
 1450                 as->type = AC97_CODEC_TYPE_MODEM;
 1451 
 1452                 /* Print capabilities */
 1453                 snprintb(flagbuf, sizeof(flagbuf),
 1454                     "\2\5CID2\4CID1\3HANDSET\2LINE2\1LINE1", as->ext_mid);
 1455                 aprint_normal_dev(sc_dev, "ac97: ext mid %s",
 1456                               flagbuf);
 1457                 aprint_normal(", %s codec\n",
 1458                               (as->ext_mid & 0xc000) == 0 ?
 1459                               "primary" : "secondary");
 1460 
 1461                 /* Setup modem and sysctls */
 1462                 err = sysctl_createv(&as->log, 0, NULL, NULL, 0, CTLTYPE_NODE,
 1463                                      "hw", NULL, NULL, 0, NULL, 0, CTL_HW,
 1464                                      CTL_EOL);
 1465                 if (err != 0)
 1466                         goto setup_modem;
 1467                 err = sysctl_createv(&as->log, 0, NULL, &node, 0,
 1468                                      CTLTYPE_NODE, device_xname(sc_dev), NULL,
 1469                                      NULL, 0, NULL, 0, CTL_HW, CTL_CREATE,
 1470                                      CTL_EOL);
 1471                 if (err != 0)
 1472                         goto setup_modem;
 1473 setup_modem:
 1474                 mutex_enter(as->lock);
 1475 
 1476                 /* reset */
 1477                 ac97_write(as, AC97_REG_EXT_MODEM_ID, 1);
 1478 
 1479                 /* program rates */
 1480                 xval = 0xff00 & ~AC97_EXT_MODEM_CTRL_PRA;
 1481                 if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
 1482                         ac97_write(as, AC97_REG_LINE1_RATE, xrate);
 1483                         xval &= ~(AC97_EXT_MODEM_CTRL_PRC |
 1484                                AC97_EXT_MODEM_CTRL_PRD);
 1485                 }
 1486                 if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
 1487                         ac97_write(as, AC97_REG_LINE2_RATE, xrate);
 1488                         xval &= ~(AC97_EXT_MODEM_CTRL_PRE |
 1489                                AC97_EXT_MODEM_CTRL_PRF);
 1490                 }
 1491                 if (as->ext_mid & AC97_EXT_MODEM_HANDSET) {
 1492                         ac97_write(as, AC97_REG_HANDSET_RATE, xrate);
 1493                         xval &= ~(AC97_EXT_MODEM_CTRL_PRG |
 1494                                AC97_EXT_MODEM_CTRL_PRH);
 1495                 }
 1496 
 1497                 /* power-up everything */
 1498                 ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0);
 1499                 for (i = 5000; i >= 0; i--) {
 1500                         ac97_read(as, AC97_REG_EXT_MODEM_CTRL, &reg);
 1501                         if ((reg & /*XXXval*/0xf) == /*XXXval*/0xf)
 1502                                break;
 1503                         DELAY(1);
 1504                 }
 1505                 if (i <= 0) {
 1506                         mutex_exit(as->lock);
 1507                         printf("%s: codec not responding, status=0x%x\n",
 1508                             device_xname(sc_dev), reg);
 1509                         return ENXIO;
 1510                 }
 1511 
 1512                 /* setup sysctls */
 1513                 if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
 1514                         ac97_read(as, AC97_REG_GPIO_CFG, &reg);
 1515                         reg &= ~AC97_GPIO_LINE1_OH;
 1516                         ac97_write(as, AC97_REG_GPIO_CFG, reg);
 1517                         ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
 1518                         reg &= ~AC97_GPIO_LINE1_OH;
 1519                         ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
 1520 
 1521                         mutex_exit(as->lock);
 1522                         err = sysctl_createv(&as->log, 0, NULL, &node_line1,
 1523                                              CTLFLAG_READWRITE, CTLTYPE_INT,
 1524                                              "line1",
 1525                                              SYSCTL_DESCR("off-hook line1"),
 1526                                              ac97_sysctl_verify, 0, (void *)as, 0,
 1527                                              CTL_HW, node->sysctl_num,
 1528                                              CTL_CREATE, CTL_EOL);
 1529                         mutex_enter(as->lock);
 1530 
 1531                         if (err != 0)
 1532                                 goto sysctl_err;
 1533                         as->offhook_line1_mib = node_line1->sysctl_num;
 1534                 }
 1535                 if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
 1536                         ac97_read(as, AC97_REG_GPIO_CFG, &reg);
 1537                         reg &= ~AC97_GPIO_LINE2_OH;
 1538                         ac97_write(as, AC97_REG_GPIO_CFG, reg);
 1539                         ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
 1540                         reg &= ~AC97_GPIO_LINE2_OH;
 1541                         ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
 1542 
 1543                         mutex_exit(as->lock);
 1544                         err = sysctl_createv(&as->log, 0, NULL, &node_line2,
 1545                                              CTLFLAG_READWRITE, CTLTYPE_INT,
 1546                                              "line2",
 1547                                              SYSCTL_DESCR("off-hook line2"),
 1548                                              ac97_sysctl_verify, 0, (void *)as, 0,
 1549                                              CTL_HW, node->sysctl_num,
 1550                                              CTL_CREATE, CTL_EOL);
 1551                         mutex_enter(as->lock);
 1552 
 1553                         if (err != 0)
 1554                                 goto sysctl_err;
 1555                         as->offhook_line2_mib = node_line2->sysctl_num;
 1556                 }
 1557 sysctl_err:
 1558 
 1559                 ac97_write(as, AC97_REG_GPIO_STICKY, 0xffff);
 1560                 ac97_write(as, AC97_REG_GPIO_WAKEUP, 0x0);
 1561                 ac97_write(as, AC97_REG_MISC_AFE, 0x0);
 1562         }
 1563 
 1564         as->source_info = (as->type == AC97_CODEC_TYPE_MODEM ?
 1565                            as->modem_source_info : as->audio_source_info);
 1566         ac97_setup_source_info(as);
 1567 
 1568         memset(&ctl, 0, sizeof(ctl));
 1569         /* disable mutes */
 1570         for (i = 0; i < 11; i++) {
 1571                 static struct {
 1572                         const char *class, *device;
 1573                 } d[11] = {
 1574                         { AudioCoutputs, AudioNmaster},
 1575                         { AudioCoutputs, AudioNheadphone},
 1576                         { AudioCoutputs, AudioNsurround},
 1577                         { AudioCoutputs, AudioNcenter},
 1578                         { AudioCoutputs, AudioNlfe},
 1579                         { AudioCinputs, AudioNdac},
 1580                         { AudioCinputs, AudioNcd},
 1581                         { AudioCinputs, AudioNline},
 1582                         { AudioCinputs, AudioNaux},
 1583                         { AudioCinputs, AudioNvideo},
 1584                         { AudioCrecord, AudioNvolume},
 1585                 };
 1586 
 1587                 ctl.type = AUDIO_MIXER_ENUM;
 1588                 ctl.un.ord = 0;
 1589 
 1590                 ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
 1591                         d[i].class, d[i].device, AudioNmute);
 1592                 ac97_mixer_set_port(&as->codec_if, &ctl);
 1593         }
 1594         ctl.type = AUDIO_MIXER_ENUM;
 1595         ctl.un.ord = 0;
 1596         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
 1597                                            AudioNsource, NULL);
 1598         ac97_mixer_set_port(&as->codec_if, &ctl);
 1599 
 1600         /* set a reasonable default volume */
 1601         ctl.type = AUDIO_MIXER_VALUE;
 1602         ctl.un.value.num_channels = 2;
 1603         ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
 1604         ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
 1605         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
 1606                                            AudioNmaster, NULL);
 1607         ac97_mixer_set_port(&as->codec_if, &ctl);
 1608         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
 1609                                            AudioNsurround, NULL);
 1610         ac97_mixer_set_port(&as->codec_if, &ctl);
 1611         ctl.un.value.num_channels = 1;
 1612         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
 1613                                            AudioNcenter, NULL);
 1614         ac97_mixer_set_port(&as->codec_if, &ctl);
 1615         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
 1616                                            AudioNlfe, NULL);
 1617         ac97_mixer_set_port(&as->codec_if, &ctl);
 1618 
 1619         if (initfunc != NULL)
 1620                 initfunc(as);
 1621 
 1622         /* restore AC97_REG_POWER */
 1623         if (as->type == AC97_CODEC_TYPE_AUDIO)
 1624                 ac97_write(as, AC97_REG_POWER, as->power_reg);
 1625 
 1626         mutex_exit(as->lock);
 1627 
 1628         return 0;
 1629 }
 1630 
 1631 static void
 1632 ac97_detach(struct ac97_codec_if *codec_if)
 1633 {
 1634         struct ac97_softc *as;
 1635 
 1636         as = (struct ac97_softc *)codec_if;
 1637 
 1638         mutex_enter(as->lock);
 1639         ac97_write(as, AC97_REG_POWER, AC97_POWER_IN | AC97_POWER_OUT
 1640                    | AC97_POWER_MIXER | AC97_POWER_MIXER_VREF
 1641                    | AC97_POWER_ACLINK | AC97_POWER_CLK | AC97_POWER_AUX
 1642                    | POWER_EAMP_OFF(as));
 1643         mutex_exit(as->lock);
 1644 
 1645         free(as, M_DEVBUF);
 1646 }
 1647 
 1648 static void
 1649 ac97_lock(struct ac97_codec_if *codec_if)
 1650 {
 1651         struct ac97_softc *as;
 1652 
 1653         as = (struct ac97_softc *)codec_if;
 1654 
 1655         KASSERT(mutex_owned(as->lock));
 1656 
 1657         as->lock_counter++;
 1658 }
 1659 
 1660 static void
 1661 ac97_unlock(struct ac97_codec_if *codec_if)
 1662 {
 1663         struct ac97_softc *as;
 1664 
 1665         as = (struct ac97_softc *)codec_if;
 1666 
 1667         KASSERT(mutex_owned(as->lock));
 1668 
 1669         as->lock_counter--;
 1670 }
 1671 
 1672 static int
 1673 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
 1674 {
 1675         struct ac97_softc *as;
 1676         struct ac97_source_info *si;
 1677         const char *name;
 1678 
 1679         as = (struct ac97_softc *)codec_if;
 1680         if (dip->index >= 0 && dip->index < as->num_source_info) {
 1681                 si = &as->source_info[dip->index];
 1682                 dip->type = si->type;
 1683                 dip->mixer_class = si->mixer_class;
 1684                 dip->prev = si->prev;
 1685                 dip->next = si->next;
 1686 
 1687                 if (si->qualifier)
 1688                         name = si->qualifier;
 1689                 else if (si->device)
 1690                         name = si->device;
 1691                 else if (si->class)
 1692                         name = si->class;
 1693                 else
 1694                         name = NULL;
 1695 
 1696                 if (name)
 1697                         strcpy(dip->label.name, name);
 1698 
 1699                 if (si->info)
 1700                         memcpy(&dip->un, si->info, si->info_size);
 1701 
 1702                 /* Set the delta for volume sources */
 1703                 if (dip->type == AUDIO_MIXER_VALUE)
 1704                         dip->un.v.delta = 1 << (8 - si->bits);
 1705 
 1706                 return 0;
 1707         }
 1708 
 1709         return ENXIO;
 1710 }
 1711 
 1712 static int
 1713 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
 1714 {
 1715         struct ac97_softc *as;
 1716         struct ac97_source_info *si;
 1717         uint16_t mask;
 1718         uint16_t val, newval;
 1719         int error;
 1720         bool spdif;
 1721 
 1722         as = (struct ac97_softc *)codec_if;
 1723 
 1724         KASSERT(mutex_owned(as->lock));
 1725 
 1726         if (cp->dev < 0 || cp->dev >= as->num_source_info)
 1727                 return EINVAL;
 1728         si = &as->source_info[cp->dev];
 1729 
 1730         if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
 1731                 return EINVAL;
 1732         spdif = si->req_feature == CHECK_SPDIF && si->reg == AC97_REG_EXT_AUDIO_CTRL;
 1733         if (spdif && as->lock_counter >= 0) {
 1734                 /* When the value of lock_counter is the default 0,
 1735                  * it is not allowed to change the SPDIF mode. */
 1736                 return EBUSY;
 1737         }
 1738 
 1739         ac97_read(as, si->reg, &val);
 1740 
 1741         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
 1742 
 1743         mask = (1 << si->bits) - 1;
 1744 
 1745         switch (cp->type) {
 1746         case AUDIO_MIXER_ENUM:
 1747                 if (cp->un.ord > mask || cp->un.ord < 0)
 1748                         return EINVAL;
 1749 
 1750                 newval = (cp->un.ord << si->ofs);
 1751                 if (si->reg == AC97_REG_RECORD_SELECT) {
 1752                         newval |= (newval << (8 + si->ofs));
 1753                         mask |= (mask << 8);
 1754                         mask = mask << si->ofs;
 1755                 } else if (si->reg == AC97_REG_SURR_MASTER) {
 1756                         newval = cp->un.ord ? 0x8080 : 0x0000;
 1757                         mask = 0x8080;
 1758                 } else
 1759                         mask = mask << si->ofs;
 1760                 break;
 1761         case AUDIO_MIXER_VALUE:
 1762         {
 1763                 const struct audio_mixer_value *value = si->info;
 1764                 uint16_t  l, r, ol, or;
 1765                 int deltal, deltar;
 1766 
 1767                 if ((cp->un.value.num_channels <= 0) ||
 1768                     (cp->un.value.num_channels > value->num_channels))
 1769                         return EINVAL;
 1770 
 1771                 if (cp->un.value.num_channels == 1) {
 1772                         l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
 1773                 } else {
 1774                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
 1775                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
 1776                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
 1777                         } else {        /* left/right is reversed here */
 1778                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
 1779                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
 1780                         }
 1781 
 1782                 }
 1783 
 1784                 if (!si->polarity) {
 1785                         l = 255 - l;
 1786                         r = 255 - r;
 1787                 }
 1788 
 1789                 ol = (val >> (8+si->ofs)) & mask;
 1790                 or = (val >> si->ofs) & mask;
 1791 
 1792                 deltal = (ol << (8 - si->bits)) - l;
 1793                 deltar = (or << (8 - si->bits)) - r;
 1794 
 1795                 l = l >> (8 - si->bits);
 1796                 r = r >> (8 - si->bits);
 1797 
 1798                 if (deltal && ol == l)
 1799                         l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
 1800                 if (deltar && or == r)
 1801                         r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
 1802 
 1803                 newval = ((r & mask) << si->ofs);
 1804                 if (value->num_channels == 2) {
 1805                         newval = newval | ((l & mask) << (si->ofs+8));
 1806                         mask |= (mask << 8);
 1807                 }
 1808                 mask = mask << si->ofs;
 1809                 break;
 1810         }
 1811         default:
 1812                 return EINVAL;
 1813         }
 1814 
 1815         error = ac97_write(as, si->reg, (val & ~mask) | newval);
 1816         if (error)
 1817                 return error;
 1818 
 1819         if (spdif && as->host_if->spdif_event != NULL) {
 1820                 DPRINTF(("%s: call spdif_event(%d)\n", __func__, cp->un.ord));
 1821                 as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
 1822         }
 1823         return 0;
 1824 }
 1825 
 1826 static int
 1827 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
 1828                          const char *device, const char *qualifier)
 1829 {
 1830         struct ac97_softc *as;
 1831         int idx;
 1832 
 1833         as = (struct ac97_softc *)codec_if;
 1834 
 1835         KASSERT(mutex_owned(as->lock));
 1836 
 1837         for (idx = 0; idx < as->num_source_info; idx++) {
 1838                 struct ac97_source_info *si = &as->source_info[idx];
 1839                 if (ac97_str_equal(class, si->class) &&
 1840                     ac97_str_equal(device, si->device) &&
 1841                     ac97_str_equal(qualifier, si->qualifier))
 1842                         return idx;
 1843         }
 1844 
 1845         return -1;
 1846 }
 1847 
 1848 static int
 1849 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
 1850 {
 1851         struct ac97_softc *as;
 1852         struct ac97_source_info *si;
 1853         uint16_t mask;
 1854         uint16_t val;
 1855 
 1856         as = (struct ac97_softc *)codec_if;
 1857 
 1858         KASSERT(mutex_owned(as->lock));
 1859 
 1860         si = &as->source_info[cp->dev];
 1861         if (cp->dev < 0 || cp->dev >= as->num_source_info)
 1862                 return EINVAL;
 1863 
 1864         if (cp->type != si->type)
 1865                 return EINVAL;
 1866 
 1867         ac97_read(as, si->reg, &val);
 1868 
 1869         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
 1870 
 1871         mask = (1 << si->bits) - 1;
 1872 
 1873         switch (cp->type) {
 1874         case AUDIO_MIXER_ENUM:
 1875                 cp->un.ord = (val >> si->ofs) & mask;
 1876                 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
 1877                              val, si->ofs, mask, cp->un.ord));
 1878                 break;
 1879         case AUDIO_MIXER_VALUE:
 1880         {
 1881                 const struct audio_mixer_value *value = si->info;
 1882                 uint16_t  l, r;
 1883 
 1884                 if ((cp->un.value.num_channels <= 0) ||
 1885                     (cp->un.value.num_channels > value->num_channels))
 1886                         return EINVAL;
 1887 
 1888                 if (value->num_channels == 1) {
 1889                         l = r = (val >> si->ofs) & mask;
 1890                 } else {
 1891                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
 1892                                 l = (val >> (si->ofs + 8)) & mask;
 1893                                 r = (val >> si->ofs) & mask;
 1894                         } else {        /* host has reversed channels */
 1895                                 r = (val >> (si->ofs + 8)) & mask;
 1896                                 l = (val >> si->ofs) & mask;
 1897                         }
 1898                 }
 1899 
 1900                 l = (l << (8 - si->bits));
 1901                 r = (r << (8 - si->bits));
 1902                 if (!si->polarity) {
 1903                         l = 255 - l;
 1904                         r = 255 - r;
 1905                 }
 1906 
 1907                 /* The EAP driver averages l and r for stereo
 1908                    channels that are requested in MONO mode. Does this
 1909                    make sense? */
 1910                 if (cp->un.value.num_channels == 1) {
 1911                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
 1912                 } else if (cp->un.value.num_channels == 2) {
 1913                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
 1914                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
 1915                 }
 1916 
 1917                 break;
 1918         }
 1919         default:
 1920                 return EINVAL;
 1921         }
 1922 
 1923         return 0;
 1924 }
 1925 
 1926 
 1927 static int
 1928 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_int *rate)
 1929 {
 1930         struct ac97_softc *as;
 1931         u_int value;
 1932         uint16_t ext_stat;
 1933         uint16_t actual;
 1934         uint16_t power;
 1935         uint16_t power_bit;
 1936 
 1937         as = (struct ac97_softc *)codec_if;
 1938 
 1939         KASSERT(mutex_owned(as->lock));
 1940 
 1941         if (target == AC97_REG_PCM_MIC_ADC_RATE) {
 1942                 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
 1943                         *rate = AC97_SINGLE_RATE;
 1944                         return 0;
 1945                 }
 1946         } else {
 1947                 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
 1948                         *rate = AC97_SINGLE_RATE;
 1949                         return 0;
 1950                 }
 1951         }
 1952         value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
 1953         ext_stat = 0;
 1954         /*
 1955          * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
 1956          *      Check VRA, DRA
 1957          * PCM_LR_ADC_RATE
 1958          *      Check VRA
 1959          * PCM_MIC_ADC_RATE
 1960          *      Check VRM
 1961          */
 1962         switch (target) {
 1963         case AC97_REG_PCM_FRONT_DAC_RATE:
 1964         case AC97_REG_PCM_SURR_DAC_RATE:
 1965         case AC97_REG_PCM_LFE_DAC_RATE:
 1966                 power_bit = AC97_POWER_OUT;
 1967                 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
 1968                         *rate = AC97_SINGLE_RATE;
 1969                         return 0;
 1970                 }
 1971                 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
 1972                         ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
 1973                         if (value > 0x1ffff) {
 1974                                 return EINVAL;
 1975                         } else if (value > 0xffff) {
 1976                                 /* Enable DRA */
 1977                                 ext_stat |= AC97_EXT_AUDIO_DRA;
 1978                                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
 1979                                 value /= 2;
 1980                         } else {
 1981                                 /* Disable DRA */
 1982                                 ext_stat &= ~AC97_EXT_AUDIO_DRA;
 1983                                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
 1984                         }
 1985                 } else {
 1986                         if (value > 0xffff)
 1987                                 return EINVAL;
 1988                 }
 1989                 break;
 1990         case AC97_REG_PCM_LR_ADC_RATE:
 1991                 power_bit = AC97_POWER_IN;
 1992                 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
 1993                         *rate = AC97_SINGLE_RATE;
 1994                         return 0;
 1995                 }
 1996                 if (value > 0xffff)
 1997                         return EINVAL;
 1998                 break;
 1999         case AC97_REG_PCM_MIC_ADC_RATE:
 2000                 power_bit = AC97_POWER_IN;
 2001                 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
 2002                         *rate = AC97_SINGLE_RATE;
 2003                         return 0;
 2004                 }
 2005                 if (value > 0xffff)
 2006                         return EINVAL;
 2007                 break;
 2008         default:
 2009                 printf("%s: Unknown register: 0x%x\n", __func__, target);
 2010                 return EINVAL;
 2011         }
 2012 
 2013         ac97_read(as, AC97_REG_POWER, &power);
 2014         ac97_write(as, AC97_REG_POWER, power | power_bit);
 2015 
 2016         ac97_write(as, target, (uint16_t)value);
 2017         ac97_read(as, target, &actual);
 2018         actual = (uint32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
 2019 
 2020         ac97_write(as, AC97_REG_POWER, power);
 2021         if (ext_stat & AC97_EXT_AUDIO_DRA) {
 2022                 *rate = actual * 2;
 2023         } else {
 2024                 *rate = actual;
 2025         }
 2026         return 0;
 2027 }
 2028 
 2029 static void
 2030 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
 2031 {
 2032         struct ac97_softc *as;
 2033 
 2034         as = (struct ac97_softc *)codec_if;
 2035 
 2036         KASSERT(mutex_owned(as->lock));
 2037 
 2038         as->ac97_clock = clock;
 2039 }
 2040 
 2041 static uint16_t
 2042 ac97_get_extcaps(struct ac97_codec_if *codec_if)
 2043 {
 2044         struct ac97_softc *as;
 2045 
 2046         as = (struct ac97_softc *)codec_if;
 2047 
 2048         KASSERT(mutex_owned(as->lock));
 2049 
 2050         return as->ext_id;
 2051 }
 2052 
 2053 static int
 2054 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
 2055 {
 2056         struct ac97_source_info *si;
 2057         int ouridx, idx;
 2058 
 2059         KASSERT(mutex_owned(as->lock));
 2060 
 2061         if ((as->type == AC97_CODEC_TYPE_AUDIO &&
 2062              as->num_source_info >= AUDIO_MAX_SOURCES) ||
 2063             (as->type == AC97_CODEC_TYPE_MODEM &&
 2064              as->num_source_info >= MODEM_MAX_SOURCES)) {
 2065                 printf("%s: internal error: increase MAX_SOURCES in %s\n",
 2066                        __func__, __FILE__);
 2067                 return -1;
 2068         }
 2069         if (!ac97_check_capability(as, src->req_feature))
 2070                 return -1;
 2071         ouridx = as->num_source_info;
 2072         si = &as->source_info[ouridx];
 2073         memcpy(si, src, sizeof(*si));
 2074 
 2075         switch (si->type) {
 2076         case AUDIO_MIXER_CLASS:
 2077         case AUDIO_MIXER_VALUE:
 2078                 printf("%s: adding class/value is not supported yet.\n",
 2079                        __func__);
 2080                 return -1;
 2081         case AUDIO_MIXER_ENUM:
 2082                 break;
 2083         default:
 2084                 printf("%s: unknown type: %d\n", __func__, si->type);
 2085                 return -1;
 2086         }
 2087         as->num_source_info++;
 2088 
 2089         si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
 2090                                                    NULL, NULL);
 2091         /* Find the root of the device */
 2092         idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
 2093                                        si->device, NULL);
 2094         /* Find the last item */
 2095         while (as->source_info[idx].next != AUDIO_MIXER_LAST)
 2096                 idx = as->source_info[idx].next;
 2097         /* Append */
 2098         as->source_info[idx].next = ouridx;
 2099         si->prev = idx;
 2100         si->next = AUDIO_MIXER_LAST;
 2101 
 2102         return 0;
 2103 }
 2104 
 2105 /**
 2106  * Codec-dependent initialization
 2107  */
 2108 
 2109 #define AD1980_REG_MISC 0x76
 2110 #define         AD1980_MISC_MBG0        0x0001  /* 0 1888/1980/1981 /1985 */
 2111 #define         AD1980_MISC_MBG1        0x0002  /* 1 1888/1980/1981 /1985 */
 2112 #define         AD1980_MISC_VREFD       0x0004  /* 2 1888/1980/1981 /1985 */
 2113 #define         AD1980_MISC_VREFH       0x0008  /* 3 1888/1980/1981 /1985 */
 2114 #define         AD1980_MISC_SRU         0x0010  /* 4 1888/1980      /1985 */
 2115 #define         AD1980_MISC_LOSEL       0x0020  /* 5 1888/1980/1981 /1985 */
 2116 #define         AD1980_MISC_2CMIC       0x0040  /* 6      1980/1981B/1985 */
 2117 #define         AD1980_MISC_SPRD        0x0080  /* 7 1888/1980      /1985 */
 2118 #define         AD1980_MISC_DMIX0       0x0100  /* 8 1888/1980      /1985 */
 2119 #define         AD1980_MISC_DMIX1       0x0200  /* 9 1888/1980      /1985 */
 2120 #define         AD1980_MISC_HPSEL       0x0400  /*10 1888/1980      /1985 */
 2121 #define         AD1980_MISC_CLDIS       0x0800  /*11 1888/1980      /1985 */
 2122 #define         AD1980_MISC_LODIS       0x1000  /*12 1888/1980/1981 /1985 */
 2123 #define         AD1980_MISC_MSPLT       0x2000  /*13 1888/1980/1981 /1985 */
 2124 #define         AD1980_MISC_AC97NC      0x4000  /*14 1888/1980      /1985 */
 2125 #define         AD1980_MISC_DACZ        0x8000  /*15 1888/1980/1981 /1985 */
 2126 #define AD1981_REG_MISC 0x76
 2127 #define         AD1981_MISC_MADST       0x0010  /* 4 */
 2128 #define         AD1981A_MISC_MADPD      0x0040  /* 6 */
 2129 #define         AD1981B_MISC_MADPD      0x0080  /* 7 */
 2130 #define         AD1981_MISC_FMXE        0x0200  /* 9 */
 2131 #define         AD1981_MISC_DAM         0x0800  /*11 */
 2132 static void
 2133 ac97_ad198x_init(struct ac97_softc *as)
 2134 {
 2135         int i;
 2136         uint16_t misc;
 2137 
 2138         KASSERT(mutex_owned(as->lock));
 2139 
 2140         ac97_read(as, AD1980_REG_MISC, &misc);
 2141         ac97_write(as, AD1980_REG_MISC,
 2142                    misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
 2143 
 2144         for (i = 0; i < as->num_source_info; i++) {
 2145                 if (as->source_info[i].type != AUDIO_MIXER_VALUE)
 2146                         continue;
 2147 
 2148                 if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
 2149                         as->source_info[i].reg = AC97_REG_SURR_MASTER;
 2150                 else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
 2151                         as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
 2152         }
 2153 }
 2154 
 2155 #define ALC650_REG_MULTI_CHANNEL_CONTROL        0x6a
 2156 #define         ALC650_MCC_SLOT_MODIFY_MASK             0xc000
 2157 #define         ALC650_MCC_FRONTDAC_FROM_SPDIFIN        0x2000 /* 13 */
 2158 #define         ALC650_MCC_SPDIFOUT_FROM_ADC            0x1000 /* 12 */
 2159 #define         ALC650_MCC_PCM_FROM_SPDIFIN             0x0800 /* 11 */
 2160 #define         ALC650_MCC_MIC_OR_CENTERLFE             0x0400 /* 10 */
 2161 #define         ALC650_MCC_LINEIN_OR_SURROUND           0x0200 /* 9 */
 2162 #define         ALC650_MCC_INDEPENDENT_MASTER_L         0x0080 /* 7 */
 2163 #define         ALC650_MCC_INDEPENDENT_MASTER_R         0x0040 /* 6 */
 2164 #define         ALC650_MCC_ANALOG_TO_CENTERLFE          0x0020 /* 5 */
 2165 #define         ALC650_MCC_ANALOG_TO_SURROUND           0x0010 /* 4 */
 2166 #define         ALC650_MCC_EXCHANGE_CENTERLFE           0x0008 /* 3 */
 2167 #define         ALC650_MCC_CENTERLFE_DOWNMIX            0x0004 /* 2 */
 2168 #define         ALC650_MCC_SURROUND_DOWNMIX             0x0002 /* 1 */
 2169 #define         ALC650_MCC_LINEOUT_TO_SURROUND          0x0001 /* 0 */
 2170 static void
 2171 ac97_alc650_init(struct ac97_softc *as)
 2172 {
 2173         static const struct ac97_source_info sources[6] = {
 2174                 { AudioCoutputs, AudioNsurround, "lineinjack",
 2175                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2176                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 2177                   0x0000, 1, 9, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
 2178                 { AudioCoutputs, AudioNsurround, "mixtofront",
 2179                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2180                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 2181                   0x0000, 1, 1, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
 2182                 { AudioCoutputs, AudioNcenter, "micjack",
 2183                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2184                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 2185                   0x0000, 1, 10, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
 2186                 { AudioCoutputs, AudioNlfe, "micjack",
 2187                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2188                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 2189                   0x0000, 1, 10, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
 2190                 { AudioCoutputs, AudioNcenter, "mixtofront",
 2191                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2192                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 2193                   0x0000, 1, 2, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
 2194                 { AudioCoutputs, AudioNlfe, "mixtofront",
 2195                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2196                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 2197                   0x0000, 1, 2, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
 2198         };
 2199 
 2200         ac97_add_port(as, &sources[0]);
 2201         ac97_add_port(as, &sources[1]);
 2202         ac97_add_port(as, &sources[2]);
 2203         ac97_add_port(as, &sources[3]);
 2204         ac97_add_port(as, &sources[4]);
 2205         ac97_add_port(as, &sources[5]);
 2206 }
 2207 
 2208 #define UCB1400_REG_FEATURE_CSR1        0x6a
 2209 #define         UCB1400_BB(bb)                  (((bb) & 0xf) << 11)
 2210 #define         UCB1400_TR(tr)                  (((tr) & 0x3) << 9)
 2211 #define         UCB1400_M_MAXIMUM               (3 << 7)
 2212 #define         UCB1400_M_MINIMUM               (1 << 7)
 2213 #define         UCB1400_M_FLAT                  (0 << 7)
 2214 #define         UCB1400_HPEN                    (1 << 6)
 2215 #define         UCB1400_DE                      (1 << 5)
 2216 #define         UCB1400_DC                      (1 << 4)
 2217 #define         UCB1400_HIPS                    (1 << 3)
 2218 #define         UCB1400_GIEN                    (1 << 2)
 2219 #define         UCB1400_OVFL                    (1 << 0)
 2220 #define UCB1400_REG_FEATURE_CSR2        0x6c
 2221 #define         UCB1400_SMT                     (1 << 15)       /* Must be 0 */
 2222 #define         UCB1400_SUEV1                   (1 << 14)       /* Must be 0 */
 2223 #define         UCB1400_SUEV0                   (1 << 13)       /* Must be 0 */
 2224 #define         UCB1400_AVE                     (1 << 12)
 2225 #define         UCB1400_AVEN1                   (1 << 11)       /* Must be 0 */
 2226 #define         UCB1400_AVEN0                   (1 << 10)       /* Must be 0 */
 2227 #define         UCB1400_SLP_ON                  \
 2228                                         (UCB1400_SLP_PLL | UCB1400_SLP_CODEC)
 2229 #define         UCB1400_SLP_PLL                 (2 << 4)
 2230 #define         UCB1400_SLP_CODEC               (1 << 4)
 2231 #define         UCB1400_SLP_NO                  (0 << 4)
 2232 #define         UCB1400_EV2                     (1 << 2)        /* Must be 0 */
 2233 #define         UCB1400_EV1                     (1 << 1)        /* Must be 0 */
 2234 #define         UCB1400_EV0                     (1 << 0)        /* Must be 0 */
 2235 static void
 2236 ac97_ucb1400_init(struct ac97_softc *as)
 2237 {
 2238 
 2239         ac97_write(as, UCB1400_REG_FEATURE_CSR1,
 2240             UCB1400_HPEN | UCB1400_DC | UCB1400_HIPS | UCB1400_OVFL);
 2241         ac97_write(as, UCB1400_REG_FEATURE_CSR2, UCB1400_AVE | UCB1400_SLP_ON);
 2242 }
 2243 
 2244 #define VT1616_REG_IO_CONTROL   0x5a
 2245 #define         VT1616_IC_LVL                   (1 << 15)
 2246 #define         VT1616_IC_LFECENTER_TO_FRONT    (1 << 12)
 2247 #define         VT1616_IC_SURROUND_TO_FRONT     (1 << 11)
 2248 #define         VT1616_IC_BPDC                  (1 << 10)
 2249 #define         VT1616_IC_DC                    (1 << 9)
 2250 #define         VT1616_IC_IB_MASK               0x000c
 2251 static void
 2252 ac97_vt1616_init(struct ac97_softc *as)
 2253 {
 2254         static const struct ac97_source_info sources[3] = {
 2255                 { AudioCoutputs, AudioNsurround, "mixtofront",
 2256                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2257                   VT1616_REG_IO_CONTROL,
 2258                   0x0000, 1, 11, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
 2259                 { AudioCoutputs, AudioNcenter, "mixtofront",
 2260                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2261                   VT1616_REG_IO_CONTROL,
 2262                   0x0000, 1, 12, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
 2263                 { AudioCoutputs, AudioNlfe, "mixtofront",
 2264                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 2265                   VT1616_REG_IO_CONTROL,
 2266                   0x0000, 1, 12, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
 2267         };
 2268 
 2269         KASSERT(mutex_owned(as->lock));
 2270 
 2271         ac97_add_port(as, &sources[0]);
 2272         ac97_add_port(as, &sources[1]);
 2273         ac97_add_port(as, &sources[2]);
 2274 }
 2275 
 2276 static int
 2277 ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval)
 2278 {
 2279         uint16_t val;
 2280 
 2281         KASSERT(mutex_owned(as->lock));
 2282 
 2283         val = as->shadow_reg[AC97_REG_GPIO_STATUS >> 1];
 2284         switch (newval) {
 2285         case 0:
 2286                 val &= ~line;
 2287                 break;
 2288         case 1:
 2289                 val |= line;
 2290                 break;
 2291         }
 2292         ac97_write(as, AC97_REG_GPIO_STATUS, val);
 2293 
 2294         return 0;
 2295 }
 2296 
 2297 static int
 2298 ac97_sysctl_verify(SYSCTLFN_ARGS)
 2299 {
 2300         int error, tmp;
 2301         struct sysctlnode node;
 2302         struct ac97_softc *as;
 2303 
 2304         node = *rnode;
 2305         as = rnode->sysctl_data;
 2306         if (node.sysctl_num == as->offhook_line1_mib) {
 2307                 tmp = as->offhook_line1;
 2308                 node.sysctl_data = &tmp;
 2309                 error = sysctl_lookup(SYSCTLFN_CALL(&node));
 2310                 if (error || newp == NULL)
 2311                         return error;
 2312 
 2313                 if (tmp < 0 || tmp > 1)
 2314                         return EINVAL;
 2315 
 2316                 as->offhook_line1 = tmp;
 2317                 mutex_enter(as->lock);
 2318                 ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp);
 2319                 mutex_exit(as->lock);
 2320         } else if (node.sysctl_num == as->offhook_line2_mib) {
 2321                 tmp = as->offhook_line2;
 2322                 node.sysctl_data = &tmp;
 2323                 error = sysctl_lookup(SYSCTLFN_CALL(&node));
 2324                 if (error || newp == NULL)
 2325                         return error;
 2326 
 2327                 if (tmp < 0 || tmp > 1)
 2328                         return EINVAL;
 2329 
 2330                 as->offhook_line2 = tmp;
 2331                 mutex_enter(as->lock);
 2332                 ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp);
 2333                 mutex_exit(as->lock);
 2334         }
 2335 
 2336         return 0;
 2337 }

Cache object: d5de3507a254c4f24b363283e5c87322


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.