git: 4ce1ba652383 - main - sndstat: nvlist schema and API definition changes

Ka Ho Ng khng at FreeBSD.org
Wed Apr 21 08:22:15 UTC 2021


The branch main has been updated by khng:

URL: https://cgit.FreeBSD.org/src/commit/?id=4ce1ba6523839b5c88331de22937b1e0483fc40b

commit 4ce1ba6523839b5c88331de22937b1e0483fc40b
Author:     Ka Ho Ng <khng at FreeBSD.org>
AuthorDate: 2021-04-21 08:19:15 +0000
Commit:     Ka Ho Ng <khng at FreeBSD.org>
CommitDate: 2021-04-21 08:19:15 +0000

    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
---
 share/man/man4/sndstat.4    | 101 ++++++++------
 sys/dev/sound/pcm/sndstat.c | 329 ++++++++++++++++++++++++++++++--------------
 sys/sys/sndstat.h           |  73 +++++-----
 3 files changed, 322 insertions(+), 181 deletions(-)

diff --git a/share/man/man4/sndstat.4 b/share/man/man4/sndstat.4
index ad5f4a76ea7e..26ecf9084dc1 100644
--- a/share/man/man4/sndstat.4
+++ b/share/man/man4/sndstat.4
@@ -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);
 	}
diff --git a/sys/dev/sound/pcm/sndstat.c b/sys/dev/sound/pcm/sndstat.c
index e89af772fe72..ea36f4ba79ba 100644
--- a/sys/dev/sound/pcm/sndstat.c
+++ b/sys/dev/sound/pcm/sndstat.c
@@ -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 @@ done:
 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:
diff --git a/sys/sys/sndstat.h b/sys/sys/sndstat.h
index 995d474f8290..bd9b76e1652d 100644
--- a/sys/sys/sndstat.h
+++ b/sys/sys/sndstat.h
@@ -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


More information about the dev-commits-src-all mailing list