⬢ DragonFlyBSD Kernel Audit
DF-4728 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/sound/pci/aureal.c
+++ b/sys/dev/sound/pci/aureal.c
@@ -123,7 +123,7 @@ static void au_wr(struct au_info *au, int mapno, int regno, u_int32_t data, int
 /* -------------------------------------------------------------------- */

 static int
-au_rdcd(kobj_t obj, void *arg, int regno)
+au_rdcd(kobj_t obj, void *arg, int regno)	/* XXX DF-4728: no failure signal */
 {
 	struct au_info *au = (struct au_info *)arg;
 	int i=0, j=0;
@@ -145,16 +145,26 @@ au_rdcd(kobj_t obj, void *arg, int regno)
 static int
 au_wrcd(kobj_t obj, void *arg, int regno, u_int32_t data)
 {
 	struct au_info *au = (struct au_info *)arg;
-	int i, j, tries;
+	int i, j, tries;
 	i=j=tries=0;
-	do {
-		while (j<50 && (i & AU_CDC_WROK) == 0) {
-			i=au_rd(au, 0, AU_REG_CODECST, 4);
-			DELAY(2000);
+	/*
+	 * DF-4728: cap the busy-wait budget and do NOT write the codec
+	 * register when the codec never asserted WROK — the old code
+	 * spun up to 100ms per register, wrote anyway, and always
+	 * reported success, leaving a dead-but-"working" mixer.
+	 */
+	do {
+		while (j<20 && (i & AU_CDC_WROK) == 0) {
+			i=au_rd(au, 0, AU_REG_CODECST, 4);
+			DELAY(2000);
 			j++;
 		}
-		if (j==50) printf("codec timeout during write of register %x, data %x\n",
-				  regno, data);
-		au_wr(au, 0, AU_REG_CODECIO, (regno<<16) | AU_CDC_REGSET | data, 4);
+		if (j==20) {
+			printf("pcm%d: codec timeout during write of register %x, data %x\n",
+			       au->unit, regno, data);
+			break;		/* skip the write: codec not ready */
+		}
+		au_wr(au, 0, AU_REG_CODECIO, (regno<<16) | AU_CDC_REGSET | data, 4);
 		tries++;
 	} while (0);