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

Cache object: 631f0cf0229628286b61e844a90add89


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