2 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
4 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #ifdef HAVE_KERNEL_OPTION_HEADERS
33 #include <dev/sound/pcm/sound.h>
35 #include "feeder_if.h"
38 SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/mixer.c 274035 2014-11-03 11:11:45Z bapt $");
40 static MALLOC_DEFINE(M_MIXER, "mixer", "mixer");
42 static int mixer_bypass = 1;
43 SYSCTL_INT(_hw_snd, OID_AUTO, vpc_mixer_bypass, CTLFLAG_RWTUN,
45 "control channel pcm/rec volume, bypassing real mixer device");
47 #define MIXER_NAMELEN 16
57 u_int32_t hwvol_mute_level;
65 char name[MIXER_NAMELEN];
67 oss_mixer_enuminfo enuminfo;
69 * Counter is incremented when applications change any of this
70 * mixer's controls. A change in value indicates that persistent
71 * mixer applications should update their displays.
76 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
77 [SOUND_MIXER_VOLUME] = 75,
78 [SOUND_MIXER_BASS] = 50,
79 [SOUND_MIXER_TREBLE] = 50,
80 [SOUND_MIXER_SYNTH] = 75,
81 [SOUND_MIXER_PCM] = 75,
82 [SOUND_MIXER_SPEAKER] = 75,
83 [SOUND_MIXER_LINE] = 75,
84 [SOUND_MIXER_MIC] = 0,
85 [SOUND_MIXER_CD] = 75,
86 [SOUND_MIXER_IGAIN] = 0,
87 [SOUND_MIXER_LINE1] = 75,
88 [SOUND_MIXER_VIDEO] = 75,
89 [SOUND_MIXER_RECLEV] = 75,
90 [SOUND_MIXER_OGAIN] = 50,
91 [SOUND_MIXER_MONITOR] = 75,
94 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
96 static d_open_t mixer_open;
97 static d_close_t mixer_close;
98 static d_ioctl_t mixer_ioctl;
100 static struct cdevsw mixer_cdevsw = {
101 .d_version = D_VERSION,
102 .d_open = mixer_open,
103 .d_close = mixer_close,
104 .d_ioctl = mixer_ioctl,
109 * Keeps a count of mixer devices; used only by OSSv4 SNDCTL_SYSINFO ioctl.
113 static eventhandler_tag mixer_ehtag = NULL;
116 mixer_get_devt(device_t dev)
118 struct snddev_info *snddev;
120 snddev = device_get_softc(dev);
122 return snddev->mixer_dev;
126 mixer_lookup(char *devname)
130 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
131 if (strncmp(devname, snd_mixernames[i],
132 strlen(snd_mixernames[i])) == 0)
137 #define MIXER_SET_UNLOCK(x, y) do { \
139 snd_mtxunlock((x)->lock); \
142 #define MIXER_SET_LOCK(x, y) do { \
144 snd_mtxlock((x)->lock); \
148 mixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d,
149 u_int left, u_int right)
151 struct pcm_channel *c;
152 int dropmtx, acquiremtx;
154 if (!PCM_REGISTERED(d))
157 if (mtx_owned(m->lock))
162 if (!(d->flags & SD_F_MPSAFE) || mtx_owned(d->lock) != 0)
168 * Be careful here. If we're coming from cdev ioctl, it is OK to
169 * not doing locking AT ALL (except on individual channel) since
170 * we've been heavily guarded by pcm cv, or if we're still
171 * under Giant influence. Since we also have mix_* calls, we cannot
172 * assume such protection and just do the lock as usuall.
174 MIXER_SET_UNLOCK(m, dropmtx);
175 MIXER_SET_LOCK(d, acquiremtx);
177 CHN_FOREACH(c, d, channels.pcm.busy) {
179 if (c->direction == PCMDIR_PLAY &&
180 (c->feederflags & (1 << FEEDER_VOLUME)))
181 chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right,
182 (left + right) >> 1);
186 MIXER_SET_UNLOCK(d, acquiremtx);
187 MIXER_SET_LOCK(m, dropmtx);
193 mixer_set_eq(struct snd_mixer *m, struct snddev_info *d,
194 u_int dev, u_int level)
196 struct pcm_channel *c;
197 struct pcm_feeder *f;
198 int tone, dropmtx, acquiremtx;
200 if (dev == SOUND_MIXER_TREBLE)
201 tone = FEEDEQ_TREBLE;
202 else if (dev == SOUND_MIXER_BASS)
207 if (!PCM_REGISTERED(d))
210 if (mtx_owned(m->lock))
215 if (!(d->flags & SD_F_MPSAFE) || mtx_owned(d->lock) != 0)
221 * Be careful here. If we're coming from cdev ioctl, it is OK to
222 * not doing locking AT ALL (except on individual channel) since
223 * we've been heavily guarded by pcm cv, or if we're still
224 * under Giant influence. Since we also have mix_* calls, we cannot
225 * assume such protection and just do the lock as usuall.
227 MIXER_SET_UNLOCK(m, dropmtx);
228 MIXER_SET_LOCK(d, acquiremtx);
230 CHN_FOREACH(c, d, channels.pcm.busy) {
232 f = chn_findfeeder(c, FEEDER_EQ);
234 (void)FEEDER_SET(f, tone, level);
238 MIXER_SET_UNLOCK(d, acquiremtx);
239 MIXER_SET_LOCK(m, dropmtx);
245 mixer_set(struct snd_mixer *m, u_int dev, u_int lev)
247 struct snddev_info *d;
249 u_int32_t parent = SOUND_MIXER_NONE, child = 0;
253 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
254 (0 == (m->devs & (1 << dev))))
257 l = min((lev & 0x00ff), 100);
258 r = min(((lev & 0xff00) >> 8), 100);
259 realdev = m->realdev[dev];
261 d = device_get_softc(m->dev);
265 /* It is safe to drop this mutex due to Giant. */
266 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(m->lock) != 0)
271 MIXER_SET_UNLOCK(m, dropmtx);
273 /* TODO: recursive handling */
274 parent = m->parent[dev];
275 if (parent >= SOUND_MIXER_NRDEVICES)
276 parent = SOUND_MIXER_NONE;
277 if (parent == SOUND_MIXER_NONE)
278 child = m->child[dev];
280 if (parent != SOUND_MIXER_NONE) {
281 tl = (l * (m->level[parent] & 0x00ff)) / 100;
282 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
283 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
284 (void)mixer_set_softpcmvol(m, d, tl, tr);
285 else if (realdev != SOUND_MIXER_NONE &&
286 MIXER_SET(m, realdev, tl, tr) < 0) {
287 MIXER_SET_LOCK(m, dropmtx);
290 } else if (child != 0) {
291 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
292 if (!(child & (1 << i)) || m->parent[i] != dev)
294 realdev = m->realdev[i];
295 tl = (l * (m->level[i] & 0x00ff)) / 100;
296 tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
297 if (i == SOUND_MIXER_PCM &&
298 (d->flags & SD_F_SOFTPCMVOL))
299 (void)mixer_set_softpcmvol(m, d, tl, tr);
300 else if (realdev != SOUND_MIXER_NONE)
301 MIXER_SET(m, realdev, tl, tr);
303 realdev = m->realdev[dev];
304 if (realdev != SOUND_MIXER_NONE &&
305 MIXER_SET(m, realdev, l, r) < 0) {
306 MIXER_SET_LOCK(m, dropmtx);
310 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
311 (void)mixer_set_softpcmvol(m, d, l, r);
312 else if ((dev == SOUND_MIXER_TREBLE ||
313 dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ))
314 (void)mixer_set_eq(m, d, dev, (l + r) >> 1);
315 else if (realdev != SOUND_MIXER_NONE &&
316 MIXER_SET(m, realdev, l, r) < 0) {
317 MIXER_SET_LOCK(m, dropmtx);
322 MIXER_SET_LOCK(m, dropmtx);
324 m->level[dev] = l | (r << 8);
330 mixer_get(struct snd_mixer *mixer, int dev)
332 if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev)))
333 return mixer->level[dev];
339 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
341 struct snddev_info *d;
345 d = device_get_softc(mixer->dev);
348 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(mixer->lock) != 0)
352 src &= mixer->recdevs;
354 src = mixer->recdevs & SOUND_MASK_MIC;
356 src = mixer->recdevs & SOUND_MASK_MONITOR;
358 src = mixer->recdevs & SOUND_MASK_LINE;
359 if (src == 0 && mixer->recdevs != 0)
360 src = (1 << (ffs(mixer->recdevs) - 1));
361 /* It is safe to drop this mutex due to Giant. */
362 MIXER_SET_UNLOCK(mixer, dropmtx);
363 recsrc = MIXER_SETRECSRC(mixer, src);
364 MIXER_SET_LOCK(mixer, dropmtx);
366 mixer->recsrc = recsrc;
372 mixer_getrecsrc(struct snd_mixer *mixer)
374 return mixer->recsrc;
378 * @brief Retrieve the route number of the current recording device
380 * OSSv4 assigns routing numbers to recording devices, unlike the previous
381 * API which relied on a fixed table of device numbers and names. This
382 * function returns the routing number of the device currently selected
385 * For now, this function is kind of a goofy compatibility stub atop the
386 * existing sound system. (For example, in theory, the old sound system
387 * allows multiple recording devices to be specified via a bitmask.)
389 * @param m mixer context container thing
392 * @retval EIDRM no recording device found (generally not possible)
393 * @todo Ask about error code
396 mixer_get_recroute(struct snd_mixer *m, int *route)
402 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
403 /** @todo can user set a multi-device mask? (== or &?) */
404 if ((1 << i) == m->recsrc)
406 if ((1 << i) & m->recdevs)
410 if (i == SOUND_MIXER_NRDEVICES)
418 * @brief Select a device for recording
420 * This function sets a recording source based on a recording device's
421 * routing number. Said number is translated to an old school recdev
422 * mask and passed over mixer_setrecsrc.
424 * @param m mixer context container thing
426 * @retval 0 success(?)
427 * @retval EINVAL User specified an invalid device number
428 * @retval otherwise error from mixer_setrecsrc
431 mixer_set_recroute(struct snd_mixer *m, int route)
438 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
439 if ((1 << i) & m->recdevs) {
446 if (i == SOUND_MIXER_NRDEVICES)
449 ret = mixer_setrecsrc(m, (1 << i));
455 mix_setdevs(struct snd_mixer *m, u_int32_t v)
457 struct snddev_info *d;
463 d = device_get_softc(m->dev);
464 if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
466 if (d != NULL && (d->flags & SD_F_EQ))
467 v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS;
468 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
469 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
470 v |= 1 << m->parent[i];
477 * @brief Record mask of available recording devices
479 * Calling functions are responsible for defining the mask of available
480 * recording devices. This function records that value in a structure
481 * used by the rest of the mixer code.
483 * This function also populates a structure used by the SNDCTL_DSP_*RECSRC*
484 * family of ioctls that are part of OSSV4. All recording device labels
485 * are concatenated in ascending order corresponding to their routing
486 * numbers. (Ex: a system might have 0 => 'vol', 1 => 'cd', 2 => 'line',
487 * etc.) For now, these labels are just the standard recording device
488 * names (cd, line1, etc.), but will eventually be fully dynamic and user
491 * @param m mixer device context container thing
492 * @param v mask of recording devices
495 mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
497 oss_mixer_enuminfo *ei;
499 int i, nvalues, nwrote, nleft, ncopied;
505 nleft = sizeof(ei->strings);
508 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
510 ei->strindex[nvalues] = nwrote;
511 ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1;
512 /* strlcpy retval doesn't include terminator */
519 * XXX I don't think this should ever be possible.
520 * Even with a move to dynamic device/channel names,
521 * each label is limited to ~16 characters, so that'd
522 * take a LOT to fill this buffer.
524 if ((nleft <= 0) || (nvalues >= OSS_ENUM_MAXVALUE)) {
525 device_printf(m->dev,
526 "mix_setrecdevs: Not enough room to store device names--please file a bug report.\n");
527 device_printf(m->dev,
528 "mix_setrecdevs: Please include details about your sound hardware, OS version, etc.\n");
532 loc = &ei->strings[nwrote];
537 * NB: The SNDCTL_DSP_GET_RECSRC_NAMES ioctl ignores the dev
540 ei->nvalues = nvalues;
545 mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs)
550 if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
552 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
555 if (childs & (1 << i)) {
557 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
558 m->child[m->parent[i]] &= ~(1 << i);
559 m->parent[i] = parent;
563 mask &= ~(1 << parent);
564 m->child[parent] = mask;
568 mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev)
570 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
571 !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
573 m->realdev[dev] = realdev;
577 mix_getparent(struct snd_mixer *m, u_int32_t dev)
579 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
580 return SOUND_MIXER_NONE;
581 return m->parent[dev];
585 mix_getchild(struct snd_mixer *m, u_int32_t dev)
587 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
589 return m->child[dev];
593 mix_getdevs(struct snd_mixer *m)
599 mix_getrecdevs(struct snd_mixer *m)
605 mix_getdevinfo(struct snd_mixer *m)
610 static struct snd_mixer *
611 mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo,
612 int type, const char *desc)
617 KASSERT(dev != NULL && cls != NULL && devinfo != NULL,
618 ("%s(): NULL data dev=%p cls=%p devinfo=%p",
619 __func__, dev, cls, devinfo));
620 KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY,
621 ("invalid mixer type=%d", type));
623 m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
624 snprintf(m->name, sizeof(m->name), "%s:mixer",
625 device_get_nameunit(dev));
627 strlcat(m->name, ":", sizeof(m->name));
628 strlcat(m->name, desc, sizeof(m->name));
630 m->lock = snd_mtxcreate(m->name, (type == MIXER_TYPE_PRIMARY) ?
631 "primary pcm mixer" : "secondary pcm mixer");
633 m->devinfo = devinfo;
636 for (i = 0; i < (sizeof(m->parent) / sizeof(m->parent[0])); i++) {
637 m->parent[i] = SOUND_MIXER_NONE;
643 snd_mtxlock(m->lock);
644 snd_mtxfree(m->lock);
645 kobj_delete((kobj_t)m, M_MIXER);
653 mixer_delete(struct snd_mixer *m)
655 KASSERT(m != NULL, ("NULL snd_mixer"));
656 KASSERT(m->type == MIXER_TYPE_SECONDARY,
657 ("%s(): illegal mixer type=%d", __func__, m->type));
659 /* mixer uninit can sleep --hps */
663 snd_mtxfree(m->lock);
664 kobj_delete((kobj_t)m, M_MIXER);
672 mixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc)
676 m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_SECONDARY, desc);
685 mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
687 struct snddev_info *snddev;
691 int i, unit, devunit, val;
693 snddev = device_get_softc(dev);
697 if (resource_int_value(device_get_name(dev),
698 device_get_unit(dev), "eq", &val) == 0 && val != 0) {
699 snddev->flags |= SD_F_EQ;
700 if ((val & SD_F_EQ_MASK) == val)
701 snddev->flags |= val;
703 snddev->flags |= SD_F_EQ_DEFAULT;
704 snddev->eqpreamp = 0;
707 m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL);
711 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
712 v = snd_mixerdefaults[i];
714 if (resource_int_value(device_get_name(dev),
715 device_get_unit(dev), snd_mixernames[i], &val) == 0) {
716 if (val >= 0 && val <= 100) {
721 mixer_set(m, i, v | (v << 8));
724 mixer_setrecsrc(m, 0); /* Set default input. */
726 unit = device_get_unit(dev);
727 devunit = snd_mkunit(unit, SND_DEV_CTL, 0);
728 pdev = make_dev(&mixer_cdevsw, PCMMINOR(devunit),
729 UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
731 snddev->mixer_dev = pdev;
736 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
737 if (!(m->devs & (1 << i)))
739 if (m->realdev[i] != i) {
740 device_printf(dev, "Mixer \"%s\" -> \"%s\":",
742 (m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
743 snd_mixernames[m->realdev[i]] : "none");
745 device_printf(dev, "Mixer \"%s\":",
748 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
749 printf(" parent=\"%s\"",
750 snd_mixernames[m->parent[i]]);
751 if (m->child[i] != 0)
752 printf(" child=0x%08x", m->child[i]);
755 if (snddev->flags & SD_F_SOFTPCMVOL)
756 device_printf(dev, "Soft PCM mixer ENABLED\n");
757 if (snddev->flags & SD_F_EQ)
758 device_printf(dev, "EQ Treble/Bass ENABLED\n");
765 mixer_uninit(device_t dev)
768 struct snddev_info *d;
772 d = device_get_softc(dev);
773 pdev = mixer_get_devt(dev);
774 if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL)
778 KASSERT(m != NULL, ("NULL snd_mixer"));
779 KASSERT(m->type == MIXER_TYPE_PRIMARY,
780 ("%s(): illegal mixer type=%d", __func__, m->type));
782 snd_mtxlock(m->lock);
785 snd_mtxunlock(m->lock);
789 /* destroy dev can sleep --hps */
791 snd_mtxunlock(m->lock);
793 pdev->si_drv1 = NULL;
796 snd_mtxlock(m->lock);
798 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
801 mixer_setrecsrc(m, SOUND_MASK_MIC);
803 snd_mtxunlock(m->lock);
805 /* mixer uninit can sleep --hps */
809 snd_mtxfree(m->lock);
810 kobj_delete((kobj_t)m, M_MIXER);
820 mixer_reinit(device_t dev)
826 pdev = mixer_get_devt(dev);
828 snd_mtxlock(m->lock);
832 snd_mtxunlock(m->lock);
836 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
837 mixer_set(m, i, m->level[i]);
839 mixer_setrecsrc(m, m->recsrc);
840 snd_mtxunlock(m->lock);
846 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
853 snd_mtxlock(m->lock);
854 strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
855 snd_mtxunlock(m->lock);
856 error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
857 snd_mtxlock(m->lock);
858 if (error == 0 && req->newptr != NULL) {
859 dev = mixer_lookup(devname);
861 snd_mtxunlock(m->lock);
864 else if (dev != m->hwvol_mixer) {
865 m->hwvol_mixer = dev;
869 snd_mtxunlock(m->lock);
874 mixer_hwvol_init(device_t dev)
879 pdev = mixer_get_devt(dev);
882 m->hwvol_mixer = SOUND_MIXER_VOLUME;
884 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
885 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
886 OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, "");
887 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
888 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
889 OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
890 sysctl_hw_snd_hwvol_mixer, "A", "");
895 mixer_hwvol_mute_locked(struct snd_mixer *m)
897 if (m->hwvol_muted) {
899 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
902 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
903 mixer_set(m, m->hwvol_mixer, 0);
908 mixer_hwvol_mute(device_t dev)
913 pdev = mixer_get_devt(dev);
915 snd_mtxlock(m->lock);
916 mixer_hwvol_mute_locked(m);
917 snd_mtxunlock(m->lock);
921 mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step)
923 int level, left, right;
925 if (m->hwvol_muted) {
927 level = m->hwvol_mute_level;
929 level = mixer_get(m, m->hwvol_mixer);
932 right = (level >> 8) & 0xff;
933 left += left_step * m->hwvol_step;
938 right += right_step * m->hwvol_step;
941 else if (right > 100)
943 mixer_set(m, m->hwvol_mixer, left | right << 8);
948 mixer_hwvol_step(device_t dev, int left_step, int right_step)
953 pdev = mixer_get_devt(dev);
955 snd_mtxlock(m->lock);
956 mixer_hwvol_step_locked(m, left_step, right_step);
957 snd_mtxunlock(m->lock);
961 mixer_busy(struct snd_mixer *m)
963 KASSERT(m != NULL, ("NULL snd_mixer"));
969 mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right)
973 KASSERT(m != NULL, ("NULL snd_mixer"));
975 snd_mtxlock(m->lock);
976 ret = mixer_set(m, dev, left | (right << 8));
977 snd_mtxunlock(m->lock);
979 return ((ret != 0) ? ENXIO : 0);
983 mix_get(struct snd_mixer *m, u_int dev)
987 KASSERT(m != NULL, ("NULL snd_mixer"));
989 snd_mtxlock(m->lock);
990 ret = mixer_get(m, dev);
991 snd_mtxunlock(m->lock);
997 mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1001 KASSERT(m != NULL, ("NULL snd_mixer"));
1003 snd_mtxlock(m->lock);
1004 ret = mixer_setrecsrc(m, src);
1005 snd_mtxunlock(m->lock);
1007 return ((ret != 0) ? ENXIO : 0);
1011 mix_getrecsrc(struct snd_mixer *m)
1015 KASSERT(m != NULL, ("NULL snd_mixer"));
1017 snd_mtxlock(m->lock);
1018 ret = mixer_getrecsrc(m);
1019 snd_mtxunlock(m->lock);
1025 mix_get_type(struct snd_mixer *m)
1027 KASSERT(m != NULL, ("NULL snd_mixer"));
1032 /* ----------------------------------------------------------------------- */
1035 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
1037 struct snddev_info *d;
1038 struct snd_mixer *m;
1041 if (i_dev == NULL || i_dev->si_drv1 == NULL)
1045 d = device_get_softc(m->dev);
1046 if (!PCM_REGISTERED(d))
1049 /* XXX Need Giant magic entry ??? */
1051 snd_mtxlock(m->lock);
1053 snd_mtxunlock(m->lock);
1059 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
1061 struct snddev_info *d;
1062 struct snd_mixer *m;
1065 if (i_dev == NULL || i_dev->si_drv1 == NULL)
1069 d = device_get_softc(m->dev);
1070 if (!PCM_REGISTERED(d))
1073 /* XXX Need Giant magic entry ??? */
1075 snd_mtxlock(m->lock);
1076 ret = (m->busy == 0) ? EBADF : 0;
1078 snd_mtxunlock(m->lock);
1084 mixer_ioctl_channel(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
1085 struct thread *td, int from)
1087 struct snddev_info *d;
1088 struct snd_mixer *m;
1089 struct pcm_channel *c, *rdch, *wrch;
1093 if (td == NULL || td->td_proc == NULL)
1097 d = device_get_softc(m->dev);
1101 case SOUND_MIXER_PCM:
1102 case SOUND_MIXER_RECLEV:
1103 case SOUND_MIXER_DEVMASK:
1104 case SOUND_MIXER_CAPS:
1105 case SOUND_MIXER_STEREODEVS:
1112 pid = td->td_proc->p_pid;
1119 * This is unfair. Imagine single proc opening multiple
1120 * instances of same direction. What we do right now
1121 * is looking for the first matching proc/pid, and just
1122 * that. Nothing more. Consider it done.
1124 * The better approach of controlling specific channel
1125 * pcm or rec volume is by doing mixer ioctl
1126 * (SNDCTL_DSP_[SET|GET][PLAY|REC]VOL / SOUND_MIXER_[PCM|RECLEV]
1127 * on its open fd, rather than cracky mixer bypassing here.
1129 CHN_FOREACH(c, d, channels.pcm.opened) {
1131 if (c->pid != pid ||
1132 !(c->feederflags & (1 << FEEDER_VOLUME))) {
1136 if (rdch == NULL && c->direction == PCMDIR_REC) {
1138 if (j == SOUND_MIXER_RECLEV)
1139 goto mixer_ioctl_channel_proc;
1140 } else if (wrch == NULL && c->direction == PCMDIR_PLAY) {
1142 if (j == SOUND_MIXER_PCM)
1143 goto mixer_ioctl_channel_proc;
1146 if (rdch != NULL && wrch != NULL)
1150 if (rdch == NULL && wrch == NULL)
1153 if ((j == SOUND_MIXER_DEVMASK || j == SOUND_MIXER_CAPS ||
1154 j == SOUND_MIXER_STEREODEVS) &&
1155 (cmd & ~0xff) == MIXER_READ(0)) {
1156 snd_mtxlock(m->lock);
1157 *(int *)arg = mix_getdevs(m);
1158 snd_mtxunlock(m->lock);
1160 *(int *)arg |= SOUND_MASK_RECLEV;
1162 *(int *)arg |= SOUND_MASK_PCM;
1168 mixer_ioctl_channel_proc:
1170 KASSERT(c != NULL, ("%s(): NULL channel", __func__));
1173 if ((cmd & ~0xff) == MIXER_WRITE(0)) {
1174 int left, right, center;
1176 left = *(int *)arg & 0x7f;
1177 right = (*(int *)arg >> 8) & 0x7f;
1178 center = (left + right) >> 1;
1179 chn_setvolume_multi(c, SND_VOL_C_PCM, left, right, center);
1180 } else if ((cmd & ~0xff) == MIXER_READ(0)) {
1181 *(int *)arg = CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FL);
1183 CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FR) << 8;
1192 mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
1195 struct snddev_info *d;
1198 if (i_dev == NULL || i_dev->si_drv1 == NULL)
1201 d = device_get_softc(((struct snd_mixer *)i_dev->si_drv1)->dev);
1202 if (!PCM_REGISTERED(d))
1206 PCM_ACQUIRE_QUICK(d);
1210 if (mixer_bypass != 0 && (d->flags & SD_F_VPC))
1211 ret = mixer_ioctl_channel(i_dev, cmd, arg, mode, td,
1215 ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td,
1218 PCM_RELEASE_QUICK(d);
1225 mixer_mixerinfo(struct snd_mixer *m, mixer_info *mi)
1227 bzero((void *)mi, sizeof(*mi));
1228 strlcpy(mi->id, m->name, sizeof(mi->id));
1229 strlcpy(mi->name, device_get_desc(m->dev), sizeof(mi->name));
1230 mi->modify_counter = m->modify_counter;
1234 * XXX Make sure you can guarantee concurrency safety before calling this
1235 * function, be it through Giant, PCM_*, etc !
1238 mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
1239 struct thread *td, int from)
1241 struct snd_mixer *m;
1242 int ret = EINVAL, *arg_i = (int *)arg;
1243 int v = -1, j = cmd & 0xff;
1246 * Certain ioctls may be made on any type of device (audio, mixer,
1247 * and MIDI). Handle those special cases here.
1249 if (IOCGROUP(cmd) == 'X') {
1251 case SNDCTL_SYSINFO:
1252 sound_oss_sysinfo((oss_sysinfo *)arg);
1254 case SNDCTL_CARDINFO:
1255 return (sound_oss_card_info((oss_card_info *)arg));
1256 case SNDCTL_AUDIOINFO:
1257 case SNDCTL_AUDIOINFO_EX:
1258 case SNDCTL_ENGINEINFO:
1259 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg));
1260 case SNDCTL_MIXERINFO:
1261 return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg));
1271 snd_mtxlock(m->lock);
1272 if (from == MIXER_CMD_CDEV && !m->busy) {
1273 snd_mtxunlock(m->lock);
1277 case SNDCTL_DSP_GET_RECSRC_NAMES:
1278 bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo));
1281 case SNDCTL_DSP_GET_RECSRC:
1282 ret = mixer_get_recroute(m, arg_i);
1284 case SNDCTL_DSP_SET_RECSRC:
1285 ret = mixer_set_recroute(m, *arg_i);
1287 case OSS_GETVERSION:
1288 *arg_i = SOUND_VERSION;
1291 case SOUND_MIXER_INFO:
1292 mixer_mixerinfo(m, (mixer_info *)arg);
1296 if ((cmd & ~0xff) == MIXER_WRITE(0)) {
1297 if (j == SOUND_MIXER_RECSRC)
1298 ret = mixer_setrecsrc(m, *arg_i);
1300 ret = mixer_set(m, j, *arg_i);
1301 snd_mtxunlock(m->lock);
1302 return ((ret == 0) ? 0 : ENXIO);
1304 if ((cmd & ~0xff) == MIXER_READ(0)) {
1306 case SOUND_MIXER_DEVMASK:
1307 case SOUND_MIXER_CAPS:
1308 case SOUND_MIXER_STEREODEVS:
1311 case SOUND_MIXER_RECMASK:
1312 v = mix_getrecdevs(m);
1314 case SOUND_MIXER_RECSRC:
1315 v = mixer_getrecsrc(m);
1318 v = mixer_get(m, j);
1321 snd_mtxunlock(m->lock);
1322 return ((v != -1) ? 0 : ENXIO);
1325 snd_mtxunlock(m->lock);
1330 mixer_clone(void *arg,
1332 char *name, int namelen, struct cdev **dev)
1334 struct snddev_info *d;
1338 if (strcmp(name, "mixer") == 0) {
1339 d = devclass_get_softc(pcm_devclass, snd_unit);
1340 if (PCM_REGISTERED(d) && d->mixer_dev != NULL) {
1341 *dev = d->mixer_dev;
1348 mixer_sysinit(void *p)
1350 if (mixer_ehtag != NULL)
1352 mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
1356 mixer_sysuninit(void *p)
1358 if (mixer_ehtag == NULL)
1360 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
1364 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
1365 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
1368 * @brief Handler for SNDCTL_MIXERINFO
1370 * This function searches for a mixer based on the numeric ID stored
1371 * in oss_miserinfo::dev. If set to -1, then information about the
1372 * current mixer handling the request is provided. Note, however, that
1373 * this ioctl may be made with any sound device (audio, mixer, midi).
1375 * @note Caller must not hold any PCM device, channel, or mixer locks.
1377 * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for
1380 * @param i_dev character device on which the ioctl arrived
1381 * @param arg user argument (oss_mixerinfo *)
1383 * @retval EINVAL oss_mixerinfo::dev specified a bad value
1387 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
1389 struct snddev_info *d;
1390 struct snd_mixer *m;
1394 * If probing the device handling the ioctl, make sure it's a mixer
1395 * device. (This ioctl is valid on audio, mixer, and midi devices.)
1397 if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw)
1405 * There's a 1:1 relationship between mixers and PCM devices, so
1406 * begin by iterating over PCM devices and search for our mixer.
1408 for (i = 0; pcm_devclass != NULL &&
1409 i < devclass_get_maxunit(pcm_devclass); i++) {
1410 d = devclass_get_softc(pcm_devclass, i);
1411 if (!PCM_REGISTERED(d))
1414 /* XXX Need Giant magic entry */
1416 /* See the note in function docblock. */
1417 PCM_UNLOCKASSERT(d);
1420 if (d->mixer_dev != NULL && d->mixer_dev->si_drv1 != NULL &&
1421 ((mi->dev == -1 && d->mixer_dev == i_dev) ||
1423 m = d->mixer_dev->si_drv1;
1427 * At this point, the following synchronization stuff
1429 * - a specific PCM device is locked.
1430 * - a specific mixer device has been locked, so be
1431 * sure to unlock when existing.
1433 bzero((void *)mi, sizeof(*mi));
1435 snprintf(mi->id, sizeof(mi->id), "mixer%d", i);
1436 strlcpy(mi->name, m->name, sizeof(mi->name));
1437 mi->modify_counter = m->modify_counter;
1438 mi->card_number = i;
1440 * Currently, FreeBSD assumes 1:1 relationship between
1441 * a pcm and mixer devices, so this is hardcoded to 0.
1443 mi->port_number = 0;
1446 * @todo Fill in @sa oss_mixerinfo::mixerhandle.
1447 * @note From 4Front: "mixerhandle is an arbitrary
1448 * string that identifies the mixer better than
1449 * the device number (mixerinfo.dev). Device
1450 * numbers may change depending on the order the
1451 * drivers are loaded. However the handle should
1452 * remain the same provided that the sound card
1453 * is not moved to another PCI slot."
1458 * @sa oss_mixerinfo::magic is a reserved field.
1461 * From 4Front: "magic is usually 0. However some
1462 * devices may have dedicated setup utilities and the
1463 * magic field may contain an unique driver specific
1464 * value (managed by [4Front])."
1467 mi->enabled = device_is_attached(m->dev) ? 1 : 0;
1469 * The only flag for @sa oss_mixerinfo::caps is
1470 * currently MIXER_CAP_VIRTUAL, which I'm not sure we
1471 * really worry about.
1474 * Mixer extensions currently aren't supported, so
1475 * leave @sa oss_mixerinfo::nrext blank for now.
1478 * @todo Fill in @sa oss_mixerinfo::priority (requires
1479 * touching drivers?)
1480 * @note The priority field is for mixer applets to
1481 * determine which mixer should be the default, with 0
1482 * being least preferred and 10 being most preferred.
1483 * From 4Front: "OSS drivers like ICH use higher
1484 * values (10) because such chips are known to be used
1485 * only on motherboards. Drivers for high end pro
1486 * devices use 0 because they will never be the
1487 * default mixer. Other devices use values 1 to 9
1488 * depending on the estimated probability of being the
1491 * XXX Described by Hannu@4Front, but not found in
1493 strlcpy(mi->devnode, devtoname(d->mixer_dev),
1494 sizeof(mi->devnode));
1495 mi->legacy_device = i;
1497 mtx_unlock(m->lock);
1511 * Allow the sound driver to use the mixer lock to protect its mixer
1515 mixer_get_lock(struct snd_mixer *m)
1517 if (m->lock == NULL) {
1524 mix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright)
1528 level = mixer_get(m, dev);
1530 *pright = *pleft = -1;
1534 *pleft = level & 0xFF;
1535 *pright = (level >> 8) & 0xFF;
1541 mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right)
1545 level = (left & 0xFF) | ((right & 0xFF) << 8);
1547 return (mixer_set(m, dev, level));