LCOV - code coverage report
Current view: top level - dev/ic - ac97.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 506 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 24 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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" }, 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           0 : ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
     610             : {
     611             :         int error;
     612             : 
     613           0 :         if (((as->host_flags & AC97_HOST_DONT_READ) &&
     614           0 :             (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
     615           0 :             reg != AC97_REG_RESET)) ||
     616           0 :             (as->host_flags & AC97_HOST_DONT_READANY)) {
     617           0 :                 *val = as->shadow_reg[reg >> 1];
     618           0 :                 return (0);
     619             :         }
     620             : 
     621           0 :         if ((error = as->host_if->read(as->host_if->arg, reg, val)))
     622           0 :                 *val = as->shadow_reg[reg >> 1];
     623           0 :         return (error);
     624           0 : }
     625             : 
     626             : int
     627           0 : ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
     628             : {
     629           0 :         as->shadow_reg[reg >> 1] = val;
     630           0 :         return (as->host_if->write(as->host_if->arg, reg, val));
     631             : }
     632             : 
     633             : void
     634           0 : ac97_setup_defaults(struct ac97_softc *as)
     635             : {
     636             :         int idx;
     637             : 
     638           0 :         bzero(as->shadow_reg, sizeof(as->shadow_reg));
     639             : 
     640           0 :         for (idx = 0; idx < nitems(source_info); idx++) {
     641           0 :                 const struct ac97_source_info *si = &source_info[idx];
     642             : 
     643           0 :                 ac97_write(as, si->reg, si->default_value);
     644             :         }
     645           0 : }
     646             : 
     647             : int
     648           0 : ac97_str_equal(const char *a, const char *b)
     649             : {
     650           0 :         return ((a == b) || (a && b && (!strcmp(a, b))));
     651             : }
     652             : 
     653             : int
     654           0 : ac97_check_capability(struct ac97_softc *as, int check)
     655             : {
     656           0 :         switch (check) {
     657             :         case CHECK_NONE:
     658           0 :                 return 1;
     659             :         case CHECK_SURROUND:
     660           0 :                 return as->ext_id & AC97_EXT_AUDIO_SDAC;
     661             :         case CHECK_CENTER:
     662           0 :                 return as->ext_id & AC97_EXT_AUDIO_CDAC;
     663             :         case CHECK_LFE:
     664           0 :                 return as->ext_id & AC97_EXT_AUDIO_LDAC;
     665             :         case CHECK_SPDIF:
     666           0 :                 return as->ext_id & AC97_EXT_AUDIO_SPDIF;
     667             :         case CHECK_HEADPHONES:
     668           0 :                 return as->caps & AC97_CAPS_HEADPHONES;
     669             :         case CHECK_TONE:
     670           0 :                 return as->caps & AC97_CAPS_TONECTRL;
     671             :         case CHECK_MIC:
     672           0 :                 return as->caps & AC97_CAPS_MICIN;
     673             :         case CHECK_LOUDNESS:
     674           0 :                 return as->caps & AC97_CAPS_LOUDNESS;
     675             :         case CHECK_3D:
     676           0 :                 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
     677             :         default:
     678           0 :                 printf("%s: internal error: feature=%d\n", __func__, check);
     679           0 :                 return 0;
     680             :         }
     681           0 : }
     682             : 
     683             : void
     684           0 : ac97_setup_source_info(struct ac97_softc *as)
     685             : {
     686             :         struct ac97_source_info *si, *si2;
     687             :         int idx, ouridx;
     688             : 
     689           0 :         for (idx = 0, ouridx = 0; idx < nitems(source_info); idx++) {
     690           0 :                 si = &as->source_info[ouridx];
     691             : 
     692           0 :                 if (!ac97_check_capability(as, source_info[idx].req_feature))
     693             :                         continue;
     694             : 
     695           0 :                 bcopy(&source_info[idx], si, sizeof(*si));
     696             : 
     697           0 :                 switch (si->type) {
     698             :                 case AUDIO_MIXER_CLASS:
     699           0 :                         si->mixer_class = ouridx;
     700           0 :                         ouridx++;
     701           0 :                         break;
     702             :                 case AUDIO_MIXER_VALUE:
     703             :                         /* Todo - Test to see if it works */
     704           0 :                         ouridx++;
     705             : 
     706             :                         /* Add an entry for mute, if necessary */
     707           0 :                         if (si->mute) {
     708           0 :                                 si = &as->source_info[ouridx];
     709           0 :                                 bcopy(&source_info[idx], si, sizeof(*si));
     710           0 :                                 si->qualifier = AudioNmute;
     711           0 :                                 si->type = AUDIO_MIXER_ENUM;
     712           0 :                                 si->info = &ac97_on_off;
     713           0 :                                 si->info_size = sizeof(ac97_on_off);
     714           0 :                                 si->bits = 1;
     715           0 :                                 si->ofs = 15;
     716           0 :                                 si->mute = 0;
     717           0 :                                 si->polarity = 0;
     718           0 :                                 ouridx++;
     719           0 :                         }
     720             :                         break;
     721             :                 case AUDIO_MIXER_ENUM:
     722             :                         /* Todo - Test to see if it works */
     723           0 :                         ouridx++;
     724           0 :                         break;
     725             :                 default:
     726           0 :                         printf ("ac97: shouldn't get here\n");
     727           0 :                         break;
     728             :                 }
     729             :         }
     730             : 
     731           0 :         as->num_source_info = ouridx;
     732             : 
     733           0 :         for (idx = 0; idx < as->num_source_info; idx++) {
     734             :                 int idx2, previdx;
     735             : 
     736           0 :                 si = &as->source_info[idx];
     737             : 
     738             :                 /* Find mixer class */
     739           0 :                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
     740           0 :                         si2 = &as->source_info[idx2];
     741             : 
     742           0 :                         if (si2->type == AUDIO_MIXER_CLASS &&
     743           0 :                             ac97_str_equal(si->class, si2->class)) {
     744           0 :                                 si->mixer_class = idx2;
     745           0 :                         }
     746             :                 }
     747             : 
     748             : 
     749             :                 /* Setup prev and next pointers */
     750           0 :                 if (si->prev != 0 || si->qualifier)
     751           0 :                         continue;
     752             : 
     753           0 :                 si->prev = AUDIO_MIXER_LAST;
     754             :                 previdx = idx;
     755             : 
     756           0 :                 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
     757           0 :                         if (idx2 == idx)
     758             :                                 continue;
     759             : 
     760           0 :                         si2 = &as->source_info[idx2];
     761             : 
     762           0 :                         if (!si2->prev &&
     763           0 :                             ac97_str_equal(si->class, si2->class) &&
     764           0 :                             ac97_str_equal(si->device, si2->device)) {
     765           0 :                                 as->source_info[previdx].next = idx2;
     766           0 :                                 as->source_info[idx2].prev = previdx;
     767             : 
     768             :                                 previdx = idx2;
     769           0 :                         }
     770             :                 }
     771             : 
     772           0 :                 as->source_info[previdx].next = AUDIO_MIXER_LAST;
     773           0 :         }
     774           0 : }
     775             : 
     776             : int
     777           0 : ac97_attach(struct ac97_host_if *host_if)
     778             : {
     779             :         struct ac97_softc *as;
     780           0 :         u_int16_t id1, id2, val;
     781             :         u_int32_t id;
     782           0 :         u_int16_t extstat, rate;
     783           0 :         mixer_ctrl_t ctl;
     784             :         int error, i;
     785             :         void (*initfunc)(struct ac97_softc *, int);
     786             : 
     787             :         initfunc = NULL;
     788             : 
     789           0 :         if (!(as = malloc(sizeof(*as), M_DEVBUF, M_NOWAIT | M_ZERO)))
     790           0 :                 return (ENOMEM);
     791             : 
     792           0 :         as->codec_if.as = as;
     793           0 :         as->codec_if.vtbl = &ac97civ;
     794           0 :         as->host_if = host_if;
     795             : 
     796           0 :         if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
     797           0 :                 free(as, M_DEVBUF, sizeof(*as));
     798           0 :                 return (error);
     799             :         }
     800             : 
     801           0 :         host_if->reset(host_if->arg);
     802           0 :         DELAY(1000);
     803             : 
     804           0 :         host_if->write(host_if->arg, AC97_REG_POWER, 0);
     805           0 :         host_if->write(host_if->arg, AC97_REG_RESET, 0);
     806           0 :         DELAY(10000);
     807             : 
     808           0 :         if (host_if->flags)
     809           0 :                 as->host_flags = host_if->flags(host_if->arg);
     810             : 
     811           0 :         ac97_setup_defaults(as);
     812           0 :         ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
     813           0 :         ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
     814           0 :         ac97_read(as, AC97_REG_RESET, &as->caps);
     815             : 
     816           0 :         id = (id1 << 16) | id2;
     817           0 :         if (id) {
     818             :                 register const struct ac97_vendorid *vendor;
     819             :                 register const struct ac97_codecid *codec;
     820             : 
     821           0 :                 printf("ac97: codec id 0x%08x", id);
     822           0 :                 for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
     823             :                      sizeof(ac97_vendors[0]) - 1];
     824           0 :                      vendor >= ac97_vendors; vendor--) {
     825           0 :                         if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
     826           0 :                                 printf(" (%s", vendor->name);
     827           0 :                                 for (codec = &vendor->codecs[vendor->num-1];
     828           0 :                                      codec >= vendor->codecs; codec--) {
     829           0 :                                         if (codec->id == (id & codec->mask))
     830             :                                                 break;
     831             :                                 }
     832           0 :                                 if (codec >= vendor->codecs && codec->mask) {
     833           0 :                                         printf(" %s", codec->name);
     834           0 :                                         initfunc = codec->init;
     835           0 :                                 } else
     836           0 :                                         printf(" <%02x>", id & 0xff);
     837           0 :                                 if (codec >= vendor->codecs && codec->rev)
     838           0 :                                         printf(" rev %d", id & codec->rev);
     839           0 :                                 printf(")");
     840           0 :                                 break;
     841             :                         }
     842             :                 }
     843           0 :                 printf("\n");
     844           0 :         } else
     845           0 :                 printf("ac97: codec id not read\n");
     846             : 
     847           0 :         if (as->caps) {
     848           0 :                 printf("ac97: codec features ");
     849           0 :                 for (i = 0; i < 10; i++) {
     850           0 :                         if (as->caps & (1 << i))
     851           0 :                                 printf("%s, ", ac97feature[i]);
     852             :                 }
     853           0 :                 printf("%s\n",
     854           0 :                     ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
     855           0 :         }
     856             : 
     857             : 
     858           0 :         as->ac97_clock = AC97_STANDARD_CLOCK;
     859           0 :         ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
     860           0 :         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           0 :                 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
     866           0 :                 extstat &= ~AC97_EXT_AUDIO_DRA;
     867             : 
     868           0 :                 if (as->ext_id & AC97_EXT_AUDIO_VRM)
     869           0 :                         extstat |= AC97_EXT_AUDIO_VRM;
     870             : 
     871           0 :                 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
     872           0 :                         extstat |= AC97_EXT_AUDIO_LDAC;
     873           0 :                 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
     874           0 :                         extstat |= AC97_EXT_AUDIO_SDAC;
     875           0 :                 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
     876           0 :                         extstat |= AC97_EXT_AUDIO_CDAC;
     877           0 :                 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           0 :                         extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
     883           0 :                         extstat |= AC97_EXT_AUDIO_SPSA34;
     884           0 :                         ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
     885           0 :                         val = (val & ~AC97_SPDIF_SPSR_MASK) |
     886             :                             AC97_SPDIF_SPSR_48K;
     887           0 :                         ac97_write(as, AC97_REG_SPDIF_CTRL, val);
     888           0 :                 }
     889           0 :                 if (as->ext_id & AC97_EXT_AUDIO_VRA)
     890           0 :                         extstat |= AC97_EXT_AUDIO_VRA;
     891           0 :                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
     892           0 :                 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           0 :                         ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
     896           0 :                         ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
     897           0 :                         if (rate != 44100) {
     898             :                                 /* We can't believe ext_id */
     899           0 :                                 as->ext_id = 0;
     900           0 :                         }
     901             :                         /* restore the default value */
     902           0 :                         ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
     903             :                                    AC97_SINGLE_RATE);
     904           0 :                 }
     905             :         }
     906             : 
     907           0 :         ac97_setup_source_info(as);
     908             : 
     909           0 :         DELAY(900 * 1000);
     910             : 
     911             :         /* use initfunc for specific device */
     912           0 :         as->codec_if.initfunc = initfunc;
     913           0 :         if (initfunc != NULL)
     914           0 :                 initfunc(as, 0);
     915             : 
     916             :         /* Just enable the DAC and master volumes by default */
     917           0 :         bzero(&ctl, sizeof(ctl));
     918             : 
     919           0 :         ctl.type = AUDIO_MIXER_ENUM;
     920           0 :         ctl.un.ord = 0;  /* off */
     921           0 :         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
     922             :             AudioNmaster, AudioNmute);
     923           0 :         ac97_mixer_set_port(&as->codec_if, &ctl);
     924             : 
     925           0 :         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
     926             :             AudioNdac, AudioNmute);
     927           0 :         ac97_mixer_set_port(&as->codec_if, &ctl);
     928             : 
     929           0 :         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
     930             :             AudioNvolume, AudioNmute);
     931           0 :         ac97_mixer_set_port(&as->codec_if, &ctl);
     932             : 
     933           0 :         ctl.type = AUDIO_MIXER_ENUM;
     934           0 :         ctl.un.ord = 0;
     935           0 :         ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
     936             :             AudioNsource, NULL);
     937           0 :         ac97_mixer_set_port(&as->codec_if, &ctl);
     938             : 
     939           0 :         return (0);
     940           0 : }
     941             : 
     942             : int
     943           0 : ac97_resume(struct ac97_host_if *host_if, struct ac97_codec_if *codec_if)
     944             : {
     945           0 :         struct ac97_softc *as = codec_if->as;
     946           0 :         u_int16_t val, extstat;
     947             : 
     948           0 :         host_if->reset(host_if->arg);
     949           0 :         DELAY(1000);
     950             : 
     951           0 :         host_if->write(host_if->arg, AC97_REG_POWER, 0);
     952           0 :         host_if->write(host_if->arg, AC97_REG_RESET, 0);
     953           0 :         DELAY(10000);
     954             : 
     955           0 :         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           0 :                 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
     961           0 :                 extstat &= ~AC97_EXT_AUDIO_DRA;
     962             : 
     963           0 :                 if (as->ext_id & AC97_EXT_AUDIO_VRM)
     964           0 :                         extstat |= AC97_EXT_AUDIO_VRM;
     965             : 
     966           0 :                 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
     967           0 :                         extstat |= AC97_EXT_AUDIO_LDAC;
     968           0 :                 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
     969           0 :                         extstat |= AC97_EXT_AUDIO_SDAC;
     970           0 :                 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
     971           0 :                         extstat |= AC97_EXT_AUDIO_CDAC;
     972             : 
     973           0 :                 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
     974           0 :                         extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
     975           0 :                         extstat |= AC97_EXT_AUDIO_SPSA34;
     976           0 :                         ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
     977           0 :                         val = (val & ~AC97_SPDIF_SPSR_MASK) |
     978             :                             AC97_SPDIF_SPSR_48K;
     979           0 :                         ac97_write(as, AC97_REG_SPDIF_CTRL, val);
     980           0 :                 }
     981           0 :                 if (as->ext_id & AC97_EXT_AUDIO_VRA)
     982           0 :                         extstat |= AC97_EXT_AUDIO_VRA;
     983           0 :                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
     984           0 :         }
     985             : 
     986             :         /* use initfunc for specific device */
     987           0 :         if (as->codec_if.initfunc != NULL)
     988           0 :                 as->codec_if.initfunc(as, 1);
     989             : 
     990           0 :         return (0);
     991           0 : }
     992             : 
     993             : void
     994           0 : ac97_lock(struct ac97_codec_if *codec_if)
     995             : {
     996           0 :         struct ac97_softc *as = (struct ac97_softc *)codec_if;
     997           0 :         as->lock_counter++;
     998           0 : }
     999             : 
    1000             : void
    1001           0 : ac97_unlock(struct ac97_codec_if *codec_if)
    1002             : {
    1003           0 :         struct ac97_softc *as = (struct ac97_softc *)codec_if;
    1004           0 :         as->lock_counter--;
    1005           0 : }
    1006             : 
    1007             : int
    1008           0 : ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
    1009             : {
    1010           0 :         struct ac97_softc *as = (struct ac97_softc *)codec_if;
    1011             : 
    1012           0 :         if (dip->index < as->num_source_info && dip->index >= 0) {
    1013           0 :                 struct ac97_source_info *si = &as->source_info[dip->index];
    1014             :                 const char *name;
    1015             : 
    1016           0 :                 dip->type = si->type;
    1017           0 :                 dip->mixer_class = si->mixer_class;
    1018           0 :                 dip->prev = si->prev;
    1019           0 :                 dip->next = si->next;
    1020             : 
    1021           0 :                 if (si->qualifier)
    1022           0 :                         name = si->qualifier;
    1023           0 :                 else if (si->device)
    1024           0 :                         name = si->device;
    1025           0 :                 else if (si->class)
    1026           0 :                         name = si->class;
    1027             :                 else
    1028             :                         name = NULL;
    1029             : 
    1030           0 :                 if (name)
    1031           0 :                         strlcpy(dip->label.name, name, sizeof dip->label.name);
    1032             : 
    1033           0 :                 bcopy(si->info, &dip->un, si->info_size);
    1034             : 
    1035             :                 /* Set the delta for volume sources */
    1036           0 :                 if (dip->type == AUDIO_MIXER_VALUE)
    1037           0 :                         dip->un.v.delta = 1 << (8 - si->bits);
    1038             : 
    1039             :                 return (0);
    1040             :         }
    1041             : 
    1042           0 :         return (ENXIO);
    1043           0 : }
    1044             : 
    1045             : int
    1046           0 : ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
    1047             : {
    1048           0 :         struct ac97_softc *as = (struct ac97_softc *)codec_if;
    1049             :         struct ac97_source_info *si;
    1050             :         u_int16_t mask;
    1051           0 :         u_int16_t val, newval;
    1052             :         int error, spdif;
    1053             : 
    1054           0 :         if (cp->dev < 0 || cp->dev >= as->num_source_info)
    1055           0 :                 return (EINVAL);
    1056             : 
    1057           0 :         si = &as->source_info[cp->dev];
    1058             : 
    1059           0 :         if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
    1060           0 :                 return (EINVAL);
    1061             : 
    1062           0 :         spdif = si->req_feature == CHECK_SPDIF &&
    1063           0 :             si->reg == AC97_REG_EXT_AUDIO_CTRL;
    1064           0 :         if (spdif && as->lock_counter >= 0)
    1065           0 :                 return EBUSY;
    1066             : 
    1067           0 :         ac97_read(as, si->reg, &val);
    1068             : 
    1069             :         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    1070             : 
    1071           0 :         mask = (1 << si->bits) - 1;
    1072             : 
    1073           0 :         switch (cp->type) {
    1074             :         case AUDIO_MIXER_ENUM:
    1075           0 :                 if (cp->un.ord > mask || cp->un.ord < 0)
    1076           0 :                         return (EINVAL);
    1077             : 
    1078           0 :                 newval = (cp->un.ord << si->ofs);
    1079           0 :                 if (si->reg == AC97_REG_RECORD_SELECT) {
    1080           0 :                         newval |= (newval << (8 + si->ofs));
    1081           0 :                         mask |= (mask << 8);
    1082           0 :                         mask = mask << si->ofs;
    1083           0 :                 } else if (si->reg == AC97_REG_SURR_MASTER) {
    1084           0 :                         newval = cp->un.ord ? 0x8080 : 0x0000;
    1085             :                         mask = 0x8080;
    1086           0 :                 } else
    1087           0 :                         mask = mask << si->ofs;
    1088             : 
    1089           0 :                 if (si->mute) {
    1090           0 :                         newval |= newval << 8;
    1091           0 :                         mask |= mask << 8;
    1092           0 :                 }
    1093             : 
    1094             :                 break;
    1095             :         case AUDIO_MIXER_VALUE:
    1096             :         {
    1097           0 :                 const struct audio_mixer_value *value = si->info;
    1098             :                 u_int16_t  l, r;
    1099             : 
    1100           0 :                 if (cp->un.value.num_channels <= 0 ||
    1101           0 :                     cp->un.value.num_channels > value->num_channels)
    1102           0 :                         return (EINVAL);
    1103             : 
    1104           0 :                 if (cp->un.value.num_channels == 1) {
    1105           0 :                         l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    1106           0 :                 } else {
    1107           0 :                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    1108             :                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    1109           0 :                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    1110           0 :                         } else {
    1111             :                                 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    1112           0 :                                 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    1113             :                         }
    1114             :                 }
    1115             : 
    1116           0 :                 if (!si->polarity) {
    1117           0 :                         l = 255 - l;
    1118           0 :                         r = 255 - r;
    1119           0 :                 }
    1120             : 
    1121           0 :                 l >>= 8 - si->bits;
    1122           0 :                 r >>= 8 - si->bits;
    1123             : 
    1124           0 :                 newval = ((l & mask) << si->ofs);
    1125           0 :                 if (value->num_channels == 2) {
    1126           0 :                         newval |= ((r & mask) << (si->ofs + 8));
    1127           0 :                         mask |= (mask << 8);
    1128           0 :                 }
    1129           0 :                 mask = mask << si->ofs;
    1130           0 :                 break;
    1131             :         }
    1132             :         default:
    1133           0 :                 return (EINVAL);
    1134             :         }
    1135             : 
    1136           0 :         error = ac97_write(as, si->reg, (val & ~mask) | newval);
    1137           0 :         if (error)
    1138           0 :                 return (error);
    1139             : 
    1140           0 :         if (spdif && as->host_if->spdif_event != NULL)
    1141           0 :                 as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
    1142             : 
    1143           0 :         return (0);
    1144           0 : }
    1145             : 
    1146             : 
    1147             : int
    1148           0 : 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           0 :         u_int16_t ext_stat;
    1153           0 :         u_int16_t actual;
    1154           0 :         u_int16_t power;
    1155             :         u_int16_t power_bit;
    1156             : 
    1157           0 :         as = (struct ac97_softc *)codec_if;
    1158             : 
    1159           0 :         if ((target == AC97_REG_PCM_SURR_DAC_RATE) &&
    1160           0 :             !(as->ext_id & AC97_EXT_AUDIO_SDAC))
    1161           0 :                         return 0;
    1162           0 :         if ((target == AC97_REG_PCM_LFE_DAC_RATE) &&
    1163           0 :             !(as->ext_id & AC97_EXT_AUDIO_LDAC))
    1164           0 :                         return 0;
    1165           0 :         if (target == AC97_REG_PCM_MIC_ADC_RATE) {
    1166           0 :                 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
    1167           0 :                         *rate = AC97_SINGLE_RATE;
    1168           0 :                         return 0;
    1169             :                 }
    1170             :         } else {
    1171           0 :                 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
    1172           0 :                         *rate = AC97_SINGLE_RATE;
    1173           0 :                         return 0;
    1174             :                 }
    1175             :         }
    1176           0 :         if (as->ac97_clock == 0)
    1177           0 :                 as->ac97_clock = AC97_STANDARD_CLOCK;
    1178           0 :         value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
    1179           0 :         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           0 :         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           0 :                 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
    1194           0 :                         ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
    1195           0 :                         if (value > 0x1ffff) {
    1196           0 :                                 return EINVAL;
    1197           0 :                         } else if (value > 0xffff) {
    1198             :                                 /* Enable DRA */
    1199           0 :                                 ext_stat |= AC97_EXT_AUDIO_DRA;
    1200           0 :                                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
    1201           0 :                                 value /= 2;
    1202           0 :                         } else {
    1203             :                                 /* Disable DRA */
    1204           0 :                                 ext_stat &= ~AC97_EXT_AUDIO_DRA;
    1205           0 :                                 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
    1206             :                         }
    1207             :                 } else {
    1208           0 :                         if (value > 0xffff)
    1209           0 :                                 return EINVAL;
    1210             :                 }
    1211             :                 break;
    1212             :         case AC97_REG_PCM_LR_ADC_RATE:
    1213             :                 power_bit = AC97_POWER_IN;
    1214           0 :                 if (value > 0xffff)
    1215           0 :                         return EINVAL;
    1216             :                 break;
    1217             :         case AC97_REG_PCM_MIC_ADC_RATE:
    1218             :                 power_bit = AC97_POWER_IN;
    1219           0 :                 if (value > 0xffff)
    1220           0 :                         return EINVAL;
    1221             :                 break;
    1222             :         default:
    1223           0 :                 printf("%s: Unknown register: 0x%x\n", __func__, target);
    1224           0 :                 return EINVAL;
    1225             :         }
    1226             : 
    1227           0 :         ac97_read(as, AC97_REG_POWER, &power);
    1228           0 :         ac97_write(as, AC97_REG_POWER, power | power_bit);
    1229             : 
    1230           0 :         ac97_write(as, target, (u_int16_t)value);
    1231           0 :         ac97_read(as, target, &actual);
    1232           0 :         actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
    1233             : 
    1234           0 :         ac97_write(as, AC97_REG_POWER, power);
    1235           0 :         if (ext_stat & AC97_EXT_AUDIO_DRA) {
    1236           0 :                 *rate = actual * 2;
    1237           0 :         } else {
    1238           0 :                 *rate = actual;
    1239             :         }
    1240           0 :         return 0;
    1241           0 : }
    1242             : 
    1243             : void
    1244           0 : ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
    1245             : {
    1246             :         struct ac97_softc *as;
    1247             : 
    1248           0 :         as = (struct ac97_softc *)codec_if;
    1249           0 :         as->ac97_clock = clock;
    1250           0 : }
    1251             : 
    1252             : u_int16_t
    1253           0 : ac97_get_extcaps(struct ac97_codec_if *codec_if)
    1254             : {
    1255             :         struct ac97_softc *as;
    1256             : 
    1257           0 :         as = (struct ac97_softc *)codec_if;
    1258           0 :         return as->ext_id;
    1259             : }
    1260             : 
    1261             : int
    1262           0 : 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           0 :         if (as->num_source_info >= MAX_SOURCES) {
    1268           0 :                 printf("%s: internal error: increase MAX_SOURCES in %s\n",
    1269             :                        __func__, __FILE__);
    1270           0 :                 return -1;
    1271             :         }
    1272           0 :         if (!ac97_check_capability(as, src->req_feature))
    1273           0 :                 return -1;
    1274           0 :         ouridx = as->num_source_info;
    1275           0 :         si = &as->source_info[ouridx];
    1276           0 :         memcpy(si, src, sizeof(*si));
    1277             : 
    1278           0 :         switch (si->type) {
    1279             :         case AUDIO_MIXER_CLASS:
    1280             :         case AUDIO_MIXER_VALUE:
    1281           0 :                 printf("%s: adding class/value is not supported yet.\n",
    1282             :                        __func__);
    1283           0 :                 return -1;
    1284             :         case AUDIO_MIXER_ENUM:
    1285             :                 break;
    1286             :         default:
    1287           0 :                 printf("%s: unknown type: %d\n", __func__, si->type);
    1288           0 :                 return -1;
    1289             :         }
    1290           0 :         as->num_source_info++;
    1291             : 
    1292           0 :         si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
    1293             :                                                    NULL, NULL);
    1294             :         /* Find the root of the device */
    1295           0 :         idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
    1296           0 :                                        si->device, NULL);
    1297             :         /* Find the last item */
    1298           0 :         while (as->source_info[idx].next != AUDIO_MIXER_LAST)
    1299             :                 idx = as->source_info[idx].next;
    1300             :         /* Append */
    1301           0 :         as->source_info[idx].next = ouridx;
    1302           0 :         si->prev = idx;
    1303           0 :         si->next = AUDIO_MIXER_LAST;
    1304             : 
    1305           0 :         return 0;
    1306           0 : }
    1307             : 
    1308             : int
    1309           0 : ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, char *class,
    1310             :     char *device, char *qualifier)
    1311             : {
    1312           0 :         struct ac97_softc *as = (struct ac97_softc *)codec_if;
    1313             :         int idx;
    1314             : 
    1315           0 :         for (idx = 0; idx < as->num_source_info; idx++) {
    1316           0 :                 struct ac97_source_info *si = &as->source_info[idx];
    1317           0 :                 if (ac97_str_equal(class, si->class) &&
    1318           0 :                     ac97_str_equal(device, si->device) &&
    1319           0 :                     ac97_str_equal(qualifier, si->qualifier))
    1320           0 :                         return (idx);
    1321           0 :         }
    1322             : 
    1323           0 :         return (-1);
    1324           0 : }
    1325             : 
    1326             : int
    1327           0 : ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
    1328             : {
    1329           0 :         struct ac97_softc *as = (struct ac97_softc *)codec_if;
    1330             :         struct ac97_source_info *si;
    1331             :         u_int16_t mask;
    1332           0 :         u_int16_t val;
    1333             : 
    1334           0 :         if (cp->dev < 0 || cp->dev >= as->num_source_info)
    1335           0 :                 return (EINVAL);
    1336             : 
    1337           0 :         si = &as->source_info[cp->dev];
    1338             : 
    1339           0 :         if (cp->type != si->type)
    1340           0 :                 return (EINVAL);
    1341             : 
    1342           0 :         ac97_read(as, si->reg, &val);
    1343             : 
    1344             :         DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    1345             : 
    1346           0 :         mask = (1 << si->bits) - 1;
    1347             : 
    1348           0 :         switch (cp->type) {
    1349             :         case AUDIO_MIXER_ENUM:
    1350           0 :                 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           0 :                 break;
    1354             :         case AUDIO_MIXER_VALUE:
    1355             :         {
    1356           0 :                 const struct audio_mixer_value *value = si->info;
    1357             :                 u_int16_t  l, r;
    1358             : 
    1359           0 :                 if ((cp->un.value.num_channels <= 0) ||
    1360           0 :                     (cp->un.value.num_channels > value->num_channels))
    1361           0 :                         return (EINVAL);
    1362             : 
    1363           0 :                 if (value->num_channels == 1)
    1364           0 :                         l = r = (val >> si->ofs) & mask;
    1365             :                 else {
    1366           0 :                         if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    1367             :                                 l = (val >> si->ofs) & mask;
    1368           0 :                                 r = (val >> (si->ofs + 8)) & mask;
    1369           0 :                         } else {
    1370             :                                 r = (val >> si->ofs) & mask;
    1371           0 :                                 l = (val >> (si->ofs + 8)) & mask;
    1372             :                         }
    1373             :                 }
    1374             : 
    1375           0 :                 l <<= 8 - si->bits;
    1376           0 :                 r <<= 8 - si->bits;
    1377           0 :                 if (!si->polarity) {
    1378           0 :                         l = 255 - l;
    1379           0 :                         r = 255 - r;
    1380           0 :                 }
    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           0 :                 if (cp->un.value.num_channels == 1) {
    1388           0 :                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
    1389           0 :                 } else if (cp->un.value.num_channels == 2) {
    1390           0 :                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
    1391           0 :                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
    1392           0 :                 }
    1393             : 
    1394           0 :                 break;
    1395             :         }
    1396             :         default:
    1397           0 :                 return (EINVAL);
    1398             :         }
    1399             : 
    1400           0 :         return (0);
    1401           0 : }
    1402             : 
    1403             : 
    1404             : /*
    1405             :  * Codec-dependent initialization
    1406             :  */
    1407             : 
    1408             : void
    1409           0 : ac97_ad1885_init(struct ac97_softc *as, int resuming)
    1410             : {
    1411             :         int i;
    1412             : 
    1413           0 :         if (resuming)
    1414           0 :                 return;
    1415             : 
    1416           0 :         for (i = 0; i < as->num_source_info; i++) {
    1417           0 :                 if (as->source_info[i].reg == AC97_REG_HEADPHONE_VOLUME)
    1418           0 :                         as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
    1419           0 :                 else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
    1420           0 :                         as->source_info[i].reg = AC97_REG_HEADPHONE_VOLUME;
    1421             :         }
    1422           0 : }
    1423             : 
    1424             : #define AC97_AD1886_JACK_SENSE  0x72
    1425             : 
    1426             : void
    1427           0 : ac97_ad1886_init(struct ac97_softc *as, int resuming)
    1428             : {
    1429           0 :         ac97_write(as, AC97_AD1886_JACK_SENSE, 0x0010);
    1430           0 : }
    1431             : 
    1432             : void
    1433           0 : ac97_ad198x_init(struct ac97_softc *as, int resuming)
    1434             : {
    1435             :         int i;
    1436           0 :         u_int16_t misc;
    1437             : 
    1438           0 :         ac97_read(as, AC97_AD_REG_MISC, &misc);
    1439           0 :         ac97_write(as, AC97_AD_REG_MISC,
    1440           0 :             misc|AC97_AD_MISC_HPSEL|AC97_AD_MISC_LOSEL);
    1441             : 
    1442           0 :         if (resuming)
    1443           0 :                 return;
    1444             : 
    1445           0 :         for (i = 0; i < as->num_source_info; i++) {
    1446           0 :                 if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
    1447           0 :                         as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
    1448           0 :                 else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
    1449           0 :                         as->source_info[i].reg = AC97_REG_SURR_MASTER;
    1450             :         }
    1451           0 : }
    1452             : 
    1453             : void
    1454           0 : ac97_alc650_init(struct ac97_softc *as, int resuming)
    1455             : {
    1456           0 :         u_int16_t misc;
    1457             : 
    1458           0 :         ac97_read(as, AC97_ALC650_REG_MISC, &misc);
    1459           0 :         if (as->host_flags & AC97_HOST_ALC650_PIN47_IS_EAPD)
    1460           0 :                 misc &= ~AC97_ALC650_MISC_PIN47;
    1461           0 :         misc &= ~AC97_ALC650_MISC_VREFDIS;
    1462           0 :         ac97_write(as, AC97_ALC650_REG_MISC, misc);
    1463             : 
    1464           0 :         if (resuming)
    1465           0 :                 return;
    1466             : 
    1467           0 :         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           0 :         ac97_add_port(as, &sources[0]);
    1482           0 :         ac97_add_port(as, &sources[1]);
    1483           0 :         ac97_add_port(as, &sources[2]);
    1484           0 : }
    1485             : 
    1486             : void
    1487           0 : ac97_cx20468_init(struct ac97_softc *as, int resuming)
    1488             : {
    1489           0 :         u_int16_t misc;
    1490             : 
    1491           0 :         ac97_read(as, AC97_CX_REG_MISC, &misc);
    1492           0 :         ac97_write(as, AC97_CX_REG_MISC, misc &
    1493             :             ~(AC97_CX_SPDIFEN | AC97_CX_COPYRIGHT | AC97_CX_MASK));
    1494           0 : }
    1495             : 
    1496             : void
    1497           0 : ac97_vt1616_init(struct ac97_softc *as, int resuming)
    1498             : {
    1499           0 :         u_int16_t reg;
    1500             : 
    1501           0 :         if (as->host_flags & AC97_HOST_VT1616_DYNEX) {
    1502           0 :                 ac97_read(as, AC97_VT_REG_TEST, &reg);
    1503             : 
    1504             :                 /* disable 'hp' mixer controls controlling the surround pins */
    1505           0 :                 reg &= ~(AC97_VT_LVL);
    1506             : 
    1507             :                 /* disable downmixing */
    1508           0 :                 reg &= ~(AC97_VT_LCTF | AC97_VT_STF);
    1509             : 
    1510             :                 /* enable DC offset removal */
    1511           0 :                 reg |= AC97_VT_BPDC;
    1512             : 
    1513           0 :                 ac97_write(as, AC97_VT_REG_TEST, reg);
    1514           0 :         }
    1515           0 : }

Generated by: LCOV version 1.13