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/mixer.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  * $FreeBSD: src/sys/dev/sound/pcm/mixer.c,v 1.43.2.5 2007/05/13 20:53:39 ariff Exp $
   27  */
   28 
   29 #include <dev/sound/pcm/sound.h>
   30 #include <dev/sound/pcm/dsp.h>
   31 
   32 #include "mixer_if.h"
   33 
   34 
   35 MALLOC_DEFINE(M_MIXER, "mixer", "mixer");
   36 
   37 #define MIXER_NAMELEN   16
   38 struct snd_mixer {
   39         KOBJ_FIELDS;
   40         const char *type;
   41         void *devinfo;
   42         int busy;
   43         int hwvol_muted;
   44         int hwvol_mixer;
   45         int hwvol_step;
   46         device_t dev;
   47         u_int32_t hwvol_mute_level;
   48         u_int32_t devs;
   49         u_int32_t recdevs;
   50         u_int32_t recsrc;
   51         u_int16_t level[32];
   52         u_int8_t parent[32];
   53         u_int32_t child[32];
   54         u_int8_t realdev[32];
   55         char name[MIXER_NAMELEN];
   56         sndlock_t       lock;
   57 };
   58 
   59 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
   60         [SOUND_MIXER_VOLUME]    = 75,
   61         [SOUND_MIXER_BASS]      = 50,
   62         [SOUND_MIXER_TREBLE]    = 50,
   63         [SOUND_MIXER_SYNTH]     = 75,
   64         [SOUND_MIXER_PCM]       = 75,
   65         [SOUND_MIXER_SPEAKER]   = 75,
   66         [SOUND_MIXER_LINE]      = 75,
   67         [SOUND_MIXER_MIC]       = 0,
   68         [SOUND_MIXER_CD]        = 75,
   69         [SOUND_MIXER_IGAIN]     = 0,
   70         [SOUND_MIXER_LINE1]     = 75,
   71         [SOUND_MIXER_VIDEO]     = 75,
   72         [SOUND_MIXER_RECLEV]    = 0,
   73         [SOUND_MIXER_OGAIN]     = 50,
   74         [SOUND_MIXER_MONITOR]   = 75,
   75 };
   76 
   77 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
   78 
   79 static d_open_t mixer_open;
   80 static d_close_t mixer_close;
   81 
   82 static struct dev_ops mixer_cdevsw = {
   83         { "mixer", 0, D_TRACKCLOSE },
   84         /* .d_flags =   D_TRACKCLOSE | D_NEEDGIANT, */
   85         .d_open =       mixer_open,
   86         .d_close =      mixer_close,
   87         .d_ioctl =      mixer_ioctl,
   88 };
   89 
   90 #ifdef USING_DEVFS
   91 static eventhandler_tag mixer_ehtag;
   92 #endif
   93 
   94 static struct cdev *
   95 mixer_get_devt(device_t dev)
   96 {
   97         struct snddev_info *snddev;
   98 
   99         snddev = device_get_softc(dev);
  100 
  101         return snddev->mixer_dev;
  102 }
  103 
  104 #ifdef SND_DYNSYSCTL
  105 static int
  106 mixer_lookup(char *devname)
  107 {
  108         int i;
  109 
  110         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  111                 if (strncmp(devname, snd_mixernames[i],
  112                     strlen(snd_mixernames[i])) == 0)
  113                         return i;
  114         return -1;
  115 }
  116 #endif
  117 
  118 /*
  119  * Always called with mixer->lock held.
  120  */
  121 static int
  122 mixer_set_softpcmvol(struct snd_mixer *mixer, struct snddev_info *d,
  123                                                 unsigned left, unsigned right)
  124 {
  125         struct snddev_channel *sce;
  126         struct pcm_channel *ch;
  127         
  128         snd_mtxunlock(mixer->lock);
  129         SLIST_FOREACH(sce, &d->channels, link) {
  130                 ch = sce->channel;
  131                 CHN_LOCK(ch);
  132                 if (ch->direction == PCMDIR_PLAY &&
  133                                 (ch->feederflags & (1 << FEEDER_VOLUME)))
  134                         chn_setvolume(ch, left, right);
  135                 CHN_UNLOCK(ch);
  136         }
  137         snd_mtxlock(mixer->lock);
  138         return 0;
  139 }
  140 
  141 static int
  142 mixer_set(struct snd_mixer *m, unsigned dev, unsigned lev)
  143 {
  144         struct snddev_info *d;
  145         unsigned l, r, tl, tr;
  146         u_int32_t parent = SOUND_MIXER_NONE, child = 0;
  147         u_int32_t realdev;
  148         int i;
  149 
  150         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
  151             (0 == (m->devs & (1 << dev))))
  152                 return -1;
  153 
  154         l = min((lev & 0x00ff), 100);
  155         r = min(((lev & 0xff00) >> 8), 100);
  156         realdev = m->realdev[dev];
  157 
  158         d = device_get_softc(m->dev);
  159         if (d == NULL)
  160                 return -1;
  161 
  162         /* TODO: recursive handling */
  163         parent = m->parent[dev];
  164         if (parent >= SOUND_MIXER_NRDEVICES)
  165                 parent = SOUND_MIXER_NONE;
  166         if (parent == SOUND_MIXER_NONE)
  167                 child = m->child[dev];
  168 
  169         if (parent != SOUND_MIXER_NONE) {
  170                 tl = (l * (m->level[parent] & 0x00ff)) / 100;
  171                 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
  172                 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
  173                         mixer_set_softpcmvol(m, d, tl, tr);
  174                 else if (realdev != SOUND_MIXER_NONE &&
  175                     MIXER_SET(m, realdev, tl, tr) < 0)
  176                         return -1;
  177         } else if (child != 0) {
  178                 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  179                         if (!(child & (1 << i)) || m->parent[i] != dev)
  180                                 continue;
  181                         realdev = m->realdev[i];
  182                         tl = (l * (m->level[i] & 0x00ff)) / 100;
  183                         tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
  184                         if (i == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
  185                                 mixer_set_softpcmvol(m, d, tl, tr);
  186                         else if (realdev != SOUND_MIXER_NONE)
  187                                 MIXER_SET(m, realdev, tl, tr);
  188                 }
  189                 realdev = m->realdev[dev];
  190                 if (realdev != SOUND_MIXER_NONE &&
  191                     MIXER_SET(m, realdev, l, r) < 0)
  192                         return -1;
  193         } else {
  194                 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
  195                         mixer_set_softpcmvol(m, d, l, r);
  196                 else if (realdev != SOUND_MIXER_NONE &&
  197                     MIXER_SET(m, realdev, l, r) < 0)
  198                         return -1;
  199         }
  200 
  201         m->level[dev] = l | (r << 8);
  202 
  203         return 0;
  204 }
  205 
  206 static int
  207 mixer_get(struct snd_mixer *mixer, int dev)
  208 {
  209         if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev)))
  210                 return mixer->level[dev];
  211         else return -1;
  212 }
  213 
  214 static int
  215 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
  216 {
  217         src &= mixer->recdevs;
  218         if (src == 0)
  219                 src = SOUND_MASK_MIC;
  220         mixer->recsrc = MIXER_SETRECSRC(mixer, src);
  221         return 0;
  222 }
  223 
  224 static int
  225 mixer_getrecsrc(struct snd_mixer *mixer)
  226 {
  227         return mixer->recsrc;
  228 }
  229 
  230 void
  231 mix_setdevs(struct snd_mixer *m, u_int32_t v)
  232 {
  233         struct snddev_info *d;
  234         int i;
  235 
  236         if (m == NULL)
  237                 return;
  238 
  239         d = device_get_softc(m->dev);
  240         if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
  241                 v |= SOUND_MASK_PCM;
  242         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  243                 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
  244                         v |= 1 << m->parent[i];
  245                 v |= m->child[i];
  246         }
  247         m->devs = v;
  248 }
  249 
  250 void
  251 mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
  252 {
  253         m->recdevs = v;
  254 }
  255 
  256 void
  257 mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs)
  258 {
  259         u_int32_t mask = 0;
  260         int i;
  261 
  262         if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
  263                 return;
  264         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  265                 if (i == parent)
  266                         continue;
  267                 if (childs & (1 << i)) {
  268                         mask |= 1 << i;
  269                         if (m->parent[i] < SOUND_MIXER_NRDEVICES)
  270                                 m->child[m->parent[i]] &= ~(1 << i);
  271                         m->parent[i] = parent;
  272                         m->child[i] = 0;
  273                 }
  274         }
  275         mask &= ~(1 << parent);
  276         m->child[parent] = mask;
  277 }
  278 
  279 void
  280 mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev)
  281 {
  282         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
  283             !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
  284                 return;
  285         m->realdev[dev] = realdev;
  286 }
  287 
  288 u_int32_t
  289 mix_getparent(struct snd_mixer *m, u_int32_t dev)
  290 {
  291         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
  292                 return SOUND_MIXER_NONE;
  293         return m->parent[dev];
  294 }
  295 
  296 u_int32_t
  297 mix_getchild(struct snd_mixer *m, u_int32_t dev)
  298 {
  299         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
  300                 return 0;
  301         return m->child[dev];
  302 }
  303 
  304 u_int32_t
  305 mix_getdevs(struct snd_mixer *m)
  306 {
  307         return m->devs;
  308 }
  309 
  310 u_int32_t
  311 mix_getrecdevs(struct snd_mixer *m)
  312 {
  313         return m->recdevs;
  314 }
  315 
  316 void *
  317 mix_getdevinfo(struct snd_mixer *m)
  318 {
  319         return m->devinfo;
  320 }
  321 
  322 int
  323 mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
  324 {
  325         struct snddev_info *snddev;
  326         struct snd_mixer *m;
  327         u_int16_t v;
  328         struct cdev *pdev;
  329         int i, unit, val;
  330 
  331         m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
  332         ksnprintf(m->name, MIXER_NAMELEN, "%s:mixer", device_get_nameunit(dev));
  333         m->lock = snd_mtxcreate(m->name, "pcm mixer");
  334         m->type = cls->name;
  335         m->devinfo = devinfo;
  336         m->busy = 0;
  337         m->dev = dev;
  338         for (i = 0; i < 32; i++) {
  339                 m->parent[i] = SOUND_MIXER_NONE;
  340                 m->child[i] = 0;
  341                 m->realdev[i] = i;
  342         }
  343 
  344         if (MIXER_INIT(m))
  345                 goto bad;
  346 
  347         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  348                 v = snd_mixerdefaults[i];
  349 
  350                 if (resource_int_value(device_get_name(dev),
  351                     device_get_unit(dev), snd_mixernames[i], &val) == 0) {
  352                         if (val >= 0 && val <= 100) {
  353                                 v = (u_int16_t) val;
  354                         }
  355                 }
  356 
  357                 snd_mtxlock(m->lock);
  358                 mixer_set(m, i, v | (v << 8));
  359                 snd_mtxunlock(m->lock);
  360         }
  361 
  362         mixer_setrecsrc(m, SOUND_MASK_MIC);
  363 
  364         unit = device_get_unit(dev);
  365         pdev = make_dev(&mixer_cdevsw, PCMMKMINOR(unit, 0),
  366                         UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
  367         reference_dev(pdev);
  368         pdev->si_drv1 = m;
  369         snddev = device_get_softc(dev);
  370         snddev->mixer_dev = pdev;
  371 
  372         if (bootverbose) {
  373                 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  374                         if (!(m->devs & (1 << i)))
  375                                 continue;
  376                         if (m->realdev[i] != i) {
  377                                 device_printf(dev, "Mixer \"%s\" -> \"%s\":",
  378                                     snd_mixernames[i],
  379                                     (m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
  380                                     snd_mixernames[m->realdev[i]] : "none");
  381                         } else {
  382                                 device_printf(dev, "Mixer \"%s\":",
  383                                     snd_mixernames[i]);
  384                         }
  385                         if (m->parent[i] < SOUND_MIXER_NRDEVICES)
  386                                 kprintf(" parent=\"%s\"",
  387                                     snd_mixernames[m->parent[i]]);
  388                         if (m->child[i] != 0)
  389                                 kprintf(" child=0x%08x", m->child[i]);
  390                         kprintf("\n");
  391                 }
  392                 if (snddev->flags & SD_F_SOFTPCMVOL)
  393                         device_printf(dev, "Soft PCM mixer ENABLED\n");
  394         }
  395 
  396         return 0;
  397 
  398 bad:
  399         snd_mtxfree(m->lock);
  400         kobj_delete((kobj_t)m, M_MIXER);
  401         return -1;
  402 }
  403 
  404 int
  405 mixer_uninit(device_t dev)
  406 {
  407         int i;
  408         int unit;
  409         struct snddev_info *d;
  410         struct snd_mixer *m;
  411         struct cdev *pdev;
  412 
  413         d = device_get_softc(dev);
  414         pdev = mixer_get_devt(dev);
  415         if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL)
  416                 return EBADF;
  417         m = pdev->si_drv1;
  418         snd_mtxlock(m->lock);
  419 
  420         if (m->busy) {
  421                 snd_mtxunlock(m->lock);
  422                 return EBUSY;
  423         }
  424 
  425         pdev->si_drv1 = NULL;
  426         release_dev(pdev);
  427         unit = device_get_unit(dev);
  428         dev_ops_remove_minor(&mixer_cdevsw, /*-1, */PCMMKMINOR(unit, 0));
  429 
  430         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  431                 mixer_set(m, i, 0);
  432 
  433         mixer_setrecsrc(m, SOUND_MASK_MIC);
  434 
  435         MIXER_UNINIT(m);
  436 
  437         snd_mtxunlock(m->lock);
  438         snd_mtxfree(m->lock);
  439         kobj_delete((kobj_t)m, M_MIXER);
  440 
  441         d->mixer_dev = NULL;
  442 
  443         return 0;
  444 }
  445 
  446 int
  447 mixer_reinit(device_t dev)
  448 {
  449         struct snd_mixer *m;
  450         struct cdev *pdev;
  451         int i;
  452 
  453         pdev = mixer_get_devt(dev);
  454         m = pdev->si_drv1;
  455         snd_mtxlock(m->lock);
  456 
  457         i = MIXER_REINIT(m);
  458         if (i) {
  459                 snd_mtxunlock(m->lock);
  460                 return i;
  461         }
  462 
  463         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  464                 mixer_set(m, i, m->level[i]);
  465 
  466         mixer_setrecsrc(m, m->recsrc);
  467         snd_mtxunlock(m->lock);
  468 
  469         return 0;
  470 }
  471 
  472 #ifdef SND_DYNSYSCTL
  473 static int
  474 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
  475 {
  476         char devname[32];
  477         int error, dev;
  478         struct snd_mixer *m;
  479 
  480         m = oidp->oid_arg1;
  481         snd_mtxlock(m->lock);
  482         strncpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
  483         snd_mtxunlock(m->lock);
  484         error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
  485         snd_mtxlock(m->lock);
  486         if (error == 0 && req->newptr != NULL) {
  487                 dev = mixer_lookup(devname);
  488                 if (dev == -1) {
  489                         snd_mtxunlock(m->lock);
  490                         return EINVAL;
  491                 }
  492                 else if (dev != m->hwvol_mixer) {
  493                         m->hwvol_mixer = dev;
  494                         m->hwvol_muted = 0;
  495                 }
  496         }
  497         snd_mtxunlock(m->lock);
  498         return error;
  499 }
  500 #endif
  501 
  502 int
  503 mixer_hwvol_init(device_t dev)
  504 {
  505         struct snd_mixer *m;
  506         struct cdev *pdev;
  507 
  508         pdev = mixer_get_devt(dev);
  509         m = pdev->si_drv1;
  510 
  511         m->hwvol_mixer = SOUND_MIXER_VOLUME;
  512         m->hwvol_step = 5;
  513 #ifdef SND_DYNSYSCTL
  514         SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  515             OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, "");
  516         SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  517             OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
  518             sysctl_hw_snd_hwvol_mixer, "A", "");
  519 #endif
  520         return 0;
  521 }
  522 
  523 void
  524 mixer_hwvol_mute(device_t dev)
  525 {
  526         struct snd_mixer *m;
  527         struct cdev *pdev;
  528 
  529         pdev = mixer_get_devt(dev);
  530         m = pdev->si_drv1;
  531         snd_mtxlock(m->lock);
  532         if (m->hwvol_muted) {
  533                 m->hwvol_muted = 0;
  534                 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
  535         } else {
  536                 m->hwvol_muted++;
  537                 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
  538                 mixer_set(m, m->hwvol_mixer, 0);
  539         }
  540         snd_mtxunlock(m->lock);
  541 }
  542 
  543 void
  544 mixer_hwvol_step(device_t dev, int left_step, int right_step)
  545 {
  546         struct snd_mixer *m;
  547         int level, left, right;
  548         struct cdev *pdev;
  549 
  550         pdev = mixer_get_devt(dev);
  551         m = pdev->si_drv1;
  552         snd_mtxlock(m->lock);
  553         if (m->hwvol_muted) {
  554                 m->hwvol_muted = 0;
  555                 level = m->hwvol_mute_level;
  556         } else
  557                 level = mixer_get(m, m->hwvol_mixer);
  558         if (level != -1) {
  559                 left = level & 0xff;
  560                 right = level >> 8;
  561                 left += left_step * m->hwvol_step;
  562                 if (left < 0)
  563                         left = 0;
  564                 right += right_step * m->hwvol_step;
  565                 if (right < 0)
  566                         right = 0;
  567                 mixer_set(m, m->hwvol_mixer, left | right << 8);
  568         }
  569         snd_mtxunlock(m->lock);
  570 }
  571 
  572 /* ----------------------------------------------------------------------- */
  573 
  574 static int
  575 vchanvolume(cdev_t i_dev, int write, int *volume, int *ret,
  576                 struct thread *td)
  577 {
  578         struct snddev_info *d;
  579         void *cookie;
  580         struct pcm_channel *ch;
  581         int vol_left, vol_right;
  582 
  583         crit_enter();
  584         d = dsp_get_info(i_dev);
  585         if (d == NULL) {
  586                 crit_exit();
  587                 return 0;
  588         }
  589         /*
  590          * We search for a vchan which is owned by the current process.
  591          */
  592         for (cookie = NULL; (ch = pcm_chn_iterate(d, &cookie)) != NULL;)
  593                 if (ch->flags & CHN_F_VIRTUAL &&
  594                     ch->pid == td->td_proc->p_pid)
  595                         break;
  596 
  597         if (ch == NULL) {
  598                 crit_exit();
  599                 return 0;
  600         }
  601 
  602         if (write) {
  603                 vol_left = min(*volume & 0x00ff, 100);
  604                 vol_right = min((*volume & 0xff00) >> 8, 100);
  605                 *ret = chn_setvolume(ch, vol_left, vol_right);
  606         } else {
  607                 *volume = ch->volume;
  608                 *ret = 0;
  609         }
  610         crit_exit();
  611         return 1;
  612 }
  613 
  614 /* ----------------------------------------------------------------------- */
  615 
  616 static int
  617 mixer_open(struct dev_open_args *ap)
  618 {
  619         struct cdev *i_dev = ap->a_head.a_dev;
  620         struct snd_mixer *m;
  621 
  622         m = i_dev->si_drv1;
  623         snd_mtxlock(m->lock);
  624 
  625         m->busy++;
  626 
  627         snd_mtxunlock(m->lock);
  628         return 0;
  629 }
  630 
  631 static int
  632 mixer_close(struct dev_close_args *ap)
  633 {
  634         struct cdev *i_dev = ap->a_head.a_dev;
  635         struct snd_mixer *m;
  636 
  637         m = i_dev->si_drv1;
  638         snd_mtxlock(m->lock);
  639 
  640         if (!m->busy) {
  641                 snd_mtxunlock(m->lock);
  642                 return EBADF;
  643         }
  644         m->busy--;
  645 
  646         snd_mtxunlock(m->lock);
  647         return 0;
  648 }
  649 
  650 int
  651 mixer_ioctl(struct dev_ioctl_args *ap)
  652 {
  653         struct cdev *i_dev = ap->a_head.a_dev;
  654         u_long cmd = ap->a_cmd;
  655         caddr_t arg = ap->a_data;
  656         int mode = ap->a_fflag;
  657         struct snd_mixer *m;
  658         int ret, *arg_i = (int *)arg;
  659         int v = -1, j = cmd & 0xff;
  660 
  661         m = i_dev->si_drv1;
  662 
  663         if (m == NULL)
  664                 return EBADF;
  665 
  666         /*
  667          * If we are handling PCM, maybe the app really wants to
  668          * set its vchan, and fails to use the correct fd.
  669          */
  670         if (j == SOUND_MIXER_PCM && curthread->td_proc) {
  671                 if (vchanvolume(i_dev,
  672                             (cmd & MIXER_WRITE(0)) == MIXER_WRITE(0),
  673                             (int *)arg, &ret, curthread))
  674                         return ret;
  675                 /* else proceed as usual */
  676         }
  677 
  678         snd_mtxlock(m->lock);
  679         if (mode != -1 && !m->busy) {
  680                 snd_mtxunlock(m->lock);
  681                 return EBADF;
  682         }
  683 
  684         if (cmd == OSS_GETVERSION) {
  685                 *arg_i = SOUND_VERSION;
  686                 snd_mtxunlock(m->lock);
  687                 return 0;
  688         }
  689 
  690         if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
  691                 if (j == SOUND_MIXER_RECSRC)
  692                         ret = mixer_setrecsrc(m, *arg_i);
  693                 else
  694                         ret = mixer_set(m, j, *arg_i);
  695                 snd_mtxunlock(m->lock);
  696                 return (ret == 0)? 0 : ENXIO;
  697         }
  698 
  699         if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) {
  700                 switch (j) {
  701                 case SOUND_MIXER_DEVMASK:
  702                 case SOUND_MIXER_CAPS:
  703                 case SOUND_MIXER_STEREODEVS:
  704                         v = mix_getdevs(m);
  705                         break;
  706 
  707                 case SOUND_MIXER_RECMASK:
  708                         v = mix_getrecdevs(m);
  709                         break;
  710 
  711                 case SOUND_MIXER_RECSRC:
  712                         v = mixer_getrecsrc(m);
  713                         break;
  714 
  715                 default:
  716                         v = mixer_get(m, j);
  717                 }
  718                 *arg_i = v;
  719                 snd_mtxunlock(m->lock);
  720                 return (v != -1)? 0 : ENXIO;
  721         }
  722         snd_mtxunlock(m->lock);
  723         return ENXIO;
  724 }
  725 
  726 #ifdef USING_DEVFS
  727 static void
  728 mixer_clone(void *arg, struct ucred *cred, char *name, int namelen,
  729     struct cdev **dev)
  730 {
  731         struct snddev_info *sd;
  732 
  733         if (*dev != NULL)
  734                 return;
  735         if (strcmp(name, "mixer") == 0) {
  736                 sd = devclass_get_softc(pcm_devclass, snd_unit);
  737                 if (sd != NULL && sd->mixer_dev != NULL) {
  738                         *dev = sd->mixer_dev;
  739                         dev_ref(*dev);
  740                 }
  741         }
  742 }
  743 
  744 static void
  745 mixer_sysinit(void *p)
  746 {
  747         mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
  748 }
  749 
  750 static void
  751 mixer_sysuninit(void *p)
  752 {
  753         if (mixer_ehtag != NULL)
  754                 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
  755 }
  756 
  757 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
  758 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
  759 #endif
  760 
  761 

Cache object: 9c6083a1b7cd332036b4ef4866cdacfe


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