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