Lines Matching +full:pcm +full:- +full:interface +full:- +full:rate

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