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