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