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