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 /*      $OpenBSD: ac97.c,v 1.84 2018/04/11 04:48:31 ratchov Exp $       */
    2 
    3 /*
    4  * Copyright (c) 1999, 2000 Constantine Sapuntzakis
    5  *
    6  * Author:      Constantine Sapuntzakis <csapuntz@stanford.edu>
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. The name of the author may not be used to endorse or promote
   17  *    products derived from this software without specific prior written
   18  *    permission.
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
   20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
   23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
   25  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
   29  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
   30  * DAMAGE.  */
   31 
   32 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
   33    the following copyright */
   34 
   35 /*
   36  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
   37  * All rights reserved.
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   58  * SUCH DAMAGE.
   59  *
   60  * $FreeBSD$
   61  */
   62 
   63 #include <sys/param.h>
   64 #include <sys/systm.h>
   65 #include <sys/kernel.h>
   66 #include <sys/malloc.h>
   67 
   68 #include <sys/audioio.h>
   69 #include <dev/audio_if.h>
   70 #include <dev/ic/ac97.h>
   71 
   72 
   73 /* default parameters; supported by all ac97 codecs */
   74 const struct audio_params ac97_audio_default = {
   75         48000,          /* sample_rate */
   76         AUDIO_ENCODING_SLINEAR_LE, /* encoding */
   77         16,             /* precision */
   78         2,              /* bps */
   79         1,              /* msb */
   80         2               /* channels */
   81 };
   82 
   83 const struct audio_mixer_enum ac97_on_off = {
   84         2,
   85         { { { AudioNoff } , 0 },
   86         { { AudioNon }  , 1 } }
   87 };
   88 
   89 const struct audio_mixer_enum ac97_mic_select = {
   90         2,
   91         { { { AudioNmicrophone "" }, 0 },
   92         { { AudioNmicrophone "1" }, 1 } }
   93 };
   94 
   95 const struct audio_mixer_enum ac97_mono_select = {
   96         2,
   97         { { { AudioNmixerout }, 0 },
   98         { { AudioNmicrophone }, 1 } }
   99 };
  100 
  101 const struct audio_mixer_enum ac97_source = {
  102         8,
  103         { { { AudioNmicrophone } , 0 },
  104         { { AudioNcd }, 1 },
  105         { { "video" }, 2 },
  106         { { AudioNaux }, 3 },
  107         { { AudioNline }, 4 },
  108         { { AudioNmixerout }, 5 },
  109         { { AudioNmixerout AudioNmono }, 6 },
  110         { { "phone" }, 7 }}
  111 };
  112 
  113 /*
  114  * Due to different values for each source that uses these structures,
  115  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
  116  * ac97_source_info.bits.
  117  */
  118 const struct audio_mixer_value ac97_volume_stereo = {
  119         { AudioNvolume },
  120         2
  121 };
  122 
  123 const struct audio_mixer_value ac97_volume_mono = {
  124         { AudioNvolume },
  125         1
  126 };
  127 
  128 #define AudioNspdif     "spdif"
  129 
  130 #define WRAP(a)  &a, sizeof(a)
  131 
  132 const struct ac97_source_info {
  133         char *class;
  134         char *device;
  135         char *qualifier;
  136         int  type;
  137 
  138         const void *info;
  139         int16_t info_size;
  140 
  141         u_int8_t  reg;
  142         u_int16_t default_value;
  143         u_int8_t  bits:3;
  144         u_int8_t  ofs:4;
  145         u_int8_t  mute:1;
  146         u_int8_t  polarity:1;           /* Does 0 == MAX or MIN */
  147         enum {
  148                 CHECK_NONE = 0,
  149                 CHECK_SURROUND,
  150                 CHECK_CENTER,
  151                 CHECK_LFE,
  152                 CHECK_HEADPHONES,
  153                 CHECK_TONE,
  154                 CHECK_MIC,
  155                 CHECK_LOUDNESS,
  156                 CHECK_3D,
  157                 CHECK_SPDIF
  158         } req_feature;
  159 
  160         int16_t  prev;
  161         int16_t  next;
  162         int16_t  mixer_class;
  163 } source_info[] = {
  164         { AudioCinputs,         NULL,           NULL,
  165           AUDIO_MIXER_CLASS, },
  166         { AudioCoutputs,        NULL,           NULL,
  167           AUDIO_MIXER_CLASS, },
  168         { AudioCrecord,         NULL,           NULL,
  169           AUDIO_MIXER_CLASS, },
  170         /* Stereo master volume*/
  171         { AudioCoutputs,        AudioNmaster,   NULL,
  172           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  173           AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1,
  174         },
  175         /* Mono volume */
  176         { AudioCoutputs,        AudioNmono,     NULL,
  177           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  178           AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1,
  179         },
  180         { AudioCoutputs,        AudioNmono,     AudioNsource,
  181           AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
  182           AC97_REG_GP, 0x0000, 1, 9, 0,
  183         },
  184         /* Headphone volume */
  185         { AudioCoutputs,        AudioNheadphone, NULL,
  186           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  187           AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1, 0, CHECK_HEADPHONES
  188         },
  189         /* Surround volume - logic hard coded for mute */
  190         { AudioCoutputs,        AudioNsurround, NULL,
  191           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  192           AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, CHECK_SURROUND
  193         },
  194         /* Center volume*/
  195         { AudioCoutputs,        AudioNcenter,   NULL,
  196           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  197           AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, CHECK_CENTER
  198         },
  199         { AudioCoutputs,        AudioNcenter,   AudioNmute,
  200           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  201           AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, CHECK_CENTER
  202         },
  203         /* LFE volume*/
  204         { AudioCoutputs,        AudioNlfe,      NULL,
  205           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  206           AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, CHECK_LFE
  207         },
  208         { AudioCoutputs,        AudioNlfe,      AudioNmute,
  209           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  210           AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, CHECK_LFE
  211         },
  212         /* Tone */
  213         { AudioCoutputs,        "tone", NULL,
  214           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  215           AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, CHECK_TONE
  216         },
  217         /* PC Beep Volume */
  218         { AudioCinputs,         AudioNspeaker,  NULL,
  219           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  220           AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1,
  221         },
  222 
  223         /* Phone */
  224         { AudioCinputs,         "phone",        NULL,
  225           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  226           AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1,
  227         },
  228         /* Mic Volume */
  229         { AudioCinputs,         AudioNmicrophone, NULL,
  230           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  231           AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1,
  232         },
  233         { AudioCinputs,         AudioNmicrophone, AudioNpreamp,
  234           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  235           AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0,
  236         },
  237         { AudioCinputs,         AudioNmicrophone, AudioNsource,
  238           AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
  239           AC97_REG_GP, 0x0000, 1, 8, 0,
  240         },
  241         /* Line in Volume */
  242         { AudioCinputs,         AudioNline,     NULL,
  243           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  244           AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1,
  245         },
  246         /* CD Volume */
  247         { AudioCinputs,         AudioNcd,       NULL,
  248           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  249           AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1,
  250         },
  251         /* Video Volume */
  252         { AudioCinputs,         AudioNvideo,    NULL,
  253           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  254           AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1,
  255         },
  256         /* AUX volume */
  257         { AudioCinputs,         AudioNaux,      NULL,
  258           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  259           AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1,
  260         },
  261         /* PCM out volume */
  262         { AudioCinputs,         AudioNdac,      NULL,
  263           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  264           AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1,
  265         },
  266         /* Record Source - some logic for this is hard coded - see below */
  267         { AudioCrecord,         AudioNsource,   NULL,
  268           AUDIO_MIXER_ENUM, WRAP(ac97_source),
  269           AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0,
  270         },
  271         /* Record Gain */
  272         { AudioCrecord,         AudioNvolume,   NULL,
  273           AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
  274           AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1,
  275         },
  276         /* Record Gain mic */
  277         { AudioCrecord,         AudioNmicrophone, NULL,
  278           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  279           AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, CHECK_MIC
  280         },
  281         /* */
  282         { AudioCoutputs,        AudioNloudness, NULL,
  283           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  284           AC97_REG_GP, 0x0000, 1, 12, 0, 0, CHECK_LOUDNESS
  285         },
  286         { AudioCoutputs,        AudioNspatial,  NULL,
  287           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  288           AC97_REG_GP, 0x0000, 1, 13, 0, 1, CHECK_3D
  289         },
  290         { AudioCoutputs,        AudioNspatial,  "center",
  291           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  292           AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, CHECK_3D
  293         },
  294         { AudioCoutputs,        AudioNspatial,  "depth",
  295           AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
  296           AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, CHECK_3D
  297         },
  298         /* External Amp */
  299         { AudioCoutputs,        AudioNextamp,   NULL,
  300           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  301           AC97_REG_POWER, 0x0000, 1, 15, 0, 0
  302         },
  303         /* S/PDIF output enable */
  304         { AudioCoutputs,        AudioNspdif,    NULL,
  305           AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
  306           AC97_REG_EXT_AUDIO_CTRL, 0x0000, 1, 2, 0, 0, CHECK_SPDIF
  307         }
  308 
  309         /* Missing features: Simulated Stereo, POP, Loopback mode */
  310 };
  311 
  312 /*
  313  * Check out http://www.intel.com/technology/computing/audio/index.htm
  314  * for 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         struct ac97_host_if *host_if;
  321 #define MAX_SOURCES     (2 * nitems(source_info))
  322         struct ac97_source_info source_info[MAX_SOURCES];
  323         int num_source_info;
  324         enum ac97_host_flags host_flags;
  325         unsigned int ac97_clock; /* usually 48000 */
  326 #define AC97_STANDARD_CLOCK     48000U
  327         u_int16_t caps;         /* -> AC97_REG_RESET */
  328         u_int16_t ext_id;       /* -> AC97_REG_EXT_AUDIO_ID */
  329         u_int16_t shadow_reg[128];
  330         int lock_counter;
  331 };
  332 
  333 int     ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
  334 int     ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
  335 void    ac97_lock(struct ac97_codec_if *);
  336 void    ac97_unlock(struct ac97_codec_if *);
  337 int     ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
  338 int     ac97_get_portnum_by_name(struct ac97_codec_if *, char *, char *,
  339             char *);
  340 int     ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate);
  341 void    ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock);
  342 u_int16_t ac97_get_extcaps(struct ac97_codec_if *codec_if);
  343 int     ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src);
  344 
  345 void    ac97_ad1885_init(struct ac97_softc *, int);
  346 void    ac97_ad1886_init(struct ac97_softc *, int);
  347 void    ac97_ad198x_init(struct ac97_softc *, int);
  348 void    ac97_alc650_init(struct ac97_softc *, int);
  349 void    ac97_cx20468_init(struct ac97_softc *, int);
  350 void    ac97_vt1616_init(struct ac97_softc *, int);
  351 
  352 struct ac97_codec_if_vtbl ac97civ = {
  353         ac97_mixer_get_port,
  354         ac97_mixer_set_port,
  355         ac97_query_devinfo,
  356         ac97_get_portnum_by_name,
  357         ac97_get_extcaps,
  358         ac97_set_rate,
  359         ac97_set_clock,
  360         ac97_lock,
  361         ac97_unlock
  362 };
  363 
  364 const struct ac97_codecid {
  365         u_int8_t id;
  366         u_int8_t mask;
  367         u_int8_t rev;
  368         u_int8_t shift; /* no use yet */
  369         char * const name;
  370         void (*init)(struct ac97_softc *, int);
  371 }  ac97_ad[] = {
  372         { 0x03, 0xff, 0, 0,     "AD1819" },
  373         { 0x40, 0xff, 0, 0,     "AD1881" },
  374         { 0x48, 0xff, 0, 0,     "AD1881A" },
  375         { 0x60, 0xff, 0, 0,     "AD1885",       ac97_ad1885_init },
  376         { 0x61, 0xff, 0, 0,     "AD1886",       ac97_ad1886_init },
  377         { 0x63, 0xff, 0, 0,     "AD1886A" },
  378         { 0x68, 0xff, 0, 0,     "AD1888",       ac97_ad198x_init },
  379         { 0x70, 0xff, 0, 0,     "AD1980",       ac97_ad198x_init },
  380         { 0x72, 0xff, 0, 0,     "AD1981A" },
  381         { 0x74, 0xff, 0, 0,     "AD1981B" },
  382         { 0x75, 0xff, 0, 0,     "AD1985",       ac97_ad198x_init },
  383 }, ac97_ak[] = {
  384         { 0x00, 0xfe, 1, 0,     "AK4540" },
  385         { 0x01, 0xfe, 1, 0,     "AK4540" },
  386         { 0x02, 0xff, 0, 0,     "AK4543" },
  387         { 0x05, 0xff, 0, 0,     "AK4544" },
  388         { 0x06, 0xff, 0, 0,     "AK4544A" },
  389         { 0x07, 0xff, 0, 0,     "AK4545" },
  390 }, ac97_av[] = {
  391         { 0x10, 0xff, 0, 0,     "ALC200" },
  392         { 0x20, 0xff, 0, 0,     "ALC650" },
  393         { 0x21, 0xff, 0, 0,     "ALC650D" },
  394         { 0x22, 0xff, 0, 0,     "ALC650E" },
  395         { 0x23, 0xff, 0, 0,     "ALC650F" },
  396         { 0x30, 0xff, 0, 0,     "ALC101" },
  397         { 0x40, 0xff, 0, 0,     "ALC202" },
  398         { 0x50, 0xff, 0, 0,     "ALC250" },
  399         { 0x52, 0xff, 0, 0,     "ALC250A?" },
  400         { 0x60, 0xf0, 0xf, 0,   "ALC655",       ac97_alc650_init },
  401         { 0x70, 0xf0, 0xf, 0,   "ALC203" },
  402         { 0x80, 0xf0, 0xf, 0,   "ALC658",       ac97_alc650_init },
  403         { 0x90, 0xf0, 0xf, 0,   "ALC850" },
  404 }, ac97_rl[] = {
  405         { 0x00, 0xf0, 0xf, 0,   "RL5306" },
  406         { 0x10, 0xf0, 0xf, 0,   "RL5382" },
  407         { 0x20, 0xf0, 0xf, 0,   "RL5383" },
  408 }, ac97_cm[] = {
  409         { 0x41, 0xff, 0, 0,     "CMI9738" },
  410         { 0x61, 0xff, 0, 0,     "CMI9739" },
  411         { 0x78, 0xff, 0, 0,     "CMI9761A" },
  412         { 0x82, 0xff, 0, 0,     "CMI9761B" },
  413         { 0x83, 0xff, 0, 0,     "CMI9761A+" },
  414 }, ac97_cr[] = {
  415         { 0x84, 0xff, 0, 0,     "EV1938" },
  416 }, ac97_cs[] = {
  417         { 0x00, 0xf8, 7, 0,     "CS4297" },
  418         { 0x10, 0xf8, 7, 0,     "CS4297A" },
  419         { 0x20, 0xf8, 7, 0,     "CS4298" },
  420         { 0x28, 0xf8, 7, 0,     "CS4294" },
  421         { 0x30, 0xf8, 7, 0,     "CS4299" },
  422         { 0x48, 0xf8, 7, 0,     "CS4201" },
  423         { 0x58, 0xf8, 7, 0,     "CS4205" },
  424         { 0x60, 0xf8, 7, 0,     "CS4291" },
  425         { 0x70, 0xf8, 7, 0,     "CS4202" },
  426 }, ac97_cx[] = {
  427         { 0x21, 0xff, 0, 0,     "HSD11246" },
  428         { 0x28, 0xf8, 7, 0,     "CX20468",      ac97_cx20468_init },
  429         { 0x30, 0xff, 0, 0,     "CXT48", },
  430         { 0x42, 0xff, 0, 0,     "CXT66", },
  431 }, ac97_dt[] = {
  432         { 0x00, 0xff, 0, 0,     "DT0398" },
  433 }, ac97_em[] = {
  434         { 0x23, 0xff, 0, 0,     "EM28023" },
  435         { 0x28, 0xff, 0, 0,     "EM28028" },
  436 }, ac97_es[] = {
  437         { 0x08, 0xff, 0, 0,     "ES1921" },
  438 }, ac97_is[] = {
  439         { 0x00, 0xff, 0, 0,     "HMP9701" },
  440 }, ac97_ic[] = {
  441         { 0x01, 0xff, 0, 0,     "ICE1230" },
  442         { 0x11, 0xff, 0, 0,     "ICE1232" },
  443         { 0x14, 0xff, 0, 0,     "ICE1232A" },
  444         { 0x51, 0xff, 0, 0,     "VIA VT1616" },
  445         { 0x52, 0xff, 0, 0,     "VIA VT1616i",  ac97_vt1616_init },
  446 }, ac97_it[] = {
  447         { 0x20, 0xff, 0, 0,     "ITE2226E" },
  448         { 0x60, 0xff, 0, 0,     "ITE2646E" },
  449 }, ac97_ns[] = {
  450         { 0x00, 0xff, 0, 0,     "LM454[03568]" },
  451         { 0x31, 0xff, 0, 0,     "LM4549" },
  452         { 0x40, 0xff, 0, 0,     "LM4540" },
  453         { 0x43, 0xff, 0, 0,     "LM4543" },
  454         { 0x46, 0xff, 0, 0,     "LM4546A" },
  455         { 0x48, 0xff, 0, 0,     "LM4548A" },
  456         { 0x49, 0xff, 0, 0,     "LM4549A" },
  457         { 0x50, 0xff, 0, 0,     "LM4550" },
  458 }, ac97_ps[] = {
  459         { 0x01, 0xff, 0, 0,     "UCB1510" },
  460         { 0x04, 0xff, 0, 0,     "UCB1400" },
  461 }, ac97_sl[] = {
  462         { 0x20, 0xe0, 0, 0,     "Si3036/38" },
  463 }, ac97_st[] = {
  464         { 0x00, 0xff, 0, 0,     "STAC9700" },
  465         { 0x04, 0xff, 0, 0,     "STAC970[135]" },
  466         { 0x05, 0xff, 0, 0,     "STAC9704" },
  467         { 0x08, 0xff, 0, 0,     "STAC9708/11" },
  468         { 0x09, 0xff, 0, 0,     "STAC9721/23" },
  469         { 0x44, 0xff, 0, 0,     "STAC9744/45" },
  470         { 0x50, 0xff, 0, 0,     "STAC9750/51" },
  471         { 0x52, 0xff, 0, 0,     "STAC9752/53" },
  472         { 0x56, 0xff, 0, 0,     "STAC9756/57" },
  473         { 0x58, 0xff, 0, 0,     "STAC9758/59" },
  474         { 0x60, 0xff, 0, 0,     "STAC9760/61" },
  475         { 0x62, 0xff, 0, 0,     "STAC9762/63" },
  476         { 0x66, 0xff, 0, 0,     "STAC9766/67" },
  477         { 0x84, 0xff, 0, 0,     "STAC9784/85" },
  478 }, ac97_vi[] = {
  479         { 0x61, 0xff, 0, 0,     "VT1612A" },
  480         { 0x70, 0xff, 0, 0,     "VT1617" },
  481 }, ac97_tt[] = {
  482         { 0x02, 0xff, 0, 0,     "TR28022" },
  483         { 0x03, 0xff, 0, 0,     "TR28023" },
  484         { 0x06, 0xff, 0, 0,     "TR28026" },
  485         { 0x08, 0xff, 0, 0,     "TR28028" },
  486         { 0x23, 0xff, 0, 0,     "TR28602" },
  487 }, ac97_ti[] = {
  488         { 0x20, 0xff, 0, 0,     "TLC320AD9xC" },
  489 }, ac97_wb[] = {
  490         { 0x01, 0xff, 0, 0,     "W83971D" },
  491 }, ac97_wo[] = {
  492         { 0x00, 0xff, 0, 0,     "WM9701A" },
  493         { 0x03, 0xff, 0, 0,     "WM9704M/Q-0" }, /* & WM9703 */
  494         { 0x04, 0xff, 0, 0,     "WM9704M/Q-1" },
  495         { 0x05, 0xff, 0, 0,     "WM9705/10" },
  496         { 0x09, 0xff, 0, 0,     "WM9709" },
  497         { 0x12, 0xff, 0, 0,     "WM9711/12" },
  498 }, ac97_ym[] = {
  499         { 0x00, 0xff, 0, 0,     "YMF743-S" },
  500         { 0x02, 0xff, 0, 0,     "YMF752-S" },
  501         { 0x03, 0xff, 0, 0,     "YMF753-S" },
  502 };
  503 
  504 #define cl(n)   n, nitems(n)
  505 const struct ac97_vendorid {
  506         u_int32_t id;
  507         char * const name;
  508         const struct ac97_codecid * const codecs;
  509         u_int8_t num;
  510 } ac97_vendors[] = {
  511         { 0x01408300, "Creative",               cl(ac97_cr) },
  512         { 0x41445300, "Analog Devices",         cl(ac97_ad) },
  513         { 0x414b4D00, "Asahi Kasei",            cl(ac97_ak) },
  514         { 0x414c4300, "Realtek",                cl(ac97_rl) },
  515         { 0x414c4700, "Avance Logic",           cl(ac97_av) },
  516         { 0x434d4900, "C-Media Electronics",    cl(ac97_cm) },
  517         { 0x43525900, "Cirrus Logic",           cl(ac97_cs) },
  518         { 0x43585400, "Conexant",               cl(ac97_cx) },
  519         { 0x44543000, "Diamond Technology",     cl(ac97_dt) },
  520         { 0x454d4300, "eMicro",                 cl(ac97_em) },
  521         { 0x45838300, "ESS Technology",         cl(ac97_es) },
  522         { 0x48525300, "Intersil",               cl(ac97_is) },
  523         { 0x49434500, "ICEnsemble",             cl(ac97_ic) },
  524         { 0x49544500, "ITE, Inc.",              cl(ac97_it) },
  525         { 0x4e534300, "National Semiconductor", cl(ac97_ns) },
  526         { 0x50534300, "Philips Semiconductor",  cl(ac97_ps) },
  527         { 0x53494c00, "Silicon Laboratory",     cl(ac97_sl) },
  528         { 0x54524100, "TriTech Microelectronics", cl(ac97_tt) },
  529         { 0x54584e00, "Texas Instruments",      cl(ac97_ti) },
  530         { 0x56494100, "VIA Technologies",       cl(ac97_vi) },
  531         { 0x57454300, "Winbond",                cl(ac97_wb) },
  532         { 0x574d4c00, "Wolfson",                cl(ac97_wo) },
  533         { 0x594d4800, "Yamaha",                 cl(ac97_ym) },
  534         { 0x83847600, "SigmaTel",               cl(ac97_st) },
  535 };
  536 #undef cl
  537 
  538 const char * const ac97enhancement[] = {
  539         "No 3D Stereo",
  540         "Analog Devices Phat Stereo",
  541         "Creative",
  542         "National Semi 3D",
  543         "Yamaha Ymersion",
  544         "BBE 3D",
  545         "Crystal Semi 3D",
  546         "Qsound QXpander",
  547         "Spatializer 3D",
  548         "SRS 3D",
  549         "Platform Tech 3D",
  550         "AKM 3D",
  551         "Aureal",
  552         "AZTECH 3D",
  553         "Binaura 3D",
  554         "ESS Technology",
  555         "Harman International VMAx",
  556         "Nvidea 3D",
  557         "Philips Incredible Sound",
  558         "Texas Instruments 3D",
  559         "VLSI Technology 3D",
  560         "TriTech 3D",
  561         "Realtek 3D",
  562         "Samsung 3D",
  563         "Wolfson Microelectronics 3D",
  564         "Delta Integration 3D",
  565         "SigmaTel 3D",
  566         "KS Waves 3D",
  567         "Rockwell 3D",
  568         "Unknown 3D",
  569         "Unknown 3D",
  570         "Unknown 3D"
  571 };
  572 
  573 const char * const ac97feature[] = {
  574         "mic channel",
  575         "reserved",
  576         "tone",
  577         "simulated stereo",
  578         "headphone",
  579         "bass boost",
  580         "18 bit DAC",
  581         "20 bit DAC",
  582         "18 bit ADC",
  583         "20 bit ADC"
  584 };
  585 
  586 
  587 int     ac97_str_equal(const char *, const char *);
  588 int     ac97_check_capability(struct ac97_softc *, int);
  589 void    ac97_setup_source_info(struct ac97_softc *);
  590 void    ac97_setup_defaults(struct ac97_softc *);
  591 int     ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *);
  592 int     ac97_write(struct ac97_softc *, u_int8_t, u_int16_t);
  593 
  594 
  595 #ifdef AUDIO_DEBUG
  596 #define DPRINTF(x)      if (ac97debug) printf x
  597 #define DPRINTFN(n,x)   if (ac97debug>(n)) printf x
  598 #ifdef AC97_DEBUG
  599 int     ac97debug = 1;
  600 #else
  601 int     ac97debug = 0;
  602 #endif
  603 #else
  604 #define DPRINTF(x)
  605 #define DPRINTFN(n,x)
  606 #endif
  607 
  608 int
  609 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
  610 {
  611         int error;
  612 
  613         if (((as->host_flags & AC97_HOST_DONT_READ) &&
  614             (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
  615             reg != AC97_REG_RESET)) ||
  616             (as->host_flags & AC97_HOST_DONT_READANY)) {
  617                 *val = as->shadow_reg[reg >> 1];
  618                 return (0);
  619         }
  620 
  621         if ((error = as->host_if->read(as->host_if->arg, reg, val)))
  622                 *val = as->shadow_reg[reg >> 1];
  623         return (error);
  624 }
  625 
  626 int
  627 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
  628 {
  629         as->shadow_reg[reg >> 1] = val;
  630         return (as->host_if->write(as->host_if->arg, reg, val));
  631 }
  632 
  633 void
  634 ac97_setup_defaults(struct ac97_softc *as)
  635 {
  636         int idx;
  637 
  638         bzero(as->shadow_reg, sizeof(as->shadow_reg));
  639 
  640         for (idx = 0; idx < nitems(source_info); idx++) {
  641                 const struct ac97_source_info *si = &source_info[idx];
  642 
  643                 ac97_write(as, si->reg, si->default_value);
  644         }
  645 }
  646 
  647 int
  648 ac97_str_equal(const char *a, const char *b)
  649 {
  650         return ((a == b) || (a && b && (!strcmp(a, b))));
  651 }
  652 
  653 int
  654 ac97_check_capability(struct ac97_softc *as, int check)
  655 {
  656         switch (check) {
  657         case CHECK_NONE:
  658                 return 1;
  659         case CHECK_SURROUND:
  660                 return as->ext_id & AC97_EXT_AUDIO_SDAC;
  661         case CHECK_CENTER:
  662                 return as->ext_id & AC97_EXT_AUDIO_CDAC;
  663         case CHECK_LFE:
  664                 return as->ext_id & AC97_EXT_AUDIO_LDAC;
  665         case CHECK_SPDIF:
  666                 return as->ext_id & AC97_EXT_AUDIO_SPDIF;
  667         case CHECK_HEADPHONES:
  668                 return as->caps & AC97_CAPS_HEADPHONES;
  669         case CHECK_TONE:
  670                 return as->caps & AC97_CAPS_TONECTRL;
  671         case CHECK_MIC:
  672                 return as->caps & AC97_CAPS_MICIN;
  673         case CHECK_LOUDNESS:
  674                 return as->caps & AC97_CAPS_LOUDNESS;
  675         case CHECK_3D:
  676                 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
  677         default:
  678                 printf("%s: internal error: feature=%d\n", __func__, check);
  679                 return 0;
  680         }
  681 }
  682 
  683 void
  684 ac97_setup_source_info(struct ac97_softc *as)
  685 {
  686         struct ac97_source_info *si, *si2;
  687         int idx, ouridx;
  688 
  689         for (idx = 0, ouridx = 0; idx < nitems(source_info); idx++) {
  690                 si = &as->source_info[ouridx];
  691 
  692                 if (!ac97_check_capability(as, source_info[idx].req_feature))
  693                         continue;
  694 
  695                 bcopy(&source_info[idx], si, sizeof(*si));
  696 
  697                 switch (si->type) {
  698                 case AUDIO_MIXER_CLASS:
  699                         si->mixer_class = ouridx;
  700                         ouridx++;
  701                         break;
  702                 case AUDIO_MIXER_VALUE:
  703                         /* Todo - Test to see if it works */
  704                         ouridx++;
  705 
  706                         /* Add an entry for mute, if necessary */
  707                         if (si->mute) {
  708                                 si = &as->source_info[ouridx];
  709                                 bcopy(&source_info[idx], si, sizeof(*si));
  710                                 si->qualifier = AudioNmute;
  711                                 si->type = AUDIO_MIXER_ENUM;
  712                                 si->info = &ac97_on_off;
  713                                 si->info_size = sizeof(ac97_on_off);
  714                                 si->bits = 1;
  715                                 si->ofs = 15;
  716                                 si->mute = 0;
  717                                 si->polarity = 0;
  718                                 ouridx++;
  719                         }
  720                         break;
  721                 case AUDIO_MIXER_ENUM:
  722                         /* Todo - Test to see if it works */
  723                         ouridx++;
  724                         break;
  725                 default:
  726                         printf ("ac97: shouldn't get here\n");
  727                         break;
  728                 }
  729         }
  730 
  731         as->num_source_info = ouridx;
  732 
  733         for (idx = 0; idx < as->num_source_info; idx++) {
  734                 int idx2, previdx;
  735 
  736                 si = &as->source_info[idx];
  737 
  738                 /* Find mixer class */
  739                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
  740                         si2 = &as->source_info[idx2];
  741 
  742                         if (si2->type == AUDIO_MIXER_CLASS &&
  743                             ac97_str_equal(si->class, si2->class)) {
  744                                 si->mixer_class = idx2;
  745                         }
  746                 }
  747 
  748 
  749                 /* Setup prev and next pointers */
  750                 if (si->prev != 0 || si->qualifier)
  751                         continue;
  752 
  753                 si->prev = AUDIO_MIXER_LAST;
  754                 previdx = idx;
  755 
  756                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
  757                         if (idx2 == idx)
  758                                 continue;
  759 
  760                         si2 = &as->source_info[idx2];
  761 
  762                         if (!si2->prev &&
  763                             ac97_str_equal(si->class, si2->class) &&
  764                             ac97_str_equal(si->device, si2->device)) {
  765                                 as->source_info[previdx].next = idx2;
  766                                 as->source_info[idx2].prev = previdx;
  767 
  768                                 previdx = idx2;
  769                         }
  770                 }
  771 
  772                 as->source_info[previdx].next = AUDIO_MIXER_LAST;
  773         }
  774 }
  775 
  776 int
  777 ac97_attach(struct ac97_host_if *host_if)
  778 {
  779         struct ac97_softc *as;
  780         u_int16_t id1, id2, val;
  781         u_int32_t id;
  782         u_int16_t extstat, rate;
  783         mixer_ctrl_t ctl;
  784         int error, i;
  785         void (*initfunc)(struct ac97_softc *, int);
  786 
  787         initfunc = NULL;
  788 
  789         if (!(as = malloc(sizeof(*as), M_DEVBUF, M_NOWAIT | M_ZERO)))
  790                 return (ENOMEM);
  791 
  792         as->codec_if.as = as;
  793         as->codec_if.vtbl = &ac97civ;
  794         as->host_if = host_if;
  795 
  796         if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
  797                 free(as, M_DEVBUF, sizeof(*as));
  798                 return (error);
  799         }
  800 
  801         host_if->reset(host_if->arg);
  802         DELAY(1000);
  803 
  804         host_if->write(host_if->arg, AC97_REG_POWER, 0);
  805         host_if->write(host_if->arg, AC97_REG_RESET, 0);
  806         DELAY(10000);
  807 
  808         if (host_if->flags)
  809                 as->host_flags = host_if->flags(host_if->arg);
  810 
  811         ac97_setup_defaults(as);
  812         ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
  813         ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
  814         ac97_read(as, AC97_REG_RESET, &as->caps);
  815 
  816         id = (id1 << 16) | id2;
  817         if (id) {
  818                 register const struct ac97_vendorid *vendor;
  819                 register const struct ac97_codecid *codec;
  820 
  821                 printf("ac97: codec id 0x%08x", id);
  822                 for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
  823                      sizeof(ac97_vendors[0]) - 1];
  824                      vendor >= ac97_vendors; vendor--) {
  825                         if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
  826                                 printf(" (%s", vendor->name);
  827                                 for (codec = &vendor->codecs[vendor->num-1];
  828                                      codec >= vendor->codecs; codec--) {
  829                                         if (codec->id == (id & codec->mask))
  830                                                 break;
  831                                 }
  832                                 if (codec >= vendor->codecs && codec->mask) {
  833                                         printf(" %s", codec->name);
  834                                         initfunc = codec->init;
  835                                 } else
  836                                         printf(" <%02x>", id & 0xff);
  837                                 if (codec >= vendor->codecs && codec->rev)
  838                                         printf(" rev %d", id & codec->rev);
  839                                 printf(")");
  840                                 break;
  841                         }
  842                 }
  843                 printf("\n");
  844         } else
  845                 printf("ac97: codec id not read\n");
  846 
  847         if (as->caps) {
  848                 printf("ac97: codec features ");
  849                 for (i = 0; i < 10; i++) {
  850                         if (as->caps & (1 << i))
  851                                 printf("%s, ", ac97feature[i]);
  852                 }
  853                 printf("%s\n",
  854                     ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
  855         }
  856 
  857 
  858         as->ac97_clock = AC97_STANDARD_CLOCK;
  859         ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
  860         if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
  861                           | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
  862                           | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
  863                           | AC97_EXT_AUDIO_LDAC)) {
  864 
  865                 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
  866                 extstat &= ~AC97_EXT_AUDIO_DRA;
  867 
  868                 if (as->ext_id & AC97_EXT_AUDIO_VRM)
  869                         extstat |= AC97_EXT_AUDIO_VRM;
  870 
  871                 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
  872                         extstat |= AC97_EXT_AUDIO_LDAC;
  873                 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
  874                         extstat |= AC97_EXT_AUDIO_SDAC;
  875                 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
  876                         extstat |= AC97_EXT_AUDIO_CDAC;
  877                 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
  878                         /* XXX S/PDIF gets same data as DAC?
  879                          * maybe this should be settable?
  880                          * default is SPSAAB (10/11) on AD1980 and ALC codecs.
  881                          */
  882                         extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
  883                         extstat |= AC97_EXT_AUDIO_SPSA34;
  884                         ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
  885                         val = (val & ~AC97_SPDIF_SPSR_MASK) |
  886                             AC97_SPDIF_SPSR_48K;
  887                         ac97_write(as, AC97_REG_SPDIF_CTRL, val);
  888                 }
  889                 if (as->ext_id & AC97_EXT_AUDIO_VRA)
  890                         extstat |= AC97_EXT_AUDIO_VRA;
  891                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
  892                 if (as->ext_id & AC97_EXT_AUDIO_VRA) {
  893                         /* VRA should be enabled. */
  894                         /* so it claims to do variable rate, let's make sure */
  895                         ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
  896                         ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
  897                         if (rate != 44100) {
  898                                 /* We can't believe ext_id */
  899                                 as->ext_id = 0;
  900                         }
  901                         /* restore the default value */
  902                         ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
  903                                    AC97_SINGLE_RATE);
  904                 }
  905         }
  906 
  907         ac97_setup_source_info(as);
  908 
  909         DELAY(900 * 1000);
  910 
  911         /* use initfunc for specific device */
  912         as->codec_if.initfunc = initfunc;
  913         if (initfunc != NULL)
  914                 initfunc(as, 0);
  915 
  916         /* Just enable the DAC and master volumes by default */
  917         bzero(&ctl, sizeof(ctl));
  918 
  919         ctl.type = AUDIO_MIXER_ENUM;
  920         ctl.un.ord = 0;  /* off */
  921         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
  922             AudioNmaster, AudioNmute);
  923         ac97_mixer_set_port(&as->codec_if, &ctl);
  924 
  925         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
  926             AudioNdac, AudioNmute);
  927         ac97_mixer_set_port(&as->codec_if, &ctl);
  928 
  929         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
  930             AudioNvolume, AudioNmute);
  931         ac97_mixer_set_port(&as->codec_if, &ctl);
  932 
  933         ctl.type = AUDIO_MIXER_ENUM;
  934         ctl.un.ord = 0;
  935         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
  936             AudioNsource, NULL);
  937         ac97_mixer_set_port(&as->codec_if, &ctl);
  938 
  939         return (0);
  940 }
  941 
  942 int
  943 ac97_resume(struct ac97_host_if *host_if, struct ac97_codec_if *codec_if)
  944 {
  945         struct ac97_softc *as = codec_if->as;
  946         u_int16_t val, extstat;
  947 
  948         host_if->reset(host_if->arg);
  949         DELAY(1000);
  950 
  951         host_if->write(host_if->arg, AC97_REG_POWER, 0);
  952         host_if->write(host_if->arg, AC97_REG_RESET, 0);
  953         DELAY(10000);
  954 
  955         if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
  956                           | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
  957                           | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
  958                           | AC97_EXT_AUDIO_LDAC)) {
  959 
  960                 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
  961                 extstat &= ~AC97_EXT_AUDIO_DRA;
  962 
  963                 if (as->ext_id & AC97_EXT_AUDIO_VRM)
  964                         extstat |= AC97_EXT_AUDIO_VRM;
  965 
  966                 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
  967                         extstat |= AC97_EXT_AUDIO_LDAC;
  968                 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
  969                         extstat |= AC97_EXT_AUDIO_SDAC;
  970                 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
  971                         extstat |= AC97_EXT_AUDIO_CDAC;
  972 
  973                 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
  974                         extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
  975                         extstat |= AC97_EXT_AUDIO_SPSA34;
  976                         ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
  977                         val = (val & ~AC97_SPDIF_SPSR_MASK) |
  978                             AC97_SPDIF_SPSR_48K;
  979                         ac97_write(as, AC97_REG_SPDIF_CTRL, val);
  980                 }
  981                 if (as->ext_id & AC97_EXT_AUDIO_VRA)
  982                         extstat |= AC97_EXT_AUDIO_VRA;
  983                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
  984         }
  985 
  986         /* use initfunc for specific device */
  987         if (as->codec_if.initfunc != NULL)
  988                 as->codec_if.initfunc(as, 1);
  989 
  990         return (0);
  991 }
  992 
  993 void
  994 ac97_lock(struct ac97_codec_if *codec_if)
  995 {
  996         struct ac97_softc *as = (struct ac97_softc *)codec_if;
  997         as->lock_counter++;
  998 }
  999 
 1000 void
 1001 ac97_unlock(struct ac97_codec_if *codec_if)
 1002 {
 1003         struct ac97_softc *as = (struct ac97_softc *)codec_if;
 1004         as->lock_counter--;
 1005 }
 1006 
 1007 int
 1008 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
 1009 {
 1010         struct ac97_softc *as = (struct ac97_softc *)codec_if;
 1011 
 1012         if (dip->index < as->num_source_info && dip->index >= 0) {
 1013                 struct ac97_source_info *si = &as->source_info[dip->index];
 1014                 const char *name;
 1015 
 1016                 dip->type = si->type;
 1017                 dip->mixer_class = si->mixer_class;
 1018                 dip->prev = si->prev;
 1019                 dip->next = si->next;
 1020 
 1021                 if (si->qualifier)
 1022                         name = si->qualifier;
 1023                 else if (si->device)
 1024                         name = si->device;
 1025                 else if (si->class)
 1026                         name = si->class;
 1027                 else
 1028                         name = NULL;
 1029 
 1030                 if (name)
 1031                         strlcpy(dip->label.name, name, sizeof dip->label.name);
 1032 
 1033                 bcopy(si->info, &dip->un, si->info_size);
 1034 
 1035                 /* Set the delta for volume sources */
 1036                 if (dip->type == AUDIO_MIXER_VALUE)
 1037                         dip->un.v.delta = 1 << (8 - si->bits);
 1038 
 1039                 return (0);
 1040         }
 1041 
 1042         return (ENXIO);
 1043 }
 1044 
 1045 int
 1046 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
 1047 {
 1048         struct ac97_softc *as = (struct ac97_softc *)codec_if;
 1049         struct ac97_source_info *si;
 1050         u_int16_t mask;
 1051         u_int16_t val, newval;
 1052         int error, spdif;
 1053 
 1054         if (cp->dev < 0 || cp->dev >= as->num_source_info)
 1055                 return (EINVAL);
 1056 
 1057         si = &as->source_info[cp->dev];
 1058 
 1059         if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
 1060                 return (EINVAL);
 1061 
 1062         spdif = si->req_feature == CHECK_SPDIF &&
 1063             si->reg == AC97_REG_EXT_AUDIO_CTRL;
 1064         if (spdif && as->lock_counter >= 0)
 1065                 return EBUSY;
 1066 
 1067         ac97_read(as, si->reg, &val);
 1068 
 1069         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
 1070 
 1071         mask = (1 << si->bits) - 1;
 1072 
 1073         switch (cp->type) {
 1074         case AUDIO_MIXER_ENUM:
 1075                 if (cp->un.ord > mask || cp->un.ord < 0)
 1076                         return (EINVAL);
 1077 
 1078                 newval = (cp->un.ord << si->ofs);
 1079                 if (si->reg == AC97_REG_RECORD_SELECT) {
 1080                         newval |= (newval << (8 + si->ofs));
 1081                         mask |= (mask << 8);
 1082                         mask = mask << si->ofs;
 1083                 } else if (si->reg == AC97_REG_SURR_MASTER) {
 1084                         newval = cp->un.ord ? 0x8080 : 0x0000;
 1085                         mask = 0x8080;
 1086                 } else
 1087                         mask = mask << si->ofs;
 1088 
 1089                 if (si->mute) {
 1090                         newval |= newval << 8;
 1091                         mask |= mask << 8;
 1092                 }
 1093 
 1094                 break;
 1095         case AUDIO_MIXER_VALUE:
 1096         {
 1097                 const struct audio_mixer_value *value = si->info;
 1098                 u_int16_t  l, r;
 1099 
 1100                 if (cp->un.value.num_channels <= 0 ||
 1101                     cp->un.value.num_channels > value->num_channels)
 1102                         return (EINVAL);
 1103 
 1104                 if (cp->un.value.num_channels == 1) {
 1105                         l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
 1106                 } else {
 1107                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
 1108                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
 1109                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
 1110                         } else {
 1111                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
 1112                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
 1113                         }
 1114                 }
 1115 
 1116                 if (!si->polarity) {
 1117                         l = 255 - l;
 1118                         r = 255 - r;
 1119                 }
 1120 
 1121                 l >>= 8 - si->bits;
 1122                 r >>= 8 - si->bits;
 1123 
 1124                 newval = ((l & mask) << si->ofs);
 1125                 if (value->num_channels == 2) {
 1126                         newval |= ((r & mask) << (si->ofs + 8));
 1127                         mask |= (mask << 8);
 1128                 }
 1129                 mask = mask << si->ofs;
 1130                 break;
 1131         }
 1132         default:
 1133                 return (EINVAL);
 1134         }
 1135 
 1136         error = ac97_write(as, si->reg, (val & ~mask) | newval);
 1137         if (error)
 1138                 return (error);
 1139 
 1140         if (spdif && as->host_if->spdif_event != NULL)
 1141                 as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
 1142 
 1143         return (0);
 1144 }
 1145 
 1146 
 1147 int
 1148 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
 1149 {
 1150         struct ac97_softc *as;
 1151         u_long value;
 1152         u_int16_t ext_stat;
 1153         u_int16_t actual;
 1154         u_int16_t power;
 1155         u_int16_t power_bit;
 1156 
 1157         as = (struct ac97_softc *)codec_if;
 1158 
 1159         if ((target == AC97_REG_PCM_SURR_DAC_RATE) &&
 1160             !(as->ext_id & AC97_EXT_AUDIO_SDAC))
 1161                         return 0;
 1162         if ((target == AC97_REG_PCM_LFE_DAC_RATE) &&
 1163             !(as->ext_id & AC97_EXT_AUDIO_LDAC))
 1164                         return 0;
 1165         if (target == AC97_REG_PCM_MIC_ADC_RATE) {
 1166                 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
 1167                         *rate = AC97_SINGLE_RATE;
 1168                         return 0;
 1169                 }
 1170         } else {
 1171                 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
 1172                         *rate = AC97_SINGLE_RATE;
 1173                         return 0;
 1174                 }
 1175         }
 1176         if (as->ac97_clock == 0)
 1177                 as->ac97_clock = AC97_STANDARD_CLOCK;
 1178         value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
 1179         ext_stat = 0;
 1180         /*
 1181          * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
 1182          *      Check VRA, DRA
 1183          * PCM_LR_ADC_RATE
 1184          *      Check VRA
 1185          * PCM_MIC_ADC_RATE
 1186          *      Check VRM
 1187          */
 1188         switch (target) {
 1189         case AC97_REG_PCM_FRONT_DAC_RATE:
 1190         case AC97_REG_PCM_SURR_DAC_RATE:
 1191         case AC97_REG_PCM_LFE_DAC_RATE:
 1192                 power_bit = AC97_POWER_OUT;
 1193                 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
 1194                         ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
 1195                         if (value > 0x1ffff) {
 1196                                 return EINVAL;
 1197                         } else if (value > 0xffff) {
 1198                                 /* Enable DRA */
 1199                                 ext_stat |= AC97_EXT_AUDIO_DRA;
 1200                                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
 1201                                 value /= 2;
 1202                         } else {
 1203                                 /* Disable DRA */
 1204                                 ext_stat &= ~AC97_EXT_AUDIO_DRA;
 1205                                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
 1206                         }
 1207                 } else {
 1208                         if (value > 0xffff)
 1209                                 return EINVAL;
 1210                 }
 1211                 break;
 1212         case AC97_REG_PCM_LR_ADC_RATE:
 1213                 power_bit = AC97_POWER_IN;
 1214                 if (value > 0xffff)
 1215                         return EINVAL;
 1216                 break;
 1217         case AC97_REG_PCM_MIC_ADC_RATE:
 1218                 power_bit = AC97_POWER_IN;
 1219                 if (value > 0xffff)
 1220                         return EINVAL;
 1221                 break;
 1222         default:
 1223                 printf("%s: Unknown register: 0x%x\n", __func__, target);
 1224                 return EINVAL;
 1225         }
 1226 
 1227         ac97_read(as, AC97_REG_POWER, &power);
 1228         ac97_write(as, AC97_REG_POWER, power | power_bit);
 1229 
 1230         ac97_write(as, target, (u_int16_t)value);
 1231         ac97_read(as, target, &actual);
 1232         actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
 1233 
 1234         ac97_write(as, AC97_REG_POWER, power);
 1235         if (ext_stat & AC97_EXT_AUDIO_DRA) {
 1236                 *rate = actual * 2;
 1237         } else {
 1238                 *rate = actual;
 1239         }
 1240         return 0;
 1241 }
 1242 
 1243 void
 1244 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
 1245 {
 1246         struct ac97_softc *as;
 1247 
 1248         as = (struct ac97_softc *)codec_if;
 1249         as->ac97_clock = clock;
 1250 }
 1251 
 1252 u_int16_t
 1253 ac97_get_extcaps(struct ac97_codec_if *codec_if)
 1254 {
 1255         struct ac97_softc *as;
 1256 
 1257         as = (struct ac97_softc *)codec_if;
 1258         return as->ext_id;
 1259 }
 1260 
 1261 int
 1262 ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src)
 1263 {
 1264         struct ac97_source_info *si;
 1265         int ouridx, idx;
 1266 
 1267         if (as->num_source_info >= MAX_SOURCES) {
 1268                 printf("%s: internal error: increase MAX_SOURCES in %s\n",
 1269                        __func__, __FILE__);
 1270                 return -1;
 1271         }
 1272         if (!ac97_check_capability(as, src->req_feature))
 1273                 return -1;
 1274         ouridx = as->num_source_info;
 1275         si = &as->source_info[ouridx];
 1276         memcpy(si, src, sizeof(*si));
 1277 
 1278         switch (si->type) {
 1279         case AUDIO_MIXER_CLASS:
 1280         case AUDIO_MIXER_VALUE:
 1281                 printf("%s: adding class/value is not supported yet.\n",
 1282                        __func__);
 1283                 return -1;
 1284         case AUDIO_MIXER_ENUM:
 1285                 break;
 1286         default:
 1287                 printf("%s: unknown type: %d\n", __func__, si->type);
 1288                 return -1;
 1289         }
 1290         as->num_source_info++;
 1291 
 1292         si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
 1293                                                    NULL, NULL);
 1294         /* Find the root of the device */
 1295         idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
 1296                                        si->device, NULL);
 1297         /* Find the last item */
 1298         while (as->source_info[idx].next != AUDIO_MIXER_LAST)
 1299                 idx = as->source_info[idx].next;
 1300         /* Append */
 1301         as->source_info[idx].next = ouridx;
 1302         si->prev = idx;
 1303         si->next = AUDIO_MIXER_LAST;
 1304 
 1305         return 0;
 1306 }
 1307 
 1308 int
 1309 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, char *class,
 1310     char *device, char *qualifier)
 1311 {
 1312         struct ac97_softc *as = (struct ac97_softc *)codec_if;
 1313         int idx;
 1314 
 1315         for (idx = 0; idx < as->num_source_info; idx++) {
 1316                 struct ac97_source_info *si = &as->source_info[idx];
 1317                 if (ac97_str_equal(class, si->class) &&
 1318                     ac97_str_equal(device, si->device) &&
 1319                     ac97_str_equal(qualifier, si->qualifier))
 1320                         return (idx);
 1321         }
 1322 
 1323         return (-1);
 1324 }
 1325 
 1326 int
 1327 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
 1328 {
 1329         struct ac97_softc *as = (struct ac97_softc *)codec_if;
 1330         struct ac97_source_info *si;
 1331         u_int16_t mask;
 1332         u_int16_t val;
 1333 
 1334         if (cp->dev < 0 || cp->dev >= as->num_source_info)
 1335                 return (EINVAL);
 1336 
 1337         si = &as->source_info[cp->dev];
 1338 
 1339         if (cp->type != si->type)
 1340                 return (EINVAL);
 1341 
 1342         ac97_read(as, si->reg, &val);
 1343 
 1344         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
 1345 
 1346         mask = (1 << si->bits) - 1;
 1347 
 1348         switch (cp->type) {
 1349         case AUDIO_MIXER_ENUM:
 1350                 cp->un.ord = (val >> si->ofs) & mask;
 1351                 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
 1352                     mask, cp->un.ord));
 1353                 break;
 1354         case AUDIO_MIXER_VALUE:
 1355         {
 1356                 const struct audio_mixer_value *value = si->info;
 1357                 u_int16_t  l, r;
 1358 
 1359                 if ((cp->un.value.num_channels <= 0) ||
 1360                     (cp->un.value.num_channels > value->num_channels))
 1361                         return (EINVAL);
 1362 
 1363                 if (value->num_channels == 1)
 1364                         l = r = (val >> si->ofs) & mask;
 1365                 else {
 1366                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
 1367                                 l = (val >> si->ofs) & mask;
 1368                                 r = (val >> (si->ofs + 8)) & mask;
 1369                         } else {
 1370                                 r = (val >> si->ofs) & mask;
 1371                                 l = (val >> (si->ofs + 8)) & mask;
 1372                         }
 1373                 }
 1374 
 1375                 l <<= 8 - si->bits;
 1376                 r <<= 8 - si->bits;
 1377                 if (!si->polarity) {
 1378                         l = 255 - l;
 1379                         r = 255 - r;
 1380                 }
 1381 
 1382                 /*
 1383                  * The EAP driver averages l and r for stereo
 1384                  * channels that are requested in MONO mode. Does this
 1385                  * make sense?
 1386                  */
 1387                 if (cp->un.value.num_channels == 1) {
 1388                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
 1389                 } else if (cp->un.value.num_channels == 2) {
 1390                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
 1391                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
 1392                 }
 1393 
 1394                 break;
 1395         }
 1396         default:
 1397                 return (EINVAL);
 1398         }
 1399 
 1400         return (0);
 1401 }
 1402 
 1403 
 1404 /*
 1405  * Codec-dependent initialization
 1406  */
 1407 
 1408 void
 1409 ac97_ad1885_init(struct ac97_softc *as, int resuming)
 1410 {
 1411         int i;
 1412 
 1413         if (resuming)
 1414                 return;
 1415 
 1416         for (i = 0; i < as->num_source_info; i++) {
 1417                 if (as->source_info[i].reg == AC97_REG_HEADPHONE_VOLUME)
 1418                         as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
 1419                 else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
 1420                         as->source_info[i].reg = AC97_REG_HEADPHONE_VOLUME;
 1421         }
 1422 }
 1423 
 1424 #define AC97_AD1886_JACK_SENSE  0x72
 1425 
 1426 void
 1427 ac97_ad1886_init(struct ac97_softc *as, int resuming)
 1428 {
 1429         ac97_write(as, AC97_AD1886_JACK_SENSE, 0x0010);
 1430 }
 1431 
 1432 void
 1433 ac97_ad198x_init(struct ac97_softc *as, int resuming)
 1434 {
 1435         int i;
 1436         u_int16_t misc;
 1437 
 1438         ac97_read(as, AC97_AD_REG_MISC, &misc);
 1439         ac97_write(as, AC97_AD_REG_MISC,
 1440             misc|AC97_AD_MISC_HPSEL|AC97_AD_MISC_LOSEL);
 1441 
 1442         if (resuming)
 1443                 return;
 1444 
 1445         for (i = 0; i < as->num_source_info; i++) {
 1446                 if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
 1447                         as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
 1448                 else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
 1449                         as->source_info[i].reg = AC97_REG_SURR_MASTER;
 1450         }
 1451 }
 1452 
 1453 void
 1454 ac97_alc650_init(struct ac97_softc *as, int resuming)
 1455 {
 1456         u_int16_t misc;
 1457 
 1458         ac97_read(as, AC97_ALC650_REG_MISC, &misc);
 1459         if (as->host_flags & AC97_HOST_ALC650_PIN47_IS_EAPD)
 1460                 misc &= ~AC97_ALC650_MISC_PIN47;
 1461         misc &= ~AC97_ALC650_MISC_VREFDIS;
 1462         ac97_write(as, AC97_ALC650_REG_MISC, misc);
 1463 
 1464         if (resuming)
 1465                 return;
 1466 
 1467         struct ac97_source_info sources[3] = {
 1468                 { AudioCoutputs, AudioNsurround, "lineinjack",
 1469                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1470                   AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
 1471                   0x0000, 1, 9, 0, 0, CHECK_SURROUND },
 1472                 { AudioCoutputs, AudioNcenter, "micjack",
 1473                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1474                   AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
 1475                   0x0000, 1, 10, 0, 0, CHECK_CENTER },
 1476                 { AudioCoutputs, AudioNlfe, "micjack",
 1477                   AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
 1478                   AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
 1479                   0x0000, 1, 10, 0, 0, CHECK_LFE }};
 1480 
 1481         ac97_add_port(as, &sources[0]);
 1482         ac97_add_port(as, &sources[1]);
 1483         ac97_add_port(as, &sources[2]);
 1484 }
 1485 
 1486 void
 1487 ac97_cx20468_init(struct ac97_softc *as, int resuming)
 1488 {
 1489         u_int16_t misc;
 1490 
 1491         ac97_read(as, AC97_CX_REG_MISC, &misc);
 1492         ac97_write(as, AC97_CX_REG_MISC, misc &
 1493             ~(AC97_CX_SPDIFEN | AC97_CX_COPYRIGHT | AC97_CX_MASK));
 1494 }
 1495 
 1496 void
 1497 ac97_vt1616_init(struct ac97_softc *as, int resuming)
 1498 {
 1499         u_int16_t reg;
 1500 
 1501         if (as->host_flags & AC97_HOST_VT1616_DYNEX) {
 1502                 ac97_read(as, AC97_VT_REG_TEST, &reg);
 1503 
 1504                 /* disable 'hp' mixer controls controlling the surround pins */
 1505                 reg &= ~(AC97_VT_LVL);
 1506 
 1507                 /* disable downmixing */
 1508                 reg &= ~(AC97_VT_LCTF | AC97_VT_STF);
 1509 
 1510                 /* enable DC offset removal */
 1511                 reg |= AC97_VT_BPDC;
 1512 
 1513                 ac97_write(as, AC97_VT_REG_TEST, reg);
 1514         }
 1515 }

Cache object: b44865c75ba6590dc9219f2ee5177ae4


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