Hello!

I need functionality similar to FreeBSD hw.snd.default_unit sysctl. It
defines which audio devices (/dev/dspN, /dev/mixerN) will be opened if
someone opens /dev/dsp or /dev/mixer.

I don't have a good idea how this can be done. I've made a quick patch for
dsp devices, it is attached.
The problem is that now the "default" node is opened all the time, no
matter if I open /dev/dsp or a specific /dev/dspN device.

My first thought was to compare ap->a_name to "dsp" to know if we just open
/dev/dsp or more specific /dev/dspN, but ap->a_name always has a form
"dspN", even if /dev/dsp is opened.

Any ideas how to implement this correctly?

                Vasily
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index 3206a42..7b1cf6d 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -1228,7 +1228,7 @@ dsp_mmap(struct dev_mmap_args *ap)
 int
 dsp_clone(struct dev_clone_args *ap)
 {
-	struct cdev *i_dev = ap->a_head.a_dev;
+	struct cdev *i_dev;
 	struct cdev *pdev;
 	struct snddev_info *pcm_dev;
 	struct snddev_channel *pcm_chan;
@@ -1236,7 +1236,8 @@ dsp_clone(struct dev_clone_args *ap)
 	int err = EBUSY;
 	int dir;
 
-	pcm_dev = dsp_get_info(i_dev);
+	pcm_dev = devclass_get_softc(pcm_devclass, snd_default_unit);
+	i_dev = pcm_dev->dsp_clonedev;
 
 	if (pcm_dev == NULL)
 		return (ENODEV);
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 8f2a455..da42354 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -42,6 +42,10 @@ devclass_t pcm_devclass;
 
 int pcm_veto_load = 1;
 
+int snd_default_unit = -1;
+TUNABLE_INT("hw.snd.default_unit", &snd_default_unit);
+static int get_suitable_unit(void);
+
 int snd_maxautovchans = 4;
 TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans);
 
@@ -354,14 +358,13 @@ pcm_setmaxautovchans(struct snddev_info *d, int num)
 		pcm_setvchans(d, 0);
 }
 
-#ifdef USING_DEVFS
 static int
 sysctl_hw_snd_unit(SYSCTL_HANDLER_ARGS)
 {
 	struct snddev_info *d;
 	int error, unit;
 
-	unit = snd_unit;
+	unit = snd_default_unit;
 	error = sysctl_handle_int(oidp, &unit, sizeof(unit), req);
 	if (error == 0 && req->newptr != NULL) {
 		if (unit < 0 || (pcm_devclass != NULL &&
@@ -370,13 +373,12 @@ sysctl_hw_snd_unit(SYSCTL_HANDLER_ARGS)
 		d = devclass_get_softc(pcm_devclass, unit);
 		if (d == NULL || SLIST_EMPTY(&d->channels))
 			return EINVAL;
-		snd_unit = unit;
+		snd_default_unit = unit;
 	}
 	return (error);
 }
-SYSCTL_PROC(_hw_snd, OID_AUTO, unit, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, CTLTYPE_INT | CTLFLAG_RW,
             0, sizeof(int), sysctl_hw_snd_unit, "I", "");
-#endif
 
 static int
 sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
@@ -744,6 +746,8 @@ pcm_setstatus(device_t dev, char *str)
 	snd_mtxunlock(d->lock);
 	if (snd_maxautovchans > 0)
 		pcm_setvchans(d, 1);
+	if (snd_default_unit < 0)
+		snd_default_unit = device_get_unit(dev);
 	return 0;
 }
 
@@ -870,6 +874,20 @@ no:
 	return ENXIO;
 }
 
+static int
+get_suitable_unit(void)
+{
+	struct snddev_info *d;
+	int i;
+	for (i = 0; pcm_devclass != NULL &&
+		i < devclass_get_maxunit(pcm_devclass); i++) {
+		d = devclass_get_softc(pcm_devclass, i);
+		if (d != NULL && (!SLIST_EMPTY(&d->channels)))
+			 return i;
+	}
+	return -1;
+}
+
 int
 pcm_unregister(device_t dev)
 {
@@ -963,6 +981,9 @@ pcm_unregister(device_t dev)
 	snd_mtxfree(d->lock);
 	sndstat_unregister(dev);
 	sndstat_release();
+
+	if (device_get_unit(dev) == snd_default_unit)
+		snd_default_unit = get_suitable_unit();
 	return 0;
 }
 
@@ -999,12 +1020,7 @@ sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose)
 		}
 		sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)", d->playcount, d->reccount, d->vchancount,
 				(d->flags & SD_F_SIMPLEX)? "" : " duplex",
-#ifdef USING_DEVFS
-				(device_get_unit(dev) == snd_unit)? " default" : ""
-#else
-				""
-#endif
-				);
+				(device_get_unit(dev) == snd_default_unit)? " default" : "");
 
 		if (verbose <= 1) {
 			snd_mtxunlock(d->lock);
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index 212db71..f5b3a94 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -174,6 +174,7 @@ int fkchan_kill(struct pcm_channel *c);
 extern int pcm_veto_load;
 extern int snd_maxautovchans;
 extern devclass_t pcm_devclass;
+extern int snd_default_unit;
 
 /*
  * some macros for debugging purposes

Reply via email to