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

Cache object: 3ab546c633ad4b990effe622f3497b12


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