root/dev/ic/ac97.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ac97_read
  2. ac97_write
  3. ac97_setup_defaults
  4. ac97_restore_shadow
  5. ac97_str_equal
  6. ac97_setup_source_info
  7. ac97_attach
  8. ac97_query_devinfo
  9. ac97_mixer_set_port
  10. ac97_get_portnum_by_name
  11. ac97_mixer_get_port
  12. ac97_set_rate
  13. ac97_ad1886_init
  14. ac97_ad198x_init
  15. ac97_alc655_init
  16. ac97_cx20468_init

    1 /*      $OpenBSD: ac97.c,v 1.63 2007/07/27 01:48:04 ian 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 #include <sys/device.h>
   68 
   69 #include <sys/audioio.h>
   70 #include <dev/audio_if.h>
   71 #include <dev/ic/ac97.h>
   72 
   73 const struct audio_mixer_enum ac97_on_off = {
   74         2,
   75         { { { AudioNoff } , 0 },
   76         { { AudioNon }  , 1 } }
   77 };
   78 
   79 const struct audio_mixer_enum ac97_mic_select = {
   80         2,
   81         { { { AudioNmicrophone "0" }, 0 },
   82         { { AudioNmicrophone "1" }, 1 } }
   83 };
   84 
   85 const struct audio_mixer_enum ac97_mono_select = {
   86         2,
   87         { { { AudioNmixerout }, 0 },
   88         { { AudioNmicrophone }, 1 } }
   89 };
   90 
   91 const struct audio_mixer_enum ac97_source = {
   92         8,
   93         { { { AudioNmicrophone } , 0 },
   94         { { AudioNcd }, 1 },
   95         { { "video" }, 2 },
   96         { { AudioNaux }, 3 },
   97         { { AudioNline }, 4 },
   98         { { AudioNmixerout }, 5 },
   99         { { AudioNmixerout AudioNmono }, 6 },
  100         { { "phone" }, 7 }}
  101 };
  102 
  103 /*
  104  * Due to different values for each source that uses these structures,
  105  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
  106  * ac97_source_info.bits.
  107  */
  108 const struct audio_mixer_value ac97_volume_stereo = {
  109         { AudioNvolume },
  110         2
  111 };
  112 
  113 const struct audio_mixer_value ac97_volume_mono = {
  114         { AudioNvolume },
  115         1
  116 };
  117 
  118 #define WRAP(a)  &a, sizeof(a)
  119 
  120 const struct ac97_source_info {
  121         char *class;
  122         char *device;
  123         char *qualifier;
  124         int  type;
  125 
  126         const void *info;
  127         int16_t info_size;
  128 
  129         u_int8_t  reg;
  130         u_int8_t  bits:3;
  131         u_int8_t  ofs:4;
  132         u_int8_t  mute:1;
  133         u_int8_t  polarity:1;           /* Does 0 == MAX or MIN */
  134         u_int16_t default_value;
  135 
  136         int16_t  prev;
  137         int16_t  next;
  138         int16_t  mixer_class;
  139 } source_info[] = {
  140         {
  141                 AudioCinputs,   NULL,           NULL,   AUDIO_MIXER_CLASS,
  142         }, {
  143                 AudioCoutputs,  NULL,           NULL,   AUDIO_MIXER_CLASS,
  144         }, {
  145                 AudioCrecord,   NULL,           NULL,   AUDIO_MIXER_CLASS,
  146         }, {
  147                 /* Stereo master volume*/
  148                 AudioCoutputs,  AudioNmaster,   NULL,   AUDIO_MIXER_VALUE,
  149                 WRAP(ac97_volume_stereo),
  150                 AC97_REG_MASTER_VOLUME, 5, 0, 1, 0, 0x8000
  151         }, {
  152                 /* Mono volume */
  153                 AudioCoutputs,  AudioNmono,     NULL,   AUDIO_MIXER_VALUE,
  154                 WRAP(ac97_volume_mono),
  155                 AC97_REG_MASTER_VOLUME_MONO, 6, 0, 1, 0, 0x8000
  156         }, {
  157                 AudioCoutputs,  AudioNmono, AudioNsource, AUDIO_MIXER_ENUM,
  158                 WRAP(ac97_mono_select),
  159                 AC97_REG_GP, 1, 9, 0, 0, 0x0000
  160         }, {
  161                 /* Headphone volume */
  162                 AudioCoutputs,  AudioNheadphone, NULL,  AUDIO_MIXER_VALUE,
  163                 WRAP(ac97_volume_stereo),
  164                 AC97_REG_HEADPHONE_VOLUME, 6, 0, 1, 0, 0x8000
  165         }, {
  166                 AudioCoutputs,  AudioNbass,     NULL,   AUDIO_MIXER_VALUE,
  167                 WRAP(ac97_volume_mono),
  168                 AC97_REG_MASTER_TONE, 4, 8, 0, 0, 0x0f0f
  169         }, {
  170                 AudioCoutputs,  AudioNtreble,   NULL,   AUDIO_MIXER_VALUE,
  171                 WRAP(ac97_volume_mono),
  172                 AC97_REG_MASTER_TONE, 4, 0, 0, 0, 0x0f0f
  173         }, {
  174                 /* PC Beep Volume */
  175                 AudioCinputs,   AudioNspeaker,  NULL,   AUDIO_MIXER_VALUE,
  176                 WRAP(ac97_volume_mono),
  177                 AC97_REG_PCBEEP_VOLUME, 4, 1, 1, 0, 0x0000
  178         }, {
  179                 /* Phone */
  180                 AudioCinputs,   "phone",        NULL,   AUDIO_MIXER_VALUE,
  181                 WRAP(ac97_volume_mono),
  182                 AC97_REG_PHONE_VOLUME, 5, 0, 1, 0, 0x8008
  183         }, {
  184                 /* Mic Volume */
  185                 AudioCinputs,   AudioNmicrophone, NULL, AUDIO_MIXER_VALUE,
  186                 WRAP(ac97_volume_mono),
  187                 AC97_REG_MIC_VOLUME, 5, 0, 1, 0, 0x8008
  188         }, {
  189                 AudioCinputs,   AudioNmicrophone, AudioNpreamp, AUDIO_MIXER_ENUM,
  190                 WRAP(ac97_on_off),
  191                 AC97_REG_MIC_VOLUME, 1, 6, 0, 0, 0x8008
  192         }, {
  193                 AudioCinputs,   AudioNmicrophone, AudioNsource, AUDIO_MIXER_ENUM,
  194                 WRAP(ac97_mic_select),
  195                 AC97_REG_GP, 1, 8, 0, 0x0000
  196         }, {
  197                 /* Line in Volume */
  198                 AudioCinputs,   AudioNline,     NULL,   AUDIO_MIXER_VALUE,
  199                 WRAP(ac97_volume_stereo),
  200                 AC97_REG_LINEIN_VOLUME, 5, 0, 1, 0, 0x8808
  201         }, {
  202                 /* CD Volume */
  203                 AudioCinputs,   AudioNcd,       NULL,   AUDIO_MIXER_VALUE,
  204                 WRAP(ac97_volume_stereo),
  205                 AC97_REG_CD_VOLUME, 5, 0, 1, 0, 0x8808
  206         }, {
  207                 /* Video Volume */
  208                 AudioCinputs,   "video",        NULL,   AUDIO_MIXER_VALUE,
  209                 WRAP(ac97_volume_stereo),
  210                 AC97_REG_VIDEO_VOLUME, 5, 0, 1, 0, 0x8808
  211         }, {
  212                 /* AUX volume */
  213                 AudioCinputs,   AudioNaux,      NULL,   AUDIO_MIXER_VALUE,
  214                 WRAP(ac97_volume_stereo),
  215                 AC97_REG_AUX_VOLUME, 5, 0, 1, 0, 0x8808
  216         }, {
  217                 /* PCM out volume */
  218                 AudioCinputs,   AudioNdac,      NULL,   AUDIO_MIXER_VALUE,
  219                 WRAP(ac97_volume_stereo),
  220                 AC97_REG_PCMOUT_VOLUME, 5, 0, 1, 0, 0x8808
  221         }, {
  222                 /* Record Source - some logic for this is hard coded - see below */
  223                 AudioCrecord,   AudioNsource,   NULL,   AUDIO_MIXER_ENUM,
  224                 WRAP(ac97_source),
  225                 AC97_REG_RECORD_SELECT, 3, 0, 0, 0, 0x0000
  226         }, {
  227                 /* Record Gain */
  228                 AudioCrecord,   AudioNvolume,   NULL,   AUDIO_MIXER_VALUE,
  229                 WRAP(ac97_volume_stereo),
  230                 AC97_REG_RECORD_GAIN, 4, 0, 1, 0, 0x8000
  231         }, {
  232                 /* Record Gain mic */
  233                 AudioCrecord,   AudioNmicrophone, NULL, AUDIO_MIXER_VALUE,
  234                 WRAP(ac97_volume_mono),
  235                 AC97_REG_RECORD_GAIN_MIC, 4, 0, 1, 1, 0x8000
  236         }, {
  237                 /* */
  238                 AudioCoutputs,  AudioNloudness, NULL,   AUDIO_MIXER_ENUM,
  239                 WRAP(ac97_on_off),
  240                 AC97_REG_GP, 1, 12, 0, 0, 0x0000
  241         }, {
  242                 AudioCoutputs,  AudioNspatial,  NULL,   AUDIO_MIXER_ENUM,
  243                 WRAP(ac97_on_off),
  244                 AC97_REG_GP, 1, 13, 0, 0, 0x0000
  245         }, {
  246                 AudioCoutputs,  AudioNspatial,  AudioNcenter,AUDIO_MIXER_VALUE,
  247                 WRAP(ac97_volume_mono),
  248                 AC97_REG_3D_CONTROL, 4, 8, 0, 1, 0x0000
  249         }, {
  250                 AudioCoutputs,  AudioNspatial,  AudioNdepth, AUDIO_MIXER_VALUE,
  251                 WRAP(ac97_volume_mono),
  252                 AC97_REG_3D_CONTROL, 4, 0, 0, 1, 0x0000
  253         }, {
  254                 /* Surround volume */
  255                 AudioCoutputs,  AudioNsurround, NULL,   AUDIO_MIXER_VALUE,
  256                 WRAP(ac97_volume_stereo),
  257                 AC97_REG_SURROUND_VOLUME, 6, 0, 1, 0, 0x8080
  258         }, {
  259                 /* Center volume */
  260                 AudioCoutputs,  AudioNcenter,   NULL,   AUDIO_MIXER_VALUE,
  261                 WRAP(ac97_volume_mono),
  262                 AC97_REG_CENTER_LFE_VOLUME, 6, 0, 1, 0, 0x8080
  263         }, {
  264                 /* LFE volume */
  265                 AudioCoutputs,  AudioNlfe,      NULL,   AUDIO_MIXER_VALUE,
  266                 WRAP(ac97_volume_mono),
  267                 AC97_REG_CENTER_LFE_VOLUME, 6, 8, 1, 0, 0x8080
  268         }, {
  269                 /* External Amp */
  270                 AudioCoutputs,  AudioNextamp,   NULL,   AUDIO_MIXER_ENUM,
  271                 WRAP(ac97_on_off),
  272                 AC97_REG_POWER, 1, 15, 0, 0, 0x0000
  273         }
  274 
  275         /* Missing features: Simulated Stereo, POP, Loopback mode */
  276 };
  277 
  278 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
  279 
  280 /*
  281  * Check out http://www.intel.com/technology/computing/audio/index.htm
  282  * for information on AC-97
  283  */
  284 
  285 struct ac97_softc {
  286         struct ac97_codec_if codec_if;
  287         struct ac97_host_if *host_if;
  288         struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE];
  289         int num_source_info;
  290         enum ac97_host_flags host_flags;
  291         u_int16_t caps, ext_id;
  292         u_int16_t shadow_reg[128];
  293 };
  294 
  295 int     ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
  296 int     ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
  297 int     ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
  298 int     ac97_get_portnum_by_name(struct ac97_codec_if *, char *, char *,
  299             char *);
  300 void    ac97_restore_shadow(struct ac97_codec_if *);
  301 
  302 void    ac97_ad1886_init(struct ac97_softc *);
  303 void    ac97_ad198x_init(struct ac97_softc *);
  304 void    ac97_alc655_init(struct ac97_softc *);
  305 void    ac97_cx20468_init(struct ac97_softc *);
  306 
  307 struct ac97_codec_if_vtbl ac97civ = {
  308         ac97_mixer_get_port,
  309         ac97_mixer_set_port,
  310         ac97_query_devinfo,
  311         ac97_get_portnum_by_name,
  312         ac97_restore_shadow
  313 };
  314 
  315 const struct ac97_codecid {
  316         u_int8_t id;
  317         u_int8_t mask;
  318         u_int8_t rev;
  319         u_int8_t shift; /* no use yet */
  320         char * const name;
  321         void (*init)(struct ac97_softc *);
  322 }  ac97_ad[] = {
  323         { 0x03, 0xff, 0, 0,     "AD1819" },
  324         { 0x40, 0xff, 0, 0,     "AD1881" },
  325         { 0x48, 0xff, 0, 0,     "AD1881A" },
  326         { 0x60, 0xff, 0, 0,     "AD1885" },
  327         { 0x61, 0xff, 0, 0,     "AD1886",       ac97_ad1886_init },
  328         { 0x63, 0xff, 0, 0,     "AD1886A" },
  329         { 0x68, 0xff, 0, 0,     "AD1888",       ac97_ad198x_init },
  330         { 0x70, 0xff, 0, 0,     "AD1980" },
  331         { 0x72, 0xff, 0, 0,     "AD1981A" },
  332         { 0x74, 0xff, 0, 0,     "AD1981B" },
  333         { 0x75, 0xff, 0, 0,     "AD1985",       ac97_ad198x_init },
  334 }, ac97_ak[] = {
  335         { 0x00, 0xfe, 1, 0,     "AK4540" },
  336         { 0x01, 0xfe, 1, 0,     "AK4540" },
  337         { 0x02, 0xff, 0, 0,     "AK4543" },
  338         { 0x05, 0xff, 0, 0,     "AK4544" },
  339         { 0x06, 0xff, 0, 0,     "AK4544A" },
  340         { 0x07, 0xff, 0, 0,     "AK4545" },
  341 }, ac97_av[] = {
  342         { 0x10, 0xff, 0, 0,     "ALC200" },
  343         { 0x20, 0xff, 0, 0,     "ALC650" },
  344         { 0x21, 0xff, 0, 0,     "ALC650D" },
  345         { 0x22, 0xff, 0, 0,     "ALC650E" },
  346         { 0x23, 0xff, 0, 0,     "ALC650F" },
  347         { 0x30, 0xff, 0, 0,     "ALC101" },
  348         { 0x40, 0xff, 0, 0,     "ALC202" },
  349         { 0x50, 0xff, 0, 0,     "ALC250" },
  350         { 0x52, 0xff, 0, 0,     "ALC250A?" },
  351         { 0x60, 0xf0, 0xf, 0,   "ALC655",       ac97_alc655_init },
  352         { 0x70, 0xf0, 0xf, 0,   "ALC203" },
  353         { 0x80, 0xf0, 0xf, 0,   "ALC658",       ac97_alc655_init },
  354         { 0x90, 0xf0, 0xf, 0,   "ALC850" },
  355 }, ac97_rl[] = {
  356         { 0x00, 0xf0, 0xf, 0,   "RL5306" },
  357         { 0x10, 0xf0, 0xf, 0,   "RL5382" },
  358         { 0x20, 0xf0, 0xf, 0,   "RL5383" },
  359 }, ac97_cm[] = {
  360         { 0x41, 0xff, 0, 0,     "CMI9738" },
  361         { 0x61, 0xff, 0, 0,     "CMI9739" },
  362         { 0x78, 0xff, 0, 0,     "CMI9761A" },
  363         { 0x82, 0xff, 0, 0,     "CMI9761B" },
  364         { 0x83, 0xff, 0, 0,     "CMI9761A+" },
  365 }, ac97_cr[] = {
  366         { 0x84, 0xff, 0, 0,     "EV1938" },
  367 }, ac97_cs[] = {
  368         { 0x00, 0xf8, 7, 0,     "CS4297" },
  369         { 0x10, 0xf8, 7, 0,     "CS4297A" },
  370         { 0x20, 0xf8, 7, 0,     "CS4298" },
  371         { 0x28, 0xf8, 7, 0,     "CS4294" },
  372         { 0x30, 0xf8, 7, 0,     "CS4299" },
  373         { 0x48, 0xf8, 7, 0,     "CS4201" },
  374         { 0x58, 0xf8, 7, 0,     "CS4205" },
  375         { 0x60, 0xf8, 7, 0,     "CS4291" },
  376         { 0x70, 0xf8, 7, 0,     "CS4202" },
  377 }, ac97_cx[] = {
  378         { 0x21, 0xff, 0, 0,     "HSD11246" },
  379         { 0x28, 0xf8, 7, 0,     "CX20468",      ac97_cx20468_init },
  380         { 0x30, 0xff, 0, 0,     "CXT48", },
  381         { 0x42, 0xff, 0, 0,     "CXT66", },
  382 }, ac97_dt[] = {
  383         { 0x00, 0xff, 0, 0,     "DT0398" },
  384 }, ac97_em[] = {
  385         { 0x23, 0xff, 0, 0,     "EM28023" },
  386         { 0x28, 0xff, 0, 0,     "EM28028" },
  387 }, ac97_es[] = {
  388         { 0x08, 0xff, 0, 0,     "ES1921" },
  389 }, ac97_is[] = {
  390         { 0x00, 0xff, 0, 0,     "HMP9701" },
  391 }, ac97_ic[] = {
  392         { 0x01, 0xff, 0, 0,     "ICE1230" },
  393         { 0x11, 0xff, 0, 0,     "ICE1232" },
  394         { 0x14, 0xff, 0, 0,     "ICE1232A" },
  395         { 0x51, 0xff, 0, 0,     "VIA VT1616" },
  396         { 0x52, 0xff, 0, 0,     "VIA VT1616i" },
  397 }, ac97_it[] = {
  398         { 0x20, 0xff, 0, 0,     "ITE2226E" },
  399         { 0x60, 0xff, 0, 0,     "ITE2646E" },
  400 }, ac97_ns[] = {
  401         { 0x00, 0xff, 0, 0,     "LM454[03568]" },
  402         { 0x31, 0xff, 0, 0,     "LM4549" },
  403         { 0x40, 0xff, 0, 0,     "LM4540" },
  404         { 0x43, 0xff, 0, 0,     "LM4543" },
  405         { 0x46, 0xff, 0, 0,     "LM4546A" },
  406         { 0x48, 0xff, 0, 0,     "LM4548A" },
  407         { 0x49, 0xff, 0, 0,     "LM4549A" },
  408         { 0x50, 0xff, 0, 0,     "LM4550" },
  409 }, ac97_ps[] = {
  410         { 0x01, 0xff, 0, 0,     "UCB1510" },
  411         { 0x04, 0xff, 0, 0,     "UCB1400" },
  412 }, ac97_sl[] = {
  413         { 0x20, 0xe0, 0, 0,     "Si3036/38" },
  414 }, ac97_st[] = {
  415         { 0x00, 0xff, 0, 0,     "STAC9700" },
  416         { 0x04, 0xff, 0, 0,     "STAC970[135]" },
  417         { 0x05, 0xff, 0, 0,     "STAC9704" },
  418         { 0x08, 0xff, 0, 0,     "STAC9708/11" },
  419         { 0x09, 0xff, 0, 0,     "STAC9721/23" },
  420         { 0x44, 0xff, 0, 0,     "STAC9744/45" },
  421         { 0x50, 0xff, 0, 0,     "STAC9750/51" },
  422         { 0x52, 0xff, 0, 0,     "STAC9752/53" },
  423         { 0x56, 0xff, 0, 0,     "STAC9756/57" },
  424         { 0x58, 0xff, 0, 0,     "STAC9758/59" },
  425         { 0x60, 0xff, 0, 0,     "STAC9760/61" },
  426         { 0x62, 0xff, 0, 0,     "STAC9762/63" },
  427         { 0x66, 0xff, 0, 0,     "STAC9766/67" },
  428         { 0x84, 0xff, 0, 0,     "STAC9784/85" },
  429 }, ac97_vi[] = {
  430         { 0x61, 0xff, 0, 0,     "VT1612A" },
  431 }, ac97_tt[] = {
  432         { 0x02, 0xff, 0, 0,     "TR28022" },
  433         { 0x03, 0xff, 0, 0,     "TR28023" },
  434         { 0x06, 0xff, 0, 0,     "TR28026" },
  435         { 0x08, 0xff, 0, 0,     "TR28028" },
  436         { 0x23, 0xff, 0, 0,     "TR28602" },
  437 }, ac97_ti[] = {
  438         { 0x20, 0xff, 0, 0,     "TLC320AD9xC" },
  439 }, ac97_wb[] = {
  440         { 0x01, 0xff, 0, 0,     "W83971D" },
  441 }, ac97_wo[] = {
  442         { 0x00, 0xff, 0, 0,     "WM9701A" },
  443         { 0x03, 0xff, 0, 0,     "WM9704M/Q-0" }, /* & WM9703 */
  444         { 0x04, 0xff, 0, 0,     "WM9704M/Q-1" },
  445         { 0x05, 0xff, 0, 0,     "WM9705/10" },
  446         { 0x09, 0xff, 0, 0,     "WM9709" },
  447         { 0x12, 0xff, 0, 0,     "WM9711/12" },
  448 }, ac97_ym[] = {
  449         { 0x00, 0xff, 0, 0,     "YMF743-S" },
  450         { 0x02, 0xff, 0, 0,     "YMF752-S" },
  451         { 0x03, 0xff, 0, 0,     "YMF753-S" },
  452 };
  453 
  454 #define cl(n)   n, sizeof(n)/sizeof(n[0])
  455 const struct ac97_vendorid {
  456         u_int32_t id;
  457         char * const name;
  458         const struct ac97_codecid * const codecs;
  459         u_int8_t num;
  460 } ac97_vendors[] = {
  461         { 0x01408300, "Creative",               cl(ac97_cr) },
  462         { 0x41445300, "Analog Devices",         cl(ac97_ad) },
  463         { 0x414b4D00, "Asahi Kasei",            cl(ac97_ak) },
  464         { 0x414c4300, "Realtek",                cl(ac97_rl) },
  465         { 0x414c4700, "Avance Logic",           cl(ac97_av) },
  466         { 0x434d4900, "C-Media Electronics",    cl(ac97_cm) },
  467         { 0x43525900, "Cirrus Logic",           cl(ac97_cs) },
  468         { 0x43585400, "Conexant",               cl(ac97_cx) },
  469         { 0x44543000, "Diamond Technology",     cl(ac97_dt) },
  470         { 0x454d4300, "eMicro",                 cl(ac97_em) },
  471         { 0x45838300, "ESS Technology",         cl(ac97_es) },
  472         { 0x48525300, "Intersil",               cl(ac97_is) },
  473         { 0x49434500, "ICEnsemble",             cl(ac97_ic) },
  474         { 0x49544500, "ITE, Inc.",              cl(ac97_it) },
  475         { 0x4e534300, "National Semiconductor", cl(ac97_ns) },
  476         { 0x50534300, "Philips Semiconductor",  cl(ac97_ps) },
  477         { 0x53494c00, "Silicon Laboratory",     cl(ac97_sl) },
  478         { 0x54524100, "TriTech Microelectronics", cl(ac97_tt) },
  479         { 0x54584e00, "Texas Instruments",      cl(ac97_ti) },
  480         { 0x56494100, "VIA Technologies",       cl(ac97_vi) },
  481         { 0x57454300, "Winbond",                cl(ac97_wb) },
  482         { 0x574d4c00, "Wolfson",                cl(ac97_wo) },
  483         { 0x594d4800, "Yamaha",                 cl(ac97_ym) },
  484         { 0x83847600, "SigmaTel",               cl(ac97_st) },
  485 };
  486 #undef cl
  487 
  488 const char * const ac97enhancement[] = {
  489         "No 3D Stereo",
  490         "Analog Devices Phat Stereo",
  491         "Creative",
  492         "National Semi 3D",
  493         "Yamaha Ymersion",
  494         "BBE 3D",
  495         "Crystal Semi 3D",
  496         "Qsound QXpander",
  497         "Spatializer 3D",
  498         "SRS 3D",
  499         "Platform Tech 3D",
  500         "AKM 3D",
  501         "Aureal",
  502         "AZTECH 3D",
  503         "Binaura 3D",
  504         "ESS Technology",
  505         "Harman International VMAx",
  506         "Nvidea 3D",
  507         "Philips Incredible Sound",
  508         "Texas Instruments 3D",
  509         "VLSI Technology 3D",
  510         "TriTech 3D",
  511         "Realtek 3D",
  512         "Samsung 3D",
  513         "Wolfson Microelectronics 3D",
  514         "Delta Integration 3D",
  515         "SigmaTel 3D",
  516         "KS Waves 3D",
  517         "Rockwell 3D",
  518         "Unknown 3D",
  519         "Unknown 3D",
  520         "Unknown 3D"
  521 };
  522 
  523 const char * const ac97feature[] = {
  524         "mic channel",
  525         "reserved",
  526         "tone",
  527         "simulated stereo",
  528         "headphone",
  529         "bass boost",
  530         "18 bit DAC",
  531         "20 bit DAC",
  532         "18 bit ADC",
  533         "20 bit ADC"
  534 };
  535 
  536 
  537 int     ac97_str_equal(const char *, const char *);
  538 void    ac97_setup_source_info(struct ac97_softc *);
  539 void    ac97_setup_defaults(struct ac97_softc *);
  540 int     ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *);
  541 int     ac97_write(struct ac97_softc *, u_int8_t, u_int16_t);
  542 
  543 
  544 #ifdef AUDIO_DEBUG
  545 #define DPRINTF(x)      if (ac97debug) printf x
  546 #define DPRINTFN(n,x)   if (ac97debug>(n)) printf x
  547 #ifdef AC97_DEBUG
  548 int     ac97debug = 1;
  549 #else
  550 int     ac97debug = 0;
  551 #endif
  552 #else
  553 #define DPRINTF(x)
  554 #define DPRINTFN(n,x)
  555 #endif
  556 
  557 int
  558 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
  559 {
  560         int error;
  561 
  562         if (((as->host_flags & AC97_HOST_DONT_READ) &&
  563             (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
  564             reg != AC97_REG_RESET)) ||
  565             (as->host_flags & AC97_HOST_DONT_READANY)) {
  566                 *val = as->shadow_reg[reg >> 1];
  567                 return (0);
  568         }
  569 
  570         if ((error = as->host_if->read(as->host_if->arg, reg, val)))
  571                 *val = as->shadow_reg[reg >> 1];
  572         return (error);
  573 }
  574 
  575 int
  576 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
  577 {
  578         as->shadow_reg[reg >> 1] = val;
  579         return (as->host_if->write(as->host_if->arg, reg, val));
  580 }
  581 
  582 void
  583 ac97_setup_defaults(struct ac97_softc *as)
  584 {
  585         int idx;
  586 
  587         bzero(as->shadow_reg, sizeof(as->shadow_reg));
  588 
  589         for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
  590                 const struct ac97_source_info *si = &source_info[idx];
  591 
  592                 ac97_write(as, si->reg, si->default_value);
  593         }
  594 }
  595 
  596 void
  597 ac97_restore_shadow(struct ac97_codec_if *self)
  598 {
  599         struct ac97_softc *as = (struct ac97_softc *)self;
  600         int idx;
  601 
  602         for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
  603                 const struct ac97_source_info *si = &source_info[idx];
  604 
  605                 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
  606         }
  607 }
  608 
  609 int
  610 ac97_str_equal(const char *a, const char *b)
  611 {
  612         return ((a == b) || (a && b && (!strcmp(a, b))));
  613 }
  614 
  615 void
  616 ac97_setup_source_info(struct ac97_softc *as)
  617 {
  618         struct ac97_source_info *si, *si2;
  619         int idx, ouridx;
  620 
  621         for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
  622                 si = &as->source_info[ouridx];
  623 
  624                 bcopy(&source_info[idx], si, sizeof(*si));
  625 
  626                 switch (si->type) {
  627                 case AUDIO_MIXER_CLASS:
  628                         si->mixer_class = ouridx;
  629                         ouridx++;
  630                         break;
  631                 case AUDIO_MIXER_VALUE:
  632                         /* Todo - Test to see if it works */
  633                         ouridx++;
  634 
  635                         /* Add an entry for mute, if necessary */
  636                         if (si->mute) {
  637                                 si = &as->source_info[ouridx];
  638                                 bcopy(&source_info[idx], si, sizeof(*si));
  639                                 si->qualifier = AudioNmute;
  640                                 si->type = AUDIO_MIXER_ENUM;
  641                                 si->info = &ac97_on_off;
  642                                 si->info_size = sizeof(ac97_on_off);
  643                                 si->bits = 1;
  644                                 si->ofs = 15;
  645                                 si->mute = 0;
  646                                 si->polarity = 0;
  647                                 ouridx++;
  648                         }
  649                         break;
  650                 case AUDIO_MIXER_ENUM:
  651                         /* Todo - Test to see if it works */
  652                         ouridx++;
  653                         break;
  654                 default:
  655                         printf ("ac97: shouldn't get here\n");
  656                         break;
  657                 }
  658         }
  659 
  660         as->num_source_info = ouridx;
  661 
  662         for (idx = 0; idx < as->num_source_info; idx++) {
  663                 int idx2, previdx;
  664 
  665                 si = &as->source_info[idx];
  666 
  667                 /* Find mixer class */
  668                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
  669                         si2 = &as->source_info[idx2];
  670 
  671                         if (si2->type == AUDIO_MIXER_CLASS &&
  672                             ac97_str_equal(si->class, si2->class)) {
  673                                 si->mixer_class = idx2;
  674                         }
  675                 }
  676 
  677 
  678                 /* Setup prev and next pointers */
  679                 if (si->prev != 0 || si->qualifier)
  680                         continue;
  681 
  682                 si->prev = AUDIO_MIXER_LAST;
  683                 previdx = idx;
  684 
  685                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
  686                         if (idx2 == idx)
  687                                 continue;
  688 
  689                         si2 = &as->source_info[idx2];
  690 
  691                         if (!si2->prev &&
  692                             ac97_str_equal(si->class, si2->class) &&
  693                             ac97_str_equal(si->device, si2->device)) {
  694                                 as->source_info[previdx].next = idx2;
  695                                 as->source_info[idx2].prev = previdx;
  696 
  697                                 previdx = idx2;
  698                         }
  699                 }
  700 
  701                 as->source_info[previdx].next = AUDIO_MIXER_LAST;
  702         }
  703 }
  704 
  705 int
  706 ac97_attach(struct ac97_host_if *host_if)
  707 {
  708         struct ac97_softc *as;
  709         u_int16_t id1, id2;
  710         u_int32_t id;
  711         mixer_ctrl_t ctl;
  712         int error, i;
  713         void (*initfunc)(struct ac97_softc *);
  714 
  715         initfunc = NULL;
  716 
  717         if (!(as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_NOWAIT)))
  718                 return (ENOMEM);
  719 
  720         bzero(as, sizeof(*as));
  721 
  722         as->codec_if.vtbl = &ac97civ;
  723         as->host_if = host_if;
  724 
  725         if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
  726                 free(as, M_DEVBUF);
  727                 return (error);
  728         }
  729 
  730         host_if->reset(host_if->arg);
  731         DELAY(1000);
  732 
  733         host_if->write(host_if->arg, AC97_REG_POWER, 0);
  734         host_if->write(host_if->arg, AC97_REG_RESET, 0);
  735         DELAY(10000);
  736 
  737         if (host_if->flags)
  738                 as->host_flags = host_if->flags(host_if->arg);
  739 
  740         ac97_setup_defaults(as);
  741         ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
  742         ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
  743         ac97_read(as, AC97_REG_RESET, &as->caps);
  744 
  745         id = (id1 << 16) | id2;
  746         if (id) {
  747                 register const struct ac97_vendorid *vendor;
  748                 register const struct ac97_codecid *codec;
  749 
  750                 printf("ac97: codec id 0x%08x", id);
  751                 for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
  752                      sizeof(ac97_vendors[0]) - 1];
  753                      vendor >= ac97_vendors; vendor--) {
  754                         if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
  755                                 printf(" (%s", vendor->name);
  756                                 for (codec = &vendor->codecs[vendor->num-1];
  757                                      codec >= vendor->codecs; codec--) {
  758                                         if (codec->id == (id & codec->mask))
  759                                                 break;
  760                                 }
  761                                 if (codec >= vendor->codecs && codec->mask) {
  762                                         printf(" %s", codec->name);
  763                                         initfunc = codec->init;
  764                                 } else
  765                                         printf(" <%02x>", id & 0xff);
  766                                 if (codec >= vendor->codecs && codec->rev)
  767                                         printf(" rev %d", id & codec->rev);
  768                                 printf(")");
  769                                 break;
  770                         }
  771                 }
  772                 printf("\n");
  773         } else
  774                 printf("ac97: codec id not read\n");
  775 
  776         if (as->caps) {
  777                 printf("ac97: codec features ");
  778                 for (i = 0; i < 10; i++) {
  779                         if (as->caps & (1 << i))
  780                                 printf("%s, ", ac97feature[i]);
  781                 }
  782                 printf("%s\n",
  783                     ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
  784         }
  785 
  786         ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
  787         if (as->ext_id)
  788                 DPRINTF(("ac97: ext id %b\n", as->ext_id,
  789                     AC97_EXT_AUDIO_BITS));
  790         if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM)) {
  791                 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &id1);
  792                 if (as->ext_id & AC97_EXT_AUDIO_VRA)
  793                         id1 |= AC97_EXT_AUDIO_VRA;
  794                 if (as->ext_id & AC97_EXT_AUDIO_VRM)
  795                         id1 |= AC97_EXT_AUDIO_VRM;
  796                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, id1);
  797         }
  798 
  799         ac97_setup_source_info(as);
  800 
  801         /* use initfunc for specific device */
  802         if (initfunc != NULL)
  803                 initfunc(as);
  804 
  805         /* Just enable the DAC and master volumes by default */
  806         bzero(&ctl, sizeof(ctl));
  807 
  808         ctl.type = AUDIO_MIXER_ENUM;
  809         ctl.un.ord = 0;  /* off */
  810         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
  811             AudioNmaster, AudioNmute);
  812         ac97_mixer_set_port(&as->codec_if, &ctl);
  813 
  814         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
  815             AudioNdac, AudioNmute);
  816         ac97_mixer_set_port(&as->codec_if, &ctl);
  817 
  818         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
  819             AudioNvolume, AudioNmute);
  820         ac97_mixer_set_port(&as->codec_if, &ctl);
  821 
  822         ctl.type = AUDIO_MIXER_ENUM;
  823         ctl.un.ord = 0;
  824         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
  825             AudioNsource, NULL);
  826         ac97_mixer_set_port(&as->codec_if, &ctl);
  827 
  828         return (0);
  829 }
  830 
  831 int
  832 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
  833 {
  834         struct ac97_softc *as = (struct ac97_softc *)codec_if;
  835 
  836         if (dip->index < as->num_source_info) {
  837                 struct ac97_source_info *si = &as->source_info[dip->index];
  838                 const char *name;
  839 
  840                 dip->type = si->type;
  841                 dip->mixer_class = si->mixer_class;
  842                 dip->prev = si->prev;
  843                 dip->next = si->next;
  844 
  845                 if (si->qualifier)
  846                         name = si->qualifier;
  847                 else if (si->device)
  848                         name = si->device;
  849                 else if (si->class)
  850                         name = si->class;
  851 
  852                 if (name)
  853                         strlcpy(dip->label.name, name, sizeof dip->label.name);
  854 
  855                 bcopy(si->info, &dip->un, si->info_size);
  856 
  857                 /* Set the delta for volume sources */
  858                 if (dip->type == AUDIO_MIXER_VALUE)
  859                         dip->un.v.delta = 1 << (8 - si->bits);
  860 
  861                 return (0);
  862         }
  863 
  864         return (ENXIO);
  865 }
  866 
  867 int
  868 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
  869 {
  870         struct ac97_softc *as = (struct ac97_softc *)codec_if;
  871         struct ac97_source_info *si = &as->source_info[cp->dev];
  872         u_int16_t mask;
  873         u_int16_t val, newval;
  874         int error;
  875 
  876         if (cp->dev < 0 || cp->dev >= as->num_source_info ||
  877             cp->type != si->type)
  878                 return (EINVAL);
  879 
  880         ac97_read(as, si->reg, &val);
  881 
  882         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
  883 
  884         mask = (1 << si->bits) - 1;
  885 
  886         switch (cp->type) {
  887         case AUDIO_MIXER_ENUM:
  888                 if (cp->un.ord > mask || cp->un.ord < 0)
  889                         return (EINVAL);
  890 
  891                 newval = (cp->un.ord << si->ofs);
  892                 if (si->reg == AC97_REG_RECORD_SELECT) {
  893                         newval |= (newval << (8 + si->ofs));
  894                         mask |= (mask << 8);
  895                 }
  896 
  897                 if (si->mute) {
  898                         newval |= newval << 8;
  899                         mask |= mask << 8;
  900                 }
  901 
  902                 break;
  903         case AUDIO_MIXER_VALUE:
  904         {
  905                 const struct audio_mixer_value *value = si->info;
  906                 u_int16_t  l, r;
  907 
  908                 if (cp->un.value.num_channels <= 0 ||
  909                     cp->un.value.num_channels > value->num_channels)
  910                         return (EINVAL);
  911 
  912                 if (cp->un.value.num_channels == 1) {
  913                         l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
  914                 } else {
  915                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
  916                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
  917                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
  918                         } else {
  919                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
  920                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
  921                         }
  922                 }
  923 
  924                 if (!si->polarity) {
  925                         l = 255 - l;
  926                         r = 255 - r;
  927                 }
  928 
  929                 l >>= 8 - si->bits;
  930                 r >>= 8 - si->bits;
  931 
  932                 newval = ((l & mask) << si->ofs);
  933                 if (value->num_channels == 2) {
  934                         newval |= ((r & mask) << (si->ofs + 8));
  935                         mask |= (mask << 8);
  936                 }
  937 
  938                 break;
  939         }
  940         default:
  941                 return (EINVAL);
  942         }
  943 
  944         mask = mask << si->ofs;
  945         error = ac97_write(as, si->reg, (val & ~mask) | newval);
  946         if (error)
  947                 return (error);
  948 
  949         return (0);
  950 }
  951 
  952 int
  953 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, char *class,
  954     char *device, char *qualifier)
  955 {
  956         struct ac97_softc *as = (struct ac97_softc *)codec_if;
  957         int idx;
  958 
  959         for (idx = 0; idx < as->num_source_info; idx++) {
  960                 struct ac97_source_info *si = &as->source_info[idx];
  961                 if (ac97_str_equal(class, si->class) &&
  962                     ac97_str_equal(device, si->device) &&
  963                     ac97_str_equal(qualifier, si->qualifier))
  964                         return (idx);
  965         }
  966 
  967         return (-1);
  968 }
  969 
  970 int
  971 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
  972 {
  973         struct ac97_softc *as = (struct ac97_softc *)codec_if;
  974         struct ac97_source_info *si = &as->source_info[cp->dev];
  975         u_int16_t mask;
  976         u_int16_t val;
  977 
  978         if (cp->dev < 0 || cp->dev >= as->num_source_info ||
  979             cp->type != si->type)
  980                 return (EINVAL);
  981 
  982         ac97_read(as, si->reg, &val);
  983 
  984         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
  985 
  986         mask = (1 << si->bits) - 1;
  987 
  988         switch (cp->type) {
  989         case AUDIO_MIXER_ENUM:
  990                 cp->un.ord = (val >> si->ofs) & mask;
  991                 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
  992                     mask, cp->un.ord));
  993                 break;
  994         case AUDIO_MIXER_VALUE:
  995         {
  996                 const struct audio_mixer_value *value = si->info;
  997                 u_int16_t  l, r;
  998 
  999                 if ((cp->un.value.num_channels <= 0) ||
 1000                     (cp->un.value.num_channels > value->num_channels))
 1001                         return (EINVAL);
 1002 
 1003                 if (value->num_channels == 1)
 1004                         l = r = (val >> si->ofs) & mask;
 1005                 else {
 1006                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
 1007                                 l = (val >> si->ofs) & mask;
 1008                                 r = (val >> (si->ofs + 8)) & mask;
 1009                         } else {
 1010                                 r = (val >> si->ofs) & mask;
 1011                                 l = (val >> (si->ofs + 8)) & mask;
 1012                         }
 1013                 }
 1014 
 1015                 l <<= 8 - si->bits;
 1016                 r <<= 8 - si->bits;
 1017                 if (!si->polarity) {
 1018                         l = 255 - l;
 1019                         r = 255 - r;
 1020                 }
 1021 
 1022                 /*
 1023                  * The EAP driver averages l and r for stereo
 1024                  * channels that are requested in MONO mode. Does this
 1025                  * make sense?
 1026                  */
 1027                 if (cp->un.value.num_channels == 1) {
 1028                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
 1029                 } else if (cp->un.value.num_channels == 2) {
 1030                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
 1031                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
 1032                 }
 1033 
 1034                 break;
 1035         }
 1036         default:
 1037                 return (EINVAL);
 1038         }
 1039 
 1040         return (0);
 1041 }
 1042 
 1043 int
 1044 ac97_set_rate(struct ac97_codec_if *codec_if, struct audio_params *p,
 1045     int mode)
 1046 {
 1047         struct ac97_softc *as = (struct ac97_softc *)codec_if;
 1048         u_int16_t reg, val, regval, id = 0;
 1049 
 1050         DPRINTFN(5, ("set_rate(%lu) ", p->sample_rate));
 1051 
 1052         if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
 1053                 p->sample_rate = AC97_SINGLERATE;
 1054                 return (0);
 1055         }
 1056 
 1057         if (p->sample_rate > 0xffff) {
 1058                 if (mode != AUMODE_PLAY)
 1059                         return (EINVAL);
 1060                 if (!(as->ext_id & AC97_EXT_AUDIO_DRA))
 1061                         return (EINVAL);
 1062                 if (ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &id))
 1063                         return (EIO);
 1064                 id |= AC97_EXT_AUDIO_DRA;
 1065                 if (ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, id))
 1066                         return (EIO);
 1067                 p->sample_rate /= 2;
 1068         }
 1069 
 1070         /* i guess it's better w/o clicks and squeecks when changing the rate */
 1071         if (ac97_read(as, AC97_REG_POWER, &val) ||
 1072             ac97_write(as, AC97_REG_POWER, val |
 1073               (mode == AUMODE_PLAY? AC97_POWER_OUT : AC97_POWER_IN)))
 1074                 return (EIO);
 1075 
 1076         reg = mode == AUMODE_PLAY ?
 1077             AC97_REG_FRONT_DAC_RATE : AC97_REG_PCM_ADC_RATE;
 1078 
 1079         if (ac97_write(as, reg, (u_int16_t) p->sample_rate) ||
 1080             ac97_read(as, reg, &regval))
 1081                 return (EIO);
 1082         p->sample_rate = regval;
 1083         if (id & AC97_EXT_AUDIO_DRA)
 1084                 p->sample_rate *= 2;
 1085 
 1086         DPRINTFN(5, (" %lu\n", regval));
 1087 
 1088         if (ac97_write(as, AC97_REG_POWER, val))
 1089                 return (EIO);
 1090 
 1091         return (0);
 1092 }
 1093 
 1094 /*
 1095  * Codec-dependent initialization
 1096  */
 1097 
 1098 #define AC97_AD1886_JACK_SENSE  0x72
 1099 
 1100 void
 1101 ac97_ad1886_init(struct ac97_softc *as)
 1102 {
 1103         ac97_write(as, AC97_AD1886_JACK_SENSE, 0x0010);
 1104 }
 1105         
 1106 void
 1107 ac97_ad198x_init(struct ac97_softc *as)
 1108 {
 1109         int i;
 1110         u_int16_t misc;
 1111 
 1112         ac97_read(as, AC97_AD_REG_MISC, &misc);
 1113         ac97_write(as, AC97_AD_REG_MISC,
 1114             misc|AC97_AD_MISC_HPSEL|AC97_AD_MISC_LOSEL);
 1115 
 1116         for (i = 0; i < as->num_source_info; i++) {
 1117                 if (as->source_info[i].reg == AC97_REG_SURROUND_VOLUME)
 1118                         as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
 1119                 else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME) {
 1120                         as->source_info[i].reg = AC97_REG_SURROUND_VOLUME;
 1121                         if (as->source_info[i].type == AUDIO_MIXER_ENUM) {
 1122                                 as->source_info[i].mute = 1;
 1123                                 as->source_info[i].ofs = 7;
 1124                         }
 1125                 }
 1126         }
 1127 }
 1128 
 1129 void
 1130 ac97_alc655_init(struct ac97_softc *as)
 1131 {
 1132         u_int16_t misc;
 1133 
 1134         ac97_read(as, AC97_AV_REG_MISC, &misc);
 1135         if (as->host_flags & AC97_HOST_DONT_ENABLE_SPDIF) {
 1136                 misc &= ~AC97_AV_MISC_SPDIFEN;
 1137         } else  {
 1138                 misc |= AC97_AV_MISC_SPDIFEN;
 1139         }
 1140         misc &= ~AC97_AV_MISC_VREFDIS;
 1141         ac97_write(as, AC97_AV_REG_MISC, misc);
 1142 
 1143         ac97_write(as, AC97_AV_REG_MULTICH, AC97_AV_MULTICH_MAGIC);
 1144 }
 1145 
 1146 void
 1147 ac97_cx20468_init(struct ac97_softc *as)
 1148 {
 1149         u_int16_t misc;
 1150 
 1151         ac97_read(as, AC97_CX_REG_MISC, &misc);
 1152         ac97_write(as, AC97_CX_REG_MISC, misc &
 1153             ~(AC97_CX_SPDIFEN | AC97_CX_COPYRIGHT | AC97_CX_MASK));
 1154 }

/* [<][>][^][v][top][bottom][index][help] */