2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3 * Portions Copyright by Luigi Rizzo - 1997-99
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * $FreeBSD: src/sys/dev/sound/pcm/channel.c,v 1.19.2.19 2003/03/11 15:15:41 orion Exp $
28 * $DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.7 2005/06/10 23:07:01 dillon Exp $
31 #include <dev/sound/pcm/sound.h>
33 #include "feeder_if.h"
35 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.7 2005/06/10 23:07:01 dillon Exp $");
37 #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
38 #define DMA_ALIGN_THRESHOLD 4
39 #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1))
41 #define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED))
47 static int chn_targetirqrate = 32;
48 TUNABLE_INT("hw.snd.targetirqrate", &chn_targetirqrate);
51 sysctl_hw_snd_targetirqrate(SYSCTL_HANDLER_ARGS)
55 val = chn_targetirqrate;
56 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
57 if (val < 16 || val > 512)
60 chn_targetirqrate = val;
64 SYSCTL_PROC(_hw_snd, OID_AUTO, targetirqrate, CTLTYPE_INT | CTLFLAG_RW,
65 0, sizeof(int), sysctl_hw_snd_targetirqrate, "I", "");
66 static int report_soft_formats = 1;
67 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
68 &report_soft_formats, 1, "report software-emulated formats");
70 static int chn_buildfeeder(struct pcm_channel *c);
73 chn_lockinit(struct pcm_channel *c)
75 c->lock = snd_mtxcreate(c->name, "pcm channel");
79 chn_lockdestroy(struct pcm_channel *c)
85 chn_polltrigger(struct pcm_channel *c)
87 struct snd_dbuf *bs = c->bufsoft;
91 if (c->flags & CHN_F_MAPPED) {
92 if (sndbuf_getprevblocks(bs) == 0)
95 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
97 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
98 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
100 return (amt >= lim)? 1 : 0;
106 chn_pollreset(struct pcm_channel *c)
108 struct snd_dbuf *bs = c->bufsoft;
111 sndbuf_updateprevtotal(bs);
116 chn_wakeup(struct pcm_channel *c)
118 struct snd_dbuf *bs = c->bufsoft;
121 if (sndbuf_getsel(bs)->si_pid && chn_polltrigger(c))
122 selwakeup(sndbuf_getsel(bs));
127 chn_sleep(struct pcm_channel *c, char *str, int timeout)
129 struct snd_dbuf *bs = c->bufsoft;
134 ret = msleep(bs, c->lock, PCATCH, str, timeout);
136 ret = tsleep(bs, PCATCH, str, timeout);
143 * chn_dmaupdate() tracks the status of a dma transfer,
144 * updating pointers. It must be called from a critical section.
148 chn_dmaupdate(struct pcm_channel *c)
150 struct snd_dbuf *b = c->bufhard;
151 unsigned int delta, old, hwptr, amt;
153 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0"));
156 old = sndbuf_gethwptr(b);
157 hwptr = chn_getptr(c);
158 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b);
159 sndbuf_sethwptr(b, hwptr);
162 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) {
163 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING)))
164 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr);
168 if (c->direction == PCMDIR_PLAY) {
169 amt = MIN(delta, sndbuf_getready(b));
171 sndbuf_dispose(b, NULL, amt);
173 amt = MIN(delta, sndbuf_getfree(b));
175 sndbuf_acquire(b, NULL, amt);
182 chn_wrupdate(struct pcm_channel *c)
187 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
189 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED))
193 /* tell the driver we've updated the primary buffer */
194 chn_trigger(c, PCMTRIG_EMLDMAWR);
196 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
201 chn_wrfeed(struct pcm_channel *c)
203 struct snd_dbuf *b = c->bufhard;
204 struct snd_dbuf *bs = c->bufsoft;
205 unsigned int ret, amt;
209 if (c->flags & CHN_F_CLOSING) {
210 sndbuf_dump(b, "b", 0x02);
211 sndbuf_dump(bs, "bs", 0x02);
214 if (c->flags & CHN_F_MAPPED)
215 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
217 amt = sndbuf_getfree(b);
218 if (sndbuf_getready(bs) < amt)
221 ret = (amt > 0)? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
222 if (ret == 0 && sndbuf_getfree(b) < amt)
229 chn_wrintr(struct pcm_channel *c)
234 /* update pointers in primary buffer */
236 /* ...and feed from secondary to primary */
238 /* tell the driver we've updated the primary buffer */
239 chn_trigger(c, PCMTRIG_EMLDMAWR);
241 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
245 * user write routine - uiomove data into secondary buffer, trigger if necessary
246 * if blocking, sleep, rinse and repeat.
248 * called externally, so must handle locking
252 chn_write(struct pcm_channel *c, struct uio *buf)
254 int ret, timeout, newsize, count, sz;
255 struct snd_dbuf *bs = c->bufsoft;
259 * XXX Certain applications attempt to write larger size
260 * of pcm data than c->blocksize2nd without blocking,
261 * resulting partial write. Expand the block size so that
262 * the write operation avoids blocking.
264 if ((c->flags & CHN_F_NBIO) && buf->uio_resid > sndbuf_getblksz(bs)) {
265 DEB(device_printf(c->dev, "broken app, nbio and tried to write %d bytes with fragsz %d\n",
266 buf->uio_resid, sndbuf_getblksz(bs)));
268 while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2))
270 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize);
271 DEB(device_printf(c->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs)));
276 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
277 sz = sndbuf_getfree(bs);
279 if (c->flags & CHN_F_NBIO)
282 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
286 ret = chn_sleep(c, "pcmwr", timeout);
287 if (ret == EWOULDBLOCK) {
294 sz = MIN(sz, buf->uio_resid);
295 KASSERT(sz > 0, ("confusion in chn_write"));
296 /* printf("sz: %d\n", sz); */
297 ret = sndbuf_uiomove(bs, buf, sz);
298 if (ret == 0 && !(c->flags & CHN_F_TRIGGERED))
302 /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */
305 c->flags |= CHN_F_DEAD;
306 printf("%s: play interrupt timeout, channel dead\n", c->name);
313 chn_rddump(struct pcm_channel *c, unsigned int cnt)
315 struct snd_dbuf *b = c->bufhard;
318 sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt);
319 return sndbuf_dispose(b, NULL, cnt);
323 * Feed new data from the read buffer. Can be called in the bottom half.
324 * Hence must be called from a critical section.
327 chn_rdfeed(struct pcm_channel *c)
329 struct snd_dbuf *b = c->bufhard;
330 struct snd_dbuf *bs = c->bufsoft;
331 unsigned int ret, amt;
335 if (c->flags & CHN_F_CLOSING) {
336 sndbuf_dump(b, "b", 0x02);
337 sndbuf_dump(bs, "bs", 0x02);
340 amt = sndbuf_getready(b);
341 if (sndbuf_getfree(bs) < amt) {
343 amt = sndbuf_getfree(bs);
345 ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0;
347 amt = sndbuf_getready(b);
357 chn_rdupdate(struct pcm_channel *c)
362 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
364 if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED))
366 chn_trigger(c, PCMTRIG_EMLDMARD);
370 printf("chn_rdfeed: %d\n", ret);
374 /* read interrupt routine. Must be called with interrupts blocked. */
376 chn_rdintr(struct pcm_channel *c)
381 /* tell the driver to update the primary buffer if non-dma */
382 chn_trigger(c, PCMTRIG_EMLDMARD);
383 /* update pointers in primary buffer */
385 /* ...and feed from primary to secondary */
390 * user read routine - trigger if necessary, uiomove data from secondary buffer
391 * if blocking, sleep, rinse and repeat.
393 * called externally, so must handle locking
397 chn_read(struct pcm_channel *c, struct uio *buf)
399 int ret, timeout, sz, count;
400 struct snd_dbuf *bs = c->bufsoft;
403 if (!(c->flags & CHN_F_TRIGGERED))
408 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
409 sz = MIN(buf->uio_resid, sndbuf_getready(bs));
412 ret = sndbuf_uiomove(bs, buf, sz);
414 if (c->flags & CHN_F_NBIO) {
417 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
420 ret = chn_sleep(c, "pcmrd", timeout);
421 if (ret == EWOULDBLOCK) {
433 c->flags |= CHN_F_DEAD;
434 printf("%s: record interrupt timeout, channel dead\n", c->name);
441 chn_intr(struct pcm_channel *c)
445 if (c->direction == PCMDIR_PLAY)
453 chn_start(struct pcm_channel *c, int force)
456 struct snd_dbuf *b = c->bufhard;
457 struct snd_dbuf *bs = c->bufsoft;
460 /* if we're running, or if we're prevented from triggering, bail */
461 if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force))
464 i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs);
465 j = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(b) : sndbuf_getready(b);
466 if (force || (i >= j)) {
467 c->flags |= CHN_F_TRIGGERED;
469 * if we're starting because a vchan started, don't feed any data
470 * or it becomes impossible to start vchans synchronised with the
471 * first one. the hardbuf should be empty so we top it up with
472 * silence to give it something to chew. the real data will be
473 * fed at the first irq.
475 if (c->direction == PCMDIR_PLAY) {
476 if (SLIST_EMPTY(&c->children))
479 sndbuf_fillsilence(b);
483 chn_trigger(c, PCMTRIG_START);
491 chn_resetbuf(struct pcm_channel *c)
493 struct snd_dbuf *b = c->bufhard;
494 struct snd_dbuf *bs = c->bufsoft;
502 * chn_sync waits until the space in the given channel goes above
503 * a threshold. The threshold is checked against fl or rl respectively.
504 * Assume that the condition can become true, do not check here...
507 chn_sync(struct pcm_channel *c, int threshold)
511 struct snd_dbuf *bs = c->bufsoft;
515 rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
516 if (rdy <= threshold) {
517 ret = chn_sleep(c, "pcmsyn", 1);
518 if (ret == ERESTART || ret == EINTR) {
519 DEB(printf("chn_sync: tsleep returns %d\n", ret));
528 /* called externally, handle locking */
530 chn_poll(struct pcm_channel *c, int ev, struct proc *p)
532 struct snd_dbuf *bs = c->bufsoft;
536 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED))
539 if (chn_polltrigger(c) && chn_pollreset(c))
542 selrecord(p->p_thread, sndbuf_getsel(bs));
547 * chn_abort terminates a running dma transfer. it may sleep up to 200ms.
548 * it returns the number of bytes that have not been transferred.
550 * called from: dsp_close, dsp_ioctl, with channel locked
553 chn_abort(struct pcm_channel *c)
556 struct snd_dbuf *b = c->bufhard;
557 struct snd_dbuf *bs = c->bufsoft;
560 if (!(c->flags & CHN_F_TRIGGERED))
562 c->flags |= CHN_F_ABORTING;
564 c->flags &= ~CHN_F_TRIGGERED;
565 /* kill the channel */
566 chn_trigger(c, PCMTRIG_ABORT);
568 if (!(c->flags & CHN_F_VIRTUAL))
570 missing = sndbuf_getready(bs) + sndbuf_getready(b);
572 c->flags &= ~CHN_F_ABORTING;
577 * this routine tries to flush the dma transfer. It is called
578 * on a close. We immediately abort any read DMA
579 * operation, and then wait for the play buffer to drain.
581 * called from: dsp_close
585 chn_flush(struct pcm_channel *c)
587 int ret, count, resid, resid_p;
588 struct snd_dbuf *b = c->bufhard;
589 struct snd_dbuf *bs = c->bufsoft;
592 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
593 DEB(printf("chn_flush c->flags 0x%08x\n", c->flags));
594 if (!(c->flags & CHN_F_TRIGGERED))
597 c->flags |= CHN_F_CLOSING;
598 resid = sndbuf_getready(bs) + sndbuf_getready(b);
602 while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) {
603 /* still pending output data. */
604 ret = chn_sleep(c, "pcmflu", hz / 10);
605 if (ret == EWOULDBLOCK)
608 resid = sndbuf_getready(bs) + sndbuf_getready(b);
609 if (resid >= resid_p)
615 DEB(printf("chn_flush: timeout\n"));
617 c->flags &= ~CHN_F_TRIGGERED;
618 /* kill the channel */
619 chn_trigger(c, PCMTRIG_ABORT);
622 c->flags &= ~CHN_F_CLOSING;
627 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist)
631 for (i = 0; fmtlist[i]; i++)
632 if (fmt == fmtlist[i])
638 chn_reset(struct pcm_channel *c, u_int32_t fmt)
643 c->flags &= CHN_F_RESET;
647 r = CHANNEL_RESET(c->methods, c->devinfo);
649 hwspd = DSP_DEFAULT_SPEED;
650 /* only do this on a record channel until feederbuilder works */
651 if (c->direction == PCMDIR_REC)
652 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
656 r = chn_setformat(c, fmt);
658 r = chn_setspeed(c, hwspd);
660 r = chn_setvolume(c, 100, 100);
663 r = chn_setblocksize(c, 0, 0);
666 r = CHANNEL_RESETDONE(c->methods, c->devinfo);
672 chn_init(struct pcm_channel *c, void *devinfo, int dir)
674 struct feeder_class *fc;
675 struct snd_dbuf *b, *bs;
687 fc = feeder_getclass(NULL);
690 if (chn_addfeeder(c, fc, NULL))
694 b = sndbuf_create(c->dev, c->name, "primary");
697 bs = sndbuf_create(c->dev, c->name, "secondary");
700 sndbuf_setup(bs, NULL, 0);
707 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, dir);
708 if (c->devinfo == NULL)
712 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0))
715 ret = chn_setdir(c, dir);
719 ret = sndbuf_setfmt(b, AFMT_U8);
723 ret = sndbuf_setfmt(bs, AFMT_U8);
731 if (CHANNEL_FREE(c->methods, c->devinfo))
738 c->flags |= CHN_F_DEAD;
749 chn_kill(struct pcm_channel *c)
751 struct snd_dbuf *b = c->bufhard;
752 struct snd_dbuf *bs = c->bufsoft;
755 if (c->flags & CHN_F_TRIGGERED)
756 chn_trigger(c, PCMTRIG_ABORT);
757 while (chn_removefeeder(c) == 0);
758 if (CHANNEL_FREE(c->methods, c->devinfo))
760 c->flags |= CHN_F_DEAD;
768 chn_setdir(struct pcm_channel *c, int dir)
770 struct snd_dbuf *b = c->bufhard;
775 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction);
776 if (!r && ISA_DMA(b))
777 sndbuf_isadmasetdir(b, c->direction);
782 chn_setvolume(struct pcm_channel *c, int left, int right)
785 /* could add a feeder for volume changing if channel returns -1 */
786 c->volume = (left << 8) | right;
791 chn_tryspeed(struct pcm_channel *c, int speed)
793 struct pcm_feeder *f;
794 struct snd_dbuf *b = c->bufhard;
795 struct snd_dbuf *bs = c->bufsoft;
800 DEB(printf("setspeed, channel %s\n", c->name));
801 DEB(printf("want speed %d, ", speed));
807 sndbuf_setspd(bs, speed);
808 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
809 DEB(printf("try speed %d, ", speed));
810 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
811 DEB(printf("got speed %d\n", sndbuf_getspd(b)));
813 delta = sndbuf_getspd(b) - sndbuf_getspd(bs);
817 c->feederflags &= ~(1 << FEEDER_RATE);
819 c->feederflags |= 1 << FEEDER_RATE;
821 sndbuf_setspd(bs, sndbuf_getspd(b));
823 r = chn_buildfeeder(c);
824 DEB(printf("r = %d\n", r));
828 r = chn_setblocksize(c, 0, 0);
832 if (!(c->feederflags & (1 << FEEDER_RATE)))
836 f = chn_findfeeder(c, FEEDER_RATE);
837 DEB(printf("feedrate = %p\n", f));
841 x = (c->direction == PCMDIR_REC)? b : bs;
842 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x));
843 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r));
847 x = (c->direction == PCMDIR_REC)? bs : b;
848 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
849 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
851 DEB(printf("setspeed done, r = %d\n", r));
858 chn_setspeed(struct pcm_channel *c, int speed)
860 int r, oldspeed = c->speed;
862 r = chn_tryspeed(c, speed);
864 DEB(printf("Failed to set speed %d falling back to %d\n", speed, oldspeed));
865 r = chn_tryspeed(c, oldspeed);
871 chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
873 struct snd_dbuf *b = c->bufhard;
874 struct snd_dbuf *bs = c->bufsoft;
879 DEB(printf("want format %d\n", fmt));
881 r = chn_buildfeeder(c);
883 sndbuf_setfmt(bs, c->format);
885 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
887 r = chn_tryspeed(c, c->speed);
895 chn_setformat(struct pcm_channel *c, u_int32_t fmt)
897 u_int32_t oldfmt = c->format;
900 r = chn_tryformat(c, fmt);
902 DEB(printf("Format change %d failed, reverting to %d\n", fmt, oldfmt));
903 chn_tryformat(c, oldfmt);
909 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
911 struct snd_dbuf *b = c->bufhard;
912 struct snd_dbuf *bs = c->bufsoft;
913 int bufsz, irqhz, tmp, ret;
916 if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED))
920 DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz));
921 if (blksz == 0 || blksz == -1) {
923 c->flags &= ~CHN_F_HAS_SIZE;
924 if (!(c->flags & CHN_F_HAS_SIZE)) {
925 blksz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / chn_targetirqrate;
931 blkcnt = CHN_2NDBUFMAXSIZE / blksz;
933 RANGE(blksz, 16, CHN_2NDBUFMAXSIZE / 2);
934 RANGE(blkcnt, 2, CHN_2NDBUFMAXSIZE / blksz);
935 DEB(printf("%s: defaulting to (%d, %d)\n", __func__, blkcnt, blksz));
937 blkcnt = sndbuf_getblkcnt(bs);
938 blksz = sndbuf_getblksz(bs);
939 DEB(printf("%s: updating (%d, %d)\n", __func__, blkcnt, blksz));
943 if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE))
946 c->flags |= CHN_F_HAS_SIZE;
949 bufsz = blkcnt * blksz;
952 if (sndbuf_remalloc(bs, blkcnt, blksz))
956 /* adjust for different hw format/speed */
957 irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / sndbuf_getblksz(bs);
958 DEB(printf("%s: soft bps %d, spd %d, irqhz == %d\n", __func__, sndbuf_getbps(bs), sndbuf_getspd(bs), irqhz));
959 RANGE(irqhz, 16, 512);
961 sndbuf_setblksz(b, (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz);
963 /* round down to 2^x */
965 while (blksz <= sndbuf_getblksz(b))
969 /* round down to fit hw buffer size */
970 RANGE(blksz, 16, sndbuf_getmaxsize(b) / 2);
971 DEB(printf("%s: hard blksz requested %d (maxsize %d), ", __func__, blksz, sndbuf_getmaxsize(b)));
973 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz));
975 irqhz = (sndbuf_getbps(b) * sndbuf_getspd(b)) / sndbuf_getblksz(b);
976 DEB(printf("got %d, irqhz == %d\n", sndbuf_getblksz(b), irqhz));
984 chn_trigger(struct pcm_channel *c, int go)
986 struct snd_dbuf *b = c->bufhard;
990 if (ISA_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD))
991 sndbuf_isadmabounce(b);
992 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
998 chn_getptr(struct pcm_channel *c)
1001 int a = (1 << c->align) - 1;
1004 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1005 /* don't allow unaligned values in the hwa ptr */
1007 hwptr &= ~a ; /* Apply channel align mask */
1009 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
1013 struct pcmchan_caps *
1014 chn_getcaps(struct pcm_channel *c)
1017 return CHANNEL_GETCAPS(c->methods, c->devinfo);
1021 chn_getformats(struct pcm_channel *c)
1023 u_int32_t *fmtlist, fmts;
1026 fmtlist = chn_getcaps(c)->fmtlist;
1028 for (i = 0; fmtlist[i]; i++)
1031 /* report software-supported formats */
1032 if (report_soft_formats)
1033 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U16_LE|AFMT_U16_BE|
1034 AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
1040 chn_buildfeeder(struct pcm_channel *c)
1042 struct feeder_class *fc;
1043 struct pcm_feederdesc desc;
1044 u_int32_t tmp[2], type, flags, hwfmt;
1048 while (chn_removefeeder(c) == 0);
1049 KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1051 c->align = sndbuf_getalign(c->bufsoft);
1053 if (SLIST_EMPTY(&c->children)) {
1054 fc = feeder_getclass(NULL);
1055 KASSERT(fc != NULL, ("can't find root feeder"));
1057 err = chn_addfeeder(c, fc, NULL);
1059 DEB(printf("can't add root feeder, err %d\n", err));
1063 c->feeder->desc->out = c->format;
1065 desc.type = FEEDER_MIXER;
1067 desc.out = c->format;
1069 fc = feeder_getclass(&desc);
1071 DEB(printf("can't find vchan feeder\n"));
1076 err = chn_addfeeder(c, fc, &desc);
1078 DEB(printf("can't add vchan feeder, err %d\n", err));
1083 flags = c->feederflags;
1085 DEB(printf("not mapped, feederflags %x\n", flags));
1087 for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) {
1088 if (flags & (1 << type)) {
1093 DEB(printf("find feeder type %d, ", type));
1094 fc = feeder_getclass(&desc);
1095 DEB(printf("got %p\n", fc));
1097 DEB(printf("can't find required feeder type %d\n", type));
1102 if (c->feeder->desc->out != fc->desc->in) {
1103 DEB(printf("build fmtchain from %x to %x: ", c->feeder->desc->out, fc->desc->in));
1104 tmp[0] = fc->desc->in;
1106 if (chn_fmtchain(c, tmp) == 0) {
1107 DEB(printf("failed\n"));
1111 DEB(printf("ok\n"));
1114 err = chn_addfeeder(c, fc, fc->desc);
1116 DEB(printf("can't add feeder %p, output %x, err %d\n", fc, fc->desc->out, err));
1120 DEB(printf("added feeder %p, output %x\n", fc, c->feeder->desc->out));
1124 if (fmtvalid(c->feeder->desc->out, chn_getcaps(c)->fmtlist)) {
1125 hwfmt = c->feeder->desc->out;
1127 if (c->direction == PCMDIR_REC) {
1130 hwfmt = chn_fmtchain(c, tmp);
1132 hwfmt = chn_fmtchain(c, chn_getcaps(c)->fmtlist);
1139 sndbuf_setfmt(c->bufhard, hwfmt);
1145 chn_notify(struct pcm_channel *c, u_int32_t flags)
1147 struct pcmchan_children *pce;
1148 struct pcm_channel *child;
1151 if (SLIST_EMPTY(&c->children))
1154 run = (c->flags & CHN_F_TRIGGERED)? 1 : 0;
1156 * if the hwchan is running, we can't change its rate, format or
1160 flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
1162 if (flags & CHN_N_RATE) {
1164 * we could do something here, like scan children and decide on
1165 * the most appropriate rate to mix at, but we don't for now
1168 if (flags & CHN_N_FORMAT) {
1170 * we could do something here, like scan children and decide on
1171 * the most appropriate mixer feeder to use, but we don't for now
1174 if (flags & CHN_N_VOLUME) {
1176 * we could do something here but we don't for now
1179 if (flags & CHN_N_BLOCKSIZE) {
1182 * scan the children, find the lowest blocksize and use that
1183 * for the hard blocksize
1185 blksz = sndbuf_getmaxsize(c->bufhard) / 2;
1186 SLIST_FOREACH(pce, &c->children, link) {
1187 child = pce->channel;
1188 if (sndbuf_getblksz(child->bufhard) < blksz)
1189 blksz = sndbuf_getblksz(child->bufhard);
1191 chn_setblocksize(c, 2, blksz);
1193 if (flags & CHN_N_TRIGGER) {
1196 * scan the children, and figure out if any are running
1197 * if so, we need to be running, otherwise we need to be stopped
1198 * if we aren't in our target sstate, move to it
1201 SLIST_FOREACH(pce, &c->children, link) {
1202 child = pce->channel;
1203 if (child->flags & CHN_F_TRIGGERED)