xref: /freebsd/sys/dev/sound/pcm/dsp.c (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
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 	.d_maj =	SND_CDEV_MAJOR,
56 };
57 
58 #ifdef USING_DEVFS
59 static eventhandler_tag dsp_ehtag;
60 #endif
61 
62 static struct snddev_info *
63 dsp_get_info(struct cdev *dev)
64 {
65 	struct snddev_info *d;
66 	int unit;
67 
68 	unit = PCMUNIT(dev);
69 	if (unit >= devclass_get_maxunit(pcm_devclass))
70 		return NULL;
71 	d = devclass_get_softc(pcm_devclass, unit);
72 
73 	return d;
74 }
75 
76 static u_int32_t
77 dsp_get_flags(struct cdev *dev)
78 {
79 	device_t bdev;
80 	int unit;
81 
82 	unit = PCMUNIT(dev);
83 	if (unit >= devclass_get_maxunit(pcm_devclass))
84 		return 0xffffffff;
85 	bdev = devclass_get_device(pcm_devclass, unit);
86 
87 	return pcm_getflags(bdev);
88 }
89 
90 static void
91 dsp_set_flags(struct cdev *dev, u_int32_t flags)
92 {
93 	device_t bdev;
94 	int unit;
95 
96 	unit = PCMUNIT(dev);
97 	if (unit >= devclass_get_maxunit(pcm_devclass))
98 		return;
99 	bdev = devclass_get_device(pcm_devclass, unit);
100 
101 	pcm_setflags(bdev, flags);
102 }
103 
104 /*
105  * return the channels channels associated with an open device instance.
106  * set the priority if the device is simplex and one direction (only) is
107  * specified.
108  * lock channels specified.
109  */
110 static int
111 getchns(struct cdev *dev, struct pcm_channel **rdch, struct pcm_channel **wrch, u_int32_t prio)
112 {
113 	struct snddev_info *d;
114 	u_int32_t flags;
115 
116 	flags = dsp_get_flags(dev);
117 	d = dsp_get_info(dev);
118 	pcm_inprog(d, 1);
119 	pcm_lock(d);
120 	KASSERT((flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \
121 		("getchns: read and write both prioritised"));
122 
123 	if ((flags & SD_F_PRIO_SET) == 0 && (prio != (SD_F_PRIO_RD | SD_F_PRIO_WR))) {
124 		flags |= prio & (SD_F_PRIO_RD | SD_F_PRIO_WR);
125 		dsp_set_flags(dev, flags);
126 	}
127 
128 	*rdch = dev->si_drv1;
129 	*wrch = dev->si_drv2;
130 	if ((flags & SD_F_SIMPLEX) && (flags & SD_F_PRIO_SET)) {
131 		if (prio) {
132 			if (*rdch && flags & SD_F_PRIO_WR) {
133 				dev->si_drv1 = NULL;
134 				*rdch = pcm_getfakechan(d);
135 			} else if (*wrch && flags & SD_F_PRIO_RD) {
136 				dev->si_drv2 = NULL;
137 				*wrch = pcm_getfakechan(d);
138 			}
139 		}
140 
141 		pcm_getfakechan(d)->flags |= CHN_F_BUSY;
142 	}
143 	pcm_unlock(d);
144 
145 	if (*rdch && *rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD))
146 		CHN_LOCK(*rdch);
147 	if (*wrch && *wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR))
148 		CHN_LOCK(*wrch);
149 
150 	return 0;
151 }
152 
153 /* unlock specified channels */
154 static void
155 relchns(struct cdev *dev, struct pcm_channel *rdch, struct pcm_channel *wrch, u_int32_t prio)
156 {
157 	struct snddev_info *d;
158 
159 	d = dsp_get_info(dev);
160 	if (wrch && wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR))
161 		CHN_UNLOCK(wrch);
162 	if (rdch && rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD))
163 		CHN_UNLOCK(rdch);
164 	pcm_inprog(d, -1);
165 }
166 
167 static int
168 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
169 {
170 	struct pcm_channel *rdch, *wrch;
171 	struct snddev_info *d;
172 	intrmask_t s;
173 	u_int32_t fmt;
174 	int devtype;
175 	int rdref;
176 	int error;
177 
178 	s = spltty();
179 	d = dsp_get_info(i_dev);
180 	devtype = PCMDEV(i_dev);
181 
182 	/* decide default format */
183 	switch (devtype) {
184 	case SND_DEV_DSP16:
185 		fmt = AFMT_S16_LE;
186 		break;
187 
188 	case SND_DEV_DSP:
189 		fmt = AFMT_U8;
190 		break;
191 
192 	case SND_DEV_AUDIO:
193 		fmt = AFMT_MU_LAW;
194 		break;
195 
196 	case SND_DEV_NORESET:
197 		fmt = 0;
198 		break;
199 
200 	case SND_DEV_DSPREC:
201 		fmt = AFMT_U8;
202 		if (mode & FWRITE) {
203 			splx(s);
204 			return EINVAL;
205 		}
206 		break;
207 
208 	default:
209 		panic("impossible devtype %d", devtype);
210 	}
211 
212 	rdref = 0;
213 
214 	/* lock snddev so nobody else can monkey with it */
215 	pcm_lock(d);
216 
217 	rdch = i_dev->si_drv1;
218 	wrch = i_dev->si_drv2;
219 
220 	if ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) && (rdch || wrch)) {
221 		/* we're a simplex device and already open, no go */
222 		pcm_unlock(d);
223 		splx(s);
224 		return EBUSY;
225 	}
226 
227 	if (((flags & FREAD) && rdch) || ((flags & FWRITE) && wrch)) {
228 		/*
229 		 * device already open in one or both directions that
230 		 * the opener wants; we can't handle this.
231 		 */
232 		pcm_unlock(d);
233 		splx(s);
234 		return EBUSY;
235 	}
236 
237 	/*
238 	 * if we get here, the open request is valid- either:
239 	 *   * we were previously not open
240 	 *   * we were open for play xor record and the opener wants
241 	 *     the non-open direction
242 	 */
243 	if (flags & FREAD) {
244 		/* open for read */
245 		if (devtype == SND_DEV_DSPREC)
246 			rdch = pcm_chnalloc(d, PCMDIR_REC, td->td_proc->p_pid, PCMCHAN(i_dev));
247 		else
248 			rdch = pcm_chnalloc(d, PCMDIR_REC, td->td_proc->p_pid, -1);
249 		if (!rdch) {
250 			/* no channel available, exit */
251 			pcm_unlock(d);
252 			splx(s);
253 			return EBUSY;
254 		}
255 		/* got a channel, already locked for us */
256 		if (chn_reset(rdch, fmt)) {
257 			pcm_chnrelease(rdch);
258 			i_dev->si_drv1 = NULL;
259 			pcm_unlock(d);
260 			splx(s);
261 			return ENODEV;
262 		}
263 
264 		if (flags & O_NONBLOCK)
265 			rdch->flags |= CHN_F_NBIO;
266 		pcm_chnref(rdch, 1);
267 	 	CHN_UNLOCK(rdch);
268 		rdref = 1;
269 		/*
270 		 * Record channel created, ref'ed and unlocked
271 		 */
272 	}
273 
274 	if (flags & FWRITE) {
275 	    /* open for write */
276 	    wrch = pcm_chnalloc(d, PCMDIR_PLAY, td->td_proc->p_pid, -1);
277 	    error = 0;
278 
279 	    if (!wrch)
280 		error = EBUSY; /* XXX Right return code? */
281 	    else if (chn_reset(wrch, fmt))
282 		error = ENODEV;
283 
284 	    if (error != 0) {
285 		if (wrch) {
286 		    /*
287 		     * Free play channel
288 		     */
289 		    pcm_chnrelease(wrch);
290 		    i_dev->si_drv2 = NULL;
291 		}
292 		if (rdref) {
293 		    /*
294 		     * Lock, deref and release previously created record channel
295 		     */
296 		    CHN_LOCK(rdch);
297 		    pcm_chnref(rdch, -1);
298 		    pcm_chnrelease(rdch);
299 		    i_dev->si_drv1 = NULL;
300 		}
301 
302 		pcm_unlock(d);
303 		splx(s);
304 		return error;
305 	    }
306 
307 	    if (flags & O_NONBLOCK)
308 		wrch->flags |= CHN_F_NBIO;
309 	    pcm_chnref(wrch, 1);
310 	    CHN_UNLOCK(wrch);
311 	}
312 
313 	i_dev->si_drv1 = rdch;
314 	i_dev->si_drv2 = wrch;
315 
316 	pcm_unlock(d);
317 	splx(s);
318 	return 0;
319 }
320 
321 static int
322 dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
323 {
324 	struct pcm_channel *rdch, *wrch;
325 	struct snddev_info *d;
326 	intrmask_t s;
327 	int refs;
328 
329 	s = spltty();
330 	d = dsp_get_info(i_dev);
331 	pcm_lock(d);
332 	rdch = i_dev->si_drv1;
333 	wrch = i_dev->si_drv2;
334 
335 	refs = 0;
336 
337 	if (rdch) {
338 		CHN_LOCK(rdch);
339 		refs += pcm_chnref(rdch, -1);
340 		CHN_UNLOCK(rdch);
341 	}
342 	if (wrch) {
343 		CHN_LOCK(wrch);
344 		refs += pcm_chnref(wrch, -1);
345 		CHN_UNLOCK(wrch);
346 	}
347 
348 	/*
349 	 * If there are no more references, release the channels.
350 	 */
351 	if ((rdch || wrch) && refs == 0) {
352 
353 		if (pcm_getfakechan(d))
354 			pcm_getfakechan(d)->flags = 0;
355 
356 		i_dev->si_drv1 = NULL;
357 		i_dev->si_drv2 = NULL;
358 
359 		dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT);
360 
361 		pcm_unlock(d);
362 
363 		if (rdch) {
364 			CHN_LOCK(rdch);
365 			chn_abort(rdch); /* won't sleep */
366 			rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
367 			chn_reset(rdch, 0);
368 			pcm_chnrelease(rdch);
369 		}
370 		if (wrch) {
371 			CHN_LOCK(wrch);
372 			/*
373 			 * XXX: Maybe the right behaviour is to abort on non_block.
374 			 * It seems that mplayer flushes the audio queue by quickly
375 			 * closing and re-opening.  In FBSD, there's a long pause
376 			 * while the audio queue flushes that I presume isn't there in
377 			 * linux.
378 			 */
379 			chn_flush(wrch); /* may sleep */
380 			wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
381 			chn_reset(wrch, 0);
382 			pcm_chnrelease(wrch);
383 		}
384 	} else
385 		pcm_unlock(d);
386 	splx(s);
387 	return 0;
388 }
389 
390 static int
391 dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
392 {
393 	struct pcm_channel *rdch, *wrch;
394 	intrmask_t s;
395 	int ret;
396 
397 	s = spltty();
398 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD);
399 
400 	KASSERT(rdch, ("dsp_read: nonexistant channel"));
401 	KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel"));
402 
403 	if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
404 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
405 		splx(s);
406 		return EINVAL;
407 	}
408 	if (!(rdch->flags & CHN_F_RUNNING))
409 		rdch->flags |= CHN_F_RUNNING;
410 	ret = chn_read(rdch, buf);
411 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
412 
413 	splx(s);
414 	return ret;
415 }
416 
417 static int
418 dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
419 {
420 	struct pcm_channel *rdch, *wrch;
421 	intrmask_t s;
422 	int ret;
423 
424 	s = spltty();
425 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_WR);
426 
427 	KASSERT(wrch, ("dsp_write: nonexistant channel"));
428 	KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel"));
429 
430 	if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
431 		relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
432 		splx(s);
433 		return EINVAL;
434 	}
435 	if (!(wrch->flags & CHN_F_RUNNING))
436 		wrch->flags |= CHN_F_RUNNING;
437 	ret = chn_write(wrch, buf);
438 	relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
439 
440 	splx(s);
441 	return ret;
442 }
443 
444 static int
445 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
446 {
447     	struct pcm_channel *chn, *rdch, *wrch;
448 	struct snddev_info *d;
449 	intrmask_t s;
450 	int kill;
451     	int ret = 0, *arg_i = (int *)arg, tmp;
452 
453 	/*
454 	 * this is an evil hack to allow broken apps to perform mixer ioctls
455 	 * on dsp devices.
456 	 */
457 
458 	d = dsp_get_info(i_dev);
459 	if (IOCGROUP(cmd) == 'M')
460 		return mixer_ioctl(d->mixer_dev, cmd, arg, mode, td);
461 
462     	s = spltty();
463 	getchns(i_dev, &rdch, &wrch, 0);
464 
465 	kill = 0;
466 	if (wrch && (wrch->flags & CHN_F_DEAD))
467 		kill |= 1;
468 	if (rdch && (rdch->flags & CHN_F_DEAD))
469 		kill |= 2;
470 	if (kill == 3) {
471 		relchns(i_dev, rdch, wrch, 0);
472 		splx(s);
473 		return EINVAL;
474 	}
475 	if (kill & 1)
476 		wrch = NULL;
477 	if (kill & 2)
478 		rdch = NULL;
479 
480     	switch(cmd) {
481 #ifdef OLDPCM_IOCTL
482     	/*
483      	 * we start with the new ioctl interface.
484      	 */
485     	case AIONWRITE:	/* how many bytes can write ? */
486 		CHN_LOCK(wrch);
487 /*
488 		if (wrch && wrch->bufhard.dl)
489 			while (chn_wrfeed(wrch) == 0);
490 */
491 		*arg_i = wrch? sndbuf_getfree(wrch->bufsoft) : 0;
492 		CHN_UNLOCK(wrch);
493 		break;
494 
495     	case AIOSSIZE:     /* set the current blocksize */
496 		{
497 	    		struct snd_size *p = (struct snd_size *)arg;
498 
499 			p->play_size = 0;
500 			p->rec_size = 0;
501 	    		if (wrch) {
502 				CHN_LOCK(wrch);
503 				chn_setblocksize(wrch, 2, p->play_size);
504 				p->play_size = sndbuf_getblksz(wrch->bufsoft);
505 				CHN_UNLOCK(wrch);
506 			}
507 	    		if (rdch) {
508 				CHN_LOCK(rdch);
509 				chn_setblocksize(rdch, 2, p->rec_size);
510 				p->rec_size = sndbuf_getblksz(rdch->bufsoft);
511 				CHN_UNLOCK(rdch);
512 			}
513 		}
514 		break;
515     	case AIOGSIZE:	/* get the current blocksize */
516 		{
517 	    		struct snd_size *p = (struct snd_size *)arg;
518 
519 	    		if (wrch) {
520 				CHN_LOCK(wrch);
521 				p->play_size = sndbuf_getblksz(wrch->bufsoft);
522 				CHN_UNLOCK(wrch);
523 			}
524 	    		if (rdch) {
525 				CHN_LOCK(rdch);
526 				p->rec_size = sndbuf_getblksz(rdch->bufsoft);
527 				CHN_UNLOCK(rdch);
528 			}
529 		}
530 		break;
531 
532     	case AIOSFMT:
533     	case AIOGFMT:
534 		{
535 	    		snd_chan_param *p = (snd_chan_param *)arg;
536 
537 	    		if (wrch) {
538 				CHN_LOCK(wrch);
539 				if (cmd == AIOSFMT) {
540 					chn_setformat(wrch, p->play_format);
541 					chn_setspeed(wrch, p->play_rate);
542 				}
543 	    			p->play_rate = wrch->speed;
544 	    			p->play_format = wrch->format;
545 				CHN_UNLOCK(wrch);
546 			} else {
547 	    			p->play_rate = 0;
548 	    			p->play_format = 0;
549 	    		}
550 	    		if (rdch) {
551 				CHN_LOCK(rdch);
552 				if (cmd == AIOSFMT) {
553 					chn_setformat(rdch, p->rec_format);
554 					chn_setspeed(rdch, p->rec_rate);
555 				}
556 				p->rec_rate = rdch->speed;
557 				p->rec_format = rdch->format;
558 				CHN_UNLOCK(rdch);
559 			} else {
560 	    			p->rec_rate = 0;
561 	    			p->rec_format = 0;
562 	    		}
563 		}
564 		break;
565 
566     	case AIOGCAP:     /* get capabilities */
567 		{
568 	    		snd_capabilities *p = (snd_capabilities *)arg;
569 			struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
570 			struct cdev *pdev;
571 
572 			if (rdch) {
573 				CHN_LOCK(rdch);
574 				rcaps = chn_getcaps(rdch);
575 			}
576 			if (wrch) {
577 				CHN_LOCK(wrch);
578 				pcaps = chn_getcaps(wrch);
579 			}
580 	    		p->rate_min = max(rcaps? rcaps->minspeed : 0,
581 	                      		  pcaps? pcaps->minspeed : 0);
582 	    		p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
583 	                      		  pcaps? pcaps->maxspeed : 1000000);
584 	    		p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
585 	                     		 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
586 			/* XXX bad on sb16 */
587 	    		p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
588 			 	     (wrch? chn_getformats(wrch) : 0xffffffff);
589 			if (rdch && wrch)
590 				p->formats |= (dsp_get_flags(i_dev) & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX;
591 			pdev = d->mixer_dev;
592 	    		p->mixers = 1; /* default: one mixer */
593 	    		p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
594 	    		p->left = p->right = 100;
595 			if (rdch)
596 				CHN_UNLOCK(rdch);
597 			if (wrch)
598 				CHN_UNLOCK(wrch);
599 		}
600 		break;
601 
602     	case AIOSTOP:
603 		if (*arg_i == AIOSYNC_PLAY && wrch) {
604 			CHN_LOCK(wrch);
605 			*arg_i = chn_abort(wrch);
606 			CHN_UNLOCK(wrch);
607 		} else if (*arg_i == AIOSYNC_CAPTURE && rdch) {
608 			CHN_LOCK(rdch);
609 			*arg_i = chn_abort(rdch);
610 			CHN_UNLOCK(rdch);
611 		} else {
612 	   	 	printf("AIOSTOP: bad channel 0x%x\n", *arg_i);
613 	    		*arg_i = 0;
614 		}
615 		break;
616 
617     	case AIOSYNC:
618 		printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
619 	    		((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
620 		break;
621 #endif
622 	/*
623 	 * here follow the standard ioctls (filio.h etc.)
624 	 */
625     	case FIONREAD: /* get # bytes to read */
626 		if (rdch) {
627 			CHN_LOCK(rdch);
628 /*			if (rdch && rdch->bufhard.dl)
629 				while (chn_rdfeed(rdch) == 0);
630 */
631 			*arg_i = sndbuf_getready(rdch->bufsoft);
632 			CHN_UNLOCK(rdch);
633 		} else
634 			*arg_i = 0;
635 		break;
636 
637     	case FIOASYNC: /*set/clear async i/o */
638 		DEB( printf("FIOASYNC\n") ; )
639 		break;
640 
641     	case SNDCTL_DSP_NONBLOCK:
642     	case FIONBIO: /* set/clear non-blocking i/o */
643 		if (rdch) {
644 			CHN_LOCK(rdch);
645 			if (*arg_i)
646 				rdch->flags |= CHN_F_NBIO;
647 			else
648 				rdch->flags &= ~CHN_F_NBIO;
649 			CHN_UNLOCK(rdch);
650 		}
651 		if (wrch) {
652 			CHN_LOCK(wrch);
653 			if (*arg_i)
654 				wrch->flags |= CHN_F_NBIO;
655 			else
656 				wrch->flags &= ~CHN_F_NBIO;
657 			CHN_UNLOCK(wrch);
658 		}
659 		break;
660 
661     	/*
662 	 * Finally, here is the linux-compatible ioctl interface
663 	 */
664 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
665     	case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
666     	case SNDCTL_DSP_GETBLKSIZE:
667 		chn = wrch ? wrch : rdch;
668 		CHN_LOCK(chn);
669 		*arg_i = sndbuf_getblksz(chn->bufsoft);
670 		CHN_UNLOCK(chn);
671 		break ;
672 
673     	case SNDCTL_DSP_SETBLKSIZE:
674 		RANGE(*arg_i, 16, 65536);
675 		if (wrch) {
676 			CHN_LOCK(wrch);
677 			chn_setblocksize(wrch, 2, *arg_i);
678 			CHN_UNLOCK(wrch);
679 		}
680 		if (rdch) {
681 			CHN_LOCK(rdch);
682 			chn_setblocksize(rdch, 2, *arg_i);
683 			CHN_UNLOCK(rdch);
684 		}
685 		break;
686 
687     	case SNDCTL_DSP_RESET:
688 		DEB(printf("dsp reset\n"));
689 		if (wrch) {
690 			CHN_LOCK(wrch);
691 			chn_abort(wrch);
692 			chn_resetbuf(wrch);
693 			CHN_UNLOCK(wrch);
694 		}
695 		if (rdch) {
696 			CHN_LOCK(rdch);
697 			chn_abort(rdch);
698 			chn_resetbuf(rdch);
699 			CHN_UNLOCK(rdch);
700 		}
701 		break;
702 
703     	case SNDCTL_DSP_SYNC:
704 		DEB(printf("dsp sync\n"));
705 		/* chn_sync may sleep */
706 		if (wrch) {
707 			CHN_LOCK(wrch);
708 			chn_sync(wrch, sndbuf_getsize(wrch->bufsoft) - 4);
709 			CHN_UNLOCK(wrch);
710 		}
711 		break;
712 
713     	case SNDCTL_DSP_SPEED:
714 		/* chn_setspeed may sleep */
715 		tmp = 0;
716 		if (wrch) {
717 			CHN_LOCK(wrch);
718 			ret = chn_setspeed(wrch, *arg_i);
719 			tmp = wrch->speed;
720 			CHN_UNLOCK(wrch);
721 		}
722 		if (rdch && ret == 0) {
723 			CHN_LOCK(rdch);
724 			ret = chn_setspeed(rdch, *arg_i);
725 			if (tmp == 0)
726 				tmp = rdch->speed;
727 			CHN_UNLOCK(rdch);
728 		}
729 		*arg_i = tmp;
730 		break;
731 
732     	case SOUND_PCM_READ_RATE:
733 		chn = wrch ? wrch : rdch;
734 		CHN_LOCK(chn);
735 		*arg_i = chn->speed;
736 		CHN_UNLOCK(chn);
737 		break;
738 
739     	case SNDCTL_DSP_STEREO:
740 		tmp = -1;
741 		*arg_i = (*arg_i)? AFMT_STEREO : 0;
742 		if (wrch) {
743 			CHN_LOCK(wrch);
744 			ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
745 			tmp = (wrch->format & AFMT_STEREO)? 1 : 0;
746 			CHN_UNLOCK(wrch);
747 		}
748 		if (rdch && ret == 0) {
749 			CHN_LOCK(rdch);
750 			ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
751 			if (tmp == -1)
752 				tmp = (rdch->format & AFMT_STEREO)? 1 : 0;
753 			CHN_UNLOCK(rdch);
754 		}
755 		*arg_i = tmp;
756 		break;
757 
758     	case SOUND_PCM_WRITE_CHANNELS:
759 /*	case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
760 		if (*arg_i != 0) {
761 			tmp = 0;
762 			*arg_i = (*arg_i != 1)? AFMT_STEREO : 0;
763 	  		if (wrch) {
764 				CHN_LOCK(wrch);
765 				ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i);
766 				tmp = (wrch->format & AFMT_STEREO)? 2 : 1;
767 				CHN_UNLOCK(wrch);
768 			}
769 			if (rdch && ret == 0) {
770 				CHN_LOCK(rdch);
771 				ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i);
772 				if (tmp == 0)
773 					tmp = (rdch->format & AFMT_STEREO)? 2 : 1;
774 				CHN_UNLOCK(rdch);
775 			}
776 			*arg_i = tmp;
777 		} else {
778 			chn = wrch ? wrch : rdch;
779 			CHN_LOCK(chn);
780 			*arg_i = (chn->format & AFMT_STEREO) ? 2 : 1;
781 			CHN_UNLOCK(chn);
782 		}
783 		break;
784 
785     	case SOUND_PCM_READ_CHANNELS:
786 		chn = wrch ? wrch : rdch;
787 		CHN_LOCK(chn);
788 		*arg_i = (chn->format & AFMT_STEREO) ? 2 : 1;
789 		CHN_UNLOCK(chn);
790 		break;
791 
792     	case SNDCTL_DSP_GETFMTS:	/* returns a mask of supported fmts */
793 		chn = wrch ? wrch : rdch;
794 		CHN_LOCK(chn);
795 		*arg_i = chn_getformats(chn);
796 		CHN_UNLOCK(chn);
797 		break ;
798 
799     	case SNDCTL_DSP_SETFMT:	/* sets _one_ format */
800 		if ((*arg_i != AFMT_QUERY)) {
801 			tmp = 0;
802 			if (wrch) {
803 				CHN_LOCK(wrch);
804 				ret = chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO));
805 				tmp = wrch->format & ~AFMT_STEREO;
806 				CHN_UNLOCK(wrch);
807 			}
808 			if (rdch && ret == 0) {
809 				CHN_LOCK(rdch);
810 				ret = chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO));
811 				if (tmp == 0)
812 					tmp = rdch->format & ~AFMT_STEREO;
813 				CHN_UNLOCK(rdch);
814 			}
815 			*arg_i = tmp;
816 		} else {
817 			chn = wrch ? wrch : rdch;
818 			CHN_LOCK(chn);
819 			*arg_i = chn->format & ~AFMT_STEREO;
820 			CHN_UNLOCK(chn);
821 		}
822 		break;
823 
824     	case SNDCTL_DSP_SETFRAGMENT:
825 		DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
826 		{
827 			u_int32_t fragln = (*arg_i) & 0x0000ffff;
828 			u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
829 			u_int32_t fragsz;
830 
831 			RANGE(fragln, 4, 16);
832 			fragsz = 1 << fragln;
833 
834 			if (maxfrags == 0)
835 				maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
836 			if (maxfrags < 2)
837 				maxfrags = 2;
838 			if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
839 				maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
840 
841 			DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
842 		    	if (rdch) {
843 				CHN_LOCK(rdch);
844 				ret = chn_setblocksize(rdch, maxfrags, fragsz);
845 				maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
846 				fragsz = sndbuf_getblksz(rdch->bufsoft);
847 				CHN_UNLOCK(rdch);
848 			}
849 		    	if (wrch && ret == 0) {
850 				CHN_LOCK(wrch);
851 				ret = chn_setblocksize(wrch, maxfrags, fragsz);
852  				maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
853 				fragsz = sndbuf_getblksz(wrch->bufsoft);
854 				CHN_UNLOCK(wrch);
855 			}
856 
857 			fragln = 0;
858 			while (fragsz > 1) {
859 				fragln++;
860 				fragsz >>= 1;
861 			}
862 	    		*arg_i = (maxfrags << 16) | fragln;
863 		}
864 		break;
865 
866     	case SNDCTL_DSP_GETISPACE:
867 		/* return the size of data available in the input queue */
868 		{
869 	    		audio_buf_info *a = (audio_buf_info *)arg;
870 	    		if (rdch) {
871 	        		struct snd_dbuf *bs = rdch->bufsoft;
872 
873 				CHN_LOCK(rdch);
874 				a->bytes = sndbuf_getready(bs);
875 	        		a->fragments = a->bytes / sndbuf_getblksz(bs);
876 	        		a->fragstotal = sndbuf_getblkcnt(bs);
877 	        		a->fragsize = sndbuf_getblksz(bs);
878 				CHN_UNLOCK(rdch);
879 	    		}
880 		}
881 		break;
882 
883     	case SNDCTL_DSP_GETOSPACE:
884 		/* return space available in the output queue */
885 		{
886 	    		audio_buf_info *a = (audio_buf_info *)arg;
887 	    		if (wrch) {
888 	        		struct snd_dbuf *bs = wrch->bufsoft;
889 
890 				CHN_LOCK(wrch);
891 				chn_wrupdate(wrch);
892 				a->bytes = sndbuf_getfree(bs);
893 	        		a->fragments = a->bytes / sndbuf_getblksz(bs);
894 	        		a->fragstotal = sndbuf_getblkcnt(bs);
895 	        		a->fragsize = sndbuf_getblksz(bs);
896 				CHN_UNLOCK(wrch);
897 	    		}
898 		}
899 		break;
900 
901     	case SNDCTL_DSP_GETIPTR:
902 		{
903 	    		count_info *a = (count_info *)arg;
904 	    		if (rdch) {
905 	        		struct snd_dbuf *bs = rdch->bufsoft;
906 
907 				CHN_LOCK(rdch);
908 				chn_rdupdate(rdch);
909 	        		a->bytes = sndbuf_gettotal(bs);
910 	        		a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
911 	        		a->ptr = sndbuf_getreadyptr(bs);
912 				rdch->blocks = sndbuf_getblocks(bs);
913 				CHN_UNLOCK(rdch);
914 	    		} else
915 				ret = EINVAL;
916 		}
917 		break;
918 
919     	case SNDCTL_DSP_GETOPTR:
920 		{
921 	    		count_info *a = (count_info *)arg;
922 	    		if (wrch) {
923 	        		struct snd_dbuf *bs = wrch->bufsoft;
924 
925 				CHN_LOCK(wrch);
926 				chn_wrupdate(wrch);
927 	        		a->bytes = sndbuf_gettotal(bs);
928 	        		a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
929 	        		a->ptr = sndbuf_getreadyptr(bs);
930 				wrch->blocks = sndbuf_getblocks(bs);
931 				CHN_UNLOCK(wrch);
932 	    		} else
933 				ret = EINVAL;
934 		}
935 		break;
936 
937     	case SNDCTL_DSP_GETCAPS:
938 		*arg_i = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER;
939 		if (rdch && wrch && !(dsp_get_flags(i_dev) & SD_F_SIMPLEX))
940 			*arg_i |= DSP_CAP_DUPLEX;
941 		break;
942 
943     	case SOUND_PCM_READ_BITS:
944 		chn = wrch ? wrch : rdch;
945 		CHN_LOCK(chn);
946         	*arg_i = (chn->format & AFMT_16BIT) ? 16 : 8;
947 		CHN_UNLOCK(chn);
948 		break;
949 
950     	case SNDCTL_DSP_SETTRIGGER:
951 		if (rdch) {
952 			CHN_LOCK(rdch);
953 			rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
954 		    	if (*arg_i & PCM_ENABLE_INPUT)
955 				chn_start(rdch, 1);
956 			else
957 				rdch->flags |= CHN_F_NOTRIGGER;
958 			CHN_UNLOCK(rdch);
959 		}
960 		if (wrch) {
961 			CHN_LOCK(wrch);
962 			wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
963 		    	if (*arg_i & PCM_ENABLE_OUTPUT)
964 				chn_start(wrch, 1);
965 			else
966 				wrch->flags |= CHN_F_NOTRIGGER;
967 			CHN_UNLOCK(wrch);
968 		}
969 		break;
970 
971     	case SNDCTL_DSP_GETTRIGGER:
972 		*arg_i = 0;
973 		if (wrch) {
974 			CHN_LOCK(wrch);
975 			if (wrch->flags & CHN_F_TRIGGERED)
976 				*arg_i |= PCM_ENABLE_OUTPUT;
977 			CHN_UNLOCK(wrch);
978 		}
979 		if (rdch) {
980 			CHN_LOCK(rdch);
981 			if (rdch->flags & CHN_F_TRIGGERED)
982 				*arg_i |= PCM_ENABLE_INPUT;
983 			CHN_UNLOCK(rdch);
984 		}
985 		break;
986 
987 	case SNDCTL_DSP_GETODELAY:
988 		if (wrch) {
989 			struct snd_dbuf *b = wrch->bufhard;
990 	        	struct snd_dbuf *bs = wrch->bufsoft;
991 
992 			CHN_LOCK(wrch);
993 			chn_wrupdate(wrch);
994 			*arg_i = sndbuf_getready(b) + sndbuf_getready(bs);
995 			CHN_UNLOCK(wrch);
996 		} else
997 			ret = EINVAL;
998 		break;
999 
1000     	case SNDCTL_DSP_POST:
1001 		if (wrch) {
1002 			CHN_LOCK(wrch);
1003 			wrch->flags &= ~CHN_F_NOTRIGGER;
1004 			chn_start(wrch, 1);
1005 			CHN_UNLOCK(wrch);
1006 		}
1007 		break;
1008 
1009 	case SNDCTL_DSP_SETDUPLEX:
1010 		/*
1011 		 * switch to full-duplex mode if card is in half-duplex
1012 		 * mode and is able to work in full-duplex mode
1013 		 */
1014 		if (rdch && wrch && (dsp_get_flags(i_dev) & SD_F_SIMPLEX))
1015 			dsp_set_flags(i_dev, dsp_get_flags(i_dev)^SD_F_SIMPLEX);
1016 		break;
1017 
1018     	case SNDCTL_DSP_MAPINBUF:
1019     	case SNDCTL_DSP_MAPOUTBUF:
1020     	case SNDCTL_DSP_SETSYNCRO:
1021 		/* undocumented */
1022 
1023     	case SNDCTL_DSP_SUBDIVIDE:
1024     	case SOUND_PCM_WRITE_FILTER:
1025     	case SOUND_PCM_READ_FILTER:
1026 		/* dunno what these do, don't sound important */
1027 
1028     	default:
1029 		DEB(printf("default ioctl fn 0x%08lx fail\n", cmd));
1030 		ret = EINVAL;
1031 		break;
1032     	}
1033 	relchns(i_dev, rdch, wrch, 0);
1034 	splx(s);
1035     	return ret;
1036 }
1037 
1038 static int
1039 dsp_poll(struct cdev *i_dev, int events, struct thread *td)
1040 {
1041 	struct pcm_channel *wrch = NULL, *rdch = NULL;
1042 	intrmask_t s;
1043 	int ret, e;
1044 
1045 	s = spltty();
1046 	ret = 0;
1047 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1048 
1049 	if (wrch) {
1050 		e = (events & (POLLOUT | POLLWRNORM));
1051 		if (e)
1052 			ret |= chn_poll(wrch, e, td);
1053 	}
1054 	if (rdch) {
1055 		e = (events & (POLLIN | POLLRDNORM));
1056 		if (e)
1057 			ret |= chn_poll(rdch, e, td);
1058 	}
1059 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1060 
1061 	splx(s);
1062 	return ret;
1063 }
1064 
1065 static int
1066 dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
1067 {
1068 	struct pcm_channel *wrch = NULL, *rdch = NULL, *c;
1069 	intrmask_t s;
1070 
1071 	if (nprot & PROT_EXEC)
1072 		return -1;
1073 
1074 	s = spltty();
1075 	getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1076 #if 0
1077 	/*
1078 	 * XXX the linux api uses the nprot to select read/write buffer
1079 	 * our vm system doesn't allow this, so force write buffer
1080 	 */
1081 
1082 	if (wrch && (nprot & PROT_WRITE)) {
1083 		c = wrch;
1084 	} else if (rdch && (nprot & PROT_READ)) {
1085 		c = rdch;
1086 	} else {
1087 		splx(s);
1088 		return -1;
1089 	}
1090 #else
1091 	c = wrch;
1092 #endif
1093 
1094 	if (c == NULL) {
1095 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1096 		splx(s);
1097 		return -1;
1098 	}
1099 
1100 	if (offset >= sndbuf_getsize(c->bufsoft)) {
1101 		relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1102 		splx(s);
1103 		return -1;
1104 	}
1105 
1106 	if (!(c->flags & CHN_F_MAPPED))
1107 		c->flags |= CHN_F_MAPPED;
1108 
1109 	*paddr = vtophys(sndbuf_getbufofs(c->bufsoft, offset));
1110 	relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
1111 
1112 	splx(s);
1113 	return 0;
1114 }
1115 
1116 #ifdef USING_DEVFS
1117 
1118 /*
1119  * Clone logic is this:
1120  * x E X = {dsp, dspW, audio}
1121  * x -> x${sysctl("hw.snd.unit")}
1122  * xN->
1123  *    for i N = 1 to channels of device N
1124  *    	if xN.i isn't busy, return its dev_t
1125  */
1126 static void
1127 dsp_clone(void *arg, char *name, int namelen, struct cdev **dev)
1128 {
1129 	struct cdev *pdev;
1130 	struct snddev_info *pcm_dev;
1131 	struct snddev_channel *pcm_chan;
1132 	int i, unit, devtype;
1133 	int devtypes[3] = {SND_DEV_DSP, SND_DEV_DSP16, SND_DEV_AUDIO};
1134 	char *devnames[3] = {"dsp", "dspW", "audio"};
1135 
1136 	if (*dev != NULL)
1137 		return;
1138 	if (pcm_devclass == NULL)
1139 		return;
1140 
1141 	devtype = 0;
1142 	unit = -1;
1143 	for (i = 0; (i < 3) && (unit == -1); i++) {
1144 		devtype = devtypes[i];
1145 		if (strcmp(name, devnames[i]) == 0) {
1146 			unit = snd_unit;
1147 		} else {
1148 			if (dev_stdclone(name, NULL, devnames[i], &unit) != 1)
1149 				unit = -1;
1150 		}
1151 	}
1152 	if (unit == -1 || unit >= devclass_get_maxunit(pcm_devclass))
1153 		return;
1154 
1155 	pcm_dev = devclass_get_softc(pcm_devclass, unit);
1156 
1157 	if (pcm_dev == NULL)
1158 		return;
1159 
1160 	SLIST_FOREACH(pcm_chan, &pcm_dev->channels, link) {
1161 
1162 		switch(devtype) {
1163 			case SND_DEV_DSP:
1164 				pdev = pcm_chan->dsp_devt;
1165 				break;
1166 			case SND_DEV_DSP16:
1167 				pdev = pcm_chan->dspW_devt;
1168 				break;
1169 			case SND_DEV_AUDIO:
1170 				pdev = pcm_chan->audio_devt;
1171 				break;
1172 			default:
1173 				panic("Unknown devtype %d", devtype);
1174 		}
1175 
1176 		if ((pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) {
1177 			*dev = pdev;
1178 			return;
1179 		}
1180 	}
1181 }
1182 
1183 static void
1184 dsp_sysinit(void *p)
1185 {
1186 	dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
1187 }
1188 
1189 static void
1190 dsp_sysuninit(void *p)
1191 {
1192 	if (dsp_ehtag != NULL)
1193 		EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
1194 }
1195 
1196 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
1197 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
1198 #endif
1199 
1200 
1201