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

Cache object: a032bccd58179dfdc370b6565e7c0d11


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