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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <dev/sound/pcm/sound.h>
   28 
   29 #include "mixer_if.h"
   30 
   31 SND_DECLARE_FILE("$FreeBSD: releng/6.3/sys/dev/sound/pcm/mixer.c 169535 2007-05-13 20:53:40Z ariff $");
   32 
   33 MALLOC_DEFINE(M_MIXER, "mixer", "mixer");
   34 
   35 #define MIXER_NAMELEN   16
   36 struct snd_mixer {
   37         KOBJ_FIELDS;
   38         const char *type;
   39         void *devinfo;
   40         int busy;
   41         int hwvol_muted;
   42         int hwvol_mixer;
   43         int hwvol_step;
   44         device_t dev;
   45         u_int32_t hwvol_mute_level;
   46         u_int32_t devs;
   47         u_int32_t recdevs;
   48         u_int32_t recsrc;
   49         u_int16_t level[32];
   50         u_int8_t parent[32];
   51         u_int32_t child[32];
   52         u_int8_t realdev[32];
   53         char name[MIXER_NAMELEN];
   54         struct mtx *lock;
   55 };
   56 
   57 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
   58         [SOUND_MIXER_VOLUME]    = 75,
   59         [SOUND_MIXER_BASS]      = 50,
   60         [SOUND_MIXER_TREBLE]    = 50,
   61         [SOUND_MIXER_SYNTH]     = 75,
   62         [SOUND_MIXER_PCM]       = 75,
   63         [SOUND_MIXER_SPEAKER]   = 75,
   64         [SOUND_MIXER_LINE]      = 75,
   65         [SOUND_MIXER_MIC]       = 0,
   66         [SOUND_MIXER_CD]        = 75,
   67         [SOUND_MIXER_IGAIN]     = 0,
   68         [SOUND_MIXER_LINE1]     = 75,
   69         [SOUND_MIXER_VIDEO]     = 75,
   70         [SOUND_MIXER_RECLEV]    = 0,
   71         [SOUND_MIXER_OGAIN]     = 50,
   72         [SOUND_MIXER_MONITOR]   = 75,
   73 };
   74 
   75 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
   76 
   77 static d_open_t mixer_open;
   78 static d_close_t mixer_close;
   79 
   80 static struct cdevsw mixer_cdevsw = {
   81         .d_version =    D_VERSION,
   82         .d_flags =      D_TRACKCLOSE | D_NEEDGIANT,
   83         .d_open =       mixer_open,
   84         .d_close =      mixer_close,
   85         .d_ioctl =      mixer_ioctl,
   86         .d_name =       "mixer",
   87 };
   88 
   89 #ifdef USING_DEVFS
   90 static eventhandler_tag mixer_ehtag;
   91 #endif
   92 
   93 static struct cdev *
   94 mixer_get_devt(device_t dev)
   95 {
   96         struct snddev_info *snddev;
   97 
   98         snddev = device_get_softc(dev);
   99 
  100         return snddev->mixer_dev;
  101 }
  102 
  103 #ifdef SND_DYNSYSCTL
  104 static int
  105 mixer_lookup(char *devname)
  106 {
  107         int i;
  108 
  109         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  110                 if (strncmp(devname, snd_mixernames[i],
  111                     strlen(snd_mixernames[i])) == 0)
  112                         return i;
  113         return -1;
  114 }
  115 #endif
  116 
  117 static int
  118 mixer_set_softpcmvol(struct snd_mixer *mixer, struct snddev_info *d,
  119                                                 unsigned left, unsigned right)
  120 {
  121         struct snddev_channel *sce;
  122         struct pcm_channel *ch;
  123 #ifdef USING_MUTEX
  124         int locked = (mixer->lock && mtx_owned((struct mtx *)(mixer->lock))) ? 1 : 0;
  125 
  126         if (locked)
  127                 snd_mtxunlock(mixer->lock);
  128 #endif
  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 #ifdef USING_MUTEX
  138         if (locked)
  139                 snd_mtxlock(mixer->lock);
  140 #endif
  141         return 0;
  142 }
  143 
  144 static int
  145 mixer_set(struct snd_mixer *m, unsigned dev, unsigned lev)
  146 {
  147         struct snddev_info *d;
  148         unsigned l, r, tl, tr;
  149         u_int32_t parent = SOUND_MIXER_NONE, child = 0;
  150         u_int32_t realdev;
  151         int i;
  152 
  153         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
  154             (0 == (m->devs & (1 << dev))))
  155                 return -1;
  156 
  157         l = min((lev & 0x00ff), 100);
  158         r = min(((lev & 0xff00) >> 8), 100);
  159         realdev = m->realdev[dev];
  160 
  161         d = device_get_softc(m->dev);
  162         if (d == NULL)
  163                 return -1;
  164 
  165         /* TODO: recursive handling */
  166         parent = m->parent[dev];
  167         if (parent >= SOUND_MIXER_NRDEVICES)
  168                 parent = SOUND_MIXER_NONE;
  169         if (parent == SOUND_MIXER_NONE)
  170                 child = m->child[dev];
  171 
  172         if (parent != SOUND_MIXER_NONE) {
  173                 tl = (l * (m->level[parent] & 0x00ff)) / 100;
  174                 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
  175                 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
  176                         mixer_set_softpcmvol(m, d, tl, tr);
  177                 else if (realdev != SOUND_MIXER_NONE &&
  178                     MIXER_SET(m, realdev, tl, tr) < 0)
  179                         return -1;
  180         } else if (child != 0) {
  181                 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  182                         if (!(child & (1 << i)) || m->parent[i] != dev)
  183                                 continue;
  184                         realdev = m->realdev[i];
  185                         tl = (l * (m->level[i] & 0x00ff)) / 100;
  186                         tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
  187                         if (i == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
  188                                 mixer_set_softpcmvol(m, d, tl, tr);
  189                         else if (realdev != SOUND_MIXER_NONE)
  190                                 MIXER_SET(m, realdev, tl, tr);
  191                 }
  192                 realdev = m->realdev[dev];
  193                 if (realdev != SOUND_MIXER_NONE &&
  194                     MIXER_SET(m, realdev, l, r) < 0)
  195                                 return -1;
  196         } else {
  197                 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
  198                         mixer_set_softpcmvol(m, d, l, r);
  199                 else if (realdev != SOUND_MIXER_NONE &&
  200                     MIXER_SET(m, realdev, l, r) < 0)
  201                         return -1;
  202         }
  203 
  204         m->level[dev] = l | (r << 8);
  205 
  206         return 0;
  207 }
  208 
  209 static int
  210 mixer_get(struct snd_mixer *mixer, int dev)
  211 {
  212         if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev)))
  213                 return mixer->level[dev];
  214         else return -1;
  215 }
  216 
  217 static int
  218 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
  219 {
  220         src &= mixer->recdevs;
  221         if (src == 0)
  222                 src = SOUND_MASK_MIC;
  223         mixer->recsrc = MIXER_SETRECSRC(mixer, src);
  224         return 0;
  225 }
  226 
  227 static int
  228 mixer_getrecsrc(struct snd_mixer *mixer)
  229 {
  230         return mixer->recsrc;
  231 }
  232 
  233 void
  234 mix_setdevs(struct snd_mixer *m, u_int32_t v)
  235 {
  236         struct snddev_info *d;
  237         int i;
  238 
  239         if (m == NULL)
  240                 return;
  241 
  242         d = device_get_softc(m->dev);
  243         if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
  244                 v |= SOUND_MASK_PCM;
  245         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  246                 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
  247                         v |= 1 << m->parent[i];
  248                 v |= m->child[i];
  249         }
  250         m->devs = v;
  251 }
  252 
  253 void
  254 mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
  255 {
  256         m->recdevs = v;
  257 }
  258 
  259 void
  260 mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs)
  261 {
  262         u_int32_t mask = 0;
  263         int i;
  264 
  265         if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
  266                 return;
  267         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  268                 if (i == parent)
  269                         continue;
  270                 if (childs & (1 << i)) {
  271                         mask |= 1 << i;
  272                         if (m->parent[i] < SOUND_MIXER_NRDEVICES)
  273                                 m->child[m->parent[i]] &= ~(1 << i);
  274                         m->parent[i] = parent;
  275                         m->child[i] = 0;
  276                 }
  277         }
  278         mask &= ~(1 << parent);
  279         m->child[parent] = mask;
  280 }
  281 
  282 void
  283 mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev)
  284 {
  285         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
  286             !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
  287                 return;
  288         m->realdev[dev] = realdev;
  289 }
  290 
  291 u_int32_t
  292 mix_getparent(struct snd_mixer *m, u_int32_t dev)
  293 {
  294         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
  295                 return SOUND_MIXER_NONE;
  296         return m->parent[dev];
  297 }
  298 
  299 u_int32_t
  300 mix_getchild(struct snd_mixer *m, u_int32_t dev)
  301 {
  302         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
  303                 return 0;
  304         return m->child[dev];
  305 }
  306 
  307 u_int32_t
  308 mix_getdevs(struct snd_mixer *m)
  309 {
  310         return m->devs;
  311 }
  312 
  313 u_int32_t
  314 mix_getrecdevs(struct snd_mixer *m)
  315 {
  316         return m->recdevs;
  317 }
  318 
  319 void *
  320 mix_getdevinfo(struct snd_mixer *m)
  321 {
  322         return m->devinfo;
  323 }
  324 
  325 int
  326 mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
  327 {
  328         struct snddev_info *snddev;
  329         struct snd_mixer *m;
  330         u_int16_t v;
  331         struct cdev *pdev;
  332         int i, unit, val;
  333 
  334         m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
  335         snprintf(m->name, MIXER_NAMELEN, "%s:mixer", device_get_nameunit(dev));
  336         m->lock = snd_mtxcreate(m->name, "pcm mixer");
  337         m->type = cls->name;
  338         m->devinfo = devinfo;
  339         m->busy = 0;
  340         m->dev = dev;
  341         for (i = 0; i < 32; i++) {
  342                 m->parent[i] = SOUND_MIXER_NONE;
  343                 m->child[i] = 0;
  344                 m->realdev[i] = i;
  345         }
  346 
  347         if (MIXER_INIT(m))
  348                 goto bad;
  349 
  350         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  351                 v = snd_mixerdefaults[i];
  352 
  353                 if (resource_int_value(device_get_name(dev),
  354                     device_get_unit(dev), snd_mixernames[i], &val) == 0) {
  355                         if (val >= 0 && val <= 100) {
  356                                 v = (u_int16_t) val;
  357                         }
  358                 }
  359 
  360                 mixer_set(m, i, v | (v << 8));
  361         }
  362 
  363         mixer_setrecsrc(m, SOUND_MASK_MIC);
  364 
  365         unit = device_get_unit(dev);
  366         pdev = make_dev(&mixer_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0),
  367                  UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
  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                                 printf(" parent=\"%s\"",
  387                                     snd_mixernames[m->parent[i]]);
  388                         if (m->child[i] != 0)
  389                                 printf(" child=0x%08x", m->child[i]);
  390                         printf("\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_mtxlock(m->lock);
  400         snd_mtxfree(m->lock);
  401         kobj_delete((kobj_t)m, M_MIXER);
  402         return -1;
  403 }
  404 
  405 int
  406 mixer_uninit(device_t dev)
  407 {
  408         int i;
  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         destroy_dev(pdev);
  427 
  428         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  429                 mixer_set(m, i, 0);
  430 
  431         mixer_setrecsrc(m, SOUND_MASK_MIC);
  432 
  433         MIXER_UNINIT(m);
  434 
  435         snd_mtxfree(m->lock);
  436         kobj_delete((kobj_t)m, M_MIXER);
  437 
  438         d->mixer_dev = NULL;
  439 
  440         return 0;
  441 }
  442 
  443 int
  444 mixer_reinit(device_t dev)
  445 {
  446         struct snd_mixer *m;
  447         struct cdev *pdev;
  448         int i;
  449 
  450         pdev = mixer_get_devt(dev);
  451         m = pdev->si_drv1;
  452         snd_mtxlock(m->lock);
  453 
  454         i = MIXER_REINIT(m);
  455         if (i) {
  456                 snd_mtxunlock(m->lock);
  457                 return i;
  458         }
  459 
  460         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  461                 mixer_set(m, i, m->level[i]);
  462 
  463         mixer_setrecsrc(m, m->recsrc);
  464         snd_mtxunlock(m->lock);
  465 
  466         return 0;
  467 }
  468 
  469 #ifdef SND_DYNSYSCTL
  470 static int
  471 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
  472 {
  473         char devname[32];
  474         int error, dev;
  475         struct snd_mixer *m;
  476 
  477         m = oidp->oid_arg1;
  478         snd_mtxlock(m->lock);
  479         strncpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
  480         snd_mtxunlock(m->lock);
  481         error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
  482         snd_mtxlock(m->lock);
  483         if (error == 0 && req->newptr != NULL) {
  484                 dev = mixer_lookup(devname);
  485                 if (dev == -1) {
  486                         snd_mtxunlock(m->lock);
  487                         return EINVAL;
  488                 }
  489                 else if (dev != m->hwvol_mixer) {
  490                         m->hwvol_mixer = dev;
  491                         m->hwvol_muted = 0;
  492                 }
  493         }
  494         snd_mtxunlock(m->lock);
  495         return error;
  496 }
  497 #endif
  498 
  499 int
  500 mixer_hwvol_init(device_t dev)
  501 {
  502         struct snd_mixer *m;
  503         struct cdev *pdev;
  504 
  505         pdev = mixer_get_devt(dev);
  506         m = pdev->si_drv1;
  507 
  508         m->hwvol_mixer = SOUND_MIXER_VOLUME;
  509         m->hwvol_step = 5;
  510 #ifdef SND_DYNSYSCTL
  511         SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  512             OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, "");
  513         SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  514             OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
  515             sysctl_hw_snd_hwvol_mixer, "A", "");
  516 #endif
  517         return 0;
  518 }
  519 
  520 void
  521 mixer_hwvol_mute(device_t dev)
  522 {
  523         struct snd_mixer *m;
  524         struct cdev *pdev;
  525 
  526         pdev = mixer_get_devt(dev);
  527         m = pdev->si_drv1;
  528         snd_mtxlock(m->lock);
  529         if (m->hwvol_muted) {
  530                 m->hwvol_muted = 0;
  531                 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
  532         } else {
  533                 m->hwvol_muted++;
  534                 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
  535                 mixer_set(m, m->hwvol_mixer, 0);
  536         }
  537         snd_mtxunlock(m->lock);
  538 }
  539 
  540 void
  541 mixer_hwvol_step(device_t dev, int left_step, int right_step)
  542 {
  543         struct snd_mixer *m;
  544         int level, left, right;
  545         struct cdev *pdev;
  546 
  547         pdev = mixer_get_devt(dev);
  548         m = pdev->si_drv1;
  549         snd_mtxlock(m->lock);
  550         if (m->hwvol_muted) {
  551                 m->hwvol_muted = 0;
  552                 level = m->hwvol_mute_level;
  553         } else
  554                 level = mixer_get(m, m->hwvol_mixer);
  555         if (level != -1) {
  556                 left = level & 0xff;
  557                 right = level >> 8;
  558                 left += left_step * m->hwvol_step;
  559                 if (left < 0)
  560                         left = 0;
  561                 right += right_step * m->hwvol_step;
  562                 if (right < 0)
  563                         right = 0;
  564                 mixer_set(m, m->hwvol_mixer, left | right << 8);
  565         }
  566         snd_mtxunlock(m->lock);
  567 }
  568 
  569 /* ----------------------------------------------------------------------- */
  570 
  571 static int
  572 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
  573 {
  574         struct snd_mixer *m;
  575 
  576         m = i_dev->si_drv1;
  577         snd_mtxlock(m->lock);
  578 
  579         m->busy++;
  580 
  581         snd_mtxunlock(m->lock);
  582         return 0;
  583 }
  584 
  585 static int
  586 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
  587 {
  588         struct snd_mixer *m;
  589 
  590         m = i_dev->si_drv1;
  591         snd_mtxlock(m->lock);
  592 
  593         if (!m->busy) {
  594                 snd_mtxunlock(m->lock);
  595                 return EBADF;
  596         }
  597         m->busy--;
  598 
  599         snd_mtxunlock(m->lock);
  600         return 0;
  601 }
  602 
  603 int
  604 mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  605 {
  606         struct snd_mixer *m;
  607         int ret, *arg_i = (int *)arg;
  608         int v = -1, j = cmd & 0xff;
  609 
  610         m = i_dev->si_drv1;
  611 
  612         if (m == NULL)
  613                 return EBADF;
  614 
  615         snd_mtxlock(m->lock);
  616         if (mode != -1 && !m->busy) {
  617                 snd_mtxunlock(m->lock);
  618                 return EBADF;
  619         }
  620 
  621         if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
  622                 if (j == SOUND_MIXER_RECSRC)
  623                         ret = mixer_setrecsrc(m, *arg_i);
  624                 else
  625                         ret = mixer_set(m, j, *arg_i);
  626                 snd_mtxunlock(m->lock);
  627                 return (ret == 0)? 0 : ENXIO;
  628         }
  629 
  630         if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) {
  631                 switch (j) {
  632                 case SOUND_MIXER_DEVMASK:
  633                 case SOUND_MIXER_CAPS:
  634                 case SOUND_MIXER_STEREODEVS:
  635                         v = mix_getdevs(m);
  636                         break;
  637 
  638                 case SOUND_MIXER_RECMASK:
  639                         v = mix_getrecdevs(m);
  640                         break;
  641 
  642                 case SOUND_MIXER_RECSRC:
  643                         v = mixer_getrecsrc(m);
  644                         break;
  645 
  646                 default:
  647                         v = mixer_get(m, j);
  648                 }
  649                 *arg_i = v;
  650                 snd_mtxunlock(m->lock);
  651                 return (v != -1)? 0 : ENXIO;
  652         }
  653         snd_mtxunlock(m->lock);
  654         return ENXIO;
  655 }
  656 
  657 #ifdef USING_DEVFS
  658 static void
  659 mixer_clone(void *arg, struct ucred *cred, char *name, int namelen,
  660     struct cdev **dev)
  661 {
  662         struct snddev_info *sd;
  663 
  664         if (*dev != NULL)
  665                 return;
  666         if (strcmp(name, "mixer") == 0) {
  667                 sd = devclass_get_softc(pcm_devclass, snd_unit);
  668                 if (sd != NULL && sd->mixer_dev != NULL) {
  669                         *dev = sd->mixer_dev;
  670                         dev_ref(*dev);
  671                 }
  672         }
  673 }
  674 
  675 static void
  676 mixer_sysinit(void *p)
  677 {
  678         mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
  679 }
  680 
  681 static void
  682 mixer_sysuninit(void *p)
  683 {
  684         if (mixer_ehtag != NULL)
  685                 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
  686 }
  687 
  688 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
  689 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
  690 #endif
  691 
  692 

Cache object: 0fb14767b8d50ae71f154a48a32e038a


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