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