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