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