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