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 
   27 #include <dev/sound/pcm/sound.h>
   28 
   29 #include "mixer_if.h"
   30 
   31 SND_DECLARE_FILE("$FreeBSD: releng/5.4/sys/dev/sound/pcm/mixer.c 141016 2005-01-30 01:00:13Z imp $");
   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_version =    D_VERSION,
   77         .d_flags =      D_NEEDGIANT,
   78         .d_open =       mixer_open,
   79         .d_close =      mixer_close,
   80         .d_ioctl =      mixer_ioctl,
   81         .d_name =       "mixer",
   82         .d_maj =        SND_CDEV_MAJOR,
   83 };
   84 
   85 #ifdef USING_DEVFS
   86 static eventhandler_tag mixer_ehtag;
   87 #endif
   88 
   89 static struct cdev *
   90 mixer_get_devt(device_t dev)
   91 {
   92         struct snddev_info *snddev;
   93 
   94         snddev = device_get_softc(dev);
   95 
   96         return snddev->mixer_dev;
   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 snddev_info *snddev;
  191         struct snd_mixer *m;
  192         u_int16_t v;
  193         struct cdev *pdev;
  194         int i, unit, val;
  195 
  196         m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
  197         snprintf(m->name, MIXER_NAMELEN, "%s:mixer", device_get_nameunit(dev));
  198         m->lock = snd_mtxcreate(m->name, "pcm mixer");
  199         m->type = cls->name;
  200         m->devinfo = devinfo;
  201         m->busy = 0;
  202 
  203         if (MIXER_INIT(m))
  204                 goto bad;
  205 
  206         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  207                 v = snd_mixerdefaults[i];
  208 
  209                 if (resource_int_value(device_get_name(dev),
  210                     device_get_unit(dev), snd_mixernames[i], &val) == 0) {
  211                         if (val >= 0 && val <= 100) {
  212                                 v = (u_int16_t) val;
  213                         }
  214                 }
  215 
  216                 mixer_set(m, i, v | (v << 8));
  217         }
  218 
  219         mixer_setrecsrc(m, SOUND_MASK_MIC);
  220 
  221         unit = device_get_unit(dev);
  222         pdev = make_dev(&mixer_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0),
  223                  UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
  224         pdev->si_drv1 = m;
  225         snddev = device_get_softc(dev);
  226         snddev->mixer_dev = pdev;
  227 
  228         return 0;
  229 
  230 bad:
  231         snd_mtxlock(m->lock);
  232         snd_mtxfree(m->lock);
  233         kobj_delete((kobj_t)m, M_MIXER);
  234         return -1;
  235 }
  236 
  237 int
  238 mixer_uninit(device_t dev)
  239 {
  240         int i;
  241         struct snd_mixer *m;
  242         struct cdev *pdev;
  243 
  244         pdev = mixer_get_devt(dev);
  245         m = pdev->si_drv1;
  246         snd_mtxlock(m->lock);
  247 
  248         if (m->busy) {
  249                 snd_mtxunlock(m->lock);
  250                 return EBUSY;
  251         }
  252 
  253         pdev->si_drv1 = NULL;
  254         destroy_dev(pdev);
  255 
  256         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  257                 mixer_set(m, i, 0);
  258 
  259         mixer_setrecsrc(m, SOUND_MASK_MIC);
  260 
  261         MIXER_UNINIT(m);
  262 
  263         snd_mtxfree(m->lock);
  264         kobj_delete((kobj_t)m, M_MIXER);
  265 
  266         return 0;
  267 }
  268 
  269 int
  270 mixer_reinit(device_t dev)
  271 {
  272         struct snd_mixer *m;
  273         struct cdev *pdev;
  274         int i;
  275 
  276         pdev = mixer_get_devt(dev);
  277         m = pdev->si_drv1;
  278         snd_mtxlock(m->lock);
  279 
  280         i = MIXER_REINIT(m);
  281         if (i) {
  282                 snd_mtxunlock(m->lock);
  283                 return i;
  284         }
  285 
  286         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  287                 mixer_set(m, i, m->level[i]);
  288 
  289         mixer_setrecsrc(m, m->recsrc);
  290         snd_mtxunlock(m->lock);
  291 
  292         return 0;
  293 }
  294 
  295 #ifdef SND_DYNSYSCTL
  296 static int
  297 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
  298 {
  299         char devname[32];
  300         int error, dev;
  301         struct snd_mixer *m;
  302 
  303         m = oidp->oid_arg1;
  304         snd_mtxlock(m->lock);
  305         strncpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
  306         snd_mtxunlock(m->lock);
  307         error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
  308         snd_mtxlock(m->lock);
  309         if (error == 0 && req->newptr != NULL) {
  310                 dev = mixer_lookup(devname);
  311                 if (dev == -1) {
  312                         snd_mtxunlock(m->lock);
  313                         return EINVAL;
  314                 }
  315                 else if (dev != m->hwvol_mixer) {
  316                         m->hwvol_mixer = dev;
  317                         m->hwvol_muted = 0;
  318                 }
  319         }
  320         snd_mtxunlock(m->lock);
  321         return error;
  322 }
  323 #endif
  324 
  325 int
  326 mixer_hwvol_init(device_t dev)
  327 {
  328         struct snd_mixer *m;
  329         struct cdev *pdev;
  330 
  331         pdev = mixer_get_devt(dev);
  332         m = pdev->si_drv1;
  333 
  334         m->hwvol_mixer = SOUND_MIXER_VOLUME;
  335         m->hwvol_step = 5;
  336 #ifdef SND_DYNSYSCTL
  337         SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  338             OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, "");
  339         SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  340             OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
  341             sysctl_hw_snd_hwvol_mixer, "A", "");
  342 #endif
  343         return 0;
  344 }
  345 
  346 void
  347 mixer_hwvol_mute(device_t dev)
  348 {
  349         struct snd_mixer *m;
  350         struct cdev *pdev;
  351 
  352         pdev = mixer_get_devt(dev);
  353         m = pdev->si_drv1;
  354         snd_mtxlock(m->lock);
  355         if (m->hwvol_muted) {
  356                 m->hwvol_muted = 0;
  357                 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
  358         } else {
  359                 m->hwvol_muted++;
  360                 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
  361                 mixer_set(m, m->hwvol_mixer, 0);
  362         }
  363         snd_mtxunlock(m->lock);
  364 }
  365 
  366 void
  367 mixer_hwvol_step(device_t dev, int left_step, int right_step)
  368 {
  369         struct snd_mixer *m;
  370         int level, left, right;
  371         struct cdev *pdev;
  372 
  373         pdev = mixer_get_devt(dev);
  374         m = pdev->si_drv1;
  375         snd_mtxlock(m->lock);
  376         if (m->hwvol_muted) {
  377                 m->hwvol_muted = 0;
  378                 level = m->hwvol_mute_level;
  379         } else
  380                 level = mixer_get(m, m->hwvol_mixer);
  381         if (level != -1) {
  382                 left = level & 0xff;
  383                 right = level >> 8;
  384                 left += left_step * m->hwvol_step;
  385                 if (left < 0)
  386                         left = 0;
  387                 right += right_step * m->hwvol_step;
  388                 if (right < 0)
  389                         right = 0;
  390                 mixer_set(m, m->hwvol_mixer, left | right << 8);
  391         }
  392         snd_mtxunlock(m->lock);
  393 }
  394 
  395 /* ----------------------------------------------------------------------- */
  396 
  397 static int
  398 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
  399 {
  400         struct snd_mixer *m;
  401         intrmask_t s;
  402 
  403         m = i_dev->si_drv1;
  404         s = spltty();
  405         snd_mtxlock(m->lock);
  406 
  407         m->busy++;
  408 
  409         snd_mtxunlock(m->lock);
  410         splx(s);
  411         return 0;
  412 }
  413 
  414 static int
  415 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
  416 {
  417         struct snd_mixer *m;
  418         intrmask_t s;
  419 
  420         m = i_dev->si_drv1;
  421         s = spltty();
  422         snd_mtxlock(m->lock);
  423 
  424         if (!m->busy) {
  425                 snd_mtxunlock(m->lock);
  426                 splx(s);
  427                 return EBADF;
  428         }
  429         m->busy--;
  430 
  431         snd_mtxunlock(m->lock);
  432         splx(s);
  433         return 0;
  434 }
  435 
  436 int
  437 mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  438 {
  439         struct snd_mixer *m;
  440         intrmask_t s;
  441         int ret, *arg_i = (int *)arg;
  442         int v = -1, j = cmd & 0xff;
  443 
  444         m = i_dev->si_drv1;
  445         if (!m->busy)
  446                 return EBADF;
  447 
  448         s = spltty();
  449         snd_mtxlock(m->lock);
  450         if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
  451                 if (j == SOUND_MIXER_RECSRC)
  452                         ret = mixer_setrecsrc(m, *arg_i);
  453                 else
  454                         ret = mixer_set(m, j, *arg_i);
  455                 snd_mtxunlock(m->lock);
  456                 splx(s);
  457                 return (ret == 0)? 0 : ENXIO;
  458         }
  459 
  460         if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) {
  461                 switch (j) {
  462                 case SOUND_MIXER_DEVMASK:
  463                 case SOUND_MIXER_CAPS:
  464                 case SOUND_MIXER_STEREODEVS:
  465                         v = mix_getdevs(m);
  466                         break;
  467 
  468                 case SOUND_MIXER_RECMASK:
  469                         v = mix_getrecdevs(m);
  470                         break;
  471 
  472                 case SOUND_MIXER_RECSRC:
  473                         v = mixer_getrecsrc(m);
  474                         break;
  475 
  476                 default:
  477                         v = mixer_get(m, j);
  478                 }
  479                 *arg_i = v;
  480                 snd_mtxunlock(m->lock);
  481                 return (v != -1)? 0 : ENXIO;
  482         }
  483         snd_mtxunlock(m->lock);
  484         splx(s);
  485         return ENXIO;
  486 }
  487 
  488 #ifdef USING_DEVFS
  489 static void
  490 mixer_clone(void *arg, char *name, int namelen, struct cdev **dev)
  491 {
  492         struct snddev_info *sd;
  493 
  494         if (*dev != NULL)
  495                 return;
  496         if (strcmp(name, "mixer") == 0) {
  497                 sd = devclass_get_softc(pcm_devclass, snd_unit);
  498                 if (sd != NULL)
  499                         *dev = sd->mixer_dev;
  500         }
  501 }
  502 
  503 static void
  504 mixer_sysinit(void *p)
  505 {
  506         mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
  507 }
  508 
  509 static void
  510 mixer_sysuninit(void *p)
  511 {
  512         if (mixer_ehtag != NULL)
  513                 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
  514 }
  515 
  516 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
  517 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
  518 #endif
  519 
  520 

Cache object: 822455af7cdbee1dcfe7c8a409f71f17


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