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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
    5  * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
    6  * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #ifdef HAVE_KERNEL_OPTION_HEADERS
   32 #include "opt_snd.h"
   33 #endif
   34 
   35 #include <dev/sound/pcm/sound.h>
   36 
   37 #include "feeder_if.h"
   38 #include "mixer_if.h"
   39 
   40 SND_DECLARE_FILE("$FreeBSD$");
   41 
   42 static MALLOC_DEFINE(M_MIXER, "mixer", "mixer");
   43 
   44 static int mixer_bypass = 1;
   45 SYSCTL_INT(_hw_snd, OID_AUTO, vpc_mixer_bypass, CTLFLAG_RWTUN,
   46     &mixer_bypass, 0,
   47     "control channel pcm/rec volume, bypassing real mixer device");
   48 
   49 #define MIXER_NAMELEN   16
   50 struct snd_mixer {
   51         KOBJ_FIELDS;
   52         void *devinfo;
   53         int busy;
   54         int hwvol_mixer;
   55         int hwvol_step;
   56         int type;
   57         device_t dev;
   58         u_int32_t devs;
   59         u_int32_t mutedevs;
   60         u_int32_t recdevs;
   61         u_int32_t recsrc;
   62         u_int16_t level[32];
   63         u_int16_t level_muted[32];
   64         u_int8_t parent[32];
   65         u_int32_t child[32];
   66         u_int8_t realdev[32];
   67         char name[MIXER_NAMELEN];
   68         struct mtx *lock;
   69         oss_mixer_enuminfo enuminfo;
   70         /** 
   71          * Counter is incremented when applications change any of this
   72          * mixer's controls.  A change in value indicates that persistent
   73          * mixer applications should update their displays.
   74          */
   75         int modify_counter;
   76 };
   77 
   78 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
   79         [SOUND_MIXER_VOLUME]    = 75,
   80         [SOUND_MIXER_BASS]      = 50,
   81         [SOUND_MIXER_TREBLE]    = 50,
   82         [SOUND_MIXER_SYNTH]     = 75,
   83         [SOUND_MIXER_PCM]       = 75,
   84         [SOUND_MIXER_SPEAKER]   = 75,
   85         [SOUND_MIXER_LINE]      = 75,
   86         [SOUND_MIXER_MIC]       = 25,
   87         [SOUND_MIXER_CD]        = 75,
   88         [SOUND_MIXER_IGAIN]     = 0,
   89         [SOUND_MIXER_LINE1]     = 75,
   90         [SOUND_MIXER_VIDEO]     = 75,
   91         [SOUND_MIXER_RECLEV]    = 75,
   92         [SOUND_MIXER_OGAIN]     = 50,
   93         [SOUND_MIXER_MONITOR]   = 75,
   94 };
   95 
   96 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
   97 
   98 static d_open_t mixer_open;
   99 static d_close_t mixer_close;
  100 static d_ioctl_t mixer_ioctl;
  101 
  102 static struct cdevsw mixer_cdevsw = {
  103         .d_version =    D_VERSION,
  104         .d_open =       mixer_open,
  105         .d_close =      mixer_close,
  106         .d_ioctl =      mixer_ioctl,
  107         .d_name =       "mixer",
  108 };
  109 
  110 /**
  111  * Keeps a count of mixer devices; used only by OSSv4 SNDCTL_SYSINFO ioctl.
  112  */
  113 int mixer_count = 0;
  114 
  115 static eventhandler_tag mixer_ehtag = NULL;
  116 
  117 static struct cdev *
  118 mixer_get_devt(device_t dev)
  119 {
  120         struct snddev_info *snddev;
  121 
  122         snddev = device_get_softc(dev);
  123 
  124         return snddev->mixer_dev;
  125 }
  126 
  127 static int
  128 mixer_lookup(char *devname)
  129 {
  130         int i;
  131 
  132         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  133                 if (strncmp(devname, snd_mixernames[i],
  134                     strlen(snd_mixernames[i])) == 0)
  135                         return i;
  136         return -1;
  137 }
  138 
  139 #define MIXER_SET_UNLOCK(x, y)          do {                            \
  140         if ((y) != 0)                                                   \
  141                 snd_mtxunlock((x)->lock);                               \
  142 } while (0)
  143 
  144 #define MIXER_SET_LOCK(x, y)            do {                            \
  145         if ((y) != 0)                                                   \
  146                 snd_mtxlock((x)->lock);                                 \
  147 } while (0)
  148 
  149 static int
  150 mixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d,
  151     u_int left, u_int right)
  152 {
  153         struct pcm_channel *c;
  154         int dropmtx, acquiremtx;
  155 
  156         if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
  157                 return (EINVAL);
  158 
  159         if (mtx_owned(m->lock))
  160                 dropmtx = 1;
  161         else
  162                 dropmtx = 0;
  163 
  164         if (!(d->flags & SD_F_MPSAFE) || mtx_owned(d->lock) != 0)
  165                 acquiremtx = 0;
  166         else
  167                 acquiremtx = 1;
  168 
  169         /*
  170          * Be careful here. If we're coming from cdev ioctl, it is OK to
  171          * not doing locking AT ALL (except on individual channel) since
  172          * we've been heavily guarded by pcm cv, or if we're still
  173          * under Giant influence. Since we also have mix_* calls, we cannot
  174          * assume such protection and just do the lock as usuall.
  175          */
  176         MIXER_SET_UNLOCK(m, dropmtx);
  177         MIXER_SET_LOCK(d, acquiremtx);
  178 
  179         CHN_FOREACH(c, d, channels.pcm.busy) {
  180                 CHN_LOCK(c);
  181                 if (c->direction == PCMDIR_PLAY &&
  182                     (c->feederflags & (1 << FEEDER_VOLUME)))
  183                         chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right,
  184                             (left + right) >> 1);
  185                 CHN_UNLOCK(c);
  186         }
  187 
  188         MIXER_SET_UNLOCK(d, acquiremtx);
  189         MIXER_SET_LOCK(m, dropmtx);
  190 
  191         return (0);
  192 }
  193 
  194 static int
  195 mixer_set_eq(struct snd_mixer *m, struct snddev_info *d,
  196     u_int dev, u_int level)
  197 {
  198         struct pcm_channel *c;
  199         struct pcm_feeder *f;
  200         int tone, dropmtx, acquiremtx;
  201 
  202         if (dev == SOUND_MIXER_TREBLE)
  203                 tone = FEEDEQ_TREBLE;
  204         else if (dev == SOUND_MIXER_BASS)
  205                 tone = FEEDEQ_BASS;
  206         else
  207                 return (EINVAL);
  208 
  209         if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
  210                 return (EINVAL);
  211 
  212         if (mtx_owned(m->lock))
  213                 dropmtx = 1;
  214         else
  215                 dropmtx = 0;
  216 
  217         if (!(d->flags & SD_F_MPSAFE) || mtx_owned(d->lock) != 0)
  218                 acquiremtx = 0;
  219         else
  220                 acquiremtx = 1;
  221 
  222         /*
  223          * Be careful here. If we're coming from cdev ioctl, it is OK to
  224          * not doing locking AT ALL (except on individual channel) since
  225          * we've been heavily guarded by pcm cv, or if we're still
  226          * under Giant influence. Since we also have mix_* calls, we cannot
  227          * assume such protection and just do the lock as usuall.
  228          */
  229         MIXER_SET_UNLOCK(m, dropmtx);
  230         MIXER_SET_LOCK(d, acquiremtx);
  231 
  232         CHN_FOREACH(c, d, channels.pcm.busy) {
  233                 CHN_LOCK(c);
  234                 f = chn_findfeeder(c, FEEDER_EQ);
  235                 if (f != NULL)
  236                         (void)FEEDER_SET(f, tone, level);
  237                 CHN_UNLOCK(c);
  238         }
  239 
  240         MIXER_SET_UNLOCK(d, acquiremtx);
  241         MIXER_SET_LOCK(m, dropmtx);
  242 
  243         return (0);
  244 }
  245 
  246 static int
  247 mixer_set(struct snd_mixer *m, u_int dev, u_int32_t muted, u_int lev)
  248 {
  249         struct snddev_info *d;
  250         u_int l, r, tl, tr;
  251         u_int32_t parent = SOUND_MIXER_NONE, child = 0;
  252         u_int32_t realdev;
  253         int i, dropmtx;
  254 
  255         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
  256             (0 == (m->devs & (1 << dev))))
  257                 return (-1);
  258 
  259         l = min((lev & 0x00ff), 100);
  260         r = min(((lev & 0xff00) >> 8), 100);
  261         realdev = m->realdev[dev];
  262 
  263         d = device_get_softc(m->dev);
  264         if (d == NULL)
  265                 return (-1);
  266 
  267         /* It is safe to drop this mutex due to Giant. */
  268         if (!(d->flags & SD_F_MPSAFE) && mtx_owned(m->lock) != 0)
  269                 dropmtx = 1;
  270         else
  271                 dropmtx = 0;
  272 
  273         /* Allow the volume to be "changed" while muted. */
  274         if (muted & (1 << dev)) {
  275                 m->level_muted[dev] = l | (r << 8);
  276                 return (0);
  277         }
  278         MIXER_SET_UNLOCK(m, dropmtx);
  279 
  280         /* TODO: recursive handling */
  281         parent = m->parent[dev];
  282         if (parent >= SOUND_MIXER_NRDEVICES)
  283                 parent = SOUND_MIXER_NONE;
  284         if (parent == SOUND_MIXER_NONE)
  285                 child = m->child[dev];
  286 
  287         if (parent != SOUND_MIXER_NONE) {
  288                 tl = (l * (m->level[parent] & 0x00ff)) / 100;
  289                 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
  290                 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
  291                         (void)mixer_set_softpcmvol(m, d, tl, tr);
  292                 else if (realdev != SOUND_MIXER_NONE &&
  293                     MIXER_SET(m, realdev, tl, tr) < 0) {
  294                         MIXER_SET_LOCK(m, dropmtx);
  295                         return (-1);
  296                 }
  297         } else if (child != 0) {
  298                 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  299                         if (!(child & (1 << i)) || m->parent[i] != dev)
  300                                 continue;
  301                         realdev = m->realdev[i];
  302                         tl = (l * (m->level[i] & 0x00ff)) / 100;
  303                         tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
  304                         if (i == SOUND_MIXER_PCM &&
  305                             (d->flags & SD_F_SOFTPCMVOL))
  306                                 (void)mixer_set_softpcmvol(m, d, tl, tr);
  307                         else if (realdev != SOUND_MIXER_NONE)
  308                                 MIXER_SET(m, realdev, tl, tr);
  309                 }
  310                 realdev = m->realdev[dev];
  311                 if (realdev != SOUND_MIXER_NONE &&
  312                     MIXER_SET(m, realdev, l, r) < 0) {
  313                         MIXER_SET_LOCK(m, dropmtx);
  314                         return (-1);
  315                 }
  316         } else {
  317                 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
  318                         (void)mixer_set_softpcmvol(m, d, l, r);
  319                 else if ((dev == SOUND_MIXER_TREBLE ||
  320                     dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ))
  321                         (void)mixer_set_eq(m, d, dev, (l + r) >> 1);
  322                 else if (realdev != SOUND_MIXER_NONE &&
  323                     MIXER_SET(m, realdev, l, r) < 0) {
  324                         MIXER_SET_LOCK(m, dropmtx);
  325                         return (-1);
  326                 }
  327         }
  328 
  329         MIXER_SET_LOCK(m, dropmtx);
  330 
  331         m->level[dev] = l | (r << 8);
  332         m->modify_counter++;
  333 
  334         return (0);
  335 }
  336 
  337 static int
  338 mixer_get(struct snd_mixer *mixer, int dev)
  339 {
  340         if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) {
  341                 if (mixer->mutedevs & (1 << dev))
  342                         return (mixer->level_muted[dev]);
  343                 else
  344                         return (mixer->level[dev]);
  345         } else {
  346                 return (-1);
  347         }
  348 }
  349 
  350 void
  351 mix_setmutedevs(struct snd_mixer *mixer, u_int32_t mutedevs)
  352 {
  353         u_int32_t delta;
  354 
  355         /* Filter out invalid values. */
  356         mutedevs &= mixer->devs;
  357         delta = (mixer->mutedevs ^ mutedevs) & mixer->devs;
  358         mixer->mutedevs = mutedevs;
  359 
  360         for (int i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  361                 if (!(delta & (1 << i)))
  362                         continue;
  363                 if (mutedevs & (1 << i)) {
  364                         mixer->level_muted[i] = mixer->level[i];
  365                         mixer_set(mixer, i, 0, 0);
  366                 } else {
  367                         mixer_set(mixer, i, 0, mixer->level_muted[i]);
  368                 }
  369         }
  370 }
  371 
  372 static int
  373 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
  374 {
  375         struct snddev_info *d;
  376         u_int32_t recsrc;
  377         int dropmtx;
  378 
  379         d = device_get_softc(mixer->dev);
  380         if (d == NULL)
  381                 return -1;
  382         if (!(d->flags & SD_F_MPSAFE) && mtx_owned(mixer->lock) != 0)
  383                 dropmtx = 1;
  384         else
  385                 dropmtx = 0;
  386         src &= mixer->recdevs;
  387         if (src == 0)
  388                 src = mixer->recdevs & SOUND_MASK_MIC;
  389         if (src == 0)
  390                 src = mixer->recdevs & SOUND_MASK_MONITOR;
  391         if (src == 0)
  392                 src = mixer->recdevs & SOUND_MASK_LINE;
  393         if (src == 0 && mixer->recdevs != 0)
  394                 src = (1 << (ffs(mixer->recdevs) - 1));
  395         /* It is safe to drop this mutex due to Giant. */
  396         MIXER_SET_UNLOCK(mixer, dropmtx);
  397         recsrc = MIXER_SETRECSRC(mixer, src);
  398         MIXER_SET_LOCK(mixer, dropmtx);
  399 
  400         mixer->recsrc = recsrc;
  401 
  402         return 0;
  403 }
  404 
  405 static int
  406 mixer_getrecsrc(struct snd_mixer *mixer)
  407 {
  408         return mixer->recsrc;
  409 }
  410 
  411 /**
  412  * @brief Retrieve the route number of the current recording device
  413  *
  414  * OSSv4 assigns routing numbers to recording devices, unlike the previous
  415  * API which relied on a fixed table of device numbers and names.  This
  416  * function returns the routing number of the device currently selected
  417  * for recording.
  418  *
  419  * For now, this function is kind of a goofy compatibility stub atop the
  420  * existing sound system.  (For example, in theory, the old sound system
  421  * allows multiple recording devices to be specified via a bitmask.)
  422  *
  423  * @param m     mixer context container thing
  424  *
  425  * @retval 0            success
  426  * @retval EIDRM        no recording device found (generally not possible)
  427  * @todo Ask about error code
  428  */
  429 static int
  430 mixer_get_recroute(struct snd_mixer *m, int *route)
  431 {
  432         int i, cnt;
  433 
  434         cnt = 0;
  435 
  436         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  437                 /** @todo can user set a multi-device mask? (== or &?) */
  438                 if ((1 << i) == m->recsrc)
  439                         break;
  440                 if ((1 << i) & m->recdevs)
  441                         ++cnt;
  442         }
  443 
  444         if (i == SOUND_MIXER_NRDEVICES)
  445                 return EIDRM;
  446 
  447         *route = cnt;
  448         return 0;
  449 }
  450 
  451 /**
  452  * @brief Select a device for recording
  453  *
  454  * This function sets a recording source based on a recording device's
  455  * routing number.  Said number is translated to an old school recdev
  456  * mask and passed over mixer_setrecsrc. 
  457  *
  458  * @param m     mixer context container thing
  459  *
  460  * @retval 0            success(?)
  461  * @retval EINVAL       User specified an invalid device number
  462  * @retval otherwise    error from mixer_setrecsrc
  463  */
  464 static int
  465 mixer_set_recroute(struct snd_mixer *m, int route)
  466 {
  467         int i, cnt, ret;
  468 
  469         ret = 0;
  470         cnt = 0;
  471 
  472         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  473                 if ((1 << i) & m->recdevs) {
  474                         if (route == cnt)
  475                                 break;
  476                         ++cnt;
  477                 }
  478         }
  479 
  480         if (i == SOUND_MIXER_NRDEVICES)
  481                 ret = EINVAL;
  482         else
  483                 ret = mixer_setrecsrc(m, (1 << i));
  484 
  485         return ret;
  486 }
  487 
  488 void
  489 mix_setdevs(struct snd_mixer *m, u_int32_t v)
  490 {
  491         struct snddev_info *d;
  492         int i;
  493 
  494         if (m == NULL)
  495                 return;
  496 
  497         d = device_get_softc(m->dev);
  498         if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
  499                 v |= SOUND_MASK_PCM;
  500         if (d != NULL && (d->flags & SD_F_EQ))
  501                 v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS;
  502         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  503                 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
  504                         v |= 1 << m->parent[i];
  505                 v |= m->child[i];
  506         }
  507         m->devs = v;
  508 }
  509 
  510 /**
  511  * @brief Record mask of available recording devices
  512  *
  513  * Calling functions are responsible for defining the mask of available
  514  * recording devices.  This function records that value in a structure
  515  * used by the rest of the mixer code.
  516  *
  517  * This function also populates a structure used by the SNDCTL_DSP_*RECSRC*
  518  * family of ioctls that are part of OSSV4.  All recording device labels
  519  * are concatenated in ascending order corresponding to their routing
  520  * numbers.  (Ex:  a system might have 0 => 'vol', 1 => 'cd', 2 => 'line',
  521  * etc.)  For now, these labels are just the standard recording device
  522  * names (cd, line1, etc.), but will eventually be fully dynamic and user
  523  * controlled.
  524  *
  525  * @param m     mixer device context container thing
  526  * @param v     mask of recording devices
  527  */
  528 void
  529 mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
  530 {
  531         oss_mixer_enuminfo *ei;
  532         char *loc;
  533         int i, nvalues, nwrote, nleft, ncopied;
  534 
  535         ei = &m->enuminfo;
  536 
  537         nvalues = 0;
  538         nwrote = 0;
  539         nleft = sizeof(ei->strings);
  540         loc = ei->strings;
  541 
  542         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  543                 if ((1 << i) & v) {
  544                         ei->strindex[nvalues] = nwrote;
  545                         ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1;
  546                             /* strlcpy retval doesn't include terminator */
  547 
  548                         nwrote += ncopied;
  549                         nleft -= ncopied;
  550                         nvalues++;
  551 
  552                         /*
  553                          * XXX I don't think this should ever be possible.
  554                          * Even with a move to dynamic device/channel names,
  555                          * each label is limited to ~16 characters, so that'd
  556                          * take a LOT to fill this buffer.
  557                          */
  558                         if ((nleft <= 0) || (nvalues >= OSS_ENUM_MAXVALUE)) {
  559                                 device_printf(m->dev,
  560                                     "mix_setrecdevs:  Not enough room to store device names--please file a bug report.\n");
  561                                 device_printf(m->dev, 
  562                                     "mix_setrecdevs:  Please include details about your sound hardware, OS version, etc.\n");
  563                                 break;
  564                         }
  565 
  566                         loc = &ei->strings[nwrote];
  567                 }
  568         }
  569 
  570         /*
  571          * NB:  The SNDCTL_DSP_GET_RECSRC_NAMES ioctl ignores the dev
  572          *      and ctrl fields.
  573          */
  574         ei->nvalues = nvalues;
  575         m->recdevs = v;
  576 }
  577 
  578 void
  579 mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs)
  580 {
  581         u_int32_t mask = 0;
  582         int i;
  583 
  584         if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
  585                 return;
  586         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  587                 if (i == parent)
  588                         continue;
  589                 if (childs & (1 << i)) {
  590                         mask |= 1 << i;
  591                         if (m->parent[i] < SOUND_MIXER_NRDEVICES)
  592                                 m->child[m->parent[i]] &= ~(1 << i);
  593                         m->parent[i] = parent;
  594                         m->child[i] = 0;
  595                 }
  596         }
  597         mask &= ~(1 << parent);
  598         m->child[parent] = mask;
  599 }
  600 
  601 void
  602 mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev)
  603 {
  604         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
  605             !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
  606                 return;
  607         m->realdev[dev] = realdev;
  608 }
  609 
  610 u_int32_t
  611 mix_getparent(struct snd_mixer *m, u_int32_t dev)
  612 {
  613         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
  614                 return SOUND_MIXER_NONE;
  615         return m->parent[dev];
  616 }
  617 
  618 u_int32_t
  619 mix_getchild(struct snd_mixer *m, u_int32_t dev)
  620 {
  621         if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
  622                 return 0;
  623         return m->child[dev];
  624 }
  625 
  626 u_int32_t
  627 mix_getdevs(struct snd_mixer *m)
  628 {
  629         return m->devs;
  630 }
  631 
  632 u_int32_t
  633 mix_getmutedevs(struct snd_mixer *m)
  634 {
  635         return m->mutedevs;
  636 }
  637 
  638 u_int32_t
  639 mix_getrecdevs(struct snd_mixer *m)
  640 {
  641         return m->recdevs;
  642 }
  643 
  644 void *
  645 mix_getdevinfo(struct snd_mixer *m)
  646 {
  647         return m->devinfo;
  648 }
  649 
  650 static struct snd_mixer *
  651 mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo,
  652     int type, const char *desc)
  653 {
  654         struct snd_mixer *m;
  655         int i;
  656 
  657         KASSERT(dev != NULL && cls != NULL && devinfo != NULL,
  658             ("%s(): NULL data dev=%p cls=%p devinfo=%p",
  659             __func__, dev, cls, devinfo));
  660         KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY,
  661             ("invalid mixer type=%d", type));
  662 
  663         m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
  664         snprintf(m->name, sizeof(m->name), "%s:mixer",
  665             device_get_nameunit(dev));
  666         if (desc != NULL) {
  667                 strlcat(m->name, ":", sizeof(m->name));
  668                 strlcat(m->name, desc, sizeof(m->name));
  669         }
  670         m->lock = snd_mtxcreate(m->name, (type == MIXER_TYPE_PRIMARY) ?
  671             "primary pcm mixer" : "secondary pcm mixer");
  672         m->type = type;
  673         m->devinfo = devinfo;
  674         m->busy = 0;
  675         m->dev = dev;
  676         for (i = 0; i < (sizeof(m->parent) / sizeof(m->parent[0])); i++) {
  677                 m->parent[i] = SOUND_MIXER_NONE;
  678                 m->child[i] = 0;
  679                 m->realdev[i] = i;
  680         }
  681 
  682         if (MIXER_INIT(m)) {
  683                 snd_mtxlock(m->lock);
  684                 snd_mtxfree(m->lock);
  685                 kobj_delete((kobj_t)m, M_MIXER);
  686                 return (NULL);
  687         }
  688 
  689         return (m);
  690 }
  691 
  692 int
  693 mixer_delete(struct snd_mixer *m)
  694 {
  695         KASSERT(m != NULL, ("NULL snd_mixer"));
  696         KASSERT(m->type == MIXER_TYPE_SECONDARY,
  697             ("%s(): illegal mixer type=%d", __func__, m->type));
  698 
  699         /* mixer uninit can sleep --hps */
  700 
  701         MIXER_UNINIT(m);
  702 
  703         snd_mtxfree(m->lock);
  704         kobj_delete((kobj_t)m, M_MIXER);
  705 
  706         --mixer_count;
  707 
  708         return (0);
  709 }
  710 
  711 struct snd_mixer *
  712 mixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc)
  713 {
  714         struct snd_mixer *m;
  715 
  716         m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_SECONDARY, desc);
  717 
  718         if (m != NULL)
  719                 ++mixer_count;
  720 
  721         return (m);
  722 }
  723 
  724 int
  725 mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
  726 {
  727         struct snddev_info *snddev;
  728         struct snd_mixer *m;
  729         u_int16_t v;
  730         struct cdev *pdev;
  731         int i, unit, devunit, val;
  732 
  733         snddev = device_get_softc(dev);
  734         if (snddev == NULL)
  735                 return (-1);
  736 
  737         if (resource_int_value(device_get_name(dev),
  738             device_get_unit(dev), "eq", &val) == 0 && val != 0) {
  739                 snddev->flags |= SD_F_EQ;
  740                 if ((val & SD_F_EQ_MASK) == val)
  741                         snddev->flags |= val;
  742                 else
  743                         snddev->flags |= SD_F_EQ_DEFAULT;
  744                 snddev->eqpreamp = 0;
  745         }
  746 
  747         m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL);
  748         if (m == NULL)
  749                 return (-1);
  750 
  751         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  752                 v = snd_mixerdefaults[i];
  753 
  754                 if (resource_int_value(device_get_name(dev),
  755                     device_get_unit(dev), snd_mixernames[i], &val) == 0) {
  756                         if (val >= 0 && val <= 100) {
  757                                 v = (u_int16_t) val;
  758                         }
  759                 }
  760 
  761                 mixer_set(m, i, 0, v | (v << 8));
  762         }
  763 
  764         mixer_setrecsrc(m, 0); /* Set default input. */
  765 
  766         unit = device_get_unit(dev);
  767         devunit = snd_mkunit(unit, SND_DEV_CTL, 0);
  768         pdev = make_dev(&mixer_cdevsw, PCMMINOR(devunit),
  769                  UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
  770         pdev->si_drv1 = m;
  771         snddev->mixer_dev = pdev;
  772 
  773         ++mixer_count;
  774 
  775         if (bootverbose) {
  776                 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  777                         if (!(m->devs & (1 << i)))
  778                                 continue;
  779                         if (m->realdev[i] != i) {
  780                                 device_printf(dev, "Mixer \"%s\" -> \"%s\":",
  781                                     snd_mixernames[i],
  782                                     (m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
  783                                     snd_mixernames[m->realdev[i]] : "none");
  784                         } else {
  785                                 device_printf(dev, "Mixer \"%s\":",
  786                                     snd_mixernames[i]);
  787                         }
  788                         if (m->parent[i] < SOUND_MIXER_NRDEVICES)
  789                                 printf(" parent=\"%s\"",
  790                                     snd_mixernames[m->parent[i]]);
  791                         if (m->child[i] != 0)
  792                                 printf(" child=0x%08x", m->child[i]);
  793                         printf("\n");
  794                 }
  795                 if (snddev->flags & SD_F_SOFTPCMVOL)
  796                         device_printf(dev, "Soft PCM mixer ENABLED\n");
  797                 if (snddev->flags & SD_F_EQ)
  798                         device_printf(dev, "EQ Treble/Bass ENABLED\n");
  799         }
  800 
  801         return (0);
  802 }
  803 
  804 int
  805 mixer_uninit(device_t dev)
  806 {
  807         int i;
  808         struct snddev_info *d;
  809         struct snd_mixer *m;
  810         struct cdev *pdev;
  811 
  812         d = device_get_softc(dev);
  813         pdev = mixer_get_devt(dev);
  814         if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL)
  815                 return EBADF;
  816 
  817         m = pdev->si_drv1;
  818         KASSERT(m != NULL, ("NULL snd_mixer"));
  819         KASSERT(m->type == MIXER_TYPE_PRIMARY,
  820             ("%s(): illegal mixer type=%d", __func__, m->type));
  821 
  822         snd_mtxlock(m->lock);
  823 
  824         if (m->busy) {
  825                 snd_mtxunlock(m->lock);
  826                 return EBUSY;
  827         }
  828 
  829         /* destroy dev can sleep --hps */
  830 
  831         snd_mtxunlock(m->lock);
  832 
  833         pdev->si_drv1 = NULL;
  834         destroy_dev(pdev);
  835 
  836         snd_mtxlock(m->lock);
  837 
  838         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  839                 mixer_set(m, i, 0, 0);
  840 
  841         mixer_setrecsrc(m, SOUND_MASK_MIC);
  842 
  843         snd_mtxunlock(m->lock);
  844 
  845         /* mixer uninit can sleep --hps */
  846 
  847         MIXER_UNINIT(m);
  848 
  849         snd_mtxfree(m->lock);
  850         kobj_delete((kobj_t)m, M_MIXER);
  851 
  852         d->mixer_dev = NULL;
  853 
  854         --mixer_count;
  855 
  856         return 0;
  857 }
  858 
  859 int
  860 mixer_reinit(device_t dev)
  861 {
  862         struct snd_mixer *m;
  863         struct cdev *pdev;
  864         int i;
  865 
  866         pdev = mixer_get_devt(dev);
  867         m = pdev->si_drv1;
  868         snd_mtxlock(m->lock);
  869 
  870         i = MIXER_REINIT(m);
  871         if (i) {
  872                 snd_mtxunlock(m->lock);
  873                 return i;
  874         }
  875 
  876         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
  877                 if (m->mutedevs & (1 << i))
  878                         mixer_set(m, i, 0, 0);
  879                 else
  880                         mixer_set(m, i, 0, m->level[i]);
  881         }
  882 
  883         mixer_setrecsrc(m, m->recsrc);
  884         snd_mtxunlock(m->lock);
  885 
  886         return 0;
  887 }
  888 
  889 static int
  890 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
  891 {
  892         char devname[32];
  893         int error, dev;
  894         struct snd_mixer *m;
  895 
  896         m = oidp->oid_arg1;
  897         snd_mtxlock(m->lock);
  898         strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
  899         snd_mtxunlock(m->lock);
  900         error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
  901         snd_mtxlock(m->lock);
  902         if (error == 0 && req->newptr != NULL) {
  903                 dev = mixer_lookup(devname);
  904                 if (dev == -1) {
  905                         snd_mtxunlock(m->lock);
  906                         return EINVAL;
  907                 } else {
  908                         m->hwvol_mixer = dev;
  909                 }
  910         }
  911         snd_mtxunlock(m->lock);
  912         return error;
  913 }
  914 
  915 int
  916 mixer_hwvol_init(device_t dev)
  917 {
  918         struct snd_mixer *m;
  919         struct cdev *pdev;
  920 
  921         pdev = mixer_get_devt(dev);
  922         m = pdev->si_drv1;
  923 
  924         m->hwvol_mixer = SOUND_MIXER_VOLUME;
  925         m->hwvol_step = 5;
  926         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
  927             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  928             OID_AUTO, "hwvol_step", CTLFLAG_RWTUN, &m->hwvol_step, 0, "");
  929         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  930             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
  931             "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
  932             m, 0, sysctl_hw_snd_hwvol_mixer, "A", "");
  933         return 0;
  934 }
  935 
  936 void
  937 mixer_hwvol_mute_locked(struct snd_mixer *m)
  938 {
  939         mix_setmutedevs(m, m->mutedevs ^ (1 << m->hwvol_mixer));
  940 }
  941 
  942 void
  943 mixer_hwvol_mute(device_t dev)
  944 {
  945         struct snd_mixer *m;
  946         struct cdev *pdev;
  947 
  948         pdev = mixer_get_devt(dev);
  949         m = pdev->si_drv1;
  950         snd_mtxlock(m->lock);
  951         mixer_hwvol_mute_locked(m);
  952         snd_mtxunlock(m->lock);
  953 }
  954 
  955 void
  956 mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step)
  957 {
  958         int level, left, right;
  959 
  960         level = mixer_get(m, m->hwvol_mixer);
  961 
  962         if (level != -1) {
  963                 left = level & 0xff;
  964                 right = (level >> 8) & 0xff;
  965                 left += left_step * m->hwvol_step;
  966                 if (left < 0)
  967                         left = 0;
  968                 else if (left > 100)
  969                         left = 100;
  970                 right += right_step * m->hwvol_step;
  971                 if (right < 0)
  972                         right = 0;
  973                 else if (right > 100)
  974                         right = 100;
  975 
  976                 mixer_set(m, m->hwvol_mixer, m->mutedevs, left | right << 8);
  977         }
  978 }
  979 
  980 void
  981 mixer_hwvol_step(device_t dev, int left_step, int right_step)
  982 {
  983         struct snd_mixer *m;
  984         struct cdev *pdev;
  985 
  986         pdev = mixer_get_devt(dev);
  987         m = pdev->si_drv1;
  988         snd_mtxlock(m->lock);
  989         mixer_hwvol_step_locked(m, left_step, right_step);
  990         snd_mtxunlock(m->lock);
  991 }
  992 
  993 int
  994 mixer_busy(struct snd_mixer *m)
  995 {
  996         KASSERT(m != NULL, ("NULL snd_mixer"));
  997 
  998         return (m->busy);
  999 }
 1000 
 1001 int
 1002 mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right)
 1003 {
 1004         int ret;
 1005 
 1006         KASSERT(m != NULL, ("NULL snd_mixer"));
 1007 
 1008         snd_mtxlock(m->lock);
 1009         ret = mixer_set(m, dev, m->mutedevs, left | (right << 8));
 1010         snd_mtxunlock(m->lock);
 1011 
 1012         return ((ret != 0) ? ENXIO : 0);
 1013 }
 1014 
 1015 int
 1016 mix_get(struct snd_mixer *m, u_int dev)
 1017 {
 1018         int ret;
 1019 
 1020         KASSERT(m != NULL, ("NULL snd_mixer"));
 1021 
 1022         snd_mtxlock(m->lock);
 1023         ret = mixer_get(m, dev);
 1024         snd_mtxunlock(m->lock);
 1025 
 1026         return (ret);
 1027 }
 1028 
 1029 int
 1030 mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
 1031 {
 1032         int ret;
 1033 
 1034         KASSERT(m != NULL, ("NULL snd_mixer"));
 1035 
 1036         snd_mtxlock(m->lock);
 1037         ret = mixer_setrecsrc(m, src);
 1038         snd_mtxunlock(m->lock);
 1039 
 1040         return ((ret != 0) ? ENXIO : 0);
 1041 }
 1042 
 1043 u_int32_t
 1044 mix_getrecsrc(struct snd_mixer *m)
 1045 {
 1046         u_int32_t ret;
 1047 
 1048         KASSERT(m != NULL, ("NULL snd_mixer"));
 1049 
 1050         snd_mtxlock(m->lock);
 1051         ret = mixer_getrecsrc(m);
 1052         snd_mtxunlock(m->lock);
 1053 
 1054         return (ret);
 1055 }
 1056 
 1057 int
 1058 mix_get_type(struct snd_mixer *m)
 1059 {
 1060         KASSERT(m != NULL, ("NULL snd_mixer"));
 1061 
 1062         return (m->type);
 1063 }
 1064 
 1065 device_t
 1066 mix_get_dev(struct snd_mixer *m)
 1067 {
 1068         KASSERT(m != NULL, ("NULL snd_mixer"));
 1069 
 1070         return (m->dev);
 1071 }
 1072 
 1073 /* ----------------------------------------------------------------------- */
 1074 
 1075 static int
 1076 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
 1077 {
 1078         struct snddev_info *d;
 1079         struct snd_mixer *m;
 1080 
 1081         if (i_dev == NULL || i_dev->si_drv1 == NULL)
 1082                 return (EBADF);
 1083 
 1084         m = i_dev->si_drv1;
 1085         d = device_get_softc(m->dev);
 1086         if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
 1087                 return (EBADF);
 1088 
 1089         /* XXX Need Giant magic entry ??? */
 1090 
 1091         snd_mtxlock(m->lock);
 1092         m->busy = 1;
 1093         snd_mtxunlock(m->lock);
 1094 
 1095         return (0);
 1096 }
 1097 
 1098 static int
 1099 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
 1100 {
 1101         struct snddev_info *d;
 1102         struct snd_mixer *m;
 1103         int ret;
 1104 
 1105         if (i_dev == NULL || i_dev->si_drv1 == NULL)
 1106                 return (EBADF);
 1107 
 1108         m = i_dev->si_drv1;
 1109         d = device_get_softc(m->dev);
 1110         if (!PCM_REGISTERED(d))
 1111                 return (EBADF);
 1112 
 1113         /* XXX Need Giant magic entry ??? */
 1114 
 1115         snd_mtxlock(m->lock);
 1116         ret = (m->busy == 0) ? EBADF : 0;
 1117         m->busy = 0;
 1118         snd_mtxunlock(m->lock);
 1119 
 1120         return (ret);
 1121 }
 1122 
 1123 static int
 1124 mixer_ioctl_channel(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
 1125     struct thread *td, int from)
 1126 {
 1127         struct snddev_info *d;
 1128         struct snd_mixer *m;
 1129         struct pcm_channel *c, *rdch, *wrch;
 1130         pid_t pid;
 1131         int j, ret;
 1132 
 1133         if (td == NULL || td->td_proc == NULL)
 1134                 return (-1);
 1135 
 1136         m = dev->si_drv1;
 1137         d = device_get_softc(m->dev);
 1138         j = cmd & 0xff;
 1139 
 1140         switch (j) {
 1141         case SOUND_MIXER_PCM:
 1142         case SOUND_MIXER_RECLEV:
 1143         case SOUND_MIXER_DEVMASK:
 1144         case SOUND_MIXER_CAPS:
 1145         case SOUND_MIXER_STEREODEVS:
 1146                 break;
 1147         default:
 1148                 return (-1);
 1149                 break;
 1150         }
 1151 
 1152         pid = td->td_proc->p_pid;
 1153         rdch = NULL;
 1154         wrch = NULL;
 1155         c = NULL;
 1156         ret = -1;
 1157 
 1158         /*
 1159          * This is unfair. Imagine single proc opening multiple
 1160          * instances of same direction. What we do right now
 1161          * is looking for the first matching proc/pid, and just
 1162          * that. Nothing more. Consider it done.
 1163          *
 1164          * The better approach of controlling specific channel
 1165          * pcm or rec volume is by doing mixer ioctl
 1166          * (SNDCTL_DSP_[SET|GET][PLAY|REC]VOL / SOUND_MIXER_[PCM|RECLEV]
 1167          * on its open fd, rather than cracky mixer bypassing here.
 1168          */
 1169         CHN_FOREACH(c, d, channels.pcm.opened) {
 1170                 CHN_LOCK(c);
 1171                 if (c->pid != pid ||
 1172                     !(c->feederflags & (1 << FEEDER_VOLUME))) {
 1173                         CHN_UNLOCK(c);
 1174                         continue;
 1175                 }
 1176                 if (rdch == NULL && c->direction == PCMDIR_REC) {
 1177                         rdch = c;
 1178                         if (j == SOUND_MIXER_RECLEV)
 1179                                 goto mixer_ioctl_channel_proc;
 1180                 } else if (wrch == NULL && c->direction == PCMDIR_PLAY) {
 1181                         wrch = c;
 1182                         if (j == SOUND_MIXER_PCM)
 1183                                 goto mixer_ioctl_channel_proc;
 1184                 }
 1185                 CHN_UNLOCK(c);
 1186                 if (rdch != NULL && wrch != NULL)
 1187                         break;
 1188         }
 1189 
 1190         if (rdch == NULL && wrch == NULL)
 1191                 return (-1);
 1192 
 1193         if ((j == SOUND_MIXER_DEVMASK || j == SOUND_MIXER_CAPS ||
 1194             j == SOUND_MIXER_STEREODEVS) &&
 1195             (cmd & ~0xff) == MIXER_READ(0)) {
 1196                 snd_mtxlock(m->lock);
 1197                 *(int *)arg = mix_getdevs(m);
 1198                 snd_mtxunlock(m->lock);
 1199                 if (rdch != NULL)
 1200                         *(int *)arg |= SOUND_MASK_RECLEV;
 1201                 if (wrch != NULL)
 1202                         *(int *)arg |= SOUND_MASK_PCM;
 1203                 ret = 0;
 1204         }
 1205 
 1206         return (ret);
 1207 
 1208 mixer_ioctl_channel_proc:
 1209 
 1210         KASSERT(c != NULL, ("%s(): NULL channel", __func__));
 1211         CHN_LOCKASSERT(c);
 1212 
 1213         if ((cmd & ~0xff) == MIXER_WRITE(0)) {
 1214                 int left, right, center;
 1215 
 1216                 left = *(int *)arg & 0x7f;
 1217                 right = (*(int *)arg >> 8) & 0x7f;
 1218                 center = (left + right) >> 1;
 1219                 chn_setvolume_multi(c, SND_VOL_C_PCM, left, right, center);
 1220         } else if ((cmd & ~0xff) == MIXER_READ(0)) {
 1221                 *(int *)arg = CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FL);
 1222                 *(int *)arg |=
 1223                     CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FR) << 8;
 1224         }
 1225 
 1226         CHN_UNLOCK(c);
 1227 
 1228         return (0);
 1229 }
 1230 
 1231 static int
 1232 mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
 1233     struct thread *td)
 1234 {
 1235         struct snddev_info *d;
 1236         int ret;
 1237 
 1238         if (i_dev == NULL || i_dev->si_drv1 == NULL)
 1239                 return (EBADF);
 1240 
 1241         d = device_get_softc(((struct snd_mixer *)i_dev->si_drv1)->dev);
 1242         if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
 1243                 return (EBADF);
 1244 
 1245         PCM_GIANT_ENTER(d);
 1246         PCM_ACQUIRE_QUICK(d);
 1247 
 1248         ret = -1;
 1249 
 1250         if (mixer_bypass != 0 && (d->flags & SD_F_VPC))
 1251                 ret = mixer_ioctl_channel(i_dev, cmd, arg, mode, td,
 1252                     MIXER_CMD_CDEV);
 1253 
 1254         if (ret == -1)
 1255                 ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td,
 1256                     MIXER_CMD_CDEV);
 1257 
 1258         PCM_RELEASE_QUICK(d);
 1259         PCM_GIANT_LEAVE(d);
 1260 
 1261         return (ret);
 1262 }
 1263 
 1264 static void
 1265 mixer_mixerinfo(struct snd_mixer *m, mixer_info *mi)
 1266 {
 1267         bzero((void *)mi, sizeof(*mi));
 1268         strlcpy(mi->id, m->name, sizeof(mi->id));
 1269         strlcpy(mi->name, device_get_desc(m->dev), sizeof(mi->name));
 1270         mi->modify_counter = m->modify_counter;
 1271 }
 1272 
 1273 /*
 1274  * XXX Make sure you can guarantee concurrency safety before calling this
 1275  *     function, be it through Giant, PCM_*, etc !
 1276  */
 1277 int
 1278 mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
 1279     struct thread *td, int from)
 1280 {
 1281         struct snd_mixer *m;
 1282         int ret = EINVAL, *arg_i = (int *)arg;
 1283         int v = -1, j = cmd & 0xff;
 1284 
 1285         /*
 1286          * Certain ioctls may be made on any type of device (audio, mixer,
 1287          * and MIDI).  Handle those special cases here.
 1288          */
 1289         if (IOCGROUP(cmd) == 'X') {
 1290                 switch (cmd) {
 1291                 case SNDCTL_SYSINFO:
 1292                         sound_oss_sysinfo((oss_sysinfo *)arg);
 1293                         return (0);
 1294                 case SNDCTL_CARDINFO:
 1295                         return (sound_oss_card_info((oss_card_info *)arg));
 1296                 case SNDCTL_AUDIOINFO:
 1297                 case SNDCTL_AUDIOINFO_EX:
 1298                 case SNDCTL_ENGINEINFO:
 1299                         return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg));
 1300                 case SNDCTL_MIXERINFO:
 1301                         return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg));
 1302                 }
 1303                 return (EINVAL);
 1304         }
 1305 
 1306         m = i_dev->si_drv1;
 1307 
 1308         if (m == NULL)
 1309                 return (EBADF);
 1310 
 1311         snd_mtxlock(m->lock);
 1312         if (from == MIXER_CMD_CDEV && !m->busy) {
 1313                 snd_mtxunlock(m->lock);
 1314                 return (EBADF);
 1315         }
 1316         switch (cmd) {
 1317         case SNDCTL_DSP_GET_RECSRC_NAMES:
 1318                 bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo));
 1319                 ret = 0;
 1320                 goto done;
 1321         case SNDCTL_DSP_GET_RECSRC:
 1322                 ret = mixer_get_recroute(m, arg_i);
 1323                 goto done;
 1324         case SNDCTL_DSP_SET_RECSRC:
 1325                 ret = mixer_set_recroute(m, *arg_i);
 1326                 goto done;
 1327         case OSS_GETVERSION:
 1328                 *arg_i = SOUND_VERSION;
 1329                 ret = 0;
 1330                 goto done;
 1331         case SOUND_MIXER_INFO:
 1332                 mixer_mixerinfo(m, (mixer_info *)arg);
 1333                 ret = 0;
 1334                 goto done;
 1335         }
 1336         if ((cmd & ~0xff) == MIXER_WRITE(0)) {
 1337                 switch (j) {
 1338                 case SOUND_MIXER_RECSRC:
 1339                         ret = mixer_setrecsrc(m, *arg_i);
 1340                         break;
 1341                 case SOUND_MIXER_MUTE:
 1342                         mix_setmutedevs(m, *arg_i);
 1343                         ret = 0;
 1344                         break;
 1345                 default:
 1346                         ret = mixer_set(m, j, m->mutedevs, *arg_i);
 1347                         break;
 1348                 }
 1349                 snd_mtxunlock(m->lock);
 1350                 return ((ret == 0) ? 0 : ENXIO);
 1351         }
 1352         if ((cmd & ~0xff) == MIXER_READ(0)) {
 1353                 switch (j) {
 1354                 case SOUND_MIXER_DEVMASK:
 1355                 case SOUND_MIXER_CAPS:
 1356                 case SOUND_MIXER_STEREODEVS:
 1357                         v = mix_getdevs(m);
 1358                         break;
 1359                 case SOUND_MIXER_MUTE:
 1360                         v = mix_getmutedevs(m);
 1361                         break;
 1362                 case SOUND_MIXER_RECMASK:
 1363                         v = mix_getrecdevs(m);
 1364                         break;
 1365                 case SOUND_MIXER_RECSRC:
 1366                         v = mixer_getrecsrc(m);
 1367                         break;
 1368                 default:
 1369                         v = mixer_get(m, j);
 1370                         break;
 1371                 }
 1372                 *arg_i = v;
 1373                 snd_mtxunlock(m->lock);
 1374                 return ((v != -1) ? 0 : ENXIO);
 1375         }
 1376 done:
 1377         snd_mtxunlock(m->lock);
 1378         return (ret);
 1379 }
 1380 
 1381 static void
 1382 mixer_clone(void *arg,
 1383     struct ucred *cred,
 1384     char *name, int namelen, struct cdev **dev)
 1385 {
 1386         struct snddev_info *d;
 1387 
 1388         if (*dev != NULL)
 1389                 return;
 1390         if (strcmp(name, "mixer") == 0) {
 1391                 d = devclass_get_softc(pcm_devclass, snd_unit);
 1392                 if (PCM_REGISTERED(d) && d->mixer_dev != NULL) {
 1393                         *dev = d->mixer_dev;
 1394                         dev_ref(*dev);
 1395                 }
 1396         }
 1397 }
 1398 
 1399 static void
 1400 mixer_sysinit(void *p)
 1401 {
 1402         if (mixer_ehtag != NULL)
 1403                 return;
 1404         mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
 1405 }
 1406 
 1407 static void
 1408 mixer_sysuninit(void *p)
 1409 {
 1410         if (mixer_ehtag == NULL)
 1411                 return;
 1412         EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
 1413         mixer_ehtag = NULL;
 1414 }
 1415 
 1416 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
 1417 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
 1418 
 1419 /**
 1420  * @brief Handler for SNDCTL_MIXERINFO
 1421  *
 1422  * This function searches for a mixer based on the numeric ID stored
 1423  * in oss_miserinfo::dev.  If set to -1, then information about the
 1424  * current mixer handling the request is provided.  Note, however, that
 1425  * this ioctl may be made with any sound device (audio, mixer, midi).
 1426  *
 1427  * @note Caller must not hold any PCM device, channel, or mixer locks.
 1428  *
 1429  * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for
 1430  * more information.
 1431  *
 1432  * @param i_dev character device on which the ioctl arrived
 1433  * @param arg   user argument (oss_mixerinfo *)
 1434  *
 1435  * @retval EINVAL       oss_mixerinfo::dev specified a bad value
 1436  * @retval 0            success
 1437  */
 1438 int
 1439 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
 1440 {
 1441         struct snddev_info *d;
 1442         struct snd_mixer *m;
 1443         int nmix, i;
 1444 
 1445         /*
 1446          * If probing the device handling the ioctl, make sure it's a mixer
 1447          * device.  (This ioctl is valid on audio, mixer, and midi devices.)
 1448          */
 1449         if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw)
 1450                 return (EINVAL);
 1451 
 1452         d = NULL;
 1453         m = NULL;
 1454         nmix = 0;
 1455 
 1456         /*
 1457          * There's a 1:1 relationship between mixers and PCM devices, so
 1458          * begin by iterating over PCM devices and search for our mixer.
 1459          */
 1460         for (i = 0; pcm_devclass != NULL &&
 1461             i < devclass_get_maxunit(pcm_devclass); i++) {
 1462                 d = devclass_get_softc(pcm_devclass, i);
 1463                 if (!PCM_REGISTERED(d) || PCM_DETACHING(d))
 1464                         continue;
 1465 
 1466                 /* XXX Need Giant magic entry */
 1467 
 1468                 /* See the note in function docblock. */
 1469                 PCM_UNLOCKASSERT(d);
 1470                 PCM_LOCK(d);
 1471 
 1472                 if (d->mixer_dev != NULL && d->mixer_dev->si_drv1 != NULL &&
 1473                     ((mi->dev == -1 && d->mixer_dev == i_dev) ||
 1474                     mi->dev == nmix)) {
 1475                         m = d->mixer_dev->si_drv1;
 1476                         mtx_lock(m->lock);
 1477 
 1478                         /*
 1479                          * At this point, the following synchronization stuff
 1480                          * has happened:
 1481                          * - a specific PCM device is locked.
 1482                          * - a specific mixer device has been locked, so be
 1483                          *   sure to unlock when existing.
 1484                          */
 1485                         bzero((void *)mi, sizeof(*mi));
 1486                         mi->dev = nmix;
 1487                         snprintf(mi->id, sizeof(mi->id), "mixer%d", i);
 1488                         strlcpy(mi->name, m->name, sizeof(mi->name));
 1489                         mi->modify_counter = m->modify_counter;
 1490                         mi->card_number = i;
 1491                         /*
 1492                          * Currently, FreeBSD assumes 1:1 relationship between
 1493                          * a pcm and mixer devices, so this is hardcoded to 0.
 1494                          */
 1495                         mi->port_number = 0;
 1496 
 1497                         /**
 1498                          * @todo Fill in @sa oss_mixerinfo::mixerhandle.
 1499                          * @note From 4Front:  "mixerhandle is an arbitrary
 1500                          *       string that identifies the mixer better than
 1501                          *       the device number (mixerinfo.dev).  Device
 1502                          *       numbers may change depending on the order the
 1503                          *       drivers are loaded. However the handle should
 1504                          *       remain the same provided that the sound card
 1505                          *       is not moved to another PCI slot."
 1506                          */
 1507 
 1508                         /**
 1509                          * @note
 1510                          * @sa oss_mixerinfo::magic is a reserved field.
 1511                          * 
 1512                          * @par
 1513                          * From 4Front:  "magic is usually 0. However some
 1514                          * devices may have dedicated setup utilities and the
 1515                          * magic field may contain an unique driver specific
 1516                          * value (managed by [4Front])."
 1517                          */
 1518 
 1519                         mi->enabled = device_is_attached(m->dev) ? 1 : 0;
 1520                         /**
 1521                          * The only flag for @sa oss_mixerinfo::caps is
 1522                          * currently MIXER_CAP_VIRTUAL, which I'm not sure we
 1523                          * really worry about.
 1524                          */
 1525                         /**
 1526                          * Mixer extensions currently aren't supported, so
 1527                          * leave @sa oss_mixerinfo::nrext blank for now.
 1528                          */
 1529                         /**
 1530                          * @todo Fill in @sa oss_mixerinfo::priority (requires
 1531                          *       touching drivers?)
 1532                          * @note The priority field is for mixer applets to
 1533                          * determine which mixer should be the default, with 0
 1534                          * being least preferred and 10 being most preferred.
 1535                          * From 4Front:  "OSS drivers like ICH use higher
 1536                          * values (10) because such chips are known to be used
 1537                          * only on motherboards.  Drivers for high end pro
 1538                          * devices use 0 because they will never be the
 1539                          * default mixer. Other devices use values 1 to 9
 1540                          * depending on the estimated probability of being the
 1541                          * default device.
 1542                          *
 1543                          * XXX Described by Hannu@4Front, but not found in
 1544                          *     soundcard.h.
 1545                         strlcpy(mi->devnode, devtoname(d->mixer_dev),
 1546                         sizeof(mi->devnode));
 1547                         mi->legacy_device = i;
 1548                          */
 1549                         mtx_unlock(m->lock);
 1550                 } else
 1551                         ++nmix;
 1552 
 1553                 PCM_UNLOCK(d);
 1554 
 1555                 if (m != NULL)
 1556                         return (0);
 1557         }
 1558 
 1559         return (EINVAL);
 1560 }
 1561 
 1562 /*
 1563  * Allow the sound driver to use the mixer lock to protect its mixer
 1564  * data:
 1565  */
 1566 struct mtx *
 1567 mixer_get_lock(struct snd_mixer *m)
 1568 {
 1569         if (m->lock == NULL) {
 1570                 return (&Giant);
 1571         }
 1572         return (m->lock);
 1573 }
 1574 
 1575 int
 1576 mix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright)
 1577 {
 1578         int level;
 1579 
 1580         level = mixer_get(m, dev);
 1581         if (level < 0) {
 1582                 *pright = *pleft = -1;
 1583                 return (-1);
 1584         }
 1585 
 1586         *pleft = level & 0xFF;
 1587         *pright = (level >> 8) & 0xFF;
 1588 
 1589         return (0);
 1590 }
 1591 
 1592 int
 1593 mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right)
 1594 {
 1595         int level;
 1596 
 1597         level = (left & 0xFF) | ((right & 0xFF) << 8);
 1598 
 1599         return (mixer_set(m, dev, m->mutedevs, level));
 1600 }

Cache object: 0529244e5429ca46ecfff07dddeaa913


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