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