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/5.2/sys/dev/sound/pcm/mixer.c 122461 2003-11-11 05:38:28Z scottl $");
   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         u_int32_t hwvol_mute_level;
   45         u_int32_t devs;
   46         u_int32_t recdevs;
   47         u_int32_t recsrc;
   48         u_int16_t level[32];
   49         char name[MIXER_NAMELEN];
   50         struct mtx *lock;
   51 };
   52 
   53 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
   54         [SOUND_MIXER_VOLUME]    = 75,
   55         [SOUND_MIXER_BASS]      = 50,
   56         [SOUND_MIXER_TREBLE]    = 50,
   57         [SOUND_MIXER_SYNTH]     = 75,
   58         [SOUND_MIXER_PCM]       = 75,
   59         [SOUND_MIXER_SPEAKER]   = 75,
   60         [SOUND_MIXER_LINE]      = 75,
   61         [SOUND_MIXER_MIC]       = 0,
   62         [SOUND_MIXER_CD]        = 75,
   63         [SOUND_MIXER_LINE1]     = 75,
   64         [SOUND_MIXER_VIDEO]     = 75,
   65         [SOUND_MIXER_RECLEV]    = 0,
   66         [SOUND_MIXER_OGAIN]     = 50,
   67         [SOUND_MIXER_MONITOR]   = 75,
   68 };
   69 
   70 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
   71 
   72 static d_open_t mixer_open;
   73 static d_close_t mixer_close;
   74 
   75 static struct cdevsw mixer_cdevsw = {
   76         .d_open =       mixer_open,
   77         .d_close =      mixer_close,
   78         .d_ioctl =      mixer_ioctl,
   79         .d_name =       "mixer",
   80         .d_maj =        SND_CDEV_MAJOR,
   81 };
   82 
   83 #ifdef USING_DEVFS
   84 static eventhandler_tag mixer_ehtag;
   85 #endif
   86 
   87 static dev_t
   88 mixer_get_devt(device_t dev)
   89 {
   90         dev_t pdev;
   91         int unit;
   92 
   93         unit = device_get_unit(dev);
   94         pdev = makedev(SND_CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_CTL, 0));
   95 
   96         return pdev;
   97 }
   98 
   99 #ifdef SND_DYNSYSCTL
  100 static int
  101 mixer_lookup(char *devname)
  102 {
  103         int i;
  104 
  105         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  106                 if (strncmp(devname, snd_mixernames[i],
  107                     strlen(snd_mixernames[i])) == 0)
  108                         return i;
  109         return -1;
  110 }
  111 #endif
  112 
  113 static int
  114 mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev)
  115 {
  116         unsigned l, r;
  117         int v;
  118 
  119         if ((dev >= SOUND_MIXER_NRDEVICES) || (0 == (mixer->devs & (1 << dev))))
  120                 return -1;
  121 
  122         l = min((lev & 0x00ff), 100);
  123         r = min(((lev & 0xff00) >> 8), 100);
  124 
  125         v = MIXER_SET(mixer, dev, l, r);
  126         if (v < 0)
  127                 return -1;
  128 
  129         mixer->level[dev] = l | (r << 8);
  130         return 0;
  131 }
  132 
  133 static int
  134 mixer_get(struct snd_mixer *mixer, int dev)
  135 {
  136         if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev)))
  137                 return mixer->level[dev];
  138         else return -1;
  139 }
  140 
  141 static int
  142 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
  143 {
  144         src &= mixer->recdevs;
  145         if (src == 0)
  146                 src = SOUND_MASK_MIC;
  147         mixer->recsrc = MIXER_SETRECSRC(mixer, src);
  148         return 0;
  149 }
  150 
  151 static int
  152 mixer_getrecsrc(struct snd_mixer *mixer)
  153 {
  154         return mixer->recsrc;
  155 }
  156 
  157 void
  158 mix_setdevs(struct snd_mixer *m, u_int32_t v)
  159 {
  160         m->devs = v;
  161 }
  162 
  163 void
  164 mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
  165 {
  166         m->recdevs = v;
  167 }
  168 
  169 u_int32_t
  170 mix_getdevs(struct snd_mixer *m)
  171 {
  172         return m->devs;
  173 }
  174 
  175 u_int32_t
  176 mix_getrecdevs(struct snd_mixer *m)
  177 {
  178         return m->recdevs;
  179 }
  180 
  181 void *
  182 mix_getdevinfo(struct snd_mixer *m)
  183 {
  184         return m->devinfo;
  185 }
  186 
  187 int
  188 mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
  189 {
  190         struct snd_mixer *m;
  191         u_int16_t v;
  192         dev_t pdev;
  193         int i, unit;
  194 
  195         m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
  196         snprintf(m->name, MIXER_NAMELEN, "%s:mixer", device_get_nameunit(dev));
  197         m->lock = snd_mtxcreate(m->name, "pcm mixer");
  198         m->type = cls->name;
  199         m->devinfo = devinfo;
  200         m->busy = 0;
  201 
  202         if (MIXER_INIT(m))
  203                 goto bad;
  204 
  205         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  206                 v = snd_mixerdefaults[i];
  207                 mixer_set(m, i, v | (v << 8));
  208         }
  209 
  210         mixer_setrecsrc(m, SOUND_MASK_MIC);
  211 
  212         unit = device_get_unit(dev);
  213         pdev = make_dev(&mixer_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0),
  214                  UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
  215         pdev->si_drv1 = m;
  216 
  217         return 0;
  218 
  219 bad:
  220         snd_mtxlock(m->lock);
  221         snd_mtxfree(m->lock);
  222         kobj_delete((kobj_t)m, M_MIXER);
  223         return -1;
  224 }
  225 
  226 int
  227 mixer_uninit(device_t dev)
  228 {
  229         int i;
  230         struct snd_mixer *m;
  231         dev_t pdev;
  232 
  233         pdev = mixer_get_devt(dev);
  234         m = pdev->si_drv1;
  235         snd_mtxlock(m->lock);
  236 
  237         if (m->busy) {
  238                 snd_mtxunlock(m->lock);
  239                 return EBUSY;
  240         }
  241 
  242         pdev->si_drv1 = NULL;
  243         destroy_dev(pdev);
  244 
  245         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  246                 mixer_set(m, i, 0);
  247 
  248         mixer_setrecsrc(m, SOUND_MASK_MIC);
  249 
  250         MIXER_UNINIT(m);
  251 
  252         snd_mtxfree(m->lock);
  253         kobj_delete((kobj_t)m, M_MIXER);
  254 
  255         return 0;
  256 }
  257 
  258 int
  259 mixer_reinit(device_t dev)
  260 {
  261         struct snd_mixer *m;
  262         dev_t pdev;
  263         int i;
  264 
  265         pdev = mixer_get_devt(dev);
  266         m = pdev->si_drv1;
  267         snd_mtxlock(m->lock);
  268 
  269         i = MIXER_REINIT(m);
  270         if (i) {
  271                 snd_mtxunlock(m->lock);
  272                 return i;
  273         }
  274 
  275         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  276                 mixer_set(m, i, m->level[i]);
  277 
  278         mixer_setrecsrc(m, m->recsrc);
  279         snd_mtxunlock(m->lock);
  280 
  281         return 0;
  282 }
  283 
  284 #ifdef SND_DYNSYSCTL
  285 static int
  286 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
  287 {
  288         char devname[32];
  289         int error, dev;
  290         struct snd_mixer *m;
  291 
  292         m = oidp->oid_arg1;
  293         snd_mtxlock(m->lock);
  294         strncpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
  295         snd_mtxunlock(m->lock);
  296         error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
  297         snd_mtxlock(m->lock);
  298         if (error == 0 && req->newptr != NULL) {
  299                 dev = mixer_lookup(devname);
  300                 if (dev == -1) {
  301                         snd_mtxunlock(m->lock);
  302                         return EINVAL;
  303                 }
  304                 else if (dev != m->hwvol_mixer) {
  305                         m->hwvol_mixer = dev;
  306                         m->hwvol_muted = 0;
  307                 }
  308         }
  309         snd_mtxunlock(m->lock);
  310         return error;
  311 }
  312 #endif
  313 
  314 int
  315 mixer_hwvol_init(device_t dev)
  316 {
  317         struct snd_mixer *m;
  318         dev_t pdev;
  319 
  320         pdev = mixer_get_devt(dev);
  321         m = pdev->si_drv1;
  322 
  323         m->hwvol_mixer = SOUND_MIXER_VOLUME;
  324         m->hwvol_step = 5;
  325 #ifdef SND_DYNSYSCTL
  326         SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  327             OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, "");
  328         SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  329             OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
  330             sysctl_hw_snd_hwvol_mixer, "A", "");
  331 #endif
  332         return 0;
  333 }
  334 
  335 void
  336 mixer_hwvol_mute(device_t dev)
  337 {
  338         struct snd_mixer *m;
  339         dev_t pdev;
  340 
  341         pdev = mixer_get_devt(dev);
  342         m = pdev->si_drv1;
  343         snd_mtxlock(m->lock);
  344         if (m->hwvol_muted) {
  345                 m->hwvol_muted = 0;
  346                 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
  347         } else {
  348                 m->hwvol_muted++;
  349                 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
  350                 mixer_set(m, m->hwvol_mixer, 0);
  351         }
  352         snd_mtxunlock(m->lock);
  353 }
  354 
  355 void
  356 mixer_hwvol_step(device_t dev, int left_step, int right_step)
  357 {
  358         struct snd_mixer *m;
  359         int level, left, right;
  360         dev_t pdev;
  361 
  362         pdev = mixer_get_devt(dev);
  363         m = pdev->si_drv1;
  364         snd_mtxlock(m->lock);
  365         if (m->hwvol_muted) {
  366                 m->hwvol_muted = 0;
  367                 level = m->hwvol_mute_level;
  368         } else
  369                 level = mixer_get(m, m->hwvol_mixer);
  370         if (level != -1) {
  371                 left = level & 0xff;
  372                 right = level >> 8;
  373                 left += left_step * m->hwvol_step;
  374                 if (left < 0)
  375                         left = 0;
  376                 right += right_step * m->hwvol_step;
  377                 if (right < 0)
  378                         right = 0;
  379                 mixer_set(m, m->hwvol_mixer, left | right << 8);
  380         }
  381         snd_mtxunlock(m->lock);
  382 }
  383 
  384 /* ----------------------------------------------------------------------- */
  385 
  386 static int
  387 mixer_open(dev_t i_dev, int flags, int mode, struct thread *td)
  388 {
  389         struct snd_mixer *m;
  390         intrmask_t s;
  391 
  392         m = i_dev->si_drv1;
  393         s = spltty();
  394         snd_mtxlock(m->lock);
  395 
  396         m->busy++;
  397 
  398         snd_mtxunlock(m->lock);
  399         splx(s);
  400         return 0;
  401 }
  402 
  403 static int
  404 mixer_close(dev_t i_dev, int flags, int mode, struct thread *td)
  405 {
  406         struct snd_mixer *m;
  407         intrmask_t s;
  408 
  409         m = i_dev->si_drv1;
  410         s = spltty();
  411         snd_mtxlock(m->lock);
  412 
  413         if (!m->busy) {
  414                 snd_mtxunlock(m->lock);
  415                 splx(s);
  416                 return EBADF;
  417         }
  418         m->busy--;
  419 
  420         snd_mtxunlock(m->lock);
  421         splx(s);
  422         return 0;
  423 }
  424 
  425 int
  426 mixer_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  427 {
  428         struct snd_mixer *m;
  429         intrmask_t s;
  430         int ret, *arg_i = (int *)arg;
  431         int v = -1, j = cmd & 0xff;
  432 
  433         m = i_dev->si_drv1;
  434         if (!m->busy)
  435                 return EBADF;
  436 
  437         s = spltty();
  438         snd_mtxlock(m->lock);
  439         if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
  440                 if (j == SOUND_MIXER_RECSRC)
  441                         ret = mixer_setrecsrc(m, *arg_i);
  442                 else
  443                         ret = mixer_set(m, j, *arg_i);
  444                 snd_mtxunlock(m->lock);
  445                 splx(s);
  446                 return (ret == 0)? 0 : ENXIO;
  447         }
  448 
  449         if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) {
  450                 switch (j) {
  451                 case SOUND_MIXER_DEVMASK:
  452                 case SOUND_MIXER_CAPS:
  453                 case SOUND_MIXER_STEREODEVS:
  454                         v = mix_getdevs(m);
  455                         break;
  456 
  457                 case SOUND_MIXER_RECMASK:
  458                         v = mix_getrecdevs(m);
  459                         break;
  460 
  461                 case SOUND_MIXER_RECSRC:
  462                         v = mixer_getrecsrc(m);
  463                         break;
  464 
  465                 default:
  466                         v = mixer_get(m, j);
  467                 }
  468                 *arg_i = v;
  469                 snd_mtxunlock(m->lock);
  470                 return (v != -1)? 0 : ENXIO;
  471         }
  472         snd_mtxunlock(m->lock);
  473         splx(s);
  474         return ENXIO;
  475 }
  476 
  477 #ifdef USING_DEVFS
  478 static void
  479 mixer_clone(void *arg, char *name, int namelen, dev_t *dev)
  480 {
  481         dev_t pdev;
  482 
  483         if (*dev != NODEV)
  484                 return;
  485         if (strcmp(name, "mixer") == 0) {
  486                 pdev = makedev(SND_CDEV_MAJOR, PCMMKMINOR(snd_unit, SND_DEV_CTL, 0));
  487                 if (pdev->si_flags & SI_NAMED)
  488                         *dev = pdev;
  489         }
  490 }
  491 
  492 static void
  493 mixer_sysinit(void *p)
  494 {
  495         mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
  496 }
  497 
  498 static void
  499 mixer_sysuninit(void *p)
  500 {
  501         if (mixer_ehtag != NULL)
  502                 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
  503 }
  504 
  505 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
  506 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
  507 #endif
  508 
  509 

Cache object: 8f44ffb5ffdf63fef408b36500891c85


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