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