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