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 --- |