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
50struct 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
58static int dsp_mmap_allow_prot_exec = 0;
59SYSCTL_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
63static int dsp_basename_clone = 1;
64SYSCTL_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
72static d_open_t dsp_open;
73static d_read_t dsp_read;
74static d_write_t dsp_write;
75static d_ioctl_t dsp_ioctl;
76static d_poll_t dsp_poll;
77static d_mmap_t dsp_mmap;
78static d_mmap_single_t dsp_mmap_single;
79
80struct 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
92static eventhandler_tag dsp_ehtag = NULL;
93
94static int dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group);
95static int dsp_oss_syncstart(int sg_id);
96static int dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy);
97static int dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled);
98static int dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
99static int dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
100static int dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch, int *mask);
101#ifdef OSSV4_EXPERIMENT
102static int dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
103static int dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
104static int dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
105static int dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
106static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name);
107#endif
108
109int
110dsp_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
135void
136dsp_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
144static void
145getchns(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
197static void
198relchns(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
212static 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
231static void
232dsp_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);
330skip:
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
349static int
350dsp_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
499static __inline int
500dsp_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
573static int
574dsp_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
584static int
585dsp_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
595static int
596dsp_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
718static int
719dsp_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
1841static int
1842dsp_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
1884static int
1885dsp_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
1897static int
1898dsp_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
1970static void
1971dsp_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;
1987found:
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
2003static void
2004dsp_sysinit(void *p)
2005{
2006	if (dsp_ehtag != NULL)
2007		return;
2008	dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
2009}
2010
2011static void
2012dsp_sysuninit(void *p)
2013{
2014	if (dsp_ehtag == NULL)
2015		return;
2016	EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
2017	dsp_ehtag = NULL;
2018}
2019
2020SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
2021SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
2022
2023char *
2024dsp_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
2043static void
2044dsp_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 */
2079int
2080dsp_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
2206static int
2207dsp_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 */
2239int
2240dsp_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 */
2457static int
2458dsp_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
2570out:
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 */
2616static int
2617dsp_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 */
2738static int
2739dsp_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 */
2789static int
2790dsp_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 */
2843static int
2844dsp_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 */
2874static int
2875dsp_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
2896static int
2897dsp_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 */
2943static int
2944dsp_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 */
2967static int
2968dsp_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 */
2992static int
2993dsp_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 */
3017static int
3018dsp_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 */
3046static int
3047dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name)
3048{
3049	return (EINVAL);
3050}
3051#endif	/* !OSSV4_EXPERIMENT */
3052