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