xref: /freebsd/sys/dev/sound/pcm/dsp.c (revision 282a3889ebf826db9839be296ff1dd903f6d6d6e)
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_TRIGGERED | CHN_F_NOTRIGGER);
1397 		    	if (*arg_i & PCM_ENABLE_INPUT)
1398 				chn_start(rdch, 1);
1399 			else
1400 				rdch->flags |= CHN_F_NOTRIGGER;
1401 			CHN_UNLOCK(rdch);
1402 		}
1403 		if (wrch) {
1404 			CHN_LOCK(wrch);
1405 			wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
1406 		    	if (*arg_i & PCM_ENABLE_OUTPUT)
1407 				chn_start(wrch, 1);
1408 			else
1409 				wrch->flags |= CHN_F_NOTRIGGER;
1410 			CHN_UNLOCK(wrch);
1411 		}
1412 		break;
1413 
1414     	case SNDCTL_DSP_GETTRIGGER:
1415 		*arg_i = 0;
1416 		if (wrch) {
1417 			CHN_LOCK(wrch);
1418 			if (wrch->flags & CHN_F_TRIGGERED)
1419 				*arg_i |= PCM_ENABLE_OUTPUT;
1420 			CHN_UNLOCK(wrch);
1421 		}
1422 		if (rdch) {
1423 			CHN_LOCK(rdch);
1424 			if (rdch->flags & CHN_F_TRIGGERED)
1425 				*arg_i |= PCM_ENABLE_INPUT;
1426 			CHN_UNLOCK(rdch);
1427 		}
1428 		break;
1429 
1430 	case SNDCTL_DSP_GETODELAY:
1431 		if (wrch) {
1432 	        	struct snd_dbuf *bs = wrch->bufsoft;
1433 
1434 			CHN_LOCK(wrch);
1435 			/* XXX abusive DMA update: chn_wrupdate(wrch); */
1436 			*arg_i = sndbuf_getready(bs);
1437 			CHN_UNLOCK(wrch);
1438 		} else
1439 			ret = EINVAL;
1440 		break;
1441 
1442     	case SNDCTL_DSP_POST:
1443 		if (wrch) {
1444 			CHN_LOCK(wrch);
1445 			wrch->flags &= ~CHN_F_NOTRIGGER;
1446 			chn_start(wrch, 1);
1447 			CHN_UNLOCK(wrch);
1448 		}
1449 		break;
1450 
1451 	case SNDCTL_DSP_SETDUPLEX:
1452 		/*
1453 		 * switch to full-duplex mode if card is in half-duplex
1454 		 * mode and is able to work in full-duplex mode
1455 		 */
1456 		pcm_lock(d);
1457 		if (rdch && wrch && (dsp_get_flags(i_dev) & SD_F_SIMPLEX))
1458 			dsp_set_flags(i_dev, dsp_get_flags(i_dev)^SD_F_SIMPLEX);
1459 		pcm_unlock(d);
1460 		break;
1461 
1462 	/*
1463 	 * The following four ioctls are simple wrappers around mixer_ioctl
1464 	 * with no further processing.  xcmd is short for "translated
1465 	 * command".
1466 	 */
1467 	case SNDCTL_DSP_GETRECVOL:
1468 		if (xcmd == 0)
1469 			xcmd = SOUND_MIXER_READ_RECLEV;
1470 		/* FALLTHROUGH */
1471 	case SNDCTL_DSP_SETRECVOL:
1472 		if (xcmd == 0)
1473 			xcmd = SOUND_MIXER_WRITE_RECLEV;
1474 		/* FALLTHROUGH */
1475 	case SNDCTL_DSP_GETPLAYVOL:
1476 		if (xcmd == 0)
1477 			xcmd = SOUND_MIXER_READ_PCM;
1478 		/* FALLTHROUGH */
1479 	case SNDCTL_DSP_SETPLAYVOL:
1480 		if (xcmd == 0)
1481 			xcmd = SOUND_MIXER_WRITE_PCM;
1482 
1483 		if (d->mixer_dev != NULL) {
1484 			PCM_ACQUIRE_QUICK(d);
1485 			ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td,
1486 			    MIXER_CMD_DIRECT);
1487 			PCM_RELEASE_QUICK(d);
1488 		} else
1489 			ret = ENOTSUP;
1490 		break;
1491 
1492 	case SNDCTL_DSP_GET_RECSRC_NAMES:
1493 	case SNDCTL_DSP_GET_RECSRC:
1494 	case SNDCTL_DSP_SET_RECSRC:
1495 		if (d->mixer_dev != NULL) {
1496 			PCM_ACQUIRE_QUICK(d);
1497 			ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
1498 			    MIXER_CMD_DIRECT);
1499 			PCM_RELEASE_QUICK(d);
1500 		} else
1501 			ret = ENOTSUP;
1502 		break;
1503 
1504 	/*
1505 	 * The following 3 ioctls aren't very useful at the moment.  For
1506 	 * now, only a single channel is associated with a cdev (/dev/dspN
1507 	 * instance), so there's only a single output routing to use (i.e.,
1508 	 * the wrch bound to this cdev).
1509 	 */
1510 	case SNDCTL_DSP_GET_PLAYTGT_NAMES:
1511 		{
1512 			oss_mixer_enuminfo *ei;
1513 			ei = (oss_mixer_enuminfo *)arg;
1514 			ei->dev = 0;
1515 			ei->ctrl = 0;
1516 			ei->version = 0; /* static for now */
1517 			ei->strindex[0] = 0;
1518 
1519 			if (wrch != NULL) {
1520 				ei->nvalues = 1;
1521 				strlcpy(ei->strings, wrch->name,
1522 					sizeof(ei->strings));
1523 			} else {
1524 				ei->nvalues = 0;
1525 				ei->strings[0] = '\0';
1526 			}
1527 		}
1528 		break;
1529 	case SNDCTL_DSP_GET_PLAYTGT:
1530 	case SNDCTL_DSP_SET_PLAYTGT:	/* yes, they are the same for now */
1531 		/*
1532 		 * Re: SET_PLAYTGT
1533 		 *   OSSv4: "The value that was accepted by the device will
1534 		 *   be returned back in the variable pointed by the
1535 		 *   argument."
1536 		 */
1537 		if (wrch != NULL)
1538 			*arg_i = 0;
1539 		else
1540 			ret = EINVAL;
1541 		break;
1542 
1543 	case SNDCTL_DSP_SILENCE:
1544 	/*
1545 	 * Flush the software (pre-feed) buffer, but try to minimize playback
1546 	 * interruption.  (I.e., record unplayed samples with intent to
1547 	 * restore by SNDCTL_DSP_SKIP.) Intended for application "pause"
1548 	 * functionality.
1549 	 */
1550 		if (wrch == NULL)
1551 			ret = EINVAL;
1552 		else {
1553 			struct snd_dbuf *bs;
1554 			CHN_LOCK(wrch);
1555 			while (wrch->inprog != 0)
1556 				cv_wait(&wrch->cv, wrch->lock);
1557 			bs = wrch->bufsoft;
1558 			if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) {
1559 				bs->sl = sndbuf_getready(bs);
1560 				sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs));
1561 				sndbuf_fillsilence(bs);
1562 				chn_start(wrch, 0);
1563 			}
1564 			CHN_UNLOCK(wrch);
1565 		}
1566 		break;
1567 
1568 	case SNDCTL_DSP_SKIP:
1569 	/*
1570 	 * OSSv4 docs: "This ioctl call discards all unplayed samples in the
1571 	 * playback buffer by moving the current write position immediately
1572 	 * before the point where the device is currently reading the samples."
1573 	 */
1574 		if (wrch == NULL)
1575 			ret = EINVAL;
1576 		else {
1577 			struct snd_dbuf *bs;
1578 			CHN_LOCK(wrch);
1579 			while (wrch->inprog != 0)
1580 				cv_wait(&wrch->cv, wrch->lock);
1581 			bs = wrch->bufsoft;
1582 			if ((bs->shadbuf != NULL) && (bs->sl > 0)) {
1583 				sndbuf_softreset(bs);
1584 				sndbuf_acquire(bs, bs->shadbuf, bs->sl);
1585 				bs->sl = 0;
1586 				chn_start(wrch, 0);
1587 			}
1588 			CHN_UNLOCK(wrch);
1589 		}
1590 		break;
1591 
1592 	case SNDCTL_DSP_CURRENT_OPTR:
1593 	case SNDCTL_DSP_CURRENT_IPTR:
1594 	/**
1595 	 * @note Changing formats resets the buffer counters, which differs
1596 	 * 	 from the 4Front drivers.  However, I don't expect this to be
1597 	 * 	 much of a problem.
1598 	 *
1599 	 * @note In a test where @c CURRENT_OPTR is called immediately after write
1600 	 * 	 returns, this driver is about 32K samples behind whereas
1601 	 * 	 4Front's is about 8K samples behind.  Should determine source
1602 	 * 	 of discrepancy, even if only out of curiosity.
1603 	 *
1604 	 * @todo Actually test SNDCTL_DSP_CURRENT_IPTR.
1605 	 */
1606 		chn = (cmd == SNDCTL_DSP_CURRENT_OPTR) ? wrch : rdch;
1607 		if (chn == NULL)
1608 			ret = EINVAL;
1609 		else {
1610 			struct snd_dbuf *bs;
1611 			/* int tmp; */
1612 
1613 			oss_count_t *oc = (oss_count_t *)arg;
1614 
1615 			CHN_LOCK(chn);
1616 			bs = chn->bufsoft;
1617 #if 0
1618 			tmp = (sndbuf_getsize(b) + chn_getptr(chn) - sndbuf_gethwptr(b)) % sndbuf_getsize(b);
1619 			oc->samples = (sndbuf_gettotal(b) + tmp) / sndbuf_getbps(b);
1620 			oc->fifo_samples = (sndbuf_getready(b) - tmp) / sndbuf_getbps(b);
1621 #else
1622 			oc->samples = sndbuf_gettotal(bs) / sndbuf_getbps(bs);
1623 			oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getbps(bs);
1624 #endif
1625 			CHN_UNLOCK(chn);
1626 		}
1627 		break;
1628 
1629 	case SNDCTL_DSP_HALT_OUTPUT:
1630 	case SNDCTL_DSP_HALT_INPUT:
1631 		chn = (cmd == SNDCTL_DSP_HALT_OUTPUT) ? wrch : rdch;
1632 		if (chn == NULL)
1633 			ret = EINVAL;
1634 		else {
1635 			CHN_LOCK(chn);
1636 			chn_abort(chn);
1637 			CHN_UNLOCK(chn);
1638 		}
1639 		break;
1640 
1641 	case SNDCTL_DSP_LOW_WATER:
1642 	/*
1643 	 * Set the number of bytes required to attract attention by
1644 	 * select/poll.
1645 	 */
1646 		if (wrch != NULL) {
1647 			CHN_LOCK(wrch);
1648 			wrch->lw = (*arg_i > 1) ? *arg_i : 1;
1649 			CHN_UNLOCK(wrch);
1650 		}
1651 		if (rdch != NULL) {
1652 			CHN_LOCK(rdch);
1653 			rdch->lw = (*arg_i > 1) ? *arg_i : 1;
1654 			CHN_UNLOCK(rdch);
1655 		}
1656 		break;
1657 
1658 	case SNDCTL_DSP_GETERROR:
1659 	/*
1660 	 * OSSv4 docs:  "All errors and counters will automatically be
1661 	 * cleared to zeroes after the call so each call will return only
1662 	 * the errors that occurred after the previous invocation. ... The
1663 	 * play_underruns and rec_overrun fields are the only usefull fields
1664 	 * returned by OSS 4.0."
1665 	 */
1666 		{
1667 			audio_errinfo *ei = (audio_errinfo *)arg;
1668 
1669 			bzero((void *)ei, sizeof(*ei));
1670 
1671 			if (wrch != NULL) {
1672 				CHN_LOCK(wrch);
1673 				ei->play_underruns = wrch->xruns;
1674 				wrch->xruns = 0;
1675 				CHN_UNLOCK(wrch);
1676 			}
1677 			if (rdch != NULL) {
1678 				CHN_LOCK(rdch);
1679 				ei->rec_overruns = rdch->xruns;
1680 				rdch->xruns = 0;
1681 				CHN_UNLOCK(rdch);
1682 			}
1683 		}
1684 		break;
1685 
1686 	case SNDCTL_DSP_SYNCGROUP:
1687 		PCM_ACQUIRE_QUICK(d);
1688 		ret = dsp_oss_syncgroup(wrch, rdch, (oss_syncgroup *)arg);
1689 		PCM_RELEASE_QUICK(d);
1690 		break;
1691 
1692 	case SNDCTL_DSP_SYNCSTART:
1693 		PCM_ACQUIRE_QUICK(d);
1694 		ret = dsp_oss_syncstart(*arg_i);
1695 		PCM_RELEASE_QUICK(d);
1696 		break;
1697 
1698 	case SNDCTL_DSP_POLICY:
1699 		PCM_ACQUIRE_QUICK(d);
1700 		ret = dsp_oss_policy(wrch, rdch, *arg_i);
1701 		PCM_RELEASE_QUICK(d);
1702 		break;
1703 
1704 #ifdef	OSSV4_EXPERIMENT
1705 	/*
1706 	 * XXX The following ioctls are not yet supported and just return
1707 	 * EINVAL.
1708 	 */
1709 	case SNDCTL_DSP_GETOPEAKS:
1710 	case SNDCTL_DSP_GETIPEAKS:
1711 		chn = (cmd == SNDCTL_DSP_GETOPEAKS) ? wrch : rdch;
1712 		if (chn == NULL)
1713 			ret = EINVAL;
1714 		else {
1715 			oss_peaks_t *op = (oss_peaks_t *)arg;
1716 			int lpeak, rpeak;
1717 
1718 			CHN_LOCK(chn);
1719 			ret = chn_getpeaks(chn, &lpeak, &rpeak);
1720 			if (ret == -1)
1721 				ret = EINVAL;
1722 			else {
1723 				(*op)[0] = lpeak;
1724 				(*op)[1] = rpeak;
1725 			}
1726 			CHN_UNLOCK(chn);
1727 		}
1728 		break;
1729 
1730 	/*
1731 	 * XXX Once implemented, revisit this for proper cv protection
1732 	 *     (if necessary).
1733 	 */
1734 	case SNDCTL_DSP_COOKEDMODE:
1735 		ret = dsp_oss_cookedmode(wrch, rdch, *arg_i);
1736 		break;
1737 	case SNDCTL_DSP_GET_CHNORDER:
1738 		ret = dsp_oss_getchnorder(wrch, rdch, (unsigned long long *)arg);
1739 		break;
1740 	case SNDCTL_DSP_SET_CHNORDER:
1741 		ret = dsp_oss_setchnorder(wrch, rdch, (unsigned long long *)arg);
1742 		break;
1743 	case SNDCTL_GETLABEL:
1744 		ret = dsp_oss_getlabel(wrch, rdch, (oss_label_t *)arg);
1745 		break;
1746 	case SNDCTL_SETLABEL:
1747 		ret = dsp_oss_setlabel(wrch, rdch, (oss_label_t *)arg);
1748 		break;
1749 	case SNDCTL_GETSONG:
1750 		ret = dsp_oss_getsong(wrch, rdch, (oss_longname_t *)arg);
1751 		break;
1752 	case SNDCTL_SETSONG:
1753 		ret = dsp_oss_setsong(wrch, rdch, (oss_longname_t *)arg);
1754 		break;
1755 	case SNDCTL_SETNAME:
1756 		ret = dsp_oss_setname(wrch, rdch, (oss_longname_t *)arg);
1757 		break;
1758 #if 0
1759 	/**
1760 	 * @note The SNDCTL_CARDINFO ioctl was omitted per 4Front developer
1761 	 * documentation.  "The usability of this call is very limited. It's
1762 	 * provided only for completeness of the API. OSS API doesn't have
1763 	 * any concept of card. Any information returned by this ioctl calld
1764 	 * is reserved exclusively for the utility programs included in the
1765 	 * OSS package. Applications should not try to use for this
1766 	 * information in any ways."
1767 	 */
1768 	case SNDCTL_CARDINFO:
1769 		ret = EINVAL;
1770 		break;
1771 	/**
1772 	 * @note The S/PDIF interface ioctls, @c SNDCTL_DSP_READCTL and
1773 	 * @c SNDCTL_DSP_WRITECTL have been omitted at the suggestion of
1774 	 * 4Front Technologies.
1775 	 */
1776 	case SNDCTL_DSP_READCTL:
1777 	case SNDCTL_DSP_WRITECTL:
1778 		ret = EINVAL;
1779 		break;
1780 #endif	/* !0 (explicitly omitted ioctls) */
1781 
1782 #endif	/* !OSSV4_EXPERIMENT */
1783     	case SNDCTL_DSP_MAPINBUF:
1784     	case SNDCTL_DSP_MAPOUTBUF:
1785     	case SNDCTL_DSP_SETSYNCRO:
1786 		/* undocumented */
1787 
1788     	case SNDCTL_DSP_SUBDIVIDE:
1789     	case SOUND_PCM_WRITE_FILTER:
1790     	case SOUND_PCM_READ_FILTER:
1791 		/* dunno what these do, don't sound important */
1792 
1793     	default:
1794 		DEB(printf("default ioctl fn 0x%08lx fail\n", cmd));
1795 		ret = EINVAL;
1796 		break;
1797     	}
1798 
1799 	relchns(i_dev, rdch, wrch, 0);
1800 
1801 	PCM_GIANT_LEAVE(d);
1802 
1803     	return (ret);
1804 }
1805 
1806 static int
1807 dsp_poll(struct cdev *i_dev, int events, struct thread *td)
1808 {
1809 	struct snddev_info *d;
1810 	struct pcm_channel *wrch, *rdch;
1811 	int ret, e;
1812 
1813 	d = dsp_get_info(i_dev);
1814 	if (!DSP_REGISTERED(d, i_dev))
1815 		return (EBADF);
1816 
1817 	PCM_GIANT_ENTER(d);
1818 
1819 	wrch = NULL;
1820 	rdch = NULL;
1821 	ret = 0;
1822 
1823 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1824 
1825 	if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) {
1826 		e = (events & (POLLOUT | POLLWRNORM));
1827 		if (e)
1828 			ret |= chn_poll(wrch, e, td);
1829 	}
1830 
1831 	if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) {
1832 		e = (events & (POLLIN | POLLRDNORM));
1833 		if (e)
1834 			ret |= chn_poll(rdch, e, td);
1835 	}
1836 
1837 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1838 
1839 	PCM_GIANT_LEAVE(d);
1840 
1841 	return (ret);
1842 }
1843 
1844 static int
1845 dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
1846 {
1847 	struct snddev_info *d;
1848 	struct pcm_channel *wrch, *rdch, *c;
1849 
1850 	/*
1851 	 * Reject PROT_EXEC by default. It just doesn't makes sense.
1852 	 * Unfortunately, we have to give up this one due to linux_mmap
1853 	 * changes.
1854 	 *
1855 	 * http://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html
1856 	 *
1857 	 */
1858 	if ((nprot & PROT_EXEC) && dsp_mmap_allow_prot_exec == 0)
1859 		return (-1);
1860 
1861 	d = dsp_get_info(i_dev);
1862 	if (!DSP_REGISTERED(d, i_dev))
1863 		return (-1);
1864 
1865 	PCM_GIANT_ENTER(d);
1866 
1867 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1868 
1869 	/*
1870 	 * XXX The linux api uses the nprot to select read/write buffer
1871 	 *     our vm system doesn't allow this, so force write buffer.
1872 	 *
1873 	 *     This is just a quack to fool full-duplex mmap, so that at
1874 	 *     least playback _or_ recording works. If you really got the
1875 	 *     urge to make _both_ work at the same time, avoid O_RDWR.
1876 	 *     Just open each direction separately and mmap() it.
1877 	 *
1878 	 *     Failure is not an option due to INVARIANTS check within
1879 	 *     device_pager.c, which means, we have to give up one over
1880 	 *     another.
1881 	 */
1882 	c = (wrch != NULL) ? wrch : rdch;
1883 
1884 	if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) ||
1885 	    offset >= sndbuf_getsize(c->bufsoft) ||
1886 	    (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) ||
1887 	    (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) {
1888 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1889 		PCM_GIANT_EXIT(d);
1890 		return (-1);
1891 	}
1892 
1893 	/* XXX full-duplex quack. */
1894 	if (wrch != NULL)
1895 		wrch->flags |= CHN_F_MAPPED;
1896 	if (rdch != NULL)
1897 		rdch->flags |= CHN_F_MAPPED;
1898 
1899 	*paddr = vtophys(sndbuf_getbufofs(c->bufsoft, offset));
1900 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1901 
1902 	PCM_GIANT_LEAVE(d);
1903 
1904 	return (0);
1905 }
1906 
1907 #ifdef USING_DEVFS
1908 
1909 /* So much for dev_stdclone() */
1910 static int
1911 dsp_stdclone(char *name, char *namep, char *sep, int use_sep, int *u, int *c)
1912 {
1913 	size_t len;
1914 
1915 	len = strlen(namep);
1916 
1917 	if (bcmp(name, namep, len) != 0)
1918 		return (ENODEV);
1919 
1920 	name += len;
1921 
1922 	if (isdigit(*name) == 0)
1923 		return (ENODEV);
1924 
1925 	len = strlen(sep);
1926 
1927 	if (*name == '0' && !(name[1] == '\0' || bcmp(name + 1, sep, len) == 0))
1928 		return (ENODEV);
1929 
1930 	for (*u = 0; isdigit(*name) != 0; name++) {
1931 		*u *= 10;
1932 		*u += *name - '0';
1933 		if (*u > dsp_umax)
1934 			return (ENODEV);
1935 	}
1936 
1937 	if (*name == '\0')
1938 		return ((use_sep == 0) ? 0 : ENODEV);
1939 
1940 	if (bcmp(name, sep, len) != 0 || isdigit(name[len]) == 0)
1941 		return (ENODEV);
1942 
1943 	name += len;
1944 
1945 	if (*name == '0' && name[1] != '\0')
1946 		return (ENODEV);
1947 
1948 	for (*c = 0; isdigit(*name) != 0; name++) {
1949 		*c *= 10;
1950 		*c += *name - '0';
1951 		if (*c > dsp_cmax)
1952 			return (ENODEV);
1953 	}
1954 
1955 	if (*name != '\0')
1956 		return (ENODEV);
1957 
1958 	return (0);
1959 }
1960 
1961 static void
1962 dsp_clone(void *arg,
1963 #if __FreeBSD_version >= 600034
1964     struct ucred *cred,
1965 #endif
1966     char *name, int namelen, struct cdev **dev)
1967 {
1968 	struct snddev_info *d;
1969 	struct snd_clone_entry *ce;
1970 	struct pcm_channel *c;
1971 	int i, unit, udcmask, cunit, devtype, devhw, devcmax, tumax;
1972 	char *devname, *devsep;
1973 
1974 	KASSERT(dsp_umax >= 0 && dsp_cmax >= 0, ("Uninitialized unit!"));
1975 
1976 	if (*dev != NULL)
1977 		return;
1978 
1979 	unit = -1;
1980 	cunit = -1;
1981 	devtype = -1;
1982 	devhw = 0;
1983 	devcmax = -1;
1984 	tumax = -1;
1985 	devname = NULL;
1986 	devsep = NULL;
1987 
1988 	for (i = 0; unit == -1 &&
1989 	    i < (sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0])); i++) {
1990 		devtype = dsp_cdevs[i].type;
1991 		devname = dsp_cdevs[i].name;
1992 		devsep = dsp_cdevs[i].sep;
1993 		devhw = dsp_cdevs[i].hw;
1994 		devcmax = dsp_cdevs[i].max - 1;
1995 		if (strcmp(name, devname) == 0)
1996 			unit = snd_unit;
1997 		else if (dsp_stdclone(name, devname, devsep,
1998 		    dsp_cdevs[i].use_sep, &unit, &cunit) != 0) {
1999 			unit = -1;
2000 			cunit = -1;
2001 		}
2002 	}
2003 
2004 	d = devclass_get_softc(pcm_devclass, unit);
2005 	if (!PCM_REGISTERED(d) || d->clones == NULL)
2006 		return;
2007 
2008 	/* XXX Need Giant magic entry ??? */
2009 
2010 	pcm_lock(d);
2011 	if (snd_clone_disabled(d->clones)) {
2012 		pcm_unlock(d);
2013 		return;
2014 	}
2015 
2016 	PCM_WAIT(d);
2017 	PCM_ACQUIRE(d);
2018 	pcm_unlock(d);
2019 
2020 	udcmask = snd_u2unit(unit) | snd_d2unit(devtype);
2021 
2022 	if (devhw != 0) {
2023 		KASSERT(devcmax <= dsp_cmax,
2024 		    ("overflow: devcmax=%d, dsp_cmax=%d", devcmax, dsp_cmax));
2025 		if (cunit > devcmax) {
2026 			PCM_RELEASE_QUICK(d);
2027 			return;
2028 		}
2029 		udcmask |= snd_c2unit(cunit);
2030 		CHN_FOREACH(c, d, channels.pcm) {
2031 			CHN_LOCK(c);
2032 			if (c->unit != udcmask) {
2033 				CHN_UNLOCK(c);
2034 				continue;
2035 			}
2036 			CHN_UNLOCK(c);
2037 			udcmask &= ~snd_c2unit(cunit);
2038 			/*
2039 			 * Temporarily increase clone maxunit to overcome
2040 			 * vchan flexibility.
2041 			 *
2042 			 * # sysctl dev.pcm.0.play.vchans=256
2043 			 * dev.pcm.0.play.vchans: 1 -> 256
2044 			 * # cat /dev/zero > /dev/dsp0.vp255 &
2045 			 * [1] 17296
2046 			 * # sysctl dev.pcm.0.play.vchans=0
2047 			 * dev.pcm.0.play.vchans: 256 -> 1
2048 			 * # fg
2049 			 * [1]  + running    cat /dev/zero > /dev/dsp0.vp255
2050 			 * ^C
2051 			 * # cat /dev/zero > /dev/dsp0.vp255
2052 			 * zsh: operation not supported: /dev/dsp0.vp255
2053 			 */
2054 			tumax = snd_clone_getmaxunit(d->clones);
2055 			if (cunit > tumax)
2056 				snd_clone_setmaxunit(d->clones, cunit);
2057 			else
2058 				tumax = -1;
2059 			goto dsp_clone_alloc;
2060 		}
2061 		/*
2062 		 * Ok, so we're requesting unallocated vchan, but still
2063 		 * within maximum vchan limit.
2064 		 */
2065 		if (((devtype == SND_DEV_DSPHW_VPLAY && d->pvchancount > 0) ||
2066 		    (devtype == SND_DEV_DSPHW_VREC && d->rvchancount > 0)) &&
2067 		    cunit < snd_maxautovchans) {
2068 			udcmask &= ~snd_c2unit(cunit);
2069 			tumax = snd_clone_getmaxunit(d->clones);
2070 			if (cunit > tumax)
2071 				snd_clone_setmaxunit(d->clones, cunit);
2072 			else
2073 				tumax = -1;
2074 			goto dsp_clone_alloc;
2075 		}
2076 		PCM_RELEASE_QUICK(d);
2077 		return;
2078 	}
2079 
2080 dsp_clone_alloc:
2081 	ce = snd_clone_alloc(d->clones, dev, &cunit, udcmask);
2082 	if (tumax != -1)
2083 		snd_clone_setmaxunit(d->clones, tumax);
2084 	if (ce != NULL) {
2085 		udcmask |= snd_c2unit(cunit);
2086 		*dev = make_dev(&dsp_cdevsw, unit2minor(udcmask),
2087 		    UID_ROOT, GID_WHEEL, 0666, "%s%d%s%d",
2088 		    devname, unit, devsep, cunit);
2089 		snd_clone_register(ce, *dev);
2090 	}
2091 
2092 	PCM_RELEASE_QUICK(d);
2093 
2094 	if (*dev != NULL)
2095 		dev_ref(*dev);
2096 }
2097 
2098 static void
2099 dsp_sysinit(void *p)
2100 {
2101 	if (dsp_ehtag != NULL)
2102 		return;
2103 	/* initialize unit numbering */
2104 	snd_unit_init();
2105 	dsp_umax = PCMMAXUNIT;
2106 	dsp_cmax = PCMMAXCHAN;
2107 	dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
2108 }
2109 
2110 static void
2111 dsp_sysuninit(void *p)
2112 {
2113 	if (dsp_ehtag == NULL)
2114 		return;
2115 	EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
2116 	dsp_ehtag = NULL;
2117 }
2118 
2119 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
2120 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
2121 #endif
2122 
2123 char *
2124 dsp_unit2name(char *buf, size_t len, int unit)
2125 {
2126 	int i, dtype;
2127 
2128 	KASSERT(buf != NULL && len != 0,
2129 	    ("bogus buf=%p len=%ju", buf, (uintmax_t)len));
2130 
2131 	dtype = snd_unit2d(unit);
2132 
2133 	for (i = 0; i < (sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0])); i++) {
2134 		if (dtype != dsp_cdevs[i].type)
2135 			continue;
2136 		snprintf(buf, len, "%s%d%s%d", dsp_cdevs[i].name,
2137 		    snd_unit2u(unit), dsp_cdevs[i].sep, snd_unit2c(unit));
2138 		return (buf);
2139 	}
2140 
2141 	return (NULL);
2142 }
2143 
2144 /**
2145  * @brief Handler for SNDCTL_AUDIOINFO.
2146  *
2147  * Gathers information about the audio device specified in ai->dev.  If
2148  * ai->dev == -1, then this function gathers information about the current
2149  * device.  If the call comes in on a non-audio device and ai->dev == -1,
2150  * return EINVAL.
2151  *
2152  * This routine is supposed to go practically straight to the hardware,
2153  * getting capabilities directly from the sound card driver, side-stepping
2154  * the intermediate channel interface.
2155  *
2156  * Note, however, that the usefulness of this command is significantly
2157  * decreased when requesting info about any device other than the one serving
2158  * the request. While each snddev_channel refers to a specific device node,
2159  * the converse is *not* true.  Currently, when a sound device node is opened,
2160  * the sound subsystem scans for an available audio channel (or channels, if
2161  * opened in read+write) and then assigns them to the si_drv[12] private
2162  * data fields.  As a result, any information returned linking a channel to
2163  * a specific character device isn't necessarily accurate.
2164  *
2165  * @note
2166  * Calling threads must not hold any snddev_info or pcm_channel locks.
2167  *
2168  * @param dev		device on which the ioctl was issued
2169  * @param ai		ioctl request data container
2170  *
2171  * @retval 0		success
2172  * @retval EINVAL	ai->dev specifies an invalid device
2173  *
2174  * @todo Verify correctness of Doxygen tags.  ;)
2175  */
2176 int
2177 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai)
2178 {
2179 	struct pcmchan_caps *caps;
2180 	struct pcm_channel *ch;
2181 	struct snddev_info *d;
2182 	uint32_t fmts;
2183 	int i, nchan, *rates, minch, maxch;
2184 	char *devname, buf[CHN_NAMELEN];
2185 
2186 	/*
2187 	 * If probing the device that received the ioctl, make sure it's a
2188 	 * DSP device.  (Users may use this ioctl with /dev/mixer and
2189 	 * /dev/midi.)
2190 	 */
2191 	if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2192 		return (EINVAL);
2193 
2194 	ch = NULL;
2195 	devname = NULL;
2196 	nchan = 0;
2197 	bzero(buf, sizeof(buf));
2198 
2199 	/*
2200 	 * Search for the requested audio device (channel).  Start by
2201 	 * iterating over pcm devices.
2202 	 */
2203 	for (i = 0; pcm_devclass != NULL &&
2204 	    i < devclass_get_maxunit(pcm_devclass); i++) {
2205 		d = devclass_get_softc(pcm_devclass, i);
2206 		if (!PCM_REGISTERED(d))
2207 			continue;
2208 
2209 		/* XXX Need Giant magic entry ??? */
2210 
2211 		/* See the note in function docblock */
2212 		mtx_assert(d->lock, MA_NOTOWNED);
2213 		pcm_lock(d);
2214 
2215 		CHN_FOREACH(ch, d, channels.pcm) {
2216 			mtx_assert(ch->lock, MA_NOTOWNED);
2217 			CHN_LOCK(ch);
2218 			if (ai->dev == -1) {
2219 				if (DSP_REGISTERED(d, i_dev) &&
2220 				    (ch == PCM_RDCH(i_dev) ||	/* record ch */
2221 				    ch == PCM_WRCH(i_dev))) {	/* playback ch */
2222 					devname = dsp_unit2name(buf,
2223 					    sizeof(buf), ch->unit);
2224 				}
2225 			} else if (ai->dev == nchan) {
2226 				devname = dsp_unit2name(buf, sizeof(buf),
2227 				    ch->unit);
2228 			}
2229 			if (devname != NULL)
2230 				break;
2231 			CHN_UNLOCK(ch);
2232 			++nchan;
2233 		}
2234 
2235 		if (devname != NULL) {
2236 			/*
2237 			 * At this point, the following synchronization stuff
2238 			 * has happened:
2239 			 * - a specific PCM device is locked.
2240 			 * - a specific audio channel has been locked, so be
2241 			 *   sure to unlock when exiting;
2242 			 */
2243 
2244 			caps = chn_getcaps(ch);
2245 
2246 			/*
2247 			 * With all handles collected, zero out the user's
2248 			 * container and begin filling in its fields.
2249 			 */
2250 			bzero((void *)ai, sizeof(oss_audioinfo));
2251 
2252 			ai->dev = nchan;
2253 			strlcpy(ai->name, ch->name,  sizeof(ai->name));
2254 
2255 			if ((ch->flags & CHN_F_BUSY) == 0)
2256 				ai->busy = 0;
2257 			else
2258 				ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ;
2259 
2260 			/**
2261 			 * @note
2262 			 * @c cmd - OSSv4 docs: "Only supported under Linux at
2263 			 *    this moment." Cop-out, I know, but I'll save
2264 			 *    running around in the process table for later.
2265 			 *    Is there a risk of leaking information?
2266 			 */
2267 			ai->pid = ch->pid;
2268 
2269 			/*
2270 			 * These flags stolen from SNDCTL_DSP_GETCAPS handler.
2271 			 * Note, however, that a single channel operates in
2272 			 * only one direction, so DSP_CAP_DUPLEX is out.
2273 			 */
2274 			/**
2275 			 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep
2276 			 *       these in pcmchan::caps?
2277 			 */
2278 			ai->caps = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER;
2279 
2280 			/*
2281 			 * Collect formats supported @b natively by the
2282 			 * device.  Also determine min/max channels.  (I.e.,
2283 			 * mono, stereo, or both?)
2284 			 *
2285 			 * If any channel is stereo, maxch = 2;
2286 			 * if all channels are stereo, minch = 2, too;
2287 			 * if any channel is mono, minch = 1;
2288 			 * and if all channels are mono, maxch = 1.
2289 			 */
2290 			minch = 0;
2291 			maxch = 0;
2292 			fmts = 0;
2293 			for (i = 0; caps->fmtlist[i]; i++) {
2294 				fmts |= caps->fmtlist[i];
2295 				if (caps->fmtlist[i] & AFMT_STEREO) {
2296 					minch = (minch == 0) ? 2 : minch;
2297 					maxch = 2;
2298 				} else {
2299 					minch = 1;
2300 					maxch = (maxch == 0) ? 1 : maxch;
2301 				}
2302 			}
2303 
2304 			if (ch->direction == PCMDIR_PLAY)
2305 				ai->oformats = fmts;
2306 			else
2307 				ai->iformats = fmts;
2308 
2309 			/**
2310 			 * @note
2311 			 * @c magic - OSSv4 docs: "Reserved for internal use
2312 			 *    by OSS."
2313 			 *
2314 			 * @par
2315 			 * @c card_number - OSSv4 docs: "Number of the sound
2316 			 *    card where this device belongs or -1 if this
2317 			 *    information is not available.  Applications
2318 			 *    should normally not use this field for any
2319 			 *    purpose."
2320 			 */
2321 			ai->card_number = -1;
2322 			/**
2323 			 * @todo @c song_name - depends first on
2324 			 *          SNDCTL_[GS]ETSONG @todo @c label - depends
2325 			 *          on SNDCTL_[GS]ETLABEL
2326 			 * @todo @c port_number - routing information?
2327 			 */
2328 			ai->port_number = -1;
2329 			ai->mixer_dev = (d->mixer_dev != NULL) ? PCMUNIT(d->mixer_dev) : -1;
2330 			/**
2331 			 * @note
2332 			 * @c real_device - OSSv4 docs:  "Obsolete."
2333 			 */
2334 			ai->real_device = -1;
2335 			strlcpy(ai->devnode, devname, sizeof(ai->devnode));
2336 			ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2337 			/**
2338 			 * @note
2339 			 * @c flags - OSSv4 docs: "Reserved for future use."
2340 			 *
2341 			 * @note
2342 			 * @c binding - OSSv4 docs: "Reserved for future use."
2343 			 *
2344 			 * @todo @c handle - haven't decided how to generate
2345 			 *       this yet; bus, vendor, device IDs?
2346 			 */
2347 			ai->min_rate = caps->minspeed;
2348 			ai->max_rate = caps->maxspeed;
2349 
2350 			ai->min_channels = minch;
2351 			ai->max_channels = maxch;
2352 
2353 			ai->nrates = chn_getrates(ch, &rates);
2354 			if (ai->nrates > OSS_MAX_SAMPLE_RATES)
2355 				ai->nrates = OSS_MAX_SAMPLE_RATES;
2356 
2357 			for (i = 0; i < ai->nrates; i++)
2358 				ai->rates[i] = rates[i];
2359 
2360 			CHN_UNLOCK(ch);
2361 		}
2362 
2363 		pcm_unlock(d);
2364 
2365 		if (devname != NULL)
2366 			return (0);
2367 	}
2368 
2369 	/* Exhausted the search -- nothing is locked, so return. */
2370 	return (EINVAL);
2371 }
2372 
2373 /**
2374  * @brief Assigns a PCM channel to a sync group.
2375  *
2376  * Sync groups are used to enable audio operations on multiple devices
2377  * simultaneously.  They may be used with any number of devices and may
2378  * span across applications.  Devices are added to groups with
2379  * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the
2380  * SNDCTL_DSP_SYNCSTART ioctl.
2381  *
2382  * If the @c id field of the @c group parameter is set to zero, then a new
2383  * sync group is created.  Otherwise, wrch and rdch (if set) are added to
2384  * the group specified.
2385  *
2386  * @todo As far as memory allocation, should we assume that things are
2387  * 	 okay and allocate with M_WAITOK before acquiring channel locks,
2388  * 	 freeing later if not?
2389  *
2390  * @param wrch	output channel associated w/ device (if any)
2391  * @param rdch	input channel associated w/ device (if any)
2392  * @param group Sync group parameters
2393  *
2394  * @retval 0		success
2395  * @retval non-zero	error to be propagated upstream
2396  */
2397 static int
2398 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group)
2399 {
2400 	struct pcmchan_syncmember *smrd, *smwr;
2401 	struct pcmchan_syncgroup *sg;
2402 	int ret, sg_ids[3];
2403 
2404 	smrd = NULL;
2405 	smwr = NULL;
2406 	sg = NULL;
2407 	ret = 0;
2408 
2409 	/*
2410 	 * Free_unr() may sleep, so store released syncgroup IDs until after
2411 	 * all locks are released.
2412 	 */
2413 	sg_ids[0] = sg_ids[1] = sg_ids[2] = 0;
2414 
2415 	PCM_SG_LOCK();
2416 
2417 	/*
2418 	 * - Insert channel(s) into group's member list.
2419 	 * - Set CHN_F_NOTRIGGER on channel(s).
2420 	 * - Stop channel(s).
2421 	 */
2422 
2423 	/*
2424 	 * If device's channels are already mapped to a group, unmap them.
2425 	 */
2426 	if (wrch) {
2427 		CHN_LOCK(wrch);
2428 		sg_ids[0] = chn_syncdestroy(wrch);
2429 	}
2430 
2431 	if (rdch) {
2432 		CHN_LOCK(rdch);
2433 		sg_ids[1] = chn_syncdestroy(rdch);
2434 	}
2435 
2436 	/*
2437 	 * Verify that mode matches character device properites.
2438 	 *  - Bail if PCM_ENABLE_OUTPUT && wrch == NULL.
2439 	 *  - Bail if PCM_ENABLE_INPUT && rdch == NULL.
2440 	 */
2441 	if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) ||
2442 	    ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) {
2443 		ret = EINVAL;
2444 		goto out;
2445 	}
2446 
2447 	/*
2448 	 * An id of zero indicates the user wants to create a new
2449 	 * syncgroup.
2450 	 */
2451 	if (group->id == 0) {
2452 		sg = (struct pcmchan_syncgroup *)malloc(sizeof(*sg), M_DEVBUF, M_NOWAIT);
2453 		if (sg != NULL) {
2454 			SLIST_INIT(&sg->members);
2455 			sg->id = alloc_unr(pcmsg_unrhdr);
2456 
2457 			group->id = sg->id;
2458 			SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link);
2459 		} else
2460 			ret = ENOMEM;
2461 	} else {
2462 		SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2463 			if (sg->id == group->id)
2464 				break;
2465 		}
2466 		if (sg == NULL)
2467 			ret = EINVAL;
2468 	}
2469 
2470 	/* Couldn't create or find a syncgroup.  Fail. */
2471 	if (sg == NULL)
2472 		goto out;
2473 
2474 	/*
2475 	 * Allocate a syncmember, assign it and a channel together, and
2476 	 * insert into syncgroup.
2477 	 */
2478 	if (group->mode & PCM_ENABLE_INPUT) {
2479 		smrd = (struct pcmchan_syncmember *)malloc(sizeof(*smrd), M_DEVBUF, M_NOWAIT);
2480 		if (smrd == NULL) {
2481 			ret = ENOMEM;
2482 			goto out;
2483 		}
2484 
2485 		SLIST_INSERT_HEAD(&sg->members, smrd, link);
2486 		smrd->parent = sg;
2487 		smrd->ch = rdch;
2488 
2489 		chn_abort(rdch);
2490 		rdch->flags |= CHN_F_NOTRIGGER;
2491 		rdch->sm = smrd;
2492 	}
2493 
2494 	if (group->mode & PCM_ENABLE_OUTPUT) {
2495 		smwr = (struct pcmchan_syncmember *)malloc(sizeof(*smwr), M_DEVBUF, M_NOWAIT);
2496 		if (smwr == NULL) {
2497 			ret = ENOMEM;
2498 			goto out;
2499 		}
2500 
2501 		SLIST_INSERT_HEAD(&sg->members, smwr, link);
2502 		smwr->parent = sg;
2503 		smwr->ch = wrch;
2504 
2505 		chn_abort(wrch);
2506 		wrch->flags |= CHN_F_NOTRIGGER;
2507 		wrch->sm = smwr;
2508 	}
2509 
2510 
2511 out:
2512 	if (ret != 0) {
2513 		if (smrd != NULL)
2514 			free(smrd, M_DEVBUF);
2515 		if ((sg != NULL) && SLIST_EMPTY(&sg->members)) {
2516 			sg_ids[2] = sg->id;
2517 			SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2518 			free(sg, M_DEVBUF);
2519 		}
2520 
2521 		if (wrch)
2522 			wrch->sm = NULL;
2523 		if (rdch)
2524 			rdch->sm = NULL;
2525 	}
2526 
2527 	if (wrch)
2528 		CHN_UNLOCK(wrch);
2529 	if (rdch)
2530 		CHN_UNLOCK(rdch);
2531 
2532 	PCM_SG_UNLOCK();
2533 
2534 	if (sg_ids[0])
2535 		free_unr(pcmsg_unrhdr, sg_ids[0]);
2536 	if (sg_ids[1])
2537 		free_unr(pcmsg_unrhdr, sg_ids[1]);
2538 	if (sg_ids[2])
2539 		free_unr(pcmsg_unrhdr, sg_ids[2]);
2540 
2541 	return (ret);
2542 }
2543 
2544 /**
2545  * @brief Launch a sync group into action
2546  *
2547  * Sync groups are established via SNDCTL_DSP_SYNCGROUP.  This function
2548  * iterates over all members, triggering them along the way.
2549  *
2550  * @note Caller must not hold any channel locks.
2551  *
2552  * @param sg_id	sync group identifier
2553  *
2554  * @retval 0	success
2555  * @retval non-zero	error worthy of propagating upstream to user
2556  */
2557 static int
2558 dsp_oss_syncstart(int sg_id)
2559 {
2560 	struct pcmchan_syncmember *sm, *sm_tmp;
2561 	struct pcmchan_syncgroup *sg;
2562 	struct pcm_channel *c;
2563 	int ret, needlocks;
2564 
2565 	/* Get the synclists lock */
2566 	PCM_SG_LOCK();
2567 
2568 	do {
2569 		ret = 0;
2570 		needlocks = 0;
2571 
2572 		/* Search for syncgroup by ID */
2573 		SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2574 			if (sg->id == sg_id)
2575 				break;
2576 		}
2577 
2578 		/* Return EINVAL if not found */
2579 		if (sg == NULL) {
2580 			ret = EINVAL;
2581 			break;
2582 		}
2583 
2584 		/* Any removals resulting in an empty group should've handled this */
2585 		KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup"));
2586 
2587 		/*
2588 		 * Attempt to lock all member channels - if any are already
2589 		 * locked, unlock those acquired, sleep for a bit, and try
2590 		 * again.
2591 		 */
2592 		SLIST_FOREACH(sm, &sg->members, link) {
2593 			if (CHN_TRYLOCK(sm->ch) == 0) {
2594 				int timo = hz * 5/1000;
2595 				if (timo < 1)
2596 					timo = 1;
2597 
2598 				/* Release all locked channels so far, retry */
2599 				SLIST_FOREACH(sm_tmp, &sg->members, link) {
2600 					/* sm is the member already locked */
2601 					if (sm == sm_tmp)
2602 						break;
2603 					CHN_UNLOCK(sm_tmp->ch);
2604 				}
2605 
2606 				/** @todo Is PRIBIO correct/ */
2607 				ret = msleep(sm, &snd_pcm_syncgroups_mtx,
2608 				    PRIBIO | PCATCH, "pcmsg", timo);
2609 				if (ret == EINTR || ret == ERESTART)
2610 					break;
2611 
2612 				needlocks = 1;
2613 				ret = 0; /* Assumes ret == EAGAIN... */
2614 			}
2615 		}
2616 	} while (needlocks && ret == 0);
2617 
2618 	/* Proceed only if no errors encountered. */
2619 	if (ret == 0) {
2620 		/* Launch channels */
2621 		while((sm = SLIST_FIRST(&sg->members)) != NULL) {
2622 			SLIST_REMOVE_HEAD(&sg->members, link);
2623 
2624 			c = sm->ch;
2625 			c->sm = NULL;
2626 			chn_start(c, 1);
2627 			c->flags &= ~CHN_F_NOTRIGGER;
2628 			CHN_UNLOCK(c);
2629 
2630 			free(sm, M_DEVBUF);
2631 		}
2632 
2633 		SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2634 		free(sg, M_DEVBUF);
2635 	}
2636 
2637 	PCM_SG_UNLOCK();
2638 
2639 	/*
2640 	 * Free_unr() may sleep, so be sure to give up the syncgroup lock
2641 	 * first.
2642 	 */
2643 	if (ret == 0)
2644 		free_unr(pcmsg_unrhdr, sg_id);
2645 
2646 	return (ret);
2647 }
2648 
2649 /**
2650  * @brief Handler for SNDCTL_DSP_POLICY
2651  *
2652  * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment
2653  * size and count like with SNDCTL_DSP_SETFRAGMENT.  Instead of the user
2654  * specifying those two parameters, s/he simply selects a number from 0..10
2655  * which corresponds to a buffer size.  Smaller numbers request smaller
2656  * buffers with lower latencies (at greater overhead from more frequent
2657  * interrupts), while greater numbers behave in the opposite manner.
2658  *
2659  * The 4Front spec states that a value of 5 should be the default.  However,
2660  * this implementation deviates slightly by using a linear scale without
2661  * consulting drivers.  I.e., even though drivers may have different default
2662  * buffer sizes, a policy argument of 5 will have the same result across
2663  * all drivers.
2664  *
2665  * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for
2666  * more information.
2667  *
2668  * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to
2669  * 	 work with hardware drivers directly.
2670  *
2671  * @note PCM channel arguments must not be locked by caller.
2672  *
2673  * @param wrch	Pointer to opened playback channel (optional; may be NULL)
2674  * @param rdch	" recording channel (optional; may be NULL)
2675  * @param policy Integer from [0:10]
2676  *
2677  * @retval 0	constant (for now)
2678  */
2679 static int
2680 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy)
2681 {
2682 	int ret;
2683 
2684 	if (policy < CHN_POLICY_MIN || policy > CHN_POLICY_MAX)
2685 		return (EIO);
2686 
2687 	/* Default: success */
2688 	ret = 0;
2689 
2690 	if (rdch) {
2691 		CHN_LOCK(rdch);
2692 		ret = chn_setlatency(rdch, policy);
2693 		CHN_UNLOCK(rdch);
2694 	}
2695 
2696 	if (wrch && ret == 0) {
2697 		CHN_LOCK(wrch);
2698 		ret = chn_setlatency(wrch, policy);
2699 		CHN_UNLOCK(wrch);
2700 	}
2701 
2702 	if (ret)
2703 		ret = EIO;
2704 
2705 	return (ret);
2706 }
2707 
2708 #ifdef OSSV4_EXPERIMENT
2709 /**
2710  * @brief Enable or disable "cooked" mode
2711  *
2712  * This is a handler for @c SNDCTL_DSP_COOKEDMODE.  When in cooked mode, which
2713  * is the default, the sound system handles rate and format conversions
2714  * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only
2715  * operates with 44100Hz/16bit/signed samples).
2716  *
2717  * Disabling cooked mode is intended for applications wanting to mmap()
2718  * a sound card's buffer space directly, bypassing the FreeBSD 2-stage
2719  * feeder architecture, presumably to gain as much control over audio
2720  * hardware as possible.
2721  *
2722  * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html
2723  * for more details.
2724  *
2725  * @note Currently, this function is just a stub that always returns EINVAL.
2726  *
2727  * @todo Figure out how to and actually implement this.
2728  *
2729  * @param wrch		playback channel (optional; may be NULL)
2730  * @param rdch		recording channel (optional; may be NULL)
2731  * @param enabled	0 = raw mode, 1 = cooked mode
2732  *
2733  * @retval EINVAL	Operation not yet supported.
2734  */
2735 static int
2736 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled)
2737 {
2738 	return (EINVAL);
2739 }
2740 
2741 /**
2742  * @brief Retrieve channel interleaving order
2743  *
2744  * This is the handler for @c SNDCTL_DSP_GET_CHNORDER.
2745  *
2746  * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html
2747  * for more details.
2748  *
2749  * @note As the ioctl definition is still under construction, FreeBSD
2750  * 	 does not currently support SNDCTL_DSP_GET_CHNORDER.
2751  *
2752  * @param wrch	playback channel (optional; may be NULL)
2753  * @param rdch	recording channel (optional; may be NULL)
2754  * @param map	channel map (result will be stored there)
2755  *
2756  * @retval EINVAL	Operation not yet supported.
2757  */
2758 static int
2759 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2760 {
2761 	return (EINVAL);
2762 }
2763 
2764 /**
2765  * @brief Specify channel interleaving order
2766  *
2767  * This is the handler for @c SNDCTL_DSP_SET_CHNORDER.
2768  *
2769  * @note As the ioctl definition is still under construction, FreeBSD
2770  * 	 does not currently support @c SNDCTL_DSP_SET_CHNORDER.
2771  *
2772  * @param wrch	playback channel (optional; may be NULL)
2773  * @param rdch	recording channel (optional; may be NULL)
2774  * @param map	channel map
2775  *
2776  * @retval EINVAL	Operation not yet supported.
2777  */
2778 static int
2779 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2780 {
2781 	return (EINVAL);
2782 }
2783 
2784 /**
2785  * @brief Retrieve an audio device's label
2786  *
2787  * This is a handler for the @c SNDCTL_GETLABEL ioctl.
2788  *
2789  * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2790  * for more details.
2791  *
2792  * From Hannu@4Front:  "For example ossxmix (just like some HW mixer
2793  * consoles) can show variable "labels" for certain controls. By default
2794  * the application name (say quake) is shown as the label but
2795  * applications may change the labels themselves."
2796  *
2797  * @note As the ioctl definition is still under construction, FreeBSD
2798  * 	 does not currently support @c SNDCTL_GETLABEL.
2799  *
2800  * @param wrch	playback channel (optional; may be NULL)
2801  * @param rdch	recording channel (optional; may be NULL)
2802  * @param label	label gets copied here
2803  *
2804  * @retval EINVAL	Operation not yet supported.
2805  */
2806 static int
2807 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2808 {
2809 	return (EINVAL);
2810 }
2811 
2812 /**
2813  * @brief Specify an audio device's label
2814  *
2815  * This is a handler for the @c SNDCTL_SETLABEL ioctl.  Please see the
2816  * comments for @c dsp_oss_getlabel immediately above.
2817  *
2818  * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2819  * for more details.
2820  *
2821  * @note As the ioctl definition is still under construction, FreeBSD
2822  * 	 does not currently support SNDCTL_SETLABEL.
2823  *
2824  * @param wrch	playback channel (optional; may be NULL)
2825  * @param rdch	recording channel (optional; may be NULL)
2826  * @param label	label gets copied from here
2827  *
2828  * @retval EINVAL	Operation not yet supported.
2829  */
2830 static int
2831 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2832 {
2833 	return (EINVAL);
2834 }
2835 
2836 /**
2837  * @brief Retrieve name of currently played song
2838  *
2839  * This is a handler for the @c SNDCTL_GETSONG ioctl.  Audio players could
2840  * tell the system the name of the currently playing song, which would be
2841  * visible in @c /dev/sndstat.
2842  *
2843  * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html
2844  * for more details.
2845  *
2846  * @note As the ioctl definition is still under construction, FreeBSD
2847  * 	 does not currently support SNDCTL_GETSONG.
2848  *
2849  * @param wrch	playback channel (optional; may be NULL)
2850  * @param rdch	recording channel (optional; may be NULL)
2851  * @param song	song name gets copied here
2852  *
2853  * @retval EINVAL	Operation not yet supported.
2854  */
2855 static int
2856 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2857 {
2858 	return (EINVAL);
2859 }
2860 
2861 /**
2862  * @brief Retrieve name of currently played song
2863  *
2864  * This is a handler for the @c SNDCTL_SETSONG ioctl.  Audio players could
2865  * tell the system the name of the currently playing song, which would be
2866  * visible in @c /dev/sndstat.
2867  *
2868  * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html
2869  * for more details.
2870  *
2871  * @note As the ioctl definition is still under construction, FreeBSD
2872  * 	 does not currently support SNDCTL_SETSONG.
2873  *
2874  * @param wrch	playback channel (optional; may be NULL)
2875  * @param rdch	recording channel (optional; may be NULL)
2876  * @param song	song name gets copied from here
2877  *
2878  * @retval EINVAL	Operation not yet supported.
2879  */
2880 static int
2881 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2882 {
2883 	return (EINVAL);
2884 }
2885 
2886 /**
2887  * @brief Rename a device
2888  *
2889  * This is a handler for the @c SNDCTL_SETNAME ioctl.
2890  *
2891  * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for
2892  * more details.
2893  *
2894  * From Hannu@4Front:  "This call is used to change the device name
2895  * reported in /dev/sndstat and ossinfo. So instead of  using some generic
2896  * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull
2897  * name depending on the current context (for example 'OSS virtual wave table
2898  * synth' or 'VoIP link to London')."
2899  *
2900  * @note As the ioctl definition is still under construction, FreeBSD
2901  * 	 does not currently support SNDCTL_SETNAME.
2902  *
2903  * @param wrch	playback channel (optional; may be NULL)
2904  * @param rdch	recording channel (optional; may be NULL)
2905  * @param name	new device name gets copied from here
2906  *
2907  * @retval EINVAL	Operation not yet supported.
2908  */
2909 static int
2910 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name)
2911 {
2912 	return (EINVAL);
2913 }
2914 #endif	/* !OSSV4_EXPERIMENT */
2915