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