xref: /freebsd/sys/dev/sound/pcm/dsp.c (revision acd3428b7d3e94cef0e1881c868cb4b131d4ff41)
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 <sys/param.h>
28 #include <sys/queue.h>
29 
30 #include <dev/sound/pcm/sound.h>
31 
32 SND_DECLARE_FILE("$FreeBSD$");
33 
34 #define OLDPCM_IOCTL
35 
36 static d_open_t dsp_open;
37 static d_close_t dsp_close;
38 static d_read_t dsp_read;
39 static d_write_t dsp_write;
40 static d_ioctl_t dsp_ioctl;
41 static d_poll_t dsp_poll;
42 static d_mmap_t dsp_mmap;
43 
44 struct cdevsw dsp_cdevsw = {
45 	.d_version =	D_VERSION,
46 	.d_flags =	D_NEEDGIANT,
47 	.d_open =	dsp_open,
48 	.d_close =	dsp_close,
49 	.d_read =	dsp_read,
50 	.d_write =	dsp_write,
51 	.d_ioctl =	dsp_ioctl,
52 	.d_poll =	dsp_poll,
53 	.d_mmap =	dsp_mmap,
54 	.d_name =	"dsp",
55 };
56 
57 #ifdef USING_DEVFS
58 static eventhandler_tag dsp_ehtag;
59 #endif
60 
61 static int dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group);
62 static int dsp_oss_syncstart(int sg_id);
63 static int dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy);
64 #ifdef OSSV4_EXPERIMENT
65 static int dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled);
66 static int dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
67 static int dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
68 static int dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
69 static int dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
70 static int dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
71 static int dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
72 static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name);
73 #endif
74 
75 static struct snddev_info *
76 dsp_get_info(struct cdev *dev)
77 {
78 	struct snddev_info *d;
79 	int unit;
80 
81 	unit = PCMUNIT(dev);
82 	if (unit >= devclass_get_maxunit(pcm_devclass))
83 		return NULL;
84 	d = devclass_get_softc(pcm_devclass, unit);
85 
86 	return d;
87 }
88 
89 static u_int32_t
90 dsp_get_flags(struct cdev *dev)
91 {
92 	device_t bdev;
93 	int unit;
94 
95 	unit = PCMUNIT(dev);
96 	if (unit >= devclass_get_maxunit(pcm_devclass))
97 		return 0xffffffff;
98 	bdev = devclass_get_device(pcm_devclass, unit);
99 
100 	return pcm_getflags(bdev);
101 }
102 
103 static void
104 dsp_set_flags(struct cdev *dev, u_int32_t flags)
105 {
106 	device_t bdev;
107 	int unit;
108 
109 	unit = PCMUNIT(dev);
110 	if (unit >= devclass_get_maxunit(pcm_devclass))
111 		return;
112 	bdev = devclass_get_device(pcm_devclass, unit);
113 
114 	pcm_setflags(bdev, flags);
115 }
116 
117 /*
118  * return the channels associated with an open device instance.
119  * set the priority if the device is simplex and one direction (only) is
120  * specified.
121  * lock channels specified.
122  */
123 static int
124 getchns(struct cdev *dev, struct pcm_channel **rdch, struct pcm_channel **wrch, u_int32_t prio)
125 {
126 	struct snddev_info *d;
127 	u_int32_t flags;
128 
129 	flags = dsp_get_flags(dev);
130 	d = dsp_get_info(dev);
131 	pcm_inprog(d, 1);
132 	pcm_lock(d);
133 	KASSERT((flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \
134 		("getchns: read and write both prioritised"));
135 
136 	if ((flags & SD_F_PRIO_SET) == 0 && (prio != (SD_F_PRIO_RD | SD_F_PRIO_WR))) {
137 		flags |= prio & (SD_F_PRIO_RD | SD_F_PRIO_WR);
138 		dsp_set_flags(dev, flags);
139 	}
140 
141 	*rdch = dev->si_drv1;
142 	*wrch = dev->si_drv2;
143 	if ((flags & SD_F_SIMPLEX) && (flags & SD_F_PRIO_SET)) {
144 		if (prio) {
145 			if (*rdch && flags & SD_F_PRIO_WR) {
146 				dev->si_drv1 = NULL;
147 				*rdch = pcm_getfakechan(d);
148 			} else if (*wrch && flags & SD_F_PRIO_RD) {
149 				dev->si_drv2 = NULL;
150 				*wrch = pcm_getfakechan(d);
151 			}
152 		}
153 
154 		pcm_getfakechan(d)->flags |= CHN_F_BUSY;
155 	}
156 	pcm_unlock(d);
157 
158 	if (*rdch && *rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD))
159 		CHN_LOCK(*rdch);
160 	if (*wrch && *wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR))
161 		CHN_LOCK(*wrch);
162 
163 	return 0;
164 }
165 
166 /* unlock specified channels */
167 static void
168 relchns(struct cdev *dev, struct pcm_channel *rdch, struct pcm_channel *wrch, u_int32_t prio)
169 {
170 	struct snddev_info *d;
171 
172 	d = dsp_get_info(dev);
173 	if (wrch && wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR))
174 		CHN_UNLOCK(wrch);
175 	if (rdch && rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD))
176 		CHN_UNLOCK(rdch);
177 	pcm_inprog(d, -1);
178 }
179 
180 static int
181 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
182 {
183 	struct pcm_channel *rdch, *wrch;
184 	struct snddev_info *d;
185 	u_int32_t fmt;
186 	int devtype;
187 	int error;
188 	int chnum;
189 
190 	if (i_dev == NULL || td == NULL)
191 		return ENODEV;
192 
193 	if ((flags & (FREAD | FWRITE)) == 0)
194 		return EINVAL;
195 
196 	d = dsp_get_info(i_dev);
197 	devtype = PCMDEV(i_dev);
198 	chnum = -1;
199 
200 	/* decide default format */
201 	switch (devtype) {
202 	case SND_DEV_DSP16:
203 		fmt = AFMT_S16_LE;
204 		break;
205 
206 	case SND_DEV_DSP:
207 		fmt = AFMT_U8;
208 		break;
209 
210 	case SND_DEV_AUDIO:
211 		fmt = AFMT_MU_LAW;
212 		break;
213 
214 	case SND_DEV_NORESET:
215 		fmt = 0;
216 		break;
217 
218 	case SND_DEV_DSPREC:
219 		fmt = AFMT_U8;
220 		if (flags & FWRITE)
221 			return EINVAL;
222 		chnum = PCMCHAN(i_dev);
223 		break;
224 
225 	default:
226 		panic("impossible devtype %d", devtype);
227 	}
228 
229 	/* lock snddev so nobody else can monkey with it */
230 	pcm_lock(d);
231 
232 	rdch = i_dev->si_drv1;
233 	wrch = i_dev->si_drv2;
234 
235 	if (rdch || wrch || ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) &&
236 		    (flags & (FREAD | FWRITE)) == (FREAD | FWRITE))) {
237 		/* simplex or not, better safe than sorry. */
238 		pcm_unlock(d);
239 		return EBUSY;
240 	}
241 
242 	/*
243 	 * if we get here, the open request is valid- either:
244 	 *   * we were previously not open
245 	 *   * we were open for play xor record and the opener wants
246 	 *     the non-open direction
247 	 */
248 	if (flags & FREAD) {
249 		/* open for read */
250 		pcm_unlock(d);
251 		error = pcm_chnalloc(d, &rdch, PCMDIR_REC, td->td_proc->p_pid, chnum);
252 		if (error != 0 && error != EBUSY && chnum != -1 && (flags & FWRITE))
253 			error = pcm_chnalloc(d, &rdch, PCMDIR_REC, td->td_proc->p_pid, -1);
254 
255 		if (error == 0 && (chn_reset(rdch, fmt) ||
256 				(fmt && chn_setspeed(rdch, DSP_DEFAULT_SPEED))))
257 			error = ENODEV;
258 
259 		if (error != 0) {
260 			if (rdch)
261 				pcm_chnrelease(rdch);
262 			return error;
263 		}
264 
265 		if (flags & O_NONBLOCK)
266 			rdch->flags |= CHN_F_NBIO;
267 		pcm_chnref(rdch, 1);
268 	 	CHN_UNLOCK(rdch);
269 		pcm_lock(d);
270 	}
271 
272 	if (flags & FWRITE) {
273 	    /* open for write */
274 	    pcm_unlock(d);
275 	    error = pcm_chnalloc(d, &wrch, PCMDIR_PLAY, td->td_proc->p_pid, chnum);
276 	    if (error != 0 && error != EBUSY && chnum != -1 && (flags & FREAD))
277 	    	error = pcm_chnalloc(d, &wrch, PCMDIR_PLAY, td->td_proc->p_pid, -1);
278 
279 	    if (error == 0 && (chn_reset(wrch, fmt) ||
280 	    		(fmt && chn_setspeed(wrch, DSP_DEFAULT_SPEED))))
281 		error = ENODEV;
282 
283 	    if (error != 0) {
284 		if (wrch)
285 		    pcm_chnrelease(wrch);
286 		if (rdch) {
287 		    /*
288 		     * Lock, deref and release previously created record channel
289 		     */
290 		    CHN_LOCK(rdch);
291 		    pcm_chnref(rdch, -1);
292 		    pcm_chnrelease(rdch);
293 		}
294 
295 		return error;
296 	    }
297 
298 	    if (flags & O_NONBLOCK)
299 		wrch->flags |= CHN_F_NBIO;
300 	    pcm_chnref(wrch, 1);
301 	    CHN_UNLOCK(wrch);
302 	    pcm_lock(d);
303 	}
304 
305 	i_dev->si_drv1 = rdch;
306 	i_dev->si_drv2 = wrch;
307 
308 	pcm_unlock(d);
309 	return 0;
310 }
311 
312 static int
313 dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
314 {
315 	struct pcm_channel *rdch, *wrch;
316 	struct snddev_info *d;
317 	int refs, sg_ids[2];
318 
319 	d = dsp_get_info(i_dev);
320 	pcm_lock(d);
321 	rdch = i_dev->si_drv1;
322 	wrch = i_dev->si_drv2;
323 	pcm_unlock(d);
324 
325 	/*
326 	 * Free_unr() may sleep, so store released syncgroup IDs until after
327 	 * all locks are released.
328 	 */
329 	sg_ids[0] = sg_ids[1] = 0;
330 
331 	if (rdch || wrch) {
332 		refs = 0;
333 		if (rdch) {
334 			/*
335 			 * The channel itself need not be locked because:
336 			 *   a)  Adding a channel to a syncgroup happens only in dsp_ioctl(),
337 			 *       which cannot run concurrently to dsp_close().
338 			 *   b)  The syncmember pointer (sm) is protected by the global
339 			 *       syncgroup list lock.
340 			 *   c)  A channel can't just disappear, invalidating pointers,
341 			 *       unless it's closed/dereferenced first.
342 			 */
343 			PCM_SG_LOCK();
344 			sg_ids[0] = chn_syncdestroy(rdch);
345 			PCM_SG_UNLOCK();
346 
347 			CHN_LOCK(rdch);
348 			refs += pcm_chnref(rdch, -1);
349 			chn_abort(rdch); /* won't sleep */
350 			rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
351 			chn_reset(rdch, 0);
352 			pcm_chnrelease(rdch);
353 		}
354 		if (wrch) {
355 			/*
356 			 * Please see block above.
357 			 */
358 			PCM_SG_LOCK();
359 			sg_ids[1] = chn_syncdestroy(wrch);
360 			PCM_SG_UNLOCK();
361 
362 			CHN_LOCK(wrch);
363 			refs += pcm_chnref(wrch, -1);
364 			/*
365 			 * XXX: Maybe the right behaviour is to abort on non_block.
366 			 * It seems that mplayer flushes the audio queue by quickly
367 			 * closing and re-opening.  In FBSD, there's a long pause
368 			 * while the audio queue flushes that I presume isn't there in
369 			 * linux.
370 			 */
371 			chn_flush(wrch); /* may sleep */
372 			wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
373 			chn_reset(wrch, 0);
374 			pcm_chnrelease(wrch);
375 		}
376 
377 		pcm_lock(d);
378 		if (rdch)
379 			i_dev->si_drv1 = NULL;
380 		if (wrch)
381 			i_dev->si_drv2 = NULL;
382 		/*
383 		 * If there are no more references, release the channels.
384 		 */
385 		if (refs == 0 && i_dev->si_drv1 == NULL &&
386 			    i_dev->si_drv2 == NULL) {
387 			if (pcm_getfakechan(d))
388 				pcm_getfakechan(d)->flags = 0;
389 			/* What is this?!? */
390 			dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT);
391 		}
392 		pcm_unlock(d);
393 	}
394 
395 
396 	if (sg_ids[0])
397 		free_unr(pcmsg_unrhdr, sg_ids[0]);
398 	if (sg_ids[1])
399 		free_unr(pcmsg_unrhdr, sg_ids[1]);
400 
401 	return 0;
402 }
403 
404 static int
405 dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
406 {
407 	struct pcm_channel *rdch, *wrch;
408 	int ret;
409 
410 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD);
411 
412 	KASSERT(rdch, ("dsp_read: nonexistant channel"));
413 	KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel"));
414 
415 	if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
416 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
417 		return EINVAL;
418 	}
419 	if (!(rdch->flags & CHN_F_RUNNING))
420 		rdch->flags |= CHN_F_RUNNING;
421 	ret = chn_read(rdch, buf);
422 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
423 
424 	return ret;
425 }
426 
427 static int
428 dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
429 {
430 	struct pcm_channel *rdch, *wrch;
431 	int ret;
432 
433 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_WR);
434 
435 	KASSERT(wrch, ("dsp_write: nonexistant channel"));
436 	KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel"));
437 
438 	if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
439 		relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
440 		return EINVAL;
441 	}
442 	if (!(wrch->flags & CHN_F_RUNNING))
443 		wrch->flags |= CHN_F_RUNNING;
444 
445 	/*
446 	 * Chn_write() must give up channel lock in order to copy bytes from
447 	 * userland, so up the "in progress" counter to make sure someone
448 	 * else doesn't come along and muss up the buffer.
449 	 */
450 	++wrch->inprog;
451 	ret = chn_write(wrch, buf);
452 	--wrch->inprog;
453 	cv_signal(&wrch->cv);
454 
455 	relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
456 
457 	return ret;
458 }
459 
460 static int
461 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
462 {
463     	struct pcm_channel *chn, *rdch, *wrch;
464 	struct snddev_info *d;
465 	int kill;
466     	int ret = 0, *arg_i = (int *)arg, tmp;
467 	int xcmd;
468 
469 	xcmd = 0;
470 
471 	/*
472 	 * this is an evil hack to allow broken apps to perform mixer ioctls
473 	 * on dsp devices.
474 	 */
475 
476 	d = dsp_get_info(i_dev);
477 	if (IOCGROUP(cmd) == 'M') {
478 		/*
479 		 * This is at least, a bug to bug compatible with OSS.
480 		 */
481 		if (d->mixer_dev != NULL)
482 			return mixer_ioctl(d->mixer_dev, cmd, arg, -1, td);
483 		else
484 			return EBADF;
485 	}
486 
487 	/*
488 	 * Certain ioctls may be made on any type of device (audio, mixer,
489 	 * and MIDI).  Handle those special cases here.
490 	 */
491 	if (IOCGROUP(cmd) == 'X') {
492 		switch(cmd) {
493 		case SNDCTL_SYSINFO:
494 			sound_oss_sysinfo((oss_sysinfo *)arg);
495 			break;
496 		case SNDCTL_AUDIOINFO:
497 			ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg);
498 			break;
499 		case SNDCTL_MIXERINFO:
500 			ret = mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg);
501 			break;
502 		default:
503 			ret = EINVAL;
504 		}
505 
506 		return ret;
507 	}
508 
509 	getchns(i_dev, &rdch, &wrch, 0);
510 
511 	kill = 0;
512 	if (wrch && (wrch->flags & CHN_F_DEAD))
513 		kill |= 1;
514 	if (rdch && (rdch->flags & CHN_F_DEAD))
515 		kill |= 2;
516 	if (kill == 3) {
517 		relchns(i_dev, rdch, wrch, 0);
518 		return EINVAL;
519 	}
520 	if (kill & 1)
521 		wrch = NULL;
522 	if (kill & 2)
523 		rdch = NULL;
524 
525     	switch(cmd) {
526 #ifdef OLDPCM_IOCTL
527     	/*
528      	 * we start with the new ioctl interface.
529      	 */
530     	case AIONWRITE:	/* how many bytes can write ? */
531 		if (wrch) {
532 			CHN_LOCK(wrch);
533 /*
534 		if (wrch && wrch->bufhard.dl)
535 			while (chn_wrfeed(wrch) == 0);
536 */
537 			*arg_i = sndbuf_getfree(wrch->bufsoft);
538 			CHN_UNLOCK(wrch);
539 		} else {
540 			*arg_i = 0;
541 			ret = EINVAL;
542 		}
543 		break;
544 
545     	case AIOSSIZE:     /* set the current blocksize */
546 		{
547 	    		struct snd_size *p = (struct snd_size *)arg;
548 
549 			p->play_size = 0;
550 			p->rec_size = 0;
551 	    		if (wrch) {
552 				CHN_LOCK(wrch);
553 				chn_setblocksize(wrch, 2, p->play_size);
554 				p->play_size = sndbuf_getblksz(wrch->bufsoft);
555 				CHN_UNLOCK(wrch);
556 			}
557 	    		if (rdch) {
558 				CHN_LOCK(rdch);
559 				chn_setblocksize(rdch, 2, p->rec_size);
560 				p->rec_size = sndbuf_getblksz(rdch->bufsoft);
561 				CHN_UNLOCK(rdch);
562 			}
563 		}
564 		break;
565     	case AIOGSIZE:	/* get the current blocksize */
566 		{
567 	    		struct snd_size *p = (struct snd_size *)arg;
568 
569 	    		if (wrch) {
570 				CHN_LOCK(wrch);
571 				p->play_size = sndbuf_getblksz(wrch->bufsoft);
572 				CHN_UNLOCK(wrch);
573 			}
574 	    		if (rdch) {
575 				CHN_LOCK(rdch);
576 				p->rec_size = sndbuf_getblksz(rdch->bufsoft);
577 				CHN_UNLOCK(rdch);
578 			}
579 		}
580 		break;
581 
582     	case AIOSFMT:
583     	case AIOGFMT:
584 		{
585 	    		snd_chan_param *p = (snd_chan_param *)arg;
586 
587 			if (cmd == AIOSFMT &&
588 			    ((p->play_format != 0 && p->play_rate == 0) ||
589 			    (p->rec_format != 0 && p->rec_rate == 0))) {
590 				ret = EINVAL;
591 				break;
592 			}
593 	    		if (wrch) {
594 				CHN_LOCK(wrch);
595 				if (cmd == AIOSFMT && p->play_format != 0) {
596 					chn_setformat(wrch, p->play_format);
597 					chn_setspeed(wrch, p->play_rate);
598 				}
599 	    			p->play_rate = wrch->speed;
600 	    			p->play_format = wrch->format;
601 				CHN_UNLOCK(wrch);
602 			} else {
603 	    			p->play_rate = 0;
604 	    			p->play_format = 0;
605 	    		}
606 	    		if (rdch) {
607 				CHN_LOCK(rdch);
608 				if (cmd == AIOSFMT && p->rec_format != 0) {
609 					chn_setformat(rdch, p->rec_format);
610 					chn_setspeed(rdch, p->rec_rate);
611 				}
612 				p->rec_rate = rdch->speed;
613 				p->rec_format = rdch->format;
614 				CHN_UNLOCK(rdch);
615 			} else {
616 	    			p->rec_rate = 0;
617 	    			p->rec_format = 0;
618 	    		}
619 		}
620 		break;
621 
622     	case AIOGCAP:     /* get capabilities */
623 		{
624 	    		snd_capabilities *p = (snd_capabilities *)arg;
625 			struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
626 			struct cdev *pdev;
627 
628 			if (rdch) {
629 				CHN_LOCK(rdch);
630 				rcaps = chn_getcaps(rdch);
631 			}
632 			if (wrch) {
633 				CHN_LOCK(wrch);
634 				pcaps = chn_getcaps(wrch);
635 			}
636 	    		p->rate_min = max(rcaps? rcaps->minspeed : 0,
637 	                      		  pcaps? pcaps->minspeed : 0);
638 	    		p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
639 	                      		  pcaps? pcaps->maxspeed : 1000000);
640 	    		p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
641 	                     		 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
642 			/* XXX bad on sb16 */
643 	    		p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
644 			 	     (wrch? chn_getformats(wrch) : 0xffffffff);
645 			if (rdch && wrch)
646 				p->formats |= (dsp_get_flags(i_dev) & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX;
647 			pdev = d->mixer_dev;
648 	    		p->mixers = 1; /* default: one mixer */
649 	    		p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
650 	    		p->left = p->right = 100;
651 			if (rdch)
652 				CHN_UNLOCK(rdch);
653 			if (wrch)
654 				CHN_UNLOCK(wrch);
655 		}
656 		break;
657 
658     	case AIOSTOP:
659 		if (*arg_i == AIOSYNC_PLAY && wrch) {
660 			CHN_LOCK(wrch);
661 			*arg_i = chn_abort(wrch);
662 			CHN_UNLOCK(wrch);
663 		} else if (*arg_i == AIOSYNC_CAPTURE && rdch) {
664 			CHN_LOCK(rdch);
665 			*arg_i = chn_abort(rdch);
666 			CHN_UNLOCK(rdch);
667 		} else {
668 	   	 	printf("AIOSTOP: bad channel 0x%x\n", *arg_i);
669 	    		*arg_i = 0;
670 		}
671 		break;
672 
673     	case AIOSYNC:
674 		printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
675 	    		((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
676 		break;
677 #endif
678 	/*
679 	 * here follow the standard ioctls (filio.h etc.)
680 	 */
681     	case FIONREAD: /* get # bytes to read */
682 		if (rdch) {
683 			CHN_LOCK(rdch);
684 /*			if (rdch && rdch->bufhard.dl)
685 				while (chn_rdfeed(rdch) == 0);
686 */
687 			*arg_i = sndbuf_getready(rdch->bufsoft);
688 			CHN_UNLOCK(rdch);
689 		} else {
690 			*arg_i = 0;
691 			ret = EINVAL;
692 		}
693 		break;
694 
695     	case FIOASYNC: /*set/clear async i/o */
696 		DEB( printf("FIOASYNC\n") ; )
697 		break;
698 
699     	case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */
700     	case FIONBIO: /* set/clear non-blocking i/o */
701 		if (rdch) {
702 			CHN_LOCK(rdch);
703 			if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
704 				rdch->flags |= CHN_F_NBIO;
705 			else
706 				rdch->flags &= ~CHN_F_NBIO;
707 			CHN_UNLOCK(rdch);
708 		}
709 		if (wrch) {
710 			CHN_LOCK(wrch);
711 			if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
712 				wrch->flags |= CHN_F_NBIO;
713 			else
714 				wrch->flags &= ~CHN_F_NBIO;
715 			CHN_UNLOCK(wrch);
716 		}
717 		break;
718 
719     	/*
720 	 * Finally, here is the linux-compatible ioctl interface
721 	 */
722 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
723     	case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
724     	case SNDCTL_DSP_GETBLKSIZE:
725 		chn = wrch ? wrch : rdch;
726 		if (chn) {
727 			CHN_LOCK(chn);
728 			*arg_i = sndbuf_getblksz(chn->bufsoft);
729 			CHN_UNLOCK(chn);
730 		} else {
731 			*arg_i = 0;
732 			ret = EINVAL;
733 		}
734 		break ;
735 
736     	case SNDCTL_DSP_SETBLKSIZE:
737 		RANGE(*arg_i, 16, 65536);
738 		if (wrch) {
739 			CHN_LOCK(wrch);
740 			chn_setblocksize(wrch, 2, *arg_i);
741 			CHN_UNLOCK(wrch);
742 		}
743 		if (rdch) {
744 			CHN_LOCK(rdch);
745 			chn_setblocksize(rdch, 2, *arg_i);
746 			CHN_UNLOCK(rdch);
747 		}
748 		break;
749 
750     	case SNDCTL_DSP_RESET:
751 		DEB(printf("dsp reset\n"));
752 		if (wrch) {
753 			CHN_LOCK(wrch);
754 			chn_abort(wrch);
755 			chn_resetbuf(wrch);
756 			CHN_UNLOCK(wrch);
757 		}
758 		if (rdch) {
759 			CHN_LOCK(rdch);
760 			chn_abort(rdch);
761 			chn_resetbuf(rdch);
762 			CHN_UNLOCK(rdch);
763 		}
764 		break;
765 
766     	case SNDCTL_DSP_SYNC:
767 		DEB(printf("dsp sync\n"));
768 		/* chn_sync may sleep */
769 		if (wrch) {
770 			CHN_LOCK(wrch);
771 			chn_sync(wrch, sndbuf_getsize(wrch->bufsoft) - 4);
772 			CHN_UNLOCK(wrch);
773 		}
774 		break;
775 
776     	case SNDCTL_DSP_SPEED:
777 		/* chn_setspeed may sleep */
778 		tmp = 0;
779 		if (wrch) {
780 			CHN_LOCK(wrch);
781 			ret = chn_setspeed(wrch, *arg_i);
782 			tmp = wrch->speed;
783 			CHN_UNLOCK(wrch);
784 		}
785 		if (rdch && ret == 0) {
786 			CHN_LOCK(rdch);
787 			ret = chn_setspeed(rdch, *arg_i);
788 			if (tmp == 0)
789 				tmp = rdch->speed;
790 			CHN_UNLOCK(rdch);
791 		}
792 		*arg_i = tmp;
793 		break;
794 
795     	case SOUND_PCM_READ_RATE:
796 		chn = wrch ? wrch : rdch;
797 		if (chn) {
798 			CHN_LOCK(chn);
799 			*arg_i = chn->speed;
800 			CHN_UNLOCK(chn);
801 		} else {
802 			*arg_i = 0;
803 			ret = EINVAL;
804 		}
805 		break;
806 
807     	case SNDCTL_DSP_STEREO:
808 		tmp = -1;
809 		*arg_i = (*arg_i)? AFMT_STEREO : 0;
810 		if (wrch) {
811 			CHN_LOCK(wrch);
812 			ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
813 			tmp = (wrch->format & AFMT_STEREO)? 1 : 0;
814 			CHN_UNLOCK(wrch);
815 		}
816 		if (rdch && ret == 0) {
817 			CHN_LOCK(rdch);
818 			ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
819 			if (tmp == -1)
820 				tmp = (rdch->format & AFMT_STEREO)? 1 : 0;
821 			CHN_UNLOCK(rdch);
822 		}
823 		*arg_i = tmp;
824 		break;
825 
826     	case SOUND_PCM_WRITE_CHANNELS:
827 /*	case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
828 		if (*arg_i != 0) {
829 			tmp = 0;
830 			*arg_i = (*arg_i != 1)? AFMT_STEREO : 0;
831 	  		if (wrch) {
832 				CHN_LOCK(wrch);
833 				ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
834 				tmp = (wrch->format & AFMT_STEREO)? 2 : 1;
835 				CHN_UNLOCK(wrch);
836 			}
837 			if (rdch && ret == 0) {
838 				CHN_LOCK(rdch);
839 				ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
840 				if (tmp == 0)
841 					tmp = (rdch->format & AFMT_STEREO)? 2 : 1;
842 				CHN_UNLOCK(rdch);
843 			}
844 			*arg_i = tmp;
845 		} else {
846 			chn = wrch ? wrch : rdch;
847 			CHN_LOCK(chn);
848 			*arg_i = (chn->format & AFMT_STEREO) ? 2 : 1;
849 			CHN_UNLOCK(chn);
850 		}
851 		break;
852 
853     	case SOUND_PCM_READ_CHANNELS:
854 		chn = wrch ? wrch : rdch;
855 		if (chn) {
856 			CHN_LOCK(chn);
857 			*arg_i = (chn->format & AFMT_STEREO) ? 2 : 1;
858 			CHN_UNLOCK(chn);
859 		} else {
860 			*arg_i = 0;
861 			ret = EINVAL;
862 		}
863 		break;
864 
865     	case SNDCTL_DSP_GETFMTS:	/* returns a mask of supported fmts */
866 		chn = wrch ? wrch : rdch;
867 		if (chn) {
868 			CHN_LOCK(chn);
869 			*arg_i = chn_getformats(chn);
870 			CHN_UNLOCK(chn);
871 		} else {
872 			*arg_i = 0;
873 			ret = EINVAL;
874 		}
875 		break ;
876 
877     	case SNDCTL_DSP_SETFMT:	/* sets _one_ format */
878 		if ((*arg_i != AFMT_QUERY)) {
879 			tmp = 0;
880 			if (wrch) {
881 				CHN_LOCK(wrch);
882 				ret = chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO));
883 				tmp = wrch->format & ~AFMT_STEREO;
884 				CHN_UNLOCK(wrch);
885 			}
886 			if (rdch && ret == 0) {
887 				CHN_LOCK(rdch);
888 				ret = chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO));
889 				if (tmp == 0)
890 					tmp = rdch->format & ~AFMT_STEREO;
891 				CHN_UNLOCK(rdch);
892 			}
893 			*arg_i = tmp;
894 		} else {
895 			chn = wrch ? wrch : rdch;
896 			CHN_LOCK(chn);
897 			*arg_i = chn->format & ~AFMT_STEREO;
898 			CHN_UNLOCK(chn);
899 		}
900 		break;
901 
902     	case SNDCTL_DSP_SETFRAGMENT:
903 		DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
904 		{
905 			u_int32_t fragln = (*arg_i) & 0x0000ffff;
906 			u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
907 			u_int32_t fragsz;
908 			u_int32_t r_maxfrags, r_fragsz;
909 
910 			RANGE(fragln, 4, 16);
911 			fragsz = 1 << fragln;
912 
913 			if (maxfrags == 0)
914 				maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
915 			if (maxfrags < 2)
916 				maxfrags = 2;
917 			if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
918 				maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
919 
920 			DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
921 		    	if (rdch) {
922 				CHN_LOCK(rdch);
923 				ret = chn_setblocksize(rdch, maxfrags, fragsz);
924 				r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
925 				r_fragsz = sndbuf_getblksz(rdch->bufsoft);
926 				CHN_UNLOCK(rdch);
927 			} else {
928 				r_maxfrags = maxfrags;
929 				r_fragsz = fragsz;
930 			}
931 		    	if (wrch && ret == 0) {
932 				CHN_LOCK(wrch);
933 				ret = chn_setblocksize(wrch, maxfrags, fragsz);
934  				maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
935 				fragsz = sndbuf_getblksz(wrch->bufsoft);
936 				CHN_UNLOCK(wrch);
937 			} else { /* use whatever came from the read channel */
938 				maxfrags = r_maxfrags;
939 				fragsz = r_fragsz;
940 			}
941 
942 			fragln = 0;
943 			while (fragsz > 1) {
944 				fragln++;
945 				fragsz >>= 1;
946 			}
947 	    		*arg_i = (maxfrags << 16) | fragln;
948 		}
949 		break;
950 
951     	case SNDCTL_DSP_GETISPACE:
952 		/* return the size of data available in the input queue */
953 		{
954 	    		audio_buf_info *a = (audio_buf_info *)arg;
955 	    		if (rdch) {
956 	        		struct snd_dbuf *bs = rdch->bufsoft;
957 
958 				CHN_LOCK(rdch);
959 				a->bytes = sndbuf_getready(bs);
960 	        		a->fragments = a->bytes / sndbuf_getblksz(bs);
961 	        		a->fragstotal = sndbuf_getblkcnt(bs);
962 	        		a->fragsize = sndbuf_getblksz(bs);
963 				CHN_UNLOCK(rdch);
964 	    		}
965 		}
966 		break;
967 
968     	case SNDCTL_DSP_GETOSPACE:
969 		/* return space available in the output queue */
970 		{
971 	    		audio_buf_info *a = (audio_buf_info *)arg;
972 	    		if (wrch) {
973 	        		struct snd_dbuf *bs = wrch->bufsoft;
974 
975 				CHN_LOCK(wrch);
976 				/* XXX abusive DMA update: chn_wrupdate(wrch); */
977 				a->bytes = sndbuf_getfree(bs);
978 	        		a->fragments = a->bytes / sndbuf_getblksz(bs);
979 	        		a->fragstotal = sndbuf_getblkcnt(bs);
980 	        		a->fragsize = sndbuf_getblksz(bs);
981 				CHN_UNLOCK(wrch);
982 	    		}
983 		}
984 		break;
985 
986     	case SNDCTL_DSP_GETIPTR:
987 		{
988 	    		count_info *a = (count_info *)arg;
989 	    		if (rdch) {
990 	        		struct snd_dbuf *bs = rdch->bufsoft;
991 
992 				CHN_LOCK(rdch);
993 				/* XXX abusive DMA update: chn_rdupdate(rdch); */
994 	        		a->bytes = sndbuf_gettotal(bs);
995 	        		a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
996 	        		a->ptr = sndbuf_getreadyptr(bs);
997 				rdch->blocks = sndbuf_getblocks(bs);
998 				CHN_UNLOCK(rdch);
999 	    		} else
1000 				ret = EINVAL;
1001 		}
1002 		break;
1003 
1004     	case SNDCTL_DSP_GETOPTR:
1005 		{
1006 	    		count_info *a = (count_info *)arg;
1007 	    		if (wrch) {
1008 	        		struct snd_dbuf *bs = wrch->bufsoft;
1009 
1010 				CHN_LOCK(wrch);
1011 				/* XXX abusive DMA update: chn_wrupdate(wrch); */
1012 	        		a->bytes = sndbuf_gettotal(bs);
1013 	        		a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
1014 	        		a->ptr = sndbuf_getreadyptr(bs);
1015 				wrch->blocks = sndbuf_getblocks(bs);
1016 				CHN_UNLOCK(wrch);
1017 	    		} else
1018 				ret = EINVAL;
1019 		}
1020 		break;
1021 
1022     	case SNDCTL_DSP_GETCAPS:
1023 		*arg_i = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER;
1024 		if (rdch && wrch && !(dsp_get_flags(i_dev) & SD_F_SIMPLEX))
1025 			*arg_i |= DSP_CAP_DUPLEX;
1026 		break;
1027 
1028     	case SOUND_PCM_READ_BITS:
1029 		chn = wrch ? wrch : rdch;
1030 		if (chn) {
1031 			CHN_LOCK(chn);
1032 			if (chn->format & AFMT_8BIT)
1033 				*arg_i = 8;
1034 			else if (chn->format & AFMT_16BIT)
1035 				*arg_i = 16;
1036 			else if (chn->format & AFMT_24BIT)
1037 				*arg_i = 24;
1038 			else if (chn->format & AFMT_32BIT)
1039 				*arg_i = 32;
1040 			else
1041 				ret = EINVAL;
1042 			CHN_UNLOCK(chn);
1043 		} else {
1044 			*arg_i = 0;
1045 			ret = EINVAL;
1046 		}
1047 		break;
1048 
1049     	case SNDCTL_DSP_SETTRIGGER:
1050 		if (rdch) {
1051 			CHN_LOCK(rdch);
1052 			rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
1053 		    	if (*arg_i & PCM_ENABLE_INPUT)
1054 				chn_start(rdch, 1);
1055 			else
1056 				rdch->flags |= CHN_F_NOTRIGGER;
1057 			CHN_UNLOCK(rdch);
1058 		}
1059 		if (wrch) {
1060 			CHN_LOCK(wrch);
1061 			wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
1062 		    	if (*arg_i & PCM_ENABLE_OUTPUT)
1063 				chn_start(wrch, 1);
1064 			else
1065 				wrch->flags |= CHN_F_NOTRIGGER;
1066 			CHN_UNLOCK(wrch);
1067 		}
1068 		break;
1069 
1070     	case SNDCTL_DSP_GETTRIGGER:
1071 		*arg_i = 0;
1072 		if (wrch) {
1073 			CHN_LOCK(wrch);
1074 			if (wrch->flags & CHN_F_TRIGGERED)
1075 				*arg_i |= PCM_ENABLE_OUTPUT;
1076 			CHN_UNLOCK(wrch);
1077 		}
1078 		if (rdch) {
1079 			CHN_LOCK(rdch);
1080 			if (rdch->flags & CHN_F_TRIGGERED)
1081 				*arg_i |= PCM_ENABLE_INPUT;
1082 			CHN_UNLOCK(rdch);
1083 		}
1084 		break;
1085 
1086 	case SNDCTL_DSP_GETODELAY:
1087 		if (wrch) {
1088 			struct snd_dbuf *b = wrch->bufhard;
1089 	        	struct snd_dbuf *bs = wrch->bufsoft;
1090 
1091 			CHN_LOCK(wrch);
1092 			/* XXX abusive DMA update: chn_wrupdate(wrch); */
1093 			*arg_i = sndbuf_getready(b) + sndbuf_getready(bs);
1094 			CHN_UNLOCK(wrch);
1095 		} else
1096 			ret = EINVAL;
1097 		break;
1098 
1099     	case SNDCTL_DSP_POST:
1100 		if (wrch) {
1101 			CHN_LOCK(wrch);
1102 			wrch->flags &= ~CHN_F_NOTRIGGER;
1103 			chn_start(wrch, 1);
1104 			CHN_UNLOCK(wrch);
1105 		}
1106 		break;
1107 
1108 	case SNDCTL_DSP_SETDUPLEX:
1109 		/*
1110 		 * switch to full-duplex mode if card is in half-duplex
1111 		 * mode and is able to work in full-duplex mode
1112 		 */
1113 		if (rdch && wrch && (dsp_get_flags(i_dev) & SD_F_SIMPLEX))
1114 			dsp_set_flags(i_dev, dsp_get_flags(i_dev)^SD_F_SIMPLEX);
1115 		break;
1116 
1117 	/*
1118 	 * The following four ioctls are simple wrappers around mixer_ioctl
1119 	 * with no further processing.  xcmd is short for "translated
1120 	 * command".
1121 	 */
1122 	case SNDCTL_DSP_GETRECVOL:
1123 		if (xcmd == 0)
1124 			xcmd = SOUND_MIXER_READ_RECLEV;
1125 		/* FALLTHROUGH */
1126 	case SNDCTL_DSP_SETRECVOL:
1127 		if (xcmd == 0)
1128 			xcmd = SOUND_MIXER_WRITE_RECLEV;
1129 		/* FALLTHROUGH */
1130 	case SNDCTL_DSP_GETPLAYVOL:
1131 		if (xcmd == 0)
1132 			xcmd = SOUND_MIXER_READ_PCM;
1133 		/* FALLTHROUGH */
1134 	case SNDCTL_DSP_SETPLAYVOL:
1135 		if (xcmd == 0)
1136 			xcmd = SOUND_MIXER_WRITE_PCM;
1137 
1138 		if (d->mixer_dev != NULL)
1139 			ret = mixer_ioctl(d->mixer_dev, xcmd, arg, -1, td);
1140 		else
1141 			ret = ENOTSUP;
1142 		break;
1143 
1144 	case SNDCTL_DSP_GET_RECSRC_NAMES:
1145 	case SNDCTL_DSP_GET_RECSRC:
1146 	case SNDCTL_DSP_SET_RECSRC:
1147 		if (d->mixer_dev != NULL)
1148 			ret = mixer_ioctl(d->mixer_dev, cmd, arg, -1, td);
1149 		else
1150 			ret = ENOTSUP;
1151 		break;
1152 
1153 	/*
1154 	 * The following 3 ioctls aren't very useful at the moment.  For
1155 	 * now, only a single channel is associated with a cdev (/dev/dspN
1156 	 * instance), so there's only a single output routing to use (i.e.,
1157 	 * the wrch bound to this cdev).
1158 	 */
1159 	case SNDCTL_DSP_GET_PLAYTGT_NAMES:
1160 		{
1161 			oss_mixer_enuminfo *ei;
1162 			ei = (oss_mixer_enuminfo *)arg;
1163 			ei->dev = 0;
1164 			ei->ctrl = 0;
1165 			ei->version = 0; /* static for now */
1166 			ei->strindex[0] = 0;
1167 
1168 			if (wrch != NULL) {
1169 				ei->nvalues = 1;
1170 				strlcpy(ei->strings, wrch->name,
1171 					sizeof(ei->strings));
1172 			} else {
1173 				ei->nvalues = 0;
1174 				ei->strings[0] = '\0';
1175 			}
1176 		}
1177 		break;
1178 	case SNDCTL_DSP_GET_PLAYTGT:
1179 	case SNDCTL_DSP_SET_PLAYTGT:	/* yes, they are the same for now */
1180 		/*
1181 		 * Re: SET_PLAYTGT
1182 		 *   OSSv4: "The value that was accepted by the device will
1183 		 *   be returned back in the variable pointed by the
1184 		 *   argument."
1185 		 */
1186 		if (wrch != NULL)
1187 			*arg_i = 0;
1188 		else
1189 			ret = EINVAL;
1190 		break;
1191 
1192 	case SNDCTL_DSP_SILENCE:
1193 	/*
1194 	 * Flush the software (pre-feed) buffer, but try to minimize playback
1195 	 * interruption.  (I.e., record unplayed samples with intent to
1196 	 * restore by SNDCTL_DSP_SKIP.) Intended for application "pause"
1197 	 * functionality.
1198 	 */
1199 		if (wrch == NULL)
1200 			ret = EINVAL;
1201 		else {
1202 			struct snd_dbuf *bs;
1203 			CHN_LOCK(wrch);
1204 			while (wrch->inprog != 0)
1205 				cv_wait(&wrch->cv, wrch->lock);
1206 			bs = wrch->bufsoft;
1207 			if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) {
1208 				bs->sl = sndbuf_getready(bs);
1209 				sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs));
1210 				sndbuf_fillsilence(bs);
1211 				chn_start(wrch, 0);
1212 			}
1213 			CHN_UNLOCK(wrch);
1214 		}
1215 		break;
1216 
1217 	case SNDCTL_DSP_SKIP:
1218 	/*
1219 	 * OSSv4 docs: "This ioctl call discards all unplayed samples in the
1220 	 * playback buffer by moving the current write position immediately
1221 	 * before the point where the device is currently reading the samples."
1222 	 */
1223 		if (wrch == NULL)
1224 			ret = EINVAL;
1225 		else {
1226 			struct snd_dbuf *bs;
1227 			CHN_LOCK(wrch);
1228 			while (wrch->inprog != 0)
1229 				cv_wait(&wrch->cv, wrch->lock);
1230 			bs = wrch->bufsoft;
1231 			if ((bs->shadbuf != NULL) && (bs->sl > 0)) {
1232 				sndbuf_softreset(bs);
1233 				sndbuf_acquire(bs, bs->shadbuf, bs->sl);
1234 				bs->sl = 0;
1235 				chn_start(wrch, 0);
1236 			}
1237 			CHN_UNLOCK(wrch);
1238 		}
1239 		break;
1240 
1241 	case SNDCTL_DSP_CURRENT_OPTR:
1242 	case SNDCTL_DSP_CURRENT_IPTR:
1243 	/**
1244 	 * @note Changing formats resets the buffer counters, which differs
1245 	 * 	 from the 4Front drivers.  However, I don't expect this to be
1246 	 * 	 much of a problem.
1247 	 *
1248 	 * @note In a test where @c CURRENT_OPTR is called immediately after write
1249 	 * 	 returns, this driver is about 32K samples behind whereas
1250 	 * 	 4Front's is about 8K samples behind.  Should determine source
1251 	 * 	 of discrepancy, even if only out of curiosity.
1252 	 *
1253 	 * @todo Actually test SNDCTL_DSP_CURRENT_IPTR.
1254 	 */
1255 		chn = (cmd == SNDCTL_DSP_CURRENT_OPTR) ? wrch : rdch;
1256 		if (chn == NULL)
1257 			ret = EINVAL;
1258 		else {
1259 			struct snd_dbuf *bs;
1260 			/* int tmp; */
1261 
1262 			oss_count_t *oc = (oss_count_t *)arg;
1263 
1264 			CHN_LOCK(chn);
1265 			bs = chn->bufsoft;
1266 #if 0
1267 			tmp = (sndbuf_getsize(b) + chn_getptr(chn) - sndbuf_gethwptr(b)) % sndbuf_getsize(b);
1268 			oc->samples = (sndbuf_gettotal(b) + tmp) / sndbuf_getbps(b);
1269 			oc->fifo_samples = (sndbuf_getready(b) - tmp) / sndbuf_getbps(b);
1270 #else
1271 			oc->samples = sndbuf_gettotal(bs) / sndbuf_getbps(bs);
1272 			oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getbps(bs);
1273 #endif
1274 			CHN_UNLOCK(chn);
1275 		}
1276 		break;
1277 
1278 	case SNDCTL_DSP_HALT_OUTPUT:
1279 	case SNDCTL_DSP_HALT_INPUT:
1280 		chn = (cmd == SNDCTL_DSP_HALT_OUTPUT) ? wrch : rdch;
1281 		if (chn == NULL)
1282 			ret = EINVAL;
1283 		else {
1284 			CHN_LOCK(chn);
1285 			chn_abort(chn);
1286 			CHN_UNLOCK(chn);
1287 		}
1288 		break;
1289 
1290 	case SNDCTL_DSP_LOW_WATER:
1291 	/*
1292 	 * Set the number of bytes required to attract attention by
1293 	 * select/poll.
1294 	 */
1295 		if (wrch != NULL) {
1296 			CHN_LOCK(wrch);
1297 			wrch->lw = (*arg_i > 1) ? *arg_i : 1;
1298 			CHN_UNLOCK(wrch);
1299 		}
1300 		if (rdch != NULL) {
1301 			CHN_LOCK(rdch);
1302 			rdch->lw = (*arg_i > 1) ? *arg_i : 1;
1303 			CHN_UNLOCK(rdch);
1304 		}
1305 		break;
1306 
1307 	case SNDCTL_DSP_GETERROR:
1308 	/*
1309 	 * OSSv4 docs:  "All errors and counters will automatically be
1310 	 * cleared to zeroes after the call so each call will return only
1311 	 * the errors that occurred after the previous invocation. ... The
1312 	 * play_underruns and rec_overrun fields are the only usefull fields
1313 	 * returned by OSS 4.0."
1314 	 */
1315 		{
1316 			audio_errinfo *ei = (audio_errinfo *)arg;
1317 
1318 			bzero((void *)ei, sizeof(*ei));
1319 
1320 			if (wrch != NULL) {
1321 				CHN_LOCK(wrch);
1322 				ei->play_underruns = wrch->xruns;
1323 				wrch->xruns = 0;
1324 				CHN_UNLOCK(wrch);
1325 			}
1326 			if (rdch != NULL) {
1327 				CHN_LOCK(rdch);
1328 				ei->rec_overruns = rdch->xruns;
1329 				rdch->xruns = 0;
1330 				CHN_UNLOCK(rdch);
1331 			}
1332 		}
1333 		break;
1334 
1335 	case SNDCTL_DSP_SYNCGROUP:
1336 		ret = dsp_oss_syncgroup(wrch, rdch, (oss_syncgroup *)arg);
1337 		break;
1338 
1339 	case SNDCTL_DSP_SYNCSTART:
1340 		ret = dsp_oss_syncstart(*arg_i);
1341 		break;
1342 
1343 	case SNDCTL_DSP_POLICY:
1344 		ret = dsp_oss_policy(wrch, rdch, *arg_i);
1345 		break;
1346 
1347 #ifdef	OSSV4_EXPERIMENT
1348 	/*
1349 	 * XXX The following ioctls are not yet supported and just return
1350 	 * EINVAL.
1351 	 */
1352 	case SNDCTL_DSP_GETOPEAKS:
1353 	case SNDCTL_DSP_GETIPEAKS:
1354 		chn = (cmd == SNDCTL_DSP_GETOPEAKS) ? wrch : rdch;
1355 		if (chn == NULL)
1356 			ret = EINVAL;
1357 		else {
1358 			oss_peaks_t *op = (oss_peaks_t *)arg;
1359 			int lpeak, rpeak;
1360 
1361 			CHN_LOCK(chn);
1362 			ret = chn_getpeaks(chn, &lpeak, &rpeak);
1363 			if (ret == -1)
1364 				ret = EINVAL;
1365 			else {
1366 				(*op)[0] = lpeak;
1367 				(*op)[1] = rpeak;
1368 			}
1369 			CHN_UNLOCK(chn);
1370 		}
1371 		break;
1372 
1373 	case SNDCTL_DSP_COOKEDMODE:
1374 		ret = dsp_oss_cookedmode(wrch, rdch, *arg_i);
1375 		break;
1376 	case SNDCTL_DSP_GET_CHNORDER:
1377 		ret = dsp_oss_getchnorder(wrch, rdch, (unsigned long long *)arg);
1378 		break;
1379 	case SNDCTL_DSP_SET_CHNORDER:
1380 		ret = dsp_oss_setchnorder(wrch, rdch, (unsigned long long *)arg);
1381 		break;
1382 	case SNDCTL_GETLABEL:
1383 		ret = dsp_oss_getlabel(wrch, rdch, (oss_label_t *)arg);
1384 		break;
1385 	case SNDCTL_SETLABEL:
1386 		ret = dsp_oss_setlabel(wrch, rdch, (oss_label_t *)arg);
1387 		break;
1388 	case SNDCTL_GETSONG:
1389 		ret = dsp_oss_getsong(wrch, rdch, (oss_longname_t *)arg);
1390 		break;
1391 	case SNDCTL_SETSONG:
1392 		ret = dsp_oss_setsong(wrch, rdch, (oss_longname_t *)arg);
1393 		break;
1394 	case SNDCTL_SETNAME:
1395 		ret = dsp_oss_setname(wrch, rdch, (oss_longname_t *)arg);
1396 		break;
1397 #if 0
1398 	/**
1399 	 * @note The SNDCTL_CARDINFO ioctl was omitted per 4Front developer
1400 	 * documentation.  "The usability of this call is very limited. It's
1401 	 * provided only for completeness of the API. OSS API doesn't have
1402 	 * any concept of card. Any information returned by this ioctl calld
1403 	 * is reserved exclusively for the utility programs included in the
1404 	 * OSS package. Applications should not try to use for this
1405 	 * information in any ways."
1406 	 */
1407 	case SNDCTL_CARDINFO:
1408 		ret = EINVAL;
1409 		break;
1410 	/**
1411 	 * @note The S/PDIF interface ioctls, @c SNDCTL_DSP_READCTL and
1412 	 * @c SNDCTL_DSP_WRITECTL have been omitted at the suggestion of
1413 	 * 4Front Technologies.
1414 	 */
1415 	case SNDCTL_DSP_READCTL:
1416 	case SNDCTL_DSP_WRITECTL:
1417 		ret = EINVAL;
1418 		break;
1419 #endif	/* !0 (explicitly omitted ioctls) */
1420 
1421 #endif	/* !OSSV4_EXPERIMENT */
1422     	case SNDCTL_DSP_MAPINBUF:
1423     	case SNDCTL_DSP_MAPOUTBUF:
1424     	case SNDCTL_DSP_SETSYNCRO:
1425 		/* undocumented */
1426 
1427     	case SNDCTL_DSP_SUBDIVIDE:
1428     	case SOUND_PCM_WRITE_FILTER:
1429     	case SOUND_PCM_READ_FILTER:
1430 		/* dunno what these do, don't sound important */
1431 
1432     	default:
1433 		DEB(printf("default ioctl fn 0x%08lx fail\n", cmd));
1434 		ret = EINVAL;
1435 		break;
1436     	}
1437 	relchns(i_dev, rdch, wrch, 0);
1438     	return ret;
1439 }
1440 
1441 static int
1442 dsp_poll(struct cdev *i_dev, int events, struct thread *td)
1443 {
1444 	struct pcm_channel *wrch = NULL, *rdch = NULL;
1445 	int ret, e;
1446 
1447 	ret = 0;
1448 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1449 
1450 	if (wrch) {
1451 		e = (events & (POLLOUT | POLLWRNORM));
1452 		if (e)
1453 			ret |= chn_poll(wrch, e, td);
1454 	}
1455 	if (rdch) {
1456 		e = (events & (POLLIN | POLLRDNORM));
1457 		if (e)
1458 			ret |= chn_poll(rdch, e, td);
1459 	}
1460 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1461 
1462 	return ret;
1463 }
1464 
1465 static int
1466 dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
1467 {
1468 	struct pcm_channel *wrch = NULL, *rdch = NULL, *c;
1469 
1470 	if (nprot & PROT_EXEC)
1471 		return -1;
1472 
1473 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1474 #if 0
1475 	/*
1476 	 * XXX the linux api uses the nprot to select read/write buffer
1477 	 * our vm system doesn't allow this, so force write buffer
1478 	 */
1479 
1480 	if (wrch && (nprot & PROT_WRITE)) {
1481 		c = wrch;
1482 	} else if (rdch && (nprot & PROT_READ)) {
1483 		c = rdch;
1484 	} else {
1485 		return -1;
1486 	}
1487 #else
1488 	c = wrch;
1489 #endif
1490 
1491 	if (c == NULL) {
1492 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1493 		return -1;
1494 	}
1495 
1496 	if (offset >= sndbuf_getsize(c->bufsoft)) {
1497 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1498 		return -1;
1499 	}
1500 
1501 	if (!(c->flags & CHN_F_MAPPED))
1502 		c->flags |= CHN_F_MAPPED;
1503 
1504 	*paddr = vtophys(sndbuf_getbufofs(c->bufsoft, offset));
1505 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1506 
1507 	return 0;
1508 }
1509 
1510 #ifdef USING_DEVFS
1511 
1512 /*
1513  * Clone logic is this:
1514  * x E X = {dsp, dspW, audio}
1515  * x -> x${sysctl("hw.snd.unit")}
1516  * xN->
1517  *    for i N = 1 to channels of device N
1518  *    	if xN.i isn't busy, return its dev_t
1519  */
1520 static void
1521 dsp_clone(void *arg, struct ucred *cred, char *name, int namelen,
1522     struct cdev **dev)
1523 {
1524 	struct cdev *pdev;
1525 	struct snddev_info *pcm_dev;
1526 	struct snddev_channel *pcm_chan;
1527 	int i, unit, devtype;
1528 	static int devtypes[3] = {SND_DEV_DSP, SND_DEV_DSP16, SND_DEV_AUDIO};
1529 	static char *devnames[3] = {"dsp", "dspW", "audio"};
1530 
1531 	if (*dev != NULL)
1532 		return;
1533 	if (pcm_devclass == NULL)
1534 		return;
1535 
1536 	devtype = 0;
1537 	unit = -1;
1538 	for (i = 0; (i < 3) && (unit == -1); i++) {
1539 		devtype = devtypes[i];
1540 		if (strcmp(name, devnames[i]) == 0) {
1541 			unit = snd_unit;
1542 		} else {
1543 			if (dev_stdclone(name, NULL, devnames[i], &unit) != 1)
1544 				unit = -1;
1545 		}
1546 	}
1547 	if (unit == -1 || unit >= devclass_get_maxunit(pcm_devclass))
1548 		return;
1549 
1550 	pcm_dev = devclass_get_softc(pcm_devclass, unit);
1551 
1552 	if (pcm_dev == NULL)
1553 		return;
1554 
1555 	SLIST_FOREACH(pcm_chan, &pcm_dev->channels, link) {
1556 
1557 		switch(devtype) {
1558 			case SND_DEV_DSP:
1559 				pdev = pcm_chan->dsp_devt;
1560 				break;
1561 			case SND_DEV_DSP16:
1562 				pdev = pcm_chan->dspW_devt;
1563 				break;
1564 			case SND_DEV_AUDIO:
1565 				pdev = pcm_chan->audio_devt;
1566 				break;
1567 			default:
1568 				panic("Unknown devtype %d", devtype);
1569 		}
1570 
1571 		if ((pdev != NULL) && (pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) {
1572 			*dev = pdev;
1573 			dev_ref(*dev);
1574 			return;
1575 		}
1576 	}
1577 }
1578 
1579 static void
1580 dsp_sysinit(void *p)
1581 {
1582 	dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
1583 }
1584 
1585 static void
1586 dsp_sysuninit(void *p)
1587 {
1588 	if (dsp_ehtag != NULL)
1589 		EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
1590 }
1591 
1592 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
1593 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
1594 #endif
1595 
1596 /**
1597  * @brief Handler for SNDCTL_AUDIOINFO.
1598  *
1599  * Gathers information about the audio device specified in ai->dev.  If
1600  * ai->dev == -1, then this function gathers information about the current
1601  * device.  If the call comes in on a non-audio device and ai->dev == -1,
1602  * return EINVAL.
1603  *
1604  * This routine is supposed to go practically straight to the hardware,
1605  * getting capabilities directly from the sound card driver, side-stepping
1606  * the intermediate channel interface.
1607  *
1608  * Note, however, that the usefulness of this command is significantly
1609  * decreased when requesting info about any device other than the one serving
1610  * the request. While each snddev_channel refers to a specific device node,
1611  * the converse is *not* true.  Currently, when a sound device node is opened,
1612  * the sound subsystem scans for an available audio channel (or channels, if
1613  * opened in read+write) and then assigns them to the si_drv[12] private
1614  * data fields.  As a result, any information returned linking a channel to
1615  * a specific character device isn't necessarily accurate.
1616  *
1617  * @note
1618  * Calling threads must not hold any snddev_info or pcm_channel locks.
1619  *
1620  * @param dev		device on which the ioctl was issued
1621  * @param ai		ioctl request data container
1622  *
1623  * @retval 0		success
1624  * @retval EINVAL	ai->dev specifies an invalid device
1625  *
1626  * @todo Verify correctness of Doxygen tags.  ;)
1627  */
1628 int
1629 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai)
1630 {
1631 	struct snddev_channel *sce;
1632 	struct pcmchan_caps *caps;
1633 	struct pcm_channel *ch;
1634 	struct snddev_info *d;
1635 	struct cdev *t_cdev;
1636 	uint32_t fmts;
1637 	int i, nchan, ret, *rates, minch, maxch;
1638 
1639 	/*
1640 	 * If probing the device that received the ioctl, make sure it's a
1641 	 * DSP device.  (Users may use this ioctl with /dev/mixer and
1642 	 * /dev/midi.)
1643 	 */
1644 	if ((ai->dev == -1) && (i_dev->si_devsw != &dsp_cdevsw))
1645 		return EINVAL;
1646 
1647 	ch = NULL;
1648 	t_cdev = NULL;
1649 	nchan = 0;
1650 	ret = 0;
1651 
1652 	/*
1653 	 * Search for the requested audio device (channel).  Start by
1654 	 * iterating over pcm devices.
1655 	 */
1656 	for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) {
1657 		d = devclass_get_softc(pcm_devclass, i);
1658 		if (d == NULL)
1659 			continue;
1660 
1661 		/* See the note in function docblock */
1662 		mtx_assert(d->lock, MA_NOTOWNED);
1663 		pcm_inprog(d, 1);
1664 		pcm_lock(d);
1665 
1666 		SLIST_FOREACH(sce, &d->channels, link) {
1667 			ch = sce->channel;
1668 			mtx_assert(ch->lock, MA_NOTOWNED);
1669 			CHN_LOCK(ch);
1670 			if (ai->dev == -1) {
1671 				if ((ch == i_dev->si_drv1) ||	/* record ch */
1672 				    (ch == i_dev->si_drv2)) {	/* playback ch */
1673 					t_cdev = i_dev;
1674 					goto dspfound;
1675 				}
1676 			} else if (ai->dev == nchan) {
1677 				t_cdev = sce->dsp_devt;
1678 				goto dspfound;
1679 			}
1680 			CHN_UNLOCK(ch);
1681 			++nchan;
1682 		}
1683 
1684 		pcm_unlock(d);
1685 		pcm_inprog(d, -1);
1686 	}
1687 
1688 	/* Exhausted the search -- nothing is locked, so return. */
1689 	return EINVAL;
1690 
1691 dspfound:
1692 	/* Should've found the device, but something isn't right */
1693 	if (t_cdev == NULL) {
1694 		ret = EINVAL;
1695 		goto out;
1696 	}
1697 
1698 	/*
1699 	 * At this point, the following synchronization stuff has happened:
1700 	 *   - a specific PCM device is locked and its "in progress
1701 	 *     operations" counter has been incremented, so be sure to unlock
1702 	 *     and decrement when exiting;
1703 	 *   - a specific audio channel has been locked, so be sure to unlock
1704 	 *     when exiting;
1705 	 */
1706 
1707 	caps = chn_getcaps(ch);
1708 
1709 	/*
1710 	 * With all handles collected, zero out the user's container and
1711 	 * begin filling in its fields.
1712 	 */
1713 	bzero((void *)ai, sizeof(oss_audioinfo));
1714 
1715 	ai->dev = nchan;
1716 	strlcpy(ai->name, ch->name,  sizeof(ai->name));
1717 
1718 	if ((ch->flags & CHN_F_BUSY) == 0)
1719 		ai->busy = 0;
1720 	else
1721 		ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ;
1722 
1723 	/**
1724 	 * @note
1725 	 * @c cmd - OSSv4 docs: "Only supported under Linux at this moment."
1726 	 * 	Cop-out, I know, but I'll save running around in the process
1727 	 * 	table for later.  Is there a risk of leaking information?
1728 	 */
1729 	ai->pid = ch->pid;
1730 
1731 	/*
1732 	 * These flags stolen from SNDCTL_DSP_GETCAPS handler.  Note, however,
1733 	 * that a single channel operates in only one direction, so
1734 	 * DSP_CAP_DUPLEX is out.
1735 	 */
1736 	/**
1737 	 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep these in
1738 	 * 	 pcmchan::caps?
1739 	 */
1740 	ai->caps = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER;
1741 
1742 	/*
1743 	 * Collect formats supported @b natively by the device.  Also
1744 	 * determine min/max channels.  (I.e., mono, stereo, or both?)
1745 	 *
1746 	 * If any channel is stereo, maxch = 2;
1747 	 * if all channels are stereo, minch = 2, too;
1748 	 * if any channel is mono, minch = 1;
1749 	 * and if all channels are mono, maxch = 1.
1750 	 */
1751 	minch = 0;
1752 	maxch = 0;
1753 	fmts = 0;
1754 	for (i = 0; caps->fmtlist[i]; i++) {
1755 		fmts |= caps->fmtlist[i];
1756 		if (caps->fmtlist[i] & AFMT_STEREO) {
1757 			minch = (minch == 0) ? 2 : minch;
1758 			maxch = 2;
1759 		} else {
1760 			minch = 1;
1761 			maxch = (maxch == 0) ? 1 : maxch;
1762 		}
1763 	}
1764 
1765 	if (ch->direction == PCMDIR_PLAY)
1766 		ai->oformats = fmts;
1767 	else
1768 		ai->iformats = fmts;
1769 
1770 	/**
1771 	 * @note
1772 	 * @c magic - OSSv4 docs: "Reserved for internal use by OSS."
1773 	 *
1774 	 * @par
1775 	 * @c card_number - OSSv4 docs: "Number of the sound card where this
1776 	 * 	device belongs or -1 if this information is not available.
1777 	 * 	Applications should normally not use this field for any
1778 	 * 	purpose."
1779 	 */
1780 	ai->card_number = -1;
1781 	/**
1782 	 * @todo @c song_name - depends first on SNDCTL_[GS]ETSONG
1783 	 * @todo @c label - depends on SNDCTL_[GS]ETLABEL
1784 	 * @todo @c port_number - routing information?
1785 	 */
1786 	ai->port_number = -1;
1787 	ai->mixer_dev = (d->mixer_dev != NULL) ? PCMUNIT(d->mixer_dev) : -1;
1788 	/**
1789 	 * @note
1790 	 * @c real_device - OSSv4 docs:  "Obsolete."
1791 	 */
1792 	ai->real_device = -1;
1793 	strlcpy(ai->devnode, t_cdev->si_name, sizeof(ai->devnode));
1794 	ai->enabled = device_is_attached(d->dev) ? 1 : 0;
1795 	/**
1796 	 * @note
1797 	 * @c flags - OSSv4 docs: "Reserved for future use."
1798 	 *
1799 	 * @note
1800 	 * @c binding - OSSv4 docs: "Reserved for future use."
1801 	 *
1802 	 * @todo @c handle - haven't decided how to generate this yet; bus,
1803 	 * 	vendor, device IDs?
1804 	 */
1805 	ai->min_rate = caps->minspeed;
1806 	ai->max_rate = caps->maxspeed;
1807 
1808 	ai->min_channels = minch;
1809 	ai->max_channels = maxch;
1810 
1811 	ai->nrates = chn_getrates(ch, &rates);
1812 	if (ai->nrates > OSS_MAX_SAMPLE_RATES)
1813 		ai->nrates = OSS_MAX_SAMPLE_RATES;
1814 
1815 	for (i = 0; i < ai->nrates; i++)
1816 		ai->rates[i] = rates[i];
1817 
1818 out:
1819 	CHN_UNLOCK(ch);
1820 	pcm_unlock(d);
1821 	pcm_inprog(d, -1);
1822 
1823 	return ret;
1824 }
1825 
1826 /**
1827  * @brief Assigns a PCM channel to a sync group.
1828  *
1829  * Sync groups are used to enable audio operations on multiple devices
1830  * simultaneously.  They may be used with any number of devices and may
1831  * span across applications.  Devices are added to groups with
1832  * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the
1833  * SNDCTL_DSP_SYNCSTART ioctl.
1834  *
1835  * If the @c id field of the @c group parameter is set to zero, then a new
1836  * sync group is created.  Otherwise, wrch and rdch (if set) are added to
1837  * the group specified.
1838  *
1839  * @todo As far as memory allocation, should we assume that things are
1840  * 	 okay and allocate with M_WAITOK before acquiring channel locks,
1841  * 	 freeing later if not?
1842  *
1843  * @param wrch	output channel associated w/ device (if any)
1844  * @param rdch	input channel associated w/ device (if any)
1845  * @param group Sync group parameters
1846  *
1847  * @retval 0		success
1848  * @retval non-zero	error to be propagated upstream
1849  */
1850 static int
1851 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group)
1852 {
1853 	struct pcmchan_syncmember *smrd, *smwr;
1854 	struct pcmchan_syncgroup *sg;
1855 	int ret, sg_ids[3];
1856 
1857 	smrd = NULL;
1858 	smwr = NULL;
1859 	sg = NULL;
1860 	ret = 0;
1861 
1862 	/*
1863 	 * Free_unr() may sleep, so store released syncgroup IDs until after
1864 	 * all locks are released.
1865 	 */
1866 	sg_ids[0] = sg_ids[1] = sg_ids[2] = 0;
1867 
1868 	PCM_SG_LOCK();
1869 
1870 	/*
1871 	 * - Insert channel(s) into group's member list.
1872 	 * - Set CHN_F_NOTRIGGER on channel(s).
1873 	 * - Stop channel(s).
1874 	 */
1875 
1876 	/*
1877 	 * If device's channels are already mapped to a group, unmap them.
1878 	 */
1879 	if (wrch) {
1880 		CHN_LOCK(wrch);
1881 		sg_ids[0] = chn_syncdestroy(wrch);
1882 	}
1883 
1884 	if (rdch) {
1885 		CHN_LOCK(rdch);
1886 		sg_ids[1] = chn_syncdestroy(rdch);
1887 	}
1888 
1889 	/*
1890 	 * Verify that mode matches character device properites.
1891 	 *  - Bail if PCM_ENABLE_OUTPUT && wrch == NULL.
1892 	 *  - Bail if PCM_ENABLE_INPUT && rdch == NULL.
1893 	 */
1894 	if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) ||
1895 	    ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) {
1896 		ret = EINVAL;
1897 		goto out;
1898 	}
1899 
1900 	/*
1901 	 * An id of zero indicates the user wants to create a new
1902 	 * syncgroup.
1903 	 */
1904 	if (group->id == 0) {
1905 		sg = (struct pcmchan_syncgroup *)malloc(sizeof(*sg), M_DEVBUF, M_NOWAIT);
1906 		if (sg != NULL) {
1907 			SLIST_INIT(&sg->members);
1908 			sg->id = alloc_unr(pcmsg_unrhdr);
1909 
1910 			group->id = sg->id;
1911 			SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link);
1912 		} else
1913 			ret = ENOMEM;
1914 	} else {
1915 		SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
1916 			if (sg->id == group->id)
1917 				break;
1918 		}
1919 		if (sg == NULL)
1920 			ret = EINVAL;
1921 	}
1922 
1923 	/* Couldn't create or find a syncgroup.  Fail. */
1924 	if (sg == NULL)
1925 		goto out;
1926 
1927 	/*
1928 	 * Allocate a syncmember, assign it and a channel together, and
1929 	 * insert into syncgroup.
1930 	 */
1931 	if (group->mode & PCM_ENABLE_INPUT) {
1932 		smrd = (struct pcmchan_syncmember *)malloc(sizeof(*smrd), M_DEVBUF, M_NOWAIT);
1933 		if (smrd == NULL) {
1934 			ret = ENOMEM;
1935 			goto out;
1936 		}
1937 
1938 		SLIST_INSERT_HEAD(&sg->members, smrd, link);
1939 		smrd->parent = sg;
1940 		smrd->ch = rdch;
1941 
1942 		chn_abort(rdch);
1943 		rdch->flags |= CHN_F_NOTRIGGER;
1944 		rdch->sm = smrd;
1945 	}
1946 
1947 	if (group->mode & PCM_ENABLE_OUTPUT) {
1948 		smwr = (struct pcmchan_syncmember *)malloc(sizeof(*smwr), M_DEVBUF, M_NOWAIT);
1949 		if (smwr == NULL) {
1950 			ret = ENOMEM;
1951 			goto out;
1952 		}
1953 
1954 		SLIST_INSERT_HEAD(&sg->members, smwr, link);
1955 		smwr->parent = sg;
1956 		smwr->ch = wrch;
1957 
1958 		chn_abort(wrch);
1959 		wrch->flags |= CHN_F_NOTRIGGER;
1960 		wrch->sm = smwr;
1961 	}
1962 
1963 
1964 out:
1965 	if (ret != 0) {
1966 		if (smrd != NULL)
1967 			free(smrd, M_DEVBUF);
1968 		if ((sg != NULL) && SLIST_EMPTY(&sg->members)) {
1969 			sg_ids[2] = sg->id;
1970 			SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
1971 			free(sg, M_DEVBUF);
1972 		}
1973 
1974 		if (wrch)
1975 			wrch->sm = NULL;
1976 		if (rdch)
1977 			rdch->sm = NULL;
1978 	}
1979 
1980 	if (wrch)
1981 		CHN_UNLOCK(wrch);
1982 	if (rdch)
1983 		CHN_UNLOCK(rdch);
1984 
1985 	PCM_SG_UNLOCK();
1986 
1987 	if (sg_ids[0])
1988 		free_unr(pcmsg_unrhdr, sg_ids[0]);
1989 	if (sg_ids[1])
1990 		free_unr(pcmsg_unrhdr, sg_ids[1]);
1991 	if (sg_ids[2])
1992 		free_unr(pcmsg_unrhdr, sg_ids[2]);
1993 
1994 	return ret;
1995 }
1996 
1997 /**
1998  * @brief Launch a sync group into action
1999  *
2000  * Sync groups are established via SNDCTL_DSP_SYNCGROUP.  This function
2001  * iterates over all members, triggering them along the way.
2002  *
2003  * @note Caller must not hold any channel locks.
2004  *
2005  * @param sg_id	sync group identifier
2006  *
2007  * @retval 0	success
2008  * @retval non-zero	error worthy of propagating upstream to user
2009  */
2010 static int
2011 dsp_oss_syncstart(int sg_id)
2012 {
2013 	struct pcmchan_syncmember *sm, *sm_tmp;
2014 	struct pcmchan_syncgroup *sg;
2015 	struct pcm_channel *c;
2016 	int ret, needlocks;
2017 
2018 	/* Get the synclists lock */
2019 	PCM_SG_LOCK();
2020 
2021 	do {
2022 		ret = 0;
2023 		needlocks = 0;
2024 
2025 		/* Search for syncgroup by ID */
2026 		SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2027 			if (sg->id == sg_id)
2028 				break;
2029 		}
2030 
2031 		/* Return EINVAL if not found */
2032 		if (sg == NULL) {
2033 			ret = EINVAL;
2034 			break;
2035 		}
2036 
2037 		/* Any removals resulting in an empty group should've handled this */
2038 		KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup"));
2039 
2040 		/*
2041 		 * Attempt to lock all member channels - if any are already
2042 		 * locked, unlock those acquired, sleep for a bit, and try
2043 		 * again.
2044 		 */
2045 		SLIST_FOREACH(sm, &sg->members, link) {
2046 			if (CHN_TRYLOCK(sm->ch) == 0) {
2047 				int timo = hz * 5/1000;
2048 				if (timo < 1)
2049 					timo = 1;
2050 
2051 				/* Release all locked channels so far, retry */
2052 				SLIST_FOREACH(sm_tmp, &sg->members, link) {
2053 					/* sm is the member already locked */
2054 					if (sm == sm_tmp)
2055 						break;
2056 					CHN_UNLOCK(sm_tmp->ch);
2057 				}
2058 
2059 				/** @todo Is PRIBIO correct/ */
2060 				ret = msleep(sm, &snd_pcm_syncgroups_mtx, PRIBIO | PCATCH, "pcmsgrp", timo);
2061 				if (ret == EINTR || ret == ERESTART)
2062 					break;
2063 
2064 				needlocks = 1;
2065 				ret = 0; /* Assumes ret == EWOULDBLOCK... */
2066 			}
2067 		}
2068 	} while (needlocks && ret == 0);
2069 
2070 	/* Proceed only if no errors encountered. */
2071 	if (ret == 0) {
2072 		/* Launch channels */
2073 		while((sm = SLIST_FIRST(&sg->members)) != NULL) {
2074 			SLIST_REMOVE_HEAD(&sg->members, link);
2075 
2076 			c = sm->ch;
2077 			c->sm = NULL;
2078 			chn_start(c, 1);
2079 			c->flags &= ~CHN_F_NOTRIGGER;
2080 			CHN_UNLOCK(c);
2081 
2082 			free(sm, M_DEVBUF);
2083 		}
2084 
2085 		SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2086 		free(sg, M_DEVBUF);
2087 	}
2088 
2089 	PCM_SG_UNLOCK();
2090 
2091 	/*
2092 	 * Free_unr() may sleep, so be sure to give up the syncgroup lock
2093 	 * first.
2094 	 */
2095 	if (ret == 0)
2096 		free_unr(pcmsg_unrhdr, sg_id);
2097 
2098 	return ret;
2099 }
2100 
2101 /**
2102  * @brief Handler for SNDCTL_DSP_POLICY
2103  *
2104  * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment
2105  * size and count like with SNDCTL_DSP_SETFRAGMENT.  Instead of the user
2106  * specifying those two parameters, s/he simply selects a number from 0..10
2107  * which corresponds to a buffer size.  Smaller numbers request smaller
2108  * buffers with lower latencies (at greater overhead from more frequent
2109  * interrupts), while greater numbers behave in the opposite manner.
2110  *
2111  * The 4Front spec states that a value of 5 should be the default.  However,
2112  * this implementation deviates slightly by using a linear scale without
2113  * consulting drivers.  I.e., even though drivers may have different default
2114  * buffer sizes, a policy argument of 5 will have the same result across
2115  * all drivers.
2116  *
2117  * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for
2118  * more information.
2119  *
2120  * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to
2121  * 	 work with hardware drivers directly.
2122  *
2123  * @note PCM channel arguments must not be locked by caller.
2124  *
2125  * @param wrch	Pointer to opened playback channel (optional; may be NULL)
2126  * @param rdch	" recording channel (optional; may be NULL)
2127  * @param policy Integer from [0:10]
2128  *
2129  * @retval 0	constant (for now)
2130  */
2131 static int
2132 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy)
2133 {
2134 	int fragln, fragsz, maxfrags, ret;
2135 
2136 	/* Default: success */
2137 	ret = 0;
2138 
2139 	/* Scale policy [0..10] to fragment size [2^4..2^16]. */
2140 	fragln = policy;
2141 	RANGE(fragln, 0, 10);
2142 	fragln += 4;
2143 	fragsz = 1 << fragln;
2144 
2145 	maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
2146 
2147 	if (rdch) {
2148 		CHN_LOCK(rdch);
2149 		ret = chn_setblocksize(rdch, maxfrags, fragsz);
2150 		CHN_UNLOCK(rdch);
2151 	}
2152 
2153 	if (wrch && ret == 0) {
2154 		CHN_LOCK(wrch);
2155 		ret = chn_setblocksize(wrch, maxfrags, fragsz);
2156 		CHN_UNLOCK(wrch);
2157 	}
2158 
2159 	return ret;
2160 }
2161 
2162 #ifdef OSSV4_EXPERIMENT
2163 /**
2164  * @brief Enable or disable "cooked" mode
2165  *
2166  * This is a handler for @c SNDCTL_DSP_COOKEDMODE.  When in cooked mode, which
2167  * is the default, the sound system handles rate and format conversions
2168  * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only
2169  * operates with 44100Hz/16bit/signed samples).
2170  *
2171  * Disabling cooked mode is intended for applications wanting to mmap()
2172  * a sound card's buffer space directly, bypassing the FreeBSD 2-stage
2173  * feeder architecture, presumably to gain as much control over audio
2174  * hardware as possible.
2175  *
2176  * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html
2177  * for more details.
2178  *
2179  * @note Currently, this function is just a stub that always returns EINVAL.
2180  *
2181  * @todo Figure out how to and actually implement this.
2182  *
2183  * @param wrch		playback channel (optional; may be NULL)
2184  * @param rdch		recording channel (optional; may be NULL)
2185  * @param enabled	0 = raw mode, 1 = cooked mode
2186  *
2187  * @retval EINVAL	Operation not yet supported.
2188  */
2189 static int
2190 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled)
2191 {
2192 	return EINVAL;
2193 }
2194 
2195 /**
2196  * @brief Retrieve channel interleaving order
2197  *
2198  * This is the handler for @c SNDCTL_DSP_GET_CHNORDER.
2199  *
2200  * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html
2201  * for more details.
2202  *
2203  * @note As the ioctl definition is still under construction, FreeBSD
2204  * 	 does not currently support SNDCTL_DSP_GET_CHNORDER.
2205  *
2206  * @param wrch	playback channel (optional; may be NULL)
2207  * @param rdch	recording channel (optional; may be NULL)
2208  * @param map	channel map (result will be stored there)
2209  *
2210  * @retval EINVAL	Operation not yet supported.
2211  */
2212 static int
2213 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2214 {
2215 	return EINVAL;
2216 }
2217 
2218 /**
2219  * @brief Specify channel interleaving order
2220  *
2221  * This is the handler for @c SNDCTL_DSP_SET_CHNORDER.
2222  *
2223  * @note As the ioctl definition is still under construction, FreeBSD
2224  * 	 does not currently support @c SNDCTL_DSP_SET_CHNORDER.
2225  *
2226  * @param wrch	playback channel (optional; may be NULL)
2227  * @param rdch	recording channel (optional; may be NULL)
2228  * @param map	channel map
2229  *
2230  * @retval EINVAL	Operation not yet supported.
2231  */
2232 static int
2233 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2234 {
2235 	return EINVAL;
2236 }
2237 
2238 /**
2239  * @brief Retrieve an audio device's label
2240  *
2241  * This is a handler for the @c SNDCTL_GETLABEL ioctl.
2242  *
2243  * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2244  * for more details.
2245  *
2246  * From Hannu@4Front:  "For example ossxmix (just like some HW mixer
2247  * consoles) can show variable "labels" for certain controls. By default
2248  * the application name (say quake) is shown as the label but
2249  * applications may change the labels themselves."
2250  *
2251  * @note As the ioctl definition is still under construction, FreeBSD
2252  * 	 does not currently support @c SNDCTL_GETLABEL.
2253  *
2254  * @param wrch	playback channel (optional; may be NULL)
2255  * @param rdch	recording channel (optional; may be NULL)
2256  * @param label	label gets copied here
2257  *
2258  * @retval EINVAL	Operation not yet supported.
2259  */
2260 static int
2261 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2262 {
2263 	return EINVAL;
2264 }
2265 
2266 /**
2267  * @brief Specify an audio device's label
2268  *
2269  * This is a handler for the @c SNDCTL_SETLABEL ioctl.  Please see the
2270  * comments for @c dsp_oss_getlabel immediately above.
2271  *
2272  * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2273  * for more details.
2274  *
2275  * @note As the ioctl definition is still under construction, FreeBSD
2276  * 	 does not currently support SNDCTL_SETLABEL.
2277  *
2278  * @param wrch	playback channel (optional; may be NULL)
2279  * @param rdch	recording channel (optional; may be NULL)
2280  * @param label	label gets copied from here
2281  *
2282  * @retval EINVAL	Operation not yet supported.
2283  */
2284 static int
2285 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2286 {
2287 	return EINVAL;
2288 }
2289 
2290 /**
2291  * @brief Retrieve name of currently played song
2292  *
2293  * This is a handler for the @c SNDCTL_GETSONG ioctl.  Audio players could
2294  * tell the system the name of the currently playing song, which would be
2295  * visible in @c /dev/sndstat.
2296  *
2297  * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html
2298  * for more details.
2299  *
2300  * @note As the ioctl definition is still under construction, FreeBSD
2301  * 	 does not currently support SNDCTL_GETSONG.
2302  *
2303  * @param wrch	playback channel (optional; may be NULL)
2304  * @param rdch	recording channel (optional; may be NULL)
2305  * @param song	song name gets copied here
2306  *
2307  * @retval EINVAL	Operation not yet supported.
2308  */
2309 static int
2310 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2311 {
2312 	return EINVAL;
2313 }
2314 
2315 /**
2316  * @brief Retrieve name of currently played song
2317  *
2318  * This is a handler for the @c SNDCTL_SETSONG ioctl.  Audio players could
2319  * tell the system the name of the currently playing song, which would be
2320  * visible in @c /dev/sndstat.
2321  *
2322  * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html
2323  * for more details.
2324  *
2325  * @note As the ioctl definition is still under construction, FreeBSD
2326  * 	 does not currently support SNDCTL_SETSONG.
2327  *
2328  * @param wrch	playback channel (optional; may be NULL)
2329  * @param rdch	recording channel (optional; may be NULL)
2330  * @param song	song name gets copied from here
2331  *
2332  * @retval EINVAL	Operation not yet supported.
2333  */
2334 static int
2335 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2336 {
2337 	return EINVAL;
2338 }
2339 
2340 /**
2341  * @brief Rename a device
2342  *
2343  * This is a handler for the @c SNDCTL_SETNAME ioctl.
2344  *
2345  * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for
2346  * more details.
2347  *
2348  * From Hannu@4Front:  "This call is used to change the device name
2349  * reported in /dev/sndstat and ossinfo. So instead of  using some generic
2350  * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull
2351  * name depending on the current context (for example 'OSS virtual wave table
2352  * synth' or 'VoIP link to London')."
2353  *
2354  * @note As the ioctl definition is still under construction, FreeBSD
2355  * 	 does not currently support SNDCTL_SETNAME.
2356  *
2357  * @param wrch	playback channel (optional; may be NULL)
2358  * @param rdch	recording channel (optional; may be NULL)
2359  * @param name	new device name gets copied from here
2360  *
2361  * @retval EINVAL	Operation not yet supported.
2362  */
2363 static int
2364 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name)
2365 {
2366 	return EINVAL;
2367 }
2368 #endif	/* !OSSV4_EXPERIMENT */
2369