Lines Matching +full:playback +full:- +full:channels
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
8 * Copyright (c) 2024-2025 The FreeBSD Foundation
60 "linux mmap compatibility (-1=force disable 0=auto 1=force enable)");
67 #define DSP_REGISTERED(x) (PCM_REGISTERED(x) && (x)->dsp_dev != NULL)
130 err = make_dev_s(&devargs, &sc->dsp_dev, "dsp%d", unit); in dsp_make_dev()
146 destroy_dev(d->dsp_dev); in dsp_destroy_dev()
152 if (priv->rdch != NULL && DSP_F_READ(prio)) in dsp_lock_chans()
153 CHN_LOCK(priv->rdch); in dsp_lock_chans()
154 if (priv->wrch != NULL && DSP_F_WRITE(prio)) in dsp_lock_chans()
155 CHN_LOCK(priv->wrch); in dsp_lock_chans()
161 if (priv->rdch != NULL && DSP_F_READ(prio)) in dsp_unlock_chans()
162 CHN_UNLOCK(priv->rdch); in dsp_unlock_chans()
163 if (priv->wrch != NULL && DSP_F_WRITE(prio)) in dsp_unlock_chans()
164 CHN_UNLOCK(priv->wrch); in dsp_unlock_chans()
183 pid = td->td_proc->p_pid; in dsp_chn_alloc()
184 comm = td->td_proc->p_comm; in dsp_chn_alloc()
186 vdir_enabled = (direction == PCMDIR_PLAY && d->flags & SD_F_PVCHANS) || in dsp_chn_alloc()
187 (direction == PCMDIR_REC && d->flags & SD_F_RVCHANS); in dsp_chn_alloc()
190 CHN_FOREACH(c, d, channels.pcm.primary) { in dsp_chn_alloc()
192 if (c->direction != direction) { in dsp_chn_alloc()
197 if ((c->flags & CHN_F_BUSY) == 0 || in dsp_chn_alloc()
198 (vdir_enabled && (c->flags & CHN_F_HAS_VCHAN))) in dsp_chn_alloc()
207 * - vchans are enabled, add a new vchan to the primary channel. in dsp_chn_alloc()
208 * - vchans are disabled, use the primary channel directly. in dsp_chn_alloc()
210 if (vdir_enabled && ((c->flags & CHN_F_BUSY) == 0 || in dsp_chn_alloc()
211 c->flags & CHN_F_HAS_VCHAN)) { in dsp_chn_alloc()
217 } else if ((c->flags & CHN_F_BUSY) == 0) { in dsp_chn_alloc()
224 (*ch)->flags |= CHN_F_BUSY; in dsp_chn_alloc()
226 (*ch)->flags |= CHN_F_NBIO; in dsp_chn_alloc()
228 (*ch)->flags |= CHN_F_EXCLUSIVE; in dsp_chn_alloc()
229 (*ch)->pid = pid; in dsp_chn_alloc()
230 strlcpy((*ch)->comm, (comm != NULL) ? comm : CHN_COMM_UNKNOWN, in dsp_chn_alloc()
231 sizeof((*ch)->comm)); in dsp_chn_alloc()
233 if ((err = chn_reset(*ch, (*ch)->format, (*ch)->speed)) != 0) in dsp_chn_alloc()
253 d = priv->sc; in dsp_close()
254 /* At this point pcm_unregister() will destroy all channels anyway. */ in dsp_close()
264 rdch = priv->rdch; in dsp_close()
265 wrch = priv->wrch; in dsp_close()
268 CHN_REMOVE(d, rdch, channels.pcm.opened); in dsp_close()
270 CHN_REMOVE(d, wrch, channels.pcm.opened); in dsp_close()
294 * primary and virtual channels to ensure that, in the in dsp_close()
296 * stopped, and the primary channels do not keep being in dsp_close()
301 rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP | in dsp_close()
305 if (rdch->flags & CHN_F_VIRTUAL) { in dsp_close()
306 parent = rdch->parentchannel; in dsp_close()
325 wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP | in dsp_close()
329 if (wrch->flags & CHN_F_VIRTUAL) { in dsp_close()
330 parent = wrch->parentchannel; in dsp_close()
361 d = i_dev->si_drv1; in dsp_open()
369 priv->sc = d; in dsp_open()
385 ((DSP_F_READ(flags) && d->reccount == 0) || in dsp_open()
386 (DSP_F_WRITE(flags) && d->playcount == 0))) in dsp_open()
388 if (pcm_getflags(d->dev) & SD_F_SIMPLEX) { in dsp_open()
391 * If no channels are opened yet, and we request in dsp_open()
392 * DUPLEX, limit to playback only, otherwise open one in dsp_open()
395 if (CHN_EMPTY(d, channels.pcm.opened)) { in dsp_open()
396 if (d->playcount > 0) in dsp_open()
398 else if (d->reccount > 0) in dsp_open()
401 ch = CHN_FIRST(d, channels.pcm.opened); in dsp_open()
402 if (ch->direction == PCMDIR_PLAY) in dsp_open()
404 else if (ch->direction == PCMDIR_REC) in dsp_open()
407 } else if (!CHN_EMPTY(d, channels.pcm.opened)) { in dsp_open()
412 ch = CHN_FIRST(d, channels.pcm.opened); in dsp_open()
414 if (ch->direction != dir) in dsp_open()
433 error = dsp_chn_alloc(d, &priv->wrch, PCMDIR_PLAY, flags, td); in dsp_open()
440 CHN_INSERT_HEAD(d, priv->wrch, channels.pcm.opened); in dsp_open()
444 error = dsp_chn_alloc(d, &priv->rdch, PCMDIR_REC, flags, td); in dsp_open()
451 CHN_INSERT_HEAD(d, priv->rdch, channels.pcm.opened); in dsp_open()
471 (buf->uio_rw == UIO_READ || buf->uio_rw == UIO_WRITE), in dsp_io_ops()
474 d = priv->sc; in dsp_io_ops()
480 switch (buf->uio_rw) { in dsp_io_ops()
483 ch = &priv->rdch; in dsp_io_ops()
488 ch = &priv->wrch; in dsp_io_ops()
492 panic("invalid/corrupted uio direction: %d", buf->uio_rw); in dsp_io_ops()
496 runpid = buf->uio_td->td_proc->p_pid; in dsp_io_ops()
500 if (*ch == NULL || !((*ch)->flags & CHN_F_BUSY)) { in dsp_io_ops()
501 if (priv->rdch != NULL || priv->wrch != NULL) in dsp_io_ops()
507 if (((*ch)->flags & (CHN_F_MMAP | CHN_F_DEAD)) || in dsp_io_ops()
508 (((*ch)->flags & CHN_F_RUNNING) && (*ch)->pid != runpid)) { in dsp_io_ops()
512 } else if (!((*ch)->flags & CHN_F_RUNNING)) { in dsp_io_ops()
513 (*ch)->flags |= CHN_F_RUNNING; in dsp_io_ops()
514 (*ch)->pid = runpid; in dsp_io_ops()
522 ++(*ch)->inprog; in dsp_io_ops()
524 --(*ch)->inprog; in dsp_io_ops()
526 CHN_BROADCAST(&(*ch)->cv); in dsp_io_ops()
565 d = priv->sc; in dsp_ioctl_channel()
566 if (!PCM_REGISTERED(d) || !(pcm_getflags(d->dev) & SD_F_VPC)) in dsp_ioctl_channel()
567 return (-1); in dsp_ioctl_channel()
573 rdch = priv->rdch; in dsp_ioctl_channel()
574 wrch = priv->wrch; in dsp_ioctl_channel()
587 if (!(ch->feederflags & (1 << FEEDER_VOLUME))) { in dsp_ioctl_channel()
596 if (ch->direction == PCMDIR_REC) { in dsp_ioctl_channel()
603 if (ch->direction != PCMDIR_PLAY) in dsp_ioctl_channel()
612 if (ch->direction != PCMDIR_REC) in dsp_ioctl_channel()
631 if (ch->direction == PCMDIR_REC) { in dsp_ioctl_channel()
638 if (ch->direction != PCMDIR_PLAY) in dsp_ioctl_channel()
646 if (ch->direction != PCMDIR_REC) in dsp_ioctl_channel()
656 if (ch->direction == PCMDIR_REC) in dsp_ioctl_channel()
687 d = priv->sc; in dsp_ioctl()
705 if (ret != -1) { in dsp_ioctl()
710 if (d->mixer_dev != NULL) { in dsp_ioctl()
712 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td, in dsp_ioctl()
758 rdch = priv->rdch; in dsp_ioctl()
759 wrch = priv->wrch; in dsp_ioctl()
761 if (wrch != NULL && (wrch->flags & CHN_F_DEAD)) in dsp_ioctl()
763 if (rdch != NULL && (rdch->flags & CHN_F_DEAD)) in dsp_ioctl()
780 if (wrch && wrch->bufhard.dl) in dsp_ioctl()
783 *arg_i = sndbuf_getfree(wrch->bufsoft); in dsp_ioctl()
795 p->play_size = 0; in dsp_ioctl()
796 p->rec_size = 0; in dsp_ioctl()
800 chn_setblocksize(wrch, 2, p->play_size); in dsp_ioctl()
801 p->play_size = sndbuf_getblksz(wrch->bufsoft); in dsp_ioctl()
806 chn_setblocksize(rdch, 2, p->rec_size); in dsp_ioctl()
807 p->rec_size = sndbuf_getblksz(rdch->bufsoft); in dsp_ioctl()
819 p->play_size = sndbuf_getblksz(wrch->bufsoft); in dsp_ioctl()
824 p->rec_size = sndbuf_getblksz(rdch->bufsoft); in dsp_ioctl()
836 ((p->play_format != 0 && p->play_rate == 0) || in dsp_ioctl()
837 (p->rec_format != 0 && p->rec_rate == 0))) { in dsp_ioctl()
844 if (cmd == AIOSFMT && p->play_format != 0) { in dsp_ioctl()
846 SND_FORMAT(p->play_format, in dsp_ioctl()
847 AFMT_CHANNEL(wrch->format), in dsp_ioctl()
848 AFMT_EXTCHANNEL(wrch->format))); in dsp_ioctl()
849 chn_setspeed(wrch, p->play_rate); in dsp_ioctl()
851 p->play_rate = wrch->speed; in dsp_ioctl()
852 p->play_format = AFMT_ENCODING(wrch->format); in dsp_ioctl()
855 p->play_rate = 0; in dsp_ioctl()
856 p->play_format = 0; in dsp_ioctl()
860 if (cmd == AIOSFMT && p->rec_format != 0) { in dsp_ioctl()
862 SND_FORMAT(p->rec_format, in dsp_ioctl()
863 AFMT_CHANNEL(rdch->format), in dsp_ioctl()
864 AFMT_EXTCHANNEL(rdch->format))); in dsp_ioctl()
865 chn_setspeed(rdch, p->rec_rate); in dsp_ioctl()
867 p->rec_rate = rdch->speed; in dsp_ioctl()
868 p->rec_format = AFMT_ENCODING(rdch->format); in dsp_ioctl()
871 p->rec_rate = 0; in dsp_ioctl()
872 p->rec_format = 0; in dsp_ioctl()
893 p->rate_min = max(rcaps? rcaps->minspeed : 0, in dsp_ioctl()
894 pcaps? pcaps->minspeed : 0); in dsp_ioctl()
895 p->rate_max = min(rcaps? rcaps->maxspeed : 1000000, in dsp_ioctl()
896 pcaps? pcaps->maxspeed : 1000000); in dsp_ioctl()
897 p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000, in dsp_ioctl()
898 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000); in dsp_ioctl()
900 p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) & in dsp_ioctl()
903 p->formats |= in dsp_ioctl()
904 (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 0 : in dsp_ioctl()
907 pdev = d->mixer_dev; in dsp_ioctl()
908 p->mixers = 1; /* default: one mixer */ in dsp_ioctl()
909 p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0; in dsp_ioctl()
910 p->left = p->right = 100; in dsp_ioctl()
936 ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos); in dsp_ioctl()
945 /* if (rdch && rdch->bufhard.dl) in dsp_ioctl()
948 *arg_i = sndbuf_getready(rdch->bufsoft); in dsp_ioctl()
960 case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */ in dsp_ioctl()
961 case FIONBIO: /* set/clear non-blocking i/o */ in dsp_ioctl()
965 rdch->flags |= CHN_F_NBIO; in dsp_ioctl()
967 rdch->flags &= ~CHN_F_NBIO; in dsp_ioctl()
973 wrch->flags |= CHN_F_NBIO; in dsp_ioctl()
975 wrch->flags &= ~CHN_F_NBIO; in dsp_ioctl()
981 * Finally, here is the linux-compatible ioctl interface in dsp_ioctl()
989 *arg_i = sndbuf_getblksz(chn->bufsoft); in dsp_ioctl()
1046 tmp = wrch->speed; in dsp_ioctl()
1053 tmp = rdch->speed; in dsp_ioctl()
1064 *arg_i = chn->speed; in dsp_ioctl()
1073 tmp = -1; in dsp_ioctl()
1079 SND_FORMAT(wrch->format, *arg_i, 0)); in dsp_ioctl()
1080 tmp = (AFMT_CHANNEL(wrch->format) > 1)? 1 : 0; in dsp_ioctl()
1086 SND_FORMAT(rdch->format, *arg_i, 0)); in dsp_ioctl()
1087 if (tmp == -1) in dsp_ioctl()
1088 tmp = (AFMT_CHANNEL(rdch->format) > 1)? 1 : 0; in dsp_ioctl()
1109 * (e.g. more than SND_CHN_MAX channels) are not in dsp_ioctl()
1112 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT)) { in dsp_ioctl()
1120 ext = m->ext; in dsp_ioctl()
1127 SND_FORMAT(wrch->format, *arg_i, ext)); in dsp_ioctl()
1128 tmp = AFMT_CHANNEL(wrch->format); in dsp_ioctl()
1134 SND_FORMAT(rdch->format, *arg_i, ext)); in dsp_ioctl()
1136 tmp = AFMT_CHANNEL(rdch->format); in dsp_ioctl()
1144 *arg_i = AFMT_CHANNEL(chn->format); in dsp_ioctl()
1153 *arg_i = AFMT_CHANNEL(chn->format); in dsp_ioctl()
1180 AFMT_CHANNEL(wrch->format), in dsp_ioctl()
1181 AFMT_EXTCHANNEL(wrch->format))); in dsp_ioctl()
1182 tmp = wrch->format; in dsp_ioctl()
1188 AFMT_CHANNEL(rdch->format), in dsp_ioctl()
1189 AFMT_EXTCHANNEL(rdch->format))); in dsp_ioctl()
1191 tmp = rdch->format; in dsp_ioctl()
1199 *arg_i = AFMT_ENCODING(chn->format); in dsp_ioctl()
1227 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft); in dsp_ioctl()
1228 r_fragsz = sndbuf_getblksz(rdch->bufsoft); in dsp_ioctl()
1237 maxfrags = sndbuf_getblkcnt(wrch->bufsoft); in dsp_ioctl()
1238 fragsz = sndbuf_getblksz(wrch->bufsoft); in dsp_ioctl()
1260 struct snd_dbuf *bs = rdch->bufsoft; in dsp_ioctl()
1263 a->bytes = sndbuf_getready(bs); in dsp_ioctl()
1264 a->fragments = a->bytes / sndbuf_getblksz(bs); in dsp_ioctl()
1265 a->fragstotal = sndbuf_getblkcnt(bs); in dsp_ioctl()
1266 a->fragsize = sndbuf_getblksz(bs); in dsp_ioctl()
1278 struct snd_dbuf *bs = wrch->bufsoft; in dsp_ioctl()
1281 a->bytes = sndbuf_getfree(bs); in dsp_ioctl()
1282 a->fragments = a->bytes / sndbuf_getblksz(bs); in dsp_ioctl()
1283 a->fragstotal = sndbuf_getblkcnt(bs); in dsp_ioctl()
1284 a->fragsize = sndbuf_getblksz(bs); in dsp_ioctl()
1295 struct snd_dbuf *bs = rdch->bufsoft; in dsp_ioctl()
1298 a->bytes = sndbuf_gettotal(bs); in dsp_ioctl()
1299 a->blocks = sndbuf_getblocks(bs) - rdch->blocks; in dsp_ioctl()
1300 a->ptr = sndbuf_getfreeptr(bs); in dsp_ioctl()
1301 rdch->blocks = sndbuf_getblocks(bs); in dsp_ioctl()
1312 struct snd_dbuf *bs = wrch->bufsoft; in dsp_ioctl()
1315 a->bytes = sndbuf_gettotal(bs); in dsp_ioctl()
1316 a->blocks = sndbuf_getblocks(bs) - wrch->blocks; in dsp_ioctl()
1317 a->ptr = sndbuf_getreadyptr(bs); in dsp_ioctl()
1318 wrch->blocks = sndbuf_getblocks(bs); in dsp_ioctl()
1328 if (rdch && wrch && !(pcm_getflags(d->dev) & SD_F_SIMPLEX)) in dsp_ioctl()
1330 if (rdch && (rdch->flags & CHN_F_VIRTUAL) != 0) in dsp_ioctl()
1332 if (wrch && (wrch->flags & CHN_F_VIRTUAL) != 0) in dsp_ioctl()
1341 if (chn->format & AFMT_8BIT) in dsp_ioctl()
1343 else if (chn->format & AFMT_16BIT) in dsp_ioctl()
1345 else if (chn->format & AFMT_24BIT) in dsp_ioctl()
1347 else if (chn->format & AFMT_32BIT) in dsp_ioctl()
1361 rdch->flags &= ~CHN_F_NOTRIGGER; in dsp_ioctl()
1367 rdch->flags |= CHN_F_NOTRIGGER; in dsp_ioctl()
1373 wrch->flags &= ~CHN_F_NOTRIGGER; in dsp_ioctl()
1379 wrch->flags |= CHN_F_NOTRIGGER; in dsp_ioctl()
1389 if (wrch->flags & CHN_F_TRIGGERED) in dsp_ioctl()
1395 if (rdch->flags & CHN_F_TRIGGERED) in dsp_ioctl()
1403 struct snd_dbuf *bs = wrch->bufsoft; in dsp_ioctl()
1415 wrch->flags &= ~CHN_F_NOTRIGGER; in dsp_ioctl()
1423 * switch to full-duplex mode if card is in half-duplex in dsp_ioctl()
1424 * mode and is able to work in full-duplex mode in dsp_ioctl()
1427 if (rdch && wrch && (pcm_getflags(d->dev) & SD_F_SIMPLEX)) in dsp_ioctl()
1428 pcm_setflags(d->dev, pcm_getflags(d->dev)^SD_F_SIMPLEX); in dsp_ioctl()
1462 if (ret != -1) { in dsp_ioctl()
1467 if (d->mixer_dev != NULL) { in dsp_ioctl()
1469 ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td, in dsp_ioctl()
1480 if (d->mixer_dev != NULL) { in dsp_ioctl()
1482 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td, in dsp_ioctl()
1499 ei->dev = 0; in dsp_ioctl()
1500 ei->ctrl = 0; in dsp_ioctl()
1501 ei->version = 0; /* static for now */ in dsp_ioctl()
1502 ei->strindex[0] = 0; in dsp_ioctl()
1505 ei->nvalues = 1; in dsp_ioctl()
1506 strlcpy(ei->strings, wrch->name, in dsp_ioctl()
1507 sizeof(ei->strings)); in dsp_ioctl()
1509 ei->nvalues = 0; in dsp_ioctl()
1510 ei->strings[0] = '\0'; in dsp_ioctl()
1530 * Flush the software (pre-feed) buffer, but try to minimize playback in dsp_ioctl()
1540 while (wrch->inprog != 0) in dsp_ioctl()
1541 cv_wait(&wrch->cv, wrch->lock); in dsp_ioctl()
1542 bs = wrch->bufsoft; in dsp_ioctl()
1543 if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) { in dsp_ioctl()
1544 bs->sl = sndbuf_getready(bs); in dsp_ioctl()
1545 sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs)); in dsp_ioctl()
1556 * playback buffer by moving the current write position immediately in dsp_ioctl()
1564 while (wrch->inprog != 0) in dsp_ioctl()
1565 cv_wait(&wrch->cv, wrch->lock); in dsp_ioctl()
1566 bs = wrch->bufsoft; in dsp_ioctl()
1567 if ((bs->shadbuf != NULL) && (bs->sl > 0)) { in dsp_ioctl()
1569 sndbuf_acquire(bs, bs->shadbuf, bs->sl); in dsp_ioctl()
1570 bs->sl = 0; in dsp_ioctl()
1601 bs = chn->bufsoft; in dsp_ioctl()
1602 oc->samples = sndbuf_gettotal(bs) / sndbuf_getalign(bs); in dsp_ioctl()
1603 oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getalign(bs); in dsp_ioctl()
1627 wrch->lw = (*arg_i > 1) ? *arg_i : 1; in dsp_ioctl()
1632 rdch->lw = (*arg_i > 1) ? *arg_i : 1; in dsp_ioctl()
1652 ei->play_underruns = wrch->xruns; in dsp_ioctl()
1653 wrch->xruns = 0; in dsp_ioctl()
1658 ei->rec_overruns = rdch->xruns; in dsp_ioctl()
1659 rdch->xruns = 0; in dsp_ioctl()
1685 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT)) in dsp_ioctl()
1723 if (ret == -1) in dsp_ioctl()
1784 d = priv->sc; in dsp_poll()
1795 wrch = priv->wrch; in dsp_poll()
1796 rdch = priv->rdch; in dsp_poll()
1798 if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) { in dsp_poll()
1804 if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) { in dsp_poll()
1844 * https://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html in dsp_mmap_single()
1866 d = priv->sc; in dsp_mmap_single()
1873 wrch = priv->wrch; in dsp_mmap_single()
1874 rdch = priv->rdch; in dsp_mmap_single()
1877 if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) || in dsp_mmap_single()
1878 (*offset + size) > sndbuf_getallocsize(c->bufsoft) || in dsp_mmap_single()
1879 (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) || in dsp_mmap_single()
1880 (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) { in dsp_mmap_single()
1887 wrch->flags |= CHN_F_MMAP; in dsp_mmap_single()
1889 rdch->flags |= CHN_F_MMAP; in dsp_mmap_single()
1891 *offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset); in dsp_mmap_single()
1894 size, nprot, *offset, curthread->td_ucred); in dsp_mmap_single()
1933 * have returned already, meaning it will have set snd_unit to -1, and in dsp_clone()
1937 *dev = d->dsp_dev; in dsp_clone()
1967 ai->dev = unit; in dsp_oss_audioinfo_unavail()
1968 snprintf(ai->name, sizeof(ai->name), "pcm%d (unavailable)", unit); in dsp_oss_audioinfo_unavail()
1969 ai->pid = -1; in dsp_oss_audioinfo_unavail()
1970 strlcpy(ai->cmd, CHN_COMM_UNUSED, sizeof(ai->cmd)); in dsp_oss_audioinfo_unavail()
1971 ai->card_number = unit; in dsp_oss_audioinfo_unavail()
1972 ai->port_number = unit; in dsp_oss_audioinfo_unavail()
1973 ai->mixer_dev = -1; in dsp_oss_audioinfo_unavail()
1974 ai->legacy_device = unit; in dsp_oss_audioinfo_unavail()
1980 * Gathers information about the audio device specified in ai->dev. If
1981 * ai->dev == -1, then this function gathers information about the current
1982 * device. If the call comes in on a non-audio device and ai->dev == -1,
1986 * getting capabilities directly from the sound card driver, side-stepping
1998 * @retval EINVAL ai->dev specifies an invalid device
2014 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw) in dsp_oss_audioinfo()
2022 if ((ai->dev == -1 && unit == snd_unit) || in dsp_oss_audioinfo()
2023 ai->dev == unit) { in dsp_oss_audioinfo()
2035 if ((ai->dev == -1 && d->dsp_dev == i_dev) || in dsp_oss_audioinfo()
2036 (ai->dev == unit)) { in dsp_oss_audioinfo()
2046 /* Exhausted the search -- nothing is locked, so return. */ in dsp_oss_audioinfo()
2056 ai->dev = unit; in dsp_oss_audioinfo()
2057 strlcpy(ai->name, device_get_desc(d->dev), sizeof(ai->name)); in dsp_oss_audioinfo()
2058 ai->pid = -1; in dsp_oss_audioinfo()
2059 strlcpy(ai->cmd, CHN_COMM_UNKNOWN, sizeof(ai->cmd)); in dsp_oss_audioinfo()
2060 ai->card_number = unit; in dsp_oss_audioinfo()
2061 ai->port_number = unit; in dsp_oss_audioinfo()
2062 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1; in dsp_oss_audioinfo()
2063 ai->legacy_device = unit; in dsp_oss_audioinfo()
2064 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit); in dsp_oss_audioinfo()
2065 ai->enabled = device_is_attached(d->dev) ? 1 : 0; in dsp_oss_audioinfo()
2066 ai->next_play_engine = 0; in dsp_oss_audioinfo()
2067 ai->next_rec_engine = 0; in dsp_oss_audioinfo()
2068 ai->busy = 0; in dsp_oss_audioinfo()
2069 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER; in dsp_oss_audioinfo()
2070 ai->iformats = 0; in dsp_oss_audioinfo()
2071 ai->oformats = 0; in dsp_oss_audioinfo()
2072 ai->min_rate = INT_MAX; in dsp_oss_audioinfo()
2073 ai->max_rate = 0; in dsp_oss_audioinfo()
2074 ai->min_channels = INT_MAX; in dsp_oss_audioinfo()
2075 ai->max_channels = 0; in dsp_oss_audioinfo()
2078 CHN_FOREACH(ch, d, channels.pcm) { in dsp_oss_audioinfo()
2083 * Skip physical channels if we are servicing SNDCTL_AUDIOINFO, in dsp_oss_audioinfo()
2086 * For SNDCTL_AUDIOINFO do not skip the physical channels if in dsp_oss_audioinfo()
2089 if ((ex && (ch->flags & CHN_F_VIRTUAL) != 0) || in dsp_oss_audioinfo()
2090 ((!ex && (ch->flags & CHN_F_VIRTUAL) == 0) && in dsp_oss_audioinfo()
2091 (d->pvchancount > 0 || d->rvchancount > 0))) { in dsp_oss_audioinfo()
2096 if ((ch->flags & CHN_F_BUSY) == 0) { in dsp_oss_audioinfo()
2097 ai->busy |= (ch->direction == PCMDIR_PLAY) ? in dsp_oss_audioinfo()
2101 ai->caps |= in dsp_oss_audioinfo()
2102 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) | in dsp_oss_audioinfo()
2103 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : in dsp_oss_audioinfo()
2111 for (i = 0; caps->fmtlist[i]; i++) { in dsp_oss_audioinfo()
2112 fmts |= AFMT_ENCODING(caps->fmtlist[i]); in dsp_oss_audioinfo()
2113 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch); in dsp_oss_audioinfo()
2114 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch); in dsp_oss_audioinfo()
2117 if (ch->direction == PCMDIR_PLAY) in dsp_oss_audioinfo()
2118 ai->oformats |= fmts; in dsp_oss_audioinfo()
2120 ai->iformats |= fmts; in dsp_oss_audioinfo()
2122 if (ex || (pcm_getflags(d->dev) & SD_F_BITPERFECT)) { in dsp_oss_audioinfo()
2123 ai->min_rate = min(ai->min_rate, caps->minspeed); in dsp_oss_audioinfo()
2124 ai->max_rate = max(ai->max_rate, caps->maxspeed); in dsp_oss_audioinfo()
2126 ai->min_rate = min(ai->min_rate, feeder_rate_min); in dsp_oss_audioinfo()
2127 ai->max_rate = max(ai->max_rate, feeder_rate_max); in dsp_oss_audioinfo()
2129 ai->min_channels = min(ai->min_channels, minch); in dsp_oss_audioinfo()
2130 ai->max_channels = max(ai->max_channels, maxch); in dsp_oss_audioinfo()
2134 if (ai->min_rate == INT_MAX) in dsp_oss_audioinfo()
2135 ai->min_rate = 0; in dsp_oss_audioinfo()
2136 if (ai->min_channels == INT_MAX) in dsp_oss_audioinfo()
2137 ai->min_channels = 0; in dsp_oss_audioinfo()
2150 if (DSP_REGISTERED(priv->sc) && (ch == priv->rdch || ch == priv->wrch)) in dsp_oss_engineinfo_cb()
2159 * Gathers information about the audio device's engine specified in ai->dev.
2160 * If ai->dev == -1, then this function gathers information about the current
2161 * device. If the call comes in on a non-audio device and ai->dev == -1,
2165 * getting capabilities directly from the sound card driver, side-stepping
2175 * @retval EINVAL ai->dev specifies an invalid device
2191 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw) in dsp_oss_engineinfo()
2214 CHN_FOREACH(ch, d, channels.pcm) { in dsp_oss_engineinfo()
2217 if ((ai->dev == -1 && devfs_foreach_cdevpriv( in dsp_oss_engineinfo()
2219 ai->dev == nchan) in dsp_oss_engineinfo()
2233 * - a specific PCM device is locked. in dsp_oss_engineinfo()
2234 * - a specific audio channel has been locked, so be in dsp_oss_engineinfo()
2246 ai->dev = nchan; in dsp_oss_engineinfo()
2247 strlcpy(ai->name, ch->name, sizeof(ai->name)); in dsp_oss_engineinfo()
2249 if ((ch->flags & CHN_F_BUSY) == 0) in dsp_oss_engineinfo()
2250 ai->busy = 0; in dsp_oss_engineinfo()
2252 ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ; in dsp_oss_engineinfo()
2254 ai->pid = ch->pid; in dsp_oss_engineinfo()
2255 strlcpy(ai->cmd, ch->comm, sizeof(ai->cmd)); in dsp_oss_engineinfo()
2263 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep in dsp_oss_engineinfo()
2266 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER | in dsp_oss_engineinfo()
2267 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) | in dsp_oss_engineinfo()
2268 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : PCM_CAP_INPUT); in dsp_oss_engineinfo()
2272 * device. Also determine min/max channels. in dsp_oss_engineinfo()
2277 for (i = 0; caps->fmtlist[i]; i++) { in dsp_oss_engineinfo()
2278 fmts |= AFMT_ENCODING(caps->fmtlist[i]); in dsp_oss_engineinfo()
2279 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch); in dsp_oss_engineinfo()
2280 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch); in dsp_oss_engineinfo()
2283 if (ch->direction == PCMDIR_PLAY) in dsp_oss_engineinfo()
2284 ai->oformats = fmts; in dsp_oss_engineinfo()
2286 ai->iformats = fmts; in dsp_oss_engineinfo()
2290 * @c magic - OSSv4 docs: "Reserved for internal use in dsp_oss_engineinfo()
2294 * @c card_number - OSSv4 docs: "Number of the sound in dsp_oss_engineinfo()
2295 * card where this device belongs or -1 if this in dsp_oss_engineinfo()
2300 ai->card_number = unit; in dsp_oss_engineinfo()
2302 * @todo @c song_name - depends first on in dsp_oss_engineinfo()
2303 * SNDCTL_[GS]ETSONG @todo @c label - depends in dsp_oss_engineinfo()
2305 * @todo @c port_number - routing information? in dsp_oss_engineinfo()
2307 ai->port_number = unit; in dsp_oss_engineinfo()
2308 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1; in dsp_oss_engineinfo()
2311 * @c legacy_device - OSSv4 docs: "Obsolete." in dsp_oss_engineinfo()
2313 ai->legacy_device = unit; in dsp_oss_engineinfo()
2314 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit); in dsp_oss_engineinfo()
2315 ai->enabled = device_is_attached(d->dev) ? 1 : 0; in dsp_oss_engineinfo()
2318 * @c flags - OSSv4 docs: "Reserved for future use." in dsp_oss_engineinfo()
2321 * @c binding - OSSv4 docs: "Reserved for future use." in dsp_oss_engineinfo()
2323 * @todo @c handle - haven't decided how to generate in dsp_oss_engineinfo()
2327 if ((ch->flags & CHN_F_EXCLUSIVE) || in dsp_oss_engineinfo()
2328 (pcm_getflags(d->dev) & SD_F_BITPERFECT)) { in dsp_oss_engineinfo()
2329 ai->min_rate = caps->minspeed; in dsp_oss_engineinfo()
2330 ai->max_rate = caps->maxspeed; in dsp_oss_engineinfo()
2332 ai->min_rate = feeder_rate_min; in dsp_oss_engineinfo()
2333 ai->max_rate = feeder_rate_max; in dsp_oss_engineinfo()
2336 ai->min_channels = minch; in dsp_oss_engineinfo()
2337 ai->max_channels = maxch; in dsp_oss_engineinfo()
2339 ai->nrates = chn_getrates(ch, &rates); in dsp_oss_engineinfo()
2340 if (ai->nrates > OSS_MAX_SAMPLE_RATES) in dsp_oss_engineinfo()
2341 ai->nrates = OSS_MAX_SAMPLE_RATES; in dsp_oss_engineinfo()
2343 for (i = 0; i < ai->nrates; i++) in dsp_oss_engineinfo()
2344 ai->rates[i] = rates[i]; in dsp_oss_engineinfo()
2346 ai->next_play_engine = 0; in dsp_oss_engineinfo()
2347 ai->next_rec_engine = 0; in dsp_oss_engineinfo()
2357 /* Exhausted the search -- nothing is locked, so return. */ in dsp_oss_engineinfo()
2383 * @retval non-zero error to be propagated upstream
2406 * - Insert channel(s) into group's member list. in dsp_oss_syncgroup()
2407 * - Set CHN_F_NOTRIGGER on channel(s). in dsp_oss_syncgroup()
2408 * - Stop channel(s). in dsp_oss_syncgroup()
2412 * If device's channels are already mapped to a group, unmap them. in dsp_oss_syncgroup()
2426 * - Bail if PCM_ENABLE_OUTPUT && wrch == NULL. in dsp_oss_syncgroup()
2427 * - Bail if PCM_ENABLE_INPUT && rdch == NULL. in dsp_oss_syncgroup()
2429 if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) || in dsp_oss_syncgroup()
2430 ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) { in dsp_oss_syncgroup()
2439 if (group->id == 0) { in dsp_oss_syncgroup()
2442 SLIST_INIT(&sg->members); in dsp_oss_syncgroup()
2443 sg->id = alloc_unr(pcmsg_unrhdr); in dsp_oss_syncgroup()
2445 group->id = sg->id; in dsp_oss_syncgroup()
2451 if (sg->id == group->id) in dsp_oss_syncgroup()
2466 if (group->mode & PCM_ENABLE_INPUT) { in dsp_oss_syncgroup()
2473 SLIST_INSERT_HEAD(&sg->members, smrd, link); in dsp_oss_syncgroup()
2474 smrd->parent = sg; in dsp_oss_syncgroup()
2475 smrd->ch = rdch; in dsp_oss_syncgroup()
2478 rdch->flags |= CHN_F_NOTRIGGER; in dsp_oss_syncgroup()
2479 rdch->sm = smrd; in dsp_oss_syncgroup()
2482 if (group->mode & PCM_ENABLE_OUTPUT) { in dsp_oss_syncgroup()
2489 SLIST_INSERT_HEAD(&sg->members, smwr, link); in dsp_oss_syncgroup()
2490 smwr->parent = sg; in dsp_oss_syncgroup()
2491 smwr->ch = wrch; in dsp_oss_syncgroup()
2494 wrch->flags |= CHN_F_NOTRIGGER; in dsp_oss_syncgroup()
2495 wrch->sm = smwr; in dsp_oss_syncgroup()
2502 if ((sg != NULL) && SLIST_EMPTY(&sg->members)) { in dsp_oss_syncgroup()
2503 sg_ids[2] = sg->id; in dsp_oss_syncgroup()
2509 wrch->sm = NULL; in dsp_oss_syncgroup()
2511 rdch->sm = NULL; in dsp_oss_syncgroup()
2542 * @retval non-zero error worthy of propagating upstream to user
2561 if (sg->id == sg_id) in dsp_oss_syncstart()
2572 KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup")); in dsp_oss_syncstart()
2575 * Attempt to lock all member channels - if any are already in dsp_oss_syncstart()
2579 SLIST_FOREACH(sm, &sg->members, link) { in dsp_oss_syncstart()
2580 if (CHN_TRYLOCK(sm->ch) == 0) { in dsp_oss_syncstart()
2585 /* Release all locked channels so far, retry */ in dsp_oss_syncstart()
2586 SLIST_FOREACH(sm_tmp, &sg->members, link) { in dsp_oss_syncstart()
2590 CHN_UNLOCK(sm_tmp->ch); in dsp_oss_syncstart()
2607 /* Launch channels */ in dsp_oss_syncstart()
2608 while ((sm = SLIST_FIRST(&sg->members)) != NULL) { in dsp_oss_syncstart()
2609 SLIST_REMOVE_HEAD(&sg->members, link); in dsp_oss_syncstart()
2611 c = sm->ch; in dsp_oss_syncstart()
2612 c->sm = NULL; in dsp_oss_syncstart()
2614 c->flags &= ~CHN_F_NOTRIGGER; in dsp_oss_syncstart()
2660 * @param wrch Pointer to opened playback channel (optional; may be NULL)
2704 * a sound card's buffer space directly, bypassing the FreeBSD 2-stage
2711 * @param wrch playback channel (optional; may be NULL)
2725 * <insert any non-printable characters here>. in dsp_oss_cookedmode()
2739 wrch->flags &= ~CHN_F_BITPERFECT; in dsp_oss_cookedmode()
2740 wrch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000; in dsp_oss_cookedmode()
2746 rdch->flags &= ~CHN_F_BITPERFECT; in dsp_oss_cookedmode()
2747 rdch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000; in dsp_oss_cookedmode()
2765 * @param wrch playback channel (optional; may be NULL)
2796 * @param wrch playback channel (optional; may be NULL)
2865 * @param wrch playback channel (optional; may be NULL)
2889 * @param wrch playback channel (optional; may be NULL)
2914 * @param wrch playback channel (optional; may be NULL)
2939 * @param wrch playback channel (optional; may be NULL)
2968 * @param wrch playback channel (optional; may be NULL)