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.9 2006/07/28 02:17:38 dillon Exp $
31 #include <dev/sound/pcm/sound.h>
32 #include <sys/vnode.h>
34 #include "feeder_if.h"
36 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.9 2006/07/28 02:17:38 dillon Exp $");
38 #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
39 #define DMA_ALIGN_THRESHOLD 4
40 #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1))
42 #define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED))
48 static int chn_targetirqrate = 32;
49 TUNABLE_INT("hw.snd.targetirqrate", &chn_targetirqrate);
52 sysctl_hw_snd_targetirqrate(SYSCTL_HANDLER_ARGS)
56 val = chn_targetirqrate;
57 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
58 if (val < 16 || val > 512)
61 chn_targetirqrate = val;
65 SYSCTL_PROC(_hw_snd, OID_AUTO, targetirqrate, CTLTYPE_INT | CTLFLAG_RW,
66 0, sizeof(int), sysctl_hw_snd_targetirqrate, "I", "");
67 static int report_soft_formats = 1;
68 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
69 &report_soft_formats, 1, "report software-emulated formats");
71 static int chn_buildfeeder(struct pcm_channel *c);
74 chn_lockinit(struct pcm_channel *c)
76 c->lock = snd_mtxcreate(c->name, "pcm channel");
80 chn_lockdestroy(struct pcm_channel *c)
86 chn_polltrigger(struct pcm_channel *c)
88 struct snd_dbuf *bs = c->bufsoft;
92 if (c->flags & CHN_F_MAPPED) {
93 if (sndbuf_getprevblocks(bs) == 0)
96 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
98 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
99 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
101 return (amt >= lim)? 1 : 0;
107 chn_pollreset(struct pcm_channel *c)
109 struct snd_dbuf *bs = c->bufsoft;
112 sndbuf_updateprevtotal(bs);
117 chn_wakeup(struct pcm_channel *c)
119 struct snd_dbuf *bs = c->bufsoft;
122 if (sndbuf_getsel(bs)->si_pid && chn_polltrigger(c))
123 selwakeup(sndbuf_getsel(bs));
128 chn_sleep(struct pcm_channel *c, char *str, int timeout)
130 struct snd_dbuf *bs = c->bufsoft;
135 ret = msleep(bs, c->lock, PCATCH, str, timeout);
137 ret = tsleep(bs, PCATCH, str, timeout);
144 * chn_dmaupdate() tracks the status of a dma transfer,
145 * updating pointers. It must be called from a critical section.
149 chn_dmaupdate(struct pcm_channel *c)
151 struct snd_dbuf *b = c->bufhard;
152 unsigned int delta, old, hwptr, amt;
154 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0"));
157 old = sndbuf_gethwptr(b);
158 hwptr = chn_getptr(c);
159 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b);
160 sndbuf_sethwptr(b, hwptr);
163 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) {
164 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING)))
165 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr);
169 if (c->direction == PCMDIR_PLAY) {
170 amt = MIN(delta, sndbuf_getready(b));
172 sndbuf_dispose(b, NULL, amt);
174 amt = MIN(delta, sndbuf_getfree(b));
176 sndbuf_acquire(b, NULL, amt);
183 chn_wrupdate(struct pcm_channel *c)
188 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
190 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED))
194 /* tell the driver we've updated the primary buffer */
195 chn_trigger(c, PCMTRIG_EMLDMAWR);
197 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
202 chn_wrfeed(struct pcm_channel *c)
204 struct snd_dbuf *b = c->bufhard;
205 struct snd_dbuf *bs = c->bufsoft;
206 unsigned int ret, amt;
210 if (c->flags & CHN_F_CLOSING) {
211 sndbuf_dump(b, "b", 0x02);
212 sndbuf_dump(bs, "bs", 0x02);
215 if (c->flags & CHN_F_MAPPED)
216 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
218 amt = sndbuf_getfree(b);
219 if (sndbuf_getready(bs) < amt)
222 ret = (amt > 0)? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
223 if (ret == 0 && sndbuf_getfree(b) < amt)
230 chn_wrintr(struct pcm_channel *c)
235 /* update pointers in primary buffer */
237 /* ...and feed from secondary to primary */
239 /* tell the driver we've updated the primary buffer */
240 chn_trigger(c, PCMTRIG_EMLDMAWR);
242 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
246 * user write routine - uiomove data into secondary buffer, trigger if necessary
247 * if blocking, sleep, rinse and repeat.
249 * called externally, so must handle locking
253 chn_write(struct pcm_channel *c, struct uio *buf, int ioflags)
255 int ret, timeout, newsize, count, sz;
257 struct snd_dbuf *bs = c->bufsoft;
260 nbio = (c->flags & CHN_F_NBIO) || (ioflags & IO_NDELAY);
262 * XXX Certain applications attempt to write larger size
263 * of pcm data than c->blocksize2nd without blocking,
264 * resulting partial write. Expand the block size so that
265 * the write operation avoids blocking.
267 if (nbio && buf->uio_resid > sndbuf_getblksz(bs)) {
268 DEB(device_printf(c->dev, "broken app, nbio and tried to write %d bytes with fragsz %d\n",
269 buf->uio_resid, sndbuf_getblksz(bs)));
271 while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2))
273 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize);
274 DEB(device_printf(c->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs)));
279 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
280 sz = sndbuf_getfree(bs);
285 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
289 ret = chn_sleep(c, "pcmwr", timeout);
290 if (ret == EWOULDBLOCK) {
297 sz = MIN(sz, buf->uio_resid);
298 KASSERT(sz > 0, ("confusion in chn_write"));
299 /* printf("sz: %d\n", sz); */
300 ret = sndbuf_uiomove(bs, buf, sz);
301 if (ret == 0 && !(c->flags & CHN_F_TRIGGERED))
305 /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */
308 c->flags |= CHN_F_DEAD;
309 printf("%s: play interrupt timeout, channel dead\n", c->name);
316 chn_rddump(struct pcm_channel *c, unsigned int cnt)
318 struct snd_dbuf *b = c->bufhard;
321 sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt);
322 return sndbuf_dispose(b, NULL, cnt);
326 * Feed new data from the read buffer. Can be called in the bottom half.
327 * Hence must be called from a critical section.
330 chn_rdfeed(struct pcm_channel *c)
332 struct snd_dbuf *b = c->bufhard;
333 struct snd_dbuf *bs = c->bufsoft;
334 unsigned int ret, amt;
338 if (c->flags & CHN_F_CLOSING) {
339 sndbuf_dump(b, "b", 0x02);
340 sndbuf_dump(bs, "bs", 0x02);
343 amt = sndbuf_getready(b);
344 if (sndbuf_getfree(bs) < amt) {
346 amt = sndbuf_getfree(bs);
348 ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0;
350 amt = sndbuf_getready(b);
360 chn_rdupdate(struct pcm_channel *c)
365 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
367 if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED))
369 chn_trigger(c, PCMTRIG_EMLDMARD);
373 printf("chn_rdfeed: %d\n", ret);
377 /* read interrupt routine. Must be called with interrupts blocked. */
379 chn_rdintr(struct pcm_channel *c)
384 /* tell the driver to update the primary buffer if non-dma */
385 chn_trigger(c, PCMTRIG_EMLDMARD);
386 /* update pointers in primary buffer */
388 /* ...and feed from primary to secondary */
393 * user read routine - trigger if necessary, uiomove data from secondary buffer
394 * if blocking, sleep, rinse and repeat.
396 * called externally, so must handle locking
400 chn_read(struct pcm_channel *c, struct uio *buf, int ioflags)
402 int ret, timeout, sz, count;
404 struct snd_dbuf *bs = c->bufsoft;
407 if (!(c->flags & CHN_F_TRIGGERED))
410 nbio = (c->flags & CHN_F_NBIO) || (ioflags & IO_NDELAY);
413 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
414 sz = MIN(buf->uio_resid, sndbuf_getready(bs));
417 ret = sndbuf_uiomove(bs, buf, sz);
422 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
425 ret = chn_sleep(c, "pcmrd", timeout);
426 if (ret == EWOULDBLOCK) {
438 c->flags |= CHN_F_DEAD;
439 printf("%s: record interrupt timeout, channel dead\n", c->name);
446 chn_intr(struct pcm_channel *c)
450 if (c->direction == PCMDIR_PLAY)
458 chn_start(struct pcm_channel *c, int force)
461 struct snd_dbuf *b = c->bufhard;
462 struct snd_dbuf *bs = c->bufsoft;
465 /* if we're running, or if we're prevented from triggering, bail */
466 if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force))
469 i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs);
470 j = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(b) : sndbuf_getready(b);
471 if (force || (i >= j)) {
472 c->flags |= CHN_F_TRIGGERED;
474 * if we're starting because a vchan started, don't feed any data
475 * or it becomes impossible to start vchans synchronised with the
476 * first one. the hardbuf should be empty so we top it up with
477 * silence to give it something to chew. the real data will be
478 * fed at the first irq.
480 if (c->direction == PCMDIR_PLAY) {
481 if (SLIST_EMPTY(&c->children))
484 sndbuf_fillsilence(b);
488 chn_trigger(c, PCMTRIG_START);
496 chn_resetbuf(struct pcm_channel *c)
498 struct snd_dbuf *b = c->bufhard;
499 struct snd_dbuf *bs = c->bufsoft;
507 * chn_sync waits until the space in the given channel goes above
508 * a threshold. The threshold is checked against fl or rl respectively.
509 * Assume that the condition can become true, do not check here...
512 chn_sync(struct pcm_channel *c, int threshold)
516 struct snd_dbuf *bs = c->bufsoft;
520 rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
521 if (rdy <= threshold) {
522 ret = chn_sleep(c, "pcmsyn", 1);
523 if (ret == ERESTART || ret == EINTR) {
524 DEB(printf("chn_sync: tsleep returns %d\n", ret));
533 /* called externally, handle locking */
535 chn_poll(struct pcm_channel *c, int ev)
537 struct snd_dbuf *bs = c->bufsoft;
541 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED))
544 if (chn_polltrigger(c) && chn_pollreset(c))
547 selrecord(curthread, sndbuf_getsel(bs));
552 * chn_abort terminates a running dma transfer. it may sleep up to 200ms.
553 * it returns the number of bytes that have not been transferred.
555 * called from: dsp_close, dsp_ioctl, with channel locked
558 chn_abort(struct pcm_channel *c)
561 struct snd_dbuf *b = c->bufhard;
562 struct snd_dbuf *bs = c->bufsoft;
565 if (!(c->flags & CHN_F_TRIGGERED))
567 c->flags |= CHN_F_ABORTING;
569 c->flags &= ~CHN_F_TRIGGERED;
570 /* kill the channel */
571 chn_trigger(c, PCMTRIG_ABORT);
573 if (!(c->flags & CHN_F_VIRTUAL))
575 missing = sndbuf_getready(bs) + sndbuf_getready(b);
577 c->flags &= ~CHN_F_ABORTING;
582 * this routine tries to flush the dma transfer. It is called
583 * on a close. We immediately abort any read DMA
584 * operation, and then wait for the play buffer to drain.
586 * called from: dsp_close
590 chn_flush(struct pcm_channel *c)
592 int ret, count, resid, resid_p;
593 struct snd_dbuf *b = c->bufhard;
594 struct snd_dbuf *bs = c->bufsoft;
597 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
598 DEB(printf("chn_flush c->flags 0x%08x\n", c->flags));
599 if (!(c->flags & CHN_F_TRIGGERED))
602 c->flags |= CHN_F_CLOSING;
603 resid = sndbuf_getready(bs) + sndbuf_getready(b);
607 while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) {
608 /* still pending output data. */
609 ret = chn_sleep(c, "pcmflu", hz / 10);
610 if (ret == EWOULDBLOCK)
613 resid = sndbuf_getready(bs) + sndbuf_getready(b);
614 if (resid >= resid_p)
620 DEB(printf("chn_flush: timeout\n"));
622 c->flags &= ~CHN_F_TRIGGERED;
623 /* kill the channel */
624 chn_trigger(c, PCMTRIG_ABORT);
627 c->flags &= ~CHN_F_CLOSING;
632 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist)
636 for (i = 0; fmtlist[i]; i++)
637 if (fmt == fmtlist[i])
643 chn_reset(struct pcm_channel *c, u_int32_t fmt)
648 c->flags &= CHN_F_RESET;
652 r = CHANNEL_RESET(c->methods, c->devinfo);
654 hwspd = DSP_DEFAULT_SPEED;
655 /* only do this on a record channel until feederbuilder works */
656 if (c->direction == PCMDIR_REC)
657 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
661 r = chn_setformat(c, fmt);
663 r = chn_setspeed(c, hwspd);
665 r = chn_setvolume(c, 100, 100);
668 r = chn_setblocksize(c, 0, 0);
671 r = CHANNEL_RESETDONE(c->methods, c->devinfo);
677 chn_init(struct pcm_channel *c, void *devinfo, int dir)
679 struct feeder_class *fc;
680 struct snd_dbuf *b, *bs;
692 fc = feeder_getclass(NULL);
695 if (chn_addfeeder(c, fc, NULL))
699 b = sndbuf_create(c->dev, c->name, "primary");
702 bs = sndbuf_create(c->dev, c->name, "secondary");
705 sndbuf_setup(bs, NULL, 0);
712 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, dir);
713 if (c->devinfo == NULL)
717 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0))
720 ret = chn_setdir(c, dir);
724 ret = sndbuf_setfmt(b, AFMT_U8);
728 ret = sndbuf_setfmt(bs, AFMT_U8);
736 if (CHANNEL_FREE(c->methods, c->devinfo))
743 c->flags |= CHN_F_DEAD;
754 chn_kill(struct pcm_channel *c)
756 struct snd_dbuf *b = c->bufhard;
757 struct snd_dbuf *bs = c->bufsoft;
760 if (c->flags & CHN_F_TRIGGERED)
761 chn_trigger(c, PCMTRIG_ABORT);
762 while (chn_removefeeder(c) == 0);
763 if (CHANNEL_FREE(c->methods, c->devinfo))
765 c->flags |= CHN_F_DEAD;
773 chn_setdir(struct pcm_channel *c, int dir)
775 struct snd_dbuf *b = c->bufhard;
780 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction);
781 if (!r && ISA_DMA(b))
782 sndbuf_isadmasetdir(b, c->direction);
787 chn_setvolume(struct pcm_channel *c, int left, int right)
790 /* could add a feeder for volume changing if channel returns -1 */
791 c->volume = (left << 8) | right;
796 chn_tryspeed(struct pcm_channel *c, int speed)
798 struct pcm_feeder *f;
799 struct snd_dbuf *b = c->bufhard;
800 struct snd_dbuf *bs = c->bufsoft;
805 DEB(printf("setspeed, channel %s\n", c->name));
806 DEB(printf("want speed %d, ", speed));
812 sndbuf_setspd(bs, speed);
813 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
814 DEB(printf("try speed %d, ", speed));
815 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
816 DEB(printf("got speed %d\n", sndbuf_getspd(b)));
818 delta = sndbuf_getspd(b) - sndbuf_getspd(bs);
822 c->feederflags &= ~(1 << FEEDER_RATE);
824 c->feederflags |= 1 << FEEDER_RATE;
826 sndbuf_setspd(bs, sndbuf_getspd(b));
828 r = chn_buildfeeder(c);
829 DEB(printf("r = %d\n", r));
833 r = chn_setblocksize(c, 0, 0);
837 if (!(c->feederflags & (1 << FEEDER_RATE)))
841 f = chn_findfeeder(c, FEEDER_RATE);
842 DEB(printf("feedrate = %p\n", f));
846 x = (c->direction == PCMDIR_REC)? b : bs;
847 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x));
848 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r));
852 x = (c->direction == PCMDIR_REC)? bs : b;
853 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
854 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
856 DEB(printf("setspeed done, r = %d\n", r));
863 chn_setspeed(struct pcm_channel *c, int speed)
865 int r, oldspeed = c->speed;
867 r = chn_tryspeed(c, speed);
869 DEB(printf("Failed to set speed %d falling back to %d\n", speed, oldspeed));
870 r = chn_tryspeed(c, oldspeed);
876 chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
878 struct snd_dbuf *b = c->bufhard;
879 struct snd_dbuf *bs = c->bufsoft;
884 DEB(printf("want format %d\n", fmt));
886 r = chn_buildfeeder(c);
888 sndbuf_setfmt(bs, c->format);
890 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
892 r = chn_tryspeed(c, c->speed);
900 chn_setformat(struct pcm_channel *c, u_int32_t fmt)
902 u_int32_t oldfmt = c->format;
905 r = chn_tryformat(c, fmt);
907 DEB(printf("Format change %d failed, reverting to %d\n", fmt, oldfmt));
908 chn_tryformat(c, oldfmt);
914 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
916 struct snd_dbuf *b = c->bufhard;
917 struct snd_dbuf *bs = c->bufsoft;
918 int bufsz, irqhz, tmp, ret;
921 if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED))
925 DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz));
926 if (blksz == 0 || blksz == -1) {
928 c->flags &= ~CHN_F_HAS_SIZE;
929 if (!(c->flags & CHN_F_HAS_SIZE)) {
930 blksz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / chn_targetirqrate;
936 blkcnt = CHN_2NDBUFMAXSIZE / blksz;
938 RANGE(blksz, 16, CHN_2NDBUFMAXSIZE / 2);
939 RANGE(blkcnt, 2, CHN_2NDBUFMAXSIZE / blksz);
940 DEB(printf("%s: defaulting to (%d, %d)\n", __func__, blkcnt, blksz));
942 blkcnt = sndbuf_getblkcnt(bs);
943 blksz = sndbuf_getblksz(bs);
944 DEB(printf("%s: updating (%d, %d)\n", __func__, blkcnt, blksz));
948 if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE))
951 c->flags |= CHN_F_HAS_SIZE;
954 bufsz = blkcnt * blksz;
957 if (sndbuf_remalloc(bs, blkcnt, blksz))
961 /* adjust for different hw format/speed */
962 irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / sndbuf_getblksz(bs);
963 DEB(printf("%s: soft bps %d, spd %d, irqhz == %d\n", __func__, sndbuf_getbps(bs), sndbuf_getspd(bs), irqhz));
964 RANGE(irqhz, 16, 512);
966 sndbuf_setblksz(b, (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz);
968 /* round down to 2^x */
970 while (blksz <= sndbuf_getblksz(b))
974 /* round down to fit hw buffer size */
975 RANGE(blksz, 16, sndbuf_getmaxsize(b) / 2);
976 DEB(printf("%s: hard blksz requested %d (maxsize %d), ", __func__, blksz, sndbuf_getmaxsize(b)));
978 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz));
980 irqhz = (sndbuf_getbps(b) * sndbuf_getspd(b)) / sndbuf_getblksz(b);
981 DEB(printf("got %d, irqhz == %d\n", sndbuf_getblksz(b), irqhz));
989 chn_trigger(struct pcm_channel *c, int go)
991 struct snd_dbuf *b = c->bufhard;
995 if (ISA_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD))
996 sndbuf_isadmabounce(b);
997 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
1003 chn_getptr(struct pcm_channel *c)
1006 int a = (1 << c->align) - 1;
1009 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1010 /* don't allow unaligned values in the hwa ptr */
1012 hwptr &= ~a ; /* Apply channel align mask */
1014 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
1018 struct pcmchan_caps *
1019 chn_getcaps(struct pcm_channel *c)
1022 return CHANNEL_GETCAPS(c->methods, c->devinfo);
1026 chn_getformats(struct pcm_channel *c)
1028 u_int32_t *fmtlist, fmts;
1031 fmtlist = chn_getcaps(c)->fmtlist;
1033 for (i = 0; fmtlist[i]; i++)
1036 /* report software-supported formats */
1037 if (report_soft_formats)
1038 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U16_LE|AFMT_U16_BE|
1039 AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
1045 chn_buildfeeder(struct pcm_channel *c)
1047 struct feeder_class *fc;
1048 struct pcm_feederdesc desc;
1049 u_int32_t tmp[2], type, flags, hwfmt;
1053 while (chn_removefeeder(c) == 0);
1054 KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1056 c->align = sndbuf_getalign(c->bufsoft);
1058 if (SLIST_EMPTY(&c->children)) {
1059 fc = feeder_getclass(NULL);
1060 KASSERT(fc != NULL, ("can't find root feeder"));
1062 err = chn_addfeeder(c, fc, NULL);
1064 DEB(printf("can't add root feeder, err %d\n", err));
1068 c->feeder->desc->out = c->format;
1070 desc.type = FEEDER_MIXER;
1072 desc.out = c->format;
1074 fc = feeder_getclass(&desc);
1076 DEB(printf("can't find vchan feeder\n"));
1081 err = chn_addfeeder(c, fc, &desc);
1083 DEB(printf("can't add vchan feeder, err %d\n", err));
1088 flags = c->feederflags;
1090 DEB(printf("not mapped, feederflags %x\n", flags));
1092 for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) {
1093 if (flags & (1 << type)) {
1098 DEB(printf("find feeder type %d, ", type));
1099 fc = feeder_getclass(&desc);
1100 DEB(printf("got %p\n", fc));
1102 DEB(printf("can't find required feeder type %d\n", type));
1107 if (c->feeder->desc->out != fc->desc->in) {
1108 DEB(printf("build fmtchain from %x to %x: ", c->feeder->desc->out, fc->desc->in));
1109 tmp[0] = fc->desc->in;
1111 if (chn_fmtchain(c, tmp) == 0) {
1112 DEB(printf("failed\n"));
1116 DEB(printf("ok\n"));
1119 err = chn_addfeeder(c, fc, fc->desc);
1121 DEB(printf("can't add feeder %p, output %x, err %d\n", fc, fc->desc->out, err));
1125 DEB(printf("added feeder %p, output %x\n", fc, c->feeder->desc->out));
1129 if (fmtvalid(c->feeder->desc->out, chn_getcaps(c)->fmtlist)) {
1130 hwfmt = c->feeder->desc->out;
1132 if (c->direction == PCMDIR_REC) {
1135 hwfmt = chn_fmtchain(c, tmp);
1137 hwfmt = chn_fmtchain(c, chn_getcaps(c)->fmtlist);
1144 sndbuf_setfmt(c->bufhard, hwfmt);
1150 chn_notify(struct pcm_channel *c, u_int32_t flags)
1152 struct pcmchan_children *pce;
1153 struct pcm_channel *child;
1156 if (SLIST_EMPTY(&c->children))
1159 run = (c->flags & CHN_F_TRIGGERED)? 1 : 0;
1161 * if the hwchan is running, we can't change its rate, format or
1165 flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
1167 if (flags & CHN_N_RATE) {
1169 * we could do something here, like scan children and decide on
1170 * the most appropriate rate to mix at, but we don't for now
1173 if (flags & CHN_N_FORMAT) {
1175 * we could do something here, like scan children and decide on
1176 * the most appropriate mixer feeder to use, but we don't for now
1179 if (flags & CHN_N_VOLUME) {
1181 * we could do something here but we don't for now
1184 if (flags & CHN_N_BLOCKSIZE) {
1187 * scan the children, find the lowest blocksize and use that
1188 * for the hard blocksize
1190 blksz = sndbuf_getmaxsize(c->bufhard) / 2;
1191 SLIST_FOREACH(pce, &c->children, link) {
1192 child = pce->channel;
1193 if (sndbuf_getblksz(child->bufhard) < blksz)
1194 blksz = sndbuf_getblksz(child->bufhard);
1196 chn_setblocksize(c, 2, blksz);
1198 if (flags & CHN_N_TRIGGER) {
1201 * scan the children, and figure out if any are running
1202 * if so, we need to be running, otherwise we need to be stopped
1203 * if we aren't in our target sstate, move to it
1206 SLIST_FOREACH(pce, &c->children, link) {
1207 child = pce->channel;
1208 if (child->flags & CHN_F_TRIGGERED)