The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/pcm/ac97.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #ifdef HAVE_KERNEL_OPTION_HEADERS
   30 #include "opt_snd.h"
   31 #endif
   32 
   33 #include <dev/sound/pcm/sound.h>
   34 #include <dev/sound/pcm/ac97.h>
   35 #include <dev/sound/pcm/ac97_patch.h>
   36 
   37 #include <dev/pci/pcivar.h>
   38 
   39 #include "mixer_if.h"
   40 
   41 SND_DECLARE_FILE("$FreeBSD$");
   42 
   43 static MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
   44 
   45 struct ac97mixtable_entry {
   46         int reg;                /* register index               */
   47                                 /* reg < 0 if inverted polarity */
   48         unsigned bits:4;        /* width of control field       */
   49         unsigned ofs:4;         /* offset (only if stereo=0)    */
   50         unsigned stereo:1;      /* set for stereo controls      */
   51         unsigned mute:1;        /* bit15 is MUTE                */
   52         unsigned recidx:4;      /* index in rec mux             */
   53         unsigned mask:1;        /* use only masked bits         */
   54         unsigned enable:1;      /* entry is enabled             */
   55 };
   56 
   57 #define AC97_MIXER_SIZE         SOUND_MIXER_NRDEVICES
   58 
   59 struct ac97_info {
   60         kobj_t methods;
   61         device_t dev;
   62         void *devinfo;
   63         u_int32_t id;
   64         u_int32_t subvendor;
   65         unsigned count, caps, se, extcaps, extid, extstat, noext:1;
   66         u_int32_t flags;
   67         struct ac97mixtable_entry mix[AC97_MIXER_SIZE];
   68         char name[16];
   69         struct mtx *lock;
   70 };
   71 
   72 struct ac97_vendorid {
   73         u_int32_t   id;
   74         const char *name;
   75 };
   76 
   77 struct ac97_codecid {
   78         u_int32_t  id;
   79         u_int8_t   stepmask;
   80         u_int8_t   noext:1;
   81         char      *name;
   82         ac97_patch patch;
   83 };
   84 
   85 static const struct ac97mixtable_entry ac97mixtable_default[AC97_MIXER_SIZE] = {
   86     /*  [offset]                        reg          bits of st mu re mk en */
   87         [SOUND_MIXER_VOLUME]    = { AC97_MIX_MASTER,    5, 0, 1, 1, 6, 0, 1 },
   88         [SOUND_MIXER_OGAIN]     = { AC97_MIX_AUXOUT,    5, 0, 1, 1, 0, 0, 0 },
   89         [SOUND_MIXER_PHONEOUT]  = { AC97_MIX_MONO,      5, 0, 0, 1, 7, 0, 0 },
   90         [SOUND_MIXER_BASS]      = { AC97_MIX_TONE,      4, 8, 0, 0, 0, 1, 0 },
   91         [SOUND_MIXER_TREBLE]    = { AC97_MIX_TONE,      4, 0, 0, 0, 0, 1, 0 },
   92         [SOUND_MIXER_PCM]       = { AC97_MIX_PCM,       5, 0, 1, 1, 0, 0, 1 },
   93         [SOUND_MIXER_SPEAKER]   = { AC97_MIX_BEEP,      4, 1, 0, 1, 0, 0, 0 },
   94         [SOUND_MIXER_LINE]      = { AC97_MIX_LINE,      5, 0, 1, 1, 5, 0, 1 },
   95         [SOUND_MIXER_PHONEIN]   = { AC97_MIX_PHONE,     5, 0, 0, 1, 8, 0, 0 },
   96         [SOUND_MIXER_MIC]       = { AC97_MIX_MIC,       5, 0, 0, 1, 1, 1, 1 },
   97         /* use igain for the mic 20dB boost */
   98         [SOUND_MIXER_IGAIN]     = { -AC97_MIX_MIC,      1, 6, 0, 0, 0, 1, 1 },
   99         [SOUND_MIXER_CD]        = { AC97_MIX_CD,        5, 0, 1, 1, 2, 0, 1 },
  100         [SOUND_MIXER_LINE1]     = { AC97_MIX_AUX,       5, 0, 1, 1, 4, 0, 0 },
  101         [SOUND_MIXER_VIDEO]     = { AC97_MIX_VIDEO,     5, 0, 1, 1, 3, 0, 0 },
  102         [SOUND_MIXER_RECLEV]    = { -AC97_MIX_RGAIN,    4, 0, 1, 1, 0, 0, 1 }
  103 };
  104 
  105 static const struct ac97_vendorid ac97vendorid[] = {
  106         { 0x41445300, "Analog Devices" },
  107         { 0x414b4d00, "Asahi Kasei" },
  108         { 0x414c4300, "Realtek" },
  109         { 0x414c4700, "Avance Logic" },
  110         { 0x43525900, "Cirrus Logic" },
  111         { 0x434d4900, "C-Media Electronics" },
  112         { 0x43585400, "Conexant" },
  113         { 0x44543000, "Diamond Technology" },
  114         { 0x454d4300, "eMicro" },
  115         { 0x45838300, "ESS Technology" },
  116         { 0x48525300, "Intersil" },
  117         { 0x49434500, "ICEnsemble" },
  118         { 0x49544500, "ITE, Inc." },
  119         { 0x4e534300, "National Semiconductor" },
  120         { 0x50534300, "Philips Semiconductor" },
  121         { 0x83847600, "SigmaTel" },
  122         { 0x53494c00, "Silicon Laboratories" },
  123         { 0x54524100, "TriTech" },
  124         { 0x54584e00, "Texas Instruments" },
  125         { 0x56494100, "VIA Technologies" },
  126         { 0x57454300, "Winbond" },
  127         { 0x574d4c00, "Wolfson" },
  128         { 0x594d4800, "Yamaha" },
  129         /* 
  130          * XXX This is a fluke, really! The real vendor
  131          * should be SigmaTel, not this! This should be
  132          * removed someday!
  133          */
  134         { 0x01408300, "Creative" },
  135         { 0x00000000, NULL }
  136 };
  137 
  138 static struct ac97_codecid ac97codecid[] = {
  139         { 0x41445303, 0x00, 0, "AD1819",        0 },
  140         { 0x41445340, 0x00, 0, "AD1881",        0 },
  141         { 0x41445348, 0x00, 0, "AD1881A",       0 },
  142         { 0x41445360, 0x00, 0, "AD1885",        0 },
  143         { 0x41445361, 0x00, 0, "AD1886",        ad1886_patch },
  144         { 0x41445362, 0x00, 0, "AD1887",        0 },
  145         { 0x41445363, 0x00, 0, "AD1886A",       0 },
  146         { 0x41445368, 0x00, 0, "AD1888",        ad198x_patch },
  147         { 0x41445370, 0x00, 0, "AD1980",        ad198x_patch },
  148         { 0x41445372, 0x00, 0, "AD1981A",       0 },
  149         { 0x41445374, 0x00, 0, "AD1981B",       ad1981b_patch },
  150         { 0x41445375, 0x00, 0, "AD1985",        ad198x_patch },
  151         { 0x41445378, 0x00, 0, "AD1986",        ad198x_patch },
  152         { 0x414b4d00, 0x00, 1, "AK4540",        0 },
  153         { 0x414b4d01, 0x00, 1, "AK4542",        0 },
  154         { 0x414b4d02, 0x00, 1, "AK4543",        0 },
  155         { 0x414b4d06, 0x00, 0, "AK4544A",       0 },
  156         { 0x454b4d07, 0x00, 0, "AK4545",        0 },
  157         { 0x414c4320, 0x0f, 0, "ALC100",        0 },
  158         { 0x414c4730, 0x0f, 0, "ALC101",        0 },
  159         { 0x414c4710, 0x0f, 0, "ALC200",        0 },
  160         { 0x414c4740, 0x0f, 0, "ALC202",        0 },
  161         { 0x414c4720, 0x0f, 0, "ALC650",        0 },
  162         { 0x414c4752, 0x0f, 0, "ALC250",        0 },
  163         { 0x414c4760, 0x0f, 0, "ALC655",        alc655_patch },
  164         { 0x414c4770, 0x0f, 0, "ALC203",        0 },
  165         { 0x414c4780, 0x0f, 0, "ALC658",        0 },
  166         { 0x414c4790, 0x0f, 0, "ALC850",        0 },
  167         { 0x43525900, 0x07, 0, "CS4297",        0 },
  168         { 0x43525910, 0x07, 0, "CS4297A",       0 },
  169         { 0x43525920, 0x07, 0, "CS4294/98",     0 },
  170         { 0x4352592d, 0x07, 0, "CS4294",        0 },
  171         { 0x43525930, 0x07, 0, "CS4299",        0 },
  172         { 0x43525940, 0x07, 0, "CS4201",        0 },
  173         { 0x43525958, 0x07, 0, "CS4205",        0 },
  174         { 0x43525960, 0x07, 0, "CS4291A",       0 },
  175         { 0x434d4961, 0x00, 0, "CMI9739",       cmi9739_patch },
  176         { 0x434d4941, 0x00, 0, "CMI9738",       0 },
  177         { 0x434d4978, 0x00, 0, "CMI9761",       0 },
  178         { 0x434d4982, 0x00, 0, "CMI9761",       0 },
  179         { 0x434d4983, 0x00, 0, "CMI9761",       0 },
  180         { 0x43585421, 0x00, 0, "HSD11246",      0 },
  181         { 0x43585428, 0x07, 0, "CX20468",       0 },
  182         { 0x43585430, 0x00, 0, "CX20468-21",    0 },
  183         { 0x44543000, 0x00, 0, "DT0398",        0 },
  184         { 0x454d4323, 0x00, 0, "EM28023",       0 },
  185         { 0x454d4328, 0x00, 0, "EM28028",       0 },
  186         { 0x45838308, 0x00, 0, "ES1988",        0 }, /* Formerly ES1921(?) */
  187         { 0x48525300, 0x00, 0, "HMP9701",       0 },
  188         { 0x49434501, 0x00, 0, "ICE1230",       0 },
  189         { 0x49434511, 0x00, 0, "ICE1232",       0 },
  190         { 0x49434514, 0x00, 0, "ICE1232A",      0 },
  191         { 0x49434551, 0x03, 0, "VT1616",        0 }, /* Via badged ICE */
  192         { 0x49544520, 0x00, 0, "ITE2226E",      0 },
  193         { 0x49544560, 0x07, 0, "ITE2646E",      0 }, /* XXX: patch needed */
  194         { 0x4e534340, 0x00, 0, "LM4540",        0 }, /* Spec blank on revid */
  195         { 0x4e534343, 0x00, 0, "LM4543",        0 }, /* Ditto */
  196         { 0x4e534346, 0x00, 0, "LM4546A",       0 },
  197         { 0x4e534348, 0x00, 0, "LM4548A",       0 },
  198         { 0x4e534331, 0x00, 0, "LM4549",        0 },
  199         { 0x4e534349, 0x00, 0, "LM4549A",       0 },
  200         { 0x4e534350, 0x00, 0, "LM4550",        0 },
  201         { 0x50534301, 0x00, 0, "UCB1510",       0 },
  202         { 0x50534304, 0x00, 0, "UCB1400",       0 },
  203         { 0x83847600, 0x00, 0, "STAC9700/83/84",        0 },
  204         { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
  205         { 0x83847605, 0x00, 0, "STAC9704",      0 },
  206         { 0x83847608, 0x00, 0, "STAC9708/11",   0 },
  207         { 0x83847609, 0x00, 0, "STAC9721/23",   0 },
  208         { 0x83847644, 0x00, 0, "STAC9744/45",   0 },
  209         { 0x83847650, 0x00, 0, "STAC9750/51",   0 },
  210         { 0x83847652, 0x00, 0, "STAC9752/53",   0 },
  211         { 0x83847656, 0x00, 0, "STAC9756/57",   0 },
  212         { 0x83847658, 0x00, 0, "STAC9758/59",   0 },
  213         { 0x83847660, 0x00, 0, "STAC9760/61",   0 }, /* Extrapolated */
  214         { 0x83847662, 0x00, 0, "STAC9762/63",   0 }, /* Extrapolated */
  215         { 0x83847666, 0x00, 0, "STAC9766/67",   0 },
  216         { 0x53494c22, 0x00, 0, "Si3036",        0 },
  217         { 0x53494c23, 0x00, 0, "Si3038",        0 },
  218         { 0x54524103, 0x00, 0, "TR28023",       0 }, /* Extrapolated */
  219         { 0x54524106, 0x00, 0, "TR28026",       0 },
  220         { 0x54524108, 0x00, 0, "TR28028",       0 },
  221         { 0x54524123, 0x00, 0, "TR28602",       0 },
  222         { 0x54524e03, 0x07, 0, "TLV320AIC27",   0 },
  223         { 0x54584e20, 0x00, 0, "TLC320AD90",    0 },
  224         { 0x56494161, 0x00, 0, "VIA1612A",      0 },
  225         { 0x56494170, 0x00, 0, "VIA1617A",      0 },
  226         { 0x574d4c00, 0x00, 0, "WM9701A",       0 },
  227         { 0x574d4c03, 0x00, 0, "WM9703/4/7/8",  0 },
  228         { 0x574d4c04, 0x00, 0, "WM9704Q",       0 },
  229         { 0x574d4c05, 0x00, 0, "WM9705/10",     0 },
  230         { 0x574d4d09, 0x00, 0, "WM9709",        0 },
  231         { 0x574d4c12, 0x00, 0, "WM9711/12",     0 }, /* XXX: patch needed */
  232         { 0x57454301, 0x00, 0, "W83971D",       0 },
  233         { 0x594d4800, 0x00, 0, "YMF743",        0 },
  234         { 0x594d4802, 0x00, 0, "YMF752",        0 },
  235         { 0x594d4803, 0x00, 0, "YMF753",        0 },
  236         /* 
  237          * XXX This is a fluke, really! The real codec
  238          * should be STAC9704, not this! This should be
  239          * removed someday!
  240          */
  241         { 0x01408384, 0x00, 0, "EV1938",        0 },
  242         { 0, 0, 0, NULL, 0 }
  243 };
  244 
  245 static char *ac97enhancement[] = {
  246         "no 3D Stereo Enhancement",
  247         "Analog Devices Phat Stereo",
  248         "Creative Stereo Enhancement",
  249         "National Semi 3D Stereo Enhancement",
  250         "Yamaha Ymersion",
  251         "BBE 3D Stereo Enhancement",
  252         "Crystal Semi 3D Stereo Enhancement",
  253         "Qsound QXpander",
  254         "Spatializer 3D Stereo Enhancement",
  255         "SRS 3D Stereo Enhancement",
  256         "Platform Tech 3D Stereo Enhancement",
  257         "AKM 3D Audio",
  258         "Aureal Stereo Enhancement",
  259         "Aztech 3D Enhancement",
  260         "Binaura 3D Audio Enhancement",
  261         "ESS Technology Stereo Enhancement",
  262         "Harman International VMAx",
  263         "Nvidea 3D Stereo Enhancement",
  264         "Philips Incredible Sound",
  265         "Texas Instruments 3D Stereo Enhancement",
  266         "VLSI Technology 3D Stereo Enhancement",
  267         "TriTech 3D Stereo Enhancement",
  268         "Realtek 3D Stereo Enhancement",
  269         "Samsung 3D Stereo Enhancement",
  270         "Wolfson Microelectronics 3D Enhancement",
  271         "Delta Integration 3D Enhancement",
  272         "SigmaTel 3D Enhancement",
  273         "Reserved 27",
  274         "Rockwell 3D Stereo Enhancement",
  275         "Reserved 29",
  276         "Reserved 30",
  277         "Reserved 31"
  278 };
  279 
  280 static char *ac97feature[] = {
  281         "mic channel",
  282         "reserved",
  283         "tone",
  284         "simulated stereo",
  285         "headphone",
  286         "bass boost",
  287         "18 bit DAC",
  288         "20 bit DAC",
  289         "18 bit ADC",
  290         "20 bit ADC"
  291 };
  292 
  293 static char *ac97extfeature[] = {
  294         "variable rate PCM",
  295         "double rate PCM",
  296         "reserved 1",
  297         "variable rate mic",
  298         "reserved 2",
  299         "reserved 3",
  300         "center DAC",
  301         "surround DAC",
  302         "LFE DAC",
  303         "AMAP",
  304         "reserved 4",
  305         "reserved 5",
  306         "reserved 6",
  307         "reserved 7",
  308 };
  309 
  310 u_int16_t
  311 ac97_rdcd(struct ac97_info *codec, int reg)
  312 {
  313         if (codec->flags & AC97_F_RDCD_BUG) {
  314                 u_int16_t i[2], j = 100;
  315 
  316                 i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
  317                 i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
  318                 while (i[0] != i[1] && j)
  319                         i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
  320 #if 0
  321                 if (j < 100) {
  322                         device_printf(codec->dev, "%s(): Inconsistent register value at"
  323                                         " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
  324                 }
  325 #endif
  326                 return i[!(j & 1)];
  327         }
  328         return AC97_READ(codec->methods, codec->devinfo, reg);
  329 }
  330 
  331 void
  332 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
  333 {
  334         AC97_WRITE(codec->methods, codec->devinfo, reg, val);
  335 }
  336 
  337 static void
  338 ac97_reset(struct ac97_info *codec)
  339 {
  340         u_int32_t i, ps;
  341         ac97_wrcd(codec, AC97_REG_RESET, 0);
  342         for (i = 0; i < 500; i++) {
  343                 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
  344                 if (ps == AC97_POWER_STATUS)
  345                         return;
  346                 DELAY(1000);
  347         }
  348         device_printf(codec->dev, "AC97 reset timed out.\n");
  349 }
  350 
  351 int
  352 ac97_setrate(struct ac97_info *codec, int which, int rate)
  353 {
  354         u_int16_t v;
  355 
  356         switch(which) {
  357         case AC97_REGEXT_FDACRATE:
  358         case AC97_REGEXT_SDACRATE:
  359         case AC97_REGEXT_LDACRATE:
  360         case AC97_REGEXT_LADCRATE:
  361         case AC97_REGEXT_MADCRATE:
  362                 break;
  363 
  364         default:
  365                 return -1;
  366         }
  367 
  368         snd_mtxlock(codec->lock);
  369         if (rate != 0) {
  370                 v = rate;
  371                 if (codec->extstat & AC97_EXTCAP_DRA)
  372                         v >>= 1;
  373                 ac97_wrcd(codec, which, v);
  374         }
  375         v = ac97_rdcd(codec, which);
  376         if (codec->extstat & AC97_EXTCAP_DRA)
  377                 v <<= 1;
  378         snd_mtxunlock(codec->lock);
  379         return v;
  380 }
  381 
  382 int
  383 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
  384 {
  385         mode &= AC97_EXTCAPS;
  386         if ((mode & ~codec->extcaps) != 0) {
  387                 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
  388                               mode);
  389                 return -1;
  390         }
  391         snd_mtxlock(codec->lock);
  392         ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
  393         codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
  394         snd_mtxunlock(codec->lock);
  395         return (mode == codec->extstat)? 0 : -1;
  396 }
  397 
  398 u_int16_t
  399 ac97_getextmode(struct ac97_info *codec)
  400 {
  401         return codec->extstat;
  402 }
  403 
  404 u_int16_t
  405 ac97_getextcaps(struct ac97_info *codec)
  406 {
  407         return codec->extcaps;
  408 }
  409 
  410 u_int16_t
  411 ac97_getcaps(struct ac97_info *codec)
  412 {
  413         return codec->caps;
  414 }
  415 
  416 u_int32_t
  417 ac97_getsubvendor(struct ac97_info *codec)
  418 {
  419         return codec->subvendor;
  420 }
  421 
  422 static int
  423 ac97_setrecsrc(struct ac97_info *codec, int channel)
  424 {
  425         struct ac97mixtable_entry *e = &codec->mix[channel];
  426 
  427         if (e->recidx > 0) {
  428                 int val = e->recidx - 1;
  429                 val |= val << 8;
  430                 snd_mtxlock(codec->lock);
  431                 ac97_wrcd(codec, AC97_REG_RECSEL, val);
  432                 snd_mtxunlock(codec->lock);
  433                 return 0;
  434         } else
  435                 return -1;
  436 }
  437 
  438 static int
  439 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
  440 {
  441         struct ac97mixtable_entry *e = &codec->mix[channel];
  442 
  443         if (e->reg && e->enable && e->bits) {
  444                 int mask, max, val, reg;
  445 
  446                 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register    */
  447                 max = (1 << e->bits) - 1;               /* actual range     */
  448                 mask = (max << 8) | max;                /* bits of interest */
  449 
  450                 if (!e->stereo)
  451                         right = left;
  452 
  453                 /*
  454                  * Invert the range if the polarity requires so,
  455                  * then scale to 0..max-1 to compute the value to
  456                  * write into the codec, and scale back to 0..100
  457                  * for the return value.
  458                  */
  459                 if (e->reg > 0) {
  460                         left = 100 - left;
  461                         right = 100 - right;
  462                 }
  463 
  464                 left = (left * max) / 100;
  465                 right = (right * max) / 100;
  466 
  467                 val = (left << 8) | right;
  468 
  469                 left = (left * 100) / max;
  470                 right = (right * 100) / max;
  471 
  472                 if (e->reg > 0) {
  473                         left = 100 - left;
  474                         right = 100 - right;
  475                 }
  476 
  477                 /*
  478                  * For mono controls, trim val and mask, also taking
  479                  * care of e->ofs (offset of control field).
  480                  */
  481                 if (e->ofs) {
  482                         val &= max;
  483                         val <<= e->ofs;
  484                         mask = (max << e->ofs);
  485                 }
  486 
  487                 /*
  488                  * If we have a mute bit, add it to the mask and
  489                  * update val and set mute if both channels require a
  490                  * zero volume.
  491                  */
  492                 if (e->mute == 1) {
  493                         mask |= AC97_MUTE;
  494                         if (left == 0 && right == 0)
  495                                 val = AC97_MUTE;
  496                 }
  497 
  498                 /*
  499                  * If the mask bit is set, do not alter the other bits.
  500                  */
  501                 snd_mtxlock(codec->lock);
  502                 if (e->mask) {
  503                         int cur = ac97_rdcd(codec, reg);
  504                         val |= cur & ~(mask);
  505                 }
  506                 ac97_wrcd(codec, reg, val);
  507                 snd_mtxunlock(codec->lock);
  508                 return left | (right << 8);
  509         } else {
  510 #if 0
  511                 printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
  512 #endif
  513                 return -1;
  514         }
  515 }
  516 
  517 static void
  518 ac97_fix_auxout(struct ac97_info *codec)
  519 {
  520         int keep_ogain;
  521 
  522         /*
  523          * By default, The ac97 aux_out register (0x04) corresponds to OSS's
  524          * OGAIN setting.
  525          *
  526          * We first check whether aux_out is a valid register.  If not
  527          * we may not want to keep ogain.
  528          */
  529         keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
  530 
  531         /*
  532          * Determine what AUX_OUT really means, it can be:
  533          *
  534          * 1. Headphone out.
  535          * 2. 4-Channel Out
  536          * 3. True line level out (effectively master volume).
  537          *
  538          * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
  539          */
  540         if (codec->extcaps & AC97_EXTCAP_SDAC &&
  541             ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
  542                 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
  543                 keep_ogain = 1;
  544         }
  545 
  546         if (keep_ogain == 0) {
  547                 bzero(&codec->mix[SOUND_MIXER_OGAIN],
  548                       sizeof(codec->mix[SOUND_MIXER_OGAIN]));
  549         }
  550 }
  551 
  552 static void
  553 ac97_fix_tone(struct ac97_info *codec)
  554 {
  555         /*
  556          * YMF chips does not indicate tone and 3D enhancement capability
  557          * in the AC97_REG_RESET register.
  558          */
  559         switch (codec->id) {
  560         case 0x594d4800:        /* YMF743 */
  561         case 0x594d4803:        /* YMF753 */
  562                 codec->caps |= AC97_CAP_TONE;
  563                 codec->se |= 0x04;
  564                 break;
  565         case 0x594d4802:        /* YMF752 */
  566                 codec->se |= 0x04;
  567                 break;
  568         default:
  569                 break;
  570         }
  571 
  572         /* Hide treble and bass if they don't exist */
  573         if ((codec->caps & AC97_CAP_TONE) == 0) {
  574                 bzero(&codec->mix[SOUND_MIXER_BASS],
  575                       sizeof(codec->mix[SOUND_MIXER_BASS]));
  576                 bzero(&codec->mix[SOUND_MIXER_TREBLE],
  577                       sizeof(codec->mix[SOUND_MIXER_TREBLE]));
  578         }
  579 }
  580 
  581 static const char*
  582 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
  583 {
  584         if (cname == NULL) {
  585                 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
  586                 return buf;
  587         }
  588 
  589         if (vname == NULL) vname = "Unknown";
  590 
  591         if (bootverbose) {
  592                 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
  593         } else {
  594                 sprintf(buf, "%s %s AC97 Codec", vname, cname);
  595         }
  596         return buf;
  597 }
  598 
  599 static unsigned
  600 ac97_initmixer(struct ac97_info *codec)
  601 {
  602         ac97_patch codec_patch;
  603         const char *cname, *vname;
  604         char desc[80];
  605         device_t pdev;
  606         unsigned i, j, k, bit, old;
  607         u_int32_t id;
  608         int reg;
  609 
  610         snd_mtxlock(codec->lock);
  611         codec->count = AC97_INIT(codec->methods, codec->devinfo);
  612         if (codec->count == 0) {
  613                 device_printf(codec->dev, "ac97 codec init failed\n");
  614                 snd_mtxunlock(codec->lock);
  615                 return ENODEV;
  616         }
  617 
  618         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  619         ac97_reset(codec);
  620         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  621 
  622         i = ac97_rdcd(codec, AC97_REG_RESET);
  623         j = ac97_rdcd(codec, AC97_REG_RESET);
  624         k = ac97_rdcd(codec, AC97_REG_RESET);
  625         /*
  626          * Let see if this codec can return consistent value.
  627          * If not, turn on aggressive read workaround
  628          * (STAC9704 comes in mind).
  629          */
  630         if (i != j || j != k) {
  631                 codec->flags |= AC97_F_RDCD_BUG;
  632                 i = ac97_rdcd(codec, AC97_REG_RESET);
  633         }
  634         codec->caps = i & 0x03ff;
  635         codec->se =  (i & 0x7c00) >> 10;
  636 
  637         id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
  638         if (id == 0 || id == 0xffffffff) {
  639                 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
  640                 snd_mtxunlock(codec->lock);
  641                 return ENODEV;
  642         }
  643 
  644         pdev = codec->dev;
  645         while (strcmp(device_get_name(device_get_parent(pdev)), "pci") != 0) {
  646                 /* find the top-level PCI device handler */
  647                 pdev = device_get_parent(pdev);
  648         }
  649         codec->id = id;
  650         codec->subvendor = (u_int32_t)pci_get_subdevice(pdev) << 16;
  651         codec->subvendor |= (u_int32_t)pci_get_subvendor(pdev) &
  652             0x0000ffff;
  653         codec->noext = 0;
  654         codec_patch = NULL;
  655 
  656         cname = NULL;
  657         for (i = 0; ac97codecid[i].id; i++) {
  658                 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
  659                 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
  660                         codec->noext = ac97codecid[i].noext;
  661                         codec_patch = ac97codecid[i].patch;
  662                         cname = ac97codecid[i].name;
  663                         break;
  664                 }
  665         }
  666 
  667         vname = NULL;
  668         for (i = 0; ac97vendorid[i].id; i++) {
  669                 if (ac97vendorid[i].id == (id & 0xffffff00)) {
  670                         vname = ac97vendorid[i].name;
  671                         break;
  672                 }
  673         }
  674 
  675         codec->extcaps = 0;
  676         codec->extid = 0;
  677         codec->extstat = 0;
  678         if (!codec->noext) {
  679                 i = ac97_rdcd(codec, AC97_REGEXT_ID);
  680                 if (i != 0xffff) {
  681                         codec->extcaps = i & 0x3fff;
  682                         codec->extid =  (i & 0xc000) >> 14;
  683                         codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
  684                 }
  685         }
  686 
  687         for (i = 0; i < AC97_MIXER_SIZE; i++) {
  688                 codec->mix[i] = ac97mixtable_default[i];
  689         }
  690         ac97_fix_auxout(codec);
  691         ac97_fix_tone(codec);
  692         if (codec_patch)
  693                 codec_patch(codec);
  694 
  695         for (i = 0; i < AC97_MIXER_SIZE; i++) {
  696                 k = codec->noext? codec->mix[i].enable : 1;
  697                 reg = codec->mix[i].reg;
  698                 if (reg < 0)
  699                         reg = -reg;
  700                 if (k && reg) {
  701                         j = old = ac97_rdcd(codec, reg);
  702                         /*
  703                          * Test for mute bit (except for AC97_MIX_TONE,
  704                          * where we simply assume it as available).
  705                          */
  706                         if (codec->mix[i].mute) {
  707                                 ac97_wrcd(codec, reg, j | 0x8000);
  708                                 j = ac97_rdcd(codec, reg);
  709                         } else
  710                                 j |= 0x8000;
  711                         if ((j & 0x8000)) {
  712                                 /*
  713                                  * Test whether the control width should be
  714                                  * 4, 5 or 6 bit. For 5bit register, we should
  715                                  * test it whether it's really 5 or 6bit. Leave
  716                                  * 4bit register alone, because sometimes an
  717                                  * attempt to write past 4th bit may cause
  718                                  * incorrect result especially for AC97_MIX_BEEP
  719                                  * (ac97 2.3).
  720                                  */
  721                                 bit = codec->mix[i].bits;
  722                                 if (bit == 5)
  723                                         bit++;
  724                                 j = ((1 << bit) - 1) << codec->mix[i].ofs;
  725                                 ac97_wrcd(codec, reg,
  726                                         j | (codec->mix[i].mute ? 0x8000 : 0));
  727                                 k = ac97_rdcd(codec, reg) & j;
  728                                 k >>= codec->mix[i].ofs;
  729                                 if (reg == AC97_MIX_TONE &&
  730                                                         ((k & 0x0001) == 0x0000))
  731                                         k >>= 1;
  732                                 for (j = 0; k >> j; j++)
  733                                         ;
  734                                 if (j != 0) {
  735 #if 0
  736                                         device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
  737                                                 i, k, bit, codec->mix[i].bits, j);
  738 #endif
  739                                         codec->mix[i].enable = 1;
  740                                         codec->mix[i].bits = j;
  741                                 } else if (reg == AC97_MIX_BEEP) {
  742                                         /*
  743                                          * Few codec such as CX20468-21 does
  744                                          * have this control register, although
  745                                          * the only usable part is the mute bit.
  746                                          */
  747                                         codec->mix[i].enable = 1;
  748                                 } else
  749                                         codec->mix[i].enable = 0;
  750                         } else
  751                                 codec->mix[i].enable = 0;
  752                         ac97_wrcd(codec, reg, old);
  753                 }
  754 #if 0
  755                 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
  756 #endif
  757         }
  758 
  759         device_printf(codec->dev, "<%s>\n",
  760                       ac97_hw_desc(codec->id, vname, cname, desc));
  761 
  762         if (bootverbose) {
  763                 if (codec->flags & AC97_F_RDCD_BUG)
  764                         device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
  765                 device_printf(codec->dev, "Codec features ");
  766                 for (i = j = 0; i < 10; i++)
  767                         if (codec->caps & (1 << i))
  768                                 printf("%s%s", j++? ", " : "", ac97feature[i]);
  769                 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
  770                 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
  771 
  772                 if (codec->extcaps != 0 || codec->extid) {
  773                         device_printf(codec->dev, "%s codec",
  774                                       codec->extid? "Secondary" : "Primary");
  775                         if (codec->extcaps)
  776                                 printf(" extended features ");
  777                         for (i = j = 0; i < 14; i++)
  778                                 if (codec->extcaps & (1 << i))
  779                                         printf("%s%s", j++? ", " : "", ac97extfeature[i]);
  780                         printf("\n");
  781                 }
  782         }
  783 
  784         i = 0;
  785         while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
  786                 if (++i == 100) {
  787                         device_printf(codec->dev, "ac97 codec reports dac not ready\n");
  788                         break;
  789                 }
  790                 DELAY(1000);
  791         }
  792         if (bootverbose)
  793                 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
  794         snd_mtxunlock(codec->lock);
  795         return 0;
  796 }
  797 
  798 static unsigned
  799 ac97_reinitmixer(struct ac97_info *codec)
  800 {
  801         snd_mtxlock(codec->lock);
  802         codec->count = AC97_INIT(codec->methods, codec->devinfo);
  803         if (codec->count == 0) {
  804                 device_printf(codec->dev, "ac97 codec init failed\n");
  805                 snd_mtxunlock(codec->lock);
  806                 return ENODEV;
  807         }
  808 
  809         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  810         ac97_reset(codec);
  811         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  812 
  813         if (!codec->noext) {
  814                 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
  815                 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
  816                     != codec->extstat)
  817                         device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
  818                                       codec->extstat,
  819                                       ac97_rdcd(codec, AC97_REGEXT_STAT) &
  820                                       AC97_EXTCAPS);
  821         }
  822 
  823         if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
  824                 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
  825         snd_mtxunlock(codec->lock);
  826         return 0;
  827 }
  828 
  829 struct ac97_info *
  830 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
  831 {
  832         struct ac97_info *codec;
  833         int i;
  834 
  835         codec = malloc(sizeof(*codec), M_AC97, M_WAITOK | M_ZERO);
  836         snprintf(codec->name, sizeof(codec->name), "%s:ac97",
  837             device_get_nameunit(dev));
  838         codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
  839         codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
  840         codec->dev = dev;
  841         codec->devinfo = devinfo;
  842         codec->flags = 0;
  843 
  844         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
  845             "eapdinv", &i) == 0 && i != 0)
  846                 codec->flags |= AC97_F_EAPD_INV;
  847 
  848         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
  849             "softpcmvol", &i) == 0 && i != 0)
  850                 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SOFTPCMVOL);
  851 
  852         return codec;
  853 }
  854 
  855 void
  856 ac97_destroy(struct ac97_info *codec)
  857 {
  858         snd_mtxlock(codec->lock);
  859         if (codec->methods != NULL)
  860                 kobj_delete(codec->methods, M_AC97);
  861         snd_mtxfree(codec->lock);
  862         free(codec, M_AC97);
  863 }
  864 
  865 void
  866 ac97_setflags(struct ac97_info *codec, u_int32_t val)
  867 {
  868         codec->flags = val;
  869 }
  870 
  871 u_int32_t
  872 ac97_getflags(struct ac97_info *codec)
  873 {
  874         return codec->flags;
  875 }
  876 
  877 /* -------------------------------------------------------------------- */
  878 
  879 static int
  880 sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)
  881 {
  882         struct ac97_info *codec;
  883         int ea, inv, err = 0;
  884         u_int16_t val;
  885 
  886         codec = oidp->oid_arg1;
  887         if (codec == NULL || codec->id == 0 || codec->lock == NULL)
  888                 return EINVAL;
  889         snd_mtxlock(codec->lock);
  890         val = ac97_rdcd(codec, AC97_REG_POWER);
  891         inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1;
  892         ea = (val >> 15) ^ inv;
  893         snd_mtxunlock(codec->lock);
  894         err = sysctl_handle_int(oidp, &ea, 0, req);
  895         if (err == 0 && req->newptr != NULL) {
  896                 if (ea != 0 && ea != 1)
  897                         return EINVAL;
  898                 if (ea != ((val >> 15) ^ inv)) {
  899                         snd_mtxlock(codec->lock);
  900                         ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000);
  901                         snd_mtxunlock(codec->lock);
  902                 }
  903         }
  904         return err;
  905 }
  906 
  907 static void
  908 ac97_init_sysctl(struct ac97_info *codec)
  909 {
  910         u_int16_t orig, val;
  911 
  912         if (codec == NULL || codec->dev == NULL)
  913                 return;
  914         snd_mtxlock(codec->lock);
  915         orig = ac97_rdcd(codec, AC97_REG_POWER);
  916         ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000);
  917         val = ac97_rdcd(codec, AC97_REG_POWER);
  918         ac97_wrcd(codec, AC97_REG_POWER, orig);
  919         snd_mtxunlock(codec->lock);
  920         if ((val & 0x8000) == (orig & 0x8000))
  921                 return;
  922         SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev),
  923             SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)),
  924             OID_AUTO, "eapd",
  925             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
  926             codec, sizeof(codec), sysctl_hw_snd_ac97_eapd,
  927             "I", "AC97 External Amplifier");
  928 }
  929 
  930 static int
  931 ac97mix_init(struct snd_mixer *m)
  932 {
  933         struct ac97_info *codec = mix_getdevinfo(m);
  934         u_int32_t i, mask;
  935 
  936         if (codec == NULL)
  937                 return -1;
  938 
  939         if (ac97_initmixer(codec))
  940                 return -1;
  941 
  942         switch (codec->id) {
  943         case 0x41445374:        /* AD1981B */
  944                 switch (codec->subvendor) {
  945                 case 0x02d91014:
  946                         /*
  947                          * IBM Thinkcentre:
  948                          *
  949                          * Tie "ogain" and "phout" to "vol" since its
  950                          * master volume is basically useless and can't
  951                          * control anything.
  952                          */
  953                         mask = 0;
  954                         if (codec->mix[SOUND_MIXER_OGAIN].enable)
  955                                 mask |= SOUND_MASK_OGAIN;
  956                         if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
  957                                 mask |= SOUND_MASK_PHONEOUT;
  958                         if (codec->mix[SOUND_MIXER_VOLUME].enable)
  959                                 mix_setparentchild(m, SOUND_MIXER_VOLUME,
  960                                     mask);
  961                         else {
  962                                 mix_setparentchild(m, SOUND_MIXER_VOLUME,
  963                                     mask);
  964                                 mix_setrealdev(m, SOUND_MIXER_VOLUME,
  965                                     SOUND_MIXER_NONE);
  966                         }
  967                         break;
  968                 case 0x099c103c:
  969                         /*
  970                          * HP nx6110:
  971                          *
  972                          * By default, "vol" is controlling internal speakers
  973                          * (not a master volume!) and "ogain" is controlling
  974                          * headphone. Enable dummy "phout" so it can be
  975                          * remapped to internal speakers and virtualize
  976                          * "vol" to control both.
  977                          */
  978                         codec->mix[SOUND_MIXER_OGAIN].enable = 1;
  979                         codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
  980                         mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
  981                             SOUND_MIXER_VOLUME);
  982                         mix_setrealdev(m, SOUND_MIXER_VOLUME,
  983                             SOUND_MIXER_NONE);
  984                         mix_setparentchild(m, SOUND_MIXER_VOLUME,
  985                             SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
  986                         break;
  987                 default:
  988                         break;
  989                 }
  990                 break;
  991         case 0x434d4941:        /* CMI9738 */
  992         case 0x434d4961:        /* CMI9739 */
  993         case 0x434d4978:        /* CMI9761 */
  994         case 0x434d4982:        /* CMI9761 */
  995         case 0x434d4983:        /* CMI9761 */
  996                 bzero(&codec->mix[SOUND_MIXER_PCM],
  997                     sizeof(codec->mix[SOUND_MIXER_PCM]));
  998                 pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
  999                     SD_F_SOFTPCMVOL);
 1000                 /* XXX How about master volume ? */
 1001                 break;
 1002         default:
 1003                 break;
 1004         }
 1005 
 1006         if (pcm_getflags(codec->dev) & SD_F_SOFTPCMVOL)
 1007                 ac97_wrcd(codec, AC97_MIX_PCM, 0);
 1008 #if 0
 1009         /* XXX For the sake of debugging purposes */
 1010         mix_setparentchild(m, SOUND_MIXER_VOLUME,
 1011             SOUND_MASK_PCM | SOUND_MASK_CD);
 1012         mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
 1013         ac97_wrcd(codec, AC97_MIX_MASTER, 0);
 1014 #endif
 1015 
 1016         mask = 0;
 1017         for (i = 0; i < AC97_MIXER_SIZE; i++)
 1018                 mask |= codec->mix[i].enable? 1 << i : 0;
 1019         mix_setdevs(m, mask);
 1020 
 1021         mask = 0;
 1022         for (i = 0; i < AC97_MIXER_SIZE; i++)
 1023                 mask |= codec->mix[i].recidx? 1 << i : 0;
 1024         mix_setrecdevs(m, mask);
 1025 
 1026         ac97_init_sysctl(codec);
 1027 
 1028         return 0;
 1029 }
 1030 
 1031 static int
 1032 ac97mix_uninit(struct snd_mixer *m)
 1033 {
 1034         struct ac97_info *codec = mix_getdevinfo(m);
 1035 
 1036         if (codec == NULL)
 1037                 return -1;
 1038         /*
 1039         if (ac97_uninitmixer(codec))
 1040                 return -1;
 1041         */
 1042         ac97_destroy(codec);
 1043         return 0;
 1044 }
 1045 
 1046 static int
 1047 ac97mix_reinit(struct snd_mixer *m)
 1048 {
 1049         struct ac97_info *codec = mix_getdevinfo(m);
 1050 
 1051         if (codec == NULL)
 1052                 return -1;
 1053         return ac97_reinitmixer(codec);
 1054 }
 1055 
 1056 static int
 1057 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
 1058 {
 1059         struct ac97_info *codec = mix_getdevinfo(m);
 1060 
 1061         if (codec == NULL || dev >= AC97_MIXER_SIZE)
 1062                 return -1;
 1063         return ac97_setmixer(codec, dev, left, right);
 1064 }
 1065 
 1066 static u_int32_t
 1067 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
 1068 {
 1069         int i;
 1070         struct ac97_info *codec = mix_getdevinfo(m);
 1071 
 1072         if (codec == NULL)
 1073                 return -1;
 1074         for (i = 0; i < AC97_MIXER_SIZE; i++)
 1075                 if ((src & (1 << i)) != 0)
 1076                         break;
 1077         return (ac97_setrecsrc(codec, i) == 0)? 1U << i : 0xffffffffU;
 1078 }
 1079 
 1080 static kobj_method_t ac97mixer_methods[] = {
 1081         KOBJMETHOD(mixer_init,          ac97mix_init),
 1082         KOBJMETHOD(mixer_uninit,        ac97mix_uninit),
 1083         KOBJMETHOD(mixer_reinit,        ac97mix_reinit),
 1084         KOBJMETHOD(mixer_set,           ac97mix_set),
 1085         KOBJMETHOD(mixer_setrecsrc,     ac97mix_setrecsrc),
 1086         KOBJMETHOD_END
 1087 };
 1088 MIXER_DECLARE(ac97mixer);
 1089 
 1090 /* -------------------------------------------------------------------- */
 1091 
 1092 kobj_class_t
 1093 ac97_getmixerclass(void)
 1094 {
 1095         return &ac97mixer_class;
 1096 }

Cache object: 3ad1e5b0c5737db0f8642ba87efc82fa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.