34#ifdef HAVE_KERNEL_OPTION_HEADERS
40#include <sys/malloc.h>
44#ifdef COMPAT_FREEBSD32
45#include <sys/sysent.h>
55#define SS_TYPE_MODULE 0
58#define SS_TYPE_SEQUENCER 3
67 .d_version = D_VERSION,
73 .d_flags = D_TRACKCLOSE,
117#define SNDSTAT_LOCK() sx_xlock(&sndstat_lock)
118#define SNDSTAT_UNLOCK() sx_xunlock(&sndstat_lock)
130sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
135 error = sysctl_handle_int(oidp, &verbose, 0, req);
136 if (error == 0 &&
req->newptr != NULL) {
137 if (verbose < 0 || verbose > 4)
145 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0,
sizeof(
int),
146 sysctl_hw_sndverbose,
"I",
150sndstat_open(
struct cdev *i_dev,
int flags,
int mode,
struct thread *td)
154 pf = malloc(
sizeof(*
pf), M_DEVBUF, M_WAITOK | M_ZERO);
156 if (sbuf_new(&
pf->sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
162 TAILQ_INIT(&
pf->userdev_list);
163 sx_init(&
pf->lock,
"sndstat_file");
166 TAILQ_INSERT_TAIL(&sndstat_filelist,
pf, entry);
185 sx_xlocked(&
pf->lock), (
"%s: Called without pf->lock", __func__));
186 while ((ud = TAILQ_FIRST(&
pf->userdev_list)) != NULL) {
187 TAILQ_REMOVE(&
pf->userdev_list, ud, link);
188 free(ud->provider, M_DEVBUF);
189 free(ud->desc, M_DEVBUF);
190 free(ud->devnode, M_DEVBUF);
191 free(ud->nameunit, M_DEVBUF);
203 sbuf_delete(&
pf->sbuf);
204 TAILQ_REMOVE(&sndstat_filelist,
pf, entry);
207 free(
pf->devs_nvlbuf, M_NVLIST);
210 sx_xunlock(&
pf->lock);
211 sx_destroy(&
pf->lock);
223 err = devfs_get_cdevpriv((
void **)&
pf);
228 if (
buf->uio_resid == 0)
232 if (
pf->out_offset != 0) {
236 }
else if (
pf->in_offset == 0) {
243 len = sbuf_len(&
pf->sbuf) -
pf->in_offset;
247 err = uiomove(sbuf_data(&
pf->sbuf) +
pf->in_offset,
len,
buf);
248 pf->in_offset +=
len;
262 err = devfs_get_cdevpriv((
void **)&
pf);
267 if (
buf->uio_resid == 0)
271 if (
buf->uio_resid > 65536)
275 if (
pf->in_offset != 0) {
282 sx_xunlock(&
pf->lock);
289 err = uiomove(temp,
len,
buf);
295 if (sbuf_bcat(&
pf->sbuf, temp,
len) < 0) {
300 sbuf_finish(&
pf->sbuf);
305 str = sbuf_data(&
pf->sbuf);
306 while ((line = strsep(&str,
"\n")) != NULL) {
314 TAILQ_INSERT_TAIL(&
pf->userdev_list, ud, link);
315 sx_xunlock(&
pf->lock);
318 pf->out_offset = sbuf_len(&
pf->sbuf);
322 sbuf_clear(&
pf->sbuf);
330 uint32_t *max_rate, uint32_t *
fmts, uint32_t *minchn, uint32_t *maxchn)
333 unsigned int encoding;
350 *min_rate = UINT32_MAX;
352 *minchn = UINT32_MAX;
364 *min_rate = min(
caps->minspeed, *min_rate);
365 *max_rate =
max(
caps->maxspeed, *max_rate);
366 for (i = 0;
caps->fmtlist[i]; i++) {
373 if (*min_rate == UINT32_MAX)
375 if (*minchn == UINT32_MAX)
381 uint32_t min_chn, uint32_t max_chn)
385 nv = nvlist_create(0);
388 nvlist_add_number(nv, SNDST_DSPS_INFO_MIN_RATE, min_rate);
389 nvlist_add_number(nv, SNDST_DSPS_INFO_MAX_RATE, max_rate);
390 nvlist_add_number(nv, SNDST_DSPS_INFO_FORMATS, formats);
391 nvlist_add_number(nv, SNDST_DSPS_INFO_MIN_CHN, min_chn);
392 nvlist_add_number(nv, SNDST_DSPS_INFO_MAX_CHN, max_chn);
399 uint32_t maxrate, minrate,
fmts, minchn, maxchn;
400 nvlist_t *di = NULL, *sound4di = NULL, *diinfo = NULL;
403 di = nvlist_create(0);
408 sound4di = nvlist_create(0);
409 if (sound4di == NULL) {
414 nvlist_add_bool(di, SNDST_DSPS_FROM_USER,
false);
415 nvlist_add_stringf(di, SNDST_DSPS_NAMEUNIT,
"%s",
416 device_get_nameunit(d->
dev));
417 nvlist_add_stringf(di, SNDST_DSPS_DEVNODE,
"dsp%d",
418 device_get_unit(d->
dev));
420 di, SNDST_DSPS_DESC, device_get_desc(d->
dev));
423 nvlist_add_number(di, SNDST_DSPS_PCHAN, d->
playcount);
424 nvlist_add_number(di, SNDST_DSPS_RCHAN, d->
reccount);
428 nvlist_add_number(di,
"pminrate", minrate);
429 nvlist_add_number(di,
"pmaxrate", maxrate);
430 nvlist_add_number(di,
"pfmts",
fmts);
434 nvlist_set_error(di, ENOMEM);
436 nvlist_move_nvlist(di, SNDST_DSPS_INFO_PLAY, diinfo);
441 nvlist_add_number(di,
"rminrate", minrate);
442 nvlist_add_number(di,
"rmaxrate", maxrate);
443 nvlist_add_number(di,
"rfmts",
fmts);
447 nvlist_set_error(di, ENOMEM);
449 nvlist_move_nvlist(di, SNDST_DSPS_INFO_REC, diinfo);
452 nvlist_add_number(sound4di, SNDST_DSPS_SOUND4_UNIT,
453 device_get_unit(d->
dev));
456 nvlist_add_number(sound4di, SNDST_DSPS_SOUND4_PVCHAN, d->
pvchancount);
457 nvlist_add_number(sound4di, SNDST_DSPS_SOUND4_RVCHAN, d->
rvchancount);
458 nvlist_move_nvlist(di, SNDST_DSPS_PROVIDER_INFO, sound4di);
461 nvlist_add_string(di, SNDST_DSPS_PROVIDER, SNDST_DSPS_SOUND4_PROVIDER);
463 err = nvlist_error(di);
471 nvlist_destroy(sound4di);
480 nvlist_t *di, *diinfo;
483 di = nvlist_create(0);
489 nvlist_add_bool(di, SNDST_DSPS_FROM_USER,
true);
490 nvlist_add_number(di, SNDST_DSPS_PCHAN, ud->pchan);
491 nvlist_add_number(di, SNDST_DSPS_RCHAN, ud->rchan);
492 nvlist_add_string(di, SNDST_DSPS_NAMEUNIT, ud->nameunit);
494 di, SNDST_DSPS_DEVNODE, ud->devnode);
495 nvlist_add_string(di, SNDST_DSPS_DESC, ud->desc);
496 if (ud->pchan != 0) {
497 nvlist_add_number(di,
"pminrate",
499 nvlist_add_number(di,
"pmaxrate",
501 nvlist_add_number(di,
"pfmts",
507 nvlist_set_error(di, ENOMEM);
509 nvlist_move_nvlist(di, SNDST_DSPS_INFO_PLAY, diinfo);
511 if (ud->rchan != 0) {
512 nvlist_add_number(di,
"rminrate",
514 nvlist_add_number(di,
"rmaxrate",
516 nvlist_add_number(di,
"rfmts",
522 nvlist_set_error(di, ENOMEM);
524 nvlist_move_nvlist(di, SNDST_DSPS_INFO_REC, diinfo);
526 nvlist_add_string(di, SNDST_DSPS_PROVIDER,
527 (ud->provider != NULL) ? ud->provider :
"");
532 err = nvlist_error(di);
556 nvl = nvlist_create(0);
560 TAILQ_FOREACH(ent, &sndstat_devlist, link) {
564 if (ent->dev == NULL)
566 d = device_get_softc(ent->dev);
574 nvlist_append_nvlist_array(nvl, SNDST_DSPS, di);
576 err = nvlist_error(nvl);
581 TAILQ_FOREACH(
pf, &sndstat_filelist, entry) {
586 TAILQ_FOREACH(ud, &
pf->userdev_list, link) {
591 sx_xunlock(&
pf->lock);
594 nvlist_append_nvlist_array(nvl, SNDST_DSPS, di);
597 err = nvlist_error(nvl);
599 sx_xunlock(&
pf->lock);
604 sx_xunlock(&
pf->lock);
619 free(
pf->devs_nvlbuf, M_NVLIST);
620 pf->devs_nvlbuf = NULL;
622 sx_unlock(&
pf->lock);
631 struct sndstioc_nv_arg *arg = (
struct sndstioc_nv_arg *)
data;
636 if (
pf->devs_nvlbuf == NULL) {
642 sx_xunlock(&
pf->lock);
652 nvlbuf = nvlist_pack(nvl, &nbytes);
653 err = nvlist_error(nvl);
655 if (nvlbuf == NULL || err != 0) {
657 sx_xunlock(&
pf->lock);
663 free(
pf->devs_nvlbuf, M_NVLIST);
664 pf->devs_nvlbuf = nvlbuf;
665 pf->devs_nbytes = nbytes;
671 arg->nbytes =
pf->devs_nbytes;
675 if (arg->nbytes <
pf->devs_nbytes) {
681 err = copyout(
pf->devs_nvlbuf, arg->buf,
pf->devs_nbytes);
685 arg->nbytes =
pf->devs_nbytes;
687 free(
pf->devs_nvlbuf, M_NVLIST);
688 pf->devs_nvlbuf = NULL;
692 sx_unlock(&
pf->lock);
702 nvlbuf = malloc(nbytes, M_DEVBUF, M_WAITOK);
703 err = copyin(unvlbuf, nvlbuf, nbytes);
705 free(nvlbuf, M_DEVBUF);
708 *nvl = nvlist_unpack(nvlbuf, nbytes, 0);
709 free(nvlbuf, M_DEVBUF);
720 if (!(nvlist_exists_number(diinfo, SNDST_DSPS_INFO_MIN_RATE) &&
721 nvlist_exists_number(diinfo, SNDST_DSPS_INFO_MAX_RATE) &&
722 nvlist_exists_number(diinfo, SNDST_DSPS_INFO_FORMATS) &&
723 nvlist_exists_number(diinfo, SNDST_DSPS_INFO_MIN_CHN) &&
724 nvlist_exists_number(diinfo, SNDST_DSPS_INFO_MAX_CHN)))
732 if (!(nvlist_exists_string(nvlist, SNDST_DSPS_DEVNODE) &&
733 nvlist_exists_string(nvlist, SNDST_DSPS_DESC) &&
734 nvlist_exists_number(nvlist, SNDST_DSPS_PCHAN) &&
735 nvlist_exists_number(nvlist, SNDST_DSPS_RCHAN)))
738 if (nvlist_get_number(nvlist, SNDST_DSPS_PCHAN) > 0) {
739 if (nvlist_exists_nvlist(nvlist, SNDST_DSPS_INFO_PLAY)) {
741 SNDST_DSPS_INFO_PLAY)))
743 }
else if (!(nvlist_exists_number(nvlist,
"pminrate") &&
744 nvlist_exists_number(nvlist,
"pmaxrate") &&
745 nvlist_exists_number(nvlist,
"pfmts")))
749 if (nvlist_get_number(nvlist, SNDST_DSPS_RCHAN) > 0) {
750 if (nvlist_exists_nvlist(nvlist, SNDST_DSPS_INFO_REC)) {
752 SNDST_DSPS_INFO_REC)))
754 }
else if (!(nvlist_exists_number(nvlist,
"rminrate") &&
755 nvlist_exists_number(nvlist,
"rmaxrate") &&
756 nvlist_exists_number(nvlist,
"rfmts")))
766 uint32_t *max_rate, uint32_t *formats, uint32_t *min_chn,
769 *min_rate = nvlist_get_number(nv, SNDST_DSPS_INFO_MIN_RATE);
770 *max_rate = nvlist_get_number(nv, SNDST_DSPS_INFO_MAX_RATE);
771 *formats = nvlist_get_number(nv, SNDST_DSPS_INFO_FORMATS);
772 *min_chn = nvlist_get_number(nv, SNDST_DSPS_INFO_MIN_CHN);
773 *max_chn = nvlist_get_number(nv, SNDST_DSPS_INFO_MAX_CHN);
779 const char *nameunit, *devnode, *
desc;
780 unsigned int pchan, rchan;
781 uint32_t pminrate = 0, pmaxrate = 0;
782 uint32_t rminrate = 0, rmaxrate = 0;
783 uint32_t pfmts = 0, rfmts = 0;
784 uint32_t pminchn = 0, pmaxchn = 0;
785 uint32_t rminchn = 0, rmaxchn = 0;
786 nvlist_t *provider_nvl = NULL;
787 const nvlist_t *diinfo;
790 devnode = nvlist_get_string(nvlist, SNDST_DSPS_DEVNODE);
791 if (nvlist_exists_string(nvlist, SNDST_DSPS_NAMEUNIT))
792 nameunit = nvlist_get_string(nvlist, SNDST_DSPS_NAMEUNIT);
795 desc = nvlist_get_string(nvlist, SNDST_DSPS_DESC);
796 pchan = nvlist_get_number(nvlist, SNDST_DSPS_PCHAN);
797 rchan = nvlist_get_number(nvlist, SNDST_DSPS_RCHAN);
799 if (nvlist_exists_nvlist(nvlist, SNDST_DSPS_INFO_PLAY)) {
800 diinfo = nvlist_get_nvlist(nvlist,
801 SNDST_DSPS_INFO_PLAY);
803 &pfmts, &pminchn, &pmaxchn);
805 pminrate = nvlist_get_number(nvlist,
"pminrate");
806 pmaxrate = nvlist_get_number(nvlist,
"pmaxrate");
807 pfmts = nvlist_get_number(nvlist,
"pfmts");
811 if (nvlist_exists_nvlist(nvlist, SNDST_DSPS_INFO_REC)) {
812 diinfo = nvlist_get_nvlist(nvlist,
813 SNDST_DSPS_INFO_REC);
815 &rfmts, &rminchn, &rmaxchn);
817 rminrate = nvlist_get_number(nvlist,
"rminrate");
818 rmaxrate = nvlist_get_number(nvlist,
"rmaxrate");
819 rfmts = nvlist_get_number(nvlist,
"rfmts");
823 provider = dnvlist_get_string(nvlist, SNDST_DSPS_PROVIDER,
"");
828 nvlist_exists_nvlist(nvlist, SNDST_DSPS_PROVIDER_INFO)) {
829 provider_nvl = nvlist_clone(
830 nvlist_get_nvlist(nvlist, SNDST_DSPS_PROVIDER_INFO));
831 if (provider_nvl == NULL)
836 ud->devnode = strdup(devnode, M_DEVBUF);
837 ud->nameunit = strdup(nameunit, M_DEVBUF);
838 ud->desc = strdup(
desc, M_DEVBUF);
859 nvlist_t *nvl = NULL;
860 const nvlist_t *
const *dsps;
862 struct sndstioc_nv_arg *arg = (
struct sndstioc_nv_arg *)
data;
864 if ((
pf->fflags & FWRITE) == 0) {
873 if (!nvlist_exists_nvlist_array(nvl, SNDST_DSPS)) {
877 dsps = nvlist_get_nvlist_array(nvl, SNDST_DSPS, &ndsps);
878 for (i = 0; i < ndsps; i++) {
885 for (i = 0; i < ndsps; i++) {
887 malloc(
sizeof(*ud), M_DEVBUF, M_WAITOK);
890 sx_unlock(&
pf->lock);
893 TAILQ_INSERT_TAIL(&
pf->userdev_list, ud, link);
895 sx_unlock(&
pf->lock);
905 if ((
pf->fflags & FWRITE) == 0)
910 sx_xunlock(&
pf->lock);
915#ifdef COMPAT_FREEBSD32
919 struct sndstioc_nv_arg32 *arg32 = (
struct sndstioc_nv_arg32 *)
data;
920 struct sndstioc_nv_arg arg;
923 arg.buf = (
void *)(uintptr_t)arg32->buf;
924 arg.nbytes = arg32->nbytes;
928 arg32->buf = (uint32_t)(uintptr_t)arg.buf;
929 arg32->nbytes = arg.nbytes;
938 struct sndstioc_nv_arg32 *arg32 = (
struct sndstioc_nv_arg32 *)
data;
939 struct sndstioc_nv_arg arg;
942 arg.buf = (
void *)(uintptr_t)arg32->buf;
943 arg.nbytes = arg32->nbytes;
947 arg32->buf = (uint32_t)(uintptr_t)arg.buf;
948 arg32->nbytes = arg.nbytes;
957 struct cdev *
dev, u_long cmd, caddr_t
data,
int fflag,
struct thread *td)
962 err = devfs_get_cdevpriv((
void **)&
pf);
967 case SNDSTIOC_GET_DEVS:
970#ifdef COMPAT_FREEBSD32
971 case SNDSTIOC_GET_DEVS32:
972 if (!SV_CURPROC_FLAG(SV_ILP32)) {
976 err = compat_sndstat_get_devs32(
pf,
data);
979 case SNDSTIOC_ADD_USER_DEVS:
982#ifdef COMPAT_FREEBSD32
983 case SNDSTIOC_ADD_USER_DEVS32:
984 if (!SV_CURPROC_FLAG(SV_ILP32)) {
988 err = compat_sndstat_add_user_devs32(
pf,
data);
991 case SNDSTIOC_REFRESH_DEVS:
994 case SNDSTIOC_FLUSH_USER_DEVS:
1010 ud = malloc(
sizeof(*ud), M_DEVBUF, M_WAITOK|M_ZERO);
1012 ud->provider = NULL;
1014 e = strchr(line,
':');
1017 ud->nameunit = strndup(line, e - line, M_DEVBUF);
1018 ud->devnode = (
char *)malloc(e - line + 1, M_DEVBUF, M_WAITOK | M_ZERO);
1019 strlcat(ud->devnode, ud->nameunit, e - line + 1);
1022 e = strchr(line,
'<');
1026 e = strrchr(line,
'>');
1029 ud->desc = strndup(line, e - line, M_DEVBUF);
1032 e = strchr(line,
'(');
1036 e = strrchr(line,
')');
1039 m = strstr(line,
"play");
1040 if (
m != NULL &&
m < e)
1042 m = strstr(line,
"rec");
1043 if (
m != NULL &&
m < e)
1049 free(ud->nameunit, M_DEVBUF);
1050 free(ud->devnode, M_DEVBUF);
1051 free(ud->desc, M_DEVBUF);
1063 const char *devtype;
1067 unit = device_get_unit(
dev);
1068 devtype = device_get_name(
dev);
1069 if (!strcmp(devtype,
"pcm"))
1071 else if (!strcmp(devtype,
"midi"))
1073 else if (!strcmp(devtype,
"sequencer"))
1082 ent = malloc(
sizeof *ent, M_DEVBUF, M_WAITOK | M_ZERO);
1087 ent->handler = handler;
1091 TAILQ_FOREACH(pre, &sndstat_devlist, link) {
1092 if (pre->unit > unit)
1094 else if (pre->unit < unit)
1096 if (pre->type >
type)
1098 else if (pre->type < unit)
1102 TAILQ_INSERT_TAIL(&sndstat_devlist, ent, link);
1104 TAILQ_INSERT_BEFORE(pre, ent, link);
1124 TAILQ_FOREACH(ent, &sndstat_devlist, link) {
1125 if (ent->dev ==
dev) {
1126 TAILQ_REMOVE(&sndstat_devlist, ent, link);
1127 free(ent, M_DEVBUF);
1144 TAILQ_FOREACH(ent, &sndstat_devlist, link) {
1145 if (ent->dev == NULL && ent->str == str) {
1146 TAILQ_REMOVE(&sndstat_devlist, ent, link);
1147 free(ent, M_DEVBUF);
1162 struct sbuf *s = &pf_self->sbuf;
1172 sbuf_printf(s,
"FreeBSD Audio Driver (%ubit %d/%s)\n",
1179 TAILQ_FOREACH(ent, &sndstat_devlist, link) {
1180 if (ent->dev == NULL)
1182 d = device_get_softc(ent->dev);
1186 sbuf_printf(s,
"Installed devices:\n");
1187 sbuf_printf(s,
"%s:", device_get_nameunit(ent->dev));
1188 sbuf_printf(s,
" <%s>", device_get_desc(ent->dev));
1190 sbuf_printf(s,
" %s", ent->str);
1197 sbuf_printf(s,
"\n");
1200 sbuf_printf(s,
"No devices installed.\n");
1204 TAILQ_FOREACH(
pf, &sndstat_filelist, entry) {
1209 sx_xlock(&
pf->lock);
1210 if (TAILQ_EMPTY(&
pf->userdev_list)) {
1211 sx_unlock(&
pf->lock);
1215 sbuf_printf(s,
"Installed devices from userspace:\n");
1216 TAILQ_FOREACH(ud, &
pf->userdev_list, link) {
1217 const char *caps = (ud->pchan && ud->rchan) ?
1219 (ud->pchan ?
"play" : (ud->rchan ?
"rec" :
""));
1220 sbuf_printf(s,
"%s: <%s>", ud->nameunit, ud->desc);
1221 sbuf_printf(s,
" (%s)", caps);
1222 sbuf_printf(s,
"\n");
1224 sx_unlock(&
pf->lock);
1227 sbuf_printf(s,
"No devices installed from userspace.\n");
1232 TAILQ_FOREACH(ent, &sndstat_devlist, link) {
1233 if (ent->dev == NULL && ent->str != NULL) {
1235 sbuf_printf(s,
"\nFile Versions:\n");
1236 sbuf_printf(s,
"%s\n", ent->str);
1240 sbuf_printf(s,
"\nNo file versions.\n");
1243 return (sbuf_len(s));
1251 UID_ROOT, GID_WHEEL, 0644,
"sndstat");
struct pcmchan_caps * chn_getcaps(struct pcm_channel *c)
#define CHN_FOREACH(x, y, z)
struct pcmchan_matrix * m
METHOD const char * provider
SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT|CTLFLAG_RWTUN|CTLFLAG_MPSAFE, 0, sizeof(int), sysctl_hw_sndverbose, "I", "verbosity level")
SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL)
static int sndstat_prepare(struct sndstat_file *pf_self)
static int sndstat_refresh_devs(struct sndstat_file *pf)
static int sndstat_create_devs_nvlist(nvlist_t **nvlp)
static struct cdev * sndstat_dev
#define SS_TYPE_SEQUENCER
static int sndstat_build_sound4_nvlist(struct snddev_info *d, nvlist_t **dip)
static int sndstat_flush_user_devs(struct sndstat_file *pf)
static struct sndstat_userdev * sndstat_line2userdev(struct sndstat_file *pf, const char *line, int n)
static nvlist_t * sndstat_create_diinfo_nv(uint32_t min_rate, uint32_t max_rate, uint32_t formats, uint32_t min_chn, uint32_t max_chn)
static void sndstat_sysuninit(void *p)
static int sndstat_get_devs(struct sndstat_file *pf, caddr_t data)
static void sndstat_get_diinfo_nv(const nvlist_t *nv, uint32_t *min_rate, uint32_t *max_rate, uint32_t *formats, uint32_t *min_chn, uint32_t *max_chn)
static bool sndstat_dsp_nvlist_is_sane(const nvlist_t *nvlist)
static int sndstat_unpack_user_nvlbuf(const void *unvlbuf, size_t nbytes, nvlist_t **nvl)
int sndstat_unregisterfile(char *str)
static TAILQ_HEAD(sndstat_entry)
SND_DECLARE_FILE("$FreeBSD$")
int sndstat_registerfile(char *str)
static d_ioctl_t sndstat_ioctl
static d_write_t sndstat_write
static void sndstat_close(void *)
static int sndstat_build_userland_nvlist(struct sndstat_userdev *ud, nvlist_t **dip)
int sndstat_unregister(device_t dev)
static struct cdevsw sndstat_cdevsw
static bool sndstat_diinfo_is_sane(const nvlist_t *diinfo)
static int sndstat_add_user_devs(struct sndstat_file *pf, caddr_t data)
static d_open_t sndstat_open
static d_read_t sndstat_read
int sndstat_register(device_t dev, char *str, sndstat_handler handler)
static void sndstat_sysinit(void *p)
static struct sx sndstat_lock
static void sndstat_remove_all_userdevs(struct sndstat_file *pf)
SYSUNINIT(sndstat_sysuninit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysuninit, NULL)
static void sndstat_get_caps(struct snddev_info *d, bool play, uint32_t *min_rate, uint32_t *max_rate, uint32_t *fmts, uint32_t *minchn, uint32_t *maxchn)
static int sndstat_dsp_unpack_nvlist(const nvlist_t *nvlist, struct sndstat_userdev *ud)
#define PCM_RELEASE_QUICK(x)
#define PCM_ACQUIRE_QUICK(x)
int(* sndstat_handler)(struct sbuf *s, device_t dev, int verbose)
#define PCM_REGISTERED(x)
struct pcm_channel::@28 channels
TAILQ_ENTRY(sndstat_userdev)