mixer.c revision 168247
1139749Simp/*-
2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
350724Scg * All rights reserved.
450724Scg *
550724Scg * Redistribution and use in source and binary forms, with or without
650724Scg * modification, are permitted provided that the following conditions
750724Scg * are met:
850724Scg * 1. Redistributions of source code must retain the above copyright
950724Scg *    notice, this list of conditions and the following disclaimer.
1050724Scg * 2. Redistributions in binary form must reproduce the above copyright
1150724Scg *    notice, this list of conditions and the following disclaimer in the
1250724Scg *    documentation and/or other materials provided with the distribution.
1350724Scg *
1450724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750724Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450724Scg * SUCH DAMAGE.
2550724Scg */
2650724Scg
2753465Scg#include <dev/sound/pcm/sound.h>
2850724Scg
2970134Scg#include "mixer_if.h"
3070134Scg
3182180ScgSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/mixer.c 168247 2007-04-02 03:46:25Z ariff $");
3282180Scg
3370134ScgMALLOC_DEFINE(M_MIXER, "mixer", "mixer");
3470134Scg
3574763Scg#define MIXER_NAMELEN	16
3674763Scgstruct snd_mixer {
3774763Scg	KOBJ_FIELDS;
3874763Scg	const char *type;
3974763Scg	void *devinfo;
40168247Sariff	int busy:1;
4174763Scg	int hwvol_muted;
4274763Scg	int hwvol_mixer;
4374763Scg	int hwvol_step;
44150825Snetchild	device_t dev;
4574763Scg	u_int32_t hwvol_mute_level;
4674763Scg	u_int32_t devs;
4774763Scg	u_int32_t recdevs;
4874763Scg	u_int32_t recsrc;
4974763Scg	u_int16_t level[32];
50162828Sariff	u_int8_t parent[32];
51162738Sariff	u_int32_t child[32];
52162828Sariff	u_int8_t realdev[32];
5374763Scg	char name[MIXER_NAMELEN];
54107285Scg	struct mtx *lock;
55162588Snetchild	oss_mixer_enuminfo enuminfo;
56162588Snetchild	/**
57162588Snetchild	 * Counter is incremented when applications change any of this
58162588Snetchild	 * mixer's controls.  A change in value indicates that persistent
59162588Snetchild	 * mixer applications should update their displays.
60162588Snetchild	 */
61162588Snetchild	int modify_counter;
6274763Scg};
6374763Scg
6450724Scgstatic u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
6550724Scg	[SOUND_MIXER_VOLUME]	= 75,
6650724Scg	[SOUND_MIXER_BASS]	= 50,
6750724Scg	[SOUND_MIXER_TREBLE]	= 50,
6862947Stanimura	[SOUND_MIXER_SYNTH]	= 75,
6950724Scg	[SOUND_MIXER_PCM]	= 75,
7050724Scg	[SOUND_MIXER_SPEAKER]	= 75,
7150724Scg	[SOUND_MIXER_LINE]	= 75,
7250724Scg	[SOUND_MIXER_MIC] 	= 0,
7350724Scg	[SOUND_MIXER_CD]	= 75,
74152422Sariff	[SOUND_MIXER_IGAIN]	= 0,
7550724Scg	[SOUND_MIXER_LINE1]	= 75,
7650724Scg	[SOUND_MIXER_VIDEO]	= 75,
7750724Scg	[SOUND_MIXER_RECLEV]	= 0,
7853203Scg	[SOUND_MIXER_OGAIN]	= 50,
7979044Scg	[SOUND_MIXER_MONITOR]	= 75,
8050724Scg};
8150724Scg
8270680Sjhbstatic char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
8370680Sjhb
8478362Scgstatic d_open_t mixer_open;
8578362Scgstatic d_close_t mixer_close;
8678362Scg
8778362Scgstatic struct cdevsw mixer_cdevsw = {
88126080Sphk	.d_version =	D_VERSION,
89168247Sariff	.d_flags =	D_NEEDGIANT,
90111815Sphk	.d_open =	mixer_open,
91111815Sphk	.d_close =	mixer_close,
92111815Sphk	.d_ioctl =	mixer_ioctl,
93111815Sphk	.d_name =	"mixer",
9478362Scg};
9578362Scg
96162588Snetchild/**
97162588Snetchild * Keeps a count of mixer devices; used only by OSSv4 SNDCTL_SYSINFO ioctl.
98162588Snetchild */
99162588Snetchildint mixer_count = 0;
100162588Snetchild
10178670Scg#ifdef USING_DEVFS
10278362Scgstatic eventhandler_tag mixer_ehtag;
10378670Scg#endif
10478362Scg
105130585Sphkstatic struct cdev *
10678362Scgmixer_get_devt(device_t dev)
10778362Scg{
108124617Sphk	struct snddev_info *snddev;
10978362Scg
110124617Sphk	snddev = device_get_softc(dev);
11178362Scg
112124617Sphk	return snddev->mixer_dev;
11378362Scg}
11478362Scg
11573127Scg#ifdef SND_DYNSYSCTL
11665390Speterstatic int
11770680Sjhbmixer_lookup(char *devname)
11870680Sjhb{
11970680Sjhb	int i;
12070680Sjhb
12170680Sjhb	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
12270680Sjhb		if (strncmp(devname, snd_mixernames[i],
12370680Sjhb		    strlen(snd_mixernames[i])) == 0)
12470680Sjhb			return i;
12570680Sjhb	return -1;
12670680Sjhb}
12773127Scg#endif
12870680Sjhb
12970680Sjhbstatic int
130162738Sariffmixer_set_softpcmvol(struct snd_mixer *mixer, struct snddev_info *d,
131162738Sariff						unsigned left, unsigned right)
13265390Speter{
133162738Sariff	struct snddev_channel *sce;
134162738Sariff	struct pcm_channel *ch;
135162738Sariff#ifdef USING_MUTEX
136162738Sariff	int locked = (mixer->lock && mtx_owned((struct mtx *)(mixer->lock))) ? 1 : 0;
137162738Sariff
138162738Sariff	if (locked)
139162738Sariff		snd_mtxunlock(mixer->lock);
140162738Sariff#endif
141162738Sariff	SLIST_FOREACH(sce, &d->channels, link) {
142162738Sariff		ch = sce->channel;
143162738Sariff		CHN_LOCK(ch);
144162738Sariff		if (ch->direction == PCMDIR_PLAY &&
145162738Sariff				(ch->feederflags & (1 << FEEDER_VOLUME)))
146162738Sariff			chn_setvolume(ch, left, right);
147162738Sariff		CHN_UNLOCK(ch);
148162738Sariff	}
149162738Sariff#ifdef USING_MUTEX
150162738Sariff	if (locked)
151162738Sariff		snd_mtxlock(mixer->lock);
152162738Sariff#endif
153162738Sariff	return 0;
154162738Sariff}
155162738Sariff
156162738Sariffstatic int
157162738Sariffmixer_set(struct snd_mixer *m, unsigned dev, unsigned lev)
158162738Sariff{
159150825Snetchild	struct snddev_info *d;
160162738Sariff	unsigned l, r, tl, tr;
161162738Sariff	u_int32_t parent = SOUND_MIXER_NONE, child = 0;
162162738Sariff	u_int32_t realdev;
163162738Sariff	int i;
16470134Scg
165162738Sariff	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
166162738Sariff	    (0 == (m->devs & (1 << dev))))
16770134Scg		return -1;
16870134Scg
16970134Scg	l = min((lev & 0x00ff), 100);
17070134Scg	r = min(((lev & 0xff00) >> 8), 100);
171162738Sariff	realdev = m->realdev[dev];
17270134Scg
173162738Sariff	d = device_get_softc(m->dev);
174162738Sariff	if (d == NULL)
175162738Sariff		return -1;
17670134Scg
177162738Sariff	/* TODO: recursive handling */
178162738Sariff	parent = m->parent[dev];
179162738Sariff	if (parent >= SOUND_MIXER_NRDEVICES)
180162738Sariff		parent = SOUND_MIXER_NONE;
181162738Sariff	if (parent == SOUND_MIXER_NONE)
182162738Sariff		child = m->child[dev];
183162738Sariff
184162738Sariff	if (parent != SOUND_MIXER_NONE) {
185162738Sariff		tl = (l * (m->level[parent] & 0x00ff)) / 100;
186162738Sariff		tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
187162738Sariff		if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
188162738Sariff			mixer_set_softpcmvol(m, d, tl, tr);
189162738Sariff		else if (realdev != SOUND_MIXER_NONE &&
190162738Sariff		    MIXER_SET(m, realdev, tl, tr) < 0)
191162738Sariff			return -1;
192162738Sariff	} else if (child != 0) {
193162738Sariff		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
194162738Sariff			if (!(child & (1 << i)) || m->parent[i] != dev)
195162738Sariff				continue;
196162738Sariff			realdev = m->realdev[i];
197162738Sariff			tl = (l * (m->level[i] & 0x00ff)) / 100;
198162738Sariff			tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
199162738Sariff			if (i == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
200162738Sariff				mixer_set_softpcmvol(m, d, tl, tr);
201162738Sariff			else if (realdev != SOUND_MIXER_NONE)
202162738Sariff				MIXER_SET(m, realdev, tl, tr);
203150825Snetchild		}
204162738Sariff		realdev = m->realdev[dev];
205162738Sariff		if (realdev != SOUND_MIXER_NONE &&
206162738Sariff		    MIXER_SET(m, realdev, l, r) < 0)
207162738Sariff				return -1;
208150825Snetchild	} else {
209162738Sariff		if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
210162738Sariff			mixer_set_softpcmvol(m, d, l, r);
211162738Sariff		else if (realdev != SOUND_MIXER_NONE &&
212162738Sariff		    MIXER_SET(m, realdev, l, r) < 0)
213150825Snetchild			return -1;
214150825Snetchild	}
215150825Snetchild
216162738Sariff	m->level[dev] = l | (r << 8);
217162738Sariff
21870134Scg	return 0;
21965390Speter}
22065390Speter
22165390Speterstatic int
22274763Scgmixer_get(struct snd_mixer *mixer, int dev)
22365390Speter{
22470134Scg	if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev)))
22570134Scg		return mixer->level[dev];
22665390Speter	else return -1;
22765390Speter}
22865390Speter
22965390Speterstatic int
23074763Scgmixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
23165390Speter{
23270134Scg	src &= mixer->recdevs;
23370134Scg	if (src == 0)
23470134Scg		src = SOUND_MASK_MIC;
23570134Scg	mixer->recsrc = MIXER_SETRECSRC(mixer, src);
23665390Speter	return 0;
23765390Speter}
23865390Speter
23965390Speterstatic int
24074763Scgmixer_getrecsrc(struct snd_mixer *mixer)
24165390Speter{
24270134Scg	return mixer->recsrc;
24365390Speter}
24465390Speter
245162588Snetchild/**
246162588Snetchild * @brief Retrieve the route number of the current recording device
247162588Snetchild *
248162588Snetchild * OSSv4 assigns routing numbers to recording devices, unlike the previous
249162588Snetchild * API which relied on a fixed table of device numbers and names.  This
250162588Snetchild * function returns the routing number of the device currently selected
251162588Snetchild * for recording.
252162588Snetchild *
253162588Snetchild * For now, this function is kind of a goofy compatibility stub atop the
254162588Snetchild * existing sound system.  (For example, in theory, the old sound system
255162588Snetchild * allows multiple recording devices to be specified via a bitmask.)
256162588Snetchild *
257162588Snetchild * @param m	mixer context container thing
258162588Snetchild *
259162588Snetchild * @retval 0		success
260162588Snetchild * @retval EIDRM	no recording device found (generally not possible)
261162588Snetchild * @todo Ask about error code
262162588Snetchild */
263162588Snetchildstatic int
264162588Snetchildmixer_get_recroute(struct snd_mixer *m, int *route)
265162588Snetchild{
266162588Snetchild	int i, cnt;
267162588Snetchild
268162588Snetchild	cnt = 0;
269162588Snetchild
270162588Snetchild	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
271162588Snetchild		/** @todo can user set a multi-device mask? (== or &?) */
272162588Snetchild		if ((1 << i) == m->recsrc)
273162588Snetchild			break;
274162588Snetchild		if ((1 << i) & m->recdevs)
275162588Snetchild			++cnt;
276162588Snetchild	}
277162588Snetchild
278162588Snetchild	if (i == SOUND_MIXER_NRDEVICES)
279162588Snetchild		return EIDRM;
280162588Snetchild
281162588Snetchild	*route = cnt;
282162588Snetchild	return 0;
283162588Snetchild}
284162588Snetchild
285162588Snetchild/**
286162588Snetchild * @brief Select a device for recording
287162588Snetchild *
288162588Snetchild * This function sets a recording source based on a recording device's
289162588Snetchild * routing number.  Said number is translated to an old school recdev
290162588Snetchild * mask and passed over mixer_setrecsrc.
291162588Snetchild *
292162588Snetchild * @param m	mixer context container thing
293162588Snetchild *
294162588Snetchild * @retval 0		success(?)
295162588Snetchild * @retval EINVAL	User specified an invalid device number
296162588Snetchild * @retval otherwise	error from mixer_setrecsrc
297162588Snetchild */
298162588Snetchildstatic int
299162588Snetchildmixer_set_recroute(struct snd_mixer *m, int route)
300162588Snetchild{
301162588Snetchild	int i, cnt, ret;
302162588Snetchild
303162588Snetchild	ret = 0;
304162588Snetchild	cnt = 0;
305162588Snetchild
306162588Snetchild	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
307162588Snetchild		if ((1 << i) & m->recdevs) {
308162588Snetchild			if (route == cnt)
309162588Snetchild				break;
310162588Snetchild			++cnt;
311162588Snetchild		}
312162588Snetchild	}
313162588Snetchild
314162588Snetchild	if (i == SOUND_MIXER_NRDEVICES)
315162588Snetchild		ret = EINVAL;
316162588Snetchild	else
317162588Snetchild		ret = mixer_setrecsrc(m, (1 << i));
318162588Snetchild
319162588Snetchild	return ret;
320162588Snetchild}
321162588Snetchild
32270134Scgvoid
32374763Scgmix_setdevs(struct snd_mixer *m, u_int32_t v)
32470134Scg{
325162791Sariff	struct snddev_info *d;
326162738Sariff	int i;
327162738Sariff
328162738Sariff	if (m == NULL)
329162738Sariff		return;
330162791Sariff
331162791Sariff	d = device_get_softc(m->dev);
332162738Sariff	if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
333150825Snetchild		v |= SOUND_MASK_PCM;
334162738Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
335162738Sariff		if (m->parent[i] < SOUND_MIXER_NRDEVICES)
336162738Sariff			v |= 1 << m->parent[i];
337162738Sariff		v |= m->child[i];
338162738Sariff	}
33970134Scg	m->devs = v;
34070134Scg}
34170134Scg
342162588Snetchild/**
343162588Snetchild * @brief Record mask of available recording devices
344162588Snetchild *
345162588Snetchild * Calling functions are responsible for defining the mask of available
346162588Snetchild * recording devices.  This function records that value in a structure
347162588Snetchild * used by the rest of the mixer code.
348162588Snetchild *
349162588Snetchild * This function also populates a structure used by the SNDCTL_DSP_*RECSRC*
350162588Snetchild * family of ioctls that are part of OSSV4.  All recording device labels
351162588Snetchild * are concatenated in ascending order corresponding to their routing
352162588Snetchild * numbers.  (Ex:  a system might have 0 => 'vol', 1 => 'cd', 2 => 'line',
353162588Snetchild * etc.)  For now, these labels are just the standard recording device
354162588Snetchild * names (cd, line1, etc.), but will eventually be fully dynamic and user
355162588Snetchild * controlled.
356162588Snetchild *
357162588Snetchild * @param m	mixer device context container thing
358162588Snetchild * @param v	mask of recording devices
359162588Snetchild */
36070134Scgvoid
36174763Scgmix_setrecdevs(struct snd_mixer *m, u_int32_t v)
36270134Scg{
363162588Snetchild	oss_mixer_enuminfo *ei;
364162588Snetchild	char *loc;
365162588Snetchild	int i, nvalues, nwrote, nleft, ncopied;
366162588Snetchild
367162588Snetchild	ei = &m->enuminfo;
368162588Snetchild
369162588Snetchild	nvalues = 0;
370162588Snetchild	nwrote = 0;
371162588Snetchild	nleft = sizeof(ei->strings);
372162588Snetchild	loc = ei->strings;
373162588Snetchild
374162588Snetchild	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
375162588Snetchild		if ((1 << i) & v) {
376162588Snetchild			ei->strindex[nvalues] = nwrote;
377162588Snetchild			ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1;
378162588Snetchild			    /* strlcpy retval doesn't include terminator */
379162588Snetchild
380162588Snetchild			nwrote += ncopied;
381162588Snetchild			nleft -= ncopied;
382162588Snetchild			nvalues++;
383162588Snetchild
384162588Snetchild			/*
385162588Snetchild			 * XXX I don't think this should ever be possible.
386162588Snetchild			 * Even with a move to dynamic device/channel names,
387162588Snetchild			 * each label is limited to ~16 characters, so that'd
388162588Snetchild			 * take a LOT to fill this buffer.
389162588Snetchild			 */
390162588Snetchild			if ((nleft <= 0) || (nvalues >= OSS_ENUM_MAXVALUE)) {
391162588Snetchild				device_printf(m->dev,
392162588Snetchild				    "mix_setrecdevs:  Not enough room to store device names--please file a bug report.\n");
393162588Snetchild				device_printf(m->dev,
394162588Snetchild				    "mix_setrecdevs:  Please include details about your sound hardware, OS version, etc.\n");
395162588Snetchild				break;
396162588Snetchild			}
397162588Snetchild
398162588Snetchild			loc = &ei->strings[nwrote];
399162588Snetchild		}
400162588Snetchild	}
401162588Snetchild
402162588Snetchild	/*
403162588Snetchild	 * NB:	The SNDCTL_DSP_GET_RECSRC_NAMES ioctl ignores the dev
404162588Snetchild	 * 	and ctrl fields.
405162588Snetchild	 */
406162588Snetchild	ei->nvalues = nvalues;
40770134Scg	m->recdevs = v;
40870134Scg}
40970134Scg
410162738Sariffvoid
411162738Sariffmix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs)
412162738Sariff{
413162738Sariff	u_int32_t mask = 0;
414162738Sariff	int i;
415162738Sariff
416162738Sariff	if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
417162738Sariff		return;
418162738Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
419162738Sariff		if (i == parent)
420162738Sariff			continue;
421162738Sariff		if (childs & (1 << i)) {
422162738Sariff			mask |= 1 << i;
423162738Sariff			if (m->parent[i] < SOUND_MIXER_NRDEVICES)
424162738Sariff				m->child[m->parent[i]] &= ~(1 << i);
425162738Sariff			m->parent[i] = parent;
426162738Sariff			m->child[i] = 0;
427162738Sariff		}
428162738Sariff	}
429162738Sariff	mask &= ~(1 << parent);
430162738Sariff	m->child[parent] = mask;
431162738Sariff}
432162738Sariff
433162738Sariffvoid
434162738Sariffmix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev)
435162738Sariff{
436162738Sariff	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
437162738Sariff	    !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
438162738Sariff		return;
439162738Sariff	m->realdev[dev] = realdev;
440162738Sariff}
441162738Sariff
44270134Scgu_int32_t
443162738Sariffmix_getparent(struct snd_mixer *m, u_int32_t dev)
444162738Sariff{
445162738Sariff	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
446162738Sariff		return SOUND_MIXER_NONE;
447162738Sariff	return m->parent[dev];
448162738Sariff}
449162738Sariff
450162738Sariffu_int32_t
451162738Sariffmix_getchild(struct snd_mixer *m, u_int32_t dev)
452162738Sariff{
453162738Sariff	if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
454162738Sariff		return 0;
455162738Sariff	return m->child[dev];
456162738Sariff}
457162738Sariff
458162738Sariffu_int32_t
45974763Scgmix_getdevs(struct snd_mixer *m)
46070134Scg{
46170134Scg	return m->devs;
46270134Scg}
46370134Scg
46470134Scgu_int32_t
46574763Scgmix_getrecdevs(struct snd_mixer *m)
46670134Scg{
46770134Scg	return m->recdevs;
46870134Scg}
46970134Scg
47070134Scgvoid *
47174763Scgmix_getdevinfo(struct snd_mixer *m)
47270134Scg{
47370134Scg	return m->devinfo;
47470134Scg}
47570134Scg
47650724Scgint
47770134Scgmixer_init(device_t dev, kobj_class_t cls, void *devinfo)
47870134Scg{
479124617Sphk	struct snddev_info *snddev;
48074763Scg	struct snd_mixer *m;
48170134Scg	u_int16_t v;
482130585Sphk	struct cdev *pdev;
483130792Sjosef	int i, unit, val;
48470134Scg
485111119Simp	m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
48674763Scg	snprintf(m->name, MIXER_NAMELEN, "%s:mixer", device_get_nameunit(dev));
48793816Sjhb	m->lock = snd_mtxcreate(m->name, "pcm mixer");
48874763Scg	m->type = cls->name;
48970134Scg	m->devinfo = devinfo;
49078362Scg	m->busy = 0;
491150825Snetchild	m->dev = dev;
492162738Sariff	for (i = 0; i < 32; i++) {
493162738Sariff		m->parent[i] = SOUND_MIXER_NONE;
494162738Sariff		m->child[i] = 0;
495162738Sariff		m->realdev[i] = i;
496162738Sariff	}
49770134Scg
49870134Scg	if (MIXER_INIT(m))
49970134Scg		goto bad;
50070134Scg
50170134Scg	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
502131105Sjosef		v = snd_mixerdefaults[i];
503131105Sjosef
504131064Sjosef		if (resource_int_value(device_get_name(dev),
505131064Sjosef		    device_get_unit(dev), snd_mixernames[i], &val) == 0) {
506131064Sjosef			if (val >= 0 && val <= 100) {
507131064Sjosef				v = (u_int16_t) val;
508131064Sjosef			}
509131064Sjosef		}
510130792Sjosef
51170134Scg		mixer_set(m, i, v | (v << 8));
51270134Scg	}
51370134Scg
51470134Scg	mixer_setrecsrc(m, SOUND_MASK_MIC);
51570134Scg
51678362Scg	unit = device_get_unit(dev);
51778362Scg	pdev = make_dev(&mixer_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0),
51878362Scg		 UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
51978362Scg	pdev->si_drv1 = m;
520124617Sphk	snddev = device_get_softc(dev);
521124617Sphk	snddev->mixer_dev = pdev;
52270134Scg
523162588Snetchild	++mixer_count;
524162588Snetchild
525162738Sariff	if (bootverbose) {
526162738Sariff		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
527162738Sariff			if (!(m->devs & (1 << i)))
528162738Sariff				continue;
529162738Sariff			if (m->realdev[i] != i) {
530162738Sariff				device_printf(dev, "Mixer \"%s\" -> \"%s\":",
531162738Sariff				    snd_mixernames[i],
532162738Sariff				    (m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
533162738Sariff				    snd_mixernames[m->realdev[i]] : "none");
534162738Sariff			} else {
535162738Sariff				device_printf(dev, "Mixer \"%s\":",
536162738Sariff				    snd_mixernames[i]);
537162738Sariff			}
538162738Sariff			if (m->parent[i] < SOUND_MIXER_NRDEVICES)
539162738Sariff				printf(" parent=\"%s\"",
540162738Sariff				    snd_mixernames[m->parent[i]]);
541162738Sariff			if (m->child[i] != 0)
542162738Sariff				printf(" child=0x%08x", m->child[i]);
543162738Sariff			printf("\n");
544162738Sariff		}
545162738Sariff		if (snddev->flags & SD_F_SOFTPCMVOL)
546162738Sariff			device_printf(dev, "Soft PCM mixer ENABLED\n");
547162738Sariff	}
548162738Sariff
54970134Scg	return 0;
55070134Scg
55174763Scgbad:
55274763Scg	snd_mtxlock(m->lock);
55374763Scg	snd_mtxfree(m->lock);
55474763Scg	kobj_delete((kobj_t)m, M_MIXER);
55570134Scg	return -1;
55670134Scg}
55770134Scg
55870134Scgint
55965340Scgmixer_uninit(device_t dev)
56058383Scg{
56158383Scg	int i;
562156929Sariff	struct snddev_info *d;
56374763Scg	struct snd_mixer *m;
564130585Sphk	struct cdev *pdev;
56570134Scg
566156929Sariff	d = device_get_softc(dev);
56778362Scg	pdev = mixer_get_devt(dev);
568156929Sariff	if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL)
569156929Sariff		return EBADF;
57078362Scg	m = pdev->si_drv1;
57174763Scg	snd_mtxlock(m->lock);
57270134Scg
57378362Scg	if (m->busy) {
57478362Scg		snd_mtxunlock(m->lock);
57578362Scg		return EBUSY;
57678362Scg	}
57778362Scg
57878362Scg	pdev->si_drv1 = NULL;
57978362Scg	destroy_dev(pdev);
58078362Scg
58165340Scg	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
58270134Scg		mixer_set(m, i, 0);
58370134Scg
58470134Scg	mixer_setrecsrc(m, SOUND_MASK_MIC);
58570134Scg
58670134Scg	MIXER_UNINIT(m);
58770134Scg
58874763Scg	snd_mtxfree(m->lock);
58970134Scg	kobj_delete((kobj_t)m, M_MIXER);
59070134Scg
591156929Sariff	d->mixer_dev = NULL;
592156929Sariff
593162588Snetchild	--mixer_count;
594162588Snetchild
59565340Scg	return 0;
59665340Scg}
59765340Scg
59865340Scgint
59965340Scgmixer_reinit(device_t dev)
60065340Scg{
60178362Scg	struct snd_mixer *m;
602130585Sphk	struct cdev *pdev;
60365340Scg	int i;
60467652Scg
60578362Scg	pdev = mixer_get_devt(dev);
60678362Scg	m = pdev->si_drv1;
60774763Scg	snd_mtxlock(m->lock);
60870134Scg
60970134Scg	i = MIXER_REINIT(m);
61074763Scg	if (i) {
61174763Scg		snd_mtxunlock(m->lock);
61267652Scg		return i;
61374763Scg	}
61470134Scg
61567652Scg	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
61670134Scg		mixer_set(m, i, m->level[i]);
61770134Scg
61870134Scg	mixer_setrecsrc(m, m->recsrc);
61974763Scg	snd_mtxunlock(m->lock);
62070134Scg
62167652Scg	return 0;
62258383Scg}
62358383Scg
62473127Scg#ifdef SND_DYNSYSCTL
62570680Sjhbstatic int
62670680Sjhbsysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
62770680Sjhb{
62870680Sjhb	char devname[32];
62970680Sjhb	int error, dev;
63074763Scg	struct snd_mixer *m;
63170618Sjhb
63270680Sjhb	m = oidp->oid_arg1;
63374763Scg	snd_mtxlock(m->lock);
634164614Sariff	strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
635100654Sgreen	snd_mtxunlock(m->lock);
63670680Sjhb	error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
637100654Sgreen	snd_mtxlock(m->lock);
63870680Sjhb	if (error == 0 && req->newptr != NULL) {
63970680Sjhb		dev = mixer_lookup(devname);
64074763Scg		if (dev == -1) {
64174763Scg			snd_mtxunlock(m->lock);
64270680Sjhb			return EINVAL;
64374763Scg		}
64470944Sjhb		else if (dev != m->hwvol_mixer) {
64570680Sjhb			m->hwvol_mixer = dev;
64670944Sjhb			m->hwvol_muted = 0;
64770944Sjhb		}
64870680Sjhb	}
64974763Scg	snd_mtxunlock(m->lock);
65070680Sjhb	return error;
65170680Sjhb}
65273127Scg#endif
65370618Sjhb
65470680Sjhbint
65570944Sjhbmixer_hwvol_init(device_t dev)
65670680Sjhb{
65774763Scg	struct snd_mixer *m;
658130585Sphk	struct cdev *pdev;
65970680Sjhb
66078362Scg	pdev = mixer_get_devt(dev);
66178362Scg	m = pdev->si_drv1;
66278362Scg
66370680Sjhb	m->hwvol_mixer = SOUND_MIXER_VOLUME;
66470680Sjhb	m->hwvol_step = 5;
66573127Scg#ifdef SND_DYNSYSCTL
666164614Sariff	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
667164614Sariff	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
66870680Sjhb            OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, "");
669164614Sariff	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
670164614Sariff	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
67170680Sjhb            OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
672100071Smarkm	    sysctl_hw_snd_hwvol_mixer, "A", "");
67373127Scg#endif
67470680Sjhb	return 0;
67570680Sjhb}
67670680Sjhb
67770618Sjhbvoid
67870944Sjhbmixer_hwvol_mute(device_t dev)
67970618Sjhb{
68074763Scg	struct snd_mixer *m;
681130585Sphk	struct cdev *pdev;
68270618Sjhb
68378362Scg	pdev = mixer_get_devt(dev);
68478362Scg	m = pdev->si_drv1;
68574763Scg	snd_mtxlock(m->lock);
68670944Sjhb	if (m->hwvol_muted) {
68770944Sjhb		m->hwvol_muted = 0;
68870944Sjhb		mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
68970680Sjhb	} else {
69070944Sjhb		m->hwvol_muted++;
69170944Sjhb		m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
69270680Sjhb		mixer_set(m, m->hwvol_mixer, 0);
69370680Sjhb	}
69474763Scg	snd_mtxunlock(m->lock);
69570618Sjhb}
69670618Sjhb
69770618Sjhbvoid
69870944Sjhbmixer_hwvol_step(device_t dev, int left_step, int right_step)
69970618Sjhb{
70074763Scg	struct snd_mixer *m;
70170618Sjhb	int level, left, right;
702130585Sphk	struct cdev *pdev;
70370618Sjhb
70478362Scg	pdev = mixer_get_devt(dev);
70578362Scg	m = pdev->si_drv1;
70674763Scg	snd_mtxlock(m->lock);
70770944Sjhb	if (m->hwvol_muted) {
70870944Sjhb		m->hwvol_muted = 0;
70970944Sjhb		level = m->hwvol_mute_level;
71070944Sjhb	} else
71170944Sjhb		level = mixer_get(m, m->hwvol_mixer);
71270618Sjhb	if (level != -1) {
71370618Sjhb		left = level & 0xff;
71470618Sjhb		right = level >> 8;
71570680Sjhb		left += left_step * m->hwvol_step;
71670618Sjhb		if (left < 0)
71770618Sjhb			left = 0;
71870680Sjhb		right += right_step * m->hwvol_step;
71970618Sjhb		if (right < 0)
72070618Sjhb			right = 0;
72170680Sjhb		mixer_set(m, m->hwvol_mixer, left | right << 8);
72270618Sjhb	}
72374763Scg	snd_mtxunlock(m->lock);
72470618Sjhb}
72570618Sjhb
72678362Scg/* ----------------------------------------------------------------------- */
72750724Scg
72878362Scgstatic int
729130585Sphkmixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
73078362Scg{
73178362Scg	struct snd_mixer *m;
73278362Scg
73382181Scg	m = i_dev->si_drv1;
73482181Scg	snd_mtxlock(m->lock);
73578362Scg
736168247Sariff	m->busy = 1;
73782181Scg
73882181Scg	snd_mtxunlock(m->lock);
73978362Scg	return 0;
74078362Scg}
74178362Scg
74278362Scgstatic int
743130585Sphkmixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
74478362Scg{
74578362Scg	struct snd_mixer *m;
74678362Scg
74782181Scg	m = i_dev->si_drv1;
74882181Scg	snd_mtxlock(m->lock);
74982181Scg
75078670Scg	if (!m->busy) {
75182181Scg		snd_mtxunlock(m->lock);
75278362Scg		return EBADF;
75378670Scg	}
754168247Sariff	m->busy = 0;
75578362Scg
75682181Scg	snd_mtxunlock(m->lock);
75778362Scg	return 0;
75878362Scg}
75978362Scg
76078362Scgint
761130585Sphkmixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
76278362Scg{
76378670Scg	struct snd_mixer *m;
76478362Scg	int ret, *arg_i = (int *)arg;
76578362Scg	int v = -1, j = cmd & 0xff;
76678362Scg
76778362Scg	m = i_dev->si_drv1;
768156929Sariff
769156929Sariff	if (m == NULL)
77078362Scg		return EBADF;
77178362Scg
77278362Scg	snd_mtxlock(m->lock);
773156929Sariff	if (mode != -1 && !m->busy) {
774156929Sariff		snd_mtxunlock(m->lock);
775156929Sariff		return EBADF;
776156929Sariff	}
777156929Sariff
778162588Snetchild	if (cmd == SNDCTL_MIXERINFO) {
779162588Snetchild		snd_mtxunlock(m->lock);
780162588Snetchild		return mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg);
781162588Snetchild	}
782162588Snetchild
78378362Scg	if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
78478362Scg		if (j == SOUND_MIXER_RECSRC)
78578362Scg			ret = mixer_setrecsrc(m, *arg_i);
78678362Scg		else
78778362Scg			ret = mixer_set(m, j, *arg_i);
78878362Scg		snd_mtxunlock(m->lock);
78978362Scg		return (ret == 0)? 0 : ENXIO;
79078362Scg	}
79178362Scg
79278362Scg    	if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) {
79378362Scg		switch (j) {
79478362Scg    		case SOUND_MIXER_DEVMASK:
79578362Scg    		case SOUND_MIXER_CAPS:
79678362Scg    		case SOUND_MIXER_STEREODEVS:
79778362Scg			v = mix_getdevs(m);
79878362Scg			break;
79978362Scg
80078362Scg    		case SOUND_MIXER_RECMASK:
80178362Scg			v = mix_getrecdevs(m);
80278362Scg			break;
80378362Scg
80478362Scg    		case SOUND_MIXER_RECSRC:
80578362Scg			v = mixer_getrecsrc(m);
80678362Scg			break;
80778362Scg
80878362Scg		default:
80978362Scg			v = mixer_get(m, j);
81078362Scg		}
81178362Scg		*arg_i = v;
81278362Scg		snd_mtxunlock(m->lock);
81378362Scg		return (v != -1)? 0 : ENXIO;
81478362Scg	}
815162588Snetchild
816162588Snetchild	ret = 0;
817162588Snetchild
818162588Snetchild	switch (cmd) {
819162588Snetchild 	/** @todo Double check return values, error codes. */
820162588Snetchild	case SNDCTL_SYSINFO:
821162588Snetchild		sound_oss_sysinfo((oss_sysinfo *)arg);
822162588Snetchild		break;
823162588Snetchild	case SNDCTL_AUDIOINFO:
824162588Snetchild		ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg);
825162588Snetchild		break;
826162588Snetchild	case SNDCTL_DSP_GET_RECSRC_NAMES:
827162588Snetchild		bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo));
828162588Snetchild		break;
829162588Snetchild	case SNDCTL_DSP_GET_RECSRC:
830162588Snetchild		ret = mixer_get_recroute(m, arg_i);
831162588Snetchild		break;
832162588Snetchild	case SNDCTL_DSP_SET_RECSRC:
833162588Snetchild		ret = mixer_set_recroute(m, *arg_i);
834162588Snetchild		break;
835164613Snetchild	case OSS_GETVERSION:
836164613Snetchild		*arg_i = SOUND_VERSION;
837164613Snetchild		break;
838162588Snetchild	default:
839162588Snetchild		ret = ENXIO;
840162588Snetchild	}
841162588Snetchild
84278362Scg	snd_mtxunlock(m->lock);
843162588Snetchild	return ret;
84478362Scg}
84578362Scg
84678670Scg#ifdef USING_DEVFS
84778362Scgstatic void
848148868Srwatsonmixer_clone(void *arg, struct ucred *cred, char *name, int namelen,
849148868Srwatson    struct cdev **dev)
85078362Scg{
851124617Sphk	struct snddev_info *sd;
85278362Scg
853130640Sphk	if (*dev != NULL)
85478362Scg		return;
85578362Scg	if (strcmp(name, "mixer") == 0) {
856124617Sphk		sd = devclass_get_softc(pcm_devclass, snd_unit);
857152005Sariff		if (sd != NULL && sd->mixer_dev != NULL) {
858124617Sphk			*dev = sd->mixer_dev;
859144389Sphk			dev_ref(*dev);
860144389Sphk		}
86178362Scg	}
86278362Scg}
86378362Scg
86478362Scgstatic void
86578362Scgmixer_sysinit(void *p)
86678362Scg{
86778362Scg	mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
86878362Scg}
86978362Scg
87078362Scgstatic void
87178362Scgmixer_sysuninit(void *p)
87278362Scg{
87378362Scg	if (mixer_ehtag != NULL)
87478362Scg		EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
87578362Scg}
87678362Scg
87778362ScgSYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
87878362ScgSYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
87978670Scg#endif
88078362Scg
881162588Snetchild/**
882162588Snetchild * @brief Handler for SNDCTL_MIXERINFO
883162588Snetchild *
884162588Snetchild * This function searches for a mixer based on the numeric ID stored
885162588Snetchild * in oss_miserinfo::dev.  If set to -1, then information about the
886162588Snetchild * current mixer handling the request is provided.  Note, however, that
887162588Snetchild * this ioctl may be made with any sound device (audio, mixer, midi).
888162588Snetchild *
889162588Snetchild * @note Caller must not hold any PCM device, channel, or mixer locks.
890162588Snetchild *
891162588Snetchild * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for
892162588Snetchild * more information.
893162588Snetchild *
894162588Snetchild * @param i_dev	character device on which the ioctl arrived
895162588Snetchild * @param arg	user argument (oss_mixerinfo *)
896162588Snetchild *
897162588Snetchild * @retval EINVAL	oss_mixerinfo::dev specified a bad value
898162588Snetchild * @retval 0		success
899162588Snetchild */
900162588Snetchildint
901162588Snetchildmixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
902162588Snetchild{
903162588Snetchild	struct snddev_info *d;
904162588Snetchild	struct snd_mixer *m;
905162588Snetchild	struct cdev *t_cdev;
906162588Snetchild	int nmix, ret, pcmunit, i;
90778362Scg
908162588Snetchild	/*
909162588Snetchild	 * If probing the device handling the ioctl, make sure it's a mixer
910162588Snetchild	 * device.  (This ioctl is valid on audio, mixer, and midi devices.)
911162588Snetchild	 */
912162588Snetchild	if ((mi->dev == -1) && (i_dev->si_devsw != &mixer_cdevsw))
913162588Snetchild		return EINVAL;
914162588Snetchild
915162606Snetchild	d = NULL;
916162588Snetchild	m = NULL;
917162588Snetchild	t_cdev = NULL;
918162588Snetchild	nmix = 0;
919162588Snetchild	ret = 0;
920162588Snetchild	pcmunit = -1; /* pcmX */
921162588Snetchild
922162588Snetchild	/*
923162588Snetchild	 * There's a 1:1 relationship between mixers and PCM devices, so
924162588Snetchild	 * begin by iterating over PCM devices and search for our mixer.
925162588Snetchild	 */
926162588Snetchild	for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) {
927162588Snetchild		d = devclass_get_softc(pcm_devclass, i);
928162588Snetchild		if (d == NULL)
929162588Snetchild			continue;
930162588Snetchild
931162588Snetchild		/* See the note in function docblock. */
932162588Snetchild		mtx_assert(d->lock, MA_NOTOWNED);
933162588Snetchild		pcm_inprog(d, 1);
934162588Snetchild		pcm_lock(d);
935162588Snetchild
936162588Snetchild		if (d->mixer_dev != NULL) {
937162588Snetchild			if (((mi->dev == -1) && (d->mixer_dev == i_dev)) || (mi->dev == nmix)) {
938162588Snetchild				t_cdev = d->mixer_dev;
939162588Snetchild				pcmunit = i;
940162588Snetchild				break;
941162588Snetchild			}
942162588Snetchild			++nmix;
943162588Snetchild		}
944162588Snetchild
945162588Snetchild		pcm_unlock(d);
946162588Snetchild		pcm_inprog(d, -1);
947162588Snetchild	}
948162588Snetchild
949162588Snetchild	/*
950162588Snetchild	 * If t_cdev is NULL, then search was exhausted and device wasn't
951162588Snetchild	 * found.  No locks are held, so just return.
952162588Snetchild	 */
953162588Snetchild	if (t_cdev == NULL)
954162588Snetchild		return EINVAL;
955162588Snetchild
956162588Snetchild	m = t_cdev->si_drv1;
957162588Snetchild	mtx_lock(m->lock);
958162588Snetchild
959162588Snetchild	/*
960162588Snetchild	 * At this point, the following synchronization stuff has happened:
961162588Snetchild	 *   - a specific PCM device is locked and its "in progress
962162588Snetchild	 *     operations" counter has been incremented, so be sure to unlock
963162588Snetchild	 *     and decrement when exiting;
964162588Snetchild	 *   - a specific mixer device has been locked, so be sure to unlock
965162588Snetchild	 *     when existing.
966162588Snetchild	 */
967162588Snetchild
968162588Snetchild	bzero((void *)mi, sizeof(*mi));
969162588Snetchild
970162588Snetchild	mi->dev = nmix;
971162588Snetchild	snprintf(mi->id, sizeof(mi->id), "mixer%d", dev2unit(t_cdev));
972162588Snetchild	strlcpy(mi->name, m->name, sizeof(mi->name));
973162588Snetchild	mi->modify_counter = m->modify_counter;
974162588Snetchild	mi->card_number = pcmunit;
975162588Snetchild	/*
976162588Snetchild	 * Currently, FreeBSD assumes 1:1 relationship between a pcm and
977162588Snetchild	 * mixer devices, so this is hardcoded to 0.
978162588Snetchild	 */
979162588Snetchild	mi->port_number = 0;
980162588Snetchild
981162588Snetchild	/**
982162588Snetchild	 * @todo Fill in @sa oss_mixerinfo::mixerhandle.
983162588Snetchild	 * @note From 4Front:  "mixerhandle is an arbitrary string that
984162588Snetchild	 * 	 identifies the mixer better than the device number
985162588Snetchild	 * 	 (mixerinfo.dev). Device numbers may change depending on
986162588Snetchild	 * 	 the order the drivers are loaded. However the handle
987162588Snetchild	 * 	 should remain the same provided that the sound card is
988162588Snetchild	 * 	 not moved to another PCI slot."
989162588Snetchild	 */
990162588Snetchild
991162588Snetchild	/**
992162588Snetchild	 * @note
993162588Snetchild	 * @sa oss_mixerinfo::magic is a reserved field.
994162588Snetchild	 *
995162588Snetchild	 * @par
996162588Snetchild	 * From 4Front:  "magic is usually 0. However some devices may have
997162588Snetchild	 * dedicated setup utilities and the magic field may contain an
998162588Snetchild	 * unique driver specific value (managed by [4Front])."
999162588Snetchild	 */
1000162588Snetchild
1001162588Snetchild	mi->enabled = device_is_attached(m->dev) ? 1 : 0;
1002162588Snetchild	/**
1003162588Snetchild	 * The only flag for @sa oss_mixerinfo::caps is currently
1004162588Snetchild	 * MIXER_CAP_VIRTUAL, which I'm not sure we really worry about.
1005162588Snetchild	 */
1006162588Snetchild	/**
1007162588Snetchild	 * Mixer extensions currently aren't supported, so leave
1008162588Snetchild	 * @sa oss_mixerinfo::nrext blank for now.
1009162588Snetchild	 */
1010162588Snetchild	/**
1011162588Snetchild	 * @todo Fill in @sa oss_mixerinfo::priority (requires touching
1012162588Snetchild	 * 	 drivers?)
1013162588Snetchild	 * @note The priority field is for mixer applets to determine which
1014162588Snetchild	 * mixer should be the default, with 0 being least preferred and 10
1015162588Snetchild	 * being most preferred.  From 4Front:  "OSS drivers like ICH use
1016162588Snetchild	 * higher values (10) because such chips are known to be used only
1017162588Snetchild	 * on motherboards.  Drivers for high end pro devices use 0 because
1018162588Snetchild	 * they will never be the default mixer. Other devices use values 1
1019162588Snetchild	 * to 9 depending on the estimated probability of being the default
1020162588Snetchild	 * device.
1021162588Snetchild	 *
1022162588Snetchild	 * XXX Described by Hannu@4Front, but not found in soundcard.h.
1023162588Snetchild	strlcpy(mi->devnode, t_cdev->si_name, sizeof(mi->devnode));
1024162588Snetchild	mi->legacy_device = pcmunit;
1025162588Snetchild	 */
1026162588Snetchild
1027162588Snetchild	mtx_unlock(m->lock);
1028162588Snetchild	pcm_unlock(d);
1029162588Snetchild	pcm_inprog(d, -1);
1030162588Snetchild
1031162588Snetchild	return ret;
1032162588Snetchild}
1033