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.52.2.3 2004/09/22 20:58:04 jmc 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.52.2.3 2004/09/22 20:58:04 jmc 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 
   74 #include <sys/audioio.h>
   75 #include <dev/audio_if.h>
   76 
   77 #include <dev/ic/ac97reg.h>
   78 #include <dev/ic/ac97var.h>
   79 
   80 struct ac97_softc;
   81 struct ac97_source_info;
   82 int ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
   83 int ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
   84 int ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
   85 int ac97_get_portnum_by_name(struct ac97_codec_if *, const char *,
   86                              const char *, const char *);
   87 void ac97_restore_shadow(struct ac97_codec_if *);
   88 int ac97_set_rate(struct ac97_codec_if *, int, u_long *);
   89 void ac97_set_clock(struct ac97_codec_if *, unsigned int);
   90 u_int16_t ac97_get_extcaps(struct ac97_codec_if *);
   91 int ac97_add_port(struct ac97_softc *, const struct ac97_source_info *);
   92 int ac97_str_equal(const char *, const char *);
   93 int ac97_check_capability(struct ac97_softc *, int);
   94 void ac97_setup_source_info(struct ac97_softc *);
   95 void ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *);
   96 void ac97_setup_defaults(struct ac97_softc *);
   97 int ac97_write(struct ac97_softc *, u_int8_t, u_int16_t);
   98 
   99 static void ac97_ad198x_init(struct ac97_softc *);
  100 static void ac97_alc650_init(struct ac97_softc *);
  101 static void ac97_vt1616_init(struct ac97_softc *);
  102 
  103 #define Ac97Ntone       "tone"
  104 #define Ac97Nphone      "phone"
  105 
  106 static const struct audio_mixer_enum
  107 ac97_on_off = { 2, { { { AudioNoff } , 0 },
  108                      { { AudioNon }  , 1 } } };
  109 
  110 static const struct audio_mixer_enum
  111 ac97_mic_select = { 2, { { { AudioNmicrophone "" }, 0 },
  112                          { { AudioNmicrophone "1" }, 1 } } };
  113 
  114 static const struct audio_mixer_enum
  115 ac97_mono_select = { 2, { { { AudioNmixerout }, 0 },
  116                           { { AudioNmicrophone }, 1 } } };
  117 
  118 static const struct audio_mixer_enum
  119 ac97_source = { 8, { { { AudioNmicrophone } , 0 },
  120                      { { AudioNcd }, 1 },
  121                      { { AudioNvideo }, 2 },
  122                      { { AudioNaux }, 3 },
  123                      { { AudioNline }, 4 },
  124                      { { AudioNmixerout }, 5 },
  125                      { { AudioNmixerout AudioNmono }, 6 },
  126                      { { Ac97Nphone }, 7 } } };
  127 
  128 /*
  129  * Due to different values for each source that uses these structures,
  130  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
  131  * ac97_source_info.bits.
  132  */
  133 static const struct audio_mixer_value
  134 ac97_volume_stereo = { { AudioNvolume }, 2 };
  135 
  136 static const struct audio_mixer_value
  137 ac97_volume_mono = { { AudioNvolume }, 1 };
  138 
  139 #define WRAP(a)  &a, sizeof(a)
  140 
  141 const struct ac97_source_info {
  142         const char *class;
  143         const char *device;
  144         const char *qualifier;
  145 
  146         int  type;
  147         const void *info;
  148         int  info_size;
  149 
  150         u_int8_t  reg;
  151         u_int16_t default_value;
  152         u_int8_t  bits:3;
  153         u_int8_t  ofs:4;
  154         u_int8_t  mute:1;
  155         u_int8_t  polarity:1;   /* Does 0 == MAX or MIN */
  156         enum {
  157                 CHECK_NONE = 0,
  158                 CHECK_SURROUND,
  159                 CHECK_CENTER,
  160                 CHECK_LFE,
  161                 CHECK_HEADPHONES,
  162                 CHECK_TONE,
  163                 CHECK_MIC,
  164                 CHECK_LOUDNESS,
  165                 CHECK_3D
  166         } req_feature;
  167 
  168         int  prev;
  169         int  next;
  170         int  mixer_class;
  171 } source_info[] = {
  172         { AudioCinputs,         NULL,           NULL,
  173           AUDIO_MIXER_CLASS, },
  174         { AudioCoutputs,        NULL,           NULL,
  175           AUDIO_MIXER_CLASS, },
  176         { AudioCrecord,         NULL,           NULL,
  177           AUDIO_MIXER_CLASS, },
  178         /* Stereo master volume*/
  179         { AudioCoutputs,        AudioNmaster,   NULL,
  180           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  181           AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1,
  182         },
  183         /* Mono volume */
  184         { AudioCoutputs,        AudioNmono,     NULL,
  185           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  186           AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1,
  187         },
  188         { AudioCoutputs,        AudioNmono,     AudioNsource,
  189           AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
  190           AC97_REG_GP, 0x0000, 1, 9, 0,
  191         },
  192         /* Headphone volume */
  193         { AudioCoutputs,        AudioNheadphone, NULL,
  194           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  195           AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1, 0, CHECK_HEADPHONES
  196         },
  197         /* Surround volume - logic hard coded for mute */
  198         { AudioCoutputs,        AudioNsurround, NULL,
  199           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  200           AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, CHECK_SURROUND
  201         },
  202         /* Center volume*/
  203         { AudioCoutputs,        AudioNcenter,   NULL,
  204           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  205           AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, CHECK_CENTER
  206         },
  207         { AudioCoutputs,        AudioNcenter,   AudioNmute,
  208           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  209           AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, CHECK_CENTER
  210         },
  211         /* LFE volume*/
  212         { AudioCoutputs,        AudioNlfe,      NULL,
  213           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  214           AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, CHECK_LFE
  215         },
  216         { AudioCoutputs,        AudioNlfe,      AudioNmute,
  217           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  218           AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, CHECK_LFE
  219         },
  220         /* Tone */
  221         { AudioCoutputs,        Ac97Ntone,      NULL,
  222           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  223           AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, CHECK_TONE
  224         },
  225         /* PC Beep Volume */
  226         { AudioCinputs,         AudioNspeaker,  NULL,
  227           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  228           AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1,
  229         },
  230 
  231         /* Phone */
  232         { AudioCinputs,         Ac97Nphone,     NULL,
  233           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  234           AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1,
  235         },
  236         /* Mic Volume */
  237         { AudioCinputs,         AudioNmicrophone, NULL,
  238           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  239           AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1,
  240         },
  241         { AudioCinputs,         AudioNmicrophone, AudioNpreamp,
  242           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  243           AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0,
  244         },
  245         { AudioCinputs,         AudioNmicrophone, AudioNsource,
  246           AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
  247           AC97_REG_GP, 0x0000, 1, 8, 0,
  248         },
  249         /* Line in Volume */
  250         { AudioCinputs,         AudioNline,     NULL,
  251           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  252           AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1,
  253         },
  254         /* CD Volume */
  255         { AudioCinputs,         AudioNcd,       NULL,
  256           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  257           AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1,
  258         },
  259         /* Video Volume */
  260         { AudioCinputs,         AudioNvideo,    NULL,
  261           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  262           AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1,
  263         },
  264         /* AUX volume */
  265         { AudioCinputs,         AudioNaux,      NULL,
  266           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  267           AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1,
  268         },
  269         /* PCM out volume */
  270         { AudioCinputs,         AudioNdac,      NULL,
  271           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  272           AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1,
  273         },
  274         /* Record Source - some logic for this is hard coded - see below */
  275         { AudioCrecord,         AudioNsource,   NULL,
  276           AUDIO_MIXER_ENUM, WRAP(ac97_source),
  277           AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0,
  278         },
  279         /* Record Gain */
  280         { AudioCrecord,         AudioNvolume,   NULL,
  281           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  282           AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 1,
  283         },
  284         /* Record Gain mic */
  285         { AudioCrecord,         AudioNmicrophone, NULL,
  286           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  287           AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, CHECK_MIC
  288         },
  289         /* */
  290         { AudioCoutputs,        AudioNloudness, NULL,
  291           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  292           AC97_REG_GP, 0x0000, 1, 12, 0, 0, CHECK_LOUDNESS
  293         },
  294         { AudioCoutputs,        AudioNspatial,  NULL,
  295           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  296           AC97_REG_GP, 0x0000, 1, 13, 0, 1, CHECK_3D
  297         },
  298         { AudioCoutputs,        AudioNspatial,  "center",
  299           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  300           AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, CHECK_3D
  301         },
  302         { AudioCoutputs,        AudioNspatial,  "depth",
  303           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  304           AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, CHECK_3D
  305         },
  306 
  307         /* Missing features: Simulated Stereo, POP, Loopback mode */
  308 } ;
  309 
  310 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
  311 
  312 /*
  313  * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
  314  * information on AC-97
  315  */
  316 
  317 struct ac97_softc {
  318         /* ac97_codec_if must be at the first of ac97_softc. */
  319         struct ac97_codec_if codec_if;
  320 
  321         struct ac97_host_if *host_if;
  322 
  323 #define MAX_SOURCES     (2 * SOURCE_INFO_SIZE)
  324         struct ac97_source_info source_info[MAX_SOURCES];
  325         int num_source_info;
  326 
  327         enum ac97_host_flags host_flags;
  328         unsigned int ac97_clock; /* usually 48000 */
  329 #define AC97_STANDARD_CLOCK     48000U
  330         u_int16_t caps;         /* -> AC97_REG_RESET */
  331         u_int16_t ext_id;       /* -> AC97_REG_EXT_AUDIO_ID */
  332         u_int16_t shadow_reg[128];
  333 };
  334 
  335 struct ac97_codec_if_vtbl ac97civ = {
  336         ac97_mixer_get_port,
  337         ac97_mixer_set_port,
  338         ac97_query_devinfo,
  339         ac97_get_portnum_by_name,
  340         ac97_restore_shadow,
  341         ac97_get_extcaps,
  342         ac97_set_rate,
  343         ac97_set_clock,
  344 };
  345 
  346 static const struct ac97_codecid {
  347         u_int32_t id;
  348         u_int32_t mask;
  349         const char *name;
  350         void (*init)(struct ac97_softc *);
  351 } ac97codecid[] = {
  352         /*
  353          * Analog Devices SoundMAX
  354          * http://www.soundmax.com/products/information/codecs.html
  355          * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf
  356          * http://www.analog.com/productSelection/pdf/AD1885_0.pdf
  357          * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf
  358          * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf
  359          * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf
  360          * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf
  361          */
  362         { AC97_CODEC_ID('A', 'D', 'S', 3),
  363           0xffffffff,                   "Analog Devices AD1819B" },
  364         { AC97_CODEC_ID('A', 'D', 'S', 0x40),
  365           0xffffffff,                   "Analog Devices AD1881" },
  366         { AC97_CODEC_ID('A', 'D', 'S', 0x48),
  367           0xffffffff,                   "Analog Devices AD1881A" },
  368         { AC97_CODEC_ID('A', 'D', 'S', 0x60),
  369           0xffffffff,                   "Analog Devices AD1885" },
  370         { AC97_CODEC_ID('A', 'D', 'S', 0x61),
  371           0xffffffff,                   "Analog Devices AD1886" },
  372         { AC97_CODEC_ID('A', 'D', 'S', 0x63),
  373           0xffffffff,                   "Analog Devices AD1886A" },
  374         { AC97_CODEC_ID('A', 'D', 'S', 0x68),
  375           0xffffffff,                   "Analog Devices AD1888", ac97_ad198x_init },
  376         { AC97_CODEC_ID('A', 'D', 'S', 0x70),
  377           0xffffffff,                   "Analog Devices AD1980", ac97_ad198x_init },
  378         { AC97_CODEC_ID('A', 'D', 'S', 0x72),
  379           0xffffffff,                   "Analog Devices AD1981A" },
  380         { AC97_CODEC_ID('A', 'D', 'S', 0x74),
  381           0xffffffff,                   "Analog Devices AD1981B" },
  382         { AC97_CODEC_ID('A', 'D', 'S', 0x75),
  383           0xffffffff,                   "Analog Devices AD1985", ac97_ad198x_init },
  384         { AC97_CODEC_ID('A', 'D', 'S', 0),
  385           AC97_VENDOR_ID_MASK,          "Analog Devices unknown" },
  386 
  387         /*
  388          * Datasheets:
  389          *      http://www.asahi-kasei.co.jp/akm/usa/product/ak4541/ek4541.pdf
  390          *      http://www.asahi-kasei.co.jp/akm/usa/product/ak4543/ek4543.pdf
  391          *      http://www.asahi-kasei.co.jp/akm/usa/product/ak4544a/ek4544a.pdf
  392          *      http://www.asahi-kasei.co.jp/akm/usa/product/ak4545/ek4545.pdf
  393          */
  394         { AC97_CODEC_ID('A', 'K', 'M', 0),
  395           0xffffffff,                   "Asahi Kasei AK4540"    },
  396         { AC97_CODEC_ID('A', 'K', 'M', 1),
  397           0xffffffff,                   "Asahi Kasei AK4542"    },
  398         { AC97_CODEC_ID('A', 'K', 'M', 2),
  399           0xffffffff,                   "Asahi Kasei AK4541/AK4543" },
  400         { AC97_CODEC_ID('A', 'K', 'M', 5),
  401           0xffffffff,                   "Asahi Kasei AK4544" },
  402         { AC97_CODEC_ID('A', 'K', 'M', 6),
  403           0xffffffff,                   "Asahi Kasei AK4544A" },
  404         { AC97_CODEC_ID('A', 'K', 'M', 7),
  405           0xffffffff,                   "Asahi Kasei AK4545" },
  406         { AC97_CODEC_ID('A', 'K', 'M', 0),
  407           AC97_VENDOR_ID_MASK,          "Asahi Kasei unknown" },
  408 
  409         /*
  410          * Realtek & Avance Logic
  411          *      http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
  412          *
  413          * ALC650 and ALC658 support VRA, but it supports only 8000, 11025,
  414          * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz.
  415          */
  416         { AC97_CODEC_ID('A', 'L', 'C', 0x00),
  417           0xfffffff0,                   "Realtek RL5306"        },
  418         { AC97_CODEC_ID('A', 'L', 'C', 0x10),
  419           0xfffffff0,                   "Realtek RL5382"        },
  420         { AC97_CODEC_ID('A', 'L', 'C', 0x20),
  421           0xfffffff0,                   "Realtek RL5383/RL5522/ALC100"  },
  422         { AC97_CODEC_ID('A', 'L', 'G', 0x10),
  423           0xffffffff,                   "Avance Logic ALC200/ALC201"    },
  424         { AC97_CODEC_ID('A', 'L', 'G', 0x20),
  425           0xfffffff0,                   "Avance Logic ALC650", ac97_alc650_init },
  426         { AC97_CODEC_ID('A', 'L', 'G', 0x30),
  427           0xffffffff,                   "Avance Logic ALC101"   },
  428         { AC97_CODEC_ID('A', 'L', 'G', 0x40),
  429           0xffffffff,                   "Avance Logic ALC202"   },
  430         { AC97_CODEC_ID('A', 'L', 'G', 0x50),
  431           0xffffffff,                   "Avance Logic ALC250"   },
  432         { AC97_CODEC_ID('A', 'L', 'G', 0x60),
  433           0xfffffff0,                   "Avance Logic ALC655"   },
  434         { AC97_CODEC_ID('A', 'L', 'G', 0x80),
  435           0xfffffff0,                   "Avance Logic ALC658"   },
  436         { AC97_CODEC_ID('A', 'L', 'G', 0x90),
  437           0xfffffff0,                   "Avance Logic ALC850"   },
  438         { AC97_CODEC_ID('A', 'L', 'C', 0),
  439           AC97_VENDOR_ID_MASK,          "Realtek unknown"       },
  440         { AC97_CODEC_ID('A', 'L', 'G', 0),
  441           AC97_VENDOR_ID_MASK,          "Avance Logic unknown"  },
  442 
  443         /**
  444          * C-Media Electronics Inc.
  445          * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf
  446          */
  447         { AC97_CODEC_ID('C', 'M', 'I', 0x61),
  448           0xffffffff,                   "C-Media CMI9739"       },
  449         { AC97_CODEC_ID('C', 'M', 'I', 0),
  450           AC97_VENDOR_ID_MASK,          "C-Media unknown"       },
  451 
  452         /* Cirrus Logic, Crystal series:
  453          *  'C' 'R' 'Y' 0x0[0-7]  - CS4297
  454          *              0x1[0-7]  - CS4297A
  455          *              0x2[0-7]  - CS4298
  456          *              0x2[8-f]  - CS4294
  457          *              0x3[0-7]  - CS4299
  458          *              0x4[8-f]  - CS4201
  459          *              0x5[8-f]  - CS4205
  460          *              0x6[0-7]  - CS4291
  461          *              0x7[0-7]  - CS4202
  462          * Datasheets:
  463          *      http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
  464          *      http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
  465          *      http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
  466          *      http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
  467          *      http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
  468          *      http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
  469          */
  470         { AC97_CODEC_ID('C', 'R', 'Y', 0x00),
  471           0xfffffff8,                   "Crystal CS4297",       },
  472         { AC97_CODEC_ID('C', 'R', 'Y', 0x10),
  473           0xfffffff8,                   "Crystal CS4297A",      },
  474         { AC97_CODEC_ID('C', 'R', 'Y', 0x20),
  475           0xfffffff8,                   "Crystal CS4298",       },
  476         { AC97_CODEC_ID('C', 'R', 'Y', 0x28),
  477           0xfffffff8,                   "Crystal CS4294",       },
  478         { AC97_CODEC_ID('C', 'R', 'Y', 0x30),
  479           0xfffffff8,                   "Crystal CS4299",       },
  480         { AC97_CODEC_ID('C', 'R', 'Y', 0x48),
  481           0xfffffff8,                   "Crystal CS4201",       },
  482         { AC97_CODEC_ID('C', 'R', 'Y', 0x58),
  483           0xfffffff8,                   "Crystal CS4205",       },
  484         { AC97_CODEC_ID('C', 'R', 'Y', 0x60),
  485           0xfffffff8,                   "Crystal CS4291",       },
  486         { AC97_CODEC_ID('C', 'R', 'Y', 0x70),
  487           0xfffffff8,                   "Crystal CS4202",       },
  488         { AC97_CODEC_ID('C', 'R', 'Y', 0),
  489           AC97_VENDOR_ID_MASK,          "Cirrus Logic unknown", },
  490 
  491         { 0x45838308, 0xffffffff,       "ESS Technology ES1921", },
  492         { 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", },
  493 
  494         { AC97_CODEC_ID('H', 'R', 'S', 0),
  495           0xffffffff,                   "Intersil HMP9701",     },
  496         { AC97_CODEC_ID('H', 'R', 'S', 0),
  497           AC97_VENDOR_ID_MASK,          "Intersil unknown",     },
  498 
  499         /*
  500          * IC Ensemble (VIA)
  501          *      http://www.viatech.com/en/datasheet/DS1616.pdf
  502          */
  503         { AC97_CODEC_ID('I', 'C', 'E', 0x01),
  504           0xffffffff,                   "ICEnsemble ICE1230/VT1611",    },
  505         { AC97_CODEC_ID('I', 'C', 'E', 0x11),
  506           0xffffffff,                   "ICEnsemble ICE1232/VT1611A",   },
  507         { AC97_CODEC_ID('I', 'C', 'E', 0x14),
  508           0xffffffff,                   "ICEnsemble ICE1232A",  },
  509         { AC97_CODEC_ID('I', 'C', 'E', 0x51),
  510           0xffffffff,                   "VIA Technologies VT1616", ac97_vt1616_init },
  511         { AC97_CODEC_ID('I', 'C', 'E', 0x52),
  512           0xffffffff,                   "VIA Technologies VT1616i", ac97_vt1616_init },
  513         { AC97_CODEC_ID('I', 'C', 'E', 0),
  514           AC97_VENDOR_ID_MASK,          "ICEnsemble/VIA unknown",       },
  515 
  516         { AC97_CODEC_ID('N', 'S', 'C', 0),
  517           0xffffffff,                   "National Semiconductor LM454[03568]", },
  518         { AC97_CODEC_ID('N', 'S', 'C', 49),
  519           0xffffffff,                   "National Semiconductor LM4549", },
  520         { AC97_CODEC_ID('N', 'S', 'C', 0),
  521           AC97_VENDOR_ID_MASK,          "National Semiconductor unknown", },
  522 
  523         { AC97_CODEC_ID('P', 'S', 'C', 4),
  524           0xffffffff,                   "Philips Semiconductor UCB1400", },
  525         { AC97_CODEC_ID('P', 'S', 'C', 0),
  526           AC97_VENDOR_ID_MASK,          "Philips Semiconductor unknown", },
  527 
  528         { AC97_CODEC_ID('S', 'I', 'L', 34),
  529           0xffffffff,                   "Silicon Laboratory Si3036", },
  530         { AC97_CODEC_ID('S', 'I', 'L', 35),
  531           0xffffffff,                   "Silicon Laboratory Si3038", },
  532         { AC97_CODEC_ID('S', 'I', 'L', 0),
  533           AC97_VENDOR_ID_MASK,          "Silicon Laboratory unknown", },
  534 
  535         { AC97_CODEC_ID('T', 'R', 'A', 2),
  536           0xffffffff,                   "TriTech TR28022",      },
  537         { AC97_CODEC_ID('T', 'R', 'A', 3),
  538           0xffffffff,                   "TriTech TR28023",      },
  539         { AC97_CODEC_ID('T', 'R', 'A', 6),
  540           0xffffffff,                   "TriTech TR28026",      },
  541         { AC97_CODEC_ID('T', 'R', 'A', 8),
  542           0xffffffff,                   "TriTech TR28028",      },
  543         { AC97_CODEC_ID('T', 'R', 'A', 35),
  544           0xffffffff,                   "TriTech TR28602",      },
  545         { AC97_CODEC_ID('T', 'R', 'A', 0),
  546           AC97_VENDOR_ID_MASK,          "TriTech unknown",      },
  547 
  548         { AC97_CODEC_ID('T', 'X', 'N', 0x20),
  549           0xffffffff,                   "Texas Instruments TLC320AD9xC", },
  550         { AC97_CODEC_ID('T', 'X', 'N', 0),
  551           AC97_VENDOR_ID_MASK,          "Texas Instruments unknown", },
  552 
  553         /*
  554          * VIA
  555          * http://www.viatech.com/en/multimedia/audio.jsp
  556          */
  557         { AC97_CODEC_ID('V', 'I', 'A', 0x61),
  558           0xffffffff,                   "VIA Technologies VT1612A", },
  559         { AC97_CODEC_ID('V', 'I', 'A', 0),
  560           AC97_VENDOR_ID_MASK,          "VIA Technologies unknown", },
  561 
  562         { AC97_CODEC_ID('W', 'E', 'C', 1),
  563           0xffffffff,                   "Winbond W83971D",      },
  564         { AC97_CODEC_ID('W', 'E', 'C', 0),
  565           AC97_VENDOR_ID_MASK,          "Winbond unknown",      },
  566 
  567         /*
  568          * http://www.wolfsonmicro.com/product_list.asp?cid=64
  569          *      http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
  570          *      http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf  - 03
  571          *      http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
  572          *      http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
  573          *      http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
  574          *      http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf  - 03
  575          *      http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
  576          *      http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
  577          */
  578         { AC97_CODEC_ID('W', 'M', 'L', 0),
  579           0xffffffff,                   "Wolfson WM9701A",      },
  580         { AC97_CODEC_ID('W', 'M', 'L', 3),
  581           0xffffffff,                   "Wolfson WM9703/WM9707/WM9708", },
  582         { AC97_CODEC_ID('W', 'M', 'L', 4),
  583           0xffffffff,                   "Wolfson WM9704",       },
  584         { AC97_CODEC_ID('W', 'M', 'L', 5),
  585           0xffffffff,                   "Wolfson WM9705/WM9710", },
  586         { AC97_CODEC_ID('W', 'M', 'L', 0),
  587           AC97_VENDOR_ID_MASK,          "Wolfson unknown",      },
  588 
  589         /*
  590          * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
  591          * Datasheets:
  592          *      http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
  593          *      http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
  594          */
  595         { AC97_CODEC_ID('Y', 'M', 'H', 0),
  596           0xffffffff,                   "Yamaha YMF743-S",      },
  597         { AC97_CODEC_ID('Y', 'M', 'H', 3),
  598           0xffffffff,                   "Yamaha YMF753-S",      },
  599         { AC97_CODEC_ID('Y', 'M', 'H', 0),
  600           AC97_VENDOR_ID_MASK,          "Yamaha unknown",       },
  601 
  602         /*
  603          * http://www.sigmatel.com/audio/audio_codecs.htm
  604          */
  605         { 0x83847600, 0xffffffff,       "SigmaTel STAC9700",    },
  606         { 0x83847604, 0xffffffff,       "SigmaTel STAC9701/3/4/5", },
  607         { 0x83847605, 0xffffffff,       "SigmaTel STAC9704",    },
  608         { 0x83847608, 0xffffffff,       "SigmaTel STAC9708",    },
  609         { 0x83847609, 0xffffffff,       "SigmaTel STAC9721/23", },
  610         { 0x83847644, 0xffffffff,       "SigmaTel STAC9744/45", },
  611         { 0x83847650, 0xffffffff,       "SigmaTel STAC9750/51", },
  612         { 0x83847656, 0xffffffff,       "SigmaTel STAC9756/57", },
  613         { 0x83847666, 0xffffffff,       "SigmaTel STAC9766/67", },
  614         { 0x83847684, 0xffffffff,       "SigmaTel STAC9783/84", },
  615         { 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown",  },
  616 
  617         { 0,
  618           0,                    NULL,                   }
  619 };
  620 
  621 static const char * const ac97enhancement[] = {
  622         "no 3D stereo",
  623         "Analog Devices Phat Stereo",
  624         "Creative",
  625         "National Semi 3D",
  626         "Yamaha Ymersion",
  627         "BBE 3D",
  628         "Crystal Semi 3D",
  629         "Qsound QXpander",
  630         "Spatializer 3D",
  631         "SRS 3D",
  632         "Platform Tech 3D",
  633         "AKM 3D",
  634         "Aureal",
  635         "AZTECH 3D",
  636         "Binaura 3D",
  637         "ESS Technology",
  638         "Harman International VMAx",
  639         "Nvidea 3D",
  640         "Philips Incredible Sound",
  641         "Texas Instruments' 3D",
  642         "VLSI Technology 3D",
  643         "TriTech 3D",
  644         "Realtek 3D",
  645         "Samsung 3D",
  646         "Wolfson Microelectronics 3D",
  647         "Delta Integration 3D",
  648         "SigmaTel 3D",
  649         "KS Waves 3D",
  650         "Rockwell 3D",
  651         "Unknown 3D",
  652         "Unknown 3D",
  653         "Unknown 3D",
  654 };
  655 
  656 static const char * const ac97feature[] = {
  657         "dedicated mic channel",
  658         "reserved",
  659         "tone",
  660         "simulated stereo",
  661         "headphone",
  662         "bass boost",
  663         "18 bit DAC",
  664         "20 bit DAC",
  665         "18 bit ADC",
  666         "20 bit ADC"
  667 };
  668 
  669 
  670 /* #define AC97_DEBUG 10 */
  671 
  672 #ifdef AUDIO_DEBUG
  673 #define DPRINTF(x)      if (ac97debug) printf x
  674 #define DPRINTFN(n,x)   if (ac97debug>(n)) printf x
  675 #ifdef AC97_DEBUG
  676 int     ac97debug = AC97_DEBUG;
  677 #else
  678 int     ac97debug = 0;
  679 #endif
  680 #else
  681 #define DPRINTF(x)
  682 #define DPRINTFN(n,x)
  683 #endif
  684 
  685 void
  686 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
  687 {
  688         if (as->host_flags & AC97_HOST_DONT_READ &&
  689             (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
  690              reg != AC97_REG_RESET)) {
  691                 *val = as->shadow_reg[reg >> 1];
  692                 return;
  693         }
  694 
  695         if (as->host_if->read(as->host_if->arg, reg, val)) {
  696                 *val = as->shadow_reg[reg >> 1];
  697         }
  698 }
  699 
  700 int
  701 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
  702 {
  703         as->shadow_reg[reg >> 1] = val;
  704         return as->host_if->write(as->host_if->arg, reg, val);
  705 }
  706 
  707 void
  708 ac97_setup_defaults(struct ac97_softc *as)
  709 {
  710         int idx;
  711         const struct ac97_source_info *si;
  712 
  713         memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
  714 
  715         for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
  716                 si = &source_info[idx];
  717                 ac97_write(as, si->reg, si->default_value);
  718         }
  719 }
  720 
  721 void
  722 ac97_restore_shadow(struct ac97_codec_if *self)
  723 {
  724         struct ac97_softc *as;
  725         const struct ac97_source_info *si;
  726         int idx;
  727         uint16_t val;
  728 
  729         as = (struct ac97_softc *) self;
  730 
  731         /* make sure chip is fully operational */
  732 #define AC97_POWER_ALL  (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \
  733                         | AC97_POWER_ADC)
  734         for (idx = 500000; idx >= 0; idx--) {
  735                 ac97_read(as, AC97_REG_POWER, &val);
  736                 if ((val & AC97_POWER_ALL) == AC97_POWER_ALL)
  737                        break;
  738                 DELAY(1);
  739         }
  740 #undef AC97_POWER_ALL
  741 
  742         for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
  743                 si = &source_info[idx];
  744                 /* don't "restore" to the reset reg! */
  745                 if (si->reg != AC97_REG_RESET)
  746                         ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
  747         }
  748 
  749         if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
  750                           | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
  751                           | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
  752                           | AC97_EXT_AUDIO_LDAC)) {
  753                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
  754                     as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]);
  755         }
  756 }
  757 
  758 int
  759 ac97_str_equal(const char *a, const char *b)
  760 {
  761         return (a == b) || (a && b && (!strcmp(a, b)));
  762 }
  763 
  764 int
  765 ac97_check_capability(struct ac97_softc *as, int check)
  766 {
  767         switch (check) {
  768         case CHECK_NONE:
  769                 return 1;
  770         case CHECK_SURROUND:
  771                 return as->ext_id & AC97_EXT_AUDIO_SDAC;
  772         case CHECK_CENTER:
  773                 return as->ext_id & AC97_EXT_AUDIO_CDAC;
  774         case CHECK_LFE:
  775                 return as->ext_id & AC97_EXT_AUDIO_LDAC;
  776         case CHECK_HEADPHONES:
  777                 return as->caps & AC97_CAPS_HEADPHONES;
  778         case CHECK_TONE:
  779                 return as->caps & AC97_CAPS_TONECTRL;
  780         case CHECK_MIC:
  781                 return as->caps & AC97_CAPS_MICIN;
  782         case CHECK_LOUDNESS:
  783                 return as->caps & AC97_CAPS_LOUDNESS;
  784         case CHECK_3D:
  785                 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
  786         default:
  787                 printf("%s: internal error: feature=%d\n", __func__, check);
  788                 return 0;
  789         }
  790 }
  791 
  792 void
  793 ac97_setup_source_info(struct ac97_softc *as)
  794 {
  795         int idx, ouridx;
  796         struct ac97_source_info *si, *si2;
  797 
  798         for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
  799                 si = &as->source_info[ouridx];
  800 
  801                 if (!ac97_check_capability(as, source_info[idx].req_feature))
  802                         continue;
  803 
  804                 memcpy(si, &source_info[idx], sizeof(*si));
  805 
  806                 switch (si->type) {
  807                 case AUDIO_MIXER_CLASS:
  808                         si->mixer_class = ouridx;
  809                         ouridx++;
  810                         break;
  811                 case AUDIO_MIXER_VALUE:
  812                         /* Todo - Test to see if it works */
  813                         ouridx++;
  814 
  815                         /* Add an entry for mute, if necessary */
  816                         if (si->mute) {
  817                                 si = &as->source_info[ouridx];
  818                                 memcpy(si, &source_info[idx], sizeof(*si));
  819                                 si->qualifier = AudioNmute;
  820                                 si->type = AUDIO_MIXER_ENUM;
  821                                 si->info = &ac97_on_off;
  822                                 si->info_size = sizeof(ac97_on_off);
  823                                 si->bits = 1;
  824                                 si->ofs = 15;
  825                                 si->mute = 0;
  826                                 si->polarity = 0;
  827                                 ouridx++;
  828                         }
  829                         break;
  830                 case AUDIO_MIXER_ENUM:
  831                         /* Todo - Test to see if it works */
  832                         ouridx++;
  833                         break;
  834                 default:
  835                         aprint_error ("ac97: shouldn't get here\n");
  836                         break;
  837                 }
  838         }
  839 
  840         as->num_source_info = ouridx;
  841 
  842         for (idx = 0; idx < as->num_source_info; idx++) {
  843                 int idx2, previdx;
  844 
  845                 si = &as->source_info[idx];
  846 
  847                 /* Find mixer class */
  848                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
  849                         si2 = &as->source_info[idx2];
  850 
  851                         if (si2->type == AUDIO_MIXER_CLASS &&
  852                             ac97_str_equal(si->class,
  853                                            si2->class)) {
  854                                 si->mixer_class = idx2;
  855                         }
  856                 }
  857 
  858 
  859                 /* Setup prev and next pointers */
  860                 if (si->prev != 0)
  861                         continue;
  862 
  863                 if (si->qualifier)
  864                         continue;
  865 
  866                 si->prev = AUDIO_MIXER_LAST;
  867                 previdx = idx;
  868 
  869                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
  870                         if (idx2 == idx)
  871                                 continue;
  872 
  873                         si2 = &as->source_info[idx2];
  874 
  875                         if (!si2->prev &&
  876                             ac97_str_equal(si->class, si2->class) &&
  877                             ac97_str_equal(si->device, si2->device)) {
  878                                 as->source_info[previdx].next = idx2;
  879                                 as->source_info[idx2].prev = previdx;
  880 
  881                                 previdx = idx2;
  882                         }
  883                 }
  884 
  885                 as->source_info[previdx].next = AUDIO_MIXER_LAST;
  886         }
  887 }
  888 
  889 int
  890 ac97_attach(struct ac97_host_if *host_if)
  891 {
  892         struct ac97_softc *as;
  893         struct device *sc_dev;
  894         int error, i, j;
  895         uint32_t id;
  896         uint16_t id1, id2;
  897         uint16_t extstat, rate;
  898         uint16_t val;
  899         mixer_ctrl_t ctl;
  900         void (*initfunc)(struct ac97_softc *);
  901 #define FLAGBUFLEN      140
  902         char flagbuf[FLAGBUFLEN];
  903 
  904         sc_dev = (struct device *)host_if->arg;
  905         initfunc = NULL;
  906         as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
  907 
  908         if (as == NULL)
  909                 return ENOMEM;
  910 
  911         as->codec_if.vtbl = &ac97civ;
  912         as->host_if = host_if;
  913 
  914         if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
  915                 free(as, M_DEVBUF);
  916                 return error;
  917         }
  918 
  919         if ((error = host_if->reset(host_if->arg))) {
  920                 free(as, M_DEVBUF);
  921                 return error;
  922         }
  923 
  924         host_if->write(host_if->arg, AC97_REG_POWER, 0);
  925         host_if->write(host_if->arg, AC97_REG_RESET, 0);
  926 
  927         if (host_if->flags)
  928                 as->host_flags = host_if->flags(host_if->arg);
  929 
  930 #define AC97_POWER_ALL  (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \
  931                         | AC97_POWER_ADC)
  932         for (i = 500000; i >= 0; i--) {
  933                 ac97_read(as, AC97_REG_POWER, &val);
  934                 if ((val & AC97_POWER_ALL) == AC97_POWER_ALL)
  935                        break;
  936                 DELAY(1);
  937         }
  938 #undef AC97_POWER_ALL
  939 
  940         ac97_setup_defaults(as);
  941         ac97_read(as, AC97_REG_RESET, &as->caps);
  942         ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
  943         ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
  944 
  945         id = (id1 << 16) | id2;
  946 
  947         aprint_normal("%s: ac97: ", sc_dev->dv_xname);
  948 
  949         for (i = 0; ; i++) {
  950                 if (ac97codecid[i].id == 0) {
  951                         char pnp[4];
  952 
  953                         AC97_GET_CODEC_ID(id, pnp);
  954 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
  955                         if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
  956                             ISASCII(pnp[2]))
  957                                 aprint_normal("%c%c%c%d",
  958                                     pnp[0], pnp[1], pnp[2], pnp[3]);
  959                         else
  960                                 aprint_normal("unknown (0x%08x)", id);
  961                         break;
  962                 }
  963                 if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
  964                         aprint_normal("%s", ac97codecid[i].name);
  965                         if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
  966                                 aprint_normal(" (0x%08x)", id);
  967                         }
  968                         initfunc = ac97codecid[i].init;
  969                         break;
  970                 }
  971         }
  972         aprint_normal(" codec; ");
  973         for (i = j = 0; i < 10; i++) {
  974                 if (as->caps & (1 << i)) {
  975                         aprint_normal("%s%s", j ? ", " : "", ac97feature[i]);
  976                         j++;
  977                 }
  978         }
  979         aprint_normal("%s%s\n", j ? ", " : "",
  980                ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
  981 
  982         as->ac97_clock = AC97_STANDARD_CLOCK;
  983         ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
  984         if (as->ext_id != 0) {
  985                 /* Print capabilities */
  986                 bitmask_snprintf(as->ext_id, "\2\20SECONDARY10\17SECONDARY01"
  987                                  "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
  988                                  "\7CDAC\4VRM\3SPDIF\2DRA\1VRA",
  989                                  flagbuf, FLAGBUFLEN);
  990                 aprint_normal("%s: ac97: ext id %s\n", sc_dev->dv_xname, flagbuf);
  991 
  992                 /* Print unusual settings */
  993                 if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
  994                         aprint_normal("%s: ac97: Slot assignment: ",
  995                                       sc_dev->dv_xname);
  996                         switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
  997                         case AC97_EXT_AUDIO_DSA01:
  998                                 aprint_normal("7&8, 6&9, 10&11.\n");
  999                                 break;
 1000                         case AC97_EXT_AUDIO_DSA10:
 1001                                 aprint_normal("6&9, 10&11, 3&4.\n");
 1002                                 break;
 1003                         case AC97_EXT_AUDIO_DSA11:
 1004                                 aprint_normal("10&11, 3&4, 7&8.\n");
 1005                                 break;
 1006                         }
 1007                 }
 1008 
 1009                 /* Enable and disable features */
 1010                 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
 1011                 extstat &= ~AC97_EXT_AUDIO_DRA;
 1012                 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
 1013                         extstat |= AC97_EXT_AUDIO_LDAC;
 1014                 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
 1015                         extstat |= AC97_EXT_AUDIO_SDAC;
 1016                 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
 1017                         extstat |= AC97_EXT_AUDIO_CDAC;
 1018                 if (as->ext_id & AC97_EXT_AUDIO_VRM)
 1019                         extstat |= AC97_EXT_AUDIO_VRM;
 1020                 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
 1021                         /* Output the same data as DAC to SPDIF output */
 1022                         extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
 1023                         extstat |= AC97_EXT_AUDIO_SPSA34;
 1024                 }
 1025                 if (as->ext_id & AC97_EXT_AUDIO_VRA)
 1026                         extstat |= AC97_EXT_AUDIO_VRA;
 1027                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
 1028                 if (as->ext_id & AC97_EXT_AUDIO_VRA) {
 1029                         /* VRA should be enabled. */
 1030                         /* so it claims to do variable rate, let's make sure */
 1031                         ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
 1032                         ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
 1033                         if (rate != 44100) {
 1034                                 /* We can't believe ext_id */
 1035                                 as->ext_id = 0;
 1036                                 aprint_normal(
 1037                                     "%s: Ignore these capabilities.\n",
 1038                                     sc_dev->dv_xname);
 1039                         }
 1040                         /* restore the default value */
 1041                         ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
 1042                                    AC97_SINGLE_RATE);
 1043                 }
 1044         }
 1045 
 1046         ac97_setup_source_info(as);
 1047 
 1048         memset(&ctl, 0, sizeof(ctl));
 1049         /* disable mutes */
 1050         for (i = 0; i < 11; i++) {
 1051                 static struct {
 1052                         char *class, *device;
 1053                 } d[11] = {
 1054                         { AudioCoutputs, AudioNmaster},
 1055                         { AudioCoutputs, AudioNheadphone},
 1056                         { AudioCoutputs, AudioNsurround},
 1057                         { AudioCoutputs, AudioNcenter},
 1058                         { AudioCoutputs, AudioNlfe},
 1059                         { AudioCinputs, AudioNdac},
 1060                         { AudioCinputs, AudioNcd},
 1061                         { AudioCinputs, AudioNline},
 1062                         { AudioCinputs, AudioNaux},
 1063                         { AudioCinputs, AudioNvideo},
 1064                         { AudioCrecord, AudioNvolume},
 1065                 };
 1066 
 1067                 ctl.type = AUDIO_MIXER_ENUM;
 1068                 ctl.un.ord = 0;
 1069 
 1070                 ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
 1071                         d[i].class, d[i].device, AudioNmute);
 1072                 ac97_mixer_set_port(&as->codec_if, &ctl);
 1073         }
 1074         ctl.type = AUDIO_MIXER_ENUM;
 1075         ctl.un.ord = 0;
 1076         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
 1077                                            AudioNsource, NULL);
 1078         ac97_mixer_set_port(&as->codec_if, &ctl);
 1079 
 1080         /* set a reasonable default volume */
 1081         ctl.type = AUDIO_MIXER_VALUE;
 1082         ctl.un.value.num_channels = 2;
 1083         ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
 1084         ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
 1085         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
 1086                                            AudioNmaster, NULL);
 1087         ac97_mixer_set_port(&as->codec_if, &ctl);
 1088         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
 1089                                            AudioNsurround, NULL);
 1090         ac97_mixer_set_port(&as->codec_if, &ctl);
 1091         ctl.un.value.num_channels = 1;
 1092         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
 1093                                            AudioNcenter, NULL);
 1094         ac97_mixer_set_port(&as->codec_if, &ctl);
 1095         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
 1096                                            AudioNlfe, NULL);
 1097         ac97_mixer_set_port(&as->codec_if, &ctl);
 1098 
 1099         if (initfunc != NULL)
 1100                 initfunc(as);
 1101         return 0;
 1102 }
 1103 
 1104 
 1105 int
 1106 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
 1107 {
 1108         struct ac97_softc *as;
 1109         struct ac97_source_info *si;
 1110         const char *name;
 1111 
 1112         as = (struct ac97_softc *)codec_if;
 1113         if (dip->index < as->num_source_info) {
 1114                 si = &as->source_info[dip->index];
 1115                 dip->type = si->type;
 1116                 dip->mixer_class = si->mixer_class;
 1117                 dip->prev = si->prev;
 1118                 dip->next = si->next;
 1119 
 1120                 if (si->qualifier)
 1121                         name = si->qualifier;
 1122                 else if (si->device)
 1123                         name = si->device;
 1124                 else if (si->class)
 1125                         name = si->class;
 1126                 else
 1127                         name = 0;
 1128 
 1129                 if (name)
 1130                         strcpy(dip->label.name, name);
 1131 
 1132                 memcpy(&dip->un, si->info, si->info_size);
 1133 
 1134                 /* Set the delta for volume sources */
 1135                 if (dip->type == AUDIO_MIXER_VALUE)
 1136                         dip->un.v.delta = 1 << (8 - si->bits);
 1137 
 1138                 return 0;
 1139         }
 1140 
 1141         return ENXIO;
 1142 }
 1143 
 1144 
 1145 
 1146 int
 1147 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
 1148 {
 1149         struct ac97_softc *as;
 1150         struct ac97_source_info *si;
 1151         u_int16_t mask;
 1152         u_int16_t val, newval;
 1153         int error;
 1154 
 1155         as = (struct ac97_softc *)codec_if;
 1156         si = &as->source_info[cp->dev];
 1157         if (cp->dev < 0 || cp->dev >= as->num_source_info)
 1158                 return EINVAL;
 1159 
 1160         if (cp->type != si->type)
 1161                 return EINVAL;
 1162 
 1163         ac97_read(as, si->reg, &val);
 1164 
 1165         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
 1166 
 1167         mask = (1 << si->bits) - 1;
 1168 
 1169         switch (cp->type) {
 1170         case AUDIO_MIXER_ENUM:
 1171                 if (cp->un.ord > mask || cp->un.ord < 0)
 1172                         return EINVAL;
 1173 
 1174                 newval = (cp->un.ord << si->ofs);
 1175                 if (si->reg == AC97_REG_RECORD_SELECT) {
 1176                         newval |= (newval << (8 + si->ofs));
 1177                         mask |= (mask << 8);
 1178                         mask = mask << si->ofs;
 1179                 } else if (si->reg == AC97_REG_SURR_MASTER) {
 1180                         newval = cp->un.ord ? 0x8080 : 0x0000;
 1181                         mask = 0x8080;
 1182                 } else
 1183                         mask = mask << si->ofs;
 1184                 break;
 1185         case AUDIO_MIXER_VALUE:
 1186         {
 1187                 const struct audio_mixer_value *value = si->info;
 1188                 u_int16_t  l, r, ol, or;
 1189                 int deltal, deltar;
 1190 
 1191                 if ((cp->un.value.num_channels <= 0) ||
 1192                     (cp->un.value.num_channels > value->num_channels))
 1193                         return EINVAL;
 1194 
 1195                 if (cp->un.value.num_channels == 1) {
 1196                         l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
 1197                 } else {
 1198                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
 1199                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
 1200                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
 1201                         } else {        /* left/right is reversed here */
 1202                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
 1203                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
 1204                         }
 1205 
 1206                 }
 1207 
 1208                 if (!si->polarity) {
 1209                         l = 255 - l;
 1210                         r = 255 - r;
 1211                 }
 1212 
 1213                 ol = (val >> (8+si->ofs)) & mask;
 1214                 or = (val >> si->ofs) & mask;
 1215 
 1216                 deltal = (ol << (8 - si->bits)) - l;
 1217                 deltar = (or << (8 - si->bits)) - r;
 1218 
 1219                 l = l >> (8 - si->bits);
 1220                 r = r >> (8 - si->bits);
 1221 
 1222                 if (deltal && ol == l)
 1223                         l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
 1224                 if (deltar && or == r)
 1225                         r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
 1226 
 1227                 newval = ((r & mask) << si->ofs);
 1228                 if (value->num_channels == 2) {
 1229                         newval = newval | ((l & mask) << (si->ofs+8));
 1230                         mask |= (mask << 8);
 1231                 }
 1232                 mask = mask << si->ofs;
 1233                 break;
 1234         }
 1235         default:
 1236                 return EINVAL;
 1237         }
 1238 
 1239         error = ac97_write(as, si->reg, (val & ~mask) | newval);
 1240         if (error)
 1241                 return error;
 1242 
 1243         return 0;
 1244 }
 1245 
 1246 int
 1247 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
 1248                          const char *device, const char *qualifier)
 1249 {
 1250         struct ac97_softc *as;
 1251         int idx;
 1252 
 1253         as = (struct ac97_softc *)codec_if;
 1254         for (idx = 0; idx < as->num_source_info; idx++) {
 1255                 struct ac97_source_info *si = &as->source_info[idx];
 1256                 if (ac97_str_equal(class, si->class) &&
 1257                     ac97_str_equal(device, si->device) &&
 1258                     ac97_str_equal(qualifier, si->qualifier))
 1259                         return idx;
 1260         }
 1261 
 1262         return -1;
 1263 }
 1264 
 1265 int
 1266 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
 1267 {
 1268         struct ac97_softc *as;
 1269         struct ac97_source_info *si;
 1270         u_int16_t mask;
 1271         u_int16_t val;
 1272 
 1273         as = (struct ac97_softc *)codec_if;
 1274         si = &as->source_info[cp->dev];
 1275         if (cp->dev < 0 || cp->dev >= as->num_source_info)
 1276                 return EINVAL;
 1277 
 1278         if (cp->type != si->type)
 1279                 return EINVAL;
 1280 
 1281         ac97_read(as, si->reg, &val);
 1282 
 1283         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
 1284 
 1285         mask = (1 << si->bits) - 1;
 1286 
 1287         switch (cp->type) {
 1288         case AUDIO_MIXER_ENUM:
 1289                 cp->un.ord = (val >> si->ofs) & mask;
 1290                 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
 1291                              val, si->ofs, mask, cp->un.ord));
 1292                 break;
 1293         case AUDIO_MIXER_VALUE:
 1294         {
 1295                 const struct audio_mixer_value *value = si->info;
 1296                 u_int16_t  l, r;
 1297 
 1298                 if ((cp->un.value.num_channels <= 0) ||
 1299                     (cp->un.value.num_channels > value->num_channels))
 1300                         return EINVAL;
 1301 
 1302                 if (value->num_channels == 1) {
 1303                         l = r = (val >> si->ofs) & mask;
 1304                 } else {
 1305                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
 1306                                 l = (val >> (si->ofs + 8)) & mask;
 1307                                 r = (val >> si->ofs) & mask;
 1308                         } else {        /* host has reversed channels */
 1309                                 r = (val >> (si->ofs + 8)) & mask;
 1310                                 l = (val >> si->ofs) & mask;
 1311                         }
 1312                 }
 1313 
 1314                 l = (l << (8 - si->bits));
 1315                 r = (r << (8 - si->bits));
 1316                 if (!si->polarity) {
 1317                         l = 255 - l;
 1318                         r = 255 - r;
 1319                 }
 1320 
 1321                 /* The EAP driver averages l and r for stereo
 1322                    channels that are requested in MONO mode. Does this
 1323                    make sense? */
 1324                 if (cp->un.value.num_channels == 1) {
 1325                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
 1326                 } else if (cp->un.value.num_channels == 2) {
 1327                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
 1328                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
 1329                 }
 1330 
 1331                 break;
 1332         }
 1333         default:
 1334                 return EINVAL;
 1335         }
 1336 
 1337         return 0;
 1338 }
 1339 
 1340 
 1341 int
 1342 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
 1343 {
 1344         struct ac97_softc *as;
 1345         u_long value;
 1346         u_int16_t ext_stat;
 1347         u_int16_t actual;
 1348         u_int16_t power;
 1349         u_int16_t power_bit;
 1350 
 1351         as = (struct ac97_softc *)codec_if;
 1352         if (target == AC97_REG_PCM_MIC_ADC_RATE) {
 1353                 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
 1354                         *rate = AC97_SINGLE_RATE;
 1355                         return 0;
 1356                 }
 1357         } else {
 1358                 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
 1359                         *rate = AC97_SINGLE_RATE;
 1360                         return 0;
 1361                 }
 1362         }
 1363         value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
 1364         ext_stat = 0;
 1365         /*
 1366          * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
 1367          *      Check VRA, DRA
 1368          * PCM_LR_ADC_RATE
 1369          *      Check VRA
 1370          * PCM_MIC_ADC_RATE
 1371          *      Check VRM
 1372          */
 1373         switch (target) {
 1374         case AC97_REG_PCM_FRONT_DAC_RATE:
 1375         case AC97_REG_PCM_SURR_DAC_RATE:
 1376         case AC97_REG_PCM_LFE_DAC_RATE:
 1377                 power_bit = AC97_POWER_OUT;
 1378                 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
 1379                         *rate = AC97_SINGLE_RATE;
 1380                         return 0;
 1381                 }
 1382                 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
 1383                         ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
 1384                         if (value > 0x1ffff) {
 1385                                 return EINVAL;
 1386                         } else if (value > 0xffff) {
 1387                                 /* Enable DRA */
 1388                                 ext_stat |= AC97_EXT_AUDIO_DRA;
 1389                                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
 1390                                 value /= 2;
 1391                         } else {
 1392                                 /* Disable DRA */
 1393                                 ext_stat &= ~AC97_EXT_AUDIO_DRA;
 1394                                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
 1395                         }
 1396                 } else {
 1397                         if (value > 0xffff)
 1398                                 return EINVAL;
 1399                 }
 1400                 break;
 1401         case AC97_REG_PCM_LR_ADC_RATE:
 1402                 power_bit = AC97_POWER_IN;
 1403                 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
 1404                         *rate = AC97_SINGLE_RATE;
 1405                         return 0;
 1406                 }
 1407                 if (value > 0xffff)
 1408                         return EINVAL;
 1409                 break;
 1410         case AC97_REG_PCM_MIC_ADC_RATE:
 1411                 power_bit = AC97_POWER_IN;
 1412                 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
 1413                         *rate = AC97_SINGLE_RATE;
 1414                         return 0;
 1415                 }
 1416                 if (value > 0xffff)
 1417                         return EINVAL;
 1418                 break;
 1419         default:
 1420                 printf("%s: Unknown register: 0x%x\n", __func__, target);
 1421                 return EINVAL;
 1422         }
 1423 
 1424         ac97_read(as, AC97_REG_POWER, &power);
 1425         ac97_write(as, AC97_REG_POWER, power | power_bit);
 1426 
 1427         ac97_write(as, target, (u_int16_t)value);
 1428         ac97_read(as, target, &actual);
 1429         actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
 1430 
 1431         ac97_write(as, AC97_REG_POWER, power);
 1432         if (ext_stat & AC97_EXT_AUDIO_DRA) {
 1433                 *rate = actual * 2;
 1434         } else {
 1435                 *rate = actual;
 1436         }
 1437         return 0;
 1438 }
 1439 
 1440 void
 1441 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
 1442 {
 1443         struct ac97_softc *as;
 1444 
 1445         as = (struct ac97_softc *)codec_if;
 1446         as->ac97_clock = clock;
 1447 }
 1448 
 1449 u_int16_t
 1450 ac97_get_extcaps(struct ac97_codec_if *codec_if)
 1451 {
 1452         struct ac97_softc *as;
 1453 
 1454         as = (struct ac97_softc *)codec_if;
 1455         return as->ext_id;
 1456 }
 1457 
 1458 int
 1459 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
 1460 {
 1461         struct ac97_source_info *si;
 1462         int ouridx, idx;
 1463 
 1464         if (as->num_source_info >= MAX_SOURCES) {
 1465                 printf("%s: internal error: increase MAX_SOURCES in %s\n",
 1466                        __func__, __FILE__);
 1467                 return -1;
 1468         }
 1469         if (!ac97_check_capability(as, src->req_feature))
 1470                 return -1;
 1471         ouridx = as->num_source_info;
 1472         si = &as->source_info[ouridx];
 1473         memcpy(si, src, sizeof(*si));
 1474 
 1475         switch (si->type) {
 1476         case AUDIO_MIXER_CLASS:
 1477         case AUDIO_MIXER_VALUE:
 1478                 printf("%s: adding class/value is not supported yet.\n",
 1479                        __func__);
 1480                 return -1;
 1481         case AUDIO_MIXER_ENUM:
 1482                 break;
 1483         default:
 1484                 printf("%s: unknown type: %d\n", __func__, si->type);
 1485                 return -1;
 1486         }
 1487         as->num_source_info++;
 1488 
 1489         si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
 1490                                                    NULL, NULL);
 1491         /* Find the root of the device */
 1492         idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
 1493                                        si->device, NULL);
 1494         /* Find the last item */
 1495         while (as->source_info[idx].next != AUDIO_MIXER_LAST)
 1496                 idx = as->source_info[idx].next;
 1497         /* Append */
 1498         as->source_info[idx].next = ouridx;
 1499         si->prev = idx;
 1500         si->next = AUDIO_MIXER_LAST;
 1501 
 1502         return 0;
 1503 }
 1504 
 1505 /**
 1506  * Codec-dependent initialization
 1507  */
 1508 
 1509 #define AD1980_REG_MISC 0x76
 1510 #define         AD1980_MISC_MBG0        0x0001  /* 0 1888/1980/1981 /1985 */
 1511 #define         AD1980_MISC_MBG1        0x0002  /* 1 1888/1980/1981 /1985 */
 1512 #define         AD1980_MISC_VREFD       0x0004  /* 2 1888/1980/1981 /1985 */
 1513 #define         AD1980_MISC_VREFH       0x0008  /* 3 1888/1980/1981 /1985 */
 1514 #define         AD1980_MISC_SRU         0x0010  /* 4 1888/1980      /1985 */
 1515 #define         AD1980_MISC_LOSEL       0x0020  /* 5 1888/1980/1981 /1985 */
 1516 #define         AD1980_MISC_2CMIC       0x0040  /* 6      1980/1981B/1985 */
 1517 #define         AD1980_MISC_SPRD        0x0080  /* 7 1888/1980      /1985 */
 1518 #define         AD1980_MISC_DMIX0       0x0100  /* 8 1888/1980      /1985 */
 1519 #define         AD1980_MISC_DMIX1       0x0200  /* 9 1888/1980      /1985 */
 1520 #define         AD1980_MISC_HPSEL       0x0400  /*10 1888/1980      /1985 */
 1521 #define         AD1980_MISC_CLDIS       0x0800  /*11 1888/1980      /1985 */
 1522 #define         AD1980_MISC_LODIS       0x1000  /*12 1888/1980/1981 /1985 */
 1523 #define         AD1980_MISC_MSPLT       0x2000  /*13 1888/1980/1981 /1985 */
 1524 #define         AD1980_MISC_AC97NC      0x4000  /*14 1888/1980      /1985 */
 1525 #define         AD1980_MISC_DACZ        0x8000  /*15 1888/1980/1981 /1985 */
 1526 #define AD1981_REG_MISC 0x76
 1527 #define         AD1981_MISC_MADST       0x0010  /* 4 */
 1528 #define         AD1981A_MISC_MADPD      0x0040  /* 6 */
 1529 #define         AD1981B_MISC_MADPD      0x0080  /* 7 */
 1530 #define         AD1981_MISC_FMXE        0x0200  /* 9 */
 1531 #define         AD1981_MISC_DAM         0x0800  /*11 */
 1532 static void
 1533 ac97_ad198x_init(struct ac97_softc *as)
 1534 {
 1535         int i;
 1536         uint16_t misc;
 1537 
 1538         ac97_read(as, AD1980_REG_MISC, &misc);
 1539         ac97_write(as, AD1980_REG_MISC,
 1540                    misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
 1541 
 1542         for (i = 0; i < as->num_source_info; i++) {
 1543                 if (as->source_info[i].type != AUDIO_MIXER_VALUE)
 1544                         continue;
 1545 
 1546                 if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
 1547                         as->source_info[i].reg = AC97_REG_SURR_MASTER;
 1548                 else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
 1549                         as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
 1550         }
 1551 }
 1552 
 1553 #define ALC650_REG_MULTI_CHANNEL_CONTROL        0x6a
 1554 #define         ALC650_MCC_SLOT_MODIFY_MASK             0xc000
 1555 #define         ALC650_MCC_FRONTDAC_FROM_SPDIFIN        0x2000 /* 13 */
 1556 #define         ALC650_MCC_SPDIFOUT_FROM_ADC            0x1000 /* 12 */
 1557 #define         ALC650_MCC_PCM_FROM_SPDIFIN             0x0800 /* 11 */
 1558 #define         ALC650_MCC_MIC_OR_CENTERLFE             0x0400 /* 10 */
 1559 #define         ALC650_MCC_LINEIN_OR_SURROUND           0x0200 /* 9 */
 1560 #define         ALC650_MCC_INDEPENDENT_MASTER_L         0x0080 /* 7 */
 1561 #define         ALC650_MCC_INDEPENDENT_MASTER_R         0x0040 /* 6 */
 1562 #define         ALC650_MCC_ANALOG_TO_CENTERLFE          0x0020 /* 5 */
 1563 #define         ALC650_MCC_ANALOG_TO_SURROUND           0x0010 /* 4 */
 1564 #define         ALC650_MCC_EXCHANGE_CENTERLFE           0x0008 /* 3 */
 1565 #define         ALC650_MCC_CENTERLFE_DOWNMIX            0x0004 /* 2 */
 1566 #define         ALC650_MCC_SURROUND_DOWNMIX             0x0002 /* 1 */
 1567 #define         ALC650_MCC_LINEOUT_TO_SURROUND          0x0001 /* 0 */
 1568 static void
 1569 ac97_alc650_init(struct ac97_softc *as)
 1570 {
 1571         static const struct ac97_source_info sources[6] = {
 1572                 { AudioCoutputs, AudioNsurround, "lineinjack",
 1573                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1574                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 1575                   0x0000, 1, 9, 0, 0, CHECK_SURROUND },
 1576                 { AudioCoutputs, AudioNsurround, "mixtofront",
 1577                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1578                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 1579                   0x0000, 1, 1, 0, 0, CHECK_SURROUND },
 1580                 { AudioCoutputs, AudioNcenter, "micjack",
 1581                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1582                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 1583                   0x0000, 1, 10, 0, 0, CHECK_CENTER },
 1584                 { AudioCoutputs, AudioNlfe, "micjack",
 1585                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1586                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 1587                   0x0000, 1, 10, 0, 0, CHECK_LFE },
 1588                 { AudioCoutputs, AudioNcenter, "mixtofront",
 1589                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1590                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 1591                   0x0000, 1, 2, 0, 0, CHECK_CENTER },
 1592                 { AudioCoutputs, AudioNlfe, "mixtofront",
 1593                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1594                   ALC650_REG_MULTI_CHANNEL_CONTROL,
 1595                   0x0000, 1, 2, 0, 0, CHECK_LFE },
 1596         };
 1597 
 1598         ac97_add_port(as, &sources[0]);
 1599         ac97_add_port(as, &sources[1]);
 1600         ac97_add_port(as, &sources[2]);
 1601         ac97_add_port(as, &sources[3]);
 1602         ac97_add_port(as, &sources[4]);
 1603         ac97_add_port(as, &sources[5]);
 1604 }
 1605 
 1606 #define VT1616_REG_IO_CONTROL   0x5a
 1607 #define         VT1616_IC_LVL                   (1 << 15)
 1608 #define         VT1616_IC_LFECENTER_TO_FRONT    (1 << 12)
 1609 #define         VT1616_IC_SURROUND_TO_FRONT     (1 << 11)
 1610 #define         VT1616_IC_BPDC                  (1 << 10)
 1611 #define         VT1616_IC_DC                    (1 << 9)
 1612 #define         VT1616_IC_IB_MASK               0x000c
 1613 static void
 1614 ac97_vt1616_init(struct ac97_softc *as)
 1615 {
 1616         static const struct ac97_source_info sources[3] = {
 1617                 { AudioCoutputs, AudioNsurround, "mixtofront",
 1618                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1619                   VT1616_REG_IO_CONTROL,
 1620                   0x0000, 1, 11, 0, 0, CHECK_SURROUND },
 1621                 { AudioCoutputs, AudioNcenter, "mixtofront",
 1622                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1623                   VT1616_REG_IO_CONTROL,
 1624                   0x0000, 1, 12, 0, 0, CHECK_CENTER },
 1625                 { AudioCoutputs, AudioNlfe, "mixtofront",
 1626                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1627                   VT1616_REG_IO_CONTROL,
 1628                   0x0000, 1, 12, 0, 0, CHECK_LFE },
 1629         };
 1630 
 1631         ac97_add_port(as, &sources[0]);
 1632         ac97_add_port(as, &sources[1]);
 1633         ac97_add_port(as, &sources[2]);
 1634 }

Cache object: d2b308769d776c7d74a2365ea412a0a6


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