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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 47809e72e5e8cf0e5d66e9bcdca7d8d6


[ 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.