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