From 69f6d261cfa932992b7ea4378ab7c4c617b45b1e Mon Sep 17 00:00:00 2001
From: Ariff Abdullah <ariff@FreeBSD.org>
Date: Tue, 5 Jun 2007 20:30:16 +0000
Subject: [PATCH] - Do triple reads on reset register to detect read register
 bug. 2 reads   seems not enough to verify its consistencies. - Define
 AC97_MIXER_SIZE as SOUND_MIXER_NRDEVICES (25), since we   don't need more
 than that. Stop doing wild and random guess about   its size since we're
 stricly bound to it.

---
 sys/dev/sound/pcm/ac97.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/sys/dev/sound/pcm/ac97.c b/sys/dev/sound/pcm/ac97.c
index 44c947c62a90..5abab7fc4304 100644
--- a/sys/dev/sound/pcm/ac97.c
+++ b/sys/dev/sound/pcm/ac97.c
@@ -48,7 +48,8 @@ struct ac97mixtable_entry {
 	unsigned enable:1;	/* entry is enabled		*/
 };
 
-#define AC97_NAMELEN	16
+#define AC97_MIXER_SIZE		SOUND_MIXER_NRDEVICES
+
 struct ac97_info {
 	kobj_t methods;
 	device_t dev;
@@ -57,8 +58,8 @@ struct ac97_info {
 	u_int32_t subvendor;
 	unsigned count, caps, se, extcaps, extid, extstat, noext:1;
 	u_int32_t flags;
-	struct ac97mixtable_entry mix[32];
-	char name[AC97_NAMELEN];
+	struct ac97mixtable_entry mix[AC97_MIXER_SIZE];
+	char name[16];
 	struct mtx *lock;
 };
 
@@ -75,7 +76,7 @@ struct ac97_codecid {
 	ac97_patch patch;
 };
 
-static const struct ac97mixtable_entry ac97mixtable_default[32] = {
+static const struct ac97mixtable_entry ac97mixtable_default[AC97_MIXER_SIZE] = {
     /*	[offset]			reg	     bits of st mu re mk en */
 	[SOUND_MIXER_VOLUME]	= { AC97_MIX_MASTER, 	5, 0, 1, 1, 6, 0, 1 },
 	[SOUND_MIXER_OGAIN]	= { AC97_MIX_AUXOUT, 	5, 0, 1, 1, 0, 0, 0 },
@@ -614,12 +615,13 @@ ac97_initmixer(struct ac97_info *codec)
 
 	i = ac97_rdcd(codec, AC97_REG_RESET);
 	j = ac97_rdcd(codec, AC97_REG_RESET);
+	k = ac97_rdcd(codec, AC97_REG_RESET);
 	/*
 	 * Let see if this codec can return consistent value.
 	 * If not, turn on aggressive read workaround
 	 * (STAC9704 comes in mind).
 	 */
-	if (i != j) {
+	if (i != j || j != k) {
 		codec->flags |= AC97_F_RDCD_BUG;
 		i = ac97_rdcd(codec, AC97_REG_RESET);
 	}
@@ -674,7 +676,7 @@ ac97_initmixer(struct ac97_info *codec)
 		}
 	}
 
-	for (i = 0; i < 32; i++) {
+	for (i = 0; i < AC97_MIXER_SIZE; i++) {
 		codec->mix[i] = ac97mixtable_default[i];
 	}
 	ac97_fix_auxout(codec);
@@ -682,7 +684,7 @@ ac97_initmixer(struct ac97_info *codec)
 	if (codec_patch)
 		codec_patch(codec);
 
-	for (i = 0; i < 32; i++) {
+	for (i = 0; i < AC97_MIXER_SIZE; i++) {
 		k = codec->noext? codec->mix[i].enable : 1;
 		reg = codec->mix[i].reg;
 		if (reg < 0)
@@ -826,7 +828,8 @@ ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
 	if (codec == NULL)
 		return NULL;
 
-	snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
+	snprintf(codec->name, sizeof(codec->name), "%s:ac97",
+	    device_get_nameunit(dev));
 	codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
 	codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
 	codec->dev = dev;
@@ -980,12 +983,12 @@ ac97mix_init(struct snd_mixer *m)
 #endif
 
 	mask = 0;
-	for (i = 0; i < 32; i++)
+	for (i = 0; i < AC97_MIXER_SIZE; i++)
 		mask |= codec->mix[i].enable? 1 << i : 0;
 	mix_setdevs(m, mask);
 
 	mask = 0;
-	for (i = 0; i < 32; i++)
+	for (i = 0; i < AC97_MIXER_SIZE; i++)
 		mask |= codec->mix[i].recidx? 1 << i : 0;
 	mix_setrecdevs(m, mask);
 
@@ -1024,7 +1027,7 @@ ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
 {
 	struct ac97_info *codec = mix_getdevinfo(m);
 
-	if (codec == NULL)
+	if (codec == NULL || dev >= AC97_MIXER_SIZE)
 		return -1;
 	return ac97_setmixer(codec, dev, left, right);
 }
@@ -1037,7 +1040,7 @@ ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
 
 	if (codec == NULL)
 		return -1;
-	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+	for (i = 0; i < AC97_MIXER_SIZE; i++)
 		if ((src & (1 << i)) != 0)
 			break;
 	return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;