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