Lines Matching +full:pcm +full:- +full:sync +full:- +full:mode
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2006-2009 Ariff Abdullah <ariff@FreeBSD.org>
34 /* Almost entirely rewritten to add multi-format/channels mixing support. */
40 #include <dev/sound/pcm/sound.h>
41 #include <dev/sound/pcm/vchan.h>
76 KASSERT(c != NULL && c->parentchannel != NULL,
80 info->channel = c;
81 info->trigger = PCMTRIG_STOP;
82 p = c->parentchannel;
86 fmtlist = chn_getcaps(p)->fmtlist;
89 info->fmtlist[j++] = fmtlist[i];
91 if (p->format & AFMT_VCHAN)
92 info->fmtlist[j] = p->format;
94 info->fmtlist[j] = VCHAN_DEFAULT_FORMAT;
95 info->caps.fmtlist = info->fmtlist +
96 ((p->flags & CHN_F_VCHAN_DYNAMIC) ? 0 : FMTLIST_OFFSET);
100 c->flags |= CHN_F_VIRTUAL;
121 CHN_LOCKASSERT(info->channel);
123 if (!snd_fmtvalid(format, info->caps.fmtlist))
124 return (-1);
136 CHN_LOCKASSERT(info->channel);
138 return (info->caps.maxspeed);
149 c = info->channel;
150 p = c->parentchannel;
153 if (!PCMTRIG_COMMON(go) || go == info->trigger)
159 otrigger = info->trigger;
160 info->trigger = go;
198 c = info->channel;
199 pformat = c->parentchannel->format;
200 pspeed = c->parentchannel->speed;
201 pflags = c->parentchannel->flags;
206 info->caps.fmtlist = info->fmtlist;
208 for (i = 0; info->caps.fmtlist[i] != 0; i++) {
209 if (info->caps.fmtlist[i] & AFMT_PASSTHROUGH)
213 info->caps.fmtlist[i] = pformat;
215 if (c->format & AFMT_PASSTHROUGH)
216 info->caps.minspeed = c->speed;
218 info->caps.minspeed = pspeed;
219 info->caps.maxspeed = info->caps.minspeed;
221 info->caps.fmtlist = info->fmtlist + FMTLIST_OFFSET;
223 info->caps.fmtlist[0] = pformat;
225 device_printf(c->dev,
228 info->caps.fmtlist[0] = VCHAN_DEFAULT_FORMAT;
230 info->caps.minspeed = pspeed;
231 info->caps.maxspeed = info->caps.minspeed;
234 return (&info->caps);
270 CHN_FOREACH(c, d, channels.pcm) {
272 ch = (c->direction == PCMDIR_PLAY) ? &wch : &rch;
273 if (c->flags & CHN_F_VIRTUAL) {
275 if (*ch != NULL && *ch != c->parentchannel) {
280 } else if (c->flags & CHN_F_HAS_VCHAN) {
305 d = devclass_get_softc(pcm_devclass, VCHAN_SYSCTL_UNIT(oidp->oid_arg1));
306 if (!PCM_REGISTERED(d) || !(d->flags & SD_F_AUTOVCHAN))
312 switch (VCHAN_SYSCTL_DIR(oidp->oid_arg1)) {
315 vchancount = d->pvchancount;
316 cnt = d->playcount;
320 vchancount = d->rvchancount;
321 cnt = d->reccount;
340 if (err == 0 && req->newptr != NULL && vchancount != cnt) {
362 d = devclass_get_softc(pcm_devclass, VCHAN_SYSCTL_UNIT(oidp->oid_arg1));
363 if (!PCM_REGISTERED(d) || !(d->flags & SD_F_AUTOVCHAN))
369 switch (VCHAN_SYSCTL_DIR(oidp->oid_arg1)) {
395 KASSERT(direction == c->direction, ("%s(): invalid direction %d/%d",
396 __func__, direction, c->direction));
399 if (c->flags & CHN_F_VCHAN_PASSTHROUGH)
401 else if (c->flags & CHN_F_VCHAN_ADAPTIVE)
408 if (ret == 0 && req->newptr != NULL) {
423 if (dflags == (c->flags & CHN_F_VCHAN_DYNAMIC) ||
424 (c->flags & CHN_F_PASSTHROUGH)) {
429 c->flags &= ~CHN_F_VCHAN_DYNAMIC;
430 c->flags |= dflags;
443 #define VCHAN_ACCESSIBLE(c) (!((c)->flags & (CHN_F_PASSTHROUGH | \
445 (((c)->flags & CHN_F_VCHAN_DYNAMIC) || \
455 d = devclass_get_softc(pcm_devclass, VCHAN_SYSCTL_UNIT(oidp->oid_arg1));
456 if (!PCM_REGISTERED(d) || !(d->flags & SD_F_AUTOVCHAN))
462 switch (VCHAN_SYSCTL_DIR(oidp->oid_arg1)) {
465 vchancount = d->pvchancount;
466 vchanrate = &d->pvchanrate;
470 vchancount = d->rvchancount;
471 vchanrate = &d->rvchanrate;
497 KASSERT(direction == c->direction, ("%s(): invalid direction %d/%d",
498 __func__, direction, c->direction));
501 newspd = c->speed;
505 if (ret != 0 || req->newptr == NULL) {
517 if (newspd != c->speed && VCHAN_ACCESSIBLE(c)) {
526 RANGE(newspd, caps->minspeed, caps->maxspeed);
527 newspd = CHANNEL_SETSPEED(c->methods,
528 c->devinfo, newspd);
531 ret = chn_reset(c, c->format, newspd);
533 *vchanrate = c->speed;
541 c->flags |= CHN_F_DIRTY;
563 d = devclass_get_softc(pcm_devclass, VCHAN_SYSCTL_UNIT(oidp->oid_arg1));
564 if (!PCM_REGISTERED(d) || !(d->flags & SD_F_AUTOVCHAN))
570 switch (VCHAN_SYSCTL_DIR(oidp->oid_arg1)) {
573 vchancount = d->pvchancount;
574 vchanformat = &d->pvchanformat;
578 vchancount = d->rvchancount;
579 vchanformat = &d->rvchanformat;
605 KASSERT(direction == c->direction, ("%s(): invalid direction %d/%d",
606 __func__, direction, c->direction));
612 if (snd_afmt2str(c->format, fmtstr, sizeof(fmtstr)) != c->format)
618 if (ret != 0 || req->newptr == NULL) {
631 if (newfmt != c->format && VCHAN_ACCESSIBLE(c)) {
638 ret = chn_reset(c, newfmt, c->speed);
640 *vchanformat = c->format;
648 c->flags |= CHN_F_DIRTY;
680 d = parent->parentsnddev;
685 if (!(parent->flags & CHN_F_BUSY))
688 if (!(parent->direction == PCMDIR_PLAY ||
689 parent->direction == PCMDIR_REC))
695 if (parent->direction == PCMDIR_PLAY) {
697 vchanfmt = d->pvchanformat;
698 vchanspd = d->pvchanrate;
701 vchanfmt = d->rvchanformat;
702 vchanspd = d->rvchanrate;
722 if (parent->flags & CHN_F_HAS_VCHAN)
725 parent->flags |= CHN_F_HAS_VCHAN;
737 r = resource_string_value(device_get_name(parent->dev),
738 device_get_unit(parent->dev), VCHAN_FMT_HINT(direction),
761 r = resource_int_value(device_get_name(parent->dev),
762 device_get_unit(parent->dev), VCHAN_SPD_HINT(direction),
768 RANGE(vchanspd, parent_caps->minspeed,
769 parent_caps->maxspeed);
775 * Limit the speed between feeder_rate_min <-> feeder_rate_max.
780 RANGE(vchanspd, parent_caps->minspeed,
781 parent_caps->maxspeed);
782 vchanspd = CHANNEL_SETSPEED(parent->methods,
783 parent->devinfo, vchanspd);
794 d->pvchanformat = parent->format;
795 d->pvchanrate = parent->speed;
797 d->rvchanformat = parent->format;
798 d->rvchanrate = parent->speed;
804 * enable passthrough mode.
806 if (snd_fmtvalid(AFMT_PASSTHROUGH, parent_caps->fmtlist)) {
807 parent->flags &= ~CHN_F_VCHAN_DYNAMIC;
808 parent->flags |= CHN_F_VCHAN_PASSTHROUGH;
815 parent->flags &= ~CHN_F_HAS_VCHAN;
828 KASSERT(c != NULL && c->parentchannel != NULL &&
829 c->parentsnddev != NULL, ("%s(): invalid channel=%p",
834 parent = c->parentchannel;
836 PCM_BUSYASSERT(c->parentsnddev);
841 if (!(parent->flags & CHN_F_BUSY))
851 parent->flags &= ~(CHN_F_BUSY | CHN_F_HAS_VCHAN);
852 chn_reset(parent, parent->format, parent->speed);
874 KASSERT(c != NULL && c->parentchannel != NULL &&
875 (c->flags & CHN_F_VIRTUAL),
878 CHN_LOCKASSERT(c->parentchannel);
880 sndbuf_setspd(c->bufhard, c->parentchannel->speed);
881 c->flags |= CHN_F_PASSTHROUGH;
883 c->flags &= ~(CHN_F_DIRTY | CHN_F_PASSTHROUGH);
885 c->flags |= CHN_F_DIRTY;
889 device_printf(c->dev, "%s(%s/%s) %s() -> re-sync err=%d\n",
890 __func__, c->name, c->comm, caller, ret);
906 if ((direction == PCMDIR_PLAY && d->playcount < 1) ||
907 (direction == PCMDIR_REC && d->reccount < 1))
910 if (!(d->flags & SD_F_AUTOVCHAN))
917 vcnt = d->pvchancount;
919 vcnt = d->rvchancount;
924 /* add new vchans - find a parent channel first */
926 CHN_FOREACH(c, d, channels.pcm) {
928 if (c->direction == direction &&
929 ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 &&
930 !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) {
935 if (c->flags & CHN_F_HAS_VCHAN) {
948 for (i = 0; caps->fmtlist[i] != 0; i++) {
949 if (caps->fmtlist[i] & AFMT_CONVERTIBLE)
952 if (caps->fmtlist[i] != 0) {
961 ch->flags |= CHN_F_BUSY;
968 device_printf(d->dev,
973 ch->flags &= ~CHN_F_BUSY;
978 CHN_FOREACH(c, d, channels.pcm) {
980 if (c->direction != direction ||
982 !(c->flags & CHN_F_HAS_VCHAN)) {
988 if (vcnt == 1 && ch->flags & CHN_F_BUSY) {
992 if (!(ch->flags & CHN_F_BUSY)) {
995 vcnt--;
1017 if (num >= 0 && d->pvchancount > num)
1019 else if (num > 0 && d->pvchancount == 0)
1022 if (num >= 0 && d->rvchancount > num)
1024 else if (num > 0 && d->rvchancount == 0)
1036 if (error == 0 && req->newptr != NULL) {
1068 SYSCTL_ADD_PROC(&d->play_sysctl_ctx,
1069 SYSCTL_CHILDREN(d->play_sysctl_tree),
1073 SYSCTL_ADD_PROC(&d->play_sysctl_ctx,
1074 SYSCTL_CHILDREN(d->play_sysctl_tree),
1080 SYSCTL_ADD_PROC(&d->play_sysctl_ctx,
1081 SYSCTL_CHILDREN(d->play_sysctl_tree),
1086 SYSCTL_ADD_PROC(&d->play_sysctl_ctx,
1087 SYSCTL_CHILDREN(d->play_sysctl_tree),
1093 SYSCTL_ADD_PROC(&d->rec_sysctl_ctx,
1094 SYSCTL_CHILDREN(d->rec_sysctl_tree),
1099 SYSCTL_ADD_PROC(&d->rec_sysctl_ctx,
1100 SYSCTL_CHILDREN(d->rec_sysctl_tree),
1106 SYSCTL_ADD_PROC(&d->rec_sysctl_ctx,
1107 SYSCTL_CHILDREN(d->rec_sysctl_tree),
1112 SYSCTL_ADD_PROC(&d->rec_sysctl_ctx,
1113 SYSCTL_CHILDREN(d->rec_sysctl_tree),