Deleted Added
sdiff udiff text old ( 168243 ) new ( 170161 )
full compact
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:

--- 17 unchanged lines hidden (view full) ---

26 */
27
28#include "opt_isa.h"
29
30#include <dev/sound/pcm/sound.h>
31
32#include "feeder_if.h"
33
34SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/channel.c 170161 2007-05-31 18:43:33Z ariff $");
35
36#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
37#if 0
38#define DMA_ALIGN_THRESHOLD 4
39#define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1))
40#endif
41
42#define CHN_STARTED(c) ((c)->flags & CHN_F_TRIGGERED)

--- 122 unchanged lines hidden (view full) ---

165
166static void
167chn_lockinit(struct pcm_channel *c, int dir)
168{
169 switch(dir) {
170 case PCMDIR_PLAY:
171 c->lock = snd_mtxcreate(c->name, "pcm play channel");
172 break;
173 case PCMDIR_PLAY_VIRTUAL:
174 c->lock = snd_mtxcreate(c->name, "pcm virtual play channel");
175 break;
176 case PCMDIR_REC:
177 c->lock = snd_mtxcreate(c->name, "pcm record channel");
178 break;
179 case PCMDIR_REC_VIRTUAL:
180 c->lock = snd_mtxcreate(c->name, "pcm virtual record channel");
181 break;
182 case 0:
183 c->lock = snd_mtxcreate(c->name, "pcm fake channel");
184 break;
185 }
186
187 cv_init(&c->cv, c->name);
188}

--- 43 unchanged lines hidden (view full) ---

232 sndbuf_updateprevtotal(bs);
233 return 1;
234}
235
236static void
237chn_wakeup(struct pcm_channel *c)
238{
239 struct snd_dbuf *bs = c->bufsoft;
240 struct pcm_channel *ch;
241
242 CHN_LOCKASSERT(c);
243 if (CHN_EMPTY(c, children)) {
244 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
245 selwakeuppri(sndbuf_getsel(bs), PRIBIO);
246 } else if (CHN_EMPTY(c, children.busy)) {
247 CHN_FOREACH(ch, c, children) {
248 CHN_LOCK(ch);
249 chn_wakeup(ch);
250 CHN_UNLOCK(ch);
251 }
252 } else {
253 CHN_FOREACH(ch, c, children.busy) {
254 CHN_LOCK(ch);
255 chn_wakeup(ch);
256 CHN_UNLOCK(ch);
257 }
258 }
259 if (c->flags & CHN_F_SLEEPING)
260 wakeup_one(bs);
261}
262
263static int
264chn_sleep(struct pcm_channel *c, char *str, int timeout)
265{
266 struct snd_dbuf *bs = c->bufsoft;
267 int ret;
268
269 CHN_LOCKASSERT(c);
270
271 c->flags |= CHN_F_SLEEPING;
272#ifdef USING_MUTEX
273 ret = msleep(bs, c->lock, PRIBIO | PCATCH, str, timeout);
274#else
275 ret = tsleep(bs, PRIBIO | PCATCH, str, timeout);
276#endif
277 c->flags &= ~CHN_F_SLEEPING;
278
279 return ret;
280}
281
282/*
283 * chn_dmaupdate() tracks the status of a dma transfer,
284 * updating pointers.
285 */

--- 219 unchanged lines hidden (view full) ---

505#if 0
506 amt = sndbuf_getready(b);
507 if (sndbuf_getfree(bs) < amt) {
508 c->xruns++;
509 amt = sndbuf_getfree(bs);
510 }
511#endif
512 amt = sndbuf_getfree(bs);
513 ret = (amt > 0) ? sndbuf_feed(b, bs, c, c->feeder, amt) : ENOSPC;
514
515 amt = sndbuf_getready(b);
516 if (amt > 0) {
517 c->xruns++;
518 sndbuf_dispose(b, NULL, amt);
519 }
520
521 if (sndbuf_getready(bs) > 0)

--- 5 unchanged lines hidden (view full) ---

527void
528chn_rdupdate(struct pcm_channel *c)
529{
530 int ret;
531
532 CHN_LOCKASSERT(c);
533 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
534
535 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
536 return;
537 chn_trigger(c, PCMTRIG_EMLDMARD);
538 chn_dmaupdate(c);
539 ret = chn_rdfeed(c);
540 DEB(if (ret)
541 printf("chn_rdfeed: %d\n", ret);)
542
543}

--- 109 unchanged lines hidden (view full) ---

653 } else {
654 struct snd_dbuf *pb;
655
656 pb = BUF_PARENT(c, b);
657 i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb);
658 j = sndbuf_getbps(pb);
659 }
660 }
661 if (snd_verbose > 3 && CHN_EMPTY(c, children))
662 printf("%s: %s (%s) threshold i=%d j=%d\n",
663 __func__, CHN_DIRSTR(c),
664 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
665 i, j);
666 }
667
668 if (i >= j) {
669 c->flags |= CHN_F_TRIGGERED;

--- 432 unchanged lines hidden (view full) ---

1102
1103 if (chn_timeout < CHN_TIMEOUT_MIN || chn_timeout > CHN_TIMEOUT_MAX)
1104 chn_timeout = CHN_TIMEOUT;
1105
1106 chn_lockinit(c, dir);
1107
1108 b = NULL;
1109 bs = NULL;
1110 CHN_INIT(c, children);
1111 CHN_INIT(c, children.busy);
1112 c->devinfo = NULL;
1113 c->feeder = NULL;
1114 c->latency = -1;
1115 c->timeout = 1;
1116
1117 ret = ENOMEM;
1118 b = sndbuf_create(c->dev, c->name, "primary", c);
1119 if (b == NULL)

--- 83 unchanged lines hidden (view full) ---

1203}
1204
1205int
1206chn_kill(struct pcm_channel *c)
1207{
1208 struct snd_dbuf *b = c->bufhard;
1209 struct snd_dbuf *bs = c->bufsoft;
1210
1211 if (CHN_STARTED(c)) {
1212 CHN_LOCK(c);
1213 chn_trigger(c, PCMTRIG_ABORT);
1214 CHN_UNLOCK(c);
1215 }
1216 while (chn_removefeeder(c) == 0)
1217 ;
1218 if (CHANNEL_FREE(c->methods, c->devinfo))
1219 sndbuf_free(b);
1220 c->flags |= CHN_F_DEAD;
1221 sndbuf_destroy(bs);
1222 sndbuf_destroy(b);
1223 chn_lockdestroy(c);
1224 return 0;
1225}

--- 316 unchanged lines hidden (view full) ---

1542 CHN_UNLOCK(c);
1543 if (chn_usefrags == 0 ||
1544 CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
1545 hblksz, hblkcnt) < 1)
1546 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
1547 c->devinfo, hblksz));
1548 CHN_LOCK(c);
1549
1550 if (!CHN_EMPTY(c, children)) {
1551 sblksz = round_blksz(
1552 sndbuf_xbytes(sndbuf_getsize(b) >> 1, b, bs),
1553 sndbuf_getbps(bs));
1554 sblkcnt = 2;
1555 limit = 0;
1556 } else if (limit != 0)
1557 limit = sndbuf_xbytes(sndbuf_getsize(b), b, bs);
1558

--- 205 unchanged lines hidden (view full) ---

1764}
1765
1766int
1767chn_trigger(struct pcm_channel *c, int go)
1768{
1769#ifdef DEV_ISA
1770 struct snd_dbuf *b = c->bufhard;
1771#endif
1772 struct snddev_info *d = c->parentsnddev;
1773 int ret;
1774
1775 CHN_LOCKASSERT(c);
1776#ifdef DEV_ISA
1777 if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD))
1778 sndbuf_dmabounce(b);
1779#endif
1780 if ((go == PCMTRIG_START || go == PCMTRIG_STOP ||
1781 go == PCMTRIG_ABORT) && go == c->trigger)
1782 return 0;
1783
1784 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
1785
1786 if (ret == 0) {
1787 switch (go) {
1788 case PCMTRIG_START:
1789 if (snd_verbose > 3)
1790 device_printf(c->dev,
1791 "%s() %s: calling go=0x%08x , "
1792 "prev=0x%08x\n", __func__, c->name, go,
1793 c->trigger);
1794 if (c->trigger != PCMTRIG_START) {
1795 c->trigger = go;
1796 CHN_UNLOCK(c);
1797 pcm_lock(d);
1798 CHN_INSERT_HEAD(d, c, channels.pcm.busy);
1799 pcm_unlock(d);
1800 CHN_LOCK(c);
1801 }
1802 break;
1803 case PCMTRIG_STOP:
1804 case PCMTRIG_ABORT:
1805 if (snd_verbose > 3)
1806 device_printf(c->dev,
1807 "%s() %s: calling go=0x%08x , "
1808 "prev=0x%08x\n", __func__, c->name, go,
1809 c->trigger);
1810 if (c->trigger == PCMTRIG_START) {
1811 c->trigger = go;
1812 CHN_UNLOCK(c);
1813 pcm_lock(d);
1814 CHN_REMOVE(d, c, channels.pcm.busy);
1815 pcm_unlock(d);
1816 CHN_LOCK(c);
1817 }
1818 break;
1819 default:
1820 break;
1821 }
1822 }
1823
1824 return ret;
1825}
1826
1827/**
1828 * @brief Queries sound driver for sample-aligned hardware buffer pointer index
1829 *
1830 * This function obtains the hardware pointer location, then aligns it to
1831 * the current bytes-per-sample value before returning. (E.g., a channel

--- 65 unchanged lines hidden (view full) ---

1897
1898 CHN_LOCKASSERT(c);
1899 while (chn_removefeeder(c) == 0)
1900 ;
1901 KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1902
1903 c->align = sndbuf_getalign(c->bufsoft);
1904
1905 if (CHN_EMPTY(c, children) || c->direction == PCMDIR_REC) {
1906 /*
1907 * Virtual rec need this.
1908 */
1909 fc = feeder_getclass(NULL);
1910 KASSERT(fc != NULL, ("can't find root feeder"));
1911
1912 err = chn_addfeeder(c, fc, NULL);
1913 if (err) {
1914 DEB(printf("can't add root feeder, err %d\n", err));
1915
1916 return err;
1917 }
1918 c->feeder->desc->out = c->format;
1919 } else if (c->direction == PCMDIR_PLAY) {
1920 if (c->flags & CHN_F_HAS_VCHAN) {
1921 desc.type = FEEDER_MIXER;
1922 desc.in = c->format;
1923 } else {
1924 DEB(printf("can't decide which feeder type to use!\n"));
1925 return EOPNOTSUPP;
1926 }
1927 desc.out = c->format;

--- 6 unchanged lines hidden (view full) ---

1934 }
1935
1936 err = chn_addfeeder(c, fc, &desc);
1937 if (err) {
1938 DEB(printf("can't add vchan feeder, err %d\n", err));
1939
1940 return err;
1941 }
1942 } else
1943 return EOPNOTSUPP;
1944
1945 c->feederflags &= ~(1 << FEEDER_VOLUME);
1946 if (c->direction == PCMDIR_PLAY &&
1947 !(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
1948 (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
1949 c->parentsnddev->mixer_dev)
1950 c->feederflags |= 1 << FEEDER_VOLUME;
1951 if (!(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
1952 ((c->direction == PCMDIR_PLAY &&

--- 83 unchanged lines hidden (view full) ---

2036 tmp[1] = 0;
2037 hwfmt = chn_fmtchain(c, tmp);
2038 } else
2039 hwfmt = chn_fmtchain(c, fmtlist);
2040
2041 if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) {
2042 DEB(printf("Invalid hardware format: 0x%08x\n", hwfmt));
2043 return ENODEV;
2044 } else if (c->direction == PCMDIR_REC && !CHN_EMPTY(c, children)) {
2045 /*
2046 * Kind of awkward. This whole "MIXER" concept need a
2047 * rethinking, I guess :) . Recording is the inverse
2048 * of Playback, which is why we push mixer vchan down here.
2049 */
2050 if (c->flags & CHN_F_HAS_VCHAN) {
2051 desc.type = FEEDER_MIXER;
2052 desc.in = c->format;
2053 } else
2054 return EOPNOTSUPP;
2055 desc.out = c->format;
2056 desc.flags = 0;
2057 fc = feeder_getclass(&desc);
2058 if (fc == NULL)
2059 return EOPNOTSUPP;
2060
2061 err = chn_addfeeder(c, fc, &desc);
2062 if (err != 0)
2063 return err;
2064 }
2065
2066 sndbuf_setfmt(c->bufhard, hwfmt);
2067
2068 if ((flags & (1 << FEEDER_VOLUME))) {
2069 u_int32_t parent = SOUND_MIXER_NONE;
2070 int vol, left, right;
2071

--- 30 unchanged lines hidden (view full) ---

2102 }
2103
2104 return 0;
2105}
2106
2107int
2108chn_notify(struct pcm_channel *c, u_int32_t flags)
2109{
2110 int run;
2111
2112 CHN_LOCK(c);
2113
2114 if (CHN_EMPTY(c, children)) {
2115 CHN_UNLOCK(c);
2116 return ENODEV;
2117 }
2118
2119 run = (CHN_STARTED(c)) ? 1 : 0;
2120 /*
2121 * if the hwchan is running, we can't change its rate, format or
2122 * blocksize

--- 21 unchanged lines hidden (view full) ---

2144 if (flags & CHN_N_BLOCKSIZE) {
2145 /*
2146 * Set to default latency profile
2147 */
2148 chn_setlatency(c, chn_latency);
2149 }
2150 if (flags & CHN_N_TRIGGER) {
2151 int nrun;
2152
2153 nrun = CHN_EMPTY(c, children.busy) ? 0 : 1;
2154 if (nrun && !run)
2155 chn_start(c, 1);
2156 if (!nrun && run)
2157 chn_abort(c);
2158 }
2159 CHN_UNLOCK(c);
2160 return 0;
2161}

--- 92 unchanged lines hidden ---