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 <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 
   29 #include "mixer_if.h"
   30 
   31 SND_DECLARE_FILE("$FreeBSD: releng/5.1/sys/dev/sound/pcm/mixer.c 111815 2003-03-03 12:15:54Z phk $");
   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         snd_mtxlock(m->lock);
  323 
  324         m->hwvol_mixer = SOUND_MIXER_VOLUME;
  325         m->hwvol_step = 5;
  326 #ifdef SND_DYNSYSCTL
  327         SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  328             OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, "");
  329         SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  330             OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
  331             sysctl_hw_snd_hwvol_mixer, "A", "");
  332 #endif
  333         snd_mtxunlock(m->lock);
  334         return 0;
  335 }
  336 
  337 void
  338 mixer_hwvol_mute(device_t dev)
  339 {
  340         struct snd_mixer *m;
  341         dev_t pdev;
  342 
  343         pdev = mixer_get_devt(dev);
  344         m = pdev->si_drv1;
  345         snd_mtxlock(m->lock);
  346         if (m->hwvol_muted) {
  347                 m->hwvol_muted = 0;
  348                 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
  349         } else {
  350                 m->hwvol_muted++;
  351                 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
  352                 mixer_set(m, m->hwvol_mixer, 0);
  353         }
  354         snd_mtxunlock(m->lock);
  355 }
  356 
  357 void
  358 mixer_hwvol_step(device_t dev, int left_step, int right_step)
  359 {
  360         struct snd_mixer *m;
  361         int level, left, right;
  362         dev_t pdev;
  363 
  364         pdev = mixer_get_devt(dev);
  365         m = pdev->si_drv1;
  366         snd_mtxlock(m->lock);
  367         if (m->hwvol_muted) {
  368                 m->hwvol_muted = 0;
  369                 level = m->hwvol_mute_level;
  370         } else
  371                 level = mixer_get(m, m->hwvol_mixer);
  372         if (level != -1) {
  373                 left = level & 0xff;
  374                 right = level >> 8;
  375                 left += left_step * m->hwvol_step;
  376                 if (left < 0)
  377                         left = 0;
  378                 right += right_step * m->hwvol_step;
  379                 if (right < 0)
  380                         right = 0;
  381                 mixer_set(m, m->hwvol_mixer, left | right << 8);
  382         }
  383         snd_mtxunlock(m->lock);
  384 }
  385 
  386 /* ----------------------------------------------------------------------- */
  387 
  388 static int
  389 mixer_open(dev_t i_dev, int flags, int mode, struct thread *td)
  390 {
  391         struct snd_mixer *m;
  392         intrmask_t s;
  393 
  394         m = i_dev->si_drv1;
  395         s = spltty();
  396         snd_mtxlock(m->lock);
  397 
  398         m->busy++;
  399 
  400         snd_mtxunlock(m->lock);
  401         splx(s);
  402         return 0;
  403 }
  404 
  405 static int
  406 mixer_close(dev_t i_dev, int flags, int mode, struct thread *td)
  407 {
  408         struct snd_mixer *m;
  409         intrmask_t s;
  410 
  411         m = i_dev->si_drv1;
  412         s = spltty();
  413         snd_mtxlock(m->lock);
  414 
  415         if (!m->busy) {
  416                 snd_mtxunlock(m->lock);
  417                 splx(s);
  418                 return EBADF;
  419         }
  420         m->busy--;
  421 
  422         snd_mtxunlock(m->lock);
  423         splx(s);
  424         return 0;
  425 }
  426 
  427 int
  428 mixer_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  429 {
  430         struct snd_mixer *m;
  431         intrmask_t s;
  432         int ret, *arg_i = (int *)arg;
  433         int v = -1, j = cmd & 0xff;
  434 
  435         m = i_dev->si_drv1;
  436         if (!m->busy)
  437                 return EBADF;
  438 
  439         s = spltty();
  440         snd_mtxlock(m->lock);
  441         if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
  442                 if (j == SOUND_MIXER_RECSRC)
  443                         ret = mixer_setrecsrc(m, *arg_i);
  444                 else
  445                         ret = mixer_set(m, j, *arg_i);
  446                 snd_mtxunlock(m->lock);
  447                 splx(s);
  448                 return (ret == 0)? 0 : ENXIO;
  449         }
  450 
  451         if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) {
  452                 switch (j) {
  453                 case SOUND_MIXER_DEVMASK:
  454                 case SOUND_MIXER_CAPS:
  455                 case SOUND_MIXER_STEREODEVS:
  456                         v = mix_getdevs(m);
  457                         break;
  458 
  459                 case SOUND_MIXER_RECMASK:
  460                         v = mix_getrecdevs(m);
  461                         break;
  462 
  463                 case SOUND_MIXER_RECSRC:
  464                         v = mixer_getrecsrc(m);
  465                         break;
  466 
  467                 default:
  468                         v = mixer_get(m, j);
  469                 }
  470                 *arg_i = v;
  471                 snd_mtxunlock(m->lock);
  472                 return (v != -1)? 0 : ENXIO;
  473         }
  474         snd_mtxunlock(m->lock);
  475         splx(s);
  476         return ENXIO;
  477 }
  478 
  479 #ifdef USING_DEVFS
  480 static void
  481 mixer_clone(void *arg, char *name, int namelen, dev_t *dev)
  482 {
  483         dev_t pdev;
  484 
  485         if (*dev != NODEV)
  486                 return;
  487         if (strcmp(name, "mixer") == 0) {
  488                 pdev = makedev(SND_CDEV_MAJOR, PCMMKMINOR(snd_unit, SND_DEV_CTL, 0));
  489                 if (pdev->si_flags & SI_NAMED)
  490                         *dev = pdev;
  491         }
  492 }
  493 
  494 static void
  495 mixer_sysinit(void *p)
  496 {
  497         mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
  498 }
  499 
  500 static void
  501 mixer_sysuninit(void *p)
  502 {
  503         if (mixer_ehtag != NULL)
  504                 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
  505 }
  506 
  507 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
  508 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
  509 #endif
  510 
  511 

Cache object: 71a854faace819a17993bd05902604b5


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