Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133083904
D26884.id78551.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D26884.id78551.diff
View Options
Index: sys/dev/sound/pcm/sndstat.c
===================================================================
--- sys/dev/sound/pcm/sndstat.c
+++ sys/dev/sound/pcm/sndstat.c
@@ -31,10 +31,19 @@
#include "opt_snd.h"
#endif
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/nv.h>
+#include <sys/sx.h>
+#ifdef COMPAT_FREEBSD32
+#include <sys/sysent.h>
+#endif
+
#include <dev/sound/pcm/sound.h>
#include <dev/sound/pcm/pcm.h>
#include <dev/sound/version.h>
-#include <sys/sx.h>
+
SND_DECLARE_FILE("$FreeBSD$");
@@ -47,12 +56,14 @@
static void sndstat_close(void *);
static d_read_t sndstat_read;
static d_write_t sndstat_write;
+static d_ioctl_t sndstat_ioctl;
static struct cdevsw sndstat_cdevsw = {
.d_version = D_VERSION,
.d_open = sndstat_open,
.d_read = sndstat_read,
.d_write = sndstat_write,
+ .d_ioctl = sndstat_ioctl,
.d_name = "sndstat",
.d_flags = D_TRACKCLOSE,
};
@@ -65,11 +76,24 @@
int type, unit;
};
+struct sndstat_userdev {
+ TAILQ_ENTRY(sndstat_userdev) link;
+ char *devnode;
+ char *desc;
+ unsigned int pchan;
+ unsigned int rchan;
+};
+
struct sndstat_file {
TAILQ_ENTRY(sndstat_file) entry;
struct sbuf sbuf;
+ struct sx lock;
+ void *devs_nvlbuf; /* (l) */
+ size_t devs_nbytes; /* (l) */
+ TAILQ_HEAD(, sndstat_userdev) userdev_list; /* (l) */
int out_offset;
int in_offset;
+ int fflags;
};
static struct sx sndstat_lock;
@@ -84,6 +108,8 @@
int snd_verbose = 0;
static int sndstat_prepare(struct sndstat_file *);
+static struct sndstat_userdev *
+sndstat_line2userdev(struct sndstat_file *, const char *, int);
static int
sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
@@ -112,12 +138,19 @@
pf = malloc(sizeof(*pf), M_DEVBUF, M_WAITOK | M_ZERO);
- SNDSTAT_LOCK();
if (sbuf_new(&pf->sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
SNDSTAT_UNLOCK();
free(pf, M_DEVBUF);
return (ENOMEM);
}
+
+ pf->devs_nvlbuf = NULL;
+ pf->devs_nbytes = 0;
+ pf->fflags = flags;
+ TAILQ_INIT(&pf->userdev_list);
+ sx_init(&pf->lock, "sndstat_file");
+
+ SNDSTAT_LOCK();
TAILQ_INSERT_TAIL(&sndstat_filelist, pf, entry);
SNDSTAT_UNLOCK();
@@ -126,6 +159,23 @@
return (0);
}
+/*
+ * Should only be called either when:
+ * * Closing
+ * * pf->lock held
+ */
+static void
+sndstat_remove_all_userdevs(struct sndstat_file *pf)
+{
+ struct sndstat_userdev *ud, *tud;
+ TAILQ_FOREACH_SAFE(ud, &pf->userdev_list, link, tud) {
+ TAILQ_REMOVE(&pf->userdev_list, ud, link);
+ free(ud->desc, M_DEVBUF);
+ free(ud->devnode, M_DEVBUF);
+ free(ud, M_DEVBUF);
+ }
+}
+
static void
sndstat_close(void *sndstat_file)
{
@@ -136,6 +186,10 @@
TAILQ_REMOVE(&sndstat_filelist, pf, entry);
SNDSTAT_UNLOCK();
+ free(pf->devs_nvlbuf, M_NVLIST);
+ sndstat_remove_all_userdevs(pf);
+ sx_destroy(&pf->lock);
+
free(pf, M_DEVBUF);
}
@@ -203,7 +257,10 @@
err = EINVAL;
} else {
/* only remember the last write - allows for updates */
- sbuf_clear(&pf->sbuf);
+ sx_xlock(&pf->lock);
+ sndstat_remove_all_userdevs(pf);
+ sx_xunlock(&pf->lock);
+
while (1) {
len = sizeof(temp);
if (len > buf->uio_resid)
@@ -221,15 +278,448 @@
}
}
sbuf_finish(&pf->sbuf);
- if (err == 0)
+
+ if (err == 0) {
+ char *line, *str;
+
+ str = sbuf_data(&pf->sbuf);
+ while ((line = strsep(&str, "\n")) != NULL) {
+ struct sndstat_userdev *ud;
+
+ ud = sndstat_line2userdev(pf, line, strlen(line));
+ if (ud == NULL)
+ continue;
+
+ sx_xlock(&pf->lock);
+ TAILQ_INSERT_TAIL(&pf->userdev_list, ud, link);
+ sx_xunlock(&pf->lock);
+ }
+
pf->out_offset = sbuf_len(&pf->sbuf);
- else
+ } else
pf->out_offset = 0;
+
+ sbuf_clear(&pf->sbuf);
+ }
+ SNDSTAT_UNLOCK();
+ return (err);
+}
+
+/*
+ * Should only be called with the following locks held:
+ * * sndstat_lock
+ */
+static int
+sndstat_create_devs_nvlist(nvlist_t **nvlp)
+{
+ int err;
+ nvlist_t *nvl;
+ struct sndstat_entry *ent;
+ struct sndstat_file *pf;
+
+ nvl = nvlist_create(0);
+ if (nvl == NULL)
+ return (ENOMEM);
+
+ TAILQ_FOREACH (ent, &sndstat_devlist, link) {
+ struct snddev_info *d;
+ nvlist_t *di;
+
+ if (ent->dev == NULL)
+ continue;
+ d = device_get_softc(ent->dev);
+ if (!PCM_REGISTERED(d))
+ continue;
+
+ di = nvlist_create(0);
+ if (di == NULL) {
+ err = ENOMEM;
+ SNDSTAT_UNLOCK();
+ goto done;
+ }
+
+ nvlist_add_bool(di, SNDSTAT_LABEL_FROM_USER, false);
+ nvlist_add_number(di, SNDSTAT_LABEL_UNIT,
+ device_get_unit(
+ ent->dev)); // XXX: I want signed integer here
+ nvlist_add_number(di, SNDSTAT_LABEL_PCHAN, d->playcount);
+ nvlist_add_number(di, SNDSTAT_LABEL_RCHAN, d->reccount);
+ nvlist_add_number(di, SNDSTAT_LABEL_PVCHAN, d->pvchancount);
+ nvlist_add_number(di, SNDSTAT_LABEL_RVCHAN, d->rvchancount);
+ nvlist_add_stringf(
+ di, SNDSTAT_LABEL_DEVNODE, "dsp%d", device_get_unit(ent->dev));
+ nvlist_add_string(di, SNDSTAT_LABEL_DESC, device_get_desc(ent->dev));
+
+ nvlist_append_nvlist_array(nvl, SNDSTAT_LABEL_DSPS, di);
+ nvlist_destroy(di);
+ err = nvlist_error(nvl);
+ if (err != 0) {
+ SNDSTAT_UNLOCK();
+ goto done;
+ }
+ }
+
+ TAILQ_FOREACH(pf, &sndstat_filelist, entry) {
+ nvlist_t *di;
+ struct sndstat_userdev *ud;
+
+ sx_xlock(&pf->lock);
+
+ TAILQ_FOREACH(ud, &pf->userdev_list, link) {
+ di = nvlist_create(0);
+ if (di == NULL) {
+ err = ENOMEM;
+ SNDSTAT_UNLOCK();
+ sx_xunlock(&pf->lock);
+ goto done;
+ }
+
+ nvlist_add_bool(di, SNDSTAT_LABEL_FROM_USER, true);
+ nvlist_add_number(di, SNDSTAT_LABEL_PCHAN, ud->pchan);
+ nvlist_add_number(di, SNDSTAT_LABEL_RCHAN, ud->rchan);
+ nvlist_add_string(di, SNDSTAT_LABEL_DEVNODE, ud->devnode);
+ nvlist_add_string(di, SNDSTAT_LABEL_DESC, ud->desc);
+
+ nvlist_append_nvlist_array(nvl, SNDSTAT_LABEL_DSPS, di);
+ nvlist_destroy(di);
+ err = nvlist_error(nvl);
+ if (err != 0) {
+ SNDSTAT_UNLOCK();
+ sx_xunlock(&pf->lock);
+ goto done;
+ }
+ }
+
+ sx_xunlock(&pf->lock);
+ }
+
+ *nvlp = nvl;
+
+done:
+ if (err != 0)
+ nvlist_destroy(nvl);
+ return (err);
+}
+
+static int
+sndstat_refresh_devs(struct sndstat_file *pf)
+{
+ int err;
+ nvlist_t *nvl;
+ void *nvlbuf;
+ size_t nbytes;
+
+ SNDSTAT_LOCK();
+ err = sndstat_create_devs_nvlist(&nvl);
+ SNDSTAT_UNLOCK();
+ if (err) {
+ sx_xunlock(&pf->lock);
+ return (err);
+ }
+
+ sx_xlock(&pf->lock);
+ nvlbuf = nvlist_pack(nvl, &nbytes);
+ if (nvlbuf == NULL) {
+ sx_xunlock(&pf->lock);
+ nvlist_destroy(nvl);
+ return (ENOMEM);
+ }
+
+ free(pf->devs_nvlbuf, M_NVLIST);
+ pf->devs_nvlbuf = nvlbuf;
+ pf->devs_nbytes = nbytes;
+ sx_unlock(&pf->lock);
+
+ nvlist_destroy(nvl);
+ return (0);
+}
+
+static int
+sndstat_get_devs(struct sndstat_file *pf, caddr_t data)
+{
+ int err;
+ struct sndstat_nvlbuf_arg *arg = (struct sndstat_nvlbuf_arg *)data;
+
+ SNDSTAT_LOCK();
+ sx_xlock(&pf->lock);
+
+ if (pf->devs_nvlbuf == NULL) {
+ nvlist_t *nvl;
+ void *nvlbuf;
+ size_t nbytes;
+ int err;
+
+ sx_xunlock(&pf->lock);
+
+ err = sndstat_create_devs_nvlist(&nvl);
+ if (err) {
+ SNDSTAT_UNLOCK();
+ return (err);
+ }
+
+ sx_xlock(&pf->lock);
+
+ nvlbuf = nvlist_pack(nvl, &nbytes);
+ err = nvlist_error(nvl);
+ nvlist_destroy(nvl);
+ if (nvlbuf == NULL || err != 0) {
+ SNDSTAT_UNLOCK();
+ sx_xunlock(&pf->lock);
+ if (err == 0)
+ return (ENOMEM);
+ return (err);
+ }
+
+ free(pf->devs_nvlbuf, M_NVLIST);
+ pf->devs_nvlbuf = nvlbuf;
+ pf->devs_nbytes = nbytes;
}
+
SNDSTAT_UNLOCK();
+
+ if (!arg->nbytes) {
+ arg->nbytes = pf->devs_nbytes;
+ err = 0;
+ goto done;
+ }
+ if (arg->nbytes < pf->devs_nbytes) {
+ arg->nbytes = 0;
+ err = 0;
+ goto done;
+ }
+
+ err = copyout(pf->devs_nvlbuf, arg->buf, pf->devs_nbytes);
+ if (err)
+ goto done;
+
+ arg->nbytes = pf->devs_nbytes;
+
+ free(pf->devs_nvlbuf, M_NVLIST);
+ pf->devs_nvlbuf = NULL;
+ pf->devs_nbytes = 0;
+
+done:
+ sx_unlock(&pf->lock);
return (err);
}
+static int
+sndstat_unpack_user_nvlbuf(const void *unvlbuf, size_t nbytes, nvlist_t **nvl)
+{
+ void *nvlbuf;
+ int err;
+
+ nvlbuf = malloc(nbytes, M_DEVBUF, M_WAITOK);
+ err = copyin(unvlbuf, nvlbuf, nbytes);
+ if (err != 0) {
+ free(nvlbuf, M_DEVBUF);
+ return (err);
+ }
+ *nvl = nvlist_unpack(nvlbuf, nbytes, 0);
+ free(nvlbuf, M_DEVBUF);
+ if (nvl == NULL) {
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static bool
+sndstat_dsp_nvlist_is_sane(const nvlist_t *nvlist)
+{
+ return (nvlist_exists_string(nvlist, SNDSTAT_LABEL_DEVNODE) &&
+ nvlist_exists_string(nvlist, SNDSTAT_LABEL_DESC) &&
+ nvlist_exists_number(nvlist, SNDSTAT_LABEL_PCHAN) &&
+ nvlist_exists_number(nvlist, SNDSTAT_LABEL_RCHAN));
+}
+
+static int
+sndstat_add_user_devs(struct sndstat_file *pf, caddr_t data)
+{
+ int err;
+ nvlist_t *nvl = NULL;
+ const nvlist_t * const *dsps;
+ size_t i, ndsps;
+ struct sndstat_nvlbuf_arg *arg = (struct sndstat_nvlbuf_arg *)data;
+
+ if ((pf->fflags & FWRITE) == 0) {
+ err = EPERM;
+ goto done;
+ }
+
+ err = sndstat_unpack_user_nvlbuf(arg->buf, arg->nbytes, &nvl);
+ if (err != 0)
+ goto done;
+
+ if (!nvlist_exists_nvlist_array(nvl, SNDSTAT_LABEL_DSPS)) {
+ err = EINVAL;
+ goto done;
+ }
+ dsps = nvlist_get_nvlist_array(nvl, SNDSTAT_LABEL_DSPS, &ndsps);
+ for (i = 0; i < ndsps; i++) {
+ if (!sndstat_dsp_nvlist_is_sane(dsps[i])) {
+ err = EINVAL;
+ goto done;
+ }
+ }
+ sx_xlock(&pf->lock);
+ for (i = 0; i < ndsps; i++) {
+ const char *devnode, *desc;
+ unsigned int pchan, rchan;
+ struct sndstat_userdev *ud;
+
+ devnode = nvlist_get_string(dsps[i], SNDSTAT_LABEL_DEVNODE);
+ desc = nvlist_get_string(dsps[i], SNDSTAT_LABEL_DESC);
+ pchan = nvlist_get_number(dsps[i], SNDSTAT_LABEL_PCHAN);
+ rchan = nvlist_get_number(dsps[i], SNDSTAT_LABEL_RCHAN);
+
+ ud = malloc(sizeof(*ud), M_DEVBUF, M_WAITOK);
+ ud->devnode = strdup(devnode, M_DEVBUF);
+ ud->desc = strdup(desc, M_DEVBUF);
+ ud->pchan = pchan;
+ ud->rchan = rchan;
+ TAILQ_INSERT_TAIL(&pf->userdev_list, ud, link);
+ }
+ sx_unlock(&pf->lock);
+
+done:
+ nvlist_destroy(nvl);
+ return (err);
+}
+
+#ifdef COMPAT_FREEBSD32
+static int
+compat_sndstat_get_devs32(struct sndstat_file *pf, caddr_t data)
+{
+ struct sndstat_nvlbuf_arg32 *arg32 = (struct sndstat_nvlbuf_arg32 *)data;
+ struct sndstat_nvlbuf_arg arg;
+ int err;
+
+ arg.buf = (void *)(uintptr_t)arg32->buf;
+ arg.nbytes = arg32->nbytes;
+
+ err = sndstat_get_devs(pf, (caddr_t)&arg);
+ if (err == 0) {
+ arg32->buf = (uint32_t)(uintptr_t)arg.buf;
+ arg32->nbytes = arg.nbytes;
+ }
+
+ return (err);
+}
+
+static int
+compat_sndstat_add_user_devs32(struct sndstat_file *pf, caddr_t data)
+{
+ struct sndstat_nvlbuf_arg32 *arg32 = (struct sndstat_nvlbuf_arg32 *)data;
+ struct sndstat_nvlbuf_arg arg;
+ int err;
+
+ arg.buf = (void *)(uintptr_t)arg32->buf;
+ arg.nbytes = arg32->nbytes;
+
+ err = sndstat_add_user_devs(pf, (caddr_t)&arg);
+ if (err == 0) {
+ arg32->buf = (uint32_t)(uintptr_t)arg.buf;
+ arg32->nbytes = arg.nbytes;
+ }
+
+ return (err);
+}
+#endif
+
+static int
+sndstat_ioctl(
+ struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+ int err;
+ struct sndstat_file *pf;
+
+ err = devfs_get_cdevpriv((void **)&pf);
+ if (err != 0)
+ return (err);
+
+ switch (cmd) {
+ case SNDSTAT_GET_DEVS:
+ err = sndstat_get_devs(pf, data);
+ break;
+#ifdef COMPAT_FREEBSD32
+ case SNDSTAT_GET_DEVS32:
+ if (!SV_CURPROC_FLAG(SV_ILP32)) {
+ err = ENODEV;
+ break;
+ }
+ err = compat_sndstat_get_devs32(pf, data);
+ break;
+#endif
+ case SNDSTAT_ADD_USER_DEVS:
+ err = sndstat_add_user_devs(pf, data);
+ break;
+#ifdef COMPAT_FREEBSD32
+ case SNDSTAT_ADD_USER_DEVS32:
+ if (!SV_CURPROC_FLAG(SV_ILP32)) {
+ err = ENODEV;
+ break;
+ }
+ err = compat_sndstat_add_user_devs32(pf, data);
+ break;
+#endif
+ case SNDSTAT_REFRESH_DEVS:
+ err = sndstat_refresh_devs(pf);
+ break;
+ default:
+ err = ENODEV;
+ }
+
+ return (err);
+}
+
+static struct sndstat_userdev *
+sndstat_line2userdev(struct sndstat_file *pf, const char *line, int n)
+{
+ struct sndstat_userdev *ud;
+ const char *e, *m;
+
+ ud = malloc(sizeof(*ud), M_DEVBUF, M_WAITOK|M_ZERO);
+
+ e = strchr(line, ':');
+ if (e == NULL)
+ goto fail;
+ ud->devnode = strndup(line, e - line, M_DEVBUF);
+ line = e + 1;
+
+ e = strchr(line, '<');
+ if (e == NULL)
+ goto fail;
+ line = e + 1;
+ e = strrchr(line, '>');
+ if (e == NULL)
+ goto fail;
+ ud->desc = strndup(line, e - line, M_DEVBUF);
+ line = e + 1;
+
+ e = strchr(line, '(');
+ if (e == NULL)
+ goto fail;
+ line = e + 1;
+ e = strrchr(line, ')');
+ if (e == NULL)
+ goto fail;
+ m = strstr(line, "play");
+ if (m != NULL && m < e)
+ ud->pchan = 1;
+ m = strstr(line, "rec");
+ if (m != NULL && m < e)
+ ud->rchan = 1;
+
+ return (ud);
+
+fail:
+ free(ud->devnode, M_DEVBUF);
+ free(ud->desc, M_DEVBUF);
+ free(ud, M_DEVBUF);
+ return (NULL);
+}
+
/************************************************************************/
int
@@ -379,14 +869,26 @@
/* append any input from userspace */
k = 0;
TAILQ_FOREACH(pf, &sndstat_filelist, entry) {
+ struct sndstat_userdev *ud;
+
if (pf == pf_self)
continue;
- if (pf->out_offset == 0)
+ sx_xlock(&pf->lock);
+ if (TAILQ_EMPTY(&pf->userdev_list)) {
+ sx_unlock(&pf->lock);
continue;
+ }
if (!k++)
sbuf_printf(s, "Installed devices from userspace:\n");
- sbuf_bcat(s, sbuf_data(&pf->sbuf),
- sbuf_len(&pf->sbuf));
+ TAILQ_FOREACH(ud, &pf->userdev_list, link) {
+ const char *caps = (ud->pchan && ud->rchan) ?
+ "play/rec" :
+ (ud->pchan ? "play" : (ud->rchan ? "rec" : ""));
+ sbuf_printf(s, "%s: <%s>", ud->devnode, ud->desc);
+ sbuf_printf(s, " (%s)", caps);
+ sbuf_printf(s, "\n");
+ }
+ sx_unlock(&pf->lock);
}
if (k == 0)
sbuf_printf(s, "No devices installed from userspace.\n");
Index: sys/dev/sound/pcm/sound.h
===================================================================
--- sys/dev/sound/pcm/sound.h
+++ sys/dev/sound/pcm/sound.h
@@ -64,6 +64,7 @@
#include <sys/poll.h>
#include <sys/sbuf.h>
#include <sys/soundcard.h>
+#include <sys/sndstat.h>
#include <sys/sysctl.h>
#include <sys/kobj.h>
#include <vm/vm.h>
Index: sys/sys/sndstat.h
===================================================================
--- /dev/null
+++ sys/sys/sndstat.h
@@ -0,0 +1,79 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Ka Ho Ng
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_SNDSTAT_H_
+#define _SYS_SNDSTAT_H_
+
+#include <sys/types.h>
+#ifndef _IOWR
+#include <sys/ioccom.h>
+#endif /* !_IOWR */
+
+struct sndstat_nvlbuf_arg {
+ size_t nbytes; /* [IN/OUT] buffer size/number of bytes filled */
+ void *buf; /* [OUT] buffer holding a packed nvlist */
+};
+
+#define SNDSTAT_LABEL_DSPS "dsps"
+#define SNDSTAT_LABEL_FROM_USER "from_user"
+#define SNDSTAT_LABEL_UNIT "unit"
+#define SNDSTAT_LABEL_PCHAN "pchan"
+#define SNDSTAT_LABEL_RCHAN "rchan"
+#define SNDSTAT_LABEL_PVCHAN "pvchan"
+#define SNDSTAT_LABEL_RVCHAN "rvchan"
+#define SNDSTAT_LABEL_DEVNODE "devnode"
+#define SNDSTAT_LABEL_DESC "desc"
+
+#define SNDSTAT_DEVS_VER_MAJOR 1
+#define SNDSTAT_DEVS_VER_MINOR 0
+
+#define SNDSTAT_REFRESH_DEVS _IO('D', 100)
+#define SNDSTAT_GET_DEVS _IOWR('D', 101, struct sndstat_nvlbuf_arg)
+#define SNDSTAT_ADD_USER_DEVS _IOWR('D', 102, struct sndstat_nvlbuf_arg)
+
+#ifdef _KERNEL
+#ifdef COMPAT_FREEBSD32
+
+struct sndstat_nvlbuf_arg32 {
+ uint32_t nbytes;
+ uint32_t buf;
+};
+
+#define SNDSTAT_GET_DEVS32 \
+ _IOC_NEWTYPE(SNDSTAT_GET_DEVS, struct sndstat_nvlbuf_arg32)
+#define SNDSTAT_ADD_USER_DEVS32 \
+ _IOC_NEWTYPE(SNDSTAT_ADD_USER_DEVS, struct sndstat_nvlbuf_arg32)
+
+#endif
+#endif
+
+#endif /* !_SYS_SNDSTAT_H_ */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Oct 23, 8:05 PM (12 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24101333
Default Alt Text
D26884.id78551.diff (16 KB)
Attached To
Mode
D26884: Implement sndstat nvlist-based enumeration ioctls.
Attached
Detach File
Event Timeline
Log In to Comment