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