Lines Matching +full:pcm +full:- +full:sync +full:- +full:mode

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
5 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
39 #include <dev/sound/pcm/sound.h>
60 "linux mmap compatibility (-1=force disable 0=auto 1=force enable)");
67 #define DSP_REGISTERED(x) (PCM_REGISTERED(x) && (x)->dsp_dev != NULL)
124 err = make_dev_s(&devargs, &sc->dsp_dev, "dsp%d", unit);
140 destroy_dev(d->dsp_dev);
146 if (priv->rdch != NULL && (prio & SD_F_PRIO_RD))
147 CHN_LOCK(priv->rdch);
148 if (priv->wrch != NULL && (prio & SD_F_PRIO_WR))
149 CHN_LOCK(priv->wrch);
155 if (priv->rdch != NULL && (prio & SD_F_PRIO_RD))
156 CHN_UNLOCK(priv->rdch);
157 if (priv->wrch != NULL && (prio & SD_F_PRIO_WR))
158 CHN_UNLOCK(priv->wrch);
178 d = priv->sc;
189 rdch = priv->rdch;
190 wrch = priv->wrch;
193 CHN_REMOVE(d, rdch, channels.pcm.opened);
195 CHN_REMOVE(d, wrch, channels.pcm.opened);
219 rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
236 wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
254 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
266 d = i_dev->si_drv1;
271 priv->sc = d;
272 priv->rdch = NULL;
273 priv->wrch = NULL;
274 priv->volch = NULL;
290 ((DSP_F_READ(flags) && d->reccount == 0) ||
291 (DSP_F_WRITE(flags) && d->playcount == 0)))
293 if (pcm_getflags(d->dev) & SD_F_SIMPLEX) {
300 if (CHN_EMPTY(d, channels.pcm.opened)) {
301 if (d->playcount > 0)
303 else if (d->reccount > 0)
306 ch = CHN_FIRST(d, channels.pcm.opened);
307 if (ch->direction == PCMDIR_PLAY)
309 else if (ch->direction == PCMDIR_REC)
312 } else if (!CHN_EMPTY(d, channels.pcm.opened)) {
317 ch = CHN_FIRST(d, channels.pcm.opened);
319 if (ch->direction != dir)
330 * That is just enough. Acquire and unlock pcm lock so
348 td->td_proc->p_pid, td->td_proc->p_comm);
364 rdch->flags |= CHN_F_NBIO;
366 rdch->flags |= CHN_F_EXCLUSIVE;
375 td->td_proc->p_pid, td->td_proc->p_comm);
399 wrch->flags |= CHN_F_NBIO;
401 wrch->flags |= CHN_F_EXCLUSIVE;
420 CHN_INSERT_HEAD(d, rdch, channels.pcm.opened);
422 CHN_INSERT_HEAD(d, wrch, channels.pcm.opened);
423 priv->rdch = rdch;
424 priv->wrch = wrch;
444 (buf->uio_rw == UIO_READ || buf->uio_rw == UIO_WRITE),
447 d = priv->sc;
453 switch (buf->uio_rw) {
456 ch = &priv->rdch;
461 ch = &priv->wrch;
465 panic("invalid/corrupted uio direction: %d", buf->uio_rw);
469 runpid = buf->uio_td->td_proc->p_pid;
473 if (*ch == NULL || !((*ch)->flags & CHN_F_BUSY)) {
474 if (priv->rdch != NULL || priv->wrch != NULL)
480 if (((*ch)->flags & (CHN_F_MMAP | CHN_F_DEAD)) ||
481 (((*ch)->flags & CHN_F_RUNNING) && (*ch)->pid != runpid)) {
485 } else if (!((*ch)->flags & CHN_F_RUNNING)) {
486 (*ch)->flags |= CHN_F_RUNNING;
487 (*ch)->pid = runpid;
495 ++(*ch)->inprog;
497 --(*ch)->inprog;
499 CHN_BROADCAST(&(*ch)->cv);
538 d = priv->sc;
539 if (!PCM_REGISTERED(d) || !(pcm_getflags(d->dev) & SD_F_VPC))
540 return (-1);
546 rdch = priv->rdch;
547 wrch = priv->wrch;
551 volch = priv->volch;
566 if (!(volch->feederflags & (1 << FEEDER_VOLUME))) {
575 if (volch->direction == PCMDIR_REC) {
582 if (volch->direction != PCMDIR_PLAY)
591 if (volch->direction != PCMDIR_REC)
610 if (volch->direction == PCMDIR_REC) {
617 if (volch->direction != PCMDIR_PLAY)
625 if (volch->direction != PCMDIR_REC)
635 if (volch->direction == PCMDIR_REC)
654 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
666 d = priv->sc;
683 ret = dsp_ioctl_channel(priv, priv->volch, cmd, arg);
684 if (ret != -1) {
689 if (d->mixer_dev != NULL) {
691 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
737 rdch = priv->rdch;
738 wrch = priv->wrch;
740 if (wrch != NULL && (wrch->flags & CHN_F_DEAD))
742 if (rdch != NULL && (rdch->flags & CHN_F_DEAD))
759 if (wrch && wrch->bufhard.dl)
762 *arg_i = sndbuf_getfree(wrch->bufsoft);
774 p->play_size = 0;
775 p->rec_size = 0;
779 chn_setblocksize(wrch, 2, p->play_size);
780 p->play_size = sndbuf_getblksz(wrch->bufsoft);
785 chn_setblocksize(rdch, 2, p->rec_size);
786 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
798 p->play_size = sndbuf_getblksz(wrch->bufsoft);
803 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
815 ((p->play_format != 0 && p->play_rate == 0) ||
816 (p->rec_format != 0 && p->rec_rate == 0))) {
823 if (cmd == AIOSFMT && p->play_format != 0) {
825 SND_FORMAT(p->play_format,
826 AFMT_CHANNEL(wrch->format),
827 AFMT_EXTCHANNEL(wrch->format)));
828 chn_setspeed(wrch, p->play_rate);
830 p->play_rate = wrch->speed;
831 p->play_format = AFMT_ENCODING(wrch->format);
834 p->play_rate = 0;
835 p->play_format = 0;
839 if (cmd == AIOSFMT && p->rec_format != 0) {
841 SND_FORMAT(p->rec_format,
842 AFMT_CHANNEL(rdch->format),
843 AFMT_EXTCHANNEL(rdch->format)));
844 chn_setspeed(rdch, p->rec_rate);
846 p->rec_rate = rdch->speed;
847 p->rec_format = AFMT_ENCODING(rdch->format);
850 p->rec_rate = 0;
851 p->rec_format = 0;
872 p->rate_min = max(rcaps? rcaps->minspeed : 0,
873 pcaps? pcaps->minspeed : 0);
874 p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
875 pcaps? pcaps->maxspeed : 1000000);
876 p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
877 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
879 p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
882 p->formats |=
883 (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 0 :
886 pdev = d->mixer_dev;
887 p->mixers = 1; /* default: one mixer */
888 p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
889 p->left = p->right = 100;
915 ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
924 /* if (rdch && rdch->bufhard.dl)
927 *arg_i = sndbuf_getready(rdch->bufsoft);
939 case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */
940 case FIONBIO: /* set/clear non-blocking i/o */
944 rdch->flags |= CHN_F_NBIO;
946 rdch->flags &= ~CHN_F_NBIO;
952 wrch->flags |= CHN_F_NBIO;
954 wrch->flags &= ~CHN_F_NBIO;
960 * Finally, here is the linux-compatible ioctl interface
968 *arg_i = sndbuf_getblksz(chn->bufsoft);
1009 DEB(printf("dsp sync\n"));
1025 tmp = wrch->speed;
1032 tmp = rdch->speed;
1043 *arg_i = chn->speed;
1052 tmp = -1;
1058 SND_FORMAT(wrch->format, *arg_i, 0));
1059 tmp = (AFMT_CHANNEL(wrch->format) > 1)? 1 : 0;
1065 SND_FORMAT(rdch->format, *arg_i, 0));
1066 if (tmp == -1)
1067 tmp = (AFMT_CHANNEL(rdch->format) > 1)? 1 : 0;
1087 * Devices that need bitperfect mode to operate
1091 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
1099 ext = m->ext;
1106 SND_FORMAT(wrch->format, *arg_i, ext));
1107 tmp = AFMT_CHANNEL(wrch->format);
1113 SND_FORMAT(rdch->format, *arg_i, ext));
1115 tmp = AFMT_CHANNEL(rdch->format);
1123 *arg_i = AFMT_CHANNEL(chn->format);
1132 *arg_i = AFMT_CHANNEL(chn->format);
1159 AFMT_CHANNEL(wrch->format),
1160 AFMT_EXTCHANNEL(wrch->format)));
1161 tmp = wrch->format;
1167 AFMT_CHANNEL(rdch->format),
1168 AFMT_EXTCHANNEL(rdch->format)));
1170 tmp = rdch->format;
1178 *arg_i = AFMT_ENCODING(chn->format);
1206 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
1207 r_fragsz = sndbuf_getblksz(rdch->bufsoft);
1216 maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
1217 fragsz = sndbuf_getblksz(wrch->bufsoft);
1239 struct snd_dbuf *bs = rdch->bufsoft;
1242 a->bytes = sndbuf_getready(bs);
1243 a->fragments = a->bytes / sndbuf_getblksz(bs);
1244 a->fragstotal = sndbuf_getblkcnt(bs);
1245 a->fragsize = sndbuf_getblksz(bs);
1257 struct snd_dbuf *bs = wrch->bufsoft;
1260 a->bytes = sndbuf_getfree(bs);
1261 a->fragments = a->bytes / sndbuf_getblksz(bs);
1262 a->fragstotal = sndbuf_getblkcnt(bs);
1263 a->fragsize = sndbuf_getblksz(bs);
1274 struct snd_dbuf *bs = rdch->bufsoft;
1277 a->bytes = sndbuf_gettotal(bs);
1278 a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
1279 a->ptr = sndbuf_getfreeptr(bs);
1280 rdch->blocks = sndbuf_getblocks(bs);
1291 struct snd_dbuf *bs = wrch->bufsoft;
1294 a->bytes = sndbuf_gettotal(bs);
1295 a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
1296 a->ptr = sndbuf_getreadyptr(bs);
1297 wrch->blocks = sndbuf_getblocks(bs);
1307 if (rdch && wrch && !(pcm_getflags(d->dev) & SD_F_SIMPLEX))
1309 if (rdch && (rdch->flags & CHN_F_VIRTUAL) != 0)
1311 if (wrch && (wrch->flags & CHN_F_VIRTUAL) != 0)
1320 if (chn->format & AFMT_8BIT)
1322 else if (chn->format & AFMT_16BIT)
1324 else if (chn->format & AFMT_24BIT)
1326 else if (chn->format & AFMT_32BIT)
1340 rdch->flags &= ~CHN_F_NOTRIGGER;
1346 rdch->flags |= CHN_F_NOTRIGGER;
1352 wrch->flags &= ~CHN_F_NOTRIGGER;
1358 wrch->flags |= CHN_F_NOTRIGGER;
1368 if (wrch->flags & CHN_F_TRIGGERED)
1374 if (rdch->flags & CHN_F_TRIGGERED)
1382 struct snd_dbuf *bs = wrch->bufsoft;
1394 wrch->flags &= ~CHN_F_NOTRIGGER;
1402 * switch to full-duplex mode if card is in half-duplex
1403 * mode and is able to work in full-duplex mode
1406 if (rdch && wrch && (pcm_getflags(d->dev) & SD_F_SIMPLEX))
1407 pcm_setflags(d->dev, pcm_getflags(d->dev)^SD_F_SIMPLEX);
1441 if (ret != -1) {
1446 if (d->mixer_dev != NULL) {
1448 ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td,
1459 if (d->mixer_dev != NULL) {
1461 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
1478 ei->dev = 0;
1479 ei->ctrl = 0;
1480 ei->version = 0; /* static for now */
1481 ei->strindex[0] = 0;
1484 ei->nvalues = 1;
1485 strlcpy(ei->strings, wrch->name,
1486 sizeof(ei->strings));
1488 ei->nvalues = 0;
1489 ei->strings[0] = '\0';
1509 * Flush the software (pre-feed) buffer, but try to minimize playback
1519 while (wrch->inprog != 0)
1520 cv_wait(&wrch->cv, wrch->lock);
1521 bs = wrch->bufsoft;
1522 if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) {
1523 bs->sl = sndbuf_getready(bs);
1524 sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs));
1543 while (wrch->inprog != 0)
1544 cv_wait(&wrch->cv, wrch->lock);
1545 bs = wrch->bufsoft;
1546 if ((bs->shadbuf != NULL) && (bs->sl > 0)) {
1548 sndbuf_acquire(bs, bs->shadbuf, bs->sl);
1549 bs->sl = 0;
1580 bs = chn->bufsoft;
1581 oc->samples = sndbuf_gettotal(bs) / sndbuf_getalign(bs);
1582 oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getalign(bs);
1606 wrch->lw = (*arg_i > 1) ? *arg_i : 1;
1611 rdch->lw = (*arg_i > 1) ? *arg_i : 1;
1631 ei->play_underruns = wrch->xruns;
1632 wrch->xruns = 0;
1637 ei->rec_overruns = rdch->xruns;
1638 rdch->xruns = 0;
1664 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT))
1702 if (ret == -1)
1763 d = priv->sc;
1774 wrch = priv->wrch;
1775 rdch = priv->rdch;
1777 if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) {
1783 if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) {
1823 * https://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html
1845 d = priv->sc;
1852 wrch = priv->wrch;
1853 rdch = priv->rdch;
1856 if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) ||
1857 (*offset + size) > sndbuf_getallocsize(c->bufsoft) ||
1858 (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) ||
1859 (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) {
1866 wrch->flags |= CHN_F_MMAP;
1868 rdch->flags |= CHN_F_MMAP;
1870 *offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset);
1873 size, nprot, *offset, curthread->td_ucred);
1912 * have returned already, meaning it will have set snd_unit to -1, and
1916 *dev = d->dsp_dev;
1946 ai->dev = unit;
1947 snprintf(ai->name, sizeof(ai->name), "pcm%d (unavailable)", unit);
1948 ai->pid = -1;
1949 strlcpy(ai->cmd, CHN_COMM_UNUSED, sizeof(ai->cmd));
1950 ai->card_number = unit;
1951 ai->port_number = unit;
1952 ai->mixer_dev = -1;
1953 ai->legacy_device = unit;
1959 * Gathers information about the audio device specified in ai->dev. If
1960 * ai->dev == -1, then this function gathers information about the current
1961 * device. If the call comes in on a non-audio device and ai->dev == -1,
1965 * getting capabilities directly from the sound card driver, side-stepping
1977 * @retval EINVAL ai->dev specifies an invalid device
1993 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2000 if ((ai->dev == -1 && unit == snd_unit) ||
2001 ai->dev == unit) {
2012 if ((ai->dev == -1 && d->dsp_dev == i_dev) ||
2013 (ai->dev == unit)) {
2022 /* Exhausted the search -- nothing is locked, so return. */
2032 ai->dev = unit;
2033 strlcpy(ai->name, device_get_desc(d->dev), sizeof(ai->name));
2034 ai->pid = -1;
2035 strlcpy(ai->cmd, CHN_COMM_UNKNOWN, sizeof(ai->cmd));
2036 ai->card_number = unit;
2037 ai->port_number = unit;
2038 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1;
2039 ai->legacy_device = unit;
2040 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit);
2041 ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2042 ai->next_play_engine = 0;
2043 ai->next_rec_engine = 0;
2044 ai->busy = 0;
2045 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER;
2046 ai->iformats = 0;
2047 ai->oformats = 0;
2048 ai->min_rate = INT_MAX;
2049 ai->max_rate = 0;
2050 ai->min_channels = INT_MAX;
2051 ai->max_channels = 0;
2054 CHN_FOREACH(ch, d, channels.pcm) {
2065 if ((ex && (ch->flags & CHN_F_VIRTUAL) != 0) ||
2066 ((!ex && (ch->flags & CHN_F_VIRTUAL) == 0) &&
2067 (d->pvchancount > 0 || d->rvchancount > 0))) {
2072 if ((ch->flags & CHN_F_BUSY) == 0) {
2073 ai->busy |= (ch->direction == PCMDIR_PLAY) ?
2077 ai->caps |=
2078 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) |
2079 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT :
2087 for (i = 0; caps->fmtlist[i]; i++) {
2088 fmts |= AFMT_ENCODING(caps->fmtlist[i]);
2089 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch);
2090 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch);
2093 if (ch->direction == PCMDIR_PLAY)
2094 ai->oformats |= fmts;
2096 ai->iformats |= fmts;
2098 if (ex || (pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
2099 ai->min_rate = min(ai->min_rate, caps->minspeed);
2100 ai->max_rate = max(ai->max_rate, caps->maxspeed);
2102 ai->min_rate = min(ai->min_rate, feeder_rate_min);
2103 ai->max_rate = max(ai->max_rate, feeder_rate_max);
2105 ai->min_channels = min(ai->min_channels, minch);
2106 ai->max_channels = max(ai->max_channels, maxch);
2110 if (ai->min_rate == INT_MAX)
2111 ai->min_rate = 0;
2112 if (ai->min_channels == INT_MAX)
2113 ai->min_channels = 0;
2126 if (DSP_REGISTERED(priv->sc) && (ch == priv->rdch || ch == priv->wrch))
2135 * Gathers information about the audio device's engine specified in ai->dev.
2136 * If ai->dev == -1, then this function gathers information about the current
2137 * device. If the call comes in on a non-audio device and ai->dev == -1,
2141 * getting capabilities directly from the sound card driver, side-stepping
2151 * @retval EINVAL ai->dev specifies an invalid device
2167 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2175 * iterating over pcm devices.
2189 CHN_FOREACH(ch, d, channels.pcm) {
2192 if ((ai->dev == -1 && devfs_foreach_cdevpriv(
2194 ai->dev == nchan)
2208 * - a specific PCM device is locked.
2209 * - a specific audio channel has been locked, so be
2221 ai->dev = nchan;
2222 strlcpy(ai->name, ch->name, sizeof(ai->name));
2224 if ((ch->flags & CHN_F_BUSY) == 0)
2225 ai->busy = 0;
2227 ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ;
2229 ai->pid = ch->pid;
2230 strlcpy(ai->cmd, ch->comm, sizeof(ai->cmd));
2238 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep
2241 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER |
2242 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) |
2243 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : PCM_CAP_INPUT);
2252 for (i = 0; caps->fmtlist[i]; i++) {
2253 fmts |= AFMT_ENCODING(caps->fmtlist[i]);
2254 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch);
2255 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch);
2258 if (ch->direction == PCMDIR_PLAY)
2259 ai->oformats = fmts;
2261 ai->iformats = fmts;
2265 * @c magic - OSSv4 docs: "Reserved for internal use
2269 * @c card_number - OSSv4 docs: "Number of the sound
2270 * card where this device belongs or -1 if this
2275 ai->card_number = unit;
2277 * @todo @c song_name - depends first on
2278 * SNDCTL_[GS]ETSONG @todo @c label - depends
2280 * @todo @c port_number - routing information?
2282 ai->port_number = unit;
2283 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1;
2286 * @c legacy_device - OSSv4 docs: "Obsolete."
2288 ai->legacy_device = unit;
2289 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit);
2290 ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2293 * @c flags - OSSv4 docs: "Reserved for future use."
2296 * @c binding - OSSv4 docs: "Reserved for future use."
2298 * @todo @c handle - haven't decided how to generate
2302 if ((ch->flags & CHN_F_EXCLUSIVE) ||
2303 (pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
2304 ai->min_rate = caps->minspeed;
2305 ai->max_rate = caps->maxspeed;
2307 ai->min_rate = feeder_rate_min;
2308 ai->max_rate = feeder_rate_max;
2311 ai->min_channels = minch;
2312 ai->max_channels = maxch;
2314 ai->nrates = chn_getrates(ch, &rates);
2315 if (ai->nrates > OSS_MAX_SAMPLE_RATES)
2316 ai->nrates = OSS_MAX_SAMPLE_RATES;
2318 for (i = 0; i < ai->nrates; i++)
2319 ai->rates[i] = rates[i];
2321 ai->next_play_engine = 0;
2322 ai->next_rec_engine = 0;
2330 /* Exhausted the search -- nothing is locked, so return. */
2335 * @brief Assigns a PCM channel to a sync group.
2337 * Sync groups are used to enable audio operations on multiple devices
2344 * sync group is created. Otherwise, wrch and rdch (if set) are added to
2353 * @param group Sync group parameters
2356 * @retval non-zero error to be propagated upstream
2379 * - Insert channel(s) into group's member list.
2380 * - Set CHN_F_NOTRIGGER on channel(s).
2381 * - Stop channel(s).
2398 * Verify that mode matches character device properites.
2399 * - Bail if PCM_ENABLE_OUTPUT && wrch == NULL.
2400 * - Bail if PCM_ENABLE_INPUT && rdch == NULL.
2402 if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) ||
2403 ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) {
2412 if (group->id == 0) {
2415 SLIST_INIT(&sg->members);
2416 sg->id = alloc_unr(pcmsg_unrhdr);
2418 group->id = sg->id;
2424 if (sg->id == group->id)
2439 if (group->mode & PCM_ENABLE_INPUT) {
2446 SLIST_INSERT_HEAD(&sg->members, smrd, link);
2447 smrd->parent = sg;
2448 smrd->ch = rdch;
2451 rdch->flags |= CHN_F_NOTRIGGER;
2452 rdch->sm = smrd;
2455 if (group->mode & PCM_ENABLE_OUTPUT) {
2462 SLIST_INSERT_HEAD(&sg->members, smwr, link);
2463 smwr->parent = sg;
2464 smwr->ch = wrch;
2467 wrch->flags |= CHN_F_NOTRIGGER;
2468 wrch->sm = smwr;
2475 if ((sg != NULL) && SLIST_EMPTY(&sg->members)) {
2476 sg_ids[2] = sg->id;
2482 wrch->sm = NULL;
2484 rdch->sm = NULL;
2505 * @brief Launch a sync group into action
2507 * Sync groups are established via SNDCTL_DSP_SYNCGROUP. This function
2512 * @param sg_id sync group identifier
2515 * @retval non-zero error worthy of propagating upstream to user
2534 if (sg->id == sg_id)
2545 KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup"));
2548 * Attempt to lock all member channels - if any are already
2552 SLIST_FOREACH(sm, &sg->members, link) {
2553 if (CHN_TRYLOCK(sm->ch) == 0) {
2559 SLIST_FOREACH(sm_tmp, &sg->members, link) {
2563 CHN_UNLOCK(sm_tmp->ch);
2581 while ((sm = SLIST_FIRST(&sg->members)) != NULL) {
2582 SLIST_REMOVE_HEAD(&sg->members, link);
2584 c = sm->ch;
2585 c->sm = NULL;
2587 c->flags &= ~CHN_F_NOTRIGGER;
2631 * @note PCM channel arguments must not be locked by caller.
2669 * @brief Enable or disable "cooked" mode
2671 * This is a handler for @c SNDCTL_DSP_COOKEDMODE. When in cooked mode, which
2676 * Disabling cooked mode is intended for applications wanting to mmap()
2677 * a sound card's buffer space directly, bypassing the FreeBSD 2-stage
2686 * @param enabled 0 = raw mode, 1 = cooked mode
2698 * <insert any non-printable characters here>.
2712 wrch->flags &= ~CHN_F_BITPERFECT;
2713 wrch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000;
2719 rdch->flags &= ~CHN_F_BITPERFECT;
2720 rdch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000;