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