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