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