xref: /freebsd/sys/dev/sound/pcm/dsp.c (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
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) 2024 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 #include <sys/ctype.h>
41 #include <sys/lock.h>
42 #include <sys/rwlock.h>
43 #include <sys/sysent.h>
44 
45 #include <vm/vm.h>
46 #include <vm/vm_object.h>
47 #include <vm/vm_page.h>
48 #include <vm/vm_pager.h>
49 
50 struct dsp_cdevpriv {
51 	struct snddev_info *sc;
52 	struct pcm_channel *rdch;
53 	struct pcm_channel *wrch;
54 	struct pcm_channel *volch;
55 	int simplex;
56 };
57 
58 static int dsp_mmap_allow_prot_exec = 0;
59 SYSCTL_INT(_hw_snd, OID_AUTO, compat_linux_mmap, CTLFLAG_RWTUN,
60     &dsp_mmap_allow_prot_exec, 0,
61     "linux mmap compatibility (-1=force disable 0=auto 1=force enable)");
62 
63 static int dsp_basename_clone = 1;
64 SYSCTL_INT(_hw_snd, OID_AUTO, basename_clone, CTLFLAG_RWTUN,
65     &dsp_basename_clone, 0,
66     "DSP basename cloning (0: Disable; 1: Enabled)");
67 
68 #define DSP_REGISTERED(x)	(PCM_REGISTERED(x) && (x)->dsp_dev != NULL)
69 
70 #define OLDPCM_IOCTL
71 
72 static d_open_t dsp_open;
73 static d_read_t dsp_read;
74 static d_write_t dsp_write;
75 static d_ioctl_t dsp_ioctl;
76 static d_poll_t dsp_poll;
77 static d_mmap_t dsp_mmap;
78 static d_mmap_single_t dsp_mmap_single;
79 
80 struct cdevsw dsp_cdevsw = {
81 	.d_version =	D_VERSION,
82 	.d_open =	dsp_open,
83 	.d_read =	dsp_read,
84 	.d_write =	dsp_write,
85 	.d_ioctl =	dsp_ioctl,
86 	.d_poll =	dsp_poll,
87 	.d_mmap =	dsp_mmap,
88 	.d_mmap_single = dsp_mmap_single,
89 	.d_name =	"dsp",
90 };
91 
92 static eventhandler_tag dsp_ehtag = NULL;
93 
94 static int dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group);
95 static int dsp_oss_syncstart(int sg_id);
96 static int dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy);
97 static int dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled);
98 static int dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
99 static int dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
100 static int dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch, int *mask);
101 #ifdef OSSV4_EXPERIMENT
102 static int dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
103 static int dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
104 static int dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
105 static int dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
106 static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name);
107 #endif
108 
109 int
110 dsp_make_dev(device_t dev)
111 {
112 	struct make_dev_args devargs;
113 	struct snddev_info *sc;
114 	int err, unit;
115 
116 	sc = device_get_softc(dev);
117 	unit = device_get_unit(dev);
118 
119 	make_dev_args_init(&devargs);
120 	devargs.mda_devsw = &dsp_cdevsw;
121 	devargs.mda_uid = UID_ROOT;
122 	devargs.mda_gid = GID_WHEEL;
123 	devargs.mda_mode = 0666;
124 	devargs.mda_si_drv1 = sc;
125 	err = make_dev_s(&devargs, &sc->dsp_dev, "dsp%d", unit);
126 	if (err != 0) {
127 		device_printf(dev, "failed to create dsp%d: error %d",
128 		    unit, err);
129 		return (ENXIO);
130 	}
131 
132 	return (0);
133 }
134 
135 void
136 dsp_destroy_dev(device_t dev)
137 {
138 	struct snddev_info *d;
139 
140 	d = device_get_softc(dev);
141 	destroy_dev_sched(d->dsp_dev);
142 }
143 
144 static void
145 getchns(struct dsp_cdevpriv *priv, uint32_t prio)
146 {
147 	struct snddev_info *d;
148 	struct pcm_channel *ch;
149 	uint32_t flags;
150 
151 	if (priv->simplex) {
152 		d = priv->sc;
153 		if (!PCM_REGISTERED(d))
154 			return;
155 		PCM_LOCK(d);
156 		PCM_WAIT(d);
157 		PCM_ACQUIRE(d);
158 		/*
159 		 * Note: order is important -
160 		 *       pcm flags -> prio query flags -> wild guess
161 		 */
162 		ch = NULL;
163 		flags = pcm_getflags(d->dev);
164 		if (flags & SD_F_PRIO_WR) {
165 			ch = priv->rdch;
166 		} else if (flags & SD_F_PRIO_RD) {
167 			ch = priv->wrch;
168 		} else if (prio & SD_F_PRIO_WR) {
169 			ch = priv->rdch;
170 			flags |= SD_F_PRIO_WR;
171 		} else if (prio & SD_F_PRIO_RD) {
172 			ch = priv->wrch;
173 			flags |= SD_F_PRIO_RD;
174 		} else if (priv->wrch != NULL) {
175 			ch = priv->rdch;
176 			flags |= SD_F_PRIO_WR;
177 		} else if (priv->rdch != NULL) {
178 			ch = priv->wrch;
179 			flags |= SD_F_PRIO_RD;
180 		}
181 		pcm_setflags(d->dev, flags);
182 		if (ch != NULL) {
183 			CHN_LOCK(ch);
184 			chn_ref(ch, -1);
185 			chn_release(ch);
186 		}
187 		PCM_RELEASE(d);
188 		PCM_UNLOCK(d);
189 	}
190 
191 	if (priv->rdch != NULL && (prio & SD_F_PRIO_RD))
192 		CHN_LOCK(priv->rdch);
193 	if (priv->wrch != NULL && (prio & SD_F_PRIO_WR))
194 		CHN_LOCK(priv->wrch);
195 }
196 
197 static void
198 relchns(struct dsp_cdevpriv *priv, uint32_t prio)
199 {
200 	if (priv->rdch != NULL && (prio & SD_F_PRIO_RD))
201 		CHN_UNLOCK(priv->rdch);
202 	if (priv->wrch != NULL && (prio & SD_F_PRIO_WR))
203 		CHN_UNLOCK(priv->wrch);
204 }
205 
206 /* duplex / simplex cdev type */
207 enum {
208 	DSP_CDEV_TYPE_RDONLY,		/* simplex read-only (record)   */
209 	DSP_CDEV_TYPE_WRONLY,		/* simplex write-only (play)    */
210 	DSP_CDEV_TYPE_RDWR		/* duplex read, write, or both  */
211 };
212 
213 #define DSP_F_VALID(x)		((x) & (FREAD | FWRITE))
214 #define DSP_F_DUPLEX(x)		(((x) & (FREAD | FWRITE)) == (FREAD | FWRITE))
215 #define DSP_F_SIMPLEX(x)	(!DSP_F_DUPLEX(x))
216 #define DSP_F_READ(x)		((x) & FREAD)
217 #define DSP_F_WRITE(x)		((x) & FWRITE)
218 
219 static const struct {
220 	int type;
221 	char *name;
222 	char *sep;
223 	char *alias;
224 	int use_sep;
225 	int hw;
226 	int max;
227 	int volctl;
228 	uint32_t fmt, spd;
229 	int query;
230 } dsp_cdevs[] = {
231 	{ SND_DEV_DSP,         "dsp",    ".", NULL, 0, 0, 0, 0,
232 	  SND_FORMAT(AFMT_U8, 1, 0),     DSP_DEFAULT_SPEED,
233 	  DSP_CDEV_TYPE_RDWR },
234 	{ SND_DEV_AUDIO,       "audio",  ".", NULL, 0, 0, 0, 0,
235 	  SND_FORMAT(AFMT_MU_LAW, 1, 0), DSP_DEFAULT_SPEED,
236 	  DSP_CDEV_TYPE_RDWR },
237 	{ SND_DEV_DSP16,       "dspW",   ".", NULL, 0, 0, 0, 0,
238 	  SND_FORMAT(AFMT_S16_LE, 1, 0), DSP_DEFAULT_SPEED,
239 	  DSP_CDEV_TYPE_RDWR },
240 	{ SND_DEV_DSPHW_PLAY,  "dsp",   ".p", NULL, 1, 1, SND_MAXHWCHAN, 1,
241 	  SND_FORMAT(AFMT_S16_LE, 2, 0), 48000, DSP_CDEV_TYPE_WRONLY },
242 	{ SND_DEV_DSPHW_VPLAY, "dsp",  ".vp", NULL, 1, 1, SND_MAXVCHANS, 1,
243 	  SND_FORMAT(AFMT_S16_LE, 2, 0), 48000, DSP_CDEV_TYPE_WRONLY },
244 	{ SND_DEV_DSPHW_REC,   "dsp",   ".r", NULL, 1, 1, SND_MAXHWCHAN, 1,
245 	  SND_FORMAT(AFMT_S16_LE, 2, 0), 48000, DSP_CDEV_TYPE_RDONLY },
246 	{ SND_DEV_DSPHW_VREC,  "dsp",  ".vr", NULL, 1, 1, SND_MAXVCHANS, 1,
247 	  SND_FORMAT(AFMT_S16_LE, 2, 0), 48000, DSP_CDEV_TYPE_RDONLY },
248 	{ SND_DEV_DSPHW_CD,    "dspcd",  ".", NULL, 0, 0, 0, 0,
249 	  SND_FORMAT(AFMT_S16_LE, 2, 0), 44100, DSP_CDEV_TYPE_RDWR   },
250 	/* Low priority, OSSv4 aliases. */
251 	{ SND_DEV_DSP,      "dsp_ac3",   ".", "dsp", 0, 0, 0, 0,
252 	  SND_FORMAT(AFMT_U8, 1, 0),     DSP_DEFAULT_SPEED,
253 	  DSP_CDEV_TYPE_RDWR },
254 	{ SND_DEV_DSP,     "dsp_mmap",   ".", "dsp", 0, 0, 0, 0,
255 	  SND_FORMAT(AFMT_U8, 1, 0),     DSP_DEFAULT_SPEED,
256 	  DSP_CDEV_TYPE_RDWR },
257 	{ SND_DEV_DSP,  "dsp_multich",   ".", "dsp", 0, 0, 0, 0,
258 	  SND_FORMAT(AFMT_U8, 1, 0),     DSP_DEFAULT_SPEED,
259 	  DSP_CDEV_TYPE_RDWR },
260 	{ SND_DEV_DSP, "dsp_spdifout",   ".", "dsp", 0, 0, 0, 0,
261 	  SND_FORMAT(AFMT_U8, 1, 0),     DSP_DEFAULT_SPEED,
262 	  DSP_CDEV_TYPE_RDWR },
263 	{ SND_DEV_DSP,  "dsp_spdifin",   ".", "dsp", 0, 0, 0, 0,
264 	  SND_FORMAT(AFMT_U8, 1, 0),     DSP_DEFAULT_SPEED,
265 	  DSP_CDEV_TYPE_RDWR },
266 };
267 
268 static void
269 dsp_close(void *data)
270 {
271 	struct dsp_cdevpriv *priv = data;
272 	struct pcm_channel *rdch, *wrch, *volch;
273 	struct snddev_info *d;
274 	int sg_ids, rdref, wdref;
275 
276 	if (priv == NULL)
277 		return;
278 
279 	d = priv->sc;
280 	/* At this point pcm_unregister() will destroy all channels anyway. */
281 	if (PCM_DETACHING(d))
282 		goto skip;
283 
284 	PCM_GIANT_ENTER(d);
285 
286 	PCM_LOCK(d);
287 	PCM_WAIT(d);
288 	PCM_ACQUIRE(d);
289 
290 	rdch = priv->rdch;
291 	wrch = priv->wrch;
292 	volch = priv->volch;
293 
294 	rdref = -1;
295 	wdref = -1;
296 
297 	if (volch != NULL) {
298 		if (volch == rdch)
299 			rdref--;
300 		else if (volch == wrch)
301 			wdref--;
302 		else {
303 			CHN_LOCK(volch);
304 			chn_ref(volch, -1);
305 			CHN_UNLOCK(volch);
306 		}
307 	}
308 
309 	if (rdch != NULL)
310 		CHN_REMOVE(d, rdch, channels.pcm.opened);
311 	if (wrch != NULL)
312 		CHN_REMOVE(d, wrch, channels.pcm.opened);
313 
314 	if (rdch != NULL || wrch != NULL) {
315 		PCM_UNLOCK(d);
316 		if (rdch != NULL) {
317 			/*
318 			 * The channel itself need not be locked because:
319 			 *   a)  Adding a channel to a syncgroup happens only
320 			 *       in dsp_ioctl(), which cannot run concurrently
321 			 *       to dsp_close().
322 			 *   b)  The syncmember pointer (sm) is protected by
323 			 *       the global syncgroup list lock.
324 			 *   c)  A channel can't just disappear, invalidating
325 			 *       pointers, unless it's closed/dereferenced
326 			 *       first.
327 			 */
328 			PCM_SG_LOCK();
329 			sg_ids = chn_syncdestroy(rdch);
330 			PCM_SG_UNLOCK();
331 			if (sg_ids != 0)
332 				free_unr(pcmsg_unrhdr, sg_ids);
333 
334 			CHN_LOCK(rdch);
335 			chn_ref(rdch, rdref);
336 			chn_abort(rdch); /* won't sleep */
337 			rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
338 			    CHN_F_DEAD | CHN_F_EXCLUSIVE);
339 			chn_reset(rdch, 0, 0);
340 			chn_release(rdch);
341 		}
342 		if (wrch != NULL) {
343 			/*
344 			 * Please see block above.
345 			 */
346 			PCM_SG_LOCK();
347 			sg_ids = chn_syncdestroy(wrch);
348 			PCM_SG_UNLOCK();
349 			if (sg_ids != 0)
350 				free_unr(pcmsg_unrhdr, sg_ids);
351 
352 			CHN_LOCK(wrch);
353 			chn_ref(wrch, wdref);
354 			chn_flush(wrch); /* may sleep */
355 			wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
356 			    CHN_F_DEAD | CHN_F_EXCLUSIVE);
357 			chn_reset(wrch, 0, 0);
358 			chn_release(wrch);
359 		}
360 		PCM_LOCK(d);
361 	}
362 
363 	PCM_RELEASE(d);
364 	PCM_UNLOCK(d);
365 
366 	PCM_GIANT_LEAVE(d);
367 skip:
368 	free(priv, M_DEVBUF);
369 	priv = NULL;
370 }
371 
372 #define DSP_FIXUP_ERROR()		do {				\
373 	prio = pcm_getflags(d->dev);					\
374 	if (!DSP_F_VALID(flags))					\
375 		error = EINVAL;						\
376 	if (!DSP_F_DUPLEX(flags) &&					\
377 	    ((DSP_F_READ(flags) && d->reccount == 0) ||			\
378 	    (DSP_F_WRITE(flags) && d->playcount == 0)))			\
379 		error = ENOTSUP;					\
380 	else if (!DSP_F_DUPLEX(flags) && (prio & SD_F_SIMPLEX) &&	\
381 	    ((DSP_F_READ(flags) && (prio & SD_F_PRIO_WR)) ||		\
382 	    (DSP_F_WRITE(flags) && (prio & SD_F_PRIO_RD))))		\
383 		error = EBUSY;						\
384 } while (0)
385 
386 static int
387 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
388 {
389 	struct dsp_cdevpriv *priv;
390 	struct pcm_channel *rdch, *wrch;
391 	struct snddev_info *d;
392 	uint32_t fmt, spd, prio;
393 	int error, rderror, wrerror;
394 
395 	/* Kind of impossible.. */
396 	if (i_dev == NULL || td == NULL)
397 		return (ENODEV);
398 
399 	d = i_dev->si_drv1;
400 	if (PCM_DETACHING(d) || !PCM_REGISTERED(d))
401 		return (EBADF);
402 
403 	priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK | M_ZERO);
404 	priv->sc = d;
405 	priv->rdch = NULL;
406 	priv->wrch = NULL;
407 	priv->volch = NULL;
408 	priv->simplex = (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 1 : 0;
409 
410 	error = devfs_set_cdevpriv(priv, dsp_close);
411 	if (error != 0)
412 		return (error);
413 
414 	PCM_GIANT_ENTER(d);
415 
416 	/* Lock snddev so nobody else can monkey with it. */
417 	PCM_LOCK(d);
418 	PCM_WAIT(d);
419 
420 	error = 0;
421 	DSP_FIXUP_ERROR();
422 	if (error != 0) {
423 		PCM_UNLOCK(d);
424 		PCM_GIANT_EXIT(d);
425 		return (error);
426 	}
427 
428 	/*
429 	 * That is just enough. Acquire and unlock pcm lock so
430 	 * the other will just have to wait until we finish doing
431 	 * everything.
432 	 */
433 	PCM_ACQUIRE(d);
434 	PCM_UNLOCK(d);
435 
436 	fmt = SND_FORMAT(AFMT_U8, 1, 0);
437 	spd = DSP_DEFAULT_SPEED;
438 
439 	rdch = NULL;
440 	wrch = NULL;
441 	rderror = 0;
442 	wrerror = 0;
443 
444 	if (DSP_F_READ(flags)) {
445 		/* open for read */
446 		rderror = pcm_chnalloc(d, &rdch, PCMDIR_REC,
447 		    td->td_proc->p_pid, td->td_proc->p_comm);
448 
449 		if (rderror == 0 && chn_reset(rdch, fmt, spd) != 0)
450 			rderror = ENXIO;
451 
452 		if (rderror != 0) {
453 			if (rdch != NULL)
454 				chn_release(rdch);
455 			if (!DSP_F_DUPLEX(flags)) {
456 				PCM_RELEASE_QUICK(d);
457 				PCM_GIANT_EXIT(d);
458 				return (rderror);
459 			}
460 			rdch = NULL;
461 		} else {
462 			if (flags & O_NONBLOCK)
463 				rdch->flags |= CHN_F_NBIO;
464 			if (flags & O_EXCL)
465 				rdch->flags |= CHN_F_EXCLUSIVE;
466 			chn_ref(rdch, 1);
467 			chn_vpc_reset(rdch, SND_VOL_C_PCM, 0);
468 		 	CHN_UNLOCK(rdch);
469 		}
470 	}
471 
472 	if (DSP_F_WRITE(flags)) {
473 		/* open for write */
474 		wrerror = pcm_chnalloc(d, &wrch, PCMDIR_PLAY,
475 		    td->td_proc->p_pid, td->td_proc->p_comm);
476 
477 		if (wrerror == 0 && chn_reset(wrch, fmt, spd) != 0)
478 			wrerror = ENXIO;
479 
480 		if (wrerror != 0) {
481 			if (wrch != NULL)
482 				chn_release(wrch);
483 			if (!DSP_F_DUPLEX(flags)) {
484 				if (rdch != NULL) {
485 					/*
486 					 * Lock, deref and release previously
487 					 * created record channel
488 					 */
489 					CHN_LOCK(rdch);
490 					chn_ref(rdch, -1);
491 					chn_release(rdch);
492 				}
493 				PCM_RELEASE_QUICK(d);
494 				PCM_GIANT_EXIT(d);
495 				return (wrerror);
496 			}
497 			wrch = NULL;
498 		} else {
499 			if (flags & O_NONBLOCK)
500 				wrch->flags |= CHN_F_NBIO;
501 			if (flags & O_EXCL)
502 				wrch->flags |= CHN_F_EXCLUSIVE;
503 			chn_ref(wrch, 1);
504 			chn_vpc_reset(wrch, SND_VOL_C_PCM, 0);
505 			CHN_UNLOCK(wrch);
506 		}
507 	}
508 
509 	PCM_LOCK(d);
510 
511 	if (wrch == NULL && rdch == NULL) {
512 		PCM_RELEASE(d);
513 		PCM_UNLOCK(d);
514 		PCM_GIANT_EXIT(d);
515 		if (wrerror != 0)
516 			return (wrerror);
517 		if (rderror != 0)
518 			return (rderror);
519 		return (EINVAL);
520 	}
521 	if (rdch != NULL)
522 		CHN_INSERT_HEAD(d, rdch, channels.pcm.opened);
523 	if (wrch != NULL)
524 		CHN_INSERT_HEAD(d, wrch, channels.pcm.opened);
525 	priv->rdch = rdch;
526 	priv->wrch = wrch;
527 
528 	PCM_RELEASE(d);
529 	PCM_UNLOCK(d);
530 
531 	PCM_GIANT_LEAVE(d);
532 
533 	return (0);
534 }
535 
536 static __inline int
537 dsp_io_ops(struct dsp_cdevpriv *priv, struct uio *buf)
538 {
539 	struct snddev_info *d;
540 	struct pcm_channel **ch;
541 	int (*chn_io)(struct pcm_channel *, struct uio *);
542 	int prio, ret;
543 	pid_t runpid;
544 
545 	KASSERT(buf != NULL &&
546 	    (buf->uio_rw == UIO_READ || buf->uio_rw == UIO_WRITE),
547 	    ("%s(): io train wreck!", __func__));
548 
549 	d = priv->sc;
550 	if (PCM_DETACHING(d) || !DSP_REGISTERED(d))
551 		return (EBADF);
552 
553 	PCM_GIANT_ENTER(d);
554 
555 	switch (buf->uio_rw) {
556 	case UIO_READ:
557 		prio = SD_F_PRIO_RD;
558 		ch = &priv->rdch;
559 		chn_io = chn_read;
560 		break;
561 	case UIO_WRITE:
562 		prio = SD_F_PRIO_WR;
563 		ch = &priv->wrch;
564 		chn_io = chn_write;
565 		break;
566 	default:
567 		panic("invalid/corrupted uio direction: %d", buf->uio_rw);
568 		break;
569 	}
570 
571 	runpid = buf->uio_td->td_proc->p_pid;
572 
573 	getchns(priv, prio);
574 
575 	if (*ch == NULL || !((*ch)->flags & CHN_F_BUSY)) {
576 		if (priv->rdch != NULL || priv->wrch != NULL)
577 			relchns(priv, prio);
578 		PCM_GIANT_EXIT(d);
579 		return (EBADF);
580 	}
581 
582 	if (((*ch)->flags & (CHN_F_MMAP | CHN_F_DEAD)) ||
583 	    (((*ch)->flags & CHN_F_RUNNING) && (*ch)->pid != runpid)) {
584 		relchns(priv, prio);
585 		PCM_GIANT_EXIT(d);
586 		return (EINVAL);
587 	} else if (!((*ch)->flags & CHN_F_RUNNING)) {
588 		(*ch)->flags |= CHN_F_RUNNING;
589 		(*ch)->pid = runpid;
590 	}
591 
592 	/*
593 	 * chn_read/write must give up channel lock in order to copy bytes
594 	 * from/to userland, so up the "in progress" counter to make sure
595 	 * someone else doesn't come along and muss up the buffer.
596 	 */
597 	++(*ch)->inprog;
598 	ret = chn_io(*ch, buf);
599 	--(*ch)->inprog;
600 
601 	CHN_BROADCAST(&(*ch)->cv);
602 
603 	relchns(priv, prio);
604 
605 	PCM_GIANT_LEAVE(d);
606 
607 	return (ret);
608 }
609 
610 static int
611 dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
612 {
613 	struct dsp_cdevpriv *priv;
614 	int err;
615 
616 	if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
617 		return (err);
618 	return (dsp_io_ops(priv, buf));
619 }
620 
621 static int
622 dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
623 {
624 	struct dsp_cdevpriv *priv;
625 	int err;
626 
627 	if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
628 		return (err);
629 	return (dsp_io_ops(priv, buf));
630 }
631 
632 static int
633 dsp_ioctl_channel(struct dsp_cdevpriv *priv, struct pcm_channel *volch,
634     u_long cmd, caddr_t arg)
635 {
636 	struct snddev_info *d;
637 	struct pcm_channel *rdch, *wrch;
638 	int j, left, right, center, mute;
639 
640 	d = priv->sc;
641 	if (!PCM_REGISTERED(d) || !(pcm_getflags(d->dev) & SD_F_VPC))
642 		return (-1);
643 
644 	PCM_UNLOCKASSERT(d);
645 
646 	j = cmd & 0xff;
647 
648 	rdch = priv->rdch;
649 	wrch = priv->wrch;
650 
651 	/* No specific channel, look into cache */
652 	if (volch == NULL)
653 		volch = priv->volch;
654 
655 	/* Look harder */
656 	if (volch == NULL) {
657 		if (j == SOUND_MIXER_RECLEV && rdch != NULL)
658 			volch = rdch;
659 		else if (j == SOUND_MIXER_PCM && wrch != NULL)
660 			volch = wrch;
661 	}
662 
663 	/* Final validation */
664 	if (volch == NULL)
665 		return (EINVAL);
666 
667 	CHN_LOCK(volch);
668 	if (!(volch->feederflags & (1 << FEEDER_VOLUME))) {
669 		CHN_UNLOCK(volch);
670 		return (EINVAL);
671 	}
672 
673 	switch (cmd & ~0xff) {
674 	case MIXER_WRITE(0):
675 		switch (j) {
676 		case SOUND_MIXER_MUTE:
677 			if (volch->direction == PCMDIR_REC) {
678 				chn_setmute_multi(volch, SND_VOL_C_PCM, (*(int *)arg & SOUND_MASK_RECLEV) != 0);
679 			} else {
680 				chn_setmute_multi(volch, SND_VOL_C_PCM, (*(int *)arg & SOUND_MASK_PCM) != 0);
681 			}
682 			break;
683 		case SOUND_MIXER_PCM:
684 			if (volch->direction != PCMDIR_PLAY)
685 				break;
686 			left = *(int *)arg & 0x7f;
687 			right = ((*(int *)arg) >> 8) & 0x7f;
688 			center = (left + right) >> 1;
689 			chn_setvolume_multi(volch, SND_VOL_C_PCM,
690 			    left, right, center);
691 			break;
692 		case SOUND_MIXER_RECLEV:
693 			if (volch->direction != PCMDIR_REC)
694 				break;
695 			left = *(int *)arg & 0x7f;
696 			right = ((*(int *)arg) >> 8) & 0x7f;
697 			center = (left + right) >> 1;
698 			chn_setvolume_multi(volch, SND_VOL_C_PCM,
699 			    left, right, center);
700 			break;
701 		default:
702 			/* ignore all other mixer writes */
703 			break;
704 		}
705 		break;
706 
707 	case MIXER_READ(0):
708 		switch (j) {
709 		case SOUND_MIXER_MUTE:
710 			mute = CHN_GETMUTE(volch, SND_VOL_C_PCM, SND_CHN_T_FL) ||
711 			    CHN_GETMUTE(volch, SND_VOL_C_PCM, SND_CHN_T_FR);
712 			if (volch->direction == PCMDIR_REC) {
713 				*(int *)arg = mute << SOUND_MIXER_RECLEV;
714 			} else {
715 				*(int *)arg = mute << SOUND_MIXER_PCM;
716 			}
717 			break;
718 		case SOUND_MIXER_PCM:
719 			if (volch->direction != PCMDIR_PLAY)
720 				break;
721 			*(int *)arg = CHN_GETVOLUME(volch,
722 			    SND_VOL_C_PCM, SND_CHN_T_FL);
723 			*(int *)arg |= CHN_GETVOLUME(volch,
724 			    SND_VOL_C_PCM, SND_CHN_T_FR) << 8;
725 			break;
726 		case SOUND_MIXER_RECLEV:
727 			if (volch->direction != PCMDIR_REC)
728 				break;
729 			*(int *)arg = CHN_GETVOLUME(volch,
730 			    SND_VOL_C_PCM, SND_CHN_T_FL);
731 			*(int *)arg |= CHN_GETVOLUME(volch,
732 			    SND_VOL_C_PCM, SND_CHN_T_FR) << 8;
733 			break;
734 		case SOUND_MIXER_DEVMASK:
735 		case SOUND_MIXER_CAPS:
736 		case SOUND_MIXER_STEREODEVS:
737 			if (volch->direction == PCMDIR_REC)
738 				*(int *)arg = SOUND_MASK_RECLEV;
739 			else
740 				*(int *)arg = SOUND_MASK_PCM;
741 			break;
742 		default:
743 			*(int *)arg = 0;
744 			break;
745 		}
746 		break;
747 
748 	default:
749 		break;
750 	}
751 	CHN_UNLOCK(volch);
752 	return (0);
753 }
754 
755 static int
756 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
757     struct thread *td)
758 {
759 	struct dsp_cdevpriv *priv;
760     	struct pcm_channel *chn, *rdch, *wrch;
761 	struct snddev_info *d;
762 	u_long xcmd;
763 	int *arg_i, ret, tmp, err;
764 
765 	if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
766 		return (err);
767 
768 	d = priv->sc;
769 	if (PCM_DETACHING(d) || !DSP_REGISTERED(d))
770 		return (EBADF);
771 
772 	PCM_GIANT_ENTER(d);
773 
774 	arg_i = (int *)arg;
775 	ret = 0;
776 	xcmd = 0;
777 	chn = NULL;
778 
779 	if (IOCGROUP(cmd) == 'M') {
780 		if (cmd == OSS_GETVERSION) {
781 			*arg_i = SOUND_VERSION;
782 			PCM_GIANT_EXIT(d);
783 			return (0);
784 		}
785 		ret = dsp_ioctl_channel(priv, priv->volch, cmd, arg);
786 		if (ret != -1) {
787 			PCM_GIANT_EXIT(d);
788 			return (ret);
789 		}
790 
791 		if (d->mixer_dev != NULL) {
792 			PCM_ACQUIRE_QUICK(d);
793 			ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
794 			    MIXER_CMD_DIRECT);
795 			PCM_RELEASE_QUICK(d);
796 		} else
797 			ret = EBADF;
798 
799 		PCM_GIANT_EXIT(d);
800 
801 		return (ret);
802 	}
803 
804 	/*
805 	 * Certain ioctls may be made on any type of device (audio, mixer,
806 	 * and MIDI).  Handle those special cases here.
807 	 */
808 	if (IOCGROUP(cmd) == 'X') {
809 		PCM_ACQUIRE_QUICK(d);
810 		switch(cmd) {
811 		case SNDCTL_SYSINFO:
812 			sound_oss_sysinfo((oss_sysinfo *)arg);
813 			break;
814 		case SNDCTL_CARDINFO:
815 			ret = sound_oss_card_info((oss_card_info *)arg);
816 			break;
817 		case SNDCTL_AUDIOINFO:
818 		case SNDCTL_AUDIOINFO_EX:
819 		case SNDCTL_ENGINEINFO:
820 			ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg);
821 			break;
822 		case SNDCTL_MIXERINFO:
823 			ret = mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg);
824 			break;
825 		default:
826 			ret = EINVAL;
827 		}
828 		PCM_RELEASE_QUICK(d);
829 		PCM_GIANT_EXIT(d);
830 		return (ret);
831 	}
832 
833 	getchns(priv, 0);
834 	rdch = priv->rdch;
835 	wrch = priv->wrch;
836 
837 	if (wrch != NULL && (wrch->flags & CHN_F_DEAD))
838 		wrch = NULL;
839 	if (rdch != NULL && (rdch->flags & CHN_F_DEAD))
840 		rdch = NULL;
841 
842 	if (wrch == NULL && rdch == NULL) {
843 		PCM_GIANT_EXIT(d);
844 		return (EINVAL);
845 	}
846 
847     	switch(cmd) {
848 #ifdef OLDPCM_IOCTL
849     	/*
850      	 * we start with the new ioctl interface.
851      	 */
852     	case AIONWRITE:	/* how many bytes can write ? */
853 		if (wrch) {
854 			CHN_LOCK(wrch);
855 /*
856 		if (wrch && wrch->bufhard.dl)
857 			while (chn_wrfeed(wrch) == 0);
858 */
859 			*arg_i = sndbuf_getfree(wrch->bufsoft);
860 			CHN_UNLOCK(wrch);
861 		} else {
862 			*arg_i = 0;
863 			ret = EINVAL;
864 		}
865 		break;
866 
867     	case AIOSSIZE:     /* set the current blocksize */
868 		{
869 	    		struct snd_size *p = (struct snd_size *)arg;
870 
871 			p->play_size = 0;
872 			p->rec_size = 0;
873 			PCM_ACQUIRE_QUICK(d);
874 	    		if (wrch) {
875 				CHN_LOCK(wrch);
876 				chn_setblocksize(wrch, 2, p->play_size);
877 				p->play_size = sndbuf_getblksz(wrch->bufsoft);
878 				CHN_UNLOCK(wrch);
879 			}
880 	    		if (rdch) {
881 				CHN_LOCK(rdch);
882 				chn_setblocksize(rdch, 2, p->rec_size);
883 				p->rec_size = sndbuf_getblksz(rdch->bufsoft);
884 				CHN_UNLOCK(rdch);
885 			}
886 			PCM_RELEASE_QUICK(d);
887 		}
888 		break;
889     	case AIOGSIZE:	/* get the current blocksize */
890 		{
891 	    		struct snd_size *p = (struct snd_size *)arg;
892 
893 	    		if (wrch) {
894 				CHN_LOCK(wrch);
895 				p->play_size = sndbuf_getblksz(wrch->bufsoft);
896 				CHN_UNLOCK(wrch);
897 			}
898 	    		if (rdch) {
899 				CHN_LOCK(rdch);
900 				p->rec_size = sndbuf_getblksz(rdch->bufsoft);
901 				CHN_UNLOCK(rdch);
902 			}
903 		}
904 		break;
905 
906     	case AIOSFMT:
907     	case AIOGFMT:
908 		{
909 	    		snd_chan_param *p = (snd_chan_param *)arg;
910 
911 			if (cmd == AIOSFMT &&
912 			    ((p->play_format != 0 && p->play_rate == 0) ||
913 			    (p->rec_format != 0 && p->rec_rate == 0))) {
914 				ret = EINVAL;
915 				break;
916 			}
917 			PCM_ACQUIRE_QUICK(d);
918 	    		if (wrch) {
919 				CHN_LOCK(wrch);
920 				if (cmd == AIOSFMT && p->play_format != 0) {
921 					chn_setformat(wrch,
922 					    SND_FORMAT(p->play_format,
923 					    AFMT_CHANNEL(wrch->format),
924 					    AFMT_EXTCHANNEL(wrch->format)));
925 					chn_setspeed(wrch, p->play_rate);
926 				}
927 	    			p->play_rate = wrch->speed;
928 	    			p->play_format = AFMT_ENCODING(wrch->format);
929 				CHN_UNLOCK(wrch);
930 			} else {
931 	    			p->play_rate = 0;
932 	    			p->play_format = 0;
933 	    		}
934 	    		if (rdch) {
935 				CHN_LOCK(rdch);
936 				if (cmd == AIOSFMT && p->rec_format != 0) {
937 					chn_setformat(rdch,
938 					    SND_FORMAT(p->rec_format,
939 					    AFMT_CHANNEL(rdch->format),
940 					    AFMT_EXTCHANNEL(rdch->format)));
941 					chn_setspeed(rdch, p->rec_rate);
942 				}
943 				p->rec_rate = rdch->speed;
944 				p->rec_format = AFMT_ENCODING(rdch->format);
945 				CHN_UNLOCK(rdch);
946 			} else {
947 	    			p->rec_rate = 0;
948 	    			p->rec_format = 0;
949 	    		}
950 			PCM_RELEASE_QUICK(d);
951 		}
952 		break;
953 
954     	case AIOGCAP:     /* get capabilities */
955 		{
956 	    		snd_capabilities *p = (snd_capabilities *)arg;
957 			struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
958 			struct cdev *pdev;
959 
960 			PCM_LOCK(d);
961 			if (rdch) {
962 				CHN_LOCK(rdch);
963 				rcaps = chn_getcaps(rdch);
964 			}
965 			if (wrch) {
966 				CHN_LOCK(wrch);
967 				pcaps = chn_getcaps(wrch);
968 			}
969 	    		p->rate_min = max(rcaps? rcaps->minspeed : 0,
970 	                      		  pcaps? pcaps->minspeed : 0);
971 	    		p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
972 	                      		  pcaps? pcaps->maxspeed : 1000000);
973 	    		p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
974 	                     		 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
975 			/* XXX bad on sb16 */
976 	    		p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
977 			 	     (wrch? chn_getformats(wrch) : 0xffffffff);
978 			if (rdch && wrch) {
979 				p->formats |=
980 				    (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 0 :
981 				    AFMT_FULLDUPLEX;
982 			}
983 			pdev = d->mixer_dev;
984 	    		p->mixers = 1; /* default: one mixer */
985 	    		p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
986 	    		p->left = p->right = 100;
987 			if (wrch)
988 				CHN_UNLOCK(wrch);
989 			if (rdch)
990 				CHN_UNLOCK(rdch);
991 			PCM_UNLOCK(d);
992 		}
993 		break;
994 
995     	case AIOSTOP:
996 		if (*arg_i == AIOSYNC_PLAY && wrch) {
997 			CHN_LOCK(wrch);
998 			*arg_i = chn_abort(wrch);
999 			CHN_UNLOCK(wrch);
1000 		} else if (*arg_i == AIOSYNC_CAPTURE && rdch) {
1001 			CHN_LOCK(rdch);
1002 			*arg_i = chn_abort(rdch);
1003 			CHN_UNLOCK(rdch);
1004 		} else {
1005 	   	 	printf("AIOSTOP: bad channel 0x%x\n", *arg_i);
1006 	    		*arg_i = 0;
1007 		}
1008 		break;
1009 
1010     	case AIOSYNC:
1011 		printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
1012 	    		((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
1013 		break;
1014 #endif
1015 	/*
1016 	 * here follow the standard ioctls (filio.h etc.)
1017 	 */
1018     	case FIONREAD: /* get # bytes to read */
1019 		if (rdch) {
1020 			CHN_LOCK(rdch);
1021 /*			if (rdch && rdch->bufhard.dl)
1022 				while (chn_rdfeed(rdch) == 0);
1023 */
1024 			*arg_i = sndbuf_getready(rdch->bufsoft);
1025 			CHN_UNLOCK(rdch);
1026 		} else {
1027 			*arg_i = 0;
1028 			ret = EINVAL;
1029 		}
1030 		break;
1031 
1032     	case FIOASYNC: /*set/clear async i/o */
1033 		DEB( printf("FIOASYNC\n") ; )
1034 		break;
1035 
1036     	case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */
1037     	case FIONBIO: /* set/clear non-blocking i/o */
1038 		if (rdch) {
1039 			CHN_LOCK(rdch);
1040 			if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
1041 				rdch->flags |= CHN_F_NBIO;
1042 			else
1043 				rdch->flags &= ~CHN_F_NBIO;
1044 			CHN_UNLOCK(rdch);
1045 		}
1046 		if (wrch) {
1047 			CHN_LOCK(wrch);
1048 			if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
1049 				wrch->flags |= CHN_F_NBIO;
1050 			else
1051 				wrch->flags &= ~CHN_F_NBIO;
1052 			CHN_UNLOCK(wrch);
1053 		}
1054 		break;
1055 
1056     	/*
1057 	 * Finally, here is the linux-compatible ioctl interface
1058 	 */
1059 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
1060     	case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
1061     	case SNDCTL_DSP_GETBLKSIZE:
1062 		chn = wrch ? wrch : rdch;
1063 		if (chn) {
1064 			CHN_LOCK(chn);
1065 			*arg_i = sndbuf_getblksz(chn->bufsoft);
1066 			CHN_UNLOCK(chn);
1067 		} else {
1068 			*arg_i = 0;
1069 			ret = EINVAL;
1070 		}
1071 		break;
1072 
1073     	case SNDCTL_DSP_SETBLKSIZE:
1074 		RANGE(*arg_i, 16, 65536);
1075 		PCM_ACQUIRE_QUICK(d);
1076 		if (wrch) {
1077 			CHN_LOCK(wrch);
1078 			chn_setblocksize(wrch, 2, *arg_i);
1079 			CHN_UNLOCK(wrch);
1080 		}
1081 		if (rdch) {
1082 			CHN_LOCK(rdch);
1083 			chn_setblocksize(rdch, 2, *arg_i);
1084 			CHN_UNLOCK(rdch);
1085 		}
1086 		PCM_RELEASE_QUICK(d);
1087 		break;
1088 
1089     	case SNDCTL_DSP_RESET:
1090 		DEB(printf("dsp reset\n"));
1091 		if (wrch) {
1092 			CHN_LOCK(wrch);
1093 			chn_abort(wrch);
1094 			chn_resetbuf(wrch);
1095 			CHN_UNLOCK(wrch);
1096 		}
1097 		if (rdch) {
1098 			CHN_LOCK(rdch);
1099 			chn_abort(rdch);
1100 			chn_resetbuf(rdch);
1101 			CHN_UNLOCK(rdch);
1102 		}
1103 		break;
1104 
1105     	case SNDCTL_DSP_SYNC:
1106 		DEB(printf("dsp sync\n"));
1107 		/* chn_sync may sleep */
1108 		if (wrch) {
1109 			CHN_LOCK(wrch);
1110 			chn_sync(wrch, 0);
1111 			CHN_UNLOCK(wrch);
1112 		}
1113 		break;
1114 
1115     	case SNDCTL_DSP_SPEED:
1116 		/* chn_setspeed may sleep */
1117 		tmp = 0;
1118 		PCM_ACQUIRE_QUICK(d);
1119 		if (wrch) {
1120 			CHN_LOCK(wrch);
1121 			ret = chn_setspeed(wrch, *arg_i);
1122 			tmp = wrch->speed;
1123 			CHN_UNLOCK(wrch);
1124 		}
1125 		if (rdch && ret == 0) {
1126 			CHN_LOCK(rdch);
1127 			ret = chn_setspeed(rdch, *arg_i);
1128 			if (tmp == 0)
1129 				tmp = rdch->speed;
1130 			CHN_UNLOCK(rdch);
1131 		}
1132 		PCM_RELEASE_QUICK(d);
1133 		*arg_i = tmp;
1134 		break;
1135 
1136     	case SOUND_PCM_READ_RATE:
1137 		chn = wrch ? wrch : rdch;
1138 		if (chn) {
1139 			CHN_LOCK(chn);
1140 			*arg_i = chn->speed;
1141 			CHN_UNLOCK(chn);
1142 		} else {
1143 			*arg_i = 0;
1144 			ret = EINVAL;
1145 		}
1146 		break;
1147 
1148     	case SNDCTL_DSP_STEREO:
1149 		tmp = -1;
1150 		*arg_i = (*arg_i)? 2 : 1;
1151 		PCM_ACQUIRE_QUICK(d);
1152 		if (wrch) {
1153 			CHN_LOCK(wrch);
1154 			ret = chn_setformat(wrch,
1155 			    SND_FORMAT(wrch->format, *arg_i, 0));
1156 			tmp = (AFMT_CHANNEL(wrch->format) > 1)? 1 : 0;
1157 			CHN_UNLOCK(wrch);
1158 		}
1159 		if (rdch && ret == 0) {
1160 			CHN_LOCK(rdch);
1161 			ret = chn_setformat(rdch,
1162 			    SND_FORMAT(rdch->format, *arg_i, 0));
1163 			if (tmp == -1)
1164 				tmp = (AFMT_CHANNEL(rdch->format) > 1)? 1 : 0;
1165 			CHN_UNLOCK(rdch);
1166 		}
1167 		PCM_RELEASE_QUICK(d);
1168 		*arg_i = tmp;
1169 		break;
1170 
1171     	case SOUND_PCM_WRITE_CHANNELS:
1172 /*	case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
1173 		if (*arg_i < 0 || *arg_i > AFMT_CHANNEL_MAX) {
1174 			*arg_i = 0;
1175 			ret = EINVAL;
1176 			break;
1177 		}
1178 		if (*arg_i != 0) {
1179 			uint32_t ext = 0;
1180 
1181 			tmp = 0;
1182 			/*
1183 			 * Map channel number to surround sound formats.
1184 			 * Devices that need bitperfect mode to operate
1185 			 * (e.g. more than SND_CHN_MAX channels) are not
1186 			 * subject to any mapping.
1187 			 */
1188 			if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
1189 				struct pcmchan_matrix *m;
1190 
1191 				if (*arg_i > SND_CHN_MAX)
1192 					*arg_i = SND_CHN_MAX;
1193 
1194 				m = feeder_matrix_default_channel_map(*arg_i);
1195 				if (m != NULL)
1196 					ext = m->ext;
1197 			}
1198 
1199 			PCM_ACQUIRE_QUICK(d);
1200 	  		if (wrch) {
1201 				CHN_LOCK(wrch);
1202 				ret = chn_setformat(wrch,
1203 				    SND_FORMAT(wrch->format, *arg_i, ext));
1204 				tmp = AFMT_CHANNEL(wrch->format);
1205 				CHN_UNLOCK(wrch);
1206 			}
1207 			if (rdch && ret == 0) {
1208 				CHN_LOCK(rdch);
1209 				ret = chn_setformat(rdch,
1210 				    SND_FORMAT(rdch->format, *arg_i, ext));
1211 				if (tmp == 0)
1212 					tmp = AFMT_CHANNEL(rdch->format);
1213 				CHN_UNLOCK(rdch);
1214 			}
1215 			PCM_RELEASE_QUICK(d);
1216 			*arg_i = tmp;
1217 		} else {
1218 			chn = wrch ? wrch : rdch;
1219 			CHN_LOCK(chn);
1220 			*arg_i = AFMT_CHANNEL(chn->format);
1221 			CHN_UNLOCK(chn);
1222 		}
1223 		break;
1224 
1225     	case SOUND_PCM_READ_CHANNELS:
1226 		chn = wrch ? wrch : rdch;
1227 		if (chn) {
1228 			CHN_LOCK(chn);
1229 			*arg_i = AFMT_CHANNEL(chn->format);
1230 			CHN_UNLOCK(chn);
1231 		} else {
1232 			*arg_i = 0;
1233 			ret = EINVAL;
1234 		}
1235 		break;
1236 
1237     	case SNDCTL_DSP_GETFMTS:	/* returns a mask of supported fmts */
1238 		chn = wrch ? wrch : rdch;
1239 		if (chn) {
1240 			CHN_LOCK(chn);
1241 			*arg_i = chn_getformats(chn);
1242 			CHN_UNLOCK(chn);
1243 		} else {
1244 			*arg_i = 0;
1245 			ret = EINVAL;
1246 		}
1247 		break;
1248 
1249     	case SNDCTL_DSP_SETFMT:	/* sets _one_ format */
1250 		if (*arg_i != AFMT_QUERY) {
1251 			tmp = 0;
1252 			PCM_ACQUIRE_QUICK(d);
1253 			if (wrch) {
1254 				CHN_LOCK(wrch);
1255 				ret = chn_setformat(wrch, SND_FORMAT(*arg_i,
1256 				    AFMT_CHANNEL(wrch->format),
1257 				    AFMT_EXTCHANNEL(wrch->format)));
1258 				tmp = wrch->format;
1259 				CHN_UNLOCK(wrch);
1260 			}
1261 			if (rdch && ret == 0) {
1262 				CHN_LOCK(rdch);
1263 				ret = chn_setformat(rdch, SND_FORMAT(*arg_i,
1264 				    AFMT_CHANNEL(rdch->format),
1265 				    AFMT_EXTCHANNEL(rdch->format)));
1266 				if (tmp == 0)
1267 					tmp = rdch->format;
1268 				CHN_UNLOCK(rdch);
1269 			}
1270 			PCM_RELEASE_QUICK(d);
1271 			*arg_i = AFMT_ENCODING(tmp);
1272 		} else {
1273 			chn = wrch ? wrch : rdch;
1274 			CHN_LOCK(chn);
1275 			*arg_i = AFMT_ENCODING(chn->format);
1276 			CHN_UNLOCK(chn);
1277 		}
1278 		break;
1279 
1280     	case SNDCTL_DSP_SETFRAGMENT:
1281 		DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
1282 		{
1283 			uint32_t fragln = (*arg_i) & 0x0000ffff;
1284 			uint32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
1285 			uint32_t fragsz;
1286 			uint32_t r_maxfrags, r_fragsz;
1287 
1288 			RANGE(fragln, 4, 16);
1289 			fragsz = 1 << fragln;
1290 
1291 			if (maxfrags == 0)
1292 				maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
1293 			if (maxfrags < 2)
1294 				maxfrags = 2;
1295 			if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
1296 				maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
1297 
1298 			DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
1299 			PCM_ACQUIRE_QUICK(d);
1300 		    	if (rdch) {
1301 				CHN_LOCK(rdch);
1302 				ret = chn_setblocksize(rdch, maxfrags, fragsz);
1303 				r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
1304 				r_fragsz = sndbuf_getblksz(rdch->bufsoft);
1305 				CHN_UNLOCK(rdch);
1306 			} else {
1307 				r_maxfrags = maxfrags;
1308 				r_fragsz = fragsz;
1309 			}
1310 		    	if (wrch && ret == 0) {
1311 				CHN_LOCK(wrch);
1312 				ret = chn_setblocksize(wrch, maxfrags, fragsz);
1313  				maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
1314 				fragsz = sndbuf_getblksz(wrch->bufsoft);
1315 				CHN_UNLOCK(wrch);
1316 			} else { /* use whatever came from the read channel */
1317 				maxfrags = r_maxfrags;
1318 				fragsz = r_fragsz;
1319 			}
1320 			PCM_RELEASE_QUICK(d);
1321 
1322 			fragln = 0;
1323 			while (fragsz > 1) {
1324 				fragln++;
1325 				fragsz >>= 1;
1326 			}
1327 	    		*arg_i = (maxfrags << 16) | fragln;
1328 		}
1329 		break;
1330 
1331     	case SNDCTL_DSP_GETISPACE:
1332 		/* return the size of data available in the input queue */
1333 		{
1334 	    		audio_buf_info *a = (audio_buf_info *)arg;
1335 	    		if (rdch) {
1336 	        		struct snd_dbuf *bs = rdch->bufsoft;
1337 
1338 				CHN_LOCK(rdch);
1339 				a->bytes = sndbuf_getready(bs);
1340 	        		a->fragments = a->bytes / sndbuf_getblksz(bs);
1341 	        		a->fragstotal = sndbuf_getblkcnt(bs);
1342 	        		a->fragsize = sndbuf_getblksz(bs);
1343 				CHN_UNLOCK(rdch);
1344 	    		} else
1345 				ret = EINVAL;
1346 		}
1347 		break;
1348 
1349     	case SNDCTL_DSP_GETOSPACE:
1350 		/* return space available in the output queue */
1351 		{
1352 	    		audio_buf_info *a = (audio_buf_info *)arg;
1353 	    		if (wrch) {
1354 	        		struct snd_dbuf *bs = wrch->bufsoft;
1355 
1356 				CHN_LOCK(wrch);
1357 				/* XXX abusive DMA update: chn_wrupdate(wrch); */
1358 				a->bytes = sndbuf_getfree(bs);
1359 	        		a->fragments = a->bytes / sndbuf_getblksz(bs);
1360 	        		a->fragstotal = sndbuf_getblkcnt(bs);
1361 	        		a->fragsize = sndbuf_getblksz(bs);
1362 				CHN_UNLOCK(wrch);
1363 	    		} else
1364 				ret = EINVAL;
1365 		}
1366 		break;
1367 
1368     	case SNDCTL_DSP_GETIPTR:
1369 		{
1370 	    		count_info *a = (count_info *)arg;
1371 	    		if (rdch) {
1372 	        		struct snd_dbuf *bs = rdch->bufsoft;
1373 
1374 				CHN_LOCK(rdch);
1375 				/* XXX abusive DMA update: chn_rdupdate(rdch); */
1376 	        		a->bytes = sndbuf_gettotal(bs);
1377 	        		a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
1378 	        		a->ptr = sndbuf_getfreeptr(bs);
1379 				rdch->blocks = sndbuf_getblocks(bs);
1380 				CHN_UNLOCK(rdch);
1381 	    		} else
1382 				ret = EINVAL;
1383 		}
1384 		break;
1385 
1386     	case SNDCTL_DSP_GETOPTR:
1387 		{
1388 	    		count_info *a = (count_info *)arg;
1389 	    		if (wrch) {
1390 	        		struct snd_dbuf *bs = wrch->bufsoft;
1391 
1392 				CHN_LOCK(wrch);
1393 				/* XXX abusive DMA update: chn_wrupdate(wrch); */
1394 	        		a->bytes = sndbuf_gettotal(bs);
1395 	        		a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
1396 	        		a->ptr = sndbuf_getreadyptr(bs);
1397 				wrch->blocks = sndbuf_getblocks(bs);
1398 				CHN_UNLOCK(wrch);
1399 	    		} else
1400 				ret = EINVAL;
1401 		}
1402 		break;
1403 
1404     	case SNDCTL_DSP_GETCAPS:
1405 		PCM_LOCK(d);
1406 		*arg_i = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER;
1407 		if (rdch && wrch && !(pcm_getflags(d->dev) & SD_F_SIMPLEX))
1408 			*arg_i |= PCM_CAP_DUPLEX;
1409 		if (rdch && (rdch->flags & CHN_F_VIRTUAL) != 0)
1410 			*arg_i |= PCM_CAP_VIRTUAL;
1411 		if (wrch && (wrch->flags & CHN_F_VIRTUAL) != 0)
1412 			*arg_i |= PCM_CAP_VIRTUAL;
1413 		PCM_UNLOCK(d);
1414 		break;
1415 
1416     	case SOUND_PCM_READ_BITS:
1417 		chn = wrch ? wrch : rdch;
1418 		if (chn) {
1419 			CHN_LOCK(chn);
1420 			if (chn->format & AFMT_8BIT)
1421 				*arg_i = 8;
1422 			else if (chn->format & AFMT_16BIT)
1423 				*arg_i = 16;
1424 			else if (chn->format & AFMT_24BIT)
1425 				*arg_i = 24;
1426 			else if (chn->format & AFMT_32BIT)
1427 				*arg_i = 32;
1428 			else
1429 				ret = EINVAL;
1430 			CHN_UNLOCK(chn);
1431 		} else {
1432 			*arg_i = 0;
1433 			ret = EINVAL;
1434 		}
1435 		break;
1436 
1437     	case SNDCTL_DSP_SETTRIGGER:
1438 		if (rdch) {
1439 			CHN_LOCK(rdch);
1440 			rdch->flags &= ~CHN_F_NOTRIGGER;
1441 		    	if (*arg_i & PCM_ENABLE_INPUT)
1442 				chn_start(rdch, 1);
1443 			else {
1444 				chn_abort(rdch);
1445 				chn_resetbuf(rdch);
1446 				rdch->flags |= CHN_F_NOTRIGGER;
1447 			}
1448 			CHN_UNLOCK(rdch);
1449 		}
1450 		if (wrch) {
1451 			CHN_LOCK(wrch);
1452 			wrch->flags &= ~CHN_F_NOTRIGGER;
1453 		    	if (*arg_i & PCM_ENABLE_OUTPUT)
1454 				chn_start(wrch, 1);
1455 			else {
1456 				chn_abort(wrch);
1457 				chn_resetbuf(wrch);
1458 				wrch->flags |= CHN_F_NOTRIGGER;
1459 			}
1460 			CHN_UNLOCK(wrch);
1461 		}
1462 		break;
1463 
1464     	case SNDCTL_DSP_GETTRIGGER:
1465 		*arg_i = 0;
1466 		if (wrch) {
1467 			CHN_LOCK(wrch);
1468 			if (wrch->flags & CHN_F_TRIGGERED)
1469 				*arg_i |= PCM_ENABLE_OUTPUT;
1470 			CHN_UNLOCK(wrch);
1471 		}
1472 		if (rdch) {
1473 			CHN_LOCK(rdch);
1474 			if (rdch->flags & CHN_F_TRIGGERED)
1475 				*arg_i |= PCM_ENABLE_INPUT;
1476 			CHN_UNLOCK(rdch);
1477 		}
1478 		break;
1479 
1480 	case SNDCTL_DSP_GETODELAY:
1481 		if (wrch) {
1482 	        	struct snd_dbuf *bs = wrch->bufsoft;
1483 
1484 			CHN_LOCK(wrch);
1485 			/* XXX abusive DMA update: chn_wrupdate(wrch); */
1486 			*arg_i = sndbuf_getready(bs);
1487 			CHN_UNLOCK(wrch);
1488 		} else
1489 			ret = EINVAL;
1490 		break;
1491 
1492     	case SNDCTL_DSP_POST:
1493 		if (wrch) {
1494 			CHN_LOCK(wrch);
1495 			wrch->flags &= ~CHN_F_NOTRIGGER;
1496 			chn_start(wrch, 1);
1497 			CHN_UNLOCK(wrch);
1498 		}
1499 		break;
1500 
1501 	case SNDCTL_DSP_SETDUPLEX:
1502 		/*
1503 		 * switch to full-duplex mode if card is in half-duplex
1504 		 * mode and is able to work in full-duplex mode
1505 		 */
1506 		PCM_LOCK(d);
1507 		if (rdch && wrch && (pcm_getflags(d->dev) & SD_F_SIMPLEX))
1508 			pcm_setflags(d->dev, pcm_getflags(d->dev)^SD_F_SIMPLEX);
1509 		PCM_UNLOCK(d);
1510 		break;
1511 
1512 	/*
1513 	 * The following four ioctls are simple wrappers around mixer_ioctl
1514 	 * with no further processing.  xcmd is short for "translated
1515 	 * command".
1516 	 */
1517 	case SNDCTL_DSP_GETRECVOL:
1518 		if (xcmd == 0) {
1519 			xcmd = SOUND_MIXER_READ_RECLEV;
1520 			chn = rdch;
1521 		}
1522 		/* FALLTHROUGH */
1523 	case SNDCTL_DSP_SETRECVOL:
1524 		if (xcmd == 0) {
1525 			xcmd = SOUND_MIXER_WRITE_RECLEV;
1526 			chn = rdch;
1527 		}
1528 		/* FALLTHROUGH */
1529 	case SNDCTL_DSP_GETPLAYVOL:
1530 		if (xcmd == 0) {
1531 			xcmd = SOUND_MIXER_READ_PCM;
1532 			chn = wrch;
1533 		}
1534 		/* FALLTHROUGH */
1535 	case SNDCTL_DSP_SETPLAYVOL:
1536 		if (xcmd == 0) {
1537 			xcmd = SOUND_MIXER_WRITE_PCM;
1538 			chn = wrch;
1539 		}
1540 
1541 		ret = dsp_ioctl_channel(priv, chn, xcmd, arg);
1542 		if (ret != -1) {
1543 			PCM_GIANT_EXIT(d);
1544 			return (ret);
1545 		}
1546 
1547 		if (d->mixer_dev != NULL) {
1548 			PCM_ACQUIRE_QUICK(d);
1549 			ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td,
1550 			    MIXER_CMD_DIRECT);
1551 			PCM_RELEASE_QUICK(d);
1552 		} else
1553 			ret = ENOTSUP;
1554 
1555 		break;
1556 
1557 	case SNDCTL_DSP_GET_RECSRC_NAMES:
1558 	case SNDCTL_DSP_GET_RECSRC:
1559 	case SNDCTL_DSP_SET_RECSRC:
1560 		if (d->mixer_dev != NULL) {
1561 			PCM_ACQUIRE_QUICK(d);
1562 			ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
1563 			    MIXER_CMD_DIRECT);
1564 			PCM_RELEASE_QUICK(d);
1565 		} else
1566 			ret = ENOTSUP;
1567 		break;
1568 
1569 	/*
1570 	 * The following 3 ioctls aren't very useful at the moment.  For
1571 	 * now, only a single channel is associated with a cdev (/dev/dspN
1572 	 * instance), so there's only a single output routing to use (i.e.,
1573 	 * the wrch bound to this cdev).
1574 	 */
1575 	case SNDCTL_DSP_GET_PLAYTGT_NAMES:
1576 		{
1577 			oss_mixer_enuminfo *ei;
1578 			ei = (oss_mixer_enuminfo *)arg;
1579 			ei->dev = 0;
1580 			ei->ctrl = 0;
1581 			ei->version = 0; /* static for now */
1582 			ei->strindex[0] = 0;
1583 
1584 			if (wrch != NULL) {
1585 				ei->nvalues = 1;
1586 				strlcpy(ei->strings, wrch->name,
1587 					sizeof(ei->strings));
1588 			} else {
1589 				ei->nvalues = 0;
1590 				ei->strings[0] = '\0';
1591 			}
1592 		}
1593 		break;
1594 	case SNDCTL_DSP_GET_PLAYTGT:
1595 	case SNDCTL_DSP_SET_PLAYTGT:	/* yes, they are the same for now */
1596 		/*
1597 		 * Re: SET_PLAYTGT
1598 		 *   OSSv4: "The value that was accepted by the device will
1599 		 *   be returned back in the variable pointed by the
1600 		 *   argument."
1601 		 */
1602 		if (wrch != NULL)
1603 			*arg_i = 0;
1604 		else
1605 			ret = EINVAL;
1606 		break;
1607 
1608 	case SNDCTL_DSP_SILENCE:
1609 	/*
1610 	 * Flush the software (pre-feed) buffer, but try to minimize playback
1611 	 * interruption.  (I.e., record unplayed samples with intent to
1612 	 * restore by SNDCTL_DSP_SKIP.) Intended for application "pause"
1613 	 * functionality.
1614 	 */
1615 		if (wrch == NULL)
1616 			ret = EINVAL;
1617 		else {
1618 			struct snd_dbuf *bs;
1619 			CHN_LOCK(wrch);
1620 			while (wrch->inprog != 0)
1621 				cv_wait(&wrch->cv, wrch->lock);
1622 			bs = wrch->bufsoft;
1623 			if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) {
1624 				bs->sl = sndbuf_getready(bs);
1625 				sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs));
1626 				sndbuf_fillsilence(bs);
1627 				chn_start(wrch, 0);
1628 			}
1629 			CHN_UNLOCK(wrch);
1630 		}
1631 		break;
1632 
1633 	case SNDCTL_DSP_SKIP:
1634 	/*
1635 	 * OSSv4 docs: "This ioctl call discards all unplayed samples in the
1636 	 * playback buffer by moving the current write position immediately
1637 	 * before the point where the device is currently reading the samples."
1638 	 */
1639 		if (wrch == NULL)
1640 			ret = EINVAL;
1641 		else {
1642 			struct snd_dbuf *bs;
1643 			CHN_LOCK(wrch);
1644 			while (wrch->inprog != 0)
1645 				cv_wait(&wrch->cv, wrch->lock);
1646 			bs = wrch->bufsoft;
1647 			if ((bs->shadbuf != NULL) && (bs->sl > 0)) {
1648 				sndbuf_softreset(bs);
1649 				sndbuf_acquire(bs, bs->shadbuf, bs->sl);
1650 				bs->sl = 0;
1651 				chn_start(wrch, 0);
1652 			}
1653 			CHN_UNLOCK(wrch);
1654 		}
1655 		break;
1656 
1657 	case SNDCTL_DSP_CURRENT_OPTR:
1658 	case SNDCTL_DSP_CURRENT_IPTR:
1659 	/**
1660 	 * @note Changing formats resets the buffer counters, which differs
1661 	 * 	 from the 4Front drivers.  However, I don't expect this to be
1662 	 * 	 much of a problem.
1663 	 *
1664 	 * @note In a test where @c CURRENT_OPTR is called immediately after write
1665 	 * 	 returns, this driver is about 32K samples behind whereas
1666 	 * 	 4Front's is about 8K samples behind.  Should determine source
1667 	 * 	 of discrepancy, even if only out of curiosity.
1668 	 *
1669 	 * @todo Actually test SNDCTL_DSP_CURRENT_IPTR.
1670 	 */
1671 		chn = (cmd == SNDCTL_DSP_CURRENT_OPTR) ? wrch : rdch;
1672 		if (chn == NULL)
1673 			ret = EINVAL;
1674 		else {
1675 			struct snd_dbuf *bs;
1676 			/* int tmp; */
1677 
1678 			oss_count_t *oc = (oss_count_t *)arg;
1679 
1680 			CHN_LOCK(chn);
1681 			bs = chn->bufsoft;
1682 #if 0
1683 			tmp = (sndbuf_getsize(b) + chn_getptr(chn) - sndbuf_gethwptr(b)) % sndbuf_getsize(b);
1684 			oc->samples = (sndbuf_gettotal(b) + tmp) / sndbuf_getalign(b);
1685 			oc->fifo_samples = (sndbuf_getready(b) - tmp) / sndbuf_getalign(b);
1686 #else
1687 			oc->samples = sndbuf_gettotal(bs) / sndbuf_getalign(bs);
1688 			oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getalign(bs);
1689 #endif
1690 			CHN_UNLOCK(chn);
1691 		}
1692 		break;
1693 
1694 	case SNDCTL_DSP_HALT_OUTPUT:
1695 	case SNDCTL_DSP_HALT_INPUT:
1696 		chn = (cmd == SNDCTL_DSP_HALT_OUTPUT) ? wrch : rdch;
1697 		if (chn == NULL)
1698 			ret = EINVAL;
1699 		else {
1700 			CHN_LOCK(chn);
1701 			chn_abort(chn);
1702 			CHN_UNLOCK(chn);
1703 		}
1704 		break;
1705 
1706 	case SNDCTL_DSP_LOW_WATER:
1707 	/*
1708 	 * Set the number of bytes required to attract attention by
1709 	 * select/poll.
1710 	 */
1711 		if (wrch != NULL) {
1712 			CHN_LOCK(wrch);
1713 			wrch->lw = (*arg_i > 1) ? *arg_i : 1;
1714 			CHN_UNLOCK(wrch);
1715 		}
1716 		if (rdch != NULL) {
1717 			CHN_LOCK(rdch);
1718 			rdch->lw = (*arg_i > 1) ? *arg_i : 1;
1719 			CHN_UNLOCK(rdch);
1720 		}
1721 		break;
1722 
1723 	case SNDCTL_DSP_GETERROR:
1724 	/*
1725 	 * OSSv4 docs:  "All errors and counters will automatically be
1726 	 * cleared to zeroes after the call so each call will return only
1727 	 * the errors that occurred after the previous invocation. ... The
1728 	 * play_underruns and rec_overrun fields are the only useful fields
1729 	 * returned by OSS 4.0."
1730 	 */
1731 		{
1732 			audio_errinfo *ei = (audio_errinfo *)arg;
1733 
1734 			bzero((void *)ei, sizeof(*ei));
1735 
1736 			if (wrch != NULL) {
1737 				CHN_LOCK(wrch);
1738 				ei->play_underruns = wrch->xruns;
1739 				wrch->xruns = 0;
1740 				CHN_UNLOCK(wrch);
1741 			}
1742 			if (rdch != NULL) {
1743 				CHN_LOCK(rdch);
1744 				ei->rec_overruns = rdch->xruns;
1745 				rdch->xruns = 0;
1746 				CHN_UNLOCK(rdch);
1747 			}
1748 		}
1749 		break;
1750 
1751 	case SNDCTL_DSP_SYNCGROUP:
1752 		PCM_ACQUIRE_QUICK(d);
1753 		ret = dsp_oss_syncgroup(wrch, rdch, (oss_syncgroup *)arg);
1754 		PCM_RELEASE_QUICK(d);
1755 		break;
1756 
1757 	case SNDCTL_DSP_SYNCSTART:
1758 		PCM_ACQUIRE_QUICK(d);
1759 		ret = dsp_oss_syncstart(*arg_i);
1760 		PCM_RELEASE_QUICK(d);
1761 		break;
1762 
1763 	case SNDCTL_DSP_POLICY:
1764 		PCM_ACQUIRE_QUICK(d);
1765 		ret = dsp_oss_policy(wrch, rdch, *arg_i);
1766 		PCM_RELEASE_QUICK(d);
1767 		break;
1768 
1769 	case SNDCTL_DSP_COOKEDMODE:
1770 		PCM_ACQUIRE_QUICK(d);
1771 		if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT))
1772 			ret = dsp_oss_cookedmode(wrch, rdch, *arg_i);
1773 		PCM_RELEASE_QUICK(d);
1774 		break;
1775 	case SNDCTL_DSP_GET_CHNORDER:
1776 		PCM_ACQUIRE_QUICK(d);
1777 		ret = dsp_oss_getchnorder(wrch, rdch, (unsigned long long *)arg);
1778 		PCM_RELEASE_QUICK(d);
1779 		break;
1780 	case SNDCTL_DSP_SET_CHNORDER:
1781 		PCM_ACQUIRE_QUICK(d);
1782 		ret = dsp_oss_setchnorder(wrch, rdch, (unsigned long long *)arg);
1783 		PCM_RELEASE_QUICK(d);
1784 		break;
1785 	case SNDCTL_DSP_GETCHANNELMASK:		/* XXX vlc */
1786 		PCM_ACQUIRE_QUICK(d);
1787 		ret = dsp_oss_getchannelmask(wrch, rdch, (int *)arg);
1788 		PCM_RELEASE_QUICK(d);
1789 		break;
1790 	case SNDCTL_DSP_BIND_CHANNEL:		/* XXX what?!? */
1791 		ret = EINVAL;
1792 		break;
1793 #ifdef	OSSV4_EXPERIMENT
1794 	/*
1795 	 * XXX The following ioctls are not yet supported and just return
1796 	 * EINVAL.
1797 	 */
1798 	case SNDCTL_DSP_GETOPEAKS:
1799 	case SNDCTL_DSP_GETIPEAKS:
1800 		chn = (cmd == SNDCTL_DSP_GETOPEAKS) ? wrch : rdch;
1801 		if (chn == NULL)
1802 			ret = EINVAL;
1803 		else {
1804 			oss_peaks_t *op = (oss_peaks_t *)arg;
1805 			int lpeak, rpeak;
1806 
1807 			CHN_LOCK(chn);
1808 			ret = chn_getpeaks(chn, &lpeak, &rpeak);
1809 			if (ret == -1)
1810 				ret = EINVAL;
1811 			else {
1812 				(*op)[0] = lpeak;
1813 				(*op)[1] = rpeak;
1814 			}
1815 			CHN_UNLOCK(chn);
1816 		}
1817 		break;
1818 
1819 	/*
1820 	 * XXX Once implemented, revisit this for proper cv protection
1821 	 *     (if necessary).
1822 	 */
1823 	case SNDCTL_GETLABEL:
1824 		ret = dsp_oss_getlabel(wrch, rdch, (oss_label_t *)arg);
1825 		break;
1826 	case SNDCTL_SETLABEL:
1827 		ret = dsp_oss_setlabel(wrch, rdch, (oss_label_t *)arg);
1828 		break;
1829 	case SNDCTL_GETSONG:
1830 		ret = dsp_oss_getsong(wrch, rdch, (oss_longname_t *)arg);
1831 		break;
1832 	case SNDCTL_SETSONG:
1833 		ret = dsp_oss_setsong(wrch, rdch, (oss_longname_t *)arg);
1834 		break;
1835 	case SNDCTL_SETNAME:
1836 		ret = dsp_oss_setname(wrch, rdch, (oss_longname_t *)arg);
1837 		break;
1838 #if 0
1839 	/**
1840 	 * @note The S/PDIF interface ioctls, @c SNDCTL_DSP_READCTL and
1841 	 * @c SNDCTL_DSP_WRITECTL have been omitted at the suggestion of
1842 	 * 4Front Technologies.
1843 	 */
1844 	case SNDCTL_DSP_READCTL:
1845 	case SNDCTL_DSP_WRITECTL:
1846 		ret = EINVAL;
1847 		break;
1848 #endif	/* !0 (explicitly omitted ioctls) */
1849 
1850 #endif	/* !OSSV4_EXPERIMENT */
1851     	case SNDCTL_DSP_MAPINBUF:
1852     	case SNDCTL_DSP_MAPOUTBUF:
1853     	case SNDCTL_DSP_SETSYNCRO:
1854 		/* undocumented */
1855 
1856     	case SNDCTL_DSP_SUBDIVIDE:
1857     	case SOUND_PCM_WRITE_FILTER:
1858     	case SOUND_PCM_READ_FILTER:
1859 		/* dunno what these do, don't sound important */
1860 
1861     	default:
1862 		DEB(printf("default ioctl fn 0x%08lx fail\n", cmd));
1863 		ret = EINVAL;
1864 		break;
1865     	}
1866 
1867 	PCM_GIANT_LEAVE(d);
1868 
1869     	return (ret);
1870 }
1871 
1872 static int
1873 dsp_poll(struct cdev *i_dev, int events, struct thread *td)
1874 {
1875 	struct dsp_cdevpriv *priv;
1876 	struct snddev_info *d;
1877 	struct pcm_channel *wrch, *rdch;
1878 	int ret, e, err;
1879 
1880 	if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
1881 		return (err);
1882 	d = priv->sc;
1883 	if (PCM_DETACHING(d) || !DSP_REGISTERED(d)) {
1884 		/* XXX many clients don't understand POLLNVAL */
1885 		return (events & (POLLHUP | POLLPRI | POLLIN |
1886 		    POLLRDNORM | POLLOUT | POLLWRNORM));
1887 	}
1888 	PCM_GIANT_ENTER(d);
1889 
1890 	ret = 0;
1891 
1892 	getchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
1893 	wrch = priv->wrch;
1894 	rdch = priv->rdch;
1895 
1896 	if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) {
1897 		e = (events & (POLLOUT | POLLWRNORM));
1898 		if (e)
1899 			ret |= chn_poll(wrch, e, td);
1900 	}
1901 
1902 	if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) {
1903 		e = (events & (POLLIN | POLLRDNORM));
1904 		if (e)
1905 			ret |= chn_poll(rdch, e, td);
1906 	}
1907 
1908 	relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
1909 
1910 	PCM_GIANT_LEAVE(d);
1911 
1912 	return (ret);
1913 }
1914 
1915 static int
1916 dsp_mmap(struct cdev *i_dev, vm_ooffset_t offset, vm_paddr_t *paddr,
1917     int nprot, vm_memattr_t *memattr)
1918 {
1919 
1920 	/*
1921 	 * offset is in range due to checks in dsp_mmap_single().
1922 	 * XXX memattr is not honored.
1923 	 */
1924 	*paddr = vtophys(offset);
1925 	return (0);
1926 }
1927 
1928 static int
1929 dsp_mmap_single(struct cdev *i_dev, vm_ooffset_t *offset,
1930     vm_size_t size, struct vm_object **object, int nprot)
1931 {
1932 	struct dsp_cdevpriv *priv;
1933 	struct snddev_info *d;
1934 	struct pcm_channel *wrch, *rdch, *c;
1935 	int err;
1936 
1937 	/*
1938 	 * Reject PROT_EXEC by default. It just doesn't makes sense.
1939 	 * Unfortunately, we have to give up this one due to linux_mmap
1940 	 * changes.
1941 	 *
1942 	 * https://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html
1943 	 *
1944 	 */
1945 #ifdef SV_ABI_LINUX
1946 	if ((nprot & PROT_EXEC) && (dsp_mmap_allow_prot_exec < 0 ||
1947 	    (dsp_mmap_allow_prot_exec == 0 &&
1948 	    SV_CURPROC_ABI() != SV_ABI_LINUX)))
1949 #else
1950 	if ((nprot & PROT_EXEC) && dsp_mmap_allow_prot_exec < 1)
1951 #endif
1952 		return (EINVAL);
1953 
1954 	/*
1955 	 * PROT_READ (alone) selects the input buffer.
1956 	 * PROT_WRITE (alone) selects the output buffer.
1957 	 * PROT_WRITE|PROT_READ together select the output buffer.
1958 	 */
1959 	if ((nprot & (PROT_READ | PROT_WRITE)) == 0)
1960 		return (EINVAL);
1961 
1962 	if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
1963 		return (err);
1964 	d = priv->sc;
1965 	if (PCM_DETACHING(d) || !DSP_REGISTERED(d))
1966 		return (EINVAL);
1967 
1968 	PCM_GIANT_ENTER(d);
1969 
1970 	getchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
1971 	wrch = priv->wrch;
1972 	rdch = priv->rdch;
1973 
1974 	c = ((nprot & PROT_WRITE) != 0) ? wrch : rdch;
1975 	if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) ||
1976 	    (*offset  + size) > sndbuf_getallocsize(c->bufsoft) ||
1977 	    (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) ||
1978 	    (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) {
1979 		relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
1980 		PCM_GIANT_EXIT(d);
1981 		return (EINVAL);
1982 	}
1983 
1984 	if (wrch != NULL)
1985 		wrch->flags |= CHN_F_MMAP;
1986 	if (rdch != NULL)
1987 		rdch->flags |= CHN_F_MMAP;
1988 
1989 	*offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset);
1990 	relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
1991 	*object = vm_pager_allocate(OBJT_DEVICE, i_dev,
1992 	    size, nprot, *offset, curthread->td_ucred);
1993 
1994 	PCM_GIANT_LEAVE(d);
1995 
1996 	if (*object == NULL)
1997 		 return (EINVAL);
1998 	return (0);
1999 }
2000 
2001 static void
2002 dsp_clone(void *arg, struct ucred *cred, char *name, int namelen,
2003     struct cdev **dev)
2004 {
2005 	struct snddev_info *d;
2006 	int i;
2007 
2008 	if (*dev != NULL)
2009 		return;
2010 	if (strcmp(name, "dsp") == 0 && dsp_basename_clone)
2011 		goto found;
2012 	for (i = 0; i < nitems(dsp_cdevs); i++) {
2013 		if (dsp_cdevs[i].alias != NULL &&
2014 		    strcmp(name, dsp_cdevs[i].name) == 0)
2015 			goto found;
2016 	}
2017 	return;
2018 found:
2019 	bus_topo_lock();
2020 	d = devclass_get_softc(pcm_devclass, snd_unit);
2021 	/*
2022 	 * If we only have a single soundcard attached and we detach it right
2023 	 * before entering dsp_clone(), there is a chance pcm_unregister() will
2024 	 * have returned already, meaning it will have set snd_unit to -1, and
2025 	 * thus devclass_get_softc() will return NULL here.
2026 	 */
2027 	if (d != NULL && PCM_REGISTERED(d) && d->dsp_dev != NULL) {
2028 		*dev = d->dsp_dev;
2029 		dev_ref(*dev);
2030 	}
2031 	bus_topo_unlock();
2032 }
2033 
2034 static void
2035 dsp_sysinit(void *p)
2036 {
2037 	if (dsp_ehtag != NULL)
2038 		return;
2039 	dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
2040 }
2041 
2042 static void
2043 dsp_sysuninit(void *p)
2044 {
2045 	if (dsp_ehtag == NULL)
2046 		return;
2047 	EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
2048 	dsp_ehtag = NULL;
2049 }
2050 
2051 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
2052 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
2053 
2054 char *
2055 dsp_unit2name(char *buf, size_t len, struct pcm_channel *ch)
2056 {
2057 	int i;
2058 
2059 	KASSERT(buf != NULL && len != 0,
2060 	    ("bogus buf=%p len=%ju", buf, (uintmax_t)len));
2061 
2062 	for (i = 0; i < nitems(dsp_cdevs); i++) {
2063 		if (ch->type != dsp_cdevs[i].type || dsp_cdevs[i].alias != NULL)
2064 			continue;
2065 		snprintf(buf, len, "%s%d%s%d",
2066 		    dsp_cdevs[i].name, device_get_unit(ch->dev),
2067 		    dsp_cdevs[i].sep, ch->unit);
2068 		return (buf);
2069 	}
2070 
2071 	return (NULL);
2072 }
2073 
2074 static int
2075 dsp_oss_audioinfo_cb(void *data, void *arg)
2076 {
2077 	struct dsp_cdevpriv *priv = data;
2078 	struct pcm_channel *ch = arg;
2079 
2080 	if (DSP_REGISTERED(priv->sc) && (ch == priv->rdch || ch == priv->wrch))
2081 		return (1);
2082 
2083 	return (0);
2084 }
2085 
2086 /**
2087  * @brief Handler for SNDCTL_AUDIOINFO.
2088  *
2089  * Gathers information about the audio device specified in ai->dev.  If
2090  * ai->dev == -1, then this function gathers information about the current
2091  * device.  If the call comes in on a non-audio device and ai->dev == -1,
2092  * return EINVAL.
2093  *
2094  * This routine is supposed to go practically straight to the hardware,
2095  * getting capabilities directly from the sound card driver, side-stepping
2096  * the intermediate channel interface.
2097  *
2098  * @note
2099  * Calling threads must not hold any snddev_info or pcm_channel locks.
2100  *
2101  * @param dev		device on which the ioctl was issued
2102  * @param ai		ioctl request data container
2103  *
2104  * @retval 0		success
2105  * @retval EINVAL	ai->dev specifies an invalid device
2106  *
2107  * @todo Verify correctness of Doxygen tags.  ;)
2108  */
2109 int
2110 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai)
2111 {
2112 	struct pcmchan_caps *caps;
2113 	struct pcm_channel *ch;
2114 	struct snddev_info *d;
2115 	uint32_t fmts;
2116 	int i, nchan, *rates, minch, maxch, unit;
2117 	char *devname, buf[CHN_NAMELEN];
2118 
2119 	/*
2120 	 * If probing the device that received the ioctl, make sure it's a
2121 	 * DSP device.  (Users may use this ioctl with /dev/mixer and
2122 	 * /dev/midi.)
2123 	 */
2124 	if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2125 		return (EINVAL);
2126 
2127 	ch = NULL;
2128 	devname = NULL;
2129 	nchan = 0;
2130 	bzero(buf, sizeof(buf));
2131 
2132 	/*
2133 	 * Search for the requested audio device (channel).  Start by
2134 	 * iterating over pcm devices.
2135 	 */
2136 	for (unit = 0; pcm_devclass != NULL &&
2137 	    unit < devclass_get_maxunit(pcm_devclass); unit++) {
2138 		d = devclass_get_softc(pcm_devclass, unit);
2139 		if (!PCM_REGISTERED(d))
2140 			continue;
2141 
2142 		/* XXX Need Giant magic entry ??? */
2143 
2144 		/* See the note in function docblock */
2145 		PCM_UNLOCKASSERT(d);
2146 		PCM_LOCK(d);
2147 
2148 		CHN_FOREACH(ch, d, channels.pcm) {
2149 			CHN_UNLOCKASSERT(ch);
2150 			CHN_LOCK(ch);
2151 			if (ai->dev == -1) {
2152 				if (devfs_foreach_cdevpriv(i_dev,
2153 				    dsp_oss_audioinfo_cb, ch) != 0) {
2154 					devname = dsp_unit2name(buf,
2155 					    sizeof(buf), ch);
2156 				}
2157 			} else if (ai->dev == nchan)
2158 				devname = dsp_unit2name(buf, sizeof(buf), ch);
2159 			if (devname != NULL)
2160 				break;
2161 			CHN_UNLOCK(ch);
2162 			++nchan;
2163 		}
2164 
2165 		if (devname != NULL) {
2166 			/*
2167 			 * At this point, the following synchronization stuff
2168 			 * has happened:
2169 			 * - a specific PCM device is locked.
2170 			 * - a specific audio channel has been locked, so be
2171 			 *   sure to unlock when exiting;
2172 			 */
2173 
2174 			caps = chn_getcaps(ch);
2175 
2176 			/*
2177 			 * With all handles collected, zero out the user's
2178 			 * container and begin filling in its fields.
2179 			 */
2180 			bzero((void *)ai, sizeof(oss_audioinfo));
2181 
2182 			ai->dev = nchan;
2183 			strlcpy(ai->name, ch->name,  sizeof(ai->name));
2184 
2185 			if ((ch->flags & CHN_F_BUSY) == 0)
2186 				ai->busy = 0;
2187 			else
2188 				ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ;
2189 
2190 			/**
2191 			 * @note
2192 			 * @c cmd - OSSv4 docs: "Only supported under Linux at
2193 			 *    this moment." Cop-out, I know, but I'll save
2194 			 *    running around in the process table for later.
2195 			 *    Is there a risk of leaking information?
2196 			 */
2197 			ai->pid = ch->pid;
2198 
2199 			/*
2200 			 * These flags stolen from SNDCTL_DSP_GETCAPS handler.
2201 			 * Note, however, that a single channel operates in
2202 			 * only one direction, so PCM_CAP_DUPLEX is out.
2203 			 */
2204 			/**
2205 			 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep
2206 			 *       these in pcmchan::caps?
2207 			 */
2208 			ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER |
2209 			    ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) |
2210 			    ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : PCM_CAP_INPUT);
2211 
2212 			/*
2213 			 * Collect formats supported @b natively by the
2214 			 * device.  Also determine min/max channels.  (I.e.,
2215 			 * mono, stereo, or both?)
2216 			 *
2217 			 * If any channel is stereo, maxch = 2;
2218 			 * if all channels are stereo, minch = 2, too;
2219 			 * if any channel is mono, minch = 1;
2220 			 * and if all channels are mono, maxch = 1.
2221 			 */
2222 			minch = 0;
2223 			maxch = 0;
2224 			fmts = 0;
2225 			for (i = 0; caps->fmtlist[i]; i++) {
2226 				fmts |= caps->fmtlist[i];
2227 				if (AFMT_CHANNEL(caps->fmtlist[i]) > 1) {
2228 					minch = (minch == 0) ? 2 : minch;
2229 					maxch = 2;
2230 				} else {
2231 					minch = 1;
2232 					maxch = (maxch == 0) ? 1 : maxch;
2233 				}
2234 			}
2235 
2236 			if (ch->direction == PCMDIR_PLAY)
2237 				ai->oformats = fmts;
2238 			else
2239 				ai->iformats = fmts;
2240 
2241 			/**
2242 			 * @note
2243 			 * @c magic - OSSv4 docs: "Reserved for internal use
2244 			 *    by OSS."
2245 			 *
2246 			 * @par
2247 			 * @c card_number - OSSv4 docs: "Number of the sound
2248 			 *    card where this device belongs or -1 if this
2249 			 *    information is not available.  Applications
2250 			 *    should normally not use this field for any
2251 			 *    purpose."
2252 			 */
2253 			ai->card_number = -1;
2254 			/**
2255 			 * @todo @c song_name - depends first on
2256 			 *          SNDCTL_[GS]ETSONG @todo @c label - depends
2257 			 *          on SNDCTL_[GS]ETLABEL
2258 			 * @todo @c port_number - routing information?
2259 			 */
2260 			ai->port_number = -1;
2261 			ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1;
2262 			/**
2263 			 * @note
2264 			 * @c real_device - OSSv4 docs:  "Obsolete."
2265 			 */
2266 			ai->real_device = -1;
2267 			snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit);
2268 			ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2269 			/**
2270 			 * @note
2271 			 * @c flags - OSSv4 docs: "Reserved for future use."
2272 			 *
2273 			 * @note
2274 			 * @c binding - OSSv4 docs: "Reserved for future use."
2275 			 *
2276 			 * @todo @c handle - haven't decided how to generate
2277 			 *       this yet; bus, vendor, device IDs?
2278 			 */
2279 			ai->min_rate = caps->minspeed;
2280 			ai->max_rate = caps->maxspeed;
2281 
2282 			ai->min_channels = minch;
2283 			ai->max_channels = maxch;
2284 
2285 			ai->nrates = chn_getrates(ch, &rates);
2286 			if (ai->nrates > OSS_MAX_SAMPLE_RATES)
2287 				ai->nrates = OSS_MAX_SAMPLE_RATES;
2288 
2289 			for (i = 0; i < ai->nrates; i++)
2290 				ai->rates[i] = rates[i];
2291 
2292 			ai->next_play_engine = 0;
2293 			ai->next_rec_engine = 0;
2294 
2295 			CHN_UNLOCK(ch);
2296 		}
2297 
2298 		PCM_UNLOCK(d);
2299 
2300 		if (devname != NULL)
2301 			return (0);
2302 	}
2303 
2304 	/* Exhausted the search -- nothing is locked, so return. */
2305 	return (EINVAL);
2306 }
2307 
2308 /**
2309  * @brief Assigns a PCM channel to a sync group.
2310  *
2311  * Sync groups are used to enable audio operations on multiple devices
2312  * simultaneously.  They may be used with any number of devices and may
2313  * span across applications.  Devices are added to groups with
2314  * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the
2315  * SNDCTL_DSP_SYNCSTART ioctl.
2316  *
2317  * If the @c id field of the @c group parameter is set to zero, then a new
2318  * sync group is created.  Otherwise, wrch and rdch (if set) are added to
2319  * the group specified.
2320  *
2321  * @todo As far as memory allocation, should we assume that things are
2322  * 	 okay and allocate with M_WAITOK before acquiring channel locks,
2323  * 	 freeing later if not?
2324  *
2325  * @param wrch	output channel associated w/ device (if any)
2326  * @param rdch	input channel associated w/ device (if any)
2327  * @param group Sync group parameters
2328  *
2329  * @retval 0		success
2330  * @retval non-zero	error to be propagated upstream
2331  */
2332 static int
2333 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group)
2334 {
2335 	struct pcmchan_syncmember *smrd, *smwr;
2336 	struct pcmchan_syncgroup *sg;
2337 	int ret, sg_ids[3];
2338 
2339 	smrd = NULL;
2340 	smwr = NULL;
2341 	sg = NULL;
2342 	ret = 0;
2343 
2344 	/*
2345 	 * Free_unr() may sleep, so store released syncgroup IDs until after
2346 	 * all locks are released.
2347 	 */
2348 	sg_ids[0] = sg_ids[1] = sg_ids[2] = 0;
2349 
2350 	PCM_SG_LOCK();
2351 
2352 	/*
2353 	 * - Insert channel(s) into group's member list.
2354 	 * - Set CHN_F_NOTRIGGER on channel(s).
2355 	 * - Stop channel(s).
2356 	 */
2357 
2358 	/*
2359 	 * If device's channels are already mapped to a group, unmap them.
2360 	 */
2361 	if (wrch) {
2362 		CHN_LOCK(wrch);
2363 		sg_ids[0] = chn_syncdestroy(wrch);
2364 	}
2365 
2366 	if (rdch) {
2367 		CHN_LOCK(rdch);
2368 		sg_ids[1] = chn_syncdestroy(rdch);
2369 	}
2370 
2371 	/*
2372 	 * Verify that mode matches character device properites.
2373 	 *  - Bail if PCM_ENABLE_OUTPUT && wrch == NULL.
2374 	 *  - Bail if PCM_ENABLE_INPUT && rdch == NULL.
2375 	 */
2376 	if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) ||
2377 	    ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) {
2378 		ret = EINVAL;
2379 		goto out;
2380 	}
2381 
2382 	/*
2383 	 * An id of zero indicates the user wants to create a new
2384 	 * syncgroup.
2385 	 */
2386 	if (group->id == 0) {
2387 		sg = (struct pcmchan_syncgroup *)malloc(sizeof(*sg), M_DEVBUF, M_NOWAIT);
2388 		if (sg != NULL) {
2389 			SLIST_INIT(&sg->members);
2390 			sg->id = alloc_unr(pcmsg_unrhdr);
2391 
2392 			group->id = sg->id;
2393 			SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link);
2394 		} else
2395 			ret = ENOMEM;
2396 	} else {
2397 		SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2398 			if (sg->id == group->id)
2399 				break;
2400 		}
2401 		if (sg == NULL)
2402 			ret = EINVAL;
2403 	}
2404 
2405 	/* Couldn't create or find a syncgroup.  Fail. */
2406 	if (sg == NULL)
2407 		goto out;
2408 
2409 	/*
2410 	 * Allocate a syncmember, assign it and a channel together, and
2411 	 * insert into syncgroup.
2412 	 */
2413 	if (group->mode & PCM_ENABLE_INPUT) {
2414 		smrd = (struct pcmchan_syncmember *)malloc(sizeof(*smrd), M_DEVBUF, M_NOWAIT);
2415 		if (smrd == NULL) {
2416 			ret = ENOMEM;
2417 			goto out;
2418 		}
2419 
2420 		SLIST_INSERT_HEAD(&sg->members, smrd, link);
2421 		smrd->parent = sg;
2422 		smrd->ch = rdch;
2423 
2424 		chn_abort(rdch);
2425 		rdch->flags |= CHN_F_NOTRIGGER;
2426 		rdch->sm = smrd;
2427 	}
2428 
2429 	if (group->mode & PCM_ENABLE_OUTPUT) {
2430 		smwr = (struct pcmchan_syncmember *)malloc(sizeof(*smwr), M_DEVBUF, M_NOWAIT);
2431 		if (smwr == NULL) {
2432 			ret = ENOMEM;
2433 			goto out;
2434 		}
2435 
2436 		SLIST_INSERT_HEAD(&sg->members, smwr, link);
2437 		smwr->parent = sg;
2438 		smwr->ch = wrch;
2439 
2440 		chn_abort(wrch);
2441 		wrch->flags |= CHN_F_NOTRIGGER;
2442 		wrch->sm = smwr;
2443 	}
2444 
2445 out:
2446 	if (ret != 0) {
2447 		if (smrd != NULL)
2448 			free(smrd, M_DEVBUF);
2449 		if ((sg != NULL) && SLIST_EMPTY(&sg->members)) {
2450 			sg_ids[2] = sg->id;
2451 			SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2452 			free(sg, M_DEVBUF);
2453 		}
2454 
2455 		if (wrch)
2456 			wrch->sm = NULL;
2457 		if (rdch)
2458 			rdch->sm = NULL;
2459 	}
2460 
2461 	if (wrch)
2462 		CHN_UNLOCK(wrch);
2463 	if (rdch)
2464 		CHN_UNLOCK(rdch);
2465 
2466 	PCM_SG_UNLOCK();
2467 
2468 	if (sg_ids[0])
2469 		free_unr(pcmsg_unrhdr, sg_ids[0]);
2470 	if (sg_ids[1])
2471 		free_unr(pcmsg_unrhdr, sg_ids[1]);
2472 	if (sg_ids[2])
2473 		free_unr(pcmsg_unrhdr, sg_ids[2]);
2474 
2475 	return (ret);
2476 }
2477 
2478 /**
2479  * @brief Launch a sync group into action
2480  *
2481  * Sync groups are established via SNDCTL_DSP_SYNCGROUP.  This function
2482  * iterates over all members, triggering them along the way.
2483  *
2484  * @note Caller must not hold any channel locks.
2485  *
2486  * @param sg_id	sync group identifier
2487  *
2488  * @retval 0	success
2489  * @retval non-zero	error worthy of propagating upstream to user
2490  */
2491 static int
2492 dsp_oss_syncstart(int sg_id)
2493 {
2494 	struct pcmchan_syncmember *sm, *sm_tmp;
2495 	struct pcmchan_syncgroup *sg;
2496 	struct pcm_channel *c;
2497 	int ret, needlocks;
2498 
2499 	/* Get the synclists lock */
2500 	PCM_SG_LOCK();
2501 
2502 	do {
2503 		ret = 0;
2504 		needlocks = 0;
2505 
2506 		/* Search for syncgroup by ID */
2507 		SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2508 			if (sg->id == sg_id)
2509 				break;
2510 		}
2511 
2512 		/* Return EINVAL if not found */
2513 		if (sg == NULL) {
2514 			ret = EINVAL;
2515 			break;
2516 		}
2517 
2518 		/* Any removals resulting in an empty group should've handled this */
2519 		KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup"));
2520 
2521 		/*
2522 		 * Attempt to lock all member channels - if any are already
2523 		 * locked, unlock those acquired, sleep for a bit, and try
2524 		 * again.
2525 		 */
2526 		SLIST_FOREACH(sm, &sg->members, link) {
2527 			if (CHN_TRYLOCK(sm->ch) == 0) {
2528 				int timo = hz * 5/1000;
2529 				if (timo < 1)
2530 					timo = 1;
2531 
2532 				/* Release all locked channels so far, retry */
2533 				SLIST_FOREACH(sm_tmp, &sg->members, link) {
2534 					/* sm is the member already locked */
2535 					if (sm == sm_tmp)
2536 						break;
2537 					CHN_UNLOCK(sm_tmp->ch);
2538 				}
2539 
2540 				/** @todo Is PRIBIO correct/ */
2541 				ret = msleep(sm, &snd_pcm_syncgroups_mtx,
2542 				    PRIBIO | PCATCH, "pcmsg", timo);
2543 				if (ret == EINTR || ret == ERESTART)
2544 					break;
2545 
2546 				needlocks = 1;
2547 				ret = 0; /* Assumes ret == EAGAIN... */
2548 			}
2549 		}
2550 	} while (needlocks && ret == 0);
2551 
2552 	/* Proceed only if no errors encountered. */
2553 	if (ret == 0) {
2554 		/* Launch channels */
2555 		while ((sm = SLIST_FIRST(&sg->members)) != NULL) {
2556 			SLIST_REMOVE_HEAD(&sg->members, link);
2557 
2558 			c = sm->ch;
2559 			c->sm = NULL;
2560 			chn_start(c, 1);
2561 			c->flags &= ~CHN_F_NOTRIGGER;
2562 			CHN_UNLOCK(c);
2563 
2564 			free(sm, M_DEVBUF);
2565 		}
2566 
2567 		SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2568 		free(sg, M_DEVBUF);
2569 	}
2570 
2571 	PCM_SG_UNLOCK();
2572 
2573 	/*
2574 	 * Free_unr() may sleep, so be sure to give up the syncgroup lock
2575 	 * first.
2576 	 */
2577 	if (ret == 0)
2578 		free_unr(pcmsg_unrhdr, sg_id);
2579 
2580 	return (ret);
2581 }
2582 
2583 /**
2584  * @brief Handler for SNDCTL_DSP_POLICY
2585  *
2586  * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment
2587  * size and count like with SNDCTL_DSP_SETFRAGMENT.  Instead of the user
2588  * specifying those two parameters, s/he simply selects a number from 0..10
2589  * which corresponds to a buffer size.  Smaller numbers request smaller
2590  * buffers with lower latencies (at greater overhead from more frequent
2591  * interrupts), while greater numbers behave in the opposite manner.
2592  *
2593  * The 4Front spec states that a value of 5 should be the default.  However,
2594  * this implementation deviates slightly by using a linear scale without
2595  * consulting drivers.  I.e., even though drivers may have different default
2596  * buffer sizes, a policy argument of 5 will have the same result across
2597  * all drivers.
2598  *
2599  * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for
2600  * more information.
2601  *
2602  * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to
2603  * 	 work with hardware drivers directly.
2604  *
2605  * @note PCM channel arguments must not be locked by caller.
2606  *
2607  * @param wrch	Pointer to opened playback channel (optional; may be NULL)
2608  * @param rdch	" recording channel (optional; may be NULL)
2609  * @param policy Integer from [0:10]
2610  *
2611  * @retval 0	constant (for now)
2612  */
2613 static int
2614 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy)
2615 {
2616 	int ret;
2617 
2618 	if (policy < CHN_POLICY_MIN || policy > CHN_POLICY_MAX)
2619 		return (EIO);
2620 
2621 	/* Default: success */
2622 	ret = 0;
2623 
2624 	if (rdch) {
2625 		CHN_LOCK(rdch);
2626 		ret = chn_setlatency(rdch, policy);
2627 		CHN_UNLOCK(rdch);
2628 	}
2629 
2630 	if (wrch && ret == 0) {
2631 		CHN_LOCK(wrch);
2632 		ret = chn_setlatency(wrch, policy);
2633 		CHN_UNLOCK(wrch);
2634 	}
2635 
2636 	if (ret)
2637 		ret = EIO;
2638 
2639 	return (ret);
2640 }
2641 
2642 /**
2643  * @brief Enable or disable "cooked" mode
2644  *
2645  * This is a handler for @c SNDCTL_DSP_COOKEDMODE.  When in cooked mode, which
2646  * is the default, the sound system handles rate and format conversions
2647  * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only
2648  * operates with 44100Hz/16bit/signed samples).
2649  *
2650  * Disabling cooked mode is intended for applications wanting to mmap()
2651  * a sound card's buffer space directly, bypassing the FreeBSD 2-stage
2652  * feeder architecture, presumably to gain as much control over audio
2653  * hardware as possible.
2654  *
2655  * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html
2656  * for more details.
2657  *
2658  * @param wrch		playback channel (optional; may be NULL)
2659  * @param rdch		recording channel (optional; may be NULL)
2660  * @param enabled	0 = raw mode, 1 = cooked mode
2661  *
2662  * @retval EINVAL	Operation not yet supported.
2663  */
2664 static int
2665 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled)
2666 {
2667 
2668 	/*
2669 	 * XXX I just don't get it. Why don't they call it
2670 	 * "BITPERFECT" ~ SNDCTL_DSP_BITPERFECT !?!?.
2671 	 * This is just plain so confusing, incoherent,
2672 	 * <insert any non-printable characters here>.
2673 	 */
2674 	if (!(enabled == 1 || enabled == 0))
2675 		return (EINVAL);
2676 
2677 	/*
2678 	 * I won't give in. I'm inverting its logic here and now.
2679 	 * Brag all you want, but "BITPERFECT" should be the better
2680 	 * term here.
2681 	 */
2682 	enabled ^= 0x00000001;
2683 
2684 	if (wrch != NULL) {
2685 		CHN_LOCK(wrch);
2686 		wrch->flags &= ~CHN_F_BITPERFECT;
2687 		wrch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000;
2688 		CHN_UNLOCK(wrch);
2689 	}
2690 
2691 	if (rdch != NULL) {
2692 		CHN_LOCK(rdch);
2693 		rdch->flags &= ~CHN_F_BITPERFECT;
2694 		rdch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000;
2695 		CHN_UNLOCK(rdch);
2696 	}
2697 
2698 	return (0);
2699 }
2700 
2701 /**
2702  * @brief Retrieve channel interleaving order
2703  *
2704  * This is the handler for @c SNDCTL_DSP_GET_CHNORDER.
2705  *
2706  * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html
2707  * for more details.
2708  *
2709  * @note As the ioctl definition is still under construction, FreeBSD
2710  * 	 does not currently support SNDCTL_DSP_GET_CHNORDER.
2711  *
2712  * @param wrch	playback channel (optional; may be NULL)
2713  * @param rdch	recording channel (optional; may be NULL)
2714  * @param map	channel map (result will be stored there)
2715  *
2716  * @retval EINVAL	Operation not yet supported.
2717  */
2718 static int
2719 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2720 {
2721 	struct pcm_channel *ch;
2722 	int ret;
2723 
2724 	ch = (wrch != NULL) ? wrch : rdch;
2725 	if (ch != NULL) {
2726 		CHN_LOCK(ch);
2727 		ret = chn_oss_getorder(ch, map);
2728 		CHN_UNLOCK(ch);
2729 	} else
2730 		ret = EINVAL;
2731 
2732 	return (ret);
2733 }
2734 
2735 /**
2736  * @brief Specify channel interleaving order
2737  *
2738  * This is the handler for @c SNDCTL_DSP_SET_CHNORDER.
2739  *
2740  * @note As the ioctl definition is still under construction, FreeBSD
2741  * 	 does not currently support @c SNDCTL_DSP_SET_CHNORDER.
2742  *
2743  * @param wrch	playback channel (optional; may be NULL)
2744  * @param rdch	recording channel (optional; may be NULL)
2745  * @param map	channel map
2746  *
2747  * @retval EINVAL	Operation not yet supported.
2748  */
2749 static int
2750 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2751 {
2752 	int ret;
2753 
2754 	ret = 0;
2755 
2756 	if (wrch != NULL) {
2757 		CHN_LOCK(wrch);
2758 		ret = chn_oss_setorder(wrch, map);
2759 		CHN_UNLOCK(wrch);
2760 	}
2761 
2762 	if (ret == 0 && rdch != NULL) {
2763 		CHN_LOCK(rdch);
2764 		ret = chn_oss_setorder(rdch, map);
2765 		CHN_UNLOCK(rdch);
2766 	}
2767 
2768 	return (ret);
2769 }
2770 
2771 static int
2772 dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch,
2773     int *mask)
2774 {
2775 	struct pcm_channel *ch;
2776 	uint32_t chnmask;
2777 	int ret;
2778 
2779 	chnmask = 0;
2780 	ch = (wrch != NULL) ? wrch : rdch;
2781 
2782 	if (ch != NULL) {
2783 		CHN_LOCK(ch);
2784 		ret = chn_oss_getmask(ch, &chnmask);
2785 		CHN_UNLOCK(ch);
2786 	} else
2787 		ret = EINVAL;
2788 
2789 	if (ret == 0)
2790 		*mask = chnmask;
2791 
2792 	return (ret);
2793 }
2794 
2795 #ifdef OSSV4_EXPERIMENT
2796 /**
2797  * @brief Retrieve an audio device's label
2798  *
2799  * This is a handler for the @c SNDCTL_GETLABEL ioctl.
2800  *
2801  * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2802  * for more details.
2803  *
2804  * From Hannu@4Front:  "For example ossxmix (just like some HW mixer
2805  * consoles) can show variable "labels" for certain controls. By default
2806  * the application name (say quake) is shown as the label but
2807  * applications may change the labels themselves."
2808  *
2809  * @note As the ioctl definition is still under construction, FreeBSD
2810  * 	 does not currently support @c SNDCTL_GETLABEL.
2811  *
2812  * @param wrch	playback channel (optional; may be NULL)
2813  * @param rdch	recording channel (optional; may be NULL)
2814  * @param label	label gets copied here
2815  *
2816  * @retval EINVAL	Operation not yet supported.
2817  */
2818 static int
2819 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2820 {
2821 	return (EINVAL);
2822 }
2823 
2824 /**
2825  * @brief Specify an audio device's label
2826  *
2827  * This is a handler for the @c SNDCTL_SETLABEL ioctl.  Please see the
2828  * comments for @c dsp_oss_getlabel immediately above.
2829  *
2830  * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2831  * for more details.
2832  *
2833  * @note As the ioctl definition is still under construction, FreeBSD
2834  * 	 does not currently support SNDCTL_SETLABEL.
2835  *
2836  * @param wrch	playback channel (optional; may be NULL)
2837  * @param rdch	recording channel (optional; may be NULL)
2838  * @param label	label gets copied from here
2839  *
2840  * @retval EINVAL	Operation not yet supported.
2841  */
2842 static int
2843 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2844 {
2845 	return (EINVAL);
2846 }
2847 
2848 /**
2849  * @brief Retrieve name of currently played song
2850  *
2851  * This is a handler for the @c SNDCTL_GETSONG ioctl.  Audio players could
2852  * tell the system the name of the currently playing song, which would be
2853  * visible in @c /dev/sndstat.
2854  *
2855  * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html
2856  * for more details.
2857  *
2858  * @note As the ioctl definition is still under construction, FreeBSD
2859  * 	 does not currently support SNDCTL_GETSONG.
2860  *
2861  * @param wrch	playback channel (optional; may be NULL)
2862  * @param rdch	recording channel (optional; may be NULL)
2863  * @param song	song name gets copied here
2864  *
2865  * @retval EINVAL	Operation not yet supported.
2866  */
2867 static int
2868 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2869 {
2870 	return (EINVAL);
2871 }
2872 
2873 /**
2874  * @brief Retrieve name of currently played song
2875  *
2876  * This is a handler for the @c SNDCTL_SETSONG ioctl.  Audio players could
2877  * tell the system the name of the currently playing song, which would be
2878  * visible in @c /dev/sndstat.
2879  *
2880  * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html
2881  * for more details.
2882  *
2883  * @note As the ioctl definition is still under construction, FreeBSD
2884  * 	 does not currently support SNDCTL_SETSONG.
2885  *
2886  * @param wrch	playback channel (optional; may be NULL)
2887  * @param rdch	recording channel (optional; may be NULL)
2888  * @param song	song name gets copied from here
2889  *
2890  * @retval EINVAL	Operation not yet supported.
2891  */
2892 static int
2893 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2894 {
2895 	return (EINVAL);
2896 }
2897 
2898 /**
2899  * @brief Rename a device
2900  *
2901  * This is a handler for the @c SNDCTL_SETNAME ioctl.
2902  *
2903  * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for
2904  * more details.
2905  *
2906  * From Hannu@4Front:  "This call is used to change the device name
2907  * reported in /dev/sndstat and ossinfo. So instead of  using some generic
2908  * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull
2909  * name depending on the current context (for example 'OSS virtual wave table
2910  * synth' or 'VoIP link to London')."
2911  *
2912  * @note As the ioctl definition is still under construction, FreeBSD
2913  * 	 does not currently support SNDCTL_SETNAME.
2914  *
2915  * @param wrch	playback channel (optional; may be NULL)
2916  * @param rdch	recording channel (optional; may be NULL)
2917  * @param name	new device name gets copied from here
2918  *
2919  * @retval EINVAL	Operation not yet supported.
2920  */
2921 static int
2922 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name)
2923 {
2924 	return (EINVAL);
2925 }
2926 #endif	/* !OSSV4_EXPERIMENT */
2927