The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/pcm/mixer.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: a500dda1a283c0fb5d4c50582eac9055


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