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