svn commit: r222826 - head/sys/dev/sound/pcm

Alexander Motin mav at FreeBSD.org
Tue Jun 7 17:01:52 UTC 2011


Author: mav
Date: Tue Jun  7 17:01:52 2011
New Revision: 222826
URL: http://svn.freebsd.org/changeset/base/222826

Log:
  Make automatic hw.snd.default_unit choice a bit more intelligent. Instead
  of just setting it to the first registered device, reevaluate it for each
  device registered, trying to choose best candidate, unless one was forced.
  For now use such preference order: play&rec, play, rec.
  
  As side effect, this should workaround the situation when HDMI audio output
  of the video card, usually not connected to anything, becomes default, that
  requires manual user intervention to make sound working. If at some point
  this won't be enough, we can try to fetch some additional priority flags
  from the device driver.

Modified:
  head/sys/dev/sound/pcm/sound.c

Modified: head/sys/dev/sound/pcm/sound.c
==============================================================================
--- head/sys/dev/sound/pcm/sound.c	Tue Jun  7 16:23:27 2011	(r222825)
+++ head/sys/dev/sound/pcm/sound.c	Tue Jun  7 17:01:52 2011	(r222826)
@@ -51,7 +51,7 @@ int pcm_veto_load = 1;
 int snd_unit = -1;
 TUNABLE_INT("hw.snd.default_unit", &snd_unit);
 
-static int snd_unit_auto = 0;
+static int snd_unit_auto = -1;
 TUNABLE_INT("hw.snd.default_auto", &snd_unit_auto);
 SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RW,
     &snd_unit_auto, 0, "assign default unit to a newly attached device");
@@ -443,6 +443,7 @@ sysctl_hw_snd_default_unit(SYSCTL_HANDLE
 		if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm))
 			return EINVAL;
 		snd_unit = unit;
+		snd_unit_auto = 0;
 	}
 	return (error);
 }
@@ -737,6 +738,32 @@ pcm_killchan(device_t dev)
 	return (pcm_chn_destroy(ch));
 }
 
+static int
+pcm_best_unit(int old)
+{
+	struct snddev_info *d;
+	int i, best, bestprio, prio;
+
+	best = -1;
+	bestprio = -100;
+	for (i = 0; pcm_devclass != NULL &&
+	    i < devclass_get_maxunit(pcm_devclass); i++) {
+		d = devclass_get_softc(pcm_devclass, i);
+		if (!PCM_REGISTERED(d))
+			continue;
+		prio = 0;
+		if (d->playcount == 0)
+			prio -= 10;
+		if (d->reccount == 0)
+			prio -= 2;
+		if (prio > bestprio || (prio == bestprio && i == old)) {
+			best = i;
+			bestprio = prio;
+		}
+	}
+	return (best);
+}
+
 int
 pcm_setstatus(device_t dev, char *str)
 {
@@ -770,8 +797,12 @@ pcm_setstatus(device_t dev, char *str)
 
 	PCM_UNLOCK(d);
 
-	if (snd_unit < 0 || snd_unit_auto != 0)
+	if (snd_unit_auto < 0)
+		snd_unit_auto = (snd_unit < 0) ? 1 : 0;
+	if (snd_unit < 0 || snd_unit_auto > 1)
 		snd_unit = device_get_unit(dev);
+	else if (snd_unit_auto == 1)
+		snd_unit = pcm_best_unit(snd_unit);
 
 	return (0);
 }
@@ -1113,7 +1144,6 @@ pcm_unregister(device_t dev)
 	struct snddev_info *d;
 	struct pcm_channel *ch;
 	struct thread *td;
-	int i;
 
 	td = curthread;
 	d = device_get_softc(dev);
@@ -1216,21 +1246,9 @@ pcm_unregister(device_t dev)
 	sndstat_release(td);
 
 	if (snd_unit == device_get_unit(dev)) {
-		/*
-		 * Reassign default unit to the next available dev, but
-		 * first, reset snd_unit to something ridiculous.
-		 */
-		snd_unit = -1;
-		for (i = 0; pcm_devclass != NULL &&
-		    i < devclass_get_maxunit(pcm_devclass); i++) {
-			if (device_get_unit(dev) == i)
-				continue;
-			d = devclass_get_softc(pcm_devclass, i);
-			if (PCM_REGISTERED(d)) {
-				snd_unit = i;
-				break;
-			}
-		}
+		snd_unit = pcm_best_unit(-1);
+		if (snd_unit_auto == 0)
+			snd_unit_auto = 1;
 	}
 
 	return (0);


More information about the svn-src-head mailing list