1139749Simp/*-
2193640Sariff * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3193640Sariff * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
4193640Sariff * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
550724Scg * All rights reserved.
650724Scg *
750724Scg * Redistribution and use in source and binary forms, with or without
850724Scg * modification, are permitted provided that the following conditions
950724Scg * are met:
1050724Scg * 1. Redistributions of source code must retain the above copyright
1150724Scg *    notice, this list of conditions and the following disclaimer.
1250724Scg * 2. Redistributions in binary form must reproduce the above copyright
1350724Scg *    notice, this list of conditions and the following disclaimer in the
1450724Scg *    documentation and/or other materials provided with the distribution.
1550724Scg *
1650724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1750724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1850724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1950724Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2050724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2150724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2250724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2350724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2450724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2550724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2650724Scg * SUCH DAMAGE.
2750724Scg */
2850724Scg
29193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
30193640Sariff#include "opt_snd.h"
31193640Sariff#endif
32193640Sariff
3353465Scg#include <dev/sound/pcm/sound.h>
3450724Scg
35193640Sariff#include "feeder_if.h"
3670134Scg#include "mixer_if.h"
3770134Scg
3882180ScgSND_DECLARE_FILE("$FreeBSD: stable/10/sys/dev/sound/pcm/mixer.c 359887 2020-04-13 16:32:18Z hselasky $");
3982180Scg
40227293Sedstatic MALLOC_DEFINE(M_MIXER, "mixer", "mixer");
4170134Scg
42193640Sariffstatic int mixer_bypass = 1;
43193640SariffTUNABLE_INT("hw.snd.vpc_mixer_bypass", &mixer_bypass);
44193640SariffSYSCTL_INT(_hw_snd, OID_AUTO, vpc_mixer_bypass, CTLFLAG_RW,
45193640Sariff    &mixer_bypass, 0,
46193640Sariff    "control channel pcm/rec volume, bypassing real mixer device");
47193640Sariff
4874763Scg#define MIXER_NAMELEN	16
4974763Scgstruct snd_mixer {
5074763Scg	KOBJ_FIELDS;
5174763Scg	void *devinfo;
52168264Sariff	int busy;
5374763Scg	int hwvol_muted;
5474763Scg	int hwvol_mixer;
5574763Scg	int hwvol_step;
56170815Sariff	int type;
57150825Snetchild	device_t dev;
5874763Scg	u_int32_t hwvol_mute_level;
5974763Scg	u_int32_t devs;
6074763Scg	u_int32_t recdevs;
6174763Scg	u_int32_t recsrc;
6274763Scg	u_int16_t level[32];
63162828Sariff	u_int8_t parent[32];
64162738Sariff	u_int32_t child[32];
65162828Sariff	u_int8_t realdev[32];
6674763Scg	char name[MIXER_NAMELEN];
67107285Scg	struct mtx *lock;
68162588Snetchild	oss_mixer_enuminfo enuminfo;
69162588Snetchild	/**
70162588Snetchild	 * Counter is incremented when applications change any of this
71162588Snetchild	 * mixer's controls.  A change in value indicates that persistent
72162588Snetchild	 * mixer applications should update their displays.
73162588Snetchild	 */
74162588Snetchild	int modify_counter;
7574763Scg};
7674763Scg
7750724Scgstatic u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
7850724Scg	[SOUND_MIXER_VOLUME]	= 75,
7950724Scg	[SOUND_MIXER_BASS]	= 50,
8050724Scg	[SOUND_MIXER_TREBLE]	= 50,
8162947Stanimura	[SOUND_MIXER_SYNTH]	= 75,
8250724Scg	[SOUND_MIXER_PCM]	= 75,
8350724Scg	[SOUND_MIXER_SPEAKER]	= 75,
8450724Scg	[SOUND_MIXER_LINE]	= 75,
85359884Shselasky	[SOUND_MIXER_MIC] 	= 25,
8650724Scg	[SOUND_MIXER_CD]	= 75,
87152422Sariff	[SOUND_MIXER_IGAIN]	= 0,
8850724Scg	[SOUND_MIXER_LINE1]	= 75,
8950724Scg	[SOUND_MIXER_VIDEO]	= 75,
90202166Smav	[SOUND_MIXER_RECLEV]	= 75,
9153203Scg	[SOUND_MIXER_OGAIN]	= 50,
9279044Scg	[SOUND_MIXER_MONITOR]	= 75,
9350724Scg};
9450724Scg
9570680Sjhbstatic char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
9670680Sjhb
9778362Scgstatic d_open_t mixer_open;
9878362Scgstatic d_close_t mixer_close;
99170815Sariffstatic d_ioctl_t mixer_ioctl;
10078362Scg
10178362Scgstatic struct cdevsw mixer_cdevsw = {
102126080Sphk	.d_version =	D_VERSION,
103111815Sphk	.d_open =	mixer_open,
104111815Sphk	.d_close =	mixer_close,
105111815Sphk	.d_ioctl =	mixer_ioctl,
106111815Sphk	.d_name =	"mixer",
10778362Scg};
10878362Scg
109162588Snetchild/**
110162588Snetchild * Keeps a count of mixer devices; used only by OSSv4 SNDCTL_SYSINFO ioctl.
111162588Snetchild */
112162588Snetchildint mixer_count = 0;
113162588Snetchild
114170161Sariffstatic eventhandler_tag mixer_ehtag = NULL;
11578362Scg
116130585Sphkstatic struct cdev *
11778362Scgmixer_get_devt(device_t dev)
11878362Scg{
119124617Sphk	struct snddev_info *snddev;
12078362Scg
121124617Sphk	snddev = device_get_softc(dev);
12278362Scg
123124617Sphk	return snddev->mixer_dev;
12478362Scg}
12578362Scg
12665390Speterstatic int
12770680Sjhbmixer_lookup(char *devname)
12870680Sjhb{
12970680Sjhb	int i;
13070680Sjhb
13170680Sjhb	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
13270680Sjhb		if (strncmp(devname, snd_mixernames[i],
13370680Sjhb		    strlen(snd_mixernames[i])) == 0)
13470680Sjhb			return i;
13570680Sjhb	return -1;
13670680Sjhb}
13770680Sjhb
138170815Sariff#define MIXER_SET_UNLOCK(x, y)		do {				\
139170815Sariff	if ((y) != 0)							\
140170815Sariff		snd_mtxunlock((x)->lock);				\
141193640Sariff} while (0)
142170815Sariff
143170815Sariff#define MIXER_SET_LOCK(x, y)		do {				\
144170815Sariff	if ((y) != 0)							\
145170815Sariff		snd_mtxlock((x)->lock);					\
146193640Sariff} while (0)
147170815Sariff
14870680Sjhbstatic int
149170815Sariffmixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d,
150193640Sariff    u_int left, u_int right)
15165390Speter{
152170161Sariff	struct pcm_channel *c;
153170815Sariff	int dropmtx, acquiremtx;
154162738Sariff
155358879Shselasky	if (PCM_DETACHING(d) || !PCM_REGISTERED(d))
156170815Sariff		return (EINVAL);
157170161Sariff
158170815Sariff	if (mtx_owned(m->lock))
159170815Sariff		dropmtx = 1;
160170815Sariff	else
161170815Sariff		dropmtx = 0;
162170815Sariff
163170815Sariff	if (!(d->flags & SD_F_MPSAFE) || mtx_owned(d->lock) != 0)
164170815Sariff		acquiremtx = 0;
165170815Sariff	else
166170815Sariff		acquiremtx = 1;
167170815Sariff
168170815Sariff	/*
169170815Sariff	 * Be careful here. If we're coming from cdev ioctl, it is OK to
170170815Sariff	 * not doing locking AT ALL (except on individual channel) since
171170815Sariff	 * we've been heavily guarded by pcm cv, or if we're still
172170815Sariff	 * under Giant influence. Since we also have mix_* calls, we cannot
173170815Sariff	 * assume such protection and just do the lock as usuall.
174170815Sariff	 */
175170815Sariff	MIXER_SET_UNLOCK(m, dropmtx);
176170815Sariff	MIXER_SET_LOCK(d, acquiremtx);
177170815Sariff
178193640Sariff	CHN_FOREACH(c, d, channels.pcm.busy) {
179193640Sariff		CHN_LOCK(c);
180193640Sariff		if (c->direction == PCMDIR_PLAY &&
181193640Sariff		    (c->feederflags & (1 << FEEDER_VOLUME)))
182193640Sariff			chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right,
183193640Sariff			    (left + right) >> 1);
184193640Sariff		CHN_UNLOCK(c);
185162738Sariff	}
186170161Sariff
187170815Sariff	MIXER_SET_UNLOCK(d, acquiremtx);
188170815Sariff	MIXER_SET_LOCK(m, dropmtx);
189170161Sariff
190170815Sariff	return (0);
191162738Sariff}
192162738Sariff
193162738Sariffstatic int
194193640Sariffmixer_set_eq(struct snd_mixer *m, struct snddev_info *d,
195193640Sariff    u_int dev, u_int level)
196162738Sariff{
197193640Sariff	struct pcm_channel *c;
198193640Sariff	struct pcm_feeder *f;
199193640Sariff	int tone, dropmtx, acquiremtx;
200193640Sariff
201193640Sariff	if (dev == SOUND_MIXER_TREBLE)
202193640Sariff		tone = FEEDEQ_TREBLE;
203193640Sariff	else if (dev == SOUND_MIXER_BASS)
204193640Sariff		tone = FEEDEQ_BASS;
205193640Sariff	else
206193640Sariff		return (EINVAL);
207193640Sariff
208358879Shselasky	if (PCM_DETACHING(d) || !PCM_REGISTERED(d))
209193640Sariff		return (EINVAL);
210193640Sariff
211193640Sariff	if (mtx_owned(m->lock))
212193640Sariff		dropmtx = 1;
213193640Sariff	else
214193640Sariff		dropmtx = 0;
215193640Sariff
216193640Sariff	if (!(d->flags & SD_F_MPSAFE) || mtx_owned(d->lock) != 0)
217193640Sariff		acquiremtx = 0;
218193640Sariff	else
219193640Sariff		acquiremtx = 1;
220193640Sariff
221193640Sariff	/*
222193640Sariff	 * Be careful here. If we're coming from cdev ioctl, it is OK to
223193640Sariff	 * not doing locking AT ALL (except on individual channel) since
224193640Sariff	 * we've been heavily guarded by pcm cv, or if we're still
225193640Sariff	 * under Giant influence. Since we also have mix_* calls, we cannot
226193640Sariff	 * assume such protection and just do the lock as usuall.
227193640Sariff	 */
228193640Sariff	MIXER_SET_UNLOCK(m, dropmtx);
229193640Sariff	MIXER_SET_LOCK(d, acquiremtx);
230193640Sariff
231193640Sariff	CHN_FOREACH(c, d, channels.pcm.busy) {
232193640Sariff		CHN_LOCK(c);
233193640Sariff		f = chn_findfeeder(c, FEEDER_EQ);
234193640Sariff		if (f != NULL)
235193640Sariff			(void)FEEDER_SET(f, tone, level);
236193640Sariff		CHN_UNLOCK(c);
237193640Sariff	}
238193640Sariff
239193640Sariff	MIXER_SET_UNLOCK(d, acquiremtx);
240193640Sariff	MIXER_SET_LOCK(m, dropmtx);
241193640Sariff
242193640Sariff	return (0);
243193640Sariff}
244193640Sariff
245193640Sariffstatic int
246193640Sariffmixer_set(struct snd_mixer *m, u_int dev, u_int lev)
247193640Sariff{
248150825Snetchild	struct snddev_info *d;
249193640Sariff	u_int l, r, tl, tr;
250162738Sariff	u_int32_t parent = SOUND_MIXER_NONE, child = 0;
251162738Sariff	u_int32_t realdev;
252170815Sariff	int i, dropmtx;
25370134Scg
254162738Sariff	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
255162738Sariff	    (0 == (m->devs & (1 << dev))))
25670134Scg		return -1;
25770134Scg
25870134Scg	l = min((lev & 0x00ff), 100);
25970134Scg	r = min(((lev & 0xff00) >> 8), 100);
260162738Sariff	realdev = m->realdev[dev];
26170134Scg
262162738Sariff	d = device_get_softc(m->dev);
263162738Sariff	if (d == NULL)
264162738Sariff		return -1;
26570134Scg
266170815Sariff	/* It is safe to drop this mutex due to Giant. */
267170815Sariff	if (!(d->flags & SD_F_MPSAFE) && mtx_owned(m->lock) != 0)
268170815Sariff		dropmtx = 1;
269170815Sariff	else
270170815Sariff		dropmtx = 0;
271170815Sariff
272170815Sariff	MIXER_SET_UNLOCK(m, dropmtx);
273170815Sariff
274162738Sariff	/* TODO: recursive handling */
275162738Sariff	parent = m->parent[dev];
276162738Sariff	if (parent >= SOUND_MIXER_NRDEVICES)
277162738Sariff		parent = SOUND_MIXER_NONE;
278162738Sariff	if (parent == SOUND_MIXER_NONE)
279162738Sariff		child = m->child[dev];
280162738Sariff
281162738Sariff	if (parent != SOUND_MIXER_NONE) {
282162738Sariff		tl = (l * (m->level[parent] & 0x00ff)) / 100;
283162738Sariff		tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
284162738Sariff		if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
285170815Sariff			(void)mixer_set_softpcmvol(m, d, tl, tr);
286162738Sariff		else if (realdev != SOUND_MIXER_NONE &&
287170815Sariff		    MIXER_SET(m, realdev, tl, tr) < 0) {
288170815Sariff			MIXER_SET_LOCK(m, dropmtx);
289162738Sariff			return -1;
290170815Sariff		}
291162738Sariff	} else if (child != 0) {
292162738Sariff		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
293162738Sariff			if (!(child & (1 << i)) || m->parent[i] != dev)
294162738Sariff				continue;
295162738Sariff			realdev = m->realdev[i];
296162738Sariff			tl = (l * (m->level[i] & 0x00ff)) / 100;
297162738Sariff			tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
298193640Sariff			if (i == SOUND_MIXER_PCM &&
299193640Sariff			    (d->flags & SD_F_SOFTPCMVOL))
300170815Sariff				(void)mixer_set_softpcmvol(m, d, tl, tr);
301162738Sariff			else if (realdev != SOUND_MIXER_NONE)
302162738Sariff				MIXER_SET(m, realdev, tl, tr);
303150825Snetchild		}
304162738Sariff		realdev = m->realdev[dev];
305162738Sariff		if (realdev != SOUND_MIXER_NONE &&
306170815Sariff		    MIXER_SET(m, realdev, l, r) < 0) {
307170815Sariff				MIXER_SET_LOCK(m, dropmtx);
308162738Sariff				return -1;
309170815Sariff		}
310150825Snetchild	} else {
311162738Sariff		if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
312170815Sariff			(void)mixer_set_softpcmvol(m, d, l, r);
313193640Sariff		else if ((dev == SOUND_MIXER_TREBLE ||
314193640Sariff		    dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ))
315193640Sariff			(void)mixer_set_eq(m, d, dev, (l + r) >> 1);
316162738Sariff		else if (realdev != SOUND_MIXER_NONE &&
317170815Sariff		    MIXER_SET(m, realdev, l, r) < 0) {
318170815Sariff			MIXER_SET_LOCK(m, dropmtx);
319150825Snetchild			return -1;
320170815Sariff		}
321150825Snetchild	}
322150825Snetchild
323193640Sariff	MIXER_SET_LOCK(m, dropmtx);
324193640Sariff
325162738Sariff	m->level[dev] = l | (r << 8);
326336890Shselasky	m->modify_counter++;
327162738Sariff
32870134Scg	return 0;
32965390Speter}
33065390Speter
33165390Speterstatic int
33274763Scgmixer_get(struct snd_mixer *mixer, int dev)
33365390Speter{
33470134Scg	if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev)))
33570134Scg		return mixer->level[dev];
336170815Sariff	else
337170815Sariff		return -1;
33865390Speter}
33965390Speter
34065390Speterstatic int
34174763Scgmixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
34265390Speter{
343170815Sariff	struct snddev_info *d;
344193640Sariff	u_int32_t recsrc;
345170815Sariff	int dropmtx;
346170815Sariff
347170815Sariff	d = device_get_softc(mixer->dev);
348170815Sariff	if (d == NULL)
349170815Sariff		return -1;
350170815Sariff	if (!(d->flags & SD_F_MPSAFE) && mtx_owned(mixer->lock) != 0)
351170815Sariff		dropmtx = 1;
352170815Sariff	else
353170815Sariff		dropmtx = 0;
35470134Scg	src &= mixer->recdevs;
35570134Scg	if (src == 0)
356202166Smav		src = mixer->recdevs & SOUND_MASK_MIC;
357202166Smav	if (src == 0)
358202166Smav		src = mixer->recdevs & SOUND_MASK_MONITOR;
359202166Smav	if (src == 0)
360202166Smav		src = mixer->recdevs & SOUND_MASK_LINE;
361202166Smav	if (src == 0 && mixer->recdevs != 0)
362202166Smav		src = (1 << (ffs(mixer->recdevs) - 1));
363170815Sariff	/* It is safe to drop this mutex due to Giant. */
364170815Sariff	MIXER_SET_UNLOCK(mixer, dropmtx);
365193640Sariff	recsrc = MIXER_SETRECSRC(mixer, src);
366170815Sariff	MIXER_SET_LOCK(mixer, dropmtx);
367193640Sariff
368193640Sariff	mixer->recsrc = recsrc;
369193640Sariff
37065390Speter	return 0;
37165390Speter}
37265390Speter
37365390Speterstatic int
37474763Scgmixer_getrecsrc(struct snd_mixer *mixer)
37565390Speter{
37670134Scg	return mixer->recsrc;
37765390Speter}
37865390Speter
379162588Snetchild/**
380162588Snetchild * @brief Retrieve the route number of the current recording device
381162588Snetchild *
382162588Snetchild * OSSv4 assigns routing numbers to recording devices, unlike the previous
383162588Snetchild * API which relied on a fixed table of device numbers and names.  This
384162588Snetchild * function returns the routing number of the device currently selected
385162588Snetchild * for recording.
386162588Snetchild *
387162588Snetchild * For now, this function is kind of a goofy compatibility stub atop the
388162588Snetchild * existing sound system.  (For example, in theory, the old sound system
389162588Snetchild * allows multiple recording devices to be specified via a bitmask.)
390162588Snetchild *
391162588Snetchild * @param m	mixer context container thing
392162588Snetchild *
393162588Snetchild * @retval 0		success
394162588Snetchild * @retval EIDRM	no recording device found (generally not possible)
395162588Snetchild * @todo Ask about error code
396162588Snetchild */
397162588Snetchildstatic int
398162588Snetchildmixer_get_recroute(struct snd_mixer *m, int *route)
399162588Snetchild{
400162588Snetchild	int i, cnt;
401162588Snetchild
402162588Snetchild	cnt = 0;
403162588Snetchild
404162588Snetchild	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
405162588Snetchild		/** @todo can user set a multi-device mask? (== or &?) */
406162588Snetchild		if ((1 << i) == m->recsrc)
407162588Snetchild			break;
408162588Snetchild		if ((1 << i) & m->recdevs)
409162588Snetchild			++cnt;
410162588Snetchild	}
411162588Snetchild
412162588Snetchild	if (i == SOUND_MIXER_NRDEVICES)
413162588Snetchild		return EIDRM;
414162588Snetchild
415162588Snetchild	*route = cnt;
416162588Snetchild	return 0;
417162588Snetchild}
418162588Snetchild
419162588Snetchild/**
420162588Snetchild * @brief Select a device for recording
421162588Snetchild *
422162588Snetchild * This function sets a recording source based on a recording device's
423162588Snetchild * routing number.  Said number is translated to an old school recdev
424162588Snetchild * mask and passed over mixer_setrecsrc.
425162588Snetchild *
426162588Snetchild * @param m	mixer context container thing
427162588Snetchild *
428162588Snetchild * @retval 0		success(?)
429162588Snetchild * @retval EINVAL	User specified an invalid device number
430162588Snetchild * @retval otherwise	error from mixer_setrecsrc
431162588Snetchild */
432162588Snetchildstatic int
433162588Snetchildmixer_set_recroute(struct snd_mixer *m, int route)
434162588Snetchild{
435162588Snetchild	int i, cnt, ret;
436162588Snetchild
437162588Snetchild	ret = 0;
438162588Snetchild	cnt = 0;
439162588Snetchild
440162588Snetchild	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
441162588Snetchild		if ((1 << i) & m->recdevs) {
442162588Snetchild			if (route == cnt)
443162588Snetchild				break;
444162588Snetchild			++cnt;
445162588Snetchild		}
446162588Snetchild	}
447162588Snetchild
448162588Snetchild	if (i == SOUND_MIXER_NRDEVICES)
449162588Snetchild		ret = EINVAL;
450162588Snetchild	else
451162588Snetchild		ret = mixer_setrecsrc(m, (1 << i));
452162588Snetchild
453162588Snetchild	return ret;
454162588Snetchild}
455162588Snetchild
45670134Scgvoid
45774763Scgmix_setdevs(struct snd_mixer *m, u_int32_t v)
45870134Scg{
459162791Sariff	struct snddev_info *d;
460162738Sariff	int i;
461162738Sariff
462162738Sariff	if (m == NULL)
463162738Sariff		return;
464162791Sariff
465162791Sariff	d = device_get_softc(m->dev);
466162738Sariff	if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
467150825Snetchild		v |= SOUND_MASK_PCM;
468193640Sariff	if (d != NULL && (d->flags & SD_F_EQ))
469193640Sariff		v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS;
470162738Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
471162738Sariff		if (m->parent[i] < SOUND_MIXER_NRDEVICES)
472162738Sariff			v |= 1 << m->parent[i];
473162738Sariff		v |= m->child[i];
474162738Sariff	}
47570134Scg	m->devs = v;
47670134Scg}
47770134Scg
478162588Snetchild/**
479162588Snetchild * @brief Record mask of available recording devices
480162588Snetchild *
481162588Snetchild * Calling functions are responsible for defining the mask of available
482162588Snetchild * recording devices.  This function records that value in a structure
483162588Snetchild * used by the rest of the mixer code.
484162588Snetchild *
485162588Snetchild * This function also populates a structure used by the SNDCTL_DSP_*RECSRC*
486162588Snetchild * family of ioctls that are part of OSSV4.  All recording device labels
487162588Snetchild * are concatenated in ascending order corresponding to their routing
488162588Snetchild * numbers.  (Ex:  a system might have 0 => 'vol', 1 => 'cd', 2 => 'line',
489162588Snetchild * etc.)  For now, these labels are just the standard recording device
490162588Snetchild * names (cd, line1, etc.), but will eventually be fully dynamic and user
491162588Snetchild * controlled.
492162588Snetchild *
493162588Snetchild * @param m	mixer device context container thing
494162588Snetchild * @param v	mask of recording devices
495162588Snetchild */
49670134Scgvoid
49774763Scgmix_setrecdevs(struct snd_mixer *m, u_int32_t v)
49870134Scg{
499162588Snetchild	oss_mixer_enuminfo *ei;
500162588Snetchild	char *loc;
501162588Snetchild	int i, nvalues, nwrote, nleft, ncopied;
502162588Snetchild
503162588Snetchild	ei = &m->enuminfo;
504162588Snetchild
505162588Snetchild	nvalues = 0;
506162588Snetchild	nwrote = 0;
507162588Snetchild	nleft = sizeof(ei->strings);
508162588Snetchild	loc = ei->strings;
509162588Snetchild
510162588Snetchild	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
511162588Snetchild		if ((1 << i) & v) {
512162588Snetchild			ei->strindex[nvalues] = nwrote;
513162588Snetchild			ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1;
514162588Snetchild			    /* strlcpy retval doesn't include terminator */
515162588Snetchild
516162588Snetchild			nwrote += ncopied;
517162588Snetchild			nleft -= ncopied;
518162588Snetchild			nvalues++;
519162588Snetchild
520162588Snetchild			/*
521162588Snetchild			 * XXX I don't think this should ever be possible.
522162588Snetchild			 * Even with a move to dynamic device/channel names,
523162588Snetchild			 * each label is limited to ~16 characters, so that'd
524162588Snetchild			 * take a LOT to fill this buffer.
525162588Snetchild			 */
526162588Snetchild			if ((nleft <= 0) || (nvalues >= OSS_ENUM_MAXVALUE)) {
527162588Snetchild				device_printf(m->dev,
528162588Snetchild				    "mix_setrecdevs:  Not enough room to store device names--please file a bug report.\n");
529162588Snetchild				device_printf(m->dev,
530162588Snetchild				    "mix_setrecdevs:  Please include details about your sound hardware, OS version, etc.\n");
531162588Snetchild				break;
532162588Snetchild			}
533162588Snetchild
534162588Snetchild			loc = &ei->strings[nwrote];
535162588Snetchild		}
536162588Snetchild	}
537162588Snetchild
538162588Snetchild	/*
539162588Snetchild	 * NB:	The SNDCTL_DSP_GET_RECSRC_NAMES ioctl ignores the dev
540162588Snetchild	 * 	and ctrl fields.
541162588Snetchild	 */
542162588Snetchild	ei->nvalues = nvalues;
54370134Scg	m->recdevs = v;
54470134Scg}
54570134Scg
546162738Sariffvoid
547162738Sariffmix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs)
548162738Sariff{
549162738Sariff	u_int32_t mask = 0;
550162738Sariff	int i;
551162738Sariff
552162738Sariff	if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
553162738Sariff		return;
554162738Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
555162738Sariff		if (i == parent)
556162738Sariff			continue;
557162738Sariff		if (childs & (1 << i)) {
558162738Sariff			mask |= 1 << i;
559162738Sariff			if (m->parent[i] < SOUND_MIXER_NRDEVICES)
560162738Sariff				m->child[m->parent[i]] &= ~(1 << i);
561162738Sariff			m->parent[i] = parent;
562162738Sariff			m->child[i] = 0;
563162738Sariff		}
564162738Sariff	}
565162738Sariff	mask &= ~(1 << parent);
566162738Sariff	m->child[parent] = mask;
567162738Sariff}
568162738Sariff
569162738Sariffvoid
570162738Sariffmix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev)
571162738Sariff{
572162738Sariff	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
573162738Sariff	    !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
574162738Sariff		return;
575162738Sariff	m->realdev[dev] = realdev;
576162738Sariff}
577162738Sariff
57870134Scgu_int32_t
579162738Sariffmix_getparent(struct snd_mixer *m, u_int32_t dev)
580162738Sariff{
581162738Sariff	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
582162738Sariff		return SOUND_MIXER_NONE;
583162738Sariff	return m->parent[dev];
584162738Sariff}
585162738Sariff
586162738Sariffu_int32_t
587162738Sariffmix_getchild(struct snd_mixer *m, u_int32_t dev)
588162738Sariff{
589162738Sariff	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
590162738Sariff		return 0;
591162738Sariff	return m->child[dev];
592162738Sariff}
593162738Sariff
594162738Sariffu_int32_t
59574763Scgmix_getdevs(struct snd_mixer *m)
59670134Scg{
59770134Scg	return m->devs;
59870134Scg}
59970134Scg
60070134Scgu_int32_t
60174763Scgmix_getrecdevs(struct snd_mixer *m)
60270134Scg{
60370134Scg	return m->recdevs;
60470134Scg}
60570134Scg
60670134Scgvoid *
60774763Scgmix_getdevinfo(struct snd_mixer *m)
60870134Scg{
60970134Scg	return m->devinfo;
61070134Scg}
61170134Scg
612170815Sariffstatic struct snd_mixer *
613170815Sariffmixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo,
614170815Sariff    int type, const char *desc)
61570134Scg{
61674763Scg	struct snd_mixer *m;
617170815Sariff	int i;
61870134Scg
619170815Sariff	KASSERT(dev != NULL && cls != NULL && devinfo != NULL,
620170815Sariff	    ("%s(): NULL data dev=%p cls=%p devinfo=%p",
621170815Sariff	    __func__, dev, cls, devinfo));
622170815Sariff	KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY,
623170815Sariff	    ("invalid mixer type=%d", type));
624170815Sariff
625111119Simp	m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
626170815Sariff	snprintf(m->name, sizeof(m->name), "%s:mixer",
627170815Sariff	    device_get_nameunit(dev));
628170815Sariff	if (desc != NULL) {
629170815Sariff		strlcat(m->name, ":", sizeof(m->name));
630170815Sariff		strlcat(m->name, desc, sizeof(m->name));
631170815Sariff	}
632170815Sariff	m->lock = snd_mtxcreate(m->name, (type == MIXER_TYPE_PRIMARY) ?
633170815Sariff	    "primary pcm mixer" : "secondary pcm mixer");
634170815Sariff	m->type = type;
63570134Scg	m->devinfo = devinfo;
63678362Scg	m->busy = 0;
637150825Snetchild	m->dev = dev;
638170815Sariff	for (i = 0; i < (sizeof(m->parent) / sizeof(m->parent[0])); i++) {
639162738Sariff		m->parent[i] = SOUND_MIXER_NONE;
640162738Sariff		m->child[i] = 0;
641162738Sariff		m->realdev[i] = i;
642162738Sariff	}
64370134Scg
644170815Sariff	if (MIXER_INIT(m)) {
645170815Sariff		snd_mtxlock(m->lock);
646170815Sariff		snd_mtxfree(m->lock);
647170815Sariff		kobj_delete((kobj_t)m, M_MIXER);
648170815Sariff		return (NULL);
649170815Sariff	}
65070134Scg
651170815Sariff	return (m);
652170815Sariff}
653170815Sariff
654170815Sariffint
655170815Sariffmixer_delete(struct snd_mixer *m)
656170815Sariff{
657170815Sariff	KASSERT(m != NULL, ("NULL snd_mixer"));
658170815Sariff	KASSERT(m->type == MIXER_TYPE_SECONDARY,
659170815Sariff	    ("%s(): illegal mixer type=%d", __func__, m->type));
660170815Sariff
661184610Salfred	/* mixer uninit can sleep --hps */
662170815Sariff
663170815Sariff	MIXER_UNINIT(m);
664170815Sariff
665170815Sariff	snd_mtxfree(m->lock);
666170815Sariff	kobj_delete((kobj_t)m, M_MIXER);
667170815Sariff
668170815Sariff	--mixer_count;
669170815Sariff
670170815Sariff	return (0);
671170815Sariff}
672170815Sariff
673170815Sariffstruct snd_mixer *
674170815Sariffmixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc)
675170815Sariff{
676170815Sariff	struct snd_mixer *m;
677170815Sariff
678170815Sariff	m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_SECONDARY, desc);
679170815Sariff
680170815Sariff	if (m != NULL)
681170815Sariff		++mixer_count;
682170815Sariff
683170815Sariff	return (m);
684170815Sariff}
685170815Sariff
686170815Sariffint
687170815Sariffmixer_init(device_t dev, kobj_class_t cls, void *devinfo)
688170815Sariff{
689170815Sariff	struct snddev_info *snddev;
690170815Sariff	struct snd_mixer *m;
691170815Sariff	u_int16_t v;
692170815Sariff	struct cdev *pdev;
693170815Sariff	int i, unit, devunit, val;
694170815Sariff
695193640Sariff	snddev = device_get_softc(dev);
696193640Sariff	if (snddev == NULL)
697193640Sariff		return (-1);
698193640Sariff
699193640Sariff	if (resource_int_value(device_get_name(dev),
700193640Sariff	    device_get_unit(dev), "eq", &val) == 0 && val != 0) {
701193640Sariff		snddev->flags |= SD_F_EQ;
702193640Sariff		if ((val & SD_F_EQ_MASK) == val)
703193640Sariff			snddev->flags |= val;
704193640Sariff		else
705193640Sariff			snddev->flags |= SD_F_EQ_DEFAULT;
706193640Sariff		snddev->eqpreamp = 0;
707193640Sariff	}
708193640Sariff
709170815Sariff	m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL);
710170815Sariff	if (m == NULL)
711170815Sariff		return (-1);
712170815Sariff
71370134Scg	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
714131105Sjosef		v = snd_mixerdefaults[i];
715131105Sjosef
716131064Sjosef		if (resource_int_value(device_get_name(dev),
717131064Sjosef		    device_get_unit(dev), snd_mixernames[i], &val) == 0) {
718131064Sjosef			if (val >= 0 && val <= 100) {
719131064Sjosef				v = (u_int16_t) val;
720131064Sjosef			}
721131064Sjosef		}
722130792Sjosef
72370134Scg		mixer_set(m, i, v | (v << 8));
72470134Scg	}
72570134Scg
726202166Smav	mixer_setrecsrc(m, 0); /* Set default input. */
72770134Scg
72878362Scg	unit = device_get_unit(dev);
729170161Sariff	devunit = snd_mkunit(unit, SND_DEV_CTL, 0);
730193640Sariff	pdev = make_dev(&mixer_cdevsw, PCMMINOR(devunit),
73178362Scg		 UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
73278362Scg	pdev->si_drv1 = m;
733124617Sphk	snddev->mixer_dev = pdev;
73470134Scg
735162588Snetchild	++mixer_count;
736162588Snetchild
737162738Sariff	if (bootverbose) {
738162738Sariff		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
739162738Sariff			if (!(m->devs & (1 << i)))
740162738Sariff				continue;
741162738Sariff			if (m->realdev[i] != i) {
742162738Sariff				device_printf(dev, "Mixer \"%s\" -> \"%s\":",
743162738Sariff				    snd_mixernames[i],
744162738Sariff				    (m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
745162738Sariff				    snd_mixernames[m->realdev[i]] : "none");
746162738Sariff			} else {
747162738Sariff				device_printf(dev, "Mixer \"%s\":",
748162738Sariff				    snd_mixernames[i]);
749162738Sariff			}
750162738Sariff			if (m->parent[i] < SOUND_MIXER_NRDEVICES)
751162738Sariff				printf(" parent=\"%s\"",
752162738Sariff				    snd_mixernames[m->parent[i]]);
753162738Sariff			if (m->child[i] != 0)
754162738Sariff				printf(" child=0x%08x", m->child[i]);
755162738Sariff			printf("\n");
756162738Sariff		}
757162738Sariff		if (snddev->flags & SD_F_SOFTPCMVOL)
758162738Sariff			device_printf(dev, "Soft PCM mixer ENABLED\n");
759193640Sariff		if (snddev->flags & SD_F_EQ)
760193640Sariff			device_printf(dev, "EQ Treble/Bass ENABLED\n");
761162738Sariff	}
762162738Sariff
763170815Sariff	return (0);
76470134Scg}
76570134Scg
76670134Scgint
76765340Scgmixer_uninit(device_t dev)
76858383Scg{
76958383Scg	int i;
770156929Sariff	struct snddev_info *d;
77174763Scg	struct snd_mixer *m;
772130585Sphk	struct cdev *pdev;
77370134Scg
774156929Sariff	d = device_get_softc(dev);
77578362Scg	pdev = mixer_get_devt(dev);
776156929Sariff	if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL)
777156929Sariff		return EBADF;
778170815Sariff
77978362Scg	m = pdev->si_drv1;
780170815Sariff	KASSERT(m != NULL, ("NULL snd_mixer"));
781170815Sariff	KASSERT(m->type == MIXER_TYPE_PRIMARY,
782170815Sariff	    ("%s(): illegal mixer type=%d", __func__, m->type));
783170815Sariff
78474763Scg	snd_mtxlock(m->lock);
78570134Scg
78678362Scg	if (m->busy) {
78778362Scg		snd_mtxunlock(m->lock);
78878362Scg		return EBUSY;
78978362Scg	}
79078362Scg
791184610Salfred	/* destroy dev can sleep --hps */
792184610Salfred
793184610Salfred	snd_mtxunlock(m->lock);
794184610Salfred
79578362Scg	pdev->si_drv1 = NULL;
79678362Scg	destroy_dev(pdev);
79778362Scg
798184610Salfred	snd_mtxlock(m->lock);
799184610Salfred
80065340Scg	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
80170134Scg		mixer_set(m, i, 0);
80270134Scg
80370134Scg	mixer_setrecsrc(m, SOUND_MASK_MIC);
80470134Scg
805184610Salfred	snd_mtxunlock(m->lock);
806184610Salfred
807184610Salfred	/* mixer uninit can sleep --hps */
808184610Salfred
80970134Scg	MIXER_UNINIT(m);
81070134Scg
81174763Scg	snd_mtxfree(m->lock);
81270134Scg	kobj_delete((kobj_t)m, M_MIXER);
81370134Scg
814156929Sariff	d->mixer_dev = NULL;
815156929Sariff
816162588Snetchild	--mixer_count;
817162588Snetchild
81865340Scg	return 0;
81965340Scg}
82065340Scg
82165340Scgint
82265340Scgmixer_reinit(device_t dev)
82365340Scg{
82478362Scg	struct snd_mixer *m;
825130585Sphk	struct cdev *pdev;
82665340Scg	int i;
82767652Scg
82878362Scg	pdev = mixer_get_devt(dev);
82978362Scg	m = pdev->si_drv1;
83074763Scg	snd_mtxlock(m->lock);
83170134Scg
83270134Scg	i = MIXER_REINIT(m);
83374763Scg	if (i) {
83474763Scg		snd_mtxunlock(m->lock);
83567652Scg		return i;
83674763Scg	}
83770134Scg
83867652Scg	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
83970134Scg		mixer_set(m, i, m->level[i]);
84070134Scg
84170134Scg	mixer_setrecsrc(m, m->recsrc);
84274763Scg	snd_mtxunlock(m->lock);
84370134Scg
84467652Scg	return 0;
84558383Scg}
84658383Scg
84770680Sjhbstatic int
84870680Sjhbsysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
84970680Sjhb{
85070680Sjhb	char devname[32];
85170680Sjhb	int error, dev;
85274763Scg	struct snd_mixer *m;
85370618Sjhb
85470680Sjhb	m = oidp->oid_arg1;
85574763Scg	snd_mtxlock(m->lock);
856164614Sariff	strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
857100654Sgreen	snd_mtxunlock(m->lock);
85870680Sjhb	error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
859100654Sgreen	snd_mtxlock(m->lock);
86070680Sjhb	if (error == 0 && req->newptr != NULL) {
86170680Sjhb		dev = mixer_lookup(devname);
86274763Scg		if (dev == -1) {
86374763Scg			snd_mtxunlock(m->lock);
86470680Sjhb			return EINVAL;
86574763Scg		}
86670944Sjhb		else if (dev != m->hwvol_mixer) {
86770680Sjhb			m->hwvol_mixer = dev;
86870944Sjhb			m->hwvol_muted = 0;
86970944Sjhb		}
87070680Sjhb	}
87174763Scg	snd_mtxunlock(m->lock);
87270680Sjhb	return error;
87370680Sjhb}
87470618Sjhb
87570680Sjhbint
87670944Sjhbmixer_hwvol_init(device_t dev)
87770680Sjhb{
87874763Scg	struct snd_mixer *m;
879130585Sphk	struct cdev *pdev;
88070680Sjhb
88178362Scg	pdev = mixer_get_devt(dev);
88278362Scg	m = pdev->si_drv1;
88378362Scg
88470680Sjhb	m->hwvol_mixer = SOUND_MIXER_VOLUME;
88570680Sjhb	m->hwvol_step = 5;
886164614Sariff	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
887164614Sariff	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
88870680Sjhb            OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, "");
889164614Sariff	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
890164614Sariff	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
89170680Sjhb            OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
892100071Smarkm	    sysctl_hw_snd_hwvol_mixer, "A", "");
89370680Sjhb	return 0;
89470680Sjhb}
89570680Sjhb
89670618Sjhbvoid
897246454Shselaskymixer_hwvol_mute_locked(struct snd_mixer *m)
89870618Sjhb{
89970944Sjhb	if (m->hwvol_muted) {
90070944Sjhb		m->hwvol_muted = 0;
90170944Sjhb		mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
90270680Sjhb	} else {
90370944Sjhb		m->hwvol_muted++;
90470944Sjhb		m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
90570680Sjhb		mixer_set(m, m->hwvol_mixer, 0);
90670680Sjhb	}
90770618Sjhb}
90870618Sjhb
90970618Sjhbvoid
910246454Shselaskymixer_hwvol_mute(device_t dev)
91170618Sjhb{
91274763Scg	struct snd_mixer *m;
913130585Sphk	struct cdev *pdev;
91470618Sjhb
91578362Scg	pdev = mixer_get_devt(dev);
91678362Scg	m = pdev->si_drv1;
91774763Scg	snd_mtxlock(m->lock);
918246454Shselasky	mixer_hwvol_mute_locked(m);
919246454Shselasky	snd_mtxunlock(m->lock);
920246454Shselasky}
921246454Shselasky
922246454Shselaskyvoid
923246454Shselaskymixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step)
924246454Shselasky{
925246454Shselasky	int level, left, right;
926246454Shselasky
92770944Sjhb	if (m->hwvol_muted) {
92870944Sjhb		m->hwvol_muted = 0;
92970944Sjhb		level = m->hwvol_mute_level;
93070944Sjhb	} else
93170944Sjhb		level = mixer_get(m, m->hwvol_mixer);
93270618Sjhb	if (level != -1) {
93370618Sjhb		left = level & 0xff;
934246454Shselasky		right = (level >> 8) & 0xff;
93570680Sjhb		left += left_step * m->hwvol_step;
93670618Sjhb		if (left < 0)
93770618Sjhb			left = 0;
938246454Shselasky		else if (left > 100)
939246454Shselasky			left = 100;
94070680Sjhb		right += right_step * m->hwvol_step;
94170618Sjhb		if (right < 0)
94270618Sjhb			right = 0;
943246454Shselasky		else if (right > 100)
944246454Shselasky			right = 100;
94570680Sjhb		mixer_set(m, m->hwvol_mixer, left | right << 8);
94670618Sjhb	}
947246454Shselasky}
948246454Shselasky
949246454Shselaskyvoid
950246454Shselaskymixer_hwvol_step(device_t dev, int left_step, int right_step)
951246454Shselasky{
952246454Shselasky	struct snd_mixer *m;
953246454Shselasky	struct cdev *pdev;
954246454Shselasky
955246454Shselasky	pdev = mixer_get_devt(dev);
956246454Shselasky	m = pdev->si_drv1;
957246454Shselasky	snd_mtxlock(m->lock);
958246454Shselasky	mixer_hwvol_step_locked(m, left_step, right_step);
95974763Scg	snd_mtxunlock(m->lock);
96070618Sjhb}
96170618Sjhb
962170815Sariffint
963170815Sariffmixer_busy(struct snd_mixer *m)
964170815Sariff{
965170815Sariff	KASSERT(m != NULL, ("NULL snd_mixer"));
966170815Sariff
967170815Sariff	return (m->busy);
968170815Sariff}
969170815Sariff
970170815Sariffint
971170815Sariffmix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right)
972170815Sariff{
973170815Sariff	int ret;
974170815Sariff
975170815Sariff	KASSERT(m != NULL, ("NULL snd_mixer"));
976170815Sariff
977170815Sariff	snd_mtxlock(m->lock);
978170815Sariff	ret = mixer_set(m, dev, left | (right << 8));
979170815Sariff	snd_mtxunlock(m->lock);
980170815Sariff
981170815Sariff	return ((ret != 0) ? ENXIO : 0);
982170815Sariff}
983170815Sariff
984170815Sariffint
985170815Sariffmix_get(struct snd_mixer *m, u_int dev)
986170815Sariff{
987170815Sariff	int ret;
988170815Sariff
989170815Sariff	KASSERT(m != NULL, ("NULL snd_mixer"));
990170815Sariff
991170815Sariff	snd_mtxlock(m->lock);
992170815Sariff	ret = mixer_get(m, dev);
993170815Sariff	snd_mtxunlock(m->lock);
994170815Sariff
995170815Sariff	return (ret);
996170815Sariff}
997170815Sariff
998170815Sariffint
999170815Sariffmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1000170815Sariff{
1001170815Sariff	int ret;
1002170815Sariff
1003170815Sariff	KASSERT(m != NULL, ("NULL snd_mixer"));
1004170815Sariff
1005170815Sariff	snd_mtxlock(m->lock);
1006170815Sariff	ret = mixer_setrecsrc(m, src);
1007170815Sariff	snd_mtxunlock(m->lock);
1008170815Sariff
1009170815Sariff	return ((ret != 0) ? ENXIO : 0);
1010170815Sariff}
1011170815Sariff
1012170815Sariffu_int32_t
1013170815Sariffmix_getrecsrc(struct snd_mixer *m)
1014170815Sariff{
1015170815Sariff	u_int32_t ret;
1016170815Sariff
1017170815Sariff	KASSERT(m != NULL, ("NULL snd_mixer"));
1018170815Sariff
1019170815Sariff	snd_mtxlock(m->lock);
1020170815Sariff	ret = mixer_getrecsrc(m);
1021170815Sariff	snd_mtxunlock(m->lock);
1022170815Sariff
1023170815Sariff	return (ret);
1024170815Sariff}
1025170815Sariff
1026170815Sariffint
1027170815Sariffmix_get_type(struct snd_mixer *m)
1028170815Sariff{
1029170815Sariff	KASSERT(m != NULL, ("NULL snd_mixer"));
1030170815Sariff
1031170815Sariff	return (m->type);
1032170815Sariff}
1033170815Sariff
1034359887Shselaskydevice_t
1035359887Shselaskymix_get_dev(struct snd_mixer *m)
1036359887Shselasky{
1037359887Shselasky	KASSERT(m != NULL, ("NULL snd_mixer"));
1038359887Shselasky
1039359887Shselasky	return (m->dev);
1040359887Shselasky}
1041359887Shselasky
104278362Scg/* ----------------------------------------------------------------------- */
104350724Scg
104478362Scgstatic int
1045130585Sphkmixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
104678362Scg{
1047170815Sariff	struct snddev_info *d;
104878362Scg	struct snd_mixer *m;
104978362Scg
1050170815Sariff
1051170815Sariff	if (i_dev == NULL || i_dev->si_drv1 == NULL)
1052170815Sariff		return (EBADF);
1053170815Sariff
105482181Scg	m = i_dev->si_drv1;
1055170815Sariff	d = device_get_softc(m->dev);
1056358879Shselasky	if (PCM_DETACHING(d) || !PCM_REGISTERED(d))
1057170815Sariff		return (EBADF);
1058170815Sariff
1059170815Sariff	/* XXX Need Giant magic entry ??? */
1060170815Sariff
106182181Scg	snd_mtxlock(m->lock);
1062168247Sariff	m->busy = 1;
1063170815Sariff	snd_mtxunlock(m->lock);
106482181Scg
1065170815Sariff	return (0);
106678362Scg}
106778362Scg
106878362Scgstatic int
1069130585Sphkmixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
107078362Scg{
1071170815Sariff	struct snddev_info *d;
107278362Scg	struct snd_mixer *m;
1073170815Sariff	int ret;
107478362Scg
1075170815Sariff	if (i_dev == NULL || i_dev->si_drv1 == NULL)
1076170815Sariff		return (EBADF);
1077170815Sariff
107882181Scg	m = i_dev->si_drv1;
1079170815Sariff	d = device_get_softc(m->dev);
1080170815Sariff	if (!PCM_REGISTERED(d))
1081170815Sariff		return (EBADF);
1082170815Sariff
1083170815Sariff	/* XXX Need Giant magic entry ??? */
1084170815Sariff
108582181Scg	snd_mtxlock(m->lock);
1086170815Sariff	ret = (m->busy == 0) ? EBADF : 0;
1087168247Sariff	m->busy = 0;
1088170815Sariff	snd_mtxunlock(m->lock);
108978362Scg
1090170815Sariff	return (ret);
109178362Scg}
109278362Scg
1093170815Sariffstatic int
1094193640Sariffmixer_ioctl_channel(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
1095193640Sariff    struct thread *td, int from)
1096193640Sariff{
1097193640Sariff	struct snddev_info *d;
1098193640Sariff	struct snd_mixer *m;
1099193640Sariff	struct pcm_channel *c, *rdch, *wrch;
1100193640Sariff	pid_t pid;
1101193640Sariff	int j, ret;
1102193640Sariff
1103193640Sariff	if (td == NULL || td->td_proc == NULL)
1104193640Sariff		return (-1);
1105193640Sariff
1106193640Sariff	m = dev->si_drv1;
1107193640Sariff	d = device_get_softc(m->dev);
1108193640Sariff	j = cmd & 0xff;
1109193640Sariff
1110193640Sariff	switch (j) {
1111193640Sariff	case SOUND_MIXER_PCM:
1112193640Sariff	case SOUND_MIXER_RECLEV:
1113193640Sariff	case SOUND_MIXER_DEVMASK:
1114193640Sariff	case SOUND_MIXER_CAPS:
1115193640Sariff	case SOUND_MIXER_STEREODEVS:
1116193640Sariff		break;
1117193640Sariff	default:
1118193640Sariff		return (-1);
1119193640Sariff		break;
1120193640Sariff	}
1121193640Sariff
1122193640Sariff	pid = td->td_proc->p_pid;
1123193640Sariff	rdch = NULL;
1124193640Sariff	wrch = NULL;
1125193640Sariff	c = NULL;
1126193640Sariff	ret = -1;
1127193640Sariff
1128193640Sariff	/*
1129193640Sariff	 * This is unfair. Imagine single proc opening multiple
1130193640Sariff	 * instances of same direction. What we do right now
1131193640Sariff	 * is looking for the first matching proc/pid, and just
1132193640Sariff	 * that. Nothing more. Consider it done.
1133193640Sariff	 *
1134193640Sariff	 * The better approach of controlling specific channel
1135193640Sariff	 * pcm or rec volume is by doing mixer ioctl
1136193640Sariff	 * (SNDCTL_DSP_[SET|GET][PLAY|REC]VOL / SOUND_MIXER_[PCM|RECLEV]
1137193640Sariff	 * on its open fd, rather than cracky mixer bypassing here.
1138193640Sariff	 */
1139193640Sariff	CHN_FOREACH(c, d, channels.pcm.opened) {
1140193640Sariff		CHN_LOCK(c);
1141193640Sariff		if (c->pid != pid ||
1142193640Sariff		    !(c->feederflags & (1 << FEEDER_VOLUME))) {
1143193640Sariff			CHN_UNLOCK(c);
1144193640Sariff			continue;
1145193640Sariff		}
1146193640Sariff		if (rdch == NULL && c->direction == PCMDIR_REC) {
1147193640Sariff			rdch = c;
1148193640Sariff			if (j == SOUND_MIXER_RECLEV)
1149193640Sariff				goto mixer_ioctl_channel_proc;
1150193640Sariff		} else if (wrch == NULL && c->direction == PCMDIR_PLAY) {
1151193640Sariff			wrch = c;
1152193640Sariff			if (j == SOUND_MIXER_PCM)
1153193640Sariff				goto mixer_ioctl_channel_proc;
1154193640Sariff		}
1155193640Sariff		CHN_UNLOCK(c);
1156193640Sariff		if (rdch != NULL && wrch != NULL)
1157193640Sariff			break;
1158193640Sariff	}
1159193640Sariff
1160193640Sariff	if (rdch == NULL && wrch == NULL)
1161193640Sariff		return (-1);
1162193640Sariff
1163193640Sariff	if ((j == SOUND_MIXER_DEVMASK || j == SOUND_MIXER_CAPS ||
1164193640Sariff	    j == SOUND_MIXER_STEREODEVS) &&
1165202150Smav	    (cmd & ~0xff) == MIXER_READ(0)) {
1166193640Sariff		snd_mtxlock(m->lock);
1167193640Sariff		*(int *)arg = mix_getdevs(m);
1168193640Sariff		snd_mtxunlock(m->lock);
1169193640Sariff		if (rdch != NULL)
1170193640Sariff			*(int *)arg |= SOUND_MASK_RECLEV;
1171193640Sariff		if (wrch != NULL)
1172193640Sariff			*(int *)arg |= SOUND_MASK_PCM;
1173193640Sariff		ret = 0;
1174193640Sariff	}
1175193640Sariff
1176193640Sariff	return (ret);
1177193640Sariff
1178193640Sariffmixer_ioctl_channel_proc:
1179193640Sariff
1180193640Sariff	KASSERT(c != NULL, ("%s(): NULL channel", __func__));
1181193640Sariff	CHN_LOCKASSERT(c);
1182193640Sariff
1183202150Smav	if ((cmd & ~0xff) == MIXER_WRITE(0)) {
1184193640Sariff		int left, right, center;
1185193640Sariff
1186193640Sariff		left = *(int *)arg & 0x7f;
1187193640Sariff		right = (*(int *)arg >> 8) & 0x7f;
1188193640Sariff		center = (left + right) >> 1;
1189193640Sariff		chn_setvolume_multi(c, SND_VOL_C_PCM, left, right, center);
1190202150Smav	} else if ((cmd & ~0xff) == MIXER_READ(0)) {
1191193640Sariff		*(int *)arg = CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FL);
1192193640Sariff		*(int *)arg |=
1193193640Sariff		    CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FR) << 8;
1194193640Sariff	}
1195193640Sariff
1196193640Sariff	CHN_UNLOCK(c);
1197193640Sariff
1198193640Sariff	return (0);
1199193640Sariff}
1200193640Sariff
1201193640Sariffstatic int
1202170815Sariffmixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
1203170815Sariff    struct thread *td)
1204170815Sariff{
1205170815Sariff	struct snddev_info *d;
1206170815Sariff	int ret;
1207170815Sariff
1208170815Sariff	if (i_dev == NULL || i_dev->si_drv1 == NULL)
1209170815Sariff		return (EBADF);
1210170815Sariff
1211170815Sariff	d = device_get_softc(((struct snd_mixer *)i_dev->si_drv1)->dev);
1212358879Shselasky	if (PCM_DETACHING(d) || !PCM_REGISTERED(d))
1213170815Sariff		return (EBADF);
1214170815Sariff
1215170815Sariff	PCM_GIANT_ENTER(d);
1216170815Sariff	PCM_ACQUIRE_QUICK(d);
1217170815Sariff
1218193640Sariff	ret = -1;
1219170815Sariff
1220193640Sariff	if (mixer_bypass != 0 && (d->flags & SD_F_VPC))
1221193640Sariff		ret = mixer_ioctl_channel(i_dev, cmd, arg, mode, td,
1222193640Sariff		    MIXER_CMD_CDEV);
1223193640Sariff
1224193640Sariff	if (ret == -1)
1225193640Sariff		ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td,
1226193640Sariff		    MIXER_CMD_CDEV);
1227193640Sariff
1228170815Sariff	PCM_RELEASE_QUICK(d);
1229170815Sariff	PCM_GIANT_LEAVE(d);
1230170815Sariff
1231170815Sariff	return (ret);
1232170815Sariff}
1233170815Sariff
1234271193Smavstatic void
1235271193Smavmixer_mixerinfo(struct snd_mixer *m, mixer_info *mi)
1236271193Smav{
1237271193Smav	bzero((void *)mi, sizeof(*mi));
1238271193Smav	strlcpy(mi->id, m->name, sizeof(mi->id));
1239271193Smav	strlcpy(mi->name, device_get_desc(m->dev), sizeof(mi->name));
1240271193Smav	mi->modify_counter = m->modify_counter;
1241271193Smav}
1242271193Smav
1243170815Sariff/*
1244170815Sariff * XXX Make sure you can guarantee concurrency safety before calling this
1245193640Sariff *     function, be it through Giant, PCM_*, etc !
1246170815Sariff */
124778362Scgint
1248170815Sariffmixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
1249170815Sariff    struct thread *td, int from)
125078362Scg{
125178670Scg	struct snd_mixer *m;
1252202150Smav	int ret = EINVAL, *arg_i = (int *)arg;
125378362Scg	int v = -1, j = cmd & 0xff;
125478362Scg
1255187030Smav	/*
1256187030Smav	 * Certain ioctls may be made on any type of device (audio, mixer,
1257187030Smav	 * and MIDI).  Handle those special cases here.
1258187030Smav	 */
1259187030Smav	if (IOCGROUP(cmd) == 'X') {
1260187030Smav		switch (cmd) {
1261187030Smav		case SNDCTL_SYSINFO:
1262187030Smav			sound_oss_sysinfo((oss_sysinfo *)arg);
1263187030Smav			return (0);
1264187030Smav		case SNDCTL_CARDINFO:
1265187030Smav			return (sound_oss_card_info((oss_card_info *)arg));
1266187030Smav	    	case SNDCTL_AUDIOINFO:
1267187030Smav	    	case SNDCTL_AUDIOINFO_EX:
1268187030Smav	    	case SNDCTL_ENGINEINFO:
1269187030Smav			return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg));
1270187030Smav		case SNDCTL_MIXERINFO:
1271187030Smav			return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg));
1272187030Smav		}
1273187036Smav		return (EINVAL);
1274187030Smav	}
1275187030Smav
127678362Scg	m = i_dev->si_drv1;
1277156929Sariff
1278156929Sariff	if (m == NULL)
1279170815Sariff		return (EBADF);
128078362Scg
128178362Scg	snd_mtxlock(m->lock);
1282170815Sariff	if (from == MIXER_CMD_CDEV && !m->busy) {
1283156929Sariff		snd_mtxunlock(m->lock);
1284170815Sariff		return (EBADF);
1285156929Sariff	}
1286202150Smav	switch (cmd) {
1287202150Smav	case SNDCTL_DSP_GET_RECSRC_NAMES:
1288202150Smav		bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo));
1289202150Smav		ret = 0;
1290202150Smav		goto done;
1291202150Smav	case SNDCTL_DSP_GET_RECSRC:
1292202150Smav		ret = mixer_get_recroute(m, arg_i);
1293202150Smav		goto done;
1294202150Smav	case SNDCTL_DSP_SET_RECSRC:
1295202150Smav		ret = mixer_set_recroute(m, *arg_i);
1296202150Smav		goto done;
1297202150Smav	case OSS_GETVERSION:
1298202150Smav		*arg_i = SOUND_VERSION;
1299202150Smav		ret = 0;
1300202150Smav		goto done;
1301271193Smav	case SOUND_MIXER_INFO:
1302271193Smav		mixer_mixerinfo(m, (mixer_info *)arg);
1303271193Smav		ret = 0;
1304271193Smav		goto done;
1305202150Smav	}
1306202150Smav	if ((cmd & ~0xff) == MIXER_WRITE(0)) {
130778362Scg		if (j == SOUND_MIXER_RECSRC)
130878362Scg			ret = mixer_setrecsrc(m, *arg_i);
130978362Scg		else
131078362Scg			ret = mixer_set(m, j, *arg_i);
131178362Scg		snd_mtxunlock(m->lock);
1312170815Sariff		return ((ret == 0) ? 0 : ENXIO);
131378362Scg	}
1314202150Smav	if ((cmd & ~0xff) == MIXER_READ(0)) {
131578362Scg		switch (j) {
1316202150Smav		case SOUND_MIXER_DEVMASK:
1317202150Smav		case SOUND_MIXER_CAPS:
1318202150Smav		case SOUND_MIXER_STEREODEVS:
131978362Scg			v = mix_getdevs(m);
132078362Scg			break;
1321202150Smav		case SOUND_MIXER_RECMASK:
132278362Scg			v = mix_getrecdevs(m);
132378362Scg			break;
1324202150Smav		case SOUND_MIXER_RECSRC:
132578362Scg			v = mixer_getrecsrc(m);
132678362Scg			break;
132778362Scg		default:
132878362Scg			v = mixer_get(m, j);
132978362Scg		}
133078362Scg		*arg_i = v;
133178362Scg		snd_mtxunlock(m->lock);
1332170815Sariff		return ((v != -1) ? 0 : ENXIO);
133378362Scg	}
1334202150Smavdone:
133578362Scg	snd_mtxunlock(m->lock);
1336170815Sariff	return (ret);
133778362Scg}
133878362Scg
133978362Scgstatic void
1340170161Sariffmixer_clone(void *arg,
1341170161Sariff#if __FreeBSD_version >= 600034
1342170161Sariff    struct ucred *cred,
1343170161Sariff#endif
1344170161Sariff    char *name, int namelen, struct cdev **dev)
134578362Scg{
1346170161Sariff	struct snddev_info *d;
134778362Scg
1348130640Sphk	if (*dev != NULL)
134978362Scg		return;
135078362Scg	if (strcmp(name, "mixer") == 0) {
1351170161Sariff		d = devclass_get_softc(pcm_devclass, snd_unit);
1352170815Sariff		if (PCM_REGISTERED(d) && d->mixer_dev != NULL) {
1353170161Sariff			*dev = d->mixer_dev;
1354144389Sphk			dev_ref(*dev);
1355144389Sphk		}
135678362Scg	}
135778362Scg}
135878362Scg
135978362Scgstatic void
136078362Scgmixer_sysinit(void *p)
136178362Scg{
1362170161Sariff	if (mixer_ehtag != NULL)
1363170161Sariff		return;
136478362Scg	mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
136578362Scg}
136678362Scg
136778362Scgstatic void
136878362Scgmixer_sysuninit(void *p)
136978362Scg{
1370170161Sariff	if (mixer_ehtag == NULL)
1371170161Sariff		return;
1372170161Sariff	EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
1373170161Sariff	mixer_ehtag = NULL;
137478362Scg}
137578362Scg
137678362ScgSYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
137778362ScgSYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
137878362Scg
1379162588Snetchild/**
1380162588Snetchild * @brief Handler for SNDCTL_MIXERINFO
1381162588Snetchild *
1382162588Snetchild * This function searches for a mixer based on the numeric ID stored
1383162588Snetchild * in oss_miserinfo::dev.  If set to -1, then information about the
1384162588Snetchild * current mixer handling the request is provided.  Note, however, that
1385162588Snetchild * this ioctl may be made with any sound device (audio, mixer, midi).
1386162588Snetchild *
1387162588Snetchild * @note Caller must not hold any PCM device, channel, or mixer locks.
1388162588Snetchild *
1389162588Snetchild * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for
1390162588Snetchild * more information.
1391162588Snetchild *
1392162588Snetchild * @param i_dev	character device on which the ioctl arrived
1393162588Snetchild * @param arg	user argument (oss_mixerinfo *)
1394162588Snetchild *
1395162588Snetchild * @retval EINVAL	oss_mixerinfo::dev specified a bad value
1396162588Snetchild * @retval 0		success
1397162588Snetchild */
1398162588Snetchildint
1399162588Snetchildmixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
1400162588Snetchild{
1401162588Snetchild	struct snddev_info *d;
1402162588Snetchild	struct snd_mixer *m;
1403170815Sariff	int nmix, i;
140478362Scg
1405162588Snetchild	/*
1406162588Snetchild	 * If probing the device handling the ioctl, make sure it's a mixer
1407162588Snetchild	 * device.  (This ioctl is valid on audio, mixer, and midi devices.)
1408162588Snetchild	 */
1409170815Sariff	if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw)
1410170815Sariff		return (EINVAL);
1411162588Snetchild
1412162606Snetchild	d = NULL;
1413162588Snetchild	m = NULL;
1414162588Snetchild	nmix = 0;
1415162588Snetchild
1416162588Snetchild	/*
1417162588Snetchild	 * There's a 1:1 relationship between mixers and PCM devices, so
1418162588Snetchild	 * begin by iterating over PCM devices and search for our mixer.
1419162588Snetchild	 */
1420170235Sariff	for (i = 0; pcm_devclass != NULL &&
1421170235Sariff	    i < devclass_get_maxunit(pcm_devclass); i++) {
1422162588Snetchild		d = devclass_get_softc(pcm_devclass, i);
1423358879Shselasky		if (PCM_DETACHING(d) || !PCM_REGISTERED(d))
1424162588Snetchild			continue;
1425162588Snetchild
1426170815Sariff		/* XXX Need Giant magic entry */
1427170815Sariff
1428162588Snetchild		/* See the note in function docblock. */
1429193640Sariff		PCM_UNLOCKASSERT(d);
1430193640Sariff		PCM_LOCK(d);
1431162588Snetchild
1432170815Sariff		if (d->mixer_dev != NULL && d->mixer_dev->si_drv1 != NULL &&
1433170815Sariff		    ((mi->dev == -1 && d->mixer_dev == i_dev) ||
1434170815Sariff		    mi->dev == nmix)) {
1435170815Sariff			m = d->mixer_dev->si_drv1;
1436170815Sariff			mtx_lock(m->lock);
1437162588Snetchild
1438170815Sariff			/*
1439170815Sariff			 * At this point, the following synchronization stuff
1440170815Sariff			 * has happened:
1441170815Sariff			 * - a specific PCM device is locked.
1442170815Sariff			 * - a specific mixer device has been locked, so be
1443170815Sariff			 *   sure to unlock when existing.
1444170815Sariff			 */
1445170815Sariff			bzero((void *)mi, sizeof(*mi));
1446170815Sariff			mi->dev = nmix;
1447170815Sariff			snprintf(mi->id, sizeof(mi->id), "mixer%d", i);
1448170815Sariff			strlcpy(mi->name, m->name, sizeof(mi->name));
1449170815Sariff			mi->modify_counter = m->modify_counter;
1450170815Sariff			mi->card_number = i;
1451170815Sariff			/*
1452170815Sariff			 * Currently, FreeBSD assumes 1:1 relationship between
1453170815Sariff			 * a pcm and mixer devices, so this is hardcoded to 0.
1454170815Sariff			 */
1455170815Sariff			mi->port_number = 0;
1456162588Snetchild
1457170815Sariff			/**
1458170815Sariff			 * @todo Fill in @sa oss_mixerinfo::mixerhandle.
1459170815Sariff			 * @note From 4Front:  "mixerhandle is an arbitrary
1460170815Sariff			 *       string that identifies the mixer better than
1461170815Sariff			 *       the device number (mixerinfo.dev).  Device
1462170815Sariff			 *       numbers may change depending on the order the
1463170815Sariff			 *       drivers are loaded. However the handle should
1464170815Sariff			 *       remain the same provided that the sound card
1465170815Sariff			 *       is not moved to another PCI slot."
1466170815Sariff			 */
1467162588Snetchild
1468170815Sariff			/**
1469170815Sariff			 * @note
1470170815Sariff			 * @sa oss_mixerinfo::magic is a reserved field.
1471170815Sariff			 *
1472170815Sariff			 * @par
1473170815Sariff			 * From 4Front:  "magic is usually 0. However some
1474170815Sariff			 * devices may have dedicated setup utilities and the
1475170815Sariff			 * magic field may contain an unique driver specific
1476170815Sariff			 * value (managed by [4Front])."
1477170815Sariff			 */
1478162588Snetchild
1479170815Sariff			mi->enabled = device_is_attached(m->dev) ? 1 : 0;
1480170815Sariff			/**
1481170815Sariff			 * The only flag for @sa oss_mixerinfo::caps is
1482170815Sariff			 * currently MIXER_CAP_VIRTUAL, which I'm not sure we
1483170815Sariff			 * really worry about.
1484170815Sariff			 */
1485170815Sariff			/**
1486170815Sariff			 * Mixer extensions currently aren't supported, so
1487170815Sariff			 * leave @sa oss_mixerinfo::nrext blank for now.
1488170815Sariff			 */
1489170815Sariff			/**
1490170815Sariff			 * @todo Fill in @sa oss_mixerinfo::priority (requires
1491170815Sariff			 *       touching drivers?)
1492170815Sariff			 * @note The priority field is for mixer applets to
1493170815Sariff			 * determine which mixer should be the default, with 0
1494170815Sariff			 * being least preferred and 10 being most preferred.
1495170815Sariff			 * From 4Front:  "OSS drivers like ICH use higher
1496170815Sariff			 * values (10) because such chips are known to be used
1497170815Sariff			 * only on motherboards.  Drivers for high end pro
1498170815Sariff			 * devices use 0 because they will never be the
1499170815Sariff			 * default mixer. Other devices use values 1 to 9
1500170815Sariff			 * depending on the estimated probability of being the
1501170815Sariff			 * default device.
1502170815Sariff			 *
1503170815Sariff			 * XXX Described by Hannu@4Front, but not found in
1504170815Sariff			 *     soundcard.h.
1505231378Sed			strlcpy(mi->devnode, devtoname(d->mixer_dev),
1506170815Sariff			sizeof(mi->devnode));
1507170815Sariff			mi->legacy_device = i;
1508170815Sariff			 */
1509170815Sariff			mtx_unlock(m->lock);
1510170815Sariff		} else
1511170815Sariff			++nmix;
1512162588Snetchild
1513193640Sariff		PCM_UNLOCK(d);
1514162588Snetchild
1515170815Sariff		if (m != NULL)
1516170815Sariff			return (0);
1517170815Sariff	}
1518162588Snetchild
1519170815Sariff	return (EINVAL);
1520162588Snetchild}
1521184610Salfred
1522184610Salfred/*
1523184610Salfred * Allow the sound driver to use the mixer lock to protect its mixer
1524184610Salfred * data:
1525184610Salfred */
1526184610Salfredstruct mtx *
1527184610Salfredmixer_get_lock(struct snd_mixer *m)
1528184610Salfred{
1529184610Salfred	if (m->lock == NULL) {
1530184610Salfred		return (&Giant);
1531184610Salfred	}
1532184610Salfred	return (m->lock);
1533184610Salfred}
1534246421Shselasky
1535246421Shselaskyint
1536246421Shselaskymix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright)
1537246421Shselasky{
1538246421Shselasky	int level;
1539246421Shselasky
1540246421Shselasky	level = mixer_get(m, dev);
1541246421Shselasky	if (level < 0) {
1542246421Shselasky		*pright = *pleft = -1;
1543246421Shselasky		return (-1);
1544246421Shselasky	}
1545246421Shselasky
1546246421Shselasky	*pleft = level & 0xFF;
1547246421Shselasky	*pright = (level >> 8) & 0xFF;
1548246421Shselasky
1549246421Shselasky	return (0);
1550246421Shselasky}
1551246421Shselasky
1552246421Shselaskyint
1553246421Shselaskymix_set_locked(struct snd_mixer *m, u_int dev, int left, int right)
1554246421Shselasky{
1555246421Shselasky	int level;
1556246421Shselasky
1557246421Shselasky	level = (left & 0xFF) | ((right & 0xFF) << 8);
1558246421Shselasky
1559246421Shselasky	return (mixer_set(m, dev, level));
1560246421Shselasky}
1561