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 <gandalf@vilnya.demon.co.uk>
    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 
   30 #include "mixer_if.h"
   31 
   32 SND_DECLARE_FILE("$FreeBSD: releng/5.0/sys/dev/sound/pcm/ac97.c 107285 2002-11-26 18:16:27Z cg $");
   33 
   34 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
   35 
   36 struct ac97mixtable_entry {
   37         int             reg:8;
   38         unsigned        bits:4;
   39         unsigned        ofs:4;
   40         unsigned        stereo:1;
   41         unsigned        mute:1;
   42         unsigned        recidx:4;
   43         unsigned        mask:1;
   44         unsigned        enable:1;
   45 };
   46 
   47 #define AC97_NAMELEN    16
   48 struct ac97_info {
   49         kobj_t methods;
   50         device_t dev;
   51         void *devinfo;
   52         char *id;
   53         char rev;
   54         unsigned count, caps, se, extcaps, extid, extstat, noext:1;
   55         u_int32_t flags;
   56         struct ac97mixtable_entry mix[32];
   57         char name[AC97_NAMELEN];
   58         struct mtx *lock;
   59 };
   60 
   61 struct ac97_codecid {
   62         u_int32_t id, noext:1;
   63         char *name;
   64 };
   65 
   66 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
   67         [SOUND_MIXER_VOLUME]    = { AC97_MIX_MASTER,    5, 0, 1, 1, 6, 0, 1 },
   68         [SOUND_MIXER_MONITOR]   = { AC97_MIX_AUXOUT,    5, 0, 1, 1, 0, 0, 0 },
   69         [SOUND_MIXER_PHONEOUT]  = { AC97_MIX_MONO,      5, 0, 0, 1, 7, 0, 0 },
   70         [SOUND_MIXER_BASS]      = { AC97_MIX_TONE,      4, 8, 0, 0, 0, 1, 0 },
   71         [SOUND_MIXER_TREBLE]    = { AC97_MIX_TONE,      4, 0, 0, 0, 0, 1, 0 },
   72         [SOUND_MIXER_PCM]       = { AC97_MIX_PCM,       5, 0, 1, 1, 0, 0, 1 },
   73         [SOUND_MIXER_SPEAKER]   = { AC97_MIX_BEEP,      4, 1, 0, 1, 0, 0, 0 },
   74         [SOUND_MIXER_LINE]      = { AC97_MIX_LINE,      5, 0, 1, 1, 5, 0, 1 },
   75         [SOUND_MIXER_PHONEIN]   = { AC97_MIX_PHONE,     5, 0, 0, 1, 8, 0, 0 },
   76         [SOUND_MIXER_MIC]       = { AC97_MIX_MIC,       5, 0, 0, 1, 1, 0, 1 },
   77         [SOUND_MIXER_CD]        = { AC97_MIX_CD,        5, 0, 1, 1, 2, 0, 1 },
   78         [SOUND_MIXER_LINE1]     = { AC97_MIX_AUX,       5, 0, 1, 1, 4, 0, 0 },
   79         [SOUND_MIXER_VIDEO]     = { AC97_MIX_VIDEO,     5, 0, 1, 1, 3, 0, 0 },
   80         [SOUND_MIXER_RECLEV]    = { -AC97_MIX_RGAIN,    4, 0, 1, 1, 0, 0, 1 }
   81 };
   82 
   83 static struct ac97_codecid ac97codecid[] = {
   84         { 0x41445303, 0, "Analog Devices AD1819" },
   85         { 0x41445340, 0, "Analog Devices AD1881" },
   86         { 0x41445348, 0, "Analog Devices AD1881A" },
   87         { 0x41445360, 0, "Analog Devices AD1885" },
   88         { 0x414b4d00, 1, "Asahi Kasei AK4540" },
   89         { 0x414b4d01, 1, "Asahi Kasei AK4542" },
   90         { 0x414b4d02, 1, "Asahi Kasei AK4543" },
   91         { 0x414c4710, 0, "Avance Logic ALC200/200P" },
   92         { 0x43525900, 0, "Cirrus Logic CS4297" },
   93         { 0x43525903, 0, "Cirrus Logic CS4297" },
   94         { 0x43525913, 0, "Cirrus Logic CS4297A" },
   95         { 0x43525914, 0, "Cirrus Logic CS4297B" },
   96         { 0x43525923, 0, "Cirrus Logic CS4294C" },
   97         { 0x4352592b, 0, "Cirrus Logic CS4298C" },
   98         { 0x43525931, 0, "Cirrus Logic CS4299A" },
   99         { 0x43525933, 0, "Cirrus Logic CS4299C" },
  100         { 0x43525934, 0, "Cirrus Logic CS4299D" },
  101         { 0x43525941, 0, "Cirrus Logic CS4201A" },
  102         { 0x43525951, 0, "Cirrus Logic CS4205A" },
  103         { 0x43525961, 0, "Cirrus Logic CS4291A" },
  104         { 0x45838308, 0, "ESS Technology ES1921" },
  105         { 0x49434511, 0, "ICEnsemble ICE1232" },
  106         { 0x4e534331, 0, "National Semiconductor LM4549" },
  107         { 0x83847600, 0, "SigmaTel STAC9700/9783/9784" },
  108         { 0x83847604, 0, "SigmaTel STAC9701/9703/9704/9705" },
  109         { 0x83847605, 0, "SigmaTel STAC9704" },
  110         { 0x83847608, 0, "SigmaTel STAC9708/9711" },
  111         { 0x83847609, 0, "SigmaTel STAC9721/9723" },
  112         { 0x83847644, 0, "SigmaTel STAC9744" },
  113         { 0x83847656, 0, "SigmaTel STAC9756/9757" },
  114         { 0x53494c22, 0, "Silicon Laboratory Si3036" },
  115         { 0x53494c23, 0, "Silicon Laboratory Si3038" },
  116         { 0x54524103, 0, "TriTech TR?????" },
  117         { 0x54524106, 0, "TriTech TR28026" },
  118         { 0x54524108, 0, "TriTech TR28028" },
  119         { 0x54524123, 0, "TriTech TR28602" },
  120         { 0x574d4c00, 0, "Wolfson WM9701A" },
  121         { 0x574d4c03, 0, "Wolfson WM9703/9704" },
  122         { 0x574d4c04, 0, "Wolfson WM9704 (quad)" },
  123         { 0, 0, NULL }
  124 };
  125 
  126 static char *ac97enhancement[] = {
  127         "no 3D Stereo Enhancement",
  128         "Analog Devices Phat Stereo",
  129         "Creative Stereo Enhancement",
  130         "National Semi 3D Stereo Enhancement",
  131         "Yamaha Ymersion",
  132         "BBE 3D Stereo Enhancement",
  133         "Crystal Semi 3D Stereo Enhancement",
  134         "Qsound QXpander",
  135         "Spatializer 3D Stereo Enhancement",
  136         "SRS 3D Stereo Enhancement",
  137         "Platform Tech 3D Stereo Enhancement",
  138         "AKM 3D Audio",
  139         "Aureal Stereo Enhancement",
  140         "Aztech 3D Enhancement",
  141         "Binaura 3D Audio Enhancement",
  142         "ESS Technology Stereo Enhancement",
  143         "Harman International VMAx",
  144         "Nvidea 3D Stereo Enhancement",
  145         "Philips Incredible Sound",
  146         "Texas Instruments 3D Stereo Enhancement",
  147         "VLSI Technology 3D Stereo Enhancement",
  148         "TriTech 3D Stereo Enhancement",
  149         "Realtek 3D Stereo Enhancement",
  150         "Samsung 3D Stereo Enhancement",
  151         "Wolfson Microelectronics 3D Enhancement",
  152         "Delta Integration 3D Enhancement",
  153         "SigmaTel 3D Enhancement",
  154         "Reserved 27",
  155         "Rockwell 3D Stereo Enhancement",
  156         "Reserved 29",
  157         "Reserved 30",
  158         "Reserved 31"
  159 };
  160 
  161 static char *ac97feature[] = {
  162         "mic channel",
  163         "reserved",
  164         "tone",
  165         "simulated stereo",
  166         "headphone",
  167         "bass boost",
  168         "18 bit DAC",
  169         "20 bit DAC",
  170         "18 bit ADC",
  171         "20 bit ADC"
  172 };
  173 
  174 static char *ac97extfeature[] = {
  175         "variable rate PCM",
  176         "double rate PCM",
  177         "reserved 1",
  178         "variable rate mic",
  179         "reserved 2",
  180         "reserved 3",
  181         "center DAC",
  182         "surround DAC",
  183         "LFE DAC",
  184         "AMAP",
  185         "reserved 4",
  186         "reserved 5",
  187         "reserved 6",
  188         "reserved 7",
  189 };
  190 
  191 static u_int16_t
  192 rdcd(struct ac97_info *codec, int reg)
  193 {
  194         return AC97_READ(codec->methods, codec->devinfo, reg);
  195 }
  196 
  197 static void
  198 wrcd(struct ac97_info *codec, int reg, u_int16_t val)
  199 {
  200         AC97_WRITE(codec->methods, codec->devinfo, reg, val);
  201 }
  202 
  203 static void
  204 ac97_reset(struct ac97_info *codec)
  205 {
  206         u_int32_t i, ps;
  207         wrcd(codec, AC97_REG_RESET, 0);
  208         for (i = 0; i < 500; i++) {
  209                 ps = rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
  210                 if (ps == AC97_POWER_STATUS)
  211                         return;
  212                 DELAY(1000);
  213         }
  214         device_printf(codec->dev, "AC97 reset timed out.");
  215 }
  216 
  217 int
  218 ac97_setrate(struct ac97_info *codec, int which, int rate)
  219 {
  220         u_int16_t v;
  221 
  222         switch(which) {
  223         case AC97_REGEXT_FDACRATE:
  224         case AC97_REGEXT_SDACRATE:
  225         case AC97_REGEXT_LDACRATE:
  226         case AC97_REGEXT_LADCRATE:
  227         case AC97_REGEXT_MADCRATE:
  228                 break;
  229 
  230         default:
  231                 return -1;
  232         }
  233 
  234         snd_mtxlock(codec->lock);
  235         if (rate != 0) {
  236                 v = rate;
  237                 if (codec->extstat & AC97_EXTCAP_DRA)
  238                         v >>= 1;
  239                 wrcd(codec, which, v);
  240         }
  241         v = rdcd(codec, which);
  242         if (codec->extstat & AC97_EXTCAP_DRA)
  243                 v <<= 1;
  244         snd_mtxunlock(codec->lock);
  245         return v;
  246 }
  247 
  248 int
  249 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
  250 {
  251         mode &= AC97_EXTCAPS;
  252         if ((mode & ~codec->extcaps) != 0) {
  253                 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
  254                               mode);
  255                 return -1;
  256         }
  257         snd_mtxlock(codec->lock);
  258         wrcd(codec, AC97_REGEXT_STAT, mode);
  259         codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
  260         snd_mtxunlock(codec->lock);
  261         return (mode == codec->extstat)? 0 : -1;
  262 }
  263 
  264 u_int16_t
  265 ac97_getextmode(struct ac97_info *codec)
  266 {
  267         return codec->extstat;
  268 }
  269 
  270 u_int16_t
  271 ac97_getextcaps(struct ac97_info *codec)
  272 {
  273         return codec->extcaps;
  274 }
  275 
  276 u_int16_t
  277 ac97_getcaps(struct ac97_info *codec)
  278 {
  279         return codec->caps;
  280 }
  281 
  282 static int
  283 ac97_setrecsrc(struct ac97_info *codec, int channel)
  284 {
  285         struct ac97mixtable_entry *e = &codec->mix[channel];
  286 
  287         if (e->recidx > 0) {
  288                 int val = e->recidx - 1;
  289                 val |= val << 8;
  290                 snd_mtxlock(codec->lock);
  291                 wrcd(codec, AC97_REG_RECSEL, val);
  292                 snd_mtxunlock(codec->lock);
  293                 return 0;
  294         } else
  295                 return -1;
  296 }
  297 
  298 static int
  299 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
  300 {
  301         struct ac97mixtable_entry *e = &codec->mix[channel];
  302 
  303         if (e->reg && e->enable && e->bits) {
  304                 int max, val, reg = (e->reg >= 0)? e->reg : -e->reg;
  305 
  306                 if (!e->stereo)
  307                         right = left;
  308                 if (e->reg > 0) {
  309                         left = 100 - left;
  310                         right = 100 - right;
  311                 }
  312 
  313                 max = (1 << e->bits) - 1;
  314                 left = (left * max) / 100;
  315                 right = (right * max) / 100;
  316 
  317                 val = (left << 8) | right;
  318 
  319                 left = (left * 100) / max;
  320                 right = (right * 100) / max;
  321 
  322                 if (e->reg > 0) {
  323                         left = 100 - left;
  324                         right = 100 - right;
  325                 }
  326 
  327                 if (!e->stereo) {
  328                         val &= max;
  329                         val <<= e->ofs;
  330                         if (e->mask) {
  331                                 int cur = rdcd(codec, e->reg);
  332                                 val |= cur & ~(max << e->ofs);
  333                         }
  334                 }
  335                 if (left == 0 && right == 0 && e->mute == 1)
  336                         val = AC97_MUTE;
  337                 snd_mtxlock(codec->lock);
  338                 wrcd(codec, reg, val);
  339                 snd_mtxunlock(codec->lock);
  340                 return left | (right << 8);
  341         } else {
  342                 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
  343                 return -1;
  344         }
  345 }
  346 
  347 #if 0
  348 static int
  349 ac97_getmixer(struct ac97_info *codec, int channel)
  350 {
  351         struct ac97mixtable_entry *e = &codec->mix[channel];
  352         if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) {
  353                 int max, val, volume;
  354 
  355                 max = (1 << e->bits) - 1;
  356                 val = rdcd(code, e->reg);
  357                 if (val == AC97_MUTE && e->mute == 1)
  358                         volume = 0;
  359                 else {
  360                         if (e->stereo == 0) val >>= e->ofs;
  361                         val &= max;
  362                         volume = (val * 100) / max;
  363                         if (e->reg > 0) volume = 100 - volume;
  364                 }
  365                 return volume;
  366         } else
  367                 return -1;
  368 }
  369 #endif
  370 
  371 static void
  372 ac97_fix_auxout(struct ac97_info *codec)
  373 {
  374         /* Determine what AUXOUT really means, it can be:
  375          *
  376          * 1. Headphone out.
  377          * 2. 4-Channel Out
  378          * 3. True line level out (effectively master volume).
  379          *
  380          * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
  381          */
  382         if (codec->caps & AC97_CAP_HEADPHONE) {
  383                 /* XXX We should probably check the AUX_OUT initial value.
  384                  * Leave AC97_MIX_AUXOUT - SOUND_MIXER_MONITOR relationship */
  385                 return;
  386         } else if (codec->extcaps & AC97_EXTCAP_SDAC &&
  387                    rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
  388                 /* 4-Channel Out, add an additional gain setting. */
  389                 codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR];
  390         } else {
  391                 /* Master volume is/maybe fixed in h/w, not sufficiently
  392                  * clear in spec to blat SOUND_MIXER_MASTER. */
  393                 codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR];
  394         }
  395         /* Blat monitor, inappropriate label if we get here */
  396         bzero(&codec->mix[SOUND_MIXER_MONITOR],
  397               sizeof(codec->mix[SOUND_MIXER_MONITOR]));
  398 }
  399 
  400 static unsigned
  401 ac97_initmixer(struct ac97_info *codec)
  402 {
  403         unsigned i, j, k, old;
  404         u_int32_t id;
  405 
  406         snd_mtxlock(codec->lock);
  407         codec->count = AC97_INIT(codec->methods, codec->devinfo);
  408         if (codec->count == 0) {
  409                 device_printf(codec->dev, "ac97 codec init failed\n");
  410                 snd_mtxunlock(codec->lock);
  411                 return ENODEV;
  412         }
  413 
  414         wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  415         ac97_reset(codec);
  416         wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  417 
  418         i = rdcd(codec, AC97_REG_RESET);
  419         codec->caps = i & 0x03ff;
  420         codec->se =  (i & 0x7c00) >> 10;
  421 
  422         id = (rdcd(codec, AC97_REG_ID1) << 16) | rdcd(codec, AC97_REG_ID2);
  423         codec->rev = id & 0x000000ff;
  424         if (id == 0 || id == 0xffffffff) {
  425                 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
  426                 snd_mtxunlock(codec->lock);
  427                 return ENODEV;
  428         }
  429 
  430         codec->noext = 0;
  431         codec->id = NULL;
  432         for (i = 0; ac97codecid[i].id; i++) {
  433                 if (ac97codecid[i].id == id) {
  434                         codec->id = ac97codecid[i].name;
  435                         codec->noext = ac97codecid[i].noext;
  436                 }
  437         }
  438 
  439         codec->extcaps = 0;
  440         codec->extid = 0;
  441         codec->extstat = 0;
  442         if (!codec->noext) {
  443                 i = rdcd(codec, AC97_REGEXT_ID);
  444                 if (i != 0xffff) {
  445                         codec->extcaps = i & 0x3fff;
  446                         codec->extid =  (i & 0xc000) >> 14;
  447                         codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
  448                 }
  449         }
  450 
  451         for (i = 0; i < 32; i++) {
  452                 codec->mix[i] = ac97mixtable_default[i];
  453         }
  454         ac97_fix_auxout(codec);
  455 
  456         for (i = 0; i < 32; i++) {
  457                 k = codec->noext? codec->mix[i].enable : 1;
  458                 if (k && (codec->mix[i].reg > 0)) {
  459                         old = rdcd(codec, codec->mix[i].reg);
  460                         wrcd(codec, codec->mix[i].reg, 0x3f);
  461                         j = rdcd(codec, codec->mix[i].reg);
  462                         wrcd(codec, codec->mix[i].reg, old);
  463                         codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
  464                         for (k = 1; j & (1 << k); k++);
  465                         codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
  466                 }
  467                 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
  468         }
  469 
  470         if (bootverbose) {
  471                 device_printf(codec->dev, "ac97 codec id 0x%08x", id);
  472                 if (codec->id)
  473                         printf(" (%s)", codec->id);
  474                 printf("\n");
  475                 device_printf(codec->dev, "ac97 codec features ");
  476                 for (i = j = 0; i < 10; i++)
  477                         if (codec->caps & (1 << i))
  478                                 printf("%s%s", j++? ", " : "", ac97feature[i]);
  479                 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
  480                 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
  481 
  482                 if (codec->extcaps != 0 || codec->extid) {
  483                         device_printf(codec->dev, "ac97 %s codec",
  484                                       codec->extid? "secondary" : "primary");
  485                         if (codec->extcaps)
  486                                 printf(" extended features ");
  487                         for (i = j = 0; i < 14; i++)
  488                                 if (codec->extcaps & (1 << i))
  489                                         printf("%s%s", j++? ", " : "", ac97extfeature[i]);
  490                         printf("\n");
  491                 }
  492         }
  493 
  494         if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
  495                 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
  496         snd_mtxunlock(codec->lock);
  497         return 0;
  498 }
  499 
  500 static unsigned
  501 ac97_reinitmixer(struct ac97_info *codec)
  502 {
  503         snd_mtxlock(codec->lock);
  504         codec->count = AC97_INIT(codec->methods, codec->devinfo);
  505         if (codec->count == 0) {
  506                 device_printf(codec->dev, "ac97 codec init failed\n");
  507                 snd_mtxunlock(codec->lock);
  508                 return ENODEV;
  509         }
  510 
  511         wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  512         ac97_reset(codec);
  513         wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  514 
  515         if (!codec->noext) {
  516                 wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
  517                 if ((rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
  518                     != codec->extstat)
  519                         device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
  520                                       codec->extstat,
  521                                       rdcd(codec, AC97_REGEXT_STAT) &
  522                                         AC97_EXTCAPS);
  523         }
  524 
  525         if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
  526                 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
  527         snd_mtxunlock(codec->lock);
  528         return 0;
  529 }
  530 
  531 struct ac97_info *
  532 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
  533 {
  534         struct ac97_info *codec;
  535 
  536         codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
  537         if (codec == NULL)
  538                 return NULL;
  539 
  540         snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
  541         codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
  542         codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
  543         if (codec->methods == NULL) {
  544                 snd_mtxlock(codec->lock);
  545                 snd_mtxfree(codec->lock);
  546                 free(codec, M_AC97);
  547                 return NULL;
  548         }
  549 
  550         codec->dev = dev;
  551         codec->devinfo = devinfo;
  552         codec->flags = 0;
  553         return codec;
  554 }
  555 
  556 void
  557 ac97_destroy(struct ac97_info *codec)
  558 {
  559         snd_mtxlock(codec->lock);
  560         if (codec->methods != NULL)
  561                 kobj_delete(codec->methods, M_AC97);
  562         snd_mtxfree(codec->lock);
  563         free(codec, M_AC97);
  564 }
  565 
  566 void
  567 ac97_setflags(struct ac97_info *codec, u_int32_t val)
  568 {
  569         codec->flags = val;
  570 }
  571 
  572 u_int32_t
  573 ac97_getflags(struct ac97_info *codec)
  574 {
  575         return codec->flags;
  576 }
  577 
  578 /* -------------------------------------------------------------------- */
  579 
  580 static int
  581 ac97mix_init(struct snd_mixer *m)
  582 {
  583         struct ac97_info *codec = mix_getdevinfo(m);
  584         u_int32_t i, mask;
  585 
  586         if (codec == NULL)
  587                 return -1;
  588 
  589         if (ac97_initmixer(codec))
  590                 return -1;
  591 
  592         mask = 0;
  593         for (i = 0; i < 32; i++)
  594                 mask |= codec->mix[i].enable? 1 << i : 0;
  595         mix_setdevs(m, mask);
  596 
  597         mask = 0;
  598         for (i = 0; i < 32; i++)
  599                 mask |= codec->mix[i].recidx? 1 << i : 0;
  600         mix_setrecdevs(m, mask);
  601         return 0;
  602 }
  603 
  604 static int
  605 ac97mix_uninit(struct snd_mixer *m)
  606 {
  607         struct ac97_info *codec = mix_getdevinfo(m);
  608 
  609         if (codec == NULL)
  610                 return -1;
  611         /*
  612         if (ac97_uninitmixer(codec))
  613                 return -1;
  614         */
  615         ac97_destroy(codec);
  616         return 0;
  617 }
  618 
  619 static int
  620 ac97mix_reinit(struct snd_mixer *m)
  621 {
  622         struct ac97_info *codec = mix_getdevinfo(m);
  623 
  624         if (codec == NULL)
  625                 return -1;
  626         return ac97_reinitmixer(codec);
  627 }
  628 
  629 static int
  630 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
  631 {
  632         struct ac97_info *codec = mix_getdevinfo(m);
  633 
  634         if (codec == NULL)
  635                 return -1;
  636         return ac97_setmixer(codec, dev, left, right);
  637 }
  638 
  639 static int
  640 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
  641 {
  642         int i;
  643         struct ac97_info *codec = mix_getdevinfo(m);
  644 
  645         if (codec == NULL)
  646                 return -1;
  647         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  648                 if ((src & (1 << i)) != 0)
  649                         break;
  650         return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
  651 }
  652 
  653 static kobj_method_t ac97mixer_methods[] = {
  654         KOBJMETHOD(mixer_init,          ac97mix_init),
  655         KOBJMETHOD(mixer_uninit,        ac97mix_uninit),
  656         KOBJMETHOD(mixer_reinit,        ac97mix_reinit),
  657         KOBJMETHOD(mixer_set,           ac97mix_set),
  658         KOBJMETHOD(mixer_setrecsrc,     ac97mix_setrecsrc),
  659         { 0, 0 }
  660 };
  661 MIXER_DECLARE(ac97mixer);
  662 
  663 /* -------------------------------------------------------------------- */
  664 
  665 kobj_class_t
  666 ac97_getmixerclass(void)
  667 {
  668         return &ac97mixer_class;
  669 }
  670 
  671 

Cache object: 67c73497fc2712258332a05939f27923


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