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