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