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