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 "mixer_if.h"
   32 
   33 SND_DECLARE_FILE("$FreeBSD: releng/5.3/sys/dev/sound/pcm/ac97.c 129044 2004-05-08 03:41:40Z sanpei $");
   34 
   35 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
   36 
   37 struct ac97mixtable_entry {
   38         int      reg:8;         /* register index               */
   39                                 /* reg < 0 if inverted polarity */
   40         unsigned bits:4;        /* width of control field       */
   41         unsigned ofs:4;         /* offset (only if stereo=0)    */
   42         unsigned stereo:1;      /* set for stereo controls      */
   43         unsigned mute:1;        /* bit15 is MUTE                */
   44         unsigned recidx:4;      /* index in rec mux             */
   45         unsigned mask:1;        /* use only masked bits         */
   46         unsigned enable:1;      /* entry is enabled             */
   47 };
   48 
   49 #define AC97_NAMELEN    16
   50 struct ac97_info {
   51         kobj_t methods;
   52         device_t dev;
   53         void *devinfo;
   54         u_int32_t id;
   55         unsigned count, caps, se, extcaps, extid, extstat, noext:1;
   56         u_int32_t flags;
   57         struct ac97mixtable_entry mix[32];
   58         char name[AC97_NAMELEN];
   59         struct mtx *lock;
   60 };
   61 
   62 struct ac97_vendorid {
   63         u_int32_t   id;
   64         const char *name;
   65 };
   66 
   67 struct ac97_codecid {
   68         u_int32_t  id;
   69         u_int8_t   stepmask;
   70         u_int8_t   noext:1;
   71         char      *name;
   72         ac97_patch patch;
   73 };
   74 
   75 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
   76     /*  [offset]                        reg          bits of st mu re mk en */
   77         [SOUND_MIXER_VOLUME]    = { AC97_MIX_MASTER,    5, 0, 1, 1, 6, 0, 1 },
   78         [SOUND_MIXER_OGAIN]     = { AC97_MIX_AUXOUT,    5, 0, 1, 1, 0, 0, 0 },
   79         [SOUND_MIXER_PHONEOUT]  = { AC97_MIX_MONO,      5, 0, 0, 1, 7, 0, 0 },
   80         [SOUND_MIXER_BASS]      = { AC97_MIX_TONE,      4, 8, 0, 0, 0, 1, 0 },
   81         [SOUND_MIXER_TREBLE]    = { AC97_MIX_TONE,      4, 0, 0, 0, 0, 1, 0 },
   82         [SOUND_MIXER_PCM]       = { AC97_MIX_PCM,       5, 0, 1, 1, 0, 0, 1 },
   83         [SOUND_MIXER_SPEAKER]   = { AC97_MIX_BEEP,      4, 1, 0, 1, 0, 0, 0 },
   84         [SOUND_MIXER_LINE]      = { AC97_MIX_LINE,      5, 0, 1, 1, 5, 0, 1 },
   85         [SOUND_MIXER_PHONEIN]   = { AC97_MIX_PHONE,     5, 0, 0, 1, 8, 0, 0 },
   86         [SOUND_MIXER_MIC]       = { AC97_MIX_MIC,       5, 0, 0, 1, 1, 1, 1 },
   87 #if 0
   88         /* use igain for the mic 20dB boost */
   89         [SOUND_MIXER_IGAIN]     = { -AC97_MIX_MIC,      1, 6, 0, 0, 0, 1, 1 },
   90 #endif
   91         [SOUND_MIXER_CD]        = { AC97_MIX_CD,        5, 0, 1, 1, 2, 0, 1 },
   92         [SOUND_MIXER_LINE1]     = { AC97_MIX_AUX,       5, 0, 1, 1, 4, 0, 0 },
   93         [SOUND_MIXER_VIDEO]     = { AC97_MIX_VIDEO,     5, 0, 1, 1, 3, 0, 0 },
   94         [SOUND_MIXER_RECLEV]    = { -AC97_MIX_RGAIN,    4, 0, 1, 1, 0, 0, 1 }
   95 };
   96 
   97 static const struct ac97_vendorid ac97vendorid[] = {
   98         { 0x41445300, "Analog Devices" },
   99         { 0x414b4d00, "Asahi Kasei" },
  100         { 0x414c4300, "Realtek" },
  101         { 0x414c4700, "Avance Logic" },
  102         { 0x43525900, "Cirrus Logic" },
  103         { 0x434d4900, "C-Media Electronics" },
  104         { 0x43585400, "Conexant" },
  105         { 0x44543000, "Diamond Technology" },
  106         { 0x454d4300, "eMicro" },
  107         { 0x45838300, "ESS Technology" },
  108         { 0x48525300, "Intersil" },
  109         { 0x49434500, "ICEnsemble" },
  110         { 0x49544500, "ITE, Inc." },
  111         { 0x4e534300, "National Semiconductor" },
  112         { 0x50534300, "Philips Semiconductor" },
  113         { 0x83847600, "SigmaTel" },
  114         { 0x53494c00, "Silicon Laboratories" },
  115         { 0x54524100, "TriTech" },
  116         { 0x54584e00, "Texas Instruments" },
  117         { 0x56494100, "VIA Technologies" },
  118         { 0x57454300, "Winbond" },
  119         { 0x574d4c00, "Wolfson" },
  120         { 0x594d4800, "Yamaha" },
  121         { 0x01408300, "Creative" },
  122         { 0x00000000, NULL }
  123 };
  124 
  125 static struct ac97_codecid ac97codecid[] = {
  126         { 0x41445303, 0x00, 0, "AD1819",        0 },
  127         { 0x41445340, 0x00, 0, "AD1881",        0 },
  128         { 0x41445348, 0x00, 0, "AD1881A",       0 },
  129         { 0x41445360, 0x00, 0, "AD1885",        0 },
  130         { 0x41445361, 0x00, 0, "AD1886",        ad1886_patch },
  131         { 0x41445362, 0x00, 0, "AD1887",        0 },
  132         { 0x41445363, 0x00, 0, "AD1886A",       0 },
  133         { 0x41445370, 0x00, 0, "AD1980",        ad198x_patch },
  134         { 0x41445372, 0x00, 0, "AD1981A",       0 },
  135         { 0x41445374, 0x00, 0, "AD1981B",       0 },
  136         { 0x41445375, 0x00, 0, "AD1985",        ad198x_patch },
  137         { 0x414b4d00, 0x00, 1, "AK4540",        0 },
  138         { 0x414b4d01, 0x00, 1, "AK4542",        0 },
  139         { 0x414b4d02, 0x00, 1, "AK4543",        0 },
  140         { 0x414b4d06, 0x00, 0, "AK4544A",       0 },
  141         { 0x454b4d07, 0x00, 0, "AK4545",        0 },
  142         { 0x414c4320, 0x0f, 0, "ALC100",        0 },
  143         { 0x414c4730, 0x0f, 0, "ALC101",        0 },
  144         { 0x414c4710, 0x0f, 0, "ALC200",        0 },
  145         { 0x414c4740, 0x0f, 0, "ALC202",        0 },
  146         { 0x414c4720, 0x0f, 0, "ALC650",        0 },
  147         { 0x414c4760, 0x0f, 0, "ALC655",        0 },
  148         { 0x414c4780, 0x0f, 0, "ALC658",        0 },
  149         { 0x414c4790, 0x0f, 0, "ALC850",        0 },
  150         { 0x43525900, 0x07, 0, "CS4297",        0 },
  151         { 0x43525910, 0x07, 0, "CS4297A",       0 },
  152         { 0x43525920, 0x07, 0, "CS4294/98",     0 },
  153         { 0x4352592d, 0x07, 0, "CS4294",        0 },
  154         { 0x43525930, 0x07, 0, "CS4299",        0 },
  155         { 0x43525940, 0x07, 0, "CS4201",        0 },
  156         { 0x43525958, 0x07, 0, "CS4205",        0 },
  157         { 0x43525960, 0x07, 0, "CS4291A",       0 },
  158         { 0x434d4961, 0x00, 0, "CMI9739",       0 },
  159         { 0x434d4941, 0x00, 0, "CMI9738",       0 },
  160         { 0x43585421, 0x00, 0, "HSD11246",      0 },
  161         { 0x43585428, 0x07, 0, "CX20468",       0 },
  162         { 0x44543000, 0x00, 0, "DT0398",        0 },
  163         { 0x454d4323, 0x00, 0, "EM28023",       0 },
  164         { 0x454d4328, 0x00, 0, "EM28028",       0 },
  165         { 0x45838308, 0x00, 0, "ES1988",        0 }, /* Formerly ES1921(?) */
  166         { 0x48525300, 0x00, 0, "HMP9701",       0 },
  167         { 0x49434501, 0x00, 0, "ICE1230",       0 },
  168         { 0x49434511, 0x00, 0, "ICE1232",       0 },
  169         { 0x49434514, 0x00, 0, "ICE1232A",      0 },
  170         { 0x49434551, 0x03, 0, "VT1616",        0 }, /* Via badged ICE */
  171         { 0x49544520, 0x00, 0, "ITE2226E",      0 },
  172         { 0x49544560, 0x07, 0, "ITE2646E",      0 }, /* XXX: patch needed */
  173         { 0x4e534340, 0x00, 0, "LM4540",        0 }, /* Spec blank on revid */
  174         { 0x4e534343, 0x00, 0, "LM4543",        0 }, /* Ditto */
  175         { 0x4e534346, 0x00, 0, "LM4546A",       0 },
  176         { 0x4e534348, 0x00, 0, "LM4548A",       0 },
  177         { 0x4e534331, 0x00, 0, "LM4549",        0 },
  178         { 0x4e534349, 0x00, 0, "LM4549A",       0 },
  179         { 0x4e534350, 0x00, 0, "LM4550",        0 },
  180         { 0x50534301, 0x00, 0, "UCB1510",       0 },
  181         { 0x50534304, 0x00, 0, "UCB1400",       0 },
  182         { 0x83847600, 0x00, 0, "STAC9700/83/84",        0 },
  183         { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
  184         { 0x83847605, 0x00, 0, "STAC9704",      0 },
  185         { 0x83847608, 0x00, 0, "STAC9708/11",   0 },
  186         { 0x83847609, 0x00, 0, "STAC9721/23",   0 },
  187         { 0x83847644, 0x00, 0, "STAC9744/45",   0 },
  188         { 0x83847650, 0x00, 0, "STAC9750/51",   0 },
  189         { 0x83847652, 0x00, 0, "STAC9752/53",   0 },
  190         { 0x83847656, 0x00, 0, "STAC9756/57",   0 },
  191         { 0x83847658, 0x00, 0, "STAC9758/59",   0 },
  192         { 0x83847660, 0x00, 0, "STAC9760/61",   0 }, /* Extrapolated */
  193         { 0x83847662, 0x00, 0, "STAC9762/63",   0 }, /* Extrapolated */
  194         { 0x53494c22, 0x00, 0, "Si3036",        0 },
  195         { 0x53494c23, 0x00, 0, "Si3038",        0 },
  196         { 0x54524103, 0x00, 0, "TR28023",       0 }, /* Extrapolated */
  197         { 0x54524106, 0x00, 0, "TR28026",       0 },
  198         { 0x54524108, 0x00, 0, "TR28028",       0 },
  199         { 0x54524123, 0x00, 0, "TR28602",       0 },
  200         { 0x54524e03, 0x07, 0, "TLV320AIC27",   0 },
  201         { 0x54584e20, 0x00, 0, "TLC320AD90",    0 },
  202         { 0x56494161, 0x00, 0, "VIA1612A",      0 },
  203         { 0x574d4c00, 0x00, 0, "WM9701A",       0 },
  204         { 0x574d4c03, 0x00, 0, "WM9703/4/7/8",  0 },
  205         { 0x574d4c04, 0x00, 0, "WM9704Q",       0 },
  206         { 0x574d4c05, 0x00, 0, "WM9705/10",     0 },
  207         { 0x574d4d09, 0x00, 0, "WM9709",        0 },
  208         { 0x574d4c12, 0x00, 0, "WM9711/12",     0 }, /* XXX: patch needed */
  209         { 0x57454301, 0x00, 0, "W83971D",       0 },
  210         { 0x594d4800, 0x00, 0, "YMF743",        0 },
  211         { 0x594d4802, 0x00, 0, "YMF752",        0 },
  212         { 0x594d4803, 0x00, 0, "YMF753",        0 },
  213         { 0x01408384, 0x00, 0, "EV1938",        0 },
  214         { 0, 0, 0, NULL, 0 }
  215 };
  216 
  217 static char *ac97enhancement[] = {
  218         "no 3D Stereo Enhancement",
  219         "Analog Devices Phat Stereo",
  220         "Creative Stereo Enhancement",
  221         "National Semi 3D Stereo Enhancement",
  222         "Yamaha Ymersion",
  223         "BBE 3D Stereo Enhancement",
  224         "Crystal Semi 3D Stereo Enhancement",
  225         "Qsound QXpander",
  226         "Spatializer 3D Stereo Enhancement",
  227         "SRS 3D Stereo Enhancement",
  228         "Platform Tech 3D Stereo Enhancement",
  229         "AKM 3D Audio",
  230         "Aureal Stereo Enhancement",
  231         "Aztech 3D Enhancement",
  232         "Binaura 3D Audio Enhancement",
  233         "ESS Technology Stereo Enhancement",
  234         "Harman International VMAx",
  235         "Nvidea 3D Stereo Enhancement",
  236         "Philips Incredible Sound",
  237         "Texas Instruments 3D Stereo Enhancement",
  238         "VLSI Technology 3D Stereo Enhancement",
  239         "TriTech 3D Stereo Enhancement",
  240         "Realtek 3D Stereo Enhancement",
  241         "Samsung 3D Stereo Enhancement",
  242         "Wolfson Microelectronics 3D Enhancement",
  243         "Delta Integration 3D Enhancement",
  244         "SigmaTel 3D Enhancement",
  245         "Reserved 27",
  246         "Rockwell 3D Stereo Enhancement",
  247         "Reserved 29",
  248         "Reserved 30",
  249         "Reserved 31"
  250 };
  251 
  252 static char *ac97feature[] = {
  253         "mic channel",
  254         "reserved",
  255         "tone",
  256         "simulated stereo",
  257         "headphone",
  258         "bass boost",
  259         "18 bit DAC",
  260         "20 bit DAC",
  261         "18 bit ADC",
  262         "20 bit ADC"
  263 };
  264 
  265 static char *ac97extfeature[] = {
  266         "variable rate PCM",
  267         "double rate PCM",
  268         "reserved 1",
  269         "variable rate mic",
  270         "reserved 2",
  271         "reserved 3",
  272         "center DAC",
  273         "surround DAC",
  274         "LFE DAC",
  275         "AMAP",
  276         "reserved 4",
  277         "reserved 5",
  278         "reserved 6",
  279         "reserved 7",
  280 };
  281 
  282 u_int16_t
  283 ac97_rdcd(struct ac97_info *codec, int reg)
  284 {
  285         return AC97_READ(codec->methods, codec->devinfo, reg);
  286 }
  287 
  288 void
  289 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
  290 {
  291         AC97_WRITE(codec->methods, codec->devinfo, reg, val);
  292 }
  293 
  294 static void
  295 ac97_reset(struct ac97_info *codec)
  296 {
  297         u_int32_t i, ps;
  298         ac97_wrcd(codec, AC97_REG_RESET, 0);
  299         for (i = 0; i < 500; i++) {
  300                 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
  301                 if (ps == AC97_POWER_STATUS)
  302                         return;
  303                 DELAY(1000);
  304         }
  305         device_printf(codec->dev, "AC97 reset timed out.\n");
  306 }
  307 
  308 int
  309 ac97_setrate(struct ac97_info *codec, int which, int rate)
  310 {
  311         u_int16_t v;
  312 
  313         switch(which) {
  314         case AC97_REGEXT_FDACRATE:
  315         case AC97_REGEXT_SDACRATE:
  316         case AC97_REGEXT_LDACRATE:
  317         case AC97_REGEXT_LADCRATE:
  318         case AC97_REGEXT_MADCRATE:
  319                 break;
  320 
  321         default:
  322                 return -1;
  323         }
  324 
  325         snd_mtxlock(codec->lock);
  326         if (rate != 0) {
  327                 v = rate;
  328                 if (codec->extstat & AC97_EXTCAP_DRA)
  329                         v >>= 1;
  330                 ac97_wrcd(codec, which, v);
  331         }
  332         v = ac97_rdcd(codec, which);
  333         if (codec->extstat & AC97_EXTCAP_DRA)
  334                 v <<= 1;
  335         snd_mtxunlock(codec->lock);
  336         return v;
  337 }
  338 
  339 int
  340 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
  341 {
  342         mode &= AC97_EXTCAPS;
  343         if ((mode & ~codec->extcaps) != 0) {
  344                 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
  345                               mode);
  346                 return -1;
  347         }
  348         snd_mtxlock(codec->lock);
  349         ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
  350         codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
  351         snd_mtxunlock(codec->lock);
  352         return (mode == codec->extstat)? 0 : -1;
  353 }
  354 
  355 u_int16_t
  356 ac97_getextmode(struct ac97_info *codec)
  357 {
  358         return codec->extstat;
  359 }
  360 
  361 u_int16_t
  362 ac97_getextcaps(struct ac97_info *codec)
  363 {
  364         return codec->extcaps;
  365 }
  366 
  367 u_int16_t
  368 ac97_getcaps(struct ac97_info *codec)
  369 {
  370         return codec->caps;
  371 }
  372 
  373 static int
  374 ac97_setrecsrc(struct ac97_info *codec, int channel)
  375 {
  376         struct ac97mixtable_entry *e = &codec->mix[channel];
  377 
  378         if (e->recidx > 0) {
  379                 int val = e->recidx - 1;
  380                 val |= val << 8;
  381                 snd_mtxlock(codec->lock);
  382                 ac97_wrcd(codec, AC97_REG_RECSEL, val);
  383                 snd_mtxunlock(codec->lock);
  384                 return 0;
  385         } else
  386                 return -1;
  387 }
  388 
  389 static int
  390 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
  391 {
  392         struct ac97mixtable_entry *e = &codec->mix[channel];
  393 
  394         if (e->reg && e->enable && e->bits) {
  395                 int mask, max, val, reg;
  396 
  397                 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register    */
  398                 max = (1 << e->bits) - 1;               /* actual range     */
  399                 mask = (max << 8) | max;                /* bits of interest */
  400 
  401                 if (!e->stereo)
  402                         right = left;
  403 
  404                 /*
  405                  * Invert the range if the polarity requires so,
  406                  * then scale to 0..max-1 to compute the value to
  407                  * write into the codec, and scale back to 0..100
  408                  * for the return value.
  409                  */
  410                 if (e->reg > 0) {
  411                         left = 100 - left;
  412                         right = 100 - right;
  413                 }
  414 
  415                 left = (left * max) / 100;
  416                 right = (right * max) / 100;
  417 
  418                 val = (left << 8) | right;
  419 
  420                 left = (left * 100) / max;
  421                 right = (right * 100) / max;
  422 
  423                 if (e->reg > 0) {
  424                         left = 100 - left;
  425                         right = 100 - right;
  426                 }
  427 
  428                 /*
  429                  * For mono controls, trim val and mask, also taking
  430                  * care of e->ofs (offset of control field).
  431                  */
  432                 if (e->ofs) {
  433                         val &= max;
  434                         val <<= e->ofs;
  435                         mask = (max << e->ofs);
  436                 }
  437 
  438                 /*
  439                  * If we have a mute bit, add it to the mask and
  440                  * update val and set mute if both channels require a
  441                  * zero volume.
  442                  */
  443                 if (e->mute == 1) {
  444                         mask |= AC97_MUTE;
  445                         if (left == 0 && right == 0)
  446                                 val = AC97_MUTE;
  447                 }
  448 
  449                 /*
  450                  * If the mask bit is set, do not alter the other bits.
  451                  */
  452                 snd_mtxlock(codec->lock);
  453                 if (e->mask) {
  454                         int cur = ac97_rdcd(codec, e->reg);
  455                         val |= cur & ~(mask);
  456                 }
  457                 ac97_wrcd(codec, reg, val);
  458                 snd_mtxunlock(codec->lock);
  459                 return left | (right << 8);
  460         } else {
  461                 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
  462                 return -1;
  463         }
  464 }
  465 
  466 static void
  467 ac97_fix_auxout(struct ac97_info *codec)
  468 {
  469         int keep_ogain;
  470 
  471         /*
  472          * By default, The ac97 aux_out register (0x04) corresponds to OSS's
  473          * OGAIN setting.
  474          *
  475          * We first check whether aux_out is a valid register.  If not
  476          * we may not want to keep ogain.
  477          */
  478         keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
  479 
  480         /*
  481          * Determine what AUX_OUT really means, it can be:
  482          *
  483          * 1. Headphone out.
  484          * 2. 4-Channel Out
  485          * 3. True line level out (effectively master volume).
  486          *
  487          * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
  488          */
  489         if (codec->extcaps & AC97_EXTCAP_SDAC &&
  490             ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
  491                 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
  492                 keep_ogain = 1;
  493         }
  494 
  495         if (keep_ogain == 0) {
  496                 bzero(&codec->mix[SOUND_MIXER_OGAIN],
  497                       sizeof(codec->mix[SOUND_MIXER_OGAIN]));
  498         }
  499 }
  500 
  501 static void
  502 ac97_fix_tone(struct ac97_info *codec)
  503 {
  504         /* Hide treble and bass if they don't exist */
  505         if ((codec->caps & AC97_CAP_TONE) == 0) {
  506                 bzero(&codec->mix[SOUND_MIXER_BASS],
  507                       sizeof(codec->mix[SOUND_MIXER_BASS]));
  508                 bzero(&codec->mix[SOUND_MIXER_TREBLE],
  509                       sizeof(codec->mix[SOUND_MIXER_TREBLE]));
  510         }
  511 }
  512 
  513 static const char*
  514 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
  515 {
  516         if (cname == NULL) {
  517                 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
  518                 return buf;
  519         }
  520 
  521         if (vname == NULL) vname = "Unknown";
  522 
  523         if (bootverbose) {
  524                 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
  525         } else {
  526                 sprintf(buf, "%s %s AC97 Codec", vname, cname);
  527         }
  528         return buf;
  529 }
  530 
  531 static unsigned
  532 ac97_initmixer(struct ac97_info *codec)
  533 {
  534         ac97_patch codec_patch;
  535         const char *cname, *vname;
  536         char desc[80];
  537         u_int8_t model, step;
  538         unsigned i, j, k, old;
  539         u_int32_t id;
  540 
  541         snd_mtxlock(codec->lock);
  542         codec->count = AC97_INIT(codec->methods, codec->devinfo);
  543         if (codec->count == 0) {
  544                 device_printf(codec->dev, "ac97 codec init failed\n");
  545                 snd_mtxunlock(codec->lock);
  546                 return ENODEV;
  547         }
  548 
  549         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  550         ac97_reset(codec);
  551         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  552 
  553         i = ac97_rdcd(codec, AC97_REG_RESET);
  554         codec->caps = i & 0x03ff;
  555         codec->se =  (i & 0x7c00) >> 10;
  556 
  557         id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
  558         if (id == 0 || id == 0xffffffff) {
  559                 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
  560                 snd_mtxunlock(codec->lock);
  561                 return ENODEV;
  562         }
  563 
  564         codec->id = id;
  565         codec->noext = 0;
  566         codec_patch = NULL;
  567 
  568         cname = NULL;
  569         model = step = 0;
  570         for (i = 0; ac97codecid[i].id; i++) {
  571                 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
  572                 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
  573                         codec->noext = ac97codecid[i].noext;
  574                         codec_patch = ac97codecid[i].patch;
  575                         cname = ac97codecid[i].name;
  576                         model = (id & modelmask) & 0xff;
  577                         step = (id & ~modelmask) & 0xff;
  578                         break;
  579                 }
  580         }
  581 
  582         vname = NULL;
  583         for (i = 0; ac97vendorid[i].id; i++) {
  584                 if (ac97vendorid[i].id == (id & 0xffffff00)) {
  585                         vname = ac97vendorid[i].name;
  586                         break;
  587                 }
  588         }
  589 
  590         codec->extcaps = 0;
  591         codec->extid = 0;
  592         codec->extstat = 0;
  593         if (!codec->noext) {
  594                 i = ac97_rdcd(codec, AC97_REGEXT_ID);
  595                 if (i != 0xffff) {
  596                         codec->extcaps = i & 0x3fff;
  597                         codec->extid =  (i & 0xc000) >> 14;
  598                         codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
  599                 }
  600         }
  601 
  602         for (i = 0; i < 32; i++) {
  603                 codec->mix[i] = ac97mixtable_default[i];
  604         }
  605         ac97_fix_auxout(codec);
  606         ac97_fix_tone(codec);
  607         if (codec_patch)
  608                 codec_patch(codec);
  609 
  610         for (i = 0; i < 32; i++) {
  611                 k = codec->noext? codec->mix[i].enable : 1;
  612                 if (k && (codec->mix[i].reg > 0)) {
  613                         old = ac97_rdcd(codec, codec->mix[i].reg);
  614                         ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
  615                         j = ac97_rdcd(codec, codec->mix[i].reg);
  616                         ac97_wrcd(codec, codec->mix[i].reg, old);
  617                         codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
  618                         for (k = 1; j & (1 << k); k++);
  619                         codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
  620                 }
  621                 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
  622         }
  623 
  624         device_printf(codec->dev, "<%s>\n",
  625                       ac97_hw_desc(codec->id, vname, cname, desc));
  626 
  627         if (bootverbose) {
  628                 device_printf(codec->dev, "Codec features ");
  629                 for (i = j = 0; i < 10; i++)
  630                         if (codec->caps & (1 << i))
  631                                 printf("%s%s", j++? ", " : "", ac97feature[i]);
  632                 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
  633                 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
  634 
  635                 if (codec->extcaps != 0 || codec->extid) {
  636                         device_printf(codec->dev, "%s codec",
  637                                       codec->extid? "Secondary" : "Primary");
  638                         if (codec->extcaps)
  639                                 printf(" extended features ");
  640                         for (i = j = 0; i < 14; i++)
  641                                 if (codec->extcaps & (1 << i))
  642                                         printf("%s%s", j++? ", " : "", ac97extfeature[i]);
  643                         printf("\n");
  644                 }
  645         }
  646 
  647         if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
  648                 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
  649         snd_mtxunlock(codec->lock);
  650         return 0;
  651 }
  652 
  653 static unsigned
  654 ac97_reinitmixer(struct ac97_info *codec)
  655 {
  656         snd_mtxlock(codec->lock);
  657         codec->count = AC97_INIT(codec->methods, codec->devinfo);
  658         if (codec->count == 0) {
  659                 device_printf(codec->dev, "ac97 codec init failed\n");
  660                 snd_mtxunlock(codec->lock);
  661                 return ENODEV;
  662         }
  663 
  664         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  665         ac97_reset(codec);
  666         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  667 
  668         if (!codec->noext) {
  669                 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
  670                 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
  671                     != codec->extstat)
  672                         device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
  673                                       codec->extstat,
  674                                       ac97_rdcd(codec, AC97_REGEXT_STAT) &
  675                                       AC97_EXTCAPS);
  676         }
  677 
  678         if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
  679                 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
  680         snd_mtxunlock(codec->lock);
  681         return 0;
  682 }
  683 
  684 struct ac97_info *
  685 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
  686 {
  687         struct ac97_info *codec;
  688 
  689         codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
  690         if (codec == NULL)
  691                 return NULL;
  692 
  693         snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
  694         codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
  695         codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
  696         if (codec->methods == NULL) {
  697                 snd_mtxlock(codec->lock);
  698                 snd_mtxfree(codec->lock);
  699                 free(codec, M_AC97);
  700                 return NULL;
  701         }
  702 
  703         codec->dev = dev;
  704         codec->devinfo = devinfo;
  705         codec->flags = 0;
  706         return codec;
  707 }
  708 
  709 void
  710 ac97_destroy(struct ac97_info *codec)
  711 {
  712         snd_mtxlock(codec->lock);
  713         if (codec->methods != NULL)
  714                 kobj_delete(codec->methods, M_AC97);
  715         snd_mtxfree(codec->lock);
  716         free(codec, M_AC97);
  717 }
  718 
  719 void
  720 ac97_setflags(struct ac97_info *codec, u_int32_t val)
  721 {
  722         codec->flags = val;
  723 }
  724 
  725 u_int32_t
  726 ac97_getflags(struct ac97_info *codec)
  727 {
  728         return codec->flags;
  729 }
  730 
  731 /* -------------------------------------------------------------------- */
  732 
  733 static int
  734 ac97mix_init(struct snd_mixer *m)
  735 {
  736         struct ac97_info *codec = mix_getdevinfo(m);
  737         u_int32_t i, mask;
  738 
  739         if (codec == NULL)
  740                 return -1;
  741 
  742         if (ac97_initmixer(codec))
  743                 return -1;
  744 
  745         mask = 0;
  746         for (i = 0; i < 32; i++)
  747                 mask |= codec->mix[i].enable? 1 << i : 0;
  748         mix_setdevs(m, mask);
  749 
  750         mask = 0;
  751         for (i = 0; i < 32; i++)
  752                 mask |= codec->mix[i].recidx? 1 << i : 0;
  753         mix_setrecdevs(m, mask);
  754         return 0;
  755 }
  756 
  757 static int
  758 ac97mix_uninit(struct snd_mixer *m)
  759 {
  760         struct ac97_info *codec = mix_getdevinfo(m);
  761 
  762         if (codec == NULL)
  763                 return -1;
  764         /*
  765         if (ac97_uninitmixer(codec))
  766                 return -1;
  767         */
  768         ac97_destroy(codec);
  769         return 0;
  770 }
  771 
  772 static int
  773 ac97mix_reinit(struct snd_mixer *m)
  774 {
  775         struct ac97_info *codec = mix_getdevinfo(m);
  776 
  777         if (codec == NULL)
  778                 return -1;
  779         return ac97_reinitmixer(codec);
  780 }
  781 
  782 static int
  783 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
  784 {
  785         struct ac97_info *codec = mix_getdevinfo(m);
  786 
  787         if (codec == NULL)
  788                 return -1;
  789         return ac97_setmixer(codec, dev, left, right);
  790 }
  791 
  792 static int
  793 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
  794 {
  795         int i;
  796         struct ac97_info *codec = mix_getdevinfo(m);
  797 
  798         if (codec == NULL)
  799                 return -1;
  800         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  801                 if ((src & (1 << i)) != 0)
  802                         break;
  803         return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
  804 }
  805 
  806 static kobj_method_t ac97mixer_methods[] = {
  807         KOBJMETHOD(mixer_init,          ac97mix_init),
  808         KOBJMETHOD(mixer_uninit,        ac97mix_uninit),
  809         KOBJMETHOD(mixer_reinit,        ac97mix_reinit),
  810         KOBJMETHOD(mixer_set,           ac97mix_set),
  811         KOBJMETHOD(mixer_setrecsrc,     ac97mix_setrecsrc),
  812         { 0, 0 }
  813 };
  814 MIXER_DECLARE(ac97mixer);
  815 
  816 /* -------------------------------------------------------------------- */
  817 
  818 kobj_class_t
  819 ac97_getmixerclass(void)
  820 {
  821         return &ac97mixer_class;
  822 }
  823 
  824 

Cache object: 224343f16a0989a7eef3f13415c22181


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