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