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