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


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

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

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

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

Cache object: bbd336306bca6ec98358b37e27576a35


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