xref: /freebsd/sys/dev/sound/pcm/mixer.c (revision 47cf9dc7861371edcfdb85a38e2c240f430ccb28)
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  * Copyright (c) 2026 The FreeBSD Foundation
9  *
10  * Portions of this software were developed by Christos Margiolis
11  * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifdef HAVE_KERNEL_OPTION_HEADERS
36 #include "opt_snd.h"
37 #endif
38 
39 #include <dev/sound/pcm/sound.h>
40 
41 #include "feeder_if.h"
42 #include "mixer_if.h"
43 
44 static uint16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
45 	[SOUND_MIXER_VOLUME]	= 75,
46 	[SOUND_MIXER_BASS]	= 50,
47 	[SOUND_MIXER_TREBLE]	= 50,
48 	[SOUND_MIXER_SYNTH]	= 75,
49 	[SOUND_MIXER_PCM]	= 75,
50 	[SOUND_MIXER_SPEAKER]	= 75,
51 	[SOUND_MIXER_LINE]	= 75,
52 	[SOUND_MIXER_MIC] 	= 25,
53 	[SOUND_MIXER_CD]	= 75,
54 	[SOUND_MIXER_IGAIN]	= 0,
55 	[SOUND_MIXER_LINE1]	= 75,
56 	[SOUND_MIXER_VIDEO]	= 75,
57 	[SOUND_MIXER_RECLEV]	= 75,
58 	[SOUND_MIXER_OGAIN]	= 50,
59 	[SOUND_MIXER_MONITOR]	= 75,
60 };
61 
62 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
63 
64 static d_open_t mixer_open;
65 static d_close_t mixer_close;
66 static d_ioctl_t mixer_ioctl;
67 
68 static struct cdevsw mixer_cdevsw = {
69 	.d_version =	D_VERSION,
70 	.d_open =	mixer_open,
71 	.d_close =	mixer_close,
72 	.d_ioctl =	mixer_ioctl,
73 	.d_name =	"mixer",
74 };
75 
76 static eventhandler_tag mixer_ehtag = NULL;
77 
78 static struct snd_mixer *
mixer_get_devt(device_t dev)79 mixer_get_devt(device_t dev)
80 {
81 	struct snddev_info *snddev;
82 
83 	snddev = device_get_softc(dev);
84 
85 	return (snddev->mixer);
86 }
87 
88 static int
mixer_lookup(char * devname)89 mixer_lookup(char *devname)
90 {
91 	int i;
92 
93 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
94 		if (strncmp(devname, snd_mixernames[i],
95 		    strlen(snd_mixernames[i])) == 0)
96 			return i;
97 	return -1;
98 }
99 
100 static int
mixer_set_softpcmvol(struct snd_mixer * m,struct snddev_info * d,unsigned int left,unsigned int right)101 mixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d,
102     unsigned int left, unsigned int right)
103 {
104 	struct pcm_channel *c;
105 
106 	if (!PCM_REGISTERED(d))
107 		return (EINVAL);
108 
109 	CHN_FOREACH(c, d, channels.pcm.busy) {
110 		CHN_LOCK(c);
111 		if (c->direction == PCMDIR_PLAY &&
112 		    (c->feederflags & (1 << FEEDER_VOLUME)))
113 			chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right,
114 			    (left + right) >> 1);
115 		CHN_UNLOCK(c);
116 	}
117 
118 	return (0);
119 }
120 
121 static int
mixer_set_eq(struct snd_mixer * m,struct snddev_info * d,unsigned int dev,unsigned int level)122 mixer_set_eq(struct snd_mixer *m, struct snddev_info *d,
123     unsigned int dev, unsigned int level)
124 {
125 	struct pcm_channel *c;
126 	struct pcm_feeder *f;
127 	int tone;
128 
129 	if (dev == SOUND_MIXER_TREBLE)
130 		tone = FEEDEQ_TREBLE;
131 	else if (dev == SOUND_MIXER_BASS)
132 		tone = FEEDEQ_BASS;
133 	else
134 		return (EINVAL);
135 
136 	if (!PCM_REGISTERED(d))
137 		return (EINVAL);
138 
139 	CHN_FOREACH(c, d, channels.pcm.busy) {
140 		CHN_LOCK(c);
141 		f = feeder_find(c, FEEDER_EQ);
142 		if (f != NULL)
143 			(void)FEEDER_SET(f, tone, level);
144 		CHN_UNLOCK(c);
145 	}
146 
147 	return (0);
148 }
149 
150 static int
mixer_set(struct snd_mixer * m,unsigned int dev,uint32_t muted,unsigned int lev)151 mixer_set(struct snd_mixer *m, unsigned int dev, uint32_t muted, unsigned int lev)
152 {
153 	struct snddev_info *d;
154 	unsigned int l, r, tl, tr;
155 	uint32_t parent = SOUND_MIXER_NONE, child = 0;
156 	uint32_t realdev;
157 	int i;
158 
159 	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
160 	    (0 == (m->devs & (1 << dev))))
161 		return (EINVAL);
162 
163 	l = min((lev & 0x00ff), 100);
164 	r = min(((lev & 0xff00) >> 8), 100);
165 	realdev = m->realdev[dev];
166 
167 	d = device_get_softc(m->dev);
168 	if (d == NULL)
169 		return (ENXIO);
170 
171 	/* Allow the volume to be "changed" while muted. */
172 	if (muted & (1 << dev)) {
173 		m->level_muted[dev] = l | (r << 8);
174 		return (0);
175 	}
176 
177 	/* TODO: recursive handling */
178 	parent = m->parent[dev];
179 	if (parent >= SOUND_MIXER_NRDEVICES)
180 		parent = SOUND_MIXER_NONE;
181 	if (parent == SOUND_MIXER_NONE)
182 		child = m->child[dev];
183 
184 	if (parent != SOUND_MIXER_NONE) {
185 		tl = (l * (m->level[parent] & 0x00ff)) / 100;
186 		tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
187 		if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
188 			(void)mixer_set_softpcmvol(m, d, tl, tr);
189 		else if (realdev != SOUND_MIXER_NONE &&
190 		    MIXER_SET(m, realdev, tl, tr) < 0)
191 			return (EINVAL);
192 	} else if (child != 0) {
193 		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
194 			if (!(child & (1 << i)) || m->parent[i] != dev)
195 				continue;
196 			realdev = m->realdev[i];
197 			tl = (l * (m->level[i] & 0x00ff)) / 100;
198 			tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
199 			if (i == SOUND_MIXER_PCM &&
200 			    (d->flags & SD_F_SOFTPCMVOL))
201 				(void)mixer_set_softpcmvol(m, d, tl, tr);
202 			else if (realdev != SOUND_MIXER_NONE)
203 				MIXER_SET(m, realdev, tl, tr);
204 		}
205 		realdev = m->realdev[dev];
206 		if (realdev != SOUND_MIXER_NONE &&
207 		    MIXER_SET(m, realdev, l, r) < 0)
208 			return (EINVAL);
209 	} else {
210 		if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
211 			(void)mixer_set_softpcmvol(m, d, l, r);
212 		else if ((dev == SOUND_MIXER_TREBLE ||
213 		    dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ))
214 			(void)mixer_set_eq(m, d, dev, (l + r) >> 1);
215 		else if (realdev != SOUND_MIXER_NONE &&
216 		    MIXER_SET(m, realdev, l, r) < 0)
217 			return (EINVAL);
218 	}
219 
220 	m->level[dev] = l | (r << 8);
221 	m->modify_counter++;
222 
223 	return (0);
224 }
225 
226 static int
mixer_get(struct snd_mixer * mixer,int dev)227 mixer_get(struct snd_mixer *mixer, int dev)
228 {
229 	if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) {
230 		if (mixer->mutedevs & (1 << dev))
231 			return (mixer->level_muted[dev]);
232 		else
233 			return (mixer->level[dev]);
234 	} else {
235 		return (-1);
236 	}
237 }
238 
239 void
mix_setmutedevs(struct snd_mixer * mixer,uint32_t mutedevs)240 mix_setmutedevs(struct snd_mixer *mixer, uint32_t mutedevs)
241 {
242 	uint32_t delta;
243 
244 	/* Filter out invalid values. */
245 	mutedevs &= mixer->devs;
246 	delta = (mixer->mutedevs ^ mutedevs) & mixer->devs;
247 	mixer->mutedevs = mutedevs;
248 
249 	for (int i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
250 		if (!(delta & (1 << i)))
251 			continue;
252 		if (mutedevs & (1 << i)) {
253 			mixer->level_muted[i] = mixer->level[i];
254 			mixer_set(mixer, i, 0, 0);
255 		} else {
256 			mixer_set(mixer, i, 0, mixer->level_muted[i]);
257 		}
258 	}
259 }
260 
261 static int
mixer_setrecsrc(struct snd_mixer * mixer,uint32_t src)262 mixer_setrecsrc(struct snd_mixer *mixer, uint32_t src)
263 {
264 	struct snddev_info *d;
265 	uint32_t recsrc;
266 
267 	d = device_get_softc(mixer->dev);
268 	if (d == NULL)
269 		return (ENXIO);
270 	src &= mixer->recdevs;
271 	if (src == 0)
272 		src = mixer->recdevs & SOUND_MASK_MIC;
273 	if (src == 0)
274 		src = mixer->recdevs & SOUND_MASK_MONITOR;
275 	if (src == 0)
276 		src = mixer->recdevs & SOUND_MASK_LINE;
277 	if (src == 0 && mixer->recdevs != 0)
278 		src = (1 << (ffs(mixer->recdevs) - 1));
279 	recsrc = MIXER_SETRECSRC(mixer, src);
280 
281 	mixer->recsrc = recsrc;
282 
283 	return (0);
284 }
285 
286 static int
mixer_getrecsrc(struct snd_mixer * mixer)287 mixer_getrecsrc(struct snd_mixer *mixer)
288 {
289 	return mixer->recsrc;
290 }
291 
292 /**
293  * @brief Retrieve the route number of the current recording device
294  *
295  * OSSv4 assigns routing numbers to recording devices, unlike the previous
296  * API which relied on a fixed table of device numbers and names.  This
297  * function returns the routing number of the device currently selected
298  * for recording.
299  *
300  * For now, this function is kind of a goofy compatibility stub atop the
301  * existing sound system.  (For example, in theory, the old sound system
302  * allows multiple recording devices to be specified via a bitmask.)
303  *
304  * @param m	mixer context container thing
305  *
306  * @retval 0		success
307  * @retval EIDRM	no recording device found (generally not possible)
308  * @todo Ask about error code
309  */
310 static int
mixer_get_recroute(struct snd_mixer * m,int * route)311 mixer_get_recroute(struct snd_mixer *m, int *route)
312 {
313 	int i, cnt;
314 
315 	cnt = 0;
316 
317 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
318 		/** @todo can user set a multi-device mask? (== or &?) */
319 		if ((1 << i) == m->recsrc)
320 			break;
321 		if ((1 << i) & m->recdevs)
322 			++cnt;
323 	}
324 
325 	if (i == SOUND_MIXER_NRDEVICES)
326 		return EIDRM;
327 
328 	*route = cnt;
329 	return 0;
330 }
331 
332 /**
333  * @brief Select a device for recording
334  *
335  * This function sets a recording source based on a recording device's
336  * routing number.  Said number is translated to an old school recdev
337  * mask and passed over mixer_setrecsrc.
338  *
339  * @param m	mixer context container thing
340  *
341  * @retval 0		success(?)
342  * @retval EINVAL	User specified an invalid device number
343  * @retval otherwise	error from mixer_setrecsrc
344  */
345 static int
mixer_set_recroute(struct snd_mixer * m,int route)346 mixer_set_recroute(struct snd_mixer *m, int route)
347 {
348 	int i, cnt, ret;
349 
350 	ret = 0;
351 	cnt = 0;
352 
353 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
354 		if ((1 << i) & m->recdevs) {
355 			if (route == cnt)
356 				break;
357 			++cnt;
358 		}
359 	}
360 
361 	if (i == SOUND_MIXER_NRDEVICES)
362 		ret = EINVAL;
363 	else
364 		ret = mixer_setrecsrc(m, (1 << i));
365 
366 	return ret;
367 }
368 
369 void
mix_setdevs(struct snd_mixer * m,uint32_t v)370 mix_setdevs(struct snd_mixer *m, uint32_t v)
371 {
372 	struct snddev_info *d;
373 	int i;
374 
375 	if (m == NULL)
376 		return;
377 
378 	d = device_get_softc(m->dev);
379 	if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
380 		v |= SOUND_MASK_PCM;
381 	v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS;
382 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
383 		if (m->parent[i] < SOUND_MIXER_NRDEVICES)
384 			v |= 1 << m->parent[i];
385 		v |= m->child[i];
386 	}
387 	m->devs = v;
388 }
389 
390 /**
391  * @brief Record mask of available recording devices
392  *
393  * Calling functions are responsible for defining the mask of available
394  * recording devices.  This function records that value in a structure
395  * used by the rest of the mixer code.
396  *
397  * @param m	mixer device context container thing
398  * @param v	mask of recording devices
399  */
400 void
mix_setrecdevs(struct snd_mixer * m,uint32_t v)401 mix_setrecdevs(struct snd_mixer *m, uint32_t v)
402 {
403 	m->recdevs = v;
404 }
405 
406 void
mix_setparentchild(struct snd_mixer * m,uint32_t parent,uint32_t childs)407 mix_setparentchild(struct snd_mixer *m, uint32_t parent, uint32_t childs)
408 {
409 	uint32_t mask = 0;
410 	int i;
411 
412 	if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
413 		return;
414 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
415 		if (i == parent)
416 			continue;
417 		if (childs & (1 << i)) {
418 			mask |= 1 << i;
419 			if (m->parent[i] < SOUND_MIXER_NRDEVICES)
420 				m->child[m->parent[i]] &= ~(1 << i);
421 			m->parent[i] = parent;
422 			m->child[i] = 0;
423 		}
424 	}
425 	mask &= ~(1 << parent);
426 	m->child[parent] = mask;
427 }
428 
429 void
mix_setrealdev(struct snd_mixer * m,uint32_t dev,uint32_t realdev)430 mix_setrealdev(struct snd_mixer *m, uint32_t dev, uint32_t realdev)
431 {
432 	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
433 	    !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
434 		return;
435 	m->realdev[dev] = realdev;
436 }
437 
438 uint32_t
mix_getparent(struct snd_mixer * m,uint32_t dev)439 mix_getparent(struct snd_mixer *m, uint32_t dev)
440 {
441 	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
442 		return SOUND_MIXER_NONE;
443 	return m->parent[dev];
444 }
445 
446 uint32_t
mix_getdevs(struct snd_mixer * m)447 mix_getdevs(struct snd_mixer *m)
448 {
449 	return m->devs;
450 }
451 
452 uint32_t
mix_getmutedevs(struct snd_mixer * m)453 mix_getmutedevs(struct snd_mixer *m)
454 {
455 	return m->mutedevs;
456 }
457 
458 uint32_t
mix_getrecdevs(struct snd_mixer * m)459 mix_getrecdevs(struct snd_mixer *m)
460 {
461 	return m->recdevs;
462 }
463 
464 void *
mix_getdevinfo(struct snd_mixer * m)465 mix_getdevinfo(struct snd_mixer *m)
466 {
467 	return m->devinfo;
468 }
469 
470 static struct snd_mixer *
mixer_obj_create(device_t dev,kobj_class_t cls,void * devinfo,int type,const char * desc)471 mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo,
472     int type, const char *desc)
473 {
474 	struct snddev_info *d;
475 	struct snd_mixer *m;
476 	size_t i;
477 
478 	KASSERT(dev != NULL && cls != NULL && devinfo != NULL,
479 	    ("%s(): NULL data dev=%p cls=%p devinfo=%p",
480 	    __func__, dev, cls, devinfo));
481 	KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY,
482 	    ("invalid mixer type=%d", type));
483 
484 	m = (struct snd_mixer *)kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO);
485 	snprintf(m->name, sizeof(m->name), "%s:mixer",
486 	    device_get_nameunit(dev));
487 	if (desc != NULL) {
488 		strlcat(m->name, ":", sizeof(m->name));
489 		strlcat(m->name, desc, sizeof(m->name));
490 	}
491 
492 	d = device_get_softc(dev);
493 	if (type == MIXER_TYPE_PRIMARY)
494 		m->lock = &d->lock;
495 	else {
496 		mtx_init(&m->priv_lock, m->name, "secondary pcm mixer", MTX_DEF);
497 		m->lock = &m->priv_lock;
498 	}
499 	m->type = type;
500 	m->devinfo = devinfo;
501 	m->dev = dev;
502 	for (i = 0; i < nitems(m->parent); i++) {
503 		m->parent[i] = SOUND_MIXER_NONE;
504 		m->child[i] = 0;
505 		m->realdev[i] = i;
506 	}
507 
508 	if (MIXER_INIT(m)) {
509 		if (type == MIXER_TYPE_SECONDARY)
510 			mtx_destroy(m->lock);
511 		kobj_delete((kobj_t)m, M_DEVBUF);
512 		return (NULL);
513 	}
514 
515 	return (m);
516 }
517 
518 int
mixer_delete(struct snd_mixer * m)519 mixer_delete(struct snd_mixer *m)
520 {
521 	KASSERT(m != NULL, ("NULL snd_mixer"));
522 
523 	/* mixer uninit can sleep --hps */
524 
525 	MIXER_UNINIT(m);
526 
527 	if (m->type == MIXER_TYPE_SECONDARY)
528 		mtx_destroy(m->lock);
529 	kobj_delete((kobj_t)m, M_DEVBUF);
530 
531 	return (0);
532 }
533 
534 struct snd_mixer *
mixer_create(device_t dev,kobj_class_t cls,void * devinfo,const char * desc)535 mixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc)
536 {
537 	return (mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_SECONDARY, desc));
538 }
539 
540 int
mixer_init(device_t dev,kobj_class_t cls,void * devinfo)541 mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
542 {
543 	struct snddev_info *snddev;
544 	struct snd_mixer *m;
545 	uint16_t v;
546 	const char *name;
547 	int i, unit, val;
548 
549 	snddev = device_get_softc(dev);
550 	if (snddev == NULL)
551 		return (-1);
552 
553 	name = device_get_name(dev);
554 	unit = device_get_unit(dev);
555 
556 	m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL);
557 	if (m == NULL)
558 		return (-1);
559 
560 	/* There is no need to lock here, but do it for consistency. */
561 	mtx_lock(m->lock);
562 
563 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
564 		v = snd_mixerdefaults[i];
565 
566 		if (resource_int_value(name, unit, snd_mixernames[i],
567 		    &val) == 0) {
568 			if (val >= 0 && val <= 100) {
569 				v = (uint16_t) val;
570 			}
571 		}
572 
573 		mixer_set(m, i, 0, v | (v << 8));
574 	}
575 
576 	mixer_setrecsrc(m, 0); /* Set default input. */
577 
578 	mtx_unlock(m->lock);
579 
580 	snddev->mixer = m;
581 
582 	if (bootverbose) {
583 		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
584 			if (!(m->devs & (1 << i)))
585 				continue;
586 			if (m->realdev[i] != i) {
587 				device_printf(dev, "Mixer \"%s\" -> \"%s\":",
588 				    snd_mixernames[i],
589 				    (m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
590 				    snd_mixernames[m->realdev[i]] : "none");
591 			} else {
592 				device_printf(dev, "Mixer \"%s\":",
593 				    snd_mixernames[i]);
594 			}
595 			if (m->parent[i] < SOUND_MIXER_NRDEVICES)
596 				printf(" parent=\"%s\"",
597 				    snd_mixernames[m->parent[i]]);
598 			if (m->child[i] != 0)
599 				printf(" child=0x%08x", m->child[i]);
600 			printf("\n");
601 		}
602 		if (snddev->flags & SD_F_SOFTPCMVOL)
603 			device_printf(dev, "Soft PCM mixer ENABLED\n");
604 		device_printf(dev, "EQ Treble/Bass ENABLED\n");
605 	}
606 
607 	return (0);
608 }
609 
610 int
mixer_uninit(device_t dev)611 mixer_uninit(device_t dev)
612 {
613 	int i;
614 	struct snd_mixer *m;
615 
616 	m = mixer_get_devt(dev);
617 
618 	KASSERT(m != NULL, ("NULL snd_mixer"));
619 	KASSERT(m->type == MIXER_TYPE_PRIMARY,
620 	    ("%s(): illegal mixer type=%d", __func__, m->type));
621 
622 	/*
623 	 * snd_uaudio(4) in particular can call mixer_uninit() directly if
624 	 * attach failed prior to pcm_register(), in which case the cdev will
625 	 * not have been created. Do not call destroy_dev() unconditionally.
626 	 */
627 	if (MIXER_REGISTERED(m))
628 		destroy_dev(m->cdev);
629 
630 	mtx_lock(m->lock);
631 
632 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
633 		mixer_set(m, i, 0, 0);
634 
635 	mtx_unlock(m->lock);
636 
637 	/* mixer uninit can sleep --hps */
638 
639 	mixer_delete(m);
640 
641 	return 0;
642 }
643 
644 int
mixer_reinit(device_t dev)645 mixer_reinit(device_t dev)
646 {
647 	struct snd_mixer *m;
648 	int i;
649 
650 	m = mixer_get_devt(dev);
651 	mtx_lock(m->lock);
652 
653 	i = MIXER_REINIT(m);
654 	if (i) {
655 		mtx_unlock(m->lock);
656 		return i;
657 	}
658 
659 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
660 		if (m->mutedevs & (1 << i))
661 			mixer_set(m, i, 0, 0);
662 		else
663 			mixer_set(m, i, 0, m->level[i]);
664 	}
665 
666 	mixer_setrecsrc(m, m->recsrc);
667 	mtx_unlock(m->lock);
668 
669 	return 0;
670 }
671 
672 int
mixer_make_dev(device_t dev)673 mixer_make_dev(device_t dev)
674 {
675 	struct make_dev_args devargs;
676 	struct snddev_info *sc;
677 	int err, unit;
678 
679 	sc = device_get_softc(dev);
680 	unit = device_get_unit(dev);
681 
682 	make_dev_args_init(&devargs);
683 	devargs.mda_devsw = &mixer_cdevsw;
684 	devargs.mda_uid = UID_ROOT;
685 	devargs.mda_gid = GID_AUDIO;
686 	devargs.mda_mode = 0660;
687 	devargs.mda_si_drv1 = sc->mixer;
688 	err = make_dev_s(&devargs, &sc->mixer->cdev, "mixer%d", unit);
689 	if (err != 0) {
690 		device_printf(dev, "failed to create mixer%d: error %d\n",
691 		    unit, err);
692 		return (err);
693 	}
694 
695 	return (0);
696 }
697 
698 static int
sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)699 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
700 {
701 	char devname[32];
702 	int error, dev;
703 	struct snd_mixer *m;
704 
705 	m = oidp->oid_arg1;
706 	strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
707 	error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
708 	if (error == 0 && req->newptr != NULL) {
709 		if ((dev = mixer_lookup(devname)) == -1)
710 			return (EINVAL);
711 		mtx_lock(m->lock);
712 		m->hwvol_mixer = dev;
713 		mtx_unlock(m->lock);
714 	}
715 	return (error);
716 }
717 
718 int
mixer_hwvol_init(device_t dev)719 mixer_hwvol_init(device_t dev)
720 {
721 	struct snd_mixer *m;
722 
723 	m = mixer_get_devt(dev);
724 
725 	m->hwvol_mixer = SOUND_MIXER_VOLUME;
726 	m->hwvol_step = 5;
727 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
728 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
729             OID_AUTO, "hwvol_step", CTLFLAG_RWTUN, &m->hwvol_step, 0, "");
730 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
731 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
732 	    "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
733 	    m, 0, sysctl_hw_snd_hwvol_mixer, "A", "");
734 	return 0;
735 }
736 
737 void
mixer_hwvol_mute(device_t dev)738 mixer_hwvol_mute(device_t dev)
739 {
740 	struct snd_mixer *m;
741 
742 	m = mixer_get_devt(dev);
743 	mtx_lock(m->lock);
744 	mix_setmutedevs(m, m->mutedevs ^ (1 << m->hwvol_mixer));
745 	mtx_unlock(m->lock);
746 }
747 
748 void
mixer_hwvol_step(device_t dev,int left_step,int right_step)749 mixer_hwvol_step(device_t dev, int left_step, int right_step)
750 {
751 	struct snd_mixer *m;
752 	int level, left, right;
753 
754 	m = mixer_get_devt(dev);
755 	mtx_lock(m->lock);
756 	level = mixer_get(m, m->hwvol_mixer);
757 	if (level != -1) {
758 		left = level & 0xff;
759 		right = (level >> 8) & 0xff;
760 		left += left_step * m->hwvol_step;
761 		if (left < 0)
762 			left = 0;
763 		else if (left > 100)
764 			left = 100;
765 		right += right_step * m->hwvol_step;
766 		if (right < 0)
767 			right = 0;
768 		else if (right > 100)
769 			right = 100;
770 
771 		mixer_set(m, m->hwvol_mixer, m->mutedevs, left | right << 8);
772 	}
773 	mtx_unlock(m->lock);
774 }
775 
776 int
mix_set(struct snd_mixer * m,unsigned int dev,unsigned int left,unsigned int right)777 mix_set(struct snd_mixer *m, unsigned int dev, unsigned int left, unsigned int right)
778 {
779 	int ret;
780 
781 	KASSERT(m != NULL, ("NULL snd_mixer"));
782 
783 	mtx_lock(m->lock);
784 	ret = mixer_set(m, dev, m->mutedevs, left | (right << 8));
785 	mtx_unlock(m->lock);
786 
787 	return (ret);
788 }
789 
790 int
mix_get(struct snd_mixer * m,unsigned int dev)791 mix_get(struct snd_mixer *m, unsigned int dev)
792 {
793 	int ret;
794 
795 	KASSERT(m != NULL, ("NULL snd_mixer"));
796 
797 	mtx_lock(m->lock);
798 	ret = mixer_get(m, dev);
799 	mtx_unlock(m->lock);
800 
801 	return (ret);
802 }
803 
804 int
mix_setrecsrc(struct snd_mixer * m,uint32_t src)805 mix_setrecsrc(struct snd_mixer *m, uint32_t src)
806 {
807 	int ret;
808 
809 	KASSERT(m != NULL, ("NULL snd_mixer"));
810 
811 	mtx_lock(m->lock);
812 	ret = mixer_setrecsrc(m, src);
813 	mtx_unlock(m->lock);
814 
815 	return (ret);
816 }
817 
818 uint32_t
mix_getrecsrc(struct snd_mixer * m)819 mix_getrecsrc(struct snd_mixer *m)
820 {
821 	uint32_t ret;
822 
823 	KASSERT(m != NULL, ("NULL snd_mixer"));
824 
825 	mtx_lock(m->lock);
826 	ret = mixer_getrecsrc(m);
827 	mtx_unlock(m->lock);
828 
829 	return (ret);
830 }
831 
832 device_t
mix_get_dev(struct snd_mixer * m)833 mix_get_dev(struct snd_mixer *m)
834 {
835 	KASSERT(m != NULL, ("NULL snd_mixer"));
836 
837 	return (m->dev);
838 }
839 
840 /* ----------------------------------------------------------------------- */
841 
842 static int
mixer_open(struct cdev * i_dev,int flags,int mode,struct thread * td)843 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
844 {
845 	struct snddev_info *d;
846 	struct snd_mixer *m;
847 
848 	m = i_dev->si_drv1;
849 	if (m == NULL)
850 		return (EBADF);
851 	d = device_get_softc(m->dev);
852 	if (!PCM_REGISTERED(d))
853 		return (EBADF);
854 
855 	return (0);
856 }
857 
858 static int
mixer_close(struct cdev * i_dev,int flags,int mode,struct thread * td)859 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
860 {
861 	struct snddev_info *d;
862 	struct snd_mixer *m;
863 
864 	m = i_dev->si_drv1;
865 	if (m == NULL)
866 		return (EBADF);
867 	d = device_get_softc(m->dev);
868 	if (!PCM_REGISTERED(d))
869 		return (EBADF);
870 
871 	return (0);
872 }
873 
874 static int
mixer_ioctl(struct cdev * i_dev,unsigned long cmd,caddr_t arg,int mode,struct thread * td)875 mixer_ioctl(struct cdev *i_dev, unsigned long cmd, caddr_t arg, int mode,
876     struct thread *td)
877 {
878 	struct snddev_info *d;
879 	struct snd_mixer *m;
880 	int ret;
881 
882 	m = i_dev->si_drv1;
883 	if (m == NULL)
884 		return (EBADF);
885 	d = device_get_softc(m->dev);
886 	if (!PCM_REGISTERED(d))
887 		return (EBADF);
888 
889 	PCM_GIANT_ENTER(d);
890 	PCM_ACQUIRE_QUICK(d);
891 
892 	ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td);
893 
894 	PCM_RELEASE_QUICK(d);
895 	PCM_GIANT_LEAVE(d);
896 
897 	return (ret);
898 }
899 
900 static void
mixer_mixerinfo(struct snd_mixer * m,mixer_info * mi)901 mixer_mixerinfo(struct snd_mixer *m, mixer_info *mi)
902 {
903 	bzero((void *)mi, sizeof(*mi));
904 	strlcpy(mi->id, m->name, sizeof(mi->id));
905 	strlcpy(mi->name, device_get_desc(m->dev), sizeof(mi->name));
906 	mi->modify_counter = m->modify_counter;
907 }
908 
909 int
mixer_ioctl_cmd(struct cdev * i_dev,unsigned long cmd,caddr_t arg,int mode,struct thread * td)910 mixer_ioctl_cmd(struct cdev *i_dev, unsigned long cmd, caddr_t arg, int mode,
911     struct thread *td)
912 {
913 	struct snd_mixer *m;
914 	int ret = EINVAL, *arg_i = (int *)arg;
915 	int v = -1, j = cmd & 0xff;
916 
917 	/*
918 	 * Certain ioctls may be made on any type of device (audio, mixer,
919 	 * and MIDI).  Handle those special cases here.
920 	 */
921 	if (IOCGROUP(cmd) == 'X') {
922 		switch (cmd) {
923 		case SNDCTL_SYSINFO:
924 			sound_oss_sysinfo((oss_sysinfo *)arg);
925 			return (0);
926 		case SNDCTL_CARDINFO:
927 			return (sound_oss_card_info((oss_card_info *)arg));
928 	    	case SNDCTL_AUDIOINFO:
929 			return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
930 			    false));
931 	    	case SNDCTL_AUDIOINFO_EX:
932 			return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
933 			    true));
934 		case SNDCTL_ENGINEINFO:
935 			return (dsp_oss_engineinfo(i_dev, (oss_audioinfo *)arg));
936 		case SNDCTL_MIXERINFO:
937 			return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg));
938 		}
939 		return (EINVAL);
940 	}
941 
942 	m = i_dev->si_drv1;
943 
944 	if (m == NULL)
945 		return (EBADF);
946 
947 	mtx_lock(m->lock);
948 	switch (cmd) {
949 	case SNDCTL_DSP_GET_RECSRC_NAMES: {
950 		oss_mixer_enuminfo *ei = (oss_mixer_enuminfo *)arg;
951 		char *loc;
952 		int i, nvalues, nwrote, nleft, ncopied;
953 
954 		nvalues = 0;
955 		nwrote = 0;
956 		nleft = sizeof(ei->strings);
957 		loc = ei->strings;
958 
959 		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
960 			if (!((1 << i) & m->recdevs))
961 				continue;
962 			ei->strindex[nvalues] = nwrote;
963 			ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1;
964 			nwrote += ncopied;
965 			nleft -= ncopied;
966 			nvalues++;
967 			loc = &ei->strings[nwrote];
968 		}
969 		ei->nvalues = nvalues;
970 
971 		ret = 0;
972 		goto done;
973 	}
974 	case SNDCTL_DSP_GET_RECSRC:
975 		ret = mixer_get_recroute(m, arg_i);
976 		goto done;
977 	case SNDCTL_DSP_SET_RECSRC:
978 		ret = mixer_set_recroute(m, *arg_i);
979 		goto done;
980 	case OSS_GETVERSION:
981 		*arg_i = SOUND_VERSION;
982 		ret = 0;
983 		goto done;
984 	case SOUND_MIXER_INFO:
985 		mixer_mixerinfo(m, (mixer_info *)arg);
986 		ret = 0;
987 		goto done;
988 	}
989 	if ((cmd & ~0xff) == MIXER_WRITE(0)) {
990 		switch (j) {
991 		case SOUND_MIXER_RECSRC:
992 			ret = mixer_setrecsrc(m, *arg_i);
993 			break;
994 		case SOUND_MIXER_MUTE:
995 			mix_setmutedevs(m, *arg_i);
996 			ret = 0;
997 			break;
998 		default:
999 			ret = mixer_set(m, j, m->mutedevs, *arg_i);
1000 			break;
1001 		}
1002 		mtx_unlock(m->lock);
1003 		return (ret);
1004 	}
1005 	if ((cmd & ~0xff) == MIXER_READ(0)) {
1006 		switch (j) {
1007 		case SOUND_MIXER_DEVMASK:
1008 		case SOUND_MIXER_CAPS:
1009 		case SOUND_MIXER_STEREODEVS:
1010 			v = mix_getdevs(m);
1011 			break;
1012 		case SOUND_MIXER_MUTE:
1013 			v = mix_getmutedevs(m);
1014 			break;
1015 		case SOUND_MIXER_RECMASK:
1016 			v = mix_getrecdevs(m);
1017 			break;
1018 		case SOUND_MIXER_RECSRC:
1019 			v = mixer_getrecsrc(m);
1020 			break;
1021 		default:
1022 			v = mixer_get(m, j);
1023 			break;
1024 		}
1025 		*arg_i = v;
1026 		mtx_unlock(m->lock);
1027 		return ((v != -1) ? 0 : ENXIO);
1028 	}
1029 done:
1030 	mtx_unlock(m->lock);
1031 	return (ret);
1032 }
1033 
1034 static void
mixer_clone(void * arg,struct ucred * cred,char * name,int namelen,struct cdev ** dev)1035 mixer_clone(void *arg,
1036     struct ucred *cred,
1037     char *name, int namelen, struct cdev **dev)
1038 {
1039 	struct snddev_info *d;
1040 
1041 	if (*dev != NULL)
1042 		return;
1043 	if (strcmp(name, "mixer") == 0) {
1044 		bus_topo_lock();
1045 		d = devclass_get_softc(pcm_devclass, snd_unit);
1046 		/* See related comment in dsp_clone(). */
1047 		if (PCM_REGISTERED(d) && MIXER_REGISTERED(d->mixer)) {
1048 			*dev = d->mixer->cdev;
1049 			dev_ref(*dev);
1050 		}
1051 		bus_topo_unlock();
1052 	}
1053 }
1054 
1055 static void
mixer_sysinit(void * p)1056 mixer_sysinit(void *p)
1057 {
1058 	if (mixer_ehtag != NULL)
1059 		return;
1060 	mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
1061 }
1062 
1063 static void
mixer_sysuninit(void * p)1064 mixer_sysuninit(void *p)
1065 {
1066 	if (mixer_ehtag == NULL)
1067 		return;
1068 	EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
1069 	mixer_ehtag = NULL;
1070 }
1071 
1072 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
1073 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
1074 
1075 static void
mixer_oss_mixerinfo_unavail(oss_mixerinfo * mi,int unit)1076 mixer_oss_mixerinfo_unavail(oss_mixerinfo *mi, int unit)
1077 {
1078 	bzero(mi, sizeof(*mi));
1079 	mi->dev = unit;
1080 	snprintf(mi->id, sizeof(mi->id), "mixer%d (n/a)", unit);
1081 	snprintf(mi->name, sizeof(mi->name), "pcm%d:mixer (unavailable)", unit);
1082 	mi->card_number = unit;
1083 	mi->legacy_device = unit;
1084 }
1085 
1086 /**
1087  * @brief Handler for SNDCTL_MIXERINFO
1088  *
1089  * This function searches for a mixer based on the numeric ID stored
1090  * in oss_miserinfo::dev.  If set to -1, then information about the
1091  * current mixer handling the request is provided.  Note, however, that
1092  * this ioctl may be made with any sound device (audio, mixer, midi).
1093  *
1094  * @note Caller must not hold any PCM device, channel, or mixer locks.
1095  *
1096  * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for
1097  * more information.
1098  *
1099  * @param i_dev	character device on which the ioctl arrived
1100  * @param arg	user argument (oss_mixerinfo *)
1101  *
1102  * @retval EINVAL	oss_mixerinfo::dev specified a bad value
1103  * @retval 0		success
1104  */
1105 int
mixer_oss_mixerinfo(struct cdev * i_dev,oss_mixerinfo * mi)1106 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
1107 {
1108 	struct snddev_info *d;
1109 	struct snd_mixer *m;
1110 	int i;
1111 
1112 	/*
1113 	 * If probing the device handling the ioctl, make sure it's a mixer
1114 	 * device.  (This ioctl is valid on audio, mixer, and midi devices.)
1115 	 */
1116 	if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw)
1117 		return (EINVAL);
1118 
1119 	d = NULL;
1120 	m = NULL;
1121 
1122 	/*
1123 	 * There's a 1:1 relationship between mixers and PCM devices, so
1124 	 * begin by iterating over PCM devices and search for our mixer.
1125 	 */
1126 	bus_topo_lock();
1127 	for (i = 0; pcm_devclass != NULL &&
1128 	    i < devclass_get_maxunit(pcm_devclass); i++) {
1129 		d = devclass_get_softc(pcm_devclass, i);
1130 		if (!PCM_REGISTERED(d)) {
1131 			if ((mi->dev == -1 && i == snd_unit) || mi->dev == i) {
1132 				mixer_oss_mixerinfo_unavail(mi, i);
1133 				bus_topo_unlock();
1134 				return (0);
1135 			} else
1136 				continue;
1137 		}
1138 
1139 		/* XXX Need Giant magic entry */
1140 
1141 		/* See the note in function docblock. */
1142 		PCM_UNLOCKASSERT(d);
1143 		PCM_LOCK(d);
1144 
1145 		if (!MIXER_REGISTERED(d->mixer)) {
1146 			if (mi->dev == i) {
1147 				mixer_oss_mixerinfo_unavail(mi, i);
1148 				PCM_UNLOCK(d);
1149 				bus_topo_unlock();
1150 				return (0);
1151 			}
1152 			PCM_UNLOCK(d);
1153 			continue;
1154 		}
1155 
1156 		if (!((d->mixer->cdev == i_dev && mi->dev == -1) ||
1157 		    mi->dev == i)) {
1158 			PCM_UNLOCK(d);
1159 			continue;
1160 		}
1161 
1162 		m = d->mixer;
1163 
1164 		/*
1165 		 * At this point, the following synchronization stuff
1166 		 * has happened:
1167 		 * - a specific PCM device is locked.
1168 		 * - a specific mixer device has been locked, so be
1169 		 *   sure to unlock when existing.
1170 		 */
1171 		bzero((void *)mi, sizeof(*mi));
1172 		mi->dev = i;
1173 		snprintf(mi->id, sizeof(mi->id), "mixer%d", i);
1174 		strlcpy(mi->name, m->name, sizeof(mi->name));
1175 		/**
1176 		 * Counter is incremented when applications change any of this
1177 		 * mixer's controls.  A change in value indicates that
1178 		 * persistent mixer applications should update their displays.
1179 		 */
1180 		mi->modify_counter = m->modify_counter;
1181 		mi->card_number = i;
1182 		/*
1183 		 * Currently, FreeBSD assumes 1:1 relationship between
1184 		 * a pcm and mixer devices, so this is hardcoded to 0.
1185 		 */
1186 		mi->port_number = 0;
1187 
1188 		/**
1189 		 * @todo Fill in @sa oss_mixerinfo::mixerhandle.
1190 		 * @note From 4Front:  "mixerhandle is an arbitrary
1191 		 *       string that identifies the mixer better than
1192 		 *       the device number (mixerinfo.dev).  Device
1193 		 *       numbers may change depending on the order the
1194 		 *       drivers are loaded. However the handle should
1195 		 *       remain the same provided that the sound card
1196 		 *       is not moved to another PCI slot."
1197 		 */
1198 
1199 		/**
1200 		 * @note
1201 		 * @sa oss_mixerinfo::magic is a reserved field.
1202 		 *
1203 		 * @par
1204 		 * From 4Front:  "magic is usually 0. However some
1205 		 * devices may have dedicated setup utilities and the
1206 		 * magic field may contain an unique driver specific
1207 		 * value (managed by [4Front])."
1208 		 */
1209 
1210 		mi->enabled = device_is_attached(m->dev) ? 1 : 0;
1211 		/**
1212 		 * The only flag for @sa oss_mixerinfo::caps is
1213 		 * currently MIXER_CAP_VIRTUAL, which I'm not sure we
1214 		 * really worry about.
1215 		 */
1216 		/**
1217 		 * Mixer extensions currently aren't supported, so
1218 		 * leave @sa oss_mixerinfo::nrext blank for now.
1219 		 */
1220 
1221 		/**
1222 		 * @todo Fill in @sa oss_mixerinfo::priority (requires
1223 		 *       touching drivers?)
1224 		 * @note The priority field is for mixer applets to
1225 		 * determine which mixer should be the default, with 0
1226 		 * being least preferred and 10 being most preferred.
1227 		 * From 4Front:  "OSS drivers like ICH use higher
1228 		 * values (10) because such chips are known to be used
1229 		 * only on motherboards.  Drivers for high end pro
1230 		 * devices use 0 because they will never be the
1231 		 * default mixer. Other devices use values 1 to 9
1232 		 * depending on the estimated probability of being the
1233 		 * default device.
1234 		 */
1235 
1236 		snprintf(mi->devnode, sizeof(mi->devnode), "/dev/mixer%d", i);
1237 		mi->legacy_device = i;
1238 
1239 		PCM_UNLOCK(d);
1240 
1241 		bus_topo_unlock();
1242 		return (0);
1243 	}
1244 	bus_topo_unlock();
1245 
1246 	return (EINVAL);
1247 }
1248