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