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

Cache object: f7b653471b0966f9ef0ab1cac1263c17


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