32#ifdef HAVE_KERNEL_OPTION_HEADERS
45#define FMTLIST_OFFSET 4
49static int snd_passthrough_verbose = 0;
50SYSCTL_INT(_hw_snd, OID_AUTO, passthrough_verbose, CTLFLAG_RWTUN,
51 &snd_passthrough_verbose, 0,
"passthrough verbosity");
68 uint32_t i, j, *fmtlist;
71 (
"vchan_init: bad direction"));
73 (
"vchan_init: bad channels"));
75 info = malloc(
sizeof(*info), M_DEVBUF, M_WAITOK | M_ZERO);
83 for (i = 0, j = 0; fmtlist[i] != 0 && j <
DIGFMTS_MAX; i++) {
85 info->
fmtlist[j++] = fmtlist[i];
192 uint32_t pformat, pspeed, pflags, i;
222 device_printf(
c->
dev,
223 "%s(): invalid vchan format 0x%08x",
231 return (&info->
caps);
259 KASSERT(d != NULL, (
"%s(): NULL snddev_info", __func__));
299 int direction, vchancount;
335 err = sysctl_handle_int(oidp, &cnt, 0,
req);
337 if (err == 0 &&
req->newptr != NULL && vchancount != cnt) {
397 strlcpy(dtype,
"passthrough",
sizeof(dtype));
399 strlcpy(dtype,
"adaptive",
sizeof(dtype));
401 strlcpy(dtype,
"fixed",
sizeof(dtype));
404 ret = sysctl_handle_string(oidp, dtype,
sizeof(dtype),
req);
405 if (ret == 0 &&
req->newptr != NULL) {
406 if (strcasecmp(dtype,
"passthrough") == 0 ||
407 strcmp(dtype,
"1") == 0)
409 else if (strcasecmp(dtype,
"adaptive") == 0 ||
410 strcmp(dtype,
"2") == 0)
412 else if (strcasecmp(dtype,
"fixed") == 0 ||
413 strcmp(dtype,
"0") == 0)
426 c->
flags &= ~CHN_F_VCHAN_DYNAMIC;
440#define VCHAN_ACCESSIBLE(c) (!((c)->flags & (CHN_F_PASSTHROUGH | \
441 CHN_F_EXCLUSIVE)) && \
442 (((c)->flags & CHN_F_VCHAN_DYNAMIC) || \
450 int *vchanrate, vchancount, direction, ret, newspd, restart;
476 if (vchancount < 1) {
494 KASSERT(direction ==
c->
direction, (
"%s(): invalid direction %d/%d",
501 ret = sysctl_handle_int(oidp, &newspd, 0,
req);
502 if (ret != 0 ||
req->newptr == NULL) {
525 newspd = CHANNEL_SETSPEED(
c->
methods,
558 int *vchanformat, vchancount,
direction, ret, restart;
585 if (vchancount < 1) {
608 bzero(fmtstr,
sizeof(fmtstr));
611 strlcpy(fmtstr,
"<ERROR>",
sizeof(fmtstr));
615 ret = sysctl_handle_string(oidp, fmtstr,
sizeof(fmtstr),
req);
616 if (ret != 0 ||
req->newptr == NULL) {
661#define VCHAN_FMT_HINT(x) ((x) == PCMDIR_PLAY_VIRTUAL) ? \
662 "play.vchanformat" : "rec.vchanformat"
663#define VCHAN_SPD_HINT(x) ((x) == PCMDIR_PLAY_VIRTUAL) ? \
664 "play.vchanrate" : "rec.vchanrate"
672 uint32_t vchanfmt, vchanspd;
673 int ret, direction,
r, save;
703 ch =
pcm_chn_create(d, parent, &vchan_class, direction, num, parent);
733 if (parent_caps == NULL)
738 if (ret == 0 && vchanfmt == 0) {
742 r = resource_string_value(device_get_name(parent->
dev),
750 if (vchanfmt != 0 && !(vchanfmt &
AFMT_VCHAN))
758 if (ret == 0 && vchanspd == 0) {
766 r = resource_int_value(device_get_name(parent->
dev),
784 if (vchanspd > parent_caps->
maxspeed)
788 if (vchanspd < parent_caps->
minspeed)
806 vchanspd = CHANNEL_SETSPEED(parent->
methods,
810 ret =
chn_reset(parent, vchanfmt, vchanspd);
813 if (ret == 0 && save) {
831 parent->
flags &= ~CHN_F_VCHAN_DYNAMIC;
837 parent->
flags &= ~CHN_F_HAS_VCHAN;
904vchan_passthrough(
struct pcm_channel *
c,
const char *caller)
913 (
"%s(): invalid passthrough", __func__));
925 if (snd_passthrough_verbose != 0) {
929 device_printf(
c->
dev,
930 "%s(%s/%s) %s() -> re-sync err=%d\n",
931 __func__, (devname != NULL) ? devname :
"dspX",
c->
comm,
945 unit = device_get_unit(
dev);
946 d = device_get_softc(
dev);
949 SYSCTL_ADD_PROC(&d->play_sysctl_ctx,
951 OID_AUTO,
"vchans", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
954 SYSCTL_ADD_PROC(&d->play_sysctl_ctx,
956 OID_AUTO,
"vchanmode",
957 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
960 "vchan format/rate selection: 0=fixed, 1=passthrough, 2=adaptive");
961 SYSCTL_ADD_PROC(&d->play_sysctl_ctx,
963 OID_AUTO,
"vchanrate",
964 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
967 SYSCTL_ADD_PROC(&d->play_sysctl_ctx,
969 OID_AUTO,
"vchanformat",
970 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
977 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
982 OID_AUTO,
"vchanmode",
983 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
986 "vchan format/rate selection: 0=fixed, 1=passthrough, 2=adaptive");
989 OID_AUTO,
"vchanrate",
990 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
995 OID_AUTO,
"vchanformat",
996 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
void sndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
int chn_reset(struct pcm_channel *c, uint32_t fmt, uint32_t spd)
uint32_t snd_str2afmt(const char *req)
uint32_t snd_afmt2str(uint32_t afmt, char *buf, size_t len)
struct pcmchan_caps * chn_getcaps(struct pcm_channel *c)
int chn_notify(struct pcm_channel *c, u_int32_t flags)
int chn_abort(struct pcm_channel *c)
int snd_fmtvalid(uint32_t fmt, uint32_t *fmtlist)
u_int32_t chn_start(struct pcm_channel *c, int force)
#define PCMDIR_PLAY_VIRTUAL
#define CHN_F_PASSTHROUGH
#define CHN_F_VCHAN_ADAPTIVE
#define CHN_F_VCHAN_PASSTHROUGH
#define CHN_INSERT_HEAD(x, y, z)
#define CHN_FOREACH(x, y, z)
#define CHN_LOCKASSERT(c)
#define PCMDIR_REC_VIRTUAL
#define CHN_INSERT_SORT_DESCEND(x, y, z)
#define CHN_REMOVE(x, y, z)
#define CHN_F_VCHAN_DYNAMIC
#define PCMTRIG_COMMON(x)
char * dsp_unit2name(char *buf, size_t len, int unit)
struct pcmchan_matrix * feeder_matrix_format_map(uint32_t)
int feeder_chain(struct pcm_channel *)
SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "")
#define RANGE(var, low, high)
int pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num)
struct pcm_channel * pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo)
int pcm_chn_destroy(struct pcm_channel *ch)
int pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
int pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
#define PCM_RELEASE_QUICK(x)
#define PCM_BUSYASSERT(x)
#define PCM_UNLOCKASSERT(d)
#define PCM_REGISTERED(x)
struct pcm_channel::@28 channels
struct pcm_channel::@27 children
struct pcm_channel::@27::@29 busy
struct snd_dbuf * bufhard
struct pcm_channel * parentchannel
struct snddev_info * parentsnddev
struct sysctl_oid * play_sysctl_tree
struct sysctl_ctx_list play_sysctl_ctx rec_sysctl_ctx
struct sysctl_oid * rec_sysctl_tree
uint32_t fmtlist[FMTLIST_MAX]
struct pcm_channel * channel
int vchan_destroy(struct pcm_channel *c)
static int vchan_free(kobj_t obj, void *data)
static struct pcmchan_caps * vchan_getcaps(kobj_t obj, void *data)
static uint32_t vchan_setspeed(kobj_t obj, void *data, uint32_t speed)
static int sysctl_dev_pcm_vchanrate(SYSCTL_HANDLER_ARGS)
static void pcm_getparentchannel(struct snddev_info *d, struct pcm_channel **wrch, struct pcm_channel **rdch)
static void * vchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
static struct pcmchan_matrix * vchan_getmatrix(kobj_t obj, void *data, uint32_t format)
static int sysctl_dev_pcm_vchanformat(SYSCTL_HANDLER_ARGS)
int vchan_sync(struct pcm_channel *c)
SND_DECLARE_FILE("$FreeBSD$")
int vchan_create(struct pcm_channel *parent, int num)
static int vchan_trigger(kobj_t obj, void *data, int go)
#define VCHAN_SPD_HINT(x)
static int sysctl_dev_pcm_vchanmode(SYSCTL_HANDLER_ARGS)
#define VCHAN_FMT_HINT(x)
static kobj_method_t vchan_methods[]
static int sysctl_dev_pcm_vchans(SYSCTL_HANDLER_ARGS)
static int vchan_setformat(kobj_t obj, void *data, uint32_t format)
void vchan_initsys(device_t dev)
#define VCHAN_ACCESSIBLE(c)
#define VCHAN_DEFAULT_FORMAT
#define VCHAN_DEFAULT_RATE
#define VCHAN_SYSCTL_DATA(x, y)
#define VCHAN_SYSCTL_DIR(x)
#define VCHAN_SYSCTL_DATA_SIZE
#define VCHAN_SYNC_REQUIRED(c)
#define VCHAN_SYSCTL_UNIT(x)