sndstat: nvlist schema and API definition changes
- SNDSTAT_LABEL_* are renamed to SNDST_DSPS_*, and SNDSTAT_LABEL_DSPS becomes SNDST_DSPS. - Centralize channel number/rate/formats into a single nvlist The above nvlist is named "info_play" and "info_rec" - Expose only encoding format in pfmts/rfmts. Userland has no direct access to AFMT_ENCODING/CHANNEL/EXTCHANNEL macros, thus it serves no meaning to expose too much information through this pair of labels. However pminrate/rminrate, pmaxrate/rmaxrate, pfmts/rfmts are deprecated and will be removed in future. This commit keeps ioctls ABI compatibility with __FreeBSD_version 1400006 for now. In future the compat ABI with 1400006 will be removed once audio/virtual_oss is rebuilt. Sponsored by: The FreeBSD Foundation Reviewed by: hselasky Approved by: philip (mentor) Differential Revision: https://reviews.freebsd.org/D29770
This commit is contained in:
parent
438b553207
commit
4ce1ba6523
@ -31,7 +31,7 @@
|
||||
.\"
|
||||
.\" Note: The date here should be updated whenever a non-trivial
|
||||
.\" change is made to the manual page.
|
||||
.Dd December 7, 2020
|
||||
.Dd April 15, 2021
|
||||
.Dt SNDSTAT 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -52,7 +52,7 @@ device allows callers to enumeration PCM audio devices available for use.
|
||||
For all ioctls requiring data exchange between the subsystem and callers,
|
||||
the following structures are used to describe a serialized nvlist:
|
||||
.Bd -literal -offset indent
|
||||
struct sndstat_nvlbuf_arg {
|
||||
struct sndstioc_nv_arg {
|
||||
size_t nbytes;
|
||||
void *buf;
|
||||
};
|
||||
@ -67,9 +67,12 @@ dsps (NVLIST ARRAY): 1
|
||||
desc (STRING): [Generic (0x8086) (Analog Line-out)]
|
||||
pchan (NUMBER): 1 (1) (0x1)
|
||||
rchan (NUMBER): 0 (0) (0x0)
|
||||
pminrate (NUMBER): 48000 (48000) (0xbb80)
|
||||
pmaxrate (NUMBER): 48000 (48000) (0xbb80)
|
||||
pfmts (NUMBER): 2097168 (2097168) (0x200010)
|
||||
info_play (NVLIST):
|
||||
min_rate (NUMBER): 48000 (48000) (0xbb80)
|
||||
max_rate (NUMBER): 48000 (48000) (0xbb80)
|
||||
formats (NUMBER): 16 (16) (0x10)
|
||||
min_chn (NUMBER): 2 (2) (0x2)
|
||||
max_chn (NUMBER): 2 (2) (0x2)
|
||||
provider_info (NVLIST):
|
||||
unit (NUMBER): 0 (0) (0x0)
|
||||
bitperfect (BOOL): FALSE
|
||||
@ -94,24 +97,38 @@ This can be 0 if this PCM audio device does not support playback at all.
|
||||
.It Dv rchan
|
||||
The number of recording channels supported by hardware.
|
||||
This can be 0 if this PCM audio device does not support recording at all.
|
||||
.It Dv pminrate
|
||||
The minimum supported playback direction sampling rate.
|
||||
Only exists if pchan is greater than 0.
|
||||
.It Dv pmaxrate
|
||||
The maximum supported playback direction sampling rate.
|
||||
Only exists if pchan is greater than 0.
|
||||
.It Dv pfmts
|
||||
The supported playback direction sample format.
|
||||
Only exists if pchan is greater than 0.
|
||||
.It Dv rminrate
|
||||
The minimum supported recording direction sampling rate.
|
||||
Only exists if rchan is greater than 0.
|
||||
.It Dv rmaxrate
|
||||
The maximum supported recording direction sampling rate.
|
||||
Only exists if rchan is greater than 0.
|
||||
.It Dv rfmts
|
||||
The supported playback recording sample format.
|
||||
Only exists if rchan is greater than 0.
|
||||
.It Dv info_play
|
||||
Supported configurations in playback direction.
|
||||
This exists only if this PCM audio device supports playback.
|
||||
There are a number of name/value pairs inside this field:
|
||||
.Bl -tag -width ".Dv min_rate"
|
||||
.It Dv min_rate
|
||||
Minimum supported sampling rate.
|
||||
.It Dv max_rate
|
||||
Maximum supported sampling rate.
|
||||
.It Dv formats
|
||||
Supported sample formats.
|
||||
.It Dv min_chn
|
||||
Minimum supported number of channels in channel layout
|
||||
.It Dv max_chn
|
||||
Maximum supported number of channels in channel layout
|
||||
.El
|
||||
.It Dv info_rec
|
||||
Supported configurations in recording direction.
|
||||
This exists only if this PCM audio device supports recording.
|
||||
There are a number of name/value pairs inside this field:
|
||||
.Bl -tag -width ".Dv min_rate"
|
||||
.It Dv min_rate
|
||||
Minimum supported sampling rate.
|
||||
.It Dv max_rate
|
||||
Maximum supported sampling rate.
|
||||
.It Dv formats
|
||||
Supported sample formats.
|
||||
.It Dv min_chn
|
||||
Minimum supported number of channels in channel layout
|
||||
.It Dv max_chn
|
||||
Maximum supported number of channels in channel layout
|
||||
.El
|
||||
.It Dv provider_info
|
||||
Provider-specific fields.
|
||||
This field may not exist if the PCM audio device is not provided by in-kernel
|
||||
@ -121,15 +138,15 @@ This field will not exist if the provider field is an empty string.
|
||||
A string specifying the provider of the PCm audio device.
|
||||
.El
|
||||
.Pp
|
||||
The following ioctls are providede for use:
|
||||
.Bl -tag -width ".Dv SNDSTAT_FLUSH_USER_DEVS"
|
||||
.It Dv SNDSTAT_REFRESH_DEVS
|
||||
The following ioctls are provided for use:
|
||||
.Bl -tag -width ".Dv SNDSTIOC_FLUSH_USER_DEVS"
|
||||
.It Dv SNDSTIOC_REFRESH_DEVS
|
||||
Drop any previously fetched PCM audio devices list snapshots.
|
||||
This ioctl takes no arguments.
|
||||
.It Dv SNDSTAT_GET_DEVS
|
||||
.It Dv SNDSTIOC_GET_DEVS
|
||||
Generate and/or return PCM audio devices list snapshots to callers.
|
||||
This ioctl takes a pointer to
|
||||
.Fa struct sndstat_nvlbuf_arg
|
||||
.Fa struct sndstioc_nv_arg
|
||||
as the first and the only argument.
|
||||
Callers need to provide a sufficiently large buffer to hold a serialized
|
||||
nvlist.
|
||||
@ -159,12 +176,12 @@ Once a PCM audio device list snapshot is returned to user-space successfully,
|
||||
the snapshot stored in the subsystem's internal structure of the given
|
||||
.Fa fd
|
||||
will be freed.
|
||||
.It Dv SNDSTAT_ADD_USER_DEVS
|
||||
.It Dv SNDSTIOC_ADD_USER_DEVS
|
||||
Add a list of PCM audio devices provided by callers to
|
||||
.Pa /dev/sndstat
|
||||
device.
|
||||
This ioctl takes a pointer to
|
||||
.Fa struct sndstat_nvlbuf_arg
|
||||
.Fa struct sndstioc_nv_arg
|
||||
as the first and the only argument.
|
||||
Callers have to provide a buffer holding a serialized nvlist.
|
||||
.Fa nbytes
|
||||
@ -173,7 +190,7 @@ should be set to the length in bytes of the serialized nvlist.
|
||||
should be pointed to a buffer storing the serialized nvlist.
|
||||
Userspace-backed PCM audio device nodes should be listed inside the serialized
|
||||
nvlist.
|
||||
.It Dv SNDSTAT_FLUSH_USER_DEVS
|
||||
.It Dv SNDSTIOC_FLUSH_USER_DEVS
|
||||
Flush any PCM audio devices previously added by callers.
|
||||
This ioctl takes no arguments.
|
||||
.El
|
||||
@ -198,7 +215,7 @@ int
|
||||
main()
|
||||
{
|
||||
int fd;
|
||||
struct sndstat_nvlbuf_arg arg;
|
||||
struct sndstioc_nv_arg arg;
|
||||
const nvlist_t * const *di;
|
||||
size_t i, nitems;
|
||||
nvlist_t *nvl;
|
||||
@ -206,28 +223,28 @@ main()
|
||||
/* Open sndstat node in read-only first */
|
||||
fd = open("/dev/sndstat", O_RDONLY);
|
||||
|
||||
if (ioctl(fd, SNDSTAT_REFRESH_DEVS, NULL))
|
||||
err(1, "ioctl(fd, SNDSTAT_REFRESH_DEVS, NULL)");
|
||||
if (ioctl(fd, SNDSTIOC_REFRESH_DEVS, NULL))
|
||||
err(1, "ioctl(fd, SNDSTIOC_REFRESH_DEVS, NULL)");
|
||||
|
||||
/* Get the size of snapshot, when nbytes = 0 */
|
||||
arg.nbytes = 0;
|
||||
arg.buf = NULL;
|
||||
if (ioctl(fd, SNDSTAT_GET_DEVS, &arg))
|
||||
err(1, "ioctl(fd, SNDSTAT_GET_DEVS, &arg)");
|
||||
if (ioctl(fd, SNDSTIOC_GET_DEVS, &arg))
|
||||
err(1, "ioctl(fd, SNDSTIOC_GET_DEVS, &arg)");
|
||||
|
||||
/* Get snapshot data */
|
||||
arg.buf = malloc(arg.nbytes);
|
||||
if (arg.buf == NULL)
|
||||
err(EX_OSERR, "malloc");
|
||||
if (ioctl(fd, SNDSTAT_GET_DEVS, &arg))
|
||||
err(1, "ioctl(fd, SNDSTAT_GET_DEVS, &arg)");
|
||||
if (ioctl(fd, SNDSTIOC_GET_DEVS, &arg))
|
||||
err(1, "ioctl(fd, SNDSTIOC_GET_DEVS, &arg)");
|
||||
|
||||
/* Deserialize the nvlist stream */
|
||||
nvl = nvlist_unpack(arg.buf, arg.nbytes, 0);
|
||||
free(arg.buf);
|
||||
|
||||
/* Get DSPs array */
|
||||
di = nvlist_get_nvlist_array(nvl, SNDSTAT_LABEL_DSPS, &nitems);
|
||||
di = nvlist_get_nvlist_array(nvl, SNDST_DSPS, &nitems);
|
||||
for (i = 0; i < nitems; i++) {
|
||||
const char *nameunit, *devnode, *desc;
|
||||
|
||||
@ -235,9 +252,9 @@ main()
|
||||
* Examine each device nvlist item
|
||||
*/
|
||||
|
||||
nameunit = nvlist_get_string(di[i], SNDSTAT_LABEL_NAMEUNIT);
|
||||
devnode = nvlist_get_string(di[i], SNDSTAT_LABEL_DEVNODE);
|
||||
desc = nvlist_get_string(di[i], SNDSTAT_LABEL_DESC);
|
||||
nameunit = nvlist_get_string(di[i], SNDST_DSPS_NAMEUNIT);
|
||||
devnode = nvlist_get_string(di[i], SNDST_DSPS_DEVNODE);
|
||||
desc = nvlist_get_string(di[i], SNDST_DSPS_DESC);
|
||||
printf("Name unit: `%s`, Device node: `%s`, Description: `%s`\n",
|
||||
nameunit, devnode, desc);
|
||||
}
|
||||
|
@ -89,12 +89,13 @@ struct sndstat_userdev {
|
||||
char *desc;
|
||||
unsigned int pchan;
|
||||
unsigned int rchan;
|
||||
uint32_t pminrate;
|
||||
uint32_t pmaxrate;
|
||||
uint32_t rminrate;
|
||||
uint32_t rmaxrate;
|
||||
uint32_t pfmts;
|
||||
uint32_t rfmts;
|
||||
struct {
|
||||
uint32_t min_rate;
|
||||
uint32_t max_rate;
|
||||
uint32_t formats;
|
||||
uint32_t min_chn;
|
||||
uint32_t max_chn;
|
||||
} info_play, info_rec;
|
||||
nvlist_t *provider_nvl;
|
||||
};
|
||||
|
||||
@ -326,46 +327,77 @@ sndstat_write(struct cdev *i_dev, struct uio *buf, int flag)
|
||||
|
||||
static void
|
||||
sndstat_get_caps(struct snddev_info *d, bool play, uint32_t *min_rate,
|
||||
uint32_t *max_rate, uint32_t *fmts)
|
||||
uint32_t *max_rate, uint32_t *fmts, uint32_t *minchn, uint32_t *maxchn)
|
||||
{
|
||||
struct pcm_channel *c;
|
||||
unsigned int encoding;
|
||||
int dir;
|
||||
|
||||
dir = play ? PCMDIR_PLAY : PCMDIR_REC;
|
||||
*min_rate = 0;
|
||||
*max_rate = 0;
|
||||
*fmts = 0;
|
||||
|
||||
if (play && d->pvchancount > 0) {
|
||||
*min_rate = *max_rate = d->pvchanrate;
|
||||
*fmts = d->pvchanformat;
|
||||
*fmts = AFMT_ENCODING(d->pvchanformat);
|
||||
*minchn = *maxchn = AFMT_CHANNEL(d->pvchanformat);
|
||||
return;
|
||||
} else if (!play && d->rvchancount > 0) {
|
||||
*min_rate = *max_rate = d->rvchanrate;
|
||||
*fmts = d->rvchanformat;
|
||||
*fmts = AFMT_ENCODING(d->rvchanformat);
|
||||
*minchn = *maxchn = AFMT_CHANNEL(d->rvchanformat);
|
||||
return;
|
||||
}
|
||||
|
||||
*min_rate = UINT32_MAX;
|
||||
*max_rate = 0;
|
||||
*minchn = UINT32_MAX;
|
||||
*maxchn = 0;
|
||||
encoding = 0;
|
||||
CHN_FOREACH(c, d, channels.pcm) {
|
||||
struct pcmchan_caps *caps;
|
||||
int i;
|
||||
|
||||
if (c->direction != dir || (c->flags & CHN_F_VIRTUAL) != 0)
|
||||
continue;
|
||||
|
||||
CHN_LOCK(c);
|
||||
caps = chn_getcaps(c);
|
||||
*min_rate = caps->minspeed;
|
||||
*max_rate = caps->maxspeed;
|
||||
*fmts = chn_getformats(c);
|
||||
*min_rate = min(caps->minspeed, *min_rate);
|
||||
*max_rate = max(caps->maxspeed, *max_rate);
|
||||
for (i = 0; caps->fmtlist[i]; i++) {
|
||||
encoding |= AFMT_ENCODING(caps->fmtlist[i]);
|
||||
*minchn = min(AFMT_CHANNEL(encoding), *minchn);
|
||||
*maxchn = max(AFMT_CHANNEL(encoding), *maxchn);
|
||||
}
|
||||
CHN_UNLOCK(c);
|
||||
}
|
||||
if (*min_rate == UINT32_MAX)
|
||||
*min_rate = 0;
|
||||
if (*minchn == UINT32_MAX)
|
||||
*minchn = 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
nvlist_t *nv;
|
||||
|
||||
nv = nvlist_create(0);
|
||||
if (nv == NULL)
|
||||
return (NULL);
|
||||
nvlist_add_number(nv, SNDST_DSPS_INFO_MIN_RATE, min_rate);
|
||||
nvlist_add_number(nv, SNDST_DSPS_INFO_MAX_RATE, max_rate);
|
||||
nvlist_add_number(nv, SNDST_DSPS_INFO_FORMATS, formats);
|
||||
nvlist_add_number(nv, SNDST_DSPS_INFO_MIN_CHN, min_chn);
|
||||
nvlist_add_number(nv, SNDST_DSPS_INFO_MAX_CHN, max_chn);
|
||||
return (nv);
|
||||
}
|
||||
|
||||
static int
|
||||
sndstat_build_sound4_nvlist(struct snddev_info *d, nvlist_t **dip)
|
||||
{
|
||||
uint32_t maxrate, minrate, fmts;
|
||||
nvlist_t *di = NULL, *sound4di = NULL;
|
||||
uint32_t maxrate, minrate, fmts, minchn, maxchn;
|
||||
nvlist_t *di = NULL, *sound4di = NULL, *diinfo = NULL;
|
||||
int err;
|
||||
|
||||
di = nvlist_create(0);
|
||||
@ -379,40 +411,54 @@ sndstat_build_sound4_nvlist(struct snddev_info *d, nvlist_t **dip)
|
||||
goto done;
|
||||
}
|
||||
|
||||
nvlist_add_bool(di, SNDSTAT_LABEL_FROM_USER, false);
|
||||
nvlist_add_stringf(di, SNDSTAT_LABEL_NAMEUNIT, "%s",
|
||||
nvlist_add_bool(di, SNDST_DSPS_FROM_USER, false);
|
||||
nvlist_add_stringf(di, SNDST_DSPS_NAMEUNIT, "%s",
|
||||
device_get_nameunit(d->dev));
|
||||
nvlist_add_stringf(di, SNDSTAT_LABEL_DEVNODE, "dsp%d",
|
||||
nvlist_add_stringf(di, SNDST_DSPS_DEVNODE, "dsp%d",
|
||||
device_get_unit(d->dev));
|
||||
nvlist_add_string(
|
||||
di, SNDSTAT_LABEL_DESC, device_get_desc(d->dev));
|
||||
di, SNDST_DSPS_DESC, device_get_desc(d->dev));
|
||||
|
||||
PCM_ACQUIRE_QUICK(d);
|
||||
nvlist_add_number(di, SNDSTAT_LABEL_PCHAN, d->playcount);
|
||||
nvlist_add_number(di, SNDSTAT_LABEL_RCHAN, d->reccount);
|
||||
nvlist_add_number(di, SNDST_DSPS_PCHAN, d->playcount);
|
||||
nvlist_add_number(di, SNDST_DSPS_RCHAN, d->reccount);
|
||||
if (d->playcount > 0) {
|
||||
sndstat_get_caps(d, true, &minrate, &maxrate, &fmts);
|
||||
nvlist_add_number(di, SNDSTAT_LABEL_PMINRATE, minrate);
|
||||
nvlist_add_number(di, SNDSTAT_LABEL_PMAXRATE, maxrate);
|
||||
nvlist_add_number(di, SNDSTAT_LABEL_PFMTS, fmts);
|
||||
sndstat_get_caps(d, true, &minrate, &maxrate, &fmts, &minchn,
|
||||
&maxchn);
|
||||
nvlist_add_number(di, "pminrate", minrate);
|
||||
nvlist_add_number(di, "pmaxrate", maxrate);
|
||||
nvlist_add_number(di, "pfmts", fmts);
|
||||
diinfo = sndstat_create_diinfo_nv(minrate, maxrate, fmts,
|
||||
minchn, maxchn);
|
||||
if (diinfo == NULL)
|
||||
nvlist_set_error(di, ENOMEM);
|
||||
else
|
||||
nvlist_move_nvlist(di, SNDST_DSPS_INFO_PLAY, diinfo);
|
||||
}
|
||||
if (d->reccount > 0) {
|
||||
sndstat_get_caps(d, false, &minrate, &maxrate, &fmts);
|
||||
nvlist_add_number(di, SNDSTAT_LABEL_RMINRATE, minrate);
|
||||
nvlist_add_number(di, SNDSTAT_LABEL_RMAXRATE, maxrate);
|
||||
nvlist_add_number(di, SNDSTAT_LABEL_RFMTS, fmts);
|
||||
sndstat_get_caps(d, false, &minrate, &maxrate, &fmts, &minchn,
|
||||
&maxchn);
|
||||
nvlist_add_number(di, "rminrate", minrate);
|
||||
nvlist_add_number(di, "rmaxrate", maxrate);
|
||||
nvlist_add_number(di, "rfmts", fmts);
|
||||
diinfo = sndstat_create_diinfo_nv(minrate, maxrate, fmts,
|
||||
minchn, maxchn);
|
||||
if (diinfo == NULL)
|
||||
nvlist_set_error(di, ENOMEM);
|
||||
else
|
||||
nvlist_move_nvlist(di, SNDST_DSPS_INFO_REC, diinfo);
|
||||
}
|
||||
|
||||
nvlist_add_number(sound4di, SNDSTAT_LABEL_SOUND4_UNIT,
|
||||
nvlist_add_number(sound4di, SNDST_DSPS_SOUND4_UNIT,
|
||||
device_get_unit(d->dev)); // XXX: I want signed integer here
|
||||
nvlist_add_bool(
|
||||
sound4di, SNDSTAT_LABEL_SOUND4_BITPERFECT, d->flags & SD_F_BITPERFECT);
|
||||
nvlist_add_number(sound4di, SNDSTAT_LABEL_SOUND4_PVCHAN, d->pvchancount);
|
||||
nvlist_add_number(sound4di, SNDSTAT_LABEL_SOUND4_RVCHAN, d->rvchancount);
|
||||
nvlist_move_nvlist(di, SNDSTAT_LABEL_PROVIDER_INFO, sound4di);
|
||||
sound4di, SNDST_DSPS_SOUND4_BITPERFECT, d->flags & SD_F_BITPERFECT);
|
||||
nvlist_add_number(sound4di, SNDST_DSPS_SOUND4_PVCHAN, d->pvchancount);
|
||||
nvlist_add_number(sound4di, SNDST_DSPS_SOUND4_RVCHAN, d->rvchancount);
|
||||
nvlist_move_nvlist(di, SNDST_DSPS_PROVIDER_INFO, sound4di);
|
||||
sound4di = NULL;
|
||||
PCM_RELEASE_QUICK(d);
|
||||
nvlist_add_string(di, SNDSTAT_LABEL_PROVIDER, SNDSTAT_LABEL_SOUND4_PROVIDER);
|
||||
nvlist_add_string(di, SNDST_DSPS_PROVIDER, SNDST_DSPS_SOUND4_PROVIDER);
|
||||
|
||||
err = nvlist_error(di);
|
||||
if (err)
|
||||
@ -431,7 +477,7 @@ sndstat_build_sound4_nvlist(struct snddev_info *d, nvlist_t **dip)
|
||||
static int
|
||||
sndstat_build_userland_nvlist(struct sndstat_userdev *ud, nvlist_t **dip)
|
||||
{
|
||||
nvlist_t *di;
|
||||
nvlist_t *di, *diinfo;
|
||||
int err;
|
||||
|
||||
di = nvlist_create(0);
|
||||
@ -440,34 +486,48 @@ sndstat_build_userland_nvlist(struct sndstat_userdev *ud, nvlist_t **dip)
|
||||
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_NAMEUNIT, ud->nameunit);
|
||||
nvlist_add_bool(di, SNDST_DSPS_FROM_USER, true);
|
||||
nvlist_add_number(di, SNDST_DSPS_PCHAN, ud->pchan);
|
||||
nvlist_add_number(di, SNDST_DSPS_RCHAN, ud->rchan);
|
||||
nvlist_add_string(di, SNDST_DSPS_NAMEUNIT, ud->nameunit);
|
||||
nvlist_add_string(
|
||||
di, SNDSTAT_LABEL_DEVNODE, ud->devnode);
|
||||
nvlist_add_string(di, SNDSTAT_LABEL_DESC, ud->desc);
|
||||
di, SNDST_DSPS_DEVNODE, ud->devnode);
|
||||
nvlist_add_string(di, SNDST_DSPS_DESC, ud->desc);
|
||||
if (ud->pchan != 0) {
|
||||
nvlist_add_number(
|
||||
di, SNDSTAT_LABEL_PMINRATE, ud->pminrate);
|
||||
nvlist_add_number(
|
||||
di, SNDSTAT_LABEL_PMAXRATE, ud->pmaxrate);
|
||||
nvlist_add_number(
|
||||
di, SNDSTAT_LABEL_PFMTS, ud->pfmts);
|
||||
nvlist_add_number(di, "pminrate",
|
||||
ud->info_play.min_rate);
|
||||
nvlist_add_number(di, "pmaxrate",
|
||||
ud->info_play.max_rate);
|
||||
nvlist_add_number(di, "pfmts",
|
||||
ud->info_play.formats);
|
||||
diinfo = sndstat_create_diinfo_nv(ud->info_play.min_rate,
|
||||
ud->info_play.max_rate, ud->info_play.formats,
|
||||
ud->info_play.min_chn, ud->info_play.max_chn);
|
||||
if (diinfo == NULL)
|
||||
nvlist_set_error(di, ENOMEM);
|
||||
else
|
||||
nvlist_move_nvlist(di, SNDST_DSPS_INFO_PLAY, diinfo);
|
||||
}
|
||||
if (ud->rchan != 0) {
|
||||
nvlist_add_number(
|
||||
di, SNDSTAT_LABEL_RMINRATE, ud->rminrate);
|
||||
nvlist_add_number(
|
||||
di, SNDSTAT_LABEL_RMAXRATE, ud->rmaxrate);
|
||||
nvlist_add_number(
|
||||
di, SNDSTAT_LABEL_RFMTS, ud->rfmts);
|
||||
nvlist_add_number(di, "rminrate",
|
||||
ud->info_rec.min_rate);
|
||||
nvlist_add_number(di, "rmaxrate",
|
||||
ud->info_rec.max_rate);
|
||||
nvlist_add_number(di, "rfmts",
|
||||
ud->info_rec.formats);
|
||||
diinfo = sndstat_create_diinfo_nv(ud->info_rec.min_rate,
|
||||
ud->info_rec.max_rate, ud->info_rec.formats,
|
||||
ud->info_rec.min_chn, ud->info_rec.max_chn);
|
||||
if (diinfo == NULL)
|
||||
nvlist_set_error(di, ENOMEM);
|
||||
else
|
||||
nvlist_move_nvlist(di, SNDST_DSPS_INFO_REC, diinfo);
|
||||
}
|
||||
nvlist_add_string(di, SNDSTAT_LABEL_PROVIDER,
|
||||
nvlist_add_string(di, SNDST_DSPS_PROVIDER,
|
||||
(ud->provider != NULL) ? ud->provider : "");
|
||||
if (ud->provider_nvl != NULL)
|
||||
nvlist_add_nvlist(
|
||||
di, SNDSTAT_LABEL_PROVIDER_INFO, ud->provider_nvl);
|
||||
di, SNDST_DSPS_PROVIDER_INFO, ud->provider_nvl);
|
||||
|
||||
err = nvlist_error(di);
|
||||
if (err)
|
||||
@ -511,7 +571,7 @@ sndstat_create_devs_nvlist(nvlist_t **nvlp)
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
nvlist_append_nvlist_array(nvl, SNDSTAT_LABEL_DSPS, di);
|
||||
nvlist_append_nvlist_array(nvl, SNDST_DSPS, di);
|
||||
nvlist_destroy(di);
|
||||
err = nvlist_error(nvl);
|
||||
if (err)
|
||||
@ -531,7 +591,7 @@ sndstat_create_devs_nvlist(nvlist_t **nvlp)
|
||||
sx_xunlock(&pf->lock);
|
||||
goto done;
|
||||
}
|
||||
nvlist_append_nvlist_array(nvl, SNDSTAT_LABEL_DSPS, di);
|
||||
nvlist_append_nvlist_array(nvl, SNDST_DSPS, di);
|
||||
nvlist_destroy(di);
|
||||
|
||||
err = nvlist_error(nvl);
|
||||
@ -568,7 +628,7 @@ static int
|
||||
sndstat_get_devs(struct sndstat_file *pf, caddr_t data)
|
||||
{
|
||||
int err;
|
||||
struct sndstat_nvlbuf_arg *arg = (struct sndstat_nvlbuf_arg *)data;
|
||||
struct sndstioc_nv_arg *arg = (struct sndstioc_nv_arg *)data;
|
||||
|
||||
SNDSTAT_LOCK();
|
||||
sx_xlock(&pf->lock);
|
||||
@ -654,31 +714,65 @@ sndstat_unpack_user_nvlbuf(const void *unvlbuf, size_t nbytes, nvlist_t **nvl)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static bool
|
||||
sndstat_diinfo_is_sane(const nvlist_t *diinfo)
|
||||
{
|
||||
if (!(nvlist_exists_number(diinfo, SNDST_DSPS_INFO_MIN_RATE) &&
|
||||
nvlist_exists_number(diinfo, SNDST_DSPS_INFO_MAX_RATE) &&
|
||||
nvlist_exists_number(diinfo, SNDST_DSPS_INFO_FORMATS) &&
|
||||
nvlist_exists_number(diinfo, SNDST_DSPS_INFO_MIN_CHN) &&
|
||||
nvlist_exists_number(diinfo, SNDST_DSPS_INFO_MAX_CHN)))
|
||||
return (false);
|
||||
return (true);
|
||||
}
|
||||
|
||||
static bool
|
||||
sndstat_dsp_nvlist_is_sane(const nvlist_t *nvlist)
|
||||
{
|
||||
if (!(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)))
|
||||
if (!(nvlist_exists_string(nvlist, SNDST_DSPS_DEVNODE) &&
|
||||
nvlist_exists_string(nvlist, SNDST_DSPS_DESC) &&
|
||||
nvlist_exists_number(nvlist, SNDST_DSPS_PCHAN) &&
|
||||
nvlist_exists_number(nvlist, SNDST_DSPS_RCHAN)))
|
||||
return (false);
|
||||
|
||||
if (nvlist_get_number(nvlist, SNDSTAT_LABEL_PCHAN) > 0)
|
||||
if (!(nvlist_exists_number(nvlist, SNDSTAT_LABEL_PMINRATE) &&
|
||||
nvlist_exists_number(nvlist, SNDSTAT_LABEL_PMAXRATE) &&
|
||||
nvlist_exists_number(nvlist, SNDSTAT_LABEL_PFMTS)))
|
||||
if (nvlist_get_number(nvlist, SNDST_DSPS_PCHAN) > 0) {
|
||||
if (nvlist_exists_nvlist(nvlist, SNDST_DSPS_INFO_PLAY)) {
|
||||
if (!sndstat_diinfo_is_sane(nvlist_get_nvlist(nvlist,
|
||||
SNDST_DSPS_INFO_PLAY)))
|
||||
return (false);
|
||||
} else if (!(nvlist_exists_number(nvlist, "pminrate") &&
|
||||
nvlist_exists_number(nvlist, "pmaxrate") &&
|
||||
nvlist_exists_number(nvlist, "pfmts")))
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (nvlist_get_number(nvlist, SNDSTAT_LABEL_RCHAN) > 0)
|
||||
if (!(nvlist_exists_number(nvlist, SNDSTAT_LABEL_RMINRATE) &&
|
||||
nvlist_exists_number(nvlist, SNDSTAT_LABEL_RMAXRATE) &&
|
||||
nvlist_exists_number(nvlist, SNDSTAT_LABEL_RFMTS)))
|
||||
if (nvlist_get_number(nvlist, SNDST_DSPS_RCHAN) > 0) {
|
||||
if (nvlist_exists_nvlist(nvlist, SNDST_DSPS_INFO_REC)) {
|
||||
if (!sndstat_diinfo_is_sane(nvlist_get_nvlist(nvlist,
|
||||
SNDST_DSPS_INFO_REC)))
|
||||
return (false);
|
||||
} else if (!(nvlist_exists_number(nvlist, "rminrate") &&
|
||||
nvlist_exists_number(nvlist, "rmaxrate") &&
|
||||
nvlist_exists_number(nvlist, "rfmts")))
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
*min_rate = nvlist_get_number(nv, SNDST_DSPS_INFO_MIN_RATE);
|
||||
*max_rate = nvlist_get_number(nv, SNDST_DSPS_INFO_MAX_RATE);
|
||||
*formats = nvlist_get_number(nv, SNDST_DSPS_INFO_FORMATS);
|
||||
*min_chn = nvlist_get_number(nv, SNDST_DSPS_INFO_MIN_CHN);
|
||||
*max_chn = nvlist_get_number(nv, SNDST_DSPS_INFO_MAX_CHN);
|
||||
}
|
||||
|
||||
static int
|
||||
sndstat_dsp_unpack_nvlist(const nvlist_t *nvlist, struct sndstat_userdev *ud)
|
||||
{
|
||||
@ -687,36 +781,53 @@ sndstat_dsp_unpack_nvlist(const nvlist_t *nvlist, struct sndstat_userdev *ud)
|
||||
uint32_t pminrate = 0, pmaxrate = 0;
|
||||
uint32_t rminrate = 0, rmaxrate = 0;
|
||||
uint32_t pfmts = 0, rfmts = 0;
|
||||
uint32_t pminchn = 0, pmaxchn = 0;
|
||||
uint32_t rminchn = 0, rmaxchn = 0;
|
||||
nvlist_t *provider_nvl = NULL;
|
||||
const nvlist_t *diinfo;
|
||||
const char *provider;
|
||||
|
||||
devnode = nvlist_get_string(nvlist, SNDSTAT_LABEL_DEVNODE);
|
||||
if (nvlist_exists_string(nvlist, SNDSTAT_LABEL_NAMEUNIT))
|
||||
nameunit = nvlist_get_string(nvlist, SNDSTAT_LABEL_NAMEUNIT);
|
||||
devnode = nvlist_get_string(nvlist, SNDST_DSPS_DEVNODE);
|
||||
if (nvlist_exists_string(nvlist, SNDST_DSPS_NAMEUNIT))
|
||||
nameunit = nvlist_get_string(nvlist, SNDST_DSPS_NAMEUNIT);
|
||||
else
|
||||
nameunit = devnode;
|
||||
desc = nvlist_get_string(nvlist, SNDSTAT_LABEL_DESC);
|
||||
pchan = nvlist_get_number(nvlist, SNDSTAT_LABEL_PCHAN);
|
||||
rchan = nvlist_get_number(nvlist, SNDSTAT_LABEL_RCHAN);
|
||||
desc = nvlist_get_string(nvlist, SNDST_DSPS_DESC);
|
||||
pchan = nvlist_get_number(nvlist, SNDST_DSPS_PCHAN);
|
||||
rchan = nvlist_get_number(nvlist, SNDST_DSPS_RCHAN);
|
||||
if (pchan != 0) {
|
||||
pminrate = nvlist_get_number(nvlist, SNDSTAT_LABEL_PMINRATE);
|
||||
pmaxrate = nvlist_get_number(nvlist, SNDSTAT_LABEL_PMAXRATE);
|
||||
pfmts = nvlist_get_number(nvlist, SNDSTAT_LABEL_PFMTS);
|
||||
if (nvlist_exists_nvlist(nvlist, SNDST_DSPS_INFO_PLAY)) {
|
||||
diinfo = nvlist_get_nvlist(nvlist,
|
||||
SNDST_DSPS_INFO_PLAY);
|
||||
sndstat_get_diinfo_nv(diinfo, &pminrate, &pmaxrate,
|
||||
&pfmts, &pminchn, &pmaxchn);
|
||||
} else {
|
||||
pminrate = nvlist_get_number(nvlist, "pminrate");
|
||||
pmaxrate = nvlist_get_number(nvlist, "pmaxrate");
|
||||
pfmts = nvlist_get_number(nvlist, "pfmts");
|
||||
}
|
||||
}
|
||||
if (rchan != 0) {
|
||||
rminrate = nvlist_get_number(nvlist, SNDSTAT_LABEL_RMINRATE);
|
||||
rmaxrate = nvlist_get_number(nvlist, SNDSTAT_LABEL_RMAXRATE);
|
||||
rfmts = nvlist_get_number(nvlist, SNDSTAT_LABEL_RFMTS);
|
||||
if (nvlist_exists_nvlist(nvlist, SNDST_DSPS_INFO_REC)) {
|
||||
diinfo = nvlist_get_nvlist(nvlist,
|
||||
SNDST_DSPS_INFO_REC);
|
||||
sndstat_get_diinfo_nv(diinfo, &rminrate, &rmaxrate,
|
||||
&rfmts, &rminchn, &rmaxchn);
|
||||
} else {
|
||||
rminrate = nvlist_get_number(nvlist, "rminrate");
|
||||
rmaxrate = nvlist_get_number(nvlist, "rmaxrate");
|
||||
rfmts = nvlist_get_number(nvlist, "rfmts");
|
||||
}
|
||||
}
|
||||
|
||||
provider = dnvlist_get_string(nvlist, SNDSTAT_LABEL_PROVIDER, "");
|
||||
provider = dnvlist_get_string(nvlist, SNDST_DSPS_PROVIDER, "");
|
||||
if (provider[0] == '\0')
|
||||
provider = NULL;
|
||||
|
||||
if (provider != NULL &&
|
||||
nvlist_exists_nvlist(nvlist, SNDSTAT_LABEL_PROVIDER_INFO)) {
|
||||
nvlist_exists_nvlist(nvlist, SNDST_DSPS_PROVIDER_INFO)) {
|
||||
provider_nvl = nvlist_clone(
|
||||
nvlist_get_nvlist(nvlist, SNDSTAT_LABEL_PROVIDER_INFO));
|
||||
nvlist_get_nvlist(nvlist, SNDST_DSPS_PROVIDER_INFO));
|
||||
if (provider_nvl == NULL)
|
||||
return (ENOMEM);
|
||||
}
|
||||
@ -727,12 +838,16 @@ sndstat_dsp_unpack_nvlist(const nvlist_t *nvlist, struct sndstat_userdev *ud)
|
||||
ud->desc = strdup(desc, M_DEVBUF);
|
||||
ud->pchan = pchan;
|
||||
ud->rchan = rchan;
|
||||
ud->pminrate = pminrate;
|
||||
ud->pmaxrate = pmaxrate;
|
||||
ud->rminrate = rminrate;
|
||||
ud->rmaxrate = rmaxrate;
|
||||
ud->pfmts = pfmts;
|
||||
ud->rfmts = rfmts;
|
||||
ud->info_play.min_rate = pminrate;
|
||||
ud->info_play.max_rate = pmaxrate;
|
||||
ud->info_play.formats = pfmts;
|
||||
ud->info_play.min_chn = pminchn;
|
||||
ud->info_play.max_chn = pmaxchn;
|
||||
ud->info_rec.min_rate = rminrate;
|
||||
ud->info_rec.max_rate = rmaxrate;
|
||||
ud->info_rec.formats = rfmts;
|
||||
ud->info_rec.min_chn = rminchn;
|
||||
ud->info_rec.max_chn = rmaxchn;
|
||||
ud->provider_nvl = provider_nvl;
|
||||
return (0);
|
||||
}
|
||||
@ -744,7 +859,7 @@ sndstat_add_user_devs(struct sndstat_file *pf, caddr_t data)
|
||||
nvlist_t *nvl = NULL;
|
||||
const nvlist_t * const *dsps;
|
||||
size_t i, ndsps;
|
||||
struct sndstat_nvlbuf_arg *arg = (struct sndstat_nvlbuf_arg *)data;
|
||||
struct sndstioc_nv_arg *arg = (struct sndstioc_nv_arg *)data;
|
||||
|
||||
if ((pf->fflags & FWRITE) == 0) {
|
||||
err = EPERM;
|
||||
@ -755,11 +870,11 @@ sndstat_add_user_devs(struct sndstat_file *pf, caddr_t data)
|
||||
if (err != 0)
|
||||
goto done;
|
||||
|
||||
if (!nvlist_exists_nvlist_array(nvl, SNDSTAT_LABEL_DSPS)) {
|
||||
if (!nvlist_exists_nvlist_array(nvl, SNDST_DSPS)) {
|
||||
err = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
dsps = nvlist_get_nvlist_array(nvl, SNDSTAT_LABEL_DSPS, &ndsps);
|
||||
dsps = nvlist_get_nvlist_array(nvl, SNDST_DSPS, &ndsps);
|
||||
for (i = 0; i < ndsps; i++) {
|
||||
if (!sndstat_dsp_nvlist_is_sane(dsps[i])) {
|
||||
err = EINVAL;
|
||||
@ -801,8 +916,8 @@ sndstat_flush_user_devs(struct sndstat_file *pf)
|
||||
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;
|
||||
struct sndstioc_nv_arg32 *arg32 = (struct sndstioc_nv_arg32 *)data;
|
||||
struct sndstioc_nv_arg arg;
|
||||
int err;
|
||||
|
||||
arg.buf = (void *)(uintptr_t)arg32->buf;
|
||||
@ -820,8 +935,8 @@ compat_sndstat_get_devs32(struct sndstat_file *pf, caddr_t data)
|
||||
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;
|
||||
struct sndstioc_nv_arg32 *arg32 = (struct sndstioc_nv_arg32 *)data;
|
||||
struct sndstioc_nv_arg arg;
|
||||
int err;
|
||||
|
||||
arg.buf = (void *)(uintptr_t)arg32->buf;
|
||||
@ -849,11 +964,11 @@ sndstat_ioctl(
|
||||
return (err);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDSTAT_GET_DEVS:
|
||||
case SNDSTIOC_GET_DEVS:
|
||||
err = sndstat_get_devs(pf, data);
|
||||
break;
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
case SNDSTAT_GET_DEVS32:
|
||||
case SNDSTIOC_GET_DEVS32:
|
||||
if (!SV_CURPROC_FLAG(SV_ILP32)) {
|
||||
err = ENODEV;
|
||||
break;
|
||||
@ -861,11 +976,11 @@ sndstat_ioctl(
|
||||
err = compat_sndstat_get_devs32(pf, data);
|
||||
break;
|
||||
#endif
|
||||
case SNDSTAT_ADD_USER_DEVS:
|
||||
case SNDSTIOC_ADD_USER_DEVS:
|
||||
err = sndstat_add_user_devs(pf, data);
|
||||
break;
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
case SNDSTAT_ADD_USER_DEVS32:
|
||||
case SNDSTIOC_ADD_USER_DEVS32:
|
||||
if (!SV_CURPROC_FLAG(SV_ILP32)) {
|
||||
err = ENODEV;
|
||||
break;
|
||||
@ -873,10 +988,10 @@ sndstat_ioctl(
|
||||
err = compat_sndstat_add_user_devs32(pf, data);
|
||||
break;
|
||||
#endif
|
||||
case SNDSTAT_REFRESH_DEVS:
|
||||
case SNDSTIOC_REFRESH_DEVS:
|
||||
err = sndstat_refresh_devs(pf);
|
||||
break;
|
||||
case SNDSTAT_FLUSH_USER_DEVS:
|
||||
case SNDSTIOC_FLUSH_USER_DEVS:
|
||||
err = sndstat_flush_user_devs(pf);
|
||||
break;
|
||||
default:
|
||||
|
@ -38,56 +38,65 @@
|
||||
#include <sys/ioccom.h>
|
||||
#endif /* !_IOWR */
|
||||
|
||||
struct sndstat_nvlbuf_arg {
|
||||
struct sndstioc_nv_arg {
|
||||
size_t nbytes; /* [IN/OUT] buffer size/number of bytes filled */
|
||||
void *buf; /* [OUT] buffer holding a packed nvlist */
|
||||
};
|
||||
|
||||
/*
|
||||
* Common labels
|
||||
* Common name/value pair names
|
||||
*/
|
||||
#define SNDSTAT_LABEL_DSPS "dsps"
|
||||
#define SNDSTAT_LABEL_FROM_USER "from_user"
|
||||
#define SNDSTAT_LABEL_PCHAN "pchan"
|
||||
#define SNDSTAT_LABEL_RCHAN "rchan"
|
||||
#define SNDSTAT_LABEL_PMINRATE "pminrate"
|
||||
#define SNDSTAT_LABEL_PMAXRATE "pmaxrate"
|
||||
#define SNDSTAT_LABEL_RMINRATE "rminrate"
|
||||
#define SNDSTAT_LABEL_RMAXRATE "rmaxrate"
|
||||
#define SNDSTAT_LABEL_PFMTS "pfmts"
|
||||
#define SNDSTAT_LABEL_RFMTS "rfmts"
|
||||
#define SNDSTAT_LABEL_NAMEUNIT "nameunit"
|
||||
#define SNDSTAT_LABEL_DEVNODE "devnode"
|
||||
#define SNDSTAT_LABEL_DESC "desc"
|
||||
#define SNDSTAT_LABEL_PROVIDER "provider"
|
||||
#define SNDSTAT_LABEL_PROVIDER_INFO "provider_info"
|
||||
#define SNDST_DSPS "dsps"
|
||||
#define SNDST_DSPS_FROM_USER "from_user"
|
||||
#define SNDST_DSPS_PCHAN "pchan"
|
||||
#define SNDST_DSPS_RCHAN "rchan"
|
||||
#define SNDST_DSPS_NAMEUNIT "nameunit"
|
||||
#define SNDST_DSPS_DEVNODE "devnode"
|
||||
#define SNDST_DSPS_DESC "desc"
|
||||
#define SNDST_DSPS_PROVIDER "provider"
|
||||
#define SNDST_DSPS_PROVIDER_INFO "provider_info"
|
||||
|
||||
/*
|
||||
* sound(4)-specific labels
|
||||
* Common name/value pair names for play/rec info
|
||||
*/
|
||||
#define SNDSTAT_LABEL_SOUND4_PROVIDER "sound(4)"
|
||||
#define SNDSTAT_LABEL_SOUND4_UNIT "unit"
|
||||
#define SNDSTAT_LABEL_SOUND4_BITPERFECT "bitperfect"
|
||||
#define SNDSTAT_LABEL_SOUND4_PVCHAN "pvchan"
|
||||
#define SNDSTAT_LABEL_SOUND4_RVCHAN "rvchan"
|
||||
#define SNDST_DSPS_INFO_PLAY "info_play"
|
||||
#define SNDST_DSPS_INFO_REC "info_rec"
|
||||
#define SNDST_DSPS_INFO_MIN_RATE "min_rate"
|
||||
#define SNDST_DSPS_INFO_MAX_RATE "max_rate"
|
||||
#define SNDST_DSPS_INFO_FORMATS "formats"
|
||||
#define SNDST_DSPS_INFO_MIN_CHN "min_chn"
|
||||
#define SNDST_DSPS_INFO_MAX_CHN "max_chn"
|
||||
|
||||
#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)
|
||||
#define SNDSTAT_FLUSH_USER_DEVS _IO('D', 103)
|
||||
/*
|
||||
* sound(4)-specific name/value pair names
|
||||
*/
|
||||
#define SNDST_DSPS_SOUND4_PROVIDER "sound(4)"
|
||||
#define SNDST_DSPS_SOUND4_UNIT "unit"
|
||||
#define SNDST_DSPS_SOUND4_BITPERFECT "bitperfect"
|
||||
#define SNDST_DSPS_SOUND4_PVCHAN "pvchan"
|
||||
#define SNDST_DSPS_SOUND4_RVCHAN "rvchan"
|
||||
|
||||
#define SNDSTIOC_REFRESH_DEVS \
|
||||
_IO('D', 100)
|
||||
#define SNDSTIOC_GET_DEVS \
|
||||
_IOWR('D', 101, struct sndstioc_nv_arg)
|
||||
#define SNDSTIOC_ADD_USER_DEVS \
|
||||
_IOWR('D', 102, struct sndstioc_nv_arg)
|
||||
#define SNDSTIOC_FLUSH_USER_DEVS \
|
||||
_IO('D', 103)
|
||||
|
||||
#ifdef _KERNEL
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
|
||||
struct sndstat_nvlbuf_arg32 {
|
||||
struct sndstioc_nv_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)
|
||||
#define SNDSTIOC_GET_DEVS32 \
|
||||
_IOC_NEWTYPE(SNDSTIOC_GET_DEVS, struct sndstioc_nv_arg32)
|
||||
#define SNDSTIOC_ADD_USER_DEVS32 \
|
||||
_IOC_NEWTYPE(SNDSTIOC_ADD_USER_DEVS, struct sndstioc_nv_arg32)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user