--- 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);