xref: /freebsd/sys/dev/sound/pcm/channel.c (revision 2bc6540439d0932b38067c9cc321fa0e2a61f264)
1 /*-
2  * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3  * Portions Copyright by Luigi Rizzo - 1997-99
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include "opt_isa.h"
29 
30 #include <dev/sound/pcm/sound.h>
31 
32 #include "feeder_if.h"
33 
34 SND_DECLARE_FILE("$FreeBSD$");
35 
36 #define MIN_CHUNK_SIZE 		256	/* for uiomove etc. */
37 #define	DMA_ALIGN_THRESHOLD	4
38 #define	DMA_ALIGN_MASK		(~(DMA_ALIGN_THRESHOLD - 1))
39 
40 #define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED))
41 
42 /*
43 #define DEB(x) x
44 */
45 
46 static int chn_targetirqrate = 32;
47 TUNABLE_INT("hw.snd.targetirqrate", &chn_targetirqrate);
48 
49 static int
50 sysctl_hw_snd_targetirqrate(SYSCTL_HANDLER_ARGS)
51 {
52 	int err, val;
53 
54 	val = chn_targetirqrate;
55 	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
56 	if (val < 16 || val > 512)
57 		err = EINVAL;
58 	else
59 		chn_targetirqrate = val;
60 
61 	return err;
62 }
63 SYSCTL_PROC(_hw_snd, OID_AUTO, targetirqrate, CTLTYPE_INT | CTLFLAG_RW,
64 	0, sizeof(int), sysctl_hw_snd_targetirqrate, "I", "");
65 static int report_soft_formats = 1;
66 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
67 	&report_soft_formats, 1, "report software-emulated formats");
68 
69 static int chn_buildfeeder(struct pcm_channel *c);
70 
71 static void
72 chn_lockinit(struct pcm_channel *c, int dir)
73 {
74 	switch(dir) {
75 	case PCMDIR_PLAY:
76 		c->lock = snd_mtxcreate(c->name, "pcm play channel");
77 		break;
78 	case PCMDIR_REC:
79 		c->lock = snd_mtxcreate(c->name, "pcm record channel");
80 		break;
81 	case PCMDIR_VIRTUAL:
82 		c->lock = snd_mtxcreate(c->name, "pcm virtual play channel");
83 		break;
84 	case 0:
85 		c->lock = snd_mtxcreate(c->name, "pcm fake channel");
86 		break;
87 	}
88 }
89 
90 static void
91 chn_lockdestroy(struct pcm_channel *c)
92 {
93 	snd_mtxfree(c->lock);
94 }
95 
96 static int
97 chn_polltrigger(struct pcm_channel *c)
98 {
99 	struct snd_dbuf *bs = c->bufsoft;
100 	unsigned amt, lim;
101 
102 	CHN_LOCKASSERT(c);
103 	if (c->flags & CHN_F_MAPPED) {
104 		if (sndbuf_getprevblocks(bs) == 0)
105 			return 1;
106 		else
107 			return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
108 	} else {
109 		amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
110 #if 0
111 		lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
112 #endif
113 		lim = 1;
114 		return (amt >= lim)? 1 : 0;
115 	}
116 	return 0;
117 }
118 
119 static int
120 chn_pollreset(struct pcm_channel *c)
121 {
122 	struct snd_dbuf *bs = c->bufsoft;
123 
124 	CHN_LOCKASSERT(c);
125 	sndbuf_updateprevtotal(bs);
126 	return 1;
127 }
128 
129 static void
130 chn_wakeup(struct pcm_channel *c)
131 {
132 	struct snd_dbuf *bs = c->bufsoft;
133 	struct pcmchan_children *pce;
134 
135 	CHN_LOCKASSERT(c);
136 	if (SLIST_EMPTY(&c->children)) {
137 		if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
138 			selwakeuppri(sndbuf_getsel(bs), PRIBIO);
139 	} else {
140 		SLIST_FOREACH(pce, &c->children, link) {
141 			CHN_LOCK(pce->channel);
142 			chn_wakeup(pce->channel);
143 			CHN_UNLOCK(pce->channel);
144 		}
145 	}
146 
147 	wakeup(bs);
148 }
149 
150 static int
151 chn_sleep(struct pcm_channel *c, char *str, int timeout)
152 {
153     	struct snd_dbuf *bs = c->bufsoft;
154 	int ret;
155 
156 	CHN_LOCKASSERT(c);
157 #ifdef USING_MUTEX
158 	ret = msleep(bs, c->lock, PRIBIO | PCATCH, str, timeout);
159 #else
160 	ret = tsleep(bs, PRIBIO | PCATCH, str, timeout);
161 #endif
162 
163 	return ret;
164 }
165 
166 /*
167  * chn_dmaupdate() tracks the status of a dma transfer,
168  * updating pointers.
169  */
170 
171 static unsigned int
172 chn_dmaupdate(struct pcm_channel *c)
173 {
174 	struct snd_dbuf *b = c->bufhard;
175 	unsigned int delta, old, hwptr, amt;
176 
177 	KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0"));
178 	CHN_LOCKASSERT(c);
179 
180 	old = sndbuf_gethwptr(b);
181 	hwptr = chn_getptr(c);
182 	delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b);
183 	sndbuf_sethwptr(b, hwptr);
184 
185 	DEB(
186 	if (delta >= ((sndbuf_getsize(b) * 15) / 16)) {
187 		if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING)))
188 			device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr);
189 	}
190 	);
191 
192 	if (c->direction == PCMDIR_PLAY) {
193 		amt = MIN(delta, sndbuf_getready(b));
194 		if (amt > 0)
195 			sndbuf_dispose(b, NULL, amt);
196 	} else {
197 		amt = MIN(delta, sndbuf_getfree(b));
198 		if (amt > 0)
199 		       sndbuf_acquire(b, NULL, amt);
200 	}
201 
202 	return delta;
203 }
204 
205 void
206 chn_wrupdate(struct pcm_channel *c)
207 {
208 	int ret;
209 
210 	CHN_LOCKASSERT(c);
211 	KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
212 
213 	if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED))
214 		return;
215 	chn_dmaupdate(c);
216 	ret = chn_wrfeed(c);
217 	/* tell the driver we've updated the primary buffer */
218 	chn_trigger(c, PCMTRIG_EMLDMAWR);
219 	DEB(if (ret)
220 		printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
221 
222 }
223 
224 int
225 chn_wrfeed(struct pcm_channel *c)
226 {
227     	struct snd_dbuf *b = c->bufhard;
228     	struct snd_dbuf *bs = c->bufsoft;
229 	unsigned int ret, amt;
230 
231 	CHN_LOCKASSERT(c);
232 #if 0
233     	DEB(
234 	if (c->flags & CHN_F_CLOSING) {
235 		sndbuf_dump(b, "b", 0x02);
236 		sndbuf_dump(bs, "bs", 0x02);
237 	})
238 #endif
239 
240 	if (c->flags & CHN_F_MAPPED)
241 		sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
242 
243 	amt = sndbuf_getfree(b);
244 	KASSERT(amt <= sndbuf_getsize(bs),
245 	    ("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name,
246 	   amt, sndbuf_getsize(bs), c->flags));
247 
248 	ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
249 	/*
250 	 * Possible xruns. There should be no empty space left in buffer.
251 	 */
252 	if (sndbuf_getfree(b) > 0)
253 		c->xruns++;
254 
255 	if (ret == 0 && sndbuf_getfree(b) < amt)
256 		chn_wakeup(c);
257 
258 	return ret;
259 }
260 
261 static void
262 chn_wrintr(struct pcm_channel *c)
263 {
264 	int ret;
265 
266 	CHN_LOCKASSERT(c);
267 	/* update pointers in primary buffer */
268 	chn_dmaupdate(c);
269 	/* ...and feed from secondary to primary */
270 	ret = chn_wrfeed(c);
271 	/* tell the driver we've updated the primary buffer */
272 	chn_trigger(c, PCMTRIG_EMLDMAWR);
273 	DEB(if (ret)
274 		printf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
275 }
276 
277 /*
278  * user write routine - uiomove data into secondary buffer, trigger if necessary
279  * if blocking, sleep, rinse and repeat.
280  *
281  * called externally, so must handle locking
282  */
283 
284 int
285 chn_write(struct pcm_channel *c, struct uio *buf)
286 {
287 	int ret, timeout, newsize, count, sz;
288 	struct snd_dbuf *bs = c->bufsoft;
289 	void *off;
290 	int t, x,togo,p;
291 
292 	CHN_LOCKASSERT(c);
293 	/*
294 	 * XXX Certain applications attempt to write larger size
295 	 * of pcm data than c->blocksize2nd without blocking,
296 	 * resulting partial write. Expand the block size so that
297 	 * the write operation avoids blocking.
298 	 */
299 	if ((c->flags & CHN_F_NBIO) && buf->uio_resid > sndbuf_getblksz(bs)) {
300 		DEB(device_printf(c->dev, "broken app, nbio and tried to write %d bytes with fragsz %d\n",
301 			buf->uio_resid, sndbuf_getblksz(bs)));
302 		newsize = 16;
303 		while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2))
304 			newsize <<= 1;
305 		chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize);
306 		DEB(device_printf(c->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs)));
307 	}
308 
309 	ret = 0;
310 	count = hz;
311 	while (!ret && (buf->uio_resid > 0) && (count > 0)) {
312 		sz = sndbuf_getfree(bs);
313 		if (sz == 0) {
314 			if (c->flags & CHN_F_NBIO)
315 				ret = EWOULDBLOCK;
316 			else {
317 				timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
318 				if (timeout < 1)
319 					timeout = 1;
320 				timeout = 1;
321 	   			ret = chn_sleep(c, "pcmwr", timeout);
322 				if (ret == EWOULDBLOCK) {
323 					count -= timeout;
324 					ret = 0;
325 				} else if (ret == 0)
326 					count = hz;
327 			}
328 		} else {
329 			sz = MIN(sz, buf->uio_resid);
330 			KASSERT(sz > 0, ("confusion in chn_write"));
331 			/* printf("sz: %d\n", sz); */
332 
333 			/*
334 			 * The following assumes that the free space in
335 			 * the buffer can never be less around the
336 			 * unlock-uiomove-lock sequence.
337 			 */
338 			togo = sz;
339 			while (ret == 0 && togo> 0) {
340 				p = sndbuf_getfreeptr(bs);
341 				t = MIN(togo, sndbuf_getsize(bs) - p);
342 				off = sndbuf_getbufofs(bs, p);
343 				CHN_UNLOCK(c);
344 				ret = uiomove(off, t, buf);
345 				CHN_LOCK(c);
346 				togo -= t;
347 				x = sndbuf_acquire(bs, NULL, t);
348 			}
349 			ret = 0;
350 			if (ret == 0 && !(c->flags & CHN_F_TRIGGERED))
351 				chn_start(c, 0);
352 		}
353 	}
354 	/* printf("ret: %d left: %d\n", ret, buf->uio_resid); */
355 
356 	if (count <= 0) {
357 		c->flags |= CHN_F_DEAD;
358 		printf("%s: play interrupt timeout, channel dead\n", c->name);
359 	}
360 
361 	return ret;
362 }
363 
364 #if 0
365 static int
366 chn_rddump(struct pcm_channel *c, unsigned int cnt)
367 {
368     	struct snd_dbuf *b = c->bufhard;
369 
370 	CHN_LOCKASSERT(c);
371 #if 0
372 	static uint32_t kk = 0;
373 	printf("%u: dumping %d bytes\n", ++kk, cnt);
374 #endif
375 	c->xruns++;
376 	sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt);
377 	return sndbuf_dispose(b, NULL, cnt);
378 }
379 #endif
380 
381 /*
382  * Feed new data from the read buffer. Can be called in the bottom half.
383  */
384 int
385 chn_rdfeed(struct pcm_channel *c)
386 {
387     	struct snd_dbuf *b = c->bufhard;
388     	struct snd_dbuf *bs = c->bufsoft;
389 	unsigned int ret, amt;
390 
391 	CHN_LOCKASSERT(c);
392     	DEB(
393 	if (c->flags & CHN_F_CLOSING) {
394 		sndbuf_dump(b, "b", 0x02);
395 		sndbuf_dump(bs, "bs", 0x02);
396 	})
397 
398 #if 0
399 	amt = sndbuf_getready(b);
400 	if (sndbuf_getfree(bs) < amt) {
401 		c->xruns++;
402 		amt = sndbuf_getfree(bs);
403 	}
404 #endif
405 	amt = sndbuf_getfree(bs);
406 	ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0;
407 
408 	amt = sndbuf_getready(b);
409 	if (amt > 0) {
410 		c->xruns++;
411 		sndbuf_dispose(b, NULL, amt);
412 	}
413 
414 	chn_wakeup(c);
415 
416 	return ret;
417 }
418 
419 void
420 chn_rdupdate(struct pcm_channel *c)
421 {
422 	int ret;
423 
424 	CHN_LOCKASSERT(c);
425 	KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
426 
427 	if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED))
428 		return;
429 	chn_trigger(c, PCMTRIG_EMLDMARD);
430 	chn_dmaupdate(c);
431 	ret = chn_rdfeed(c);
432 	DEB(if (ret)
433 		printf("chn_rdfeed: %d\n", ret);)
434 
435 }
436 
437 /* read interrupt routine. Must be called with interrupts blocked. */
438 static void
439 chn_rdintr(struct pcm_channel *c)
440 {
441 	int ret;
442 
443 	CHN_LOCKASSERT(c);
444 	/* tell the driver to update the primary buffer if non-dma */
445 	chn_trigger(c, PCMTRIG_EMLDMARD);
446 	/* update pointers in primary buffer */
447 	chn_dmaupdate(c);
448 	/* ...and feed from primary to secondary */
449 	ret = chn_rdfeed(c);
450 }
451 
452 /*
453  * user read routine - trigger if necessary, uiomove data from secondary buffer
454  * if blocking, sleep, rinse and repeat.
455  *
456  * called externally, so must handle locking
457  */
458 
459 int
460 chn_read(struct pcm_channel *c, struct uio *buf)
461 {
462 	int		ret, timeout, sz, count;
463 	struct snd_dbuf       *bs = c->bufsoft;
464 	void *off;
465 	int t, x,togo,p;
466 
467 	CHN_LOCKASSERT(c);
468 	if (!(c->flags & CHN_F_TRIGGERED))
469 		chn_start(c, 0);
470 
471 	ret = 0;
472 	count = hz;
473 	while (!ret && (buf->uio_resid > 0) && (count > 0)) {
474 		sz = MIN(buf->uio_resid, sndbuf_getready(bs));
475 
476 		if (sz > 0) {
477 			/*
478 			 * The following assumes that the free space in
479 			 * the buffer can never be less around the
480 			 * unlock-uiomove-lock sequence.
481 			 */
482 			togo = sz;
483 			while (ret == 0 && togo> 0) {
484 				p = sndbuf_getreadyptr(bs);
485 				t = MIN(togo, sndbuf_getsize(bs) - p);
486 				off = sndbuf_getbufofs(bs, p);
487 				CHN_UNLOCK(c);
488 				ret = uiomove(off, t, buf);
489 				CHN_LOCK(c);
490 				togo -= t;
491 				x = sndbuf_dispose(bs, NULL, t);
492 			}
493 			ret = 0;
494 		} else {
495 			if (c->flags & CHN_F_NBIO) {
496 				ret = EWOULDBLOCK;
497 			} else {
498 				timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
499 				if (timeout < 1)
500 					timeout = 1;
501 	   			ret = chn_sleep(c, "pcmrd", timeout);
502 				if (ret == EWOULDBLOCK) {
503 					count -= timeout;
504 					ret = 0;
505 				} else {
506 					count = hz;
507 				}
508 
509 			}
510 		}
511 	}
512 
513 	if (count <= 0) {
514 		c->flags |= CHN_F_DEAD;
515 		printf("%s: record interrupt timeout, channel dead\n", c->name);
516 	}
517 
518 	return ret;
519 }
520 
521 void
522 chn_intr(struct pcm_channel *c)
523 {
524 	CHN_LOCK(c);
525 	c->interrupts++;
526 	if (c->direction == PCMDIR_PLAY)
527 		chn_wrintr(c);
528 	else
529 		chn_rdintr(c);
530 	CHN_UNLOCK(c);
531 }
532 
533 u_int32_t
534 chn_start(struct pcm_channel *c, int force)
535 {
536 	u_int32_t i, j;
537 	struct snd_dbuf *b = c->bufhard;
538 	struct snd_dbuf *bs = c->bufsoft;
539 
540 	CHN_LOCKASSERT(c);
541 	/* if we're running, or if we're prevented from triggering, bail */
542 	if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force))
543 		return EINVAL;
544 
545 	i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs);
546 	j = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(b) : sndbuf_getready(b);
547 	if (force || (i >= j)) {
548 		c->flags |= CHN_F_TRIGGERED;
549 		/*
550 		 * if we're starting because a vchan started, don't feed any data
551 		 * or it becomes impossible to start vchans synchronised with the
552 		 * first one.  the hardbuf should be empty so we top it up with
553 		 * silence to give it something to chew.  the real data will be
554 		 * fed at the first irq.
555 		 */
556 		if (c->direction == PCMDIR_PLAY) {
557 			/*
558 			 * Reduce pops during playback startup.
559 			 */
560 			sndbuf_fillsilence(b);
561 			if (SLIST_EMPTY(&c->children))
562 				chn_wrfeed(c);
563 		}
564 		sndbuf_setrun(b, 1);
565 		c->xruns = 0;
566 	    	chn_trigger(c, PCMTRIG_START);
567 		return 0;
568 	}
569 
570 	return 0;
571 }
572 
573 void
574 chn_resetbuf(struct pcm_channel *c)
575 {
576 	struct snd_dbuf *b = c->bufhard;
577 	struct snd_dbuf *bs = c->bufsoft;
578 
579 	c->blocks = 0;
580 	sndbuf_reset(b);
581 	sndbuf_reset(bs);
582 }
583 
584 /*
585  * chn_sync waits until the space in the given channel goes above
586  * a threshold. The threshold is checked against fl or rl respectively.
587  * Assume that the condition can become true, do not check here...
588  */
589 int
590 chn_sync(struct pcm_channel *c, int threshold)
591 {
592     	u_long rdy;
593     	int ret;
594     	struct snd_dbuf *bs = c->bufsoft;
595 
596 	CHN_LOCKASSERT(c);
597 
598 	/* if we haven't yet started and nothing is buffered, else start*/
599 	if (!(c->flags & CHN_F_TRIGGERED)) {
600 		if (sndbuf_getready(bs) > 0) {
601 			ret = chn_start(c, 1);
602 			if (ret)
603 				return ret;
604 		} else {
605 			return 0;
606 		}
607 	}
608 
609 	for (;;) {
610 		rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
611 		if (rdy <= threshold) {
612 	    		ret = chn_sleep(c, "pcmsyn", 1);
613 	    		if (ret == ERESTART || ret == EINTR) {
614 				DEB(printf("chn_sync: tsleep returns %d\n", ret));
615 				return -1;
616 	    		}
617 		} else
618 			break;
619     	}
620     	return 0;
621 }
622 
623 /* called externally, handle locking */
624 int
625 chn_poll(struct pcm_channel *c, int ev, struct thread *td)
626 {
627 	struct snd_dbuf *bs = c->bufsoft;
628 	int ret;
629 
630 	CHN_LOCKASSERT(c);
631     	if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED))
632 		chn_start(c, 1);
633 	ret = 0;
634 	if (chn_polltrigger(c) && chn_pollreset(c))
635 		ret = ev;
636 	else
637 		selrecord(td, sndbuf_getsel(bs));
638 	return ret;
639 }
640 
641 /*
642  * chn_abort terminates a running dma transfer.  it may sleep up to 200ms.
643  * it returns the number of bytes that have not been transferred.
644  *
645  * called from: dsp_close, dsp_ioctl, with channel locked
646  */
647 int
648 chn_abort(struct pcm_channel *c)
649 {
650     	int missing = 0;
651     	struct snd_dbuf *b = c->bufhard;
652     	struct snd_dbuf *bs = c->bufsoft;
653 
654 	CHN_LOCKASSERT(c);
655 	if (!(c->flags & CHN_F_TRIGGERED))
656 		return 0;
657 	c->flags |= CHN_F_ABORTING;
658 
659 	c->flags &= ~CHN_F_TRIGGERED;
660 	/* kill the channel */
661 	chn_trigger(c, PCMTRIG_ABORT);
662 	sndbuf_setrun(b, 0);
663 	if (!(c->flags & CHN_F_VIRTUAL))
664 		chn_dmaupdate(c);
665     	missing = sndbuf_getready(bs) + sndbuf_getready(b);
666 
667 	c->flags &= ~CHN_F_ABORTING;
668 	return missing;
669 }
670 
671 /*
672  * this routine tries to flush the dma transfer. It is called
673  * on a close of a playback channel.
674  * first, if there is data in the buffer, but the dma has not yet
675  * begun, we need to start it.
676  * next, we wait for the play buffer to drain
677  * finally, we stop the dma.
678  *
679  * called from: dsp_close, not valid for record channels.
680  */
681 
682 int
683 chn_flush(struct pcm_channel *c)
684 {
685     	int ret, count, resid, resid_p;
686     	struct snd_dbuf *b = c->bufhard;
687     	struct snd_dbuf *bs = c->bufsoft;
688 
689 	CHN_LOCKASSERT(c);
690 	KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel"));
691     	DEB(printf("chn_flush: c->flags 0x%08x\n", c->flags));
692 
693 	/* if we haven't yet started and nothing is buffered, else start*/
694 	if (!(c->flags & CHN_F_TRIGGERED)) {
695 		if (sndbuf_getready(bs) > 0) {
696 			ret = chn_start(c, 1);
697 			if (ret)
698 				return ret;
699 		} else {
700 			return 0;
701 		}
702 	}
703 
704 	c->flags |= CHN_F_CLOSING;
705 	resid = sndbuf_getready(bs) + sndbuf_getready(b);
706 	resid_p = resid;
707 	count = 10;
708 	ret = 0;
709 	while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) {
710 		/* still pending output data. */
711 		ret = chn_sleep(c, "pcmflu", hz / 10);
712 		if (ret == EWOULDBLOCK)
713 			ret = 0;
714 		if (ret == 0) {
715 			resid = sndbuf_getready(bs) + sndbuf_getready(b);
716 			if (resid == resid_p)
717 				count--;
718 			if (resid > resid_p)
719 				DEB(printf("chn_flush: buffer length increasind %d -> %d\n", resid_p, resid));
720 			resid_p = resid;
721 		}
722    	}
723 	if (count == 0)
724 		DEB(printf("chn_flush: timeout, hw %d, sw %d\n",
725 			sndbuf_getready(b), sndbuf_getready(bs)));
726 
727 	c->flags &= ~CHN_F_TRIGGERED;
728 	/* kill the channel */
729 	chn_trigger(c, PCMTRIG_ABORT);
730 	sndbuf_setrun(b, 0);
731 
732     	c->flags &= ~CHN_F_CLOSING;
733     	return 0;
734 }
735 
736 int
737 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist)
738 {
739 	int i;
740 
741 	for (i = 0; fmtlist[i]; i++)
742 		if (fmt == fmtlist[i])
743 			return 1;
744 	return 0;
745 }
746 
747 int
748 chn_reset(struct pcm_channel *c, u_int32_t fmt)
749 {
750 	int hwspd, r;
751 
752 	CHN_LOCKASSERT(c);
753 	c->flags &= CHN_F_RESET;
754 	c->interrupts = 0;
755 	c->xruns = 0;
756 
757 	r = CHANNEL_RESET(c->methods, c->devinfo);
758 	if (fmt != 0) {
759 #if 0
760 		hwspd = DSP_DEFAULT_SPEED;
761 		/* only do this on a record channel until feederbuilder works */
762 		if (c->direction == PCMDIR_REC)
763 			RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
764 		c->speed = hwspd;
765 #endif
766 		hwspd = chn_getcaps(c)->minspeed;
767 		c->speed = hwspd;
768 
769 		if (r == 0)
770 			r = chn_setformat(c, fmt);
771 		if (r == 0)
772 			r = chn_setspeed(c, hwspd);
773 #if 0
774 		if (r == 0)
775 			r = chn_setvolume(c, 100, 100);
776 #endif
777 	}
778 	if (r == 0)
779 		r = chn_setblocksize(c, 0, 0);
780 	if (r == 0) {
781 		chn_resetbuf(c);
782 		r = CHANNEL_RESETDONE(c->methods, c->devinfo);
783 	}
784 	return r;
785 }
786 
787 int
788 chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction)
789 {
790 	struct feeder_class *fc;
791 	struct snd_dbuf *b, *bs;
792 	int ret;
793 
794 	chn_lockinit(c, dir);
795 
796 	b = NULL;
797 	bs = NULL;
798 	c->devinfo = NULL;
799 	c->feeder = NULL;
800 
801 	ret = ENOMEM;
802 	b = sndbuf_create(c->dev, c->name, "primary", c);
803 	if (b == NULL)
804 		goto out;
805 	bs = sndbuf_create(c->dev, c->name, "secondary", c);
806 	if (bs == NULL)
807 		goto out;
808 
809 	CHN_LOCK(c);
810 
811 	ret = EINVAL;
812 	fc = feeder_getclass(NULL);
813 	if (fc == NULL)
814 		goto out;
815 	if (chn_addfeeder(c, fc, NULL))
816 		goto out;
817 
818 	/*
819 	 * XXX - sndbuf_setup() & sndbuf_resize() expect to be called
820 	 *	 with the channel unlocked because they are also called
821 	 *	 from driver methods that don't know about locking
822 	 */
823 	CHN_UNLOCK(c);
824 	sndbuf_setup(bs, NULL, 0);
825 	CHN_LOCK(c);
826 	c->bufhard = b;
827 	c->bufsoft = bs;
828 	c->flags = 0;
829 	c->feederflags = 0;
830 
831 	ret = ENODEV;
832 	CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() malloc() call */
833 	c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction);
834 	CHN_LOCK(c);
835 	if (c->devinfo == NULL)
836 		goto out;
837 
838 	ret = ENOMEM;
839 	if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0))
840 		goto out;
841 
842 	ret = chn_setdir(c, direction);
843 	if (ret)
844 		goto out;
845 
846 	ret = sndbuf_setfmt(b, AFMT_U8);
847 	if (ret)
848 		goto out;
849 
850 	ret = sndbuf_setfmt(bs, AFMT_U8);
851 	if (ret)
852 		goto out;
853 
854 
855 out:
856 	CHN_UNLOCK(c);
857 	if (ret) {
858 		if (c->devinfo) {
859 			if (CHANNEL_FREE(c->methods, c->devinfo))
860 				sndbuf_free(b);
861 		}
862 		if (bs)
863 			sndbuf_destroy(bs);
864 		if (b)
865 			sndbuf_destroy(b);
866 		c->flags |= CHN_F_DEAD;
867 		chn_lockdestroy(c);
868 
869 		return ret;
870 	}
871 
872 	return 0;
873 }
874 
875 int
876 chn_kill(struct pcm_channel *c)
877 {
878     	struct snd_dbuf *b = c->bufhard;
879     	struct snd_dbuf *bs = c->bufsoft;
880 
881 	if (c->flags & CHN_F_TRIGGERED)
882 		chn_trigger(c, PCMTRIG_ABORT);
883 	while (chn_removefeeder(c) == 0);
884 	if (CHANNEL_FREE(c->methods, c->devinfo))
885 		sndbuf_free(b);
886 	c->flags |= CHN_F_DEAD;
887 	sndbuf_destroy(bs);
888 	sndbuf_destroy(b);
889 	chn_lockdestroy(c);
890 	return 0;
891 }
892 
893 int
894 chn_setdir(struct pcm_channel *c, int dir)
895 {
896 #ifdef DEV_ISA
897     	struct snd_dbuf *b = c->bufhard;
898 #endif
899 	int r;
900 
901 	CHN_LOCKASSERT(c);
902 	c->direction = dir;
903 	r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction);
904 #ifdef DEV_ISA
905 	if (!r && SND_DMA(b))
906 		sndbuf_dmasetdir(b, c->direction);
907 #endif
908 	return r;
909 }
910 
911 int
912 chn_setvolume(struct pcm_channel *c, int left, int right)
913 {
914 	CHN_LOCKASSERT(c);
915 	/* should add a feeder for volume changing if channel returns -1 */
916 	if (left > 100)
917 		left = 100;
918 	if (left < 0)
919 		left = 0;
920 	if (right > 100)
921 		right = 100;
922 	if (right < 0)
923 		right = 0;
924 	c->volume = left | (right << 8);
925 	return 0;
926 }
927 
928 static int
929 chn_tryspeed(struct pcm_channel *c, int speed)
930 {
931 	struct pcm_feeder *f;
932     	struct snd_dbuf *b = c->bufhard;
933     	struct snd_dbuf *bs = c->bufsoft;
934     	struct snd_dbuf *x;
935 	int r, delta;
936 
937 	CHN_LOCKASSERT(c);
938 	DEB(printf("setspeed, channel %s\n", c->name));
939 	DEB(printf("want speed %d, ", speed));
940 	if (speed <= 0)
941 		return EINVAL;
942 	if (CANCHANGE(c)) {
943 		r = 0;
944 		c->speed = speed;
945 		sndbuf_setspd(bs, speed);
946 		RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
947 		DEB(printf("try speed %d, ", speed));
948 		sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
949 		DEB(printf("got speed %d\n", sndbuf_getspd(b)));
950 
951 		delta = sndbuf_getspd(b) - sndbuf_getspd(bs);
952 		if (delta < 0)
953 			delta = -delta;
954 
955 		c->feederflags &= ~(1 << FEEDER_RATE);
956 		/*
957 		 * Used to be 500. It was too big!
958 		 */
959 		if (delta > 25)
960 			c->feederflags |= 1 << FEEDER_RATE;
961 		else
962 			sndbuf_setspd(bs, sndbuf_getspd(b));
963 
964 		r = chn_buildfeeder(c);
965 		DEB(printf("r = %d\n", r));
966 		if (r)
967 			goto out;
968 
969 		r = chn_setblocksize(c, 0, 0);
970 		if (r)
971 			goto out;
972 
973 		if (!(c->feederflags & (1 << FEEDER_RATE)))
974 			goto out;
975 
976 		r = EINVAL;
977 		f = chn_findfeeder(c, FEEDER_RATE);
978 		DEB(printf("feedrate = %p\n", f));
979 		if (f == NULL)
980 			goto out;
981 
982 		x = (c->direction == PCMDIR_REC)? b : bs;
983 		r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x));
984 		DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r));
985 		if (r)
986 			goto out;
987 
988 		x = (c->direction == PCMDIR_REC)? bs : b;
989 		r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
990 		DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
991 out:
992 		if (!r)
993 			r = CHANNEL_SETFORMAT(c->methods, c->devinfo,
994 							sndbuf_getfmt(b));
995 		if (!r)
996 			sndbuf_setfmt(bs, c->format);
997 		DEB(printf("setspeed done, r = %d\n", r));
998 		return r;
999 	} else
1000 		return EINVAL;
1001 }
1002 
1003 int
1004 chn_setspeed(struct pcm_channel *c, int speed)
1005 {
1006 	int r, oldspeed = c->speed;
1007 
1008 	r = chn_tryspeed(c, speed);
1009 	if (r) {
1010 		DEB(printf("Failed to set speed %d falling back to %d\n", speed, oldspeed));
1011 		r = chn_tryspeed(c, oldspeed);
1012 	}
1013 	return r;
1014 }
1015 
1016 static int
1017 chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
1018 {
1019 	struct snd_dbuf *b = c->bufhard;
1020 	struct snd_dbuf *bs = c->bufsoft;
1021 	int r;
1022 
1023 	CHN_LOCKASSERT(c);
1024 	if (CANCHANGE(c)) {
1025 		DEB(printf("want format %d\n", fmt));
1026 		c->format = fmt;
1027 		r = chn_buildfeeder(c);
1028 		if (r == 0) {
1029 			sndbuf_setfmt(bs, c->format);
1030 			chn_resetbuf(c);
1031 			r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
1032 			if (r == 0)
1033 				r = chn_tryspeed(c, c->speed);
1034 		}
1035 		return r;
1036 	} else
1037 		return EINVAL;
1038 }
1039 
1040 int
1041 chn_setformat(struct pcm_channel *c, u_int32_t fmt)
1042 {
1043 	u_int32_t oldfmt = c->format;
1044 	int r;
1045 
1046 	r = chn_tryformat(c, fmt);
1047 	if (r) {
1048 		DEB(printf("Format change %d failed, reverting to %d\n", fmt, oldfmt));
1049 		chn_tryformat(c, oldfmt);
1050 	}
1051 	return r;
1052 }
1053 
1054 /*
1055  * given a bufsz value, round it to a power of 2 in the min-max range
1056  * XXX only works if min and max are powers of 2
1057  */
1058 static int
1059 round_bufsz(int bufsz, int min, int max)
1060 {
1061 	int tmp = min * 2;
1062 
1063 	KASSERT((min & (min-1)) == 0, ("min %d must be power of 2\n", min));
1064 	KASSERT((max & (max-1)) == 0, ("max %d must be power of 2\n", max));
1065 	while (tmp <= bufsz)
1066 		tmp <<= 1;
1067 	tmp >>= 1;
1068 	if (tmp > max)
1069 		tmp = max;
1070 	return tmp;
1071 }
1072 
1073 /*
1074  * set the channel's blocksize both for soft and hard buffers.
1075  *
1076  * blksz should be a power of 2 between 2**4 and 2**16 -- it is useful
1077  * that it has the same value for both bufsoft and bufhard.
1078  * blksz == -1 computes values according to a target irq rate.
1079  * blksz == 0 reuses previous values if available, otherwise
1080  * behaves as for -1
1081  *
1082  * blkcnt is set by the user, between 2 and (2**17)/blksz for bufsoft,
1083  * but should be a power of 2 for bufhard to simplify life to low
1084  * level drivers.
1085  * Note, for the rec channel a large blkcnt is ok,
1086  * but for the play channel we want blksz as small as possible to keep
1087  * the delay small, because routines in the write path always try to
1088  * keep bufhard full.
1089  *
1090  * Unless we have good reason to, use the values suggested by the caller.
1091  */
1092 int
1093 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
1094 {
1095 	struct snd_dbuf *b = c->bufhard;
1096 	struct snd_dbuf *bs = c->bufsoft;
1097 	int irqhz, ret, maxsz, maxsize, reqblksz;
1098 
1099 	CHN_LOCKASSERT(c);
1100 	if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) {
1101 		KASSERT(sndbuf_getsize(bs) ==  0 ||
1102 		    sndbuf_getsize(bs) >= sndbuf_getsize(b),
1103 		    ("%s(%s): bufsoft size %d < bufhard size %d", __func__,
1104 		    c->name, sndbuf_getsize(bs), sndbuf_getsize(b)));
1105 		return EINVAL;
1106 	}
1107 	c->flags |= CHN_F_SETBLOCKSIZE;
1108 
1109 	ret = 0;
1110 	DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz));
1111 	if (blksz == 0 || blksz == -1) { /* let the driver choose values */
1112 		if (blksz == -1)	/* delete previous values */
1113 			c->flags &= ~CHN_F_HAS_SIZE;
1114 		if (!(c->flags & CHN_F_HAS_SIZE)) { /* no previous value */
1115 			/*
1116 			 * compute a base blksz according to the target irq
1117 			 * rate, then round to a suitable power of 2
1118 			 * in the range 16.. 2^17/2.
1119 			 * Finally compute a suitable blkcnt.
1120 			 */
1121 			blksz = round_bufsz( (sndbuf_getbps(bs) *
1122 				sndbuf_getspd(bs)) / chn_targetirqrate,
1123 				16, CHN_2NDBUFMAXSIZE / 2);
1124 			blkcnt = CHN_2NDBUFMAXSIZE / blksz;
1125 		} else { /* use previously defined value */
1126 			blkcnt = sndbuf_getblkcnt(bs);
1127 			blksz = sndbuf_getblksz(bs);
1128 		}
1129 	} else {
1130 		/*
1131 		 * use supplied values if reasonable. Note that here we
1132 		 * might have blksz which is not a power of 2 if the
1133 		 * ioctl() to compute it allows such values.
1134 		 */
1135 		ret = EINVAL;
1136 		if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE))
1137 			goto out;
1138 		ret = 0;
1139 		c->flags |= CHN_F_HAS_SIZE;
1140 	}
1141 
1142 	reqblksz = blksz;
1143 	if (reqblksz < sndbuf_getbps(bs))
1144 		reqblksz = sndbuf_getbps(bs);
1145 	if (reqblksz % sndbuf_getbps(bs))
1146 		reqblksz -= reqblksz % sndbuf_getbps(bs);
1147 
1148 	/* adjust for different hw format/speed */
1149 	/*
1150 	 * Now compute the approx irq rate for the given (soft) blksz,
1151 	 * reduce to the acceptable range and compute a corresponding blksz
1152 	 * for the hard buffer. Then set the channel's blocksize and
1153 	 * corresponding hardbuf value. The number of blocks used should
1154 	 * be set by the device-specific routine. In fact, even the
1155 	 * call to sndbuf_setblksz() should not be here! XXX
1156 	 */
1157 
1158 	irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / blksz;
1159 	RANGE(irqhz, 16, 512);
1160 
1161 	maxsz = sndbuf_getmaxsize(b);
1162 	if (maxsz == 0) /* virtual channels don't appear to allocate bufhard */
1163 		maxsz = CHN_2NDBUFMAXSIZE;
1164 	blksz = round_bufsz( (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz,
1165 			16, maxsz / 2);
1166 
1167 	/* Increase the size of bufsoft if before increasing bufhard. */
1168 	maxsize = sndbuf_getsize(b);
1169 	if (sndbuf_getsize(bs) > maxsize)
1170 		maxsize = sndbuf_getsize(bs);
1171 	if (reqblksz * blkcnt > maxsize)
1172 		maxsize = reqblksz * blkcnt;
1173 	if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) {
1174 		ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz);
1175 		if (ret)
1176 			goto out1;
1177 	}
1178 
1179 	CHN_UNLOCK(c);
1180 	sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz));
1181 	CHN_LOCK(c);
1182 
1183 	/* Decrease the size of bufsoft after decreasing bufhard. */
1184 	maxsize = sndbuf_getsize(b);
1185 	if (reqblksz * blkcnt > maxsize)
1186 		maxsize = reqblksz * blkcnt;
1187 	if (maxsize > sndbuf_getsize(bs))
1188 		printf("Danger! %s bufsoft size increasing from %d to %d after CHANNEL_SETBLOCKSIZE()\n",
1189 		    c->name, sndbuf_getsize(bs), maxsize);
1190 	if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) {
1191 		ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz);
1192 		if (ret)
1193 			goto out1;
1194 	}
1195 
1196 	chn_resetbuf(c);
1197 out1:
1198 	KASSERT(sndbuf_getsize(bs) ==  0 ||
1199 	    sndbuf_getsize(bs) >= sndbuf_getsize(b),
1200 	    ("%s(%s): bufsoft size %d < bufhard size %d, reqblksz=%d blksz=%d maxsize=%d blkcnt=%d",
1201 	    __func__, c->name, sndbuf_getsize(bs), sndbuf_getsize(b), reqblksz,
1202 	    blksz, maxsize, blkcnt));
1203 out:
1204 	c->flags &= ~CHN_F_SETBLOCKSIZE;
1205 #if 0
1206 	if (1) {
1207 		static uint32_t kk = 0;
1208 		printf("%u: b %d/%d/%d : (%d)%d/0x%0x | bs %d/%d/%d : (%d)%d/0x%0x\n", ++kk,
1209 			sndbuf_getsize(b), sndbuf_getblksz(b), sndbuf_getblkcnt(b),
1210 			sndbuf_getbps(b),
1211 			sndbuf_getspd(b), sndbuf_getfmt(b),
1212 			sndbuf_getsize(bs), sndbuf_getblksz(bs), sndbuf_getblkcnt(bs),
1213 			sndbuf_getbps(bs),
1214 			sndbuf_getspd(bs), sndbuf_getfmt(bs));
1215 		if (sndbuf_getsize(b) % sndbuf_getbps(b) ||
1216 				sndbuf_getblksz(b) % sndbuf_getbps(b) ||
1217 				sndbuf_getsize(bs) % sndbuf_getbps(bs) ||
1218 				sndbuf_getblksz(b) % sndbuf_getbps(b)) {
1219 			printf("%u: bps/blksz alignment screwed!\n", kk);
1220 		}
1221 	}
1222 #endif
1223 	return ret;
1224 }
1225 
1226 int
1227 chn_trigger(struct pcm_channel *c, int go)
1228 {
1229 #ifdef DEV_ISA
1230     	struct snd_dbuf *b = c->bufhard;
1231 #endif
1232 	int ret;
1233 
1234 	CHN_LOCKASSERT(c);
1235 #ifdef DEV_ISA
1236 	if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD))
1237 		sndbuf_dmabounce(b);
1238 #endif
1239 	ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
1240 
1241 	return ret;
1242 }
1243 
1244 int
1245 chn_getptr(struct pcm_channel *c)
1246 {
1247 	int hwptr;
1248 	int a = (1 << c->align) - 1;
1249 
1250 	CHN_LOCKASSERT(c);
1251 	hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1252 	/* don't allow unaligned values in the hwa ptr */
1253 #if 1
1254 	hwptr &= ~a ; /* Apply channel align mask */
1255 #endif
1256 	hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
1257 	return hwptr;
1258 }
1259 
1260 struct pcmchan_caps *
1261 chn_getcaps(struct pcm_channel *c)
1262 {
1263 	CHN_LOCKASSERT(c);
1264 	return CHANNEL_GETCAPS(c->methods, c->devinfo);
1265 }
1266 
1267 u_int32_t
1268 chn_getformats(struct pcm_channel *c)
1269 {
1270 	u_int32_t *fmtlist, fmts;
1271 	int i;
1272 
1273 	fmtlist = chn_getcaps(c)->fmtlist;
1274 	fmts = 0;
1275 	for (i = 0; fmtlist[i]; i++)
1276 		fmts |= fmtlist[i];
1277 
1278 	/* report software-supported formats */
1279 	if (report_soft_formats)
1280 		fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE|
1281 		    AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE|
1282 		    AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE|
1283 		    AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
1284 
1285 	return fmts;
1286 }
1287 
1288 static int
1289 chn_buildfeeder(struct pcm_channel *c)
1290 {
1291 	struct feeder_class *fc;
1292 	struct pcm_feederdesc desc;
1293 	u_int32_t tmp[2], type, flags, hwfmt, *fmtlist;
1294 	int err;
1295 
1296 	CHN_LOCKASSERT(c);
1297 	while (chn_removefeeder(c) == 0);
1298 	KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1299 
1300 	c->align = sndbuf_getalign(c->bufsoft);
1301 
1302 	if (SLIST_EMPTY(&c->children)) {
1303 		fc = feeder_getclass(NULL);
1304 		KASSERT(fc != NULL, ("can't find root feeder"));
1305 
1306 		err = chn_addfeeder(c, fc, NULL);
1307 		if (err) {
1308 			DEB(printf("can't add root feeder, err %d\n", err));
1309 
1310 			return err;
1311 		}
1312 		c->feeder->desc->out = c->format;
1313 	} else {
1314 		if (c->flags & CHN_F_HAS_VCHAN) {
1315 			desc.type = FEEDER_MIXER;
1316 			desc.in = 0;
1317 		} else {
1318 			DEB(printf("can't decide which feeder type to use!\n"));
1319 			return EOPNOTSUPP;
1320 		}
1321 		desc.out = c->format;
1322 		desc.flags = 0;
1323 		fc = feeder_getclass(&desc);
1324 		if (fc == NULL) {
1325 			DEB(printf("can't find vchan feeder\n"));
1326 
1327 			return EOPNOTSUPP;
1328 		}
1329 
1330 		err = chn_addfeeder(c, fc, &desc);
1331 		if (err) {
1332 			DEB(printf("can't add vchan feeder, err %d\n", err));
1333 
1334 			return err;
1335 		}
1336 	}
1337 	c->feederflags &= ~(1 << FEEDER_VOLUME);
1338 	if (c->direction == PCMDIR_PLAY &&
1339 			!(c->flags & CHN_F_VIRTUAL) &&
1340 			c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTVOL) &&
1341 			c->parentsnddev->mixer_dev)
1342 		c->feederflags |= 1 << FEEDER_VOLUME;
1343 	flags = c->feederflags;
1344 	fmtlist = chn_getcaps(c)->fmtlist;
1345 
1346 	DEB(printf("feederflags %x\n", flags));
1347 
1348 	for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) {
1349 		if (flags & (1 << type)) {
1350 			desc.type = type;
1351 			desc.in = 0;
1352 			desc.out = 0;
1353 			desc.flags = 0;
1354 			DEB(printf("find feeder type %d, ", type));
1355 			fc = feeder_getclass(&desc);
1356 			DEB(printf("got %p\n", fc));
1357 			if (fc == NULL) {
1358 				DEB(printf("can't find required feeder type %d\n", type));
1359 
1360 				return EOPNOTSUPP;
1361 			}
1362 
1363 			if ((type == FEEDER_RATE &&
1364 					!fmtvalid(fc->desc->in, fmtlist))
1365 					|| c->feeder->desc->out != fc->desc->in) {
1366  				DEB(printf("build fmtchain from 0x%x to 0x%x: ", c->feeder->desc->out, fc->desc->in));
1367 				tmp[0] = fc->desc->in;
1368 				tmp[1] = 0;
1369 				if (chn_fmtchain(c, tmp) == 0) {
1370 					DEB(printf("failed\n"));
1371 
1372 					return ENODEV;
1373 				}
1374  				DEB(printf("ok\n"));
1375 			}
1376 
1377 			err = chn_addfeeder(c, fc, fc->desc);
1378 			if (err) {
1379 				DEB(printf("can't add feeder %p, output 0x%x, err %d\n", fc, fc->desc->out, err));
1380 
1381 				return err;
1382 			}
1383 			DEB(printf("added feeder %p, output 0x%x\n", fc, c->feeder->desc->out));
1384 		}
1385 	}
1386 
1387 	if (fmtvalid(c->feeder->desc->out, fmtlist)
1388 			&& !(c->direction == PCMDIR_REC &&
1389 				c->format != c->feeder->desc->out))
1390 		hwfmt = c->feeder->desc->out;
1391 	else {
1392 		if (c->direction == PCMDIR_REC) {
1393 			tmp[0] = c->format;
1394 			tmp[1] = 0;
1395 			hwfmt = chn_fmtchain(c, tmp);
1396 		} else
1397 			hwfmt = chn_fmtchain(c, fmtlist);
1398 	}
1399 
1400 	if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) {
1401 		DEB(printf("Invalid hardware format: 0x%x\n", hwfmt));
1402 		return ENODEV;
1403 	}
1404 
1405 	sndbuf_setfmt(c->bufhard, hwfmt);
1406 
1407 	if ((flags & (1 << FEEDER_VOLUME))) {
1408 		int vol = 100 | (100 << 8);
1409 
1410 		CHN_UNLOCK(c);
1411 		/*
1412 		 * XXX This is ugly! The way mixer subs being so secretive
1413 		 * about its own internals force us to use this silly
1414 		 * monkey trick.
1415 		 */
1416 		if (mixer_ioctl(c->parentsnddev->mixer_dev,
1417 				MIXER_READ(SOUND_MIXER_PCM), (caddr_t)&vol, -1, NULL) != 0)
1418 			device_printf(c->dev, "Soft Volume: Failed to read default value\n");
1419 		CHN_LOCK(c);
1420 		chn_setvolume(c, vol & 0x7f, (vol >> 8) & 0x7f);
1421 	}
1422 
1423 	return 0;
1424 }
1425 
1426 int
1427 chn_notify(struct pcm_channel *c, u_int32_t flags)
1428 {
1429 	struct pcmchan_children *pce;
1430 	struct pcm_channel *child;
1431 	int run;
1432 
1433 	CHN_LOCK(c);
1434 
1435 	if (SLIST_EMPTY(&c->children)) {
1436 		CHN_UNLOCK(c);
1437 		return ENODEV;
1438 	}
1439 
1440 	run = (c->flags & CHN_F_TRIGGERED)? 1 : 0;
1441 	/*
1442 	 * if the hwchan is running, we can't change its rate, format or
1443 	 * blocksize
1444 	 */
1445 	if (run)
1446 		flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
1447 
1448 	if (flags & CHN_N_RATE) {
1449 		/*
1450 		 * we could do something here, like scan children and decide on
1451 		 * the most appropriate rate to mix at, but we don't for now
1452 		 */
1453 	}
1454 	if (flags & CHN_N_FORMAT) {
1455 		/*
1456 		 * we could do something here, like scan children and decide on
1457 		 * the most appropriate mixer feeder to use, but we don't for now
1458 		 */
1459 	}
1460 	if (flags & CHN_N_VOLUME) {
1461 		/*
1462 		 * we could do something here but we don't for now
1463 		 */
1464 	}
1465 	if (flags & CHN_N_BLOCKSIZE) {
1466 		int blksz;
1467 		/*
1468 		 * scan the children, find the lowest blocksize and use that
1469 		 * for the hard blocksize
1470 		 */
1471 		blksz = sndbuf_getmaxsize(c->bufhard) / 2;
1472 		SLIST_FOREACH(pce, &c->children, link) {
1473 			child = pce->channel;
1474 			CHN_LOCK(child);
1475 			if (sndbuf_getblksz(child->bufhard) < blksz)
1476 				blksz = sndbuf_getblksz(child->bufhard);
1477 			CHN_UNLOCK(child);
1478 		}
1479 		chn_setblocksize(c, 2, blksz);
1480 	}
1481 	if (flags & CHN_N_TRIGGER) {
1482 		int nrun;
1483 		/*
1484 		 * scan the children, and figure out if any are running
1485 		 * if so, we need to be running, otherwise we need to be stopped
1486 		 * if we aren't in our target sstate, move to it
1487 		 */
1488 		nrun = 0;
1489 		SLIST_FOREACH(pce, &c->children, link) {
1490 			child = pce->channel;
1491 			CHN_LOCK(child);
1492 			if (child->flags & CHN_F_TRIGGERED)
1493 				nrun = 1;
1494 			CHN_UNLOCK(child);
1495 		}
1496 		if (nrun && !run)
1497 			chn_start(c, 1);
1498 		if (!nrun && run)
1499 			chn_abort(c);
1500 	}
1501 	CHN_UNLOCK(c);
1502 	return 0;
1503 }
1504 
1505 void
1506 chn_lock(struct pcm_channel *c)
1507 {
1508 	CHN_LOCK(c);
1509 }
1510 
1511 void
1512 chn_unlock(struct pcm_channel *c)
1513 {
1514 	CHN_UNLOCK(c);
1515 }
1516