From michaels@sdf.lonestar.org  Wed Aug 10 03:28:15 2005
Return-Path: <michaels@sdf.lonestar.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 182C116A41F
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 10 Aug 2005 03:28:15 +0000 (GMT)
	(envelope-from michaels@sdf.lonestar.org)
Received: from sdf.lonestar.org (mx.freeshell.ORG [192.94.73.21])
	by mx1.FreeBSD.org (Postfix) with ESMTP id BEB7645BAD
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 10 Aug 2005 03:28:14 +0000 (GMT)
	(envelope-from michaels@sdf.lonestar.org)
Received: from sdf.lonestar.org (IDENT:michaels@otaku.freeshell.org [192.94.73.2])
	by sdf.lonestar.org (8.13.1/8.12.10) with ESMTP id j7A3RFJ6025690;
	Wed, 10 Aug 2005 03:27:15 GMT
Received: (from michaels@localhost)
	by sdf.lonestar.org (8.13.1/8.12.8/Submit) id j7A3RFkj010203;
	Wed, 10 Aug 2005 03:27:15 GMT
Message-Id: <20050810032715.GA10051@SDF.LONESTAR.ORG>
Date: Wed, 10 Aug 2005 03:27:15 +0000
From: michaels@sdf.lonestar.org
To: FreeBSD-gnats-submit@freebsd.org
Cc: michaels.maillist@gmail.com
Subject: [sound] [patch] ac97 broken mixing capabilities checking
X-Send-Pr-Version: 3.113

>Number:         84728
>Category:       kern
>Synopsis:       [sound] [patch] ac97 broken mixing capabilities checking
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Aug 10 03:30:11 GMT 2005
>Closed-Date:    Sun Sep 11 09:05:49 GMT 2005
>Last-Modified:  Sun Sep 11 09:05:49 GMT 2005
>Originator:     Michael Seyfert
>Release:        FreeBSD 7.0-CURRENT i386
>Organization:
>Environment:
System: FreeBSD icemach.my.domain 7.0-CURRENT i386

>Description:

new sys/dev/sound/pcm/ac97.c introduces some problems with mixer
capabilities checking.
It does not properly set the "width of control field" for cards with
a non-default width. As such the volume control is misaligned ( I can
only change the volume from 50% to 100% on my audigy card.)

Also, there's an if statement and for loops that logically don't do
anything at all, which has me wondering about the quality of this code.

I think the author (Ariff Abdullah <skywizard@MyBSD.org.my>) should redo it.

>How-To-Repeat:
	Audigy 2 card...

>Fix:

Here's a patch to revert this code to the previous version.

--- sys/dev/sound/pcm/ac97.c	Sun Jul 31 08:28:31 2005
+++ /home/michael/work/ac97.c	Tue Aug  9 19:12:01 2005
@@ -611,39 +611,15 @@
 	for (i = 0; i < 32; i++) {
 		k = codec->noext? codec->mix[i].enable : 1;
 		if (k && (codec->mix[i].reg > 0)) {
-			j = old = ac97_rdcd(codec, codec->mix[i].reg);
-			if (!(j & 0x8000)) {
-				ac97_wrcd(codec, codec->mix[i].reg, j | 0x8000);
-				j = ac97_rdcd(codec, codec->mix[i].reg);
-			}
-			if ((j & 0x8000)) {
-				j = ((1 << 6) - 1) << codec->mix[i].ofs;
-				if (codec->mix[i].mute)
-					j |= 0x8000;
-				ac97_wrcd(codec, codec->mix[i].reg, j);
-				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
-				j >>= codec->mix[i].ofs;
-				if (codec->mix[i].reg == AC97_MIX_TONE &&
-						((j & 0x0001) == 0x0000))
-					j >>= 1;
-				for (k = 0; j != 0; k++)
-					j >>= 1;
-				for (j = 0; k != 0; j++)
-					k >>= 1;
-				if (j != 0) {
-					codec->mix[i].enable = 1;
-#if 0
-					codec->mix[i].bits = j;
-#endif
-				} else
-					codec->mix[i].enable = 0;
-			} else
-				codec->mix[i].enable = 0;
+			old = ac97_rdcd(codec, codec->mix[i].reg);
+			ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
+			j = ac97_rdcd(codec, codec->mix[i].reg);
 			ac97_wrcd(codec, codec->mix[i].reg, old);
+			codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
+			for (k = 1; j & (1 << k); k++);
+			codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
 		}
-#if 0
-		printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
-#endif
+		/* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
 	}
 
 	device_printf(codec->dev, "<%s>\n",
>Release-Note:
>Audit-Trail:

From: Ariff Abdullah <skywizard@MyBSD.org.my>
To: michaels@sdf.lonestar.org
Cc: FreeBSD-gnats-submit@FreeBSD.org, michaels.maillist@gmail.com
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities
 checking
Date: Thu, 11 Aug 2005 02:02:05 +0800

 On Wed, 10 Aug 2005 03:27:15 +0000
 michaels@sdf.lonestar.org wrote:
 > 
 > >Number:         84728
 > >Category:       kern
 > >Synopsis:       [sound] [patch] ac97 broken mixing capabilities checking
 > >Confidential:   no
 > >Severity:       non-critical
 > >Priority:       medium
 > >Responsible:    freebsd-bugs
 > >State:          open
 > >Quarter:        
 > >Keywords:       
 > >Date-Required:
 > >Class:          change-request
 > >Submitter-Id:   current-users
 > >Arrival-Date:   Wed Aug 10 03:30:11 GMT 2005
 > >Closed-Date:
 > >Last-Modified:
 > >Originator:     Michael Seyfert
 > >Release:        FreeBSD 7.0-CURRENT i386
 > >Organization:
 > >Environment:
 > System: FreeBSD icemach.my.domain 7.0-CURRENT i386
 > 
 > >Description:
 > 
 > new sys/dev/sound/pcm/ac97.c introduces some problems with mixer
 > capabilities checking.
 > It does not properly set the "width of control field" for cards with
 > a non-default width. As such the volume control is misaligned ( I can
 > only change the volume from 50% to 100% on my audigy card.)
 > 
 > Also, there's an if statement and for loops that logically don't do
 > anything at all, which has me wondering about the quality of this code.
 > 
 > I think the author (Ariff Abdullah <skywizard@MyBSD.org.my>) should redo it.
 > 
 > >How-To-Repeat:
 > 	Audigy 2 card...
 > 
 > >Fix:
 > 
 > Here's a patch to revert this code to the previous version.
 > 
 > --- sys/dev/sound/pcm/ac97.c	Sun Jul 31 08:28:31 2005
 > +++ /home/michael/work/ac97.c	Tue Aug  9 19:12:01 2005
 > @@ -611,39 +611,15 @@
 >  	for (i = 0; i < 32; i++) {
 >  		k = codec->noext? codec->mix[i].enable : 1;
 >  		if (k && (codec->mix[i].reg > 0)) {
 > -			j = old = ac97_rdcd(codec, codec->mix[i].reg);
 > -			if (!(j & 0x8000)) {
 > -				ac97_wrcd(codec, codec->mix[i].reg, j | 0x8000);
 > -				j = ac97_rdcd(codec, codec->mix[i].reg);
 > -			}
 > -			if ((j & 0x8000)) {
 > -				j = ((1 << 6) - 1) << codec->mix[i].ofs;
 > -				if (codec->mix[i].mute)
 > -					j |= 0x8000;
 > -				ac97_wrcd(codec, codec->mix[i].reg, j);
 > -				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
 > -				j >>= codec->mix[i].ofs;
 > -				if (codec->mix[i].reg == AC97_MIX_TONE &&
 > -						((j & 0x0001) == 0x0000))
 > -					j >>= 1;
 > -				for (k = 0; j != 0; k++)
 > -					j >>= 1;
 > -				for (j = 0; k != 0; j++)
 > -					k >>= 1;
 > -				if (j != 0) {
 > -					codec->mix[i].enable = 1;
 > -#if 0
 > -					codec->mix[i].bits = j;
 > -#endif
 > -				} else
 > -					codec->mix[i].enable = 0;
 > -			} else
 > -				codec->mix[i].enable = 0;
 > +			old = ac97_rdcd(codec, codec->mix[i].reg);
 > +			ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
 > +			j = ac97_rdcd(codec, codec->mix[i].reg);
 >  			ac97_wrcd(codec, codec->mix[i].reg, old);
 > +			codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
 > +			for (k = 1; j & (1 << k); k++);
 > +			codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
 >  		}
 > -#if 0
 > -		printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
 > -#endif
 > +		/* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
 >  	}
 >  
 >  	device_printf(codec->dev, "<%s>\n",
 > >Release-Note:
 > >Audit-Trail:
 > >Unformatted:
 > _______________________________________________
 > freebsd-bugs@freebsd.org mailing list
 > http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
 > To unsubscribe, send any mail to "freebsd-bugs-unsubscribe@freebsd.org"
 
 Please try this patch:
 
 --- sys/dev/sound/pcm/ac97.c.orig	Thu Aug 11 01:50:30 2005
 +++ sys/dev/sound/pcm/ac97.c	Thu Aug 11 01:52:35 2005
 @@ -608,33 +608,40 @@
  	if (codec_patch)
  		codec_patch(codec);
  
 +	/*
 +	 * YES. Do ac97_rdcd()  T W I C E.
 +	 */
  	for (i = 0; i < 32; i++) {
  		k = codec->noext? codec->mix[i].enable : 1;
  		if (k && (codec->mix[i].reg > 0)) {
 +			(void)ac97_rdcd(codec, codec->mix[i].reg);
  			j = old = ac97_rdcd(codec, codec->mix[i].reg);
  			if (!(j & 0x8000)) {
  				ac97_wrcd(codec, codec->mix[i].reg, j | 0x8000);
 +				(void)ac97_rdcd(codec, codec->mix[i].reg);
  				j = ac97_rdcd(codec, codec->mix[i].reg);
  			}
  			if ((j & 0x8000)) {
 -				j = ((1 << 6) - 1) << codec->mix[i].ofs;
 +				j = ((1 << codec->mix[i].bits) - 1) << codec->mix[i].ofs;
  				if (codec->mix[i].mute)
  					j |= 0x8000;
  				ac97_wrcd(codec, codec->mix[i].reg, j);
 -				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
 -				j >>= codec->mix[i].ofs;
 +				(void)ac97_rdcd(codec, codec->mix[i].reg);
 +				k = ac97_rdcd(codec, codec->mix[i].reg) & (j & ~0x8000);
 +				k >>= codec->mix[i].ofs;
  				if (codec->mix[i].reg == AC97_MIX_TONE &&
 -						((j & 0x0001) == 0x0000))
 -					j >>= 1;
 -				for (k = 0; j != 0; k++)
 -					j >>= 1;
 +						((k & 0x0001) == 0x0000))
 +					k >>= 1;
  				for (j = 0; k != 0; j++)
  					k >>= 1;
  				if (j != 0) {
 -					codec->mix[i].enable = 1;
  #if 0
 -					codec->mix[i].bits = j;
 +					device_printf(codec->dev,
 +						"%d: %d -> %d\n",
 +						i, codec->mix[i].bits, j);
  #endif
 +					codec->mix[i].enable = 1;
 +					codec->mix[i].bits = j;
  				} else
  					codec->mix[i].enable = 0;
  			} else
 
 
 --
 
 Ariff Abdullah
 MyBSD
 
 http://www.MyBSD.org.my (IPv6/IPv4)
 http://staff.MyBSD.org.my (IPv6/IPv4)
 http://tomoyo.MyBSD.org.my (IPv6/IPv4)

From: Michael Seyfert <michaels@sdf.lonestar.org>
To: bug-followup@FreeBSD.org
Cc: skywizard@MyBSD.org.my
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities checking
Date: Wed, 10 Aug 2005 23:24:13 +0000

 > Please try this patch:
 >  
 >  --- sys/dev/sound/pcm/ac97.c.orig	Thu Aug 11 01:50:30 2005
 >  +++ sys/dev/sound/pcm/ac97.c	Thu Aug 11 01:52:35 2005
 >  @@ -608,33 +608,40 @@
 >   	if (codec_patch)
 >   		codec_patch(codec);
 >   
 >  +	/*
 >  +	 * YES. Do ac97_rdcd()  T W I C E.
 >  +	 */
 >   	for (i = 0; i < 32; i++) {
 >   		k = codec->noext? codec->mix[i].enable : 1;
 >   		if (k && (codec->mix[i].reg > 0)) {
 >  +			(void)ac97_rdcd(codec, codec->mix[i].reg);
 >   			j = old = ac97_rdcd(codec, codec->mix[i].reg);
 >   			if (!(j & 0x8000)) {
 >   				ac97_wrcd(codec, codec->mix[i].reg, j | 0x8000);
 >  +				(void)ac97_rdcd(codec, codec->mix[i].reg);
 >   				j = ac97_rdcd(codec, codec->mix[i].reg);
 >   			}
 >   			if ((j & 0x8000)) {
 >  -				j = ((1 << 6) - 1) << codec->mix[i].ofs;
 >  +				j = ((1 << codec->mix[i].bits) - 1) << codec->mix[i].ofs;
 >   				if (codec->mix[i].mute)
 >   					j |= 0x8000;
 >   				ac97_wrcd(codec, codec->mix[i].reg, j);
 >  -				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
 >  -				j >>= codec->mix[i].ofs;
 >  +				(void)ac97_rdcd(codec, codec->mix[i].reg);
 >  +				k = ac97_rdcd(codec, codec->mix[i].reg) & (j & ~0x8000);
 >  +				k >>= codec->mix[i].ofs;
 >   				if (codec->mix[i].reg == AC97_MIX_TONE &&
 >  -						((j & 0x0001) == 0x0000))
 >  -					j >>= 1;
 >  -				for (k = 0; j != 0; k++)
 >  -					j >>= 1;
 >  +						((k & 0x0001) == 0x0000))
 >  +					k >>= 1;
 >   				for (j = 0; k != 0; j++)
 >   					k >>= 1;
 >   				if (j != 0) {
 >  -					codec->mix[i].enable = 1;
 >   #if 0
 >  -					codec->mix[i].bits = j;
 >  +					device_printf(codec->dev,
 >  +						"%d: %d -> %d\n",
 >  +						i, codec->mix[i].bits, j);
 >   #endif
 >  +					codec->mix[i].enable = 1;
 >  +					codec->mix[i].bits = j;
 >   				} else
 >   					codec->mix[i].enable = 0;
 >   			} else
 >  
 >  
 >  --
 >  
 >  Ariff Abdullah
 >  MyBSD
 >  
 >  http://www.MyBSD.org.my (IPv6/IPv4)
 >  http://staff.MyBSD.org.my (IPv6/IPv4)
 >  http://tomoyo.MyBSD.org.my (IPv6/IPv4)
 > 
 
 No good.. please try this one:
 
 --- sys/dev/sound/pcm/ac97.c.orig	Wed Aug 10 16:25:42 2005
 +++ sys/dev/sound/pcm/ac97.c	Wed Aug 10 16:25:53 2005
 @@ -618,25 +618,12 @@
  			}
  			if ((j & 0x8000)) {
  				j = ((1 << 6) - 1) << codec->mix[i].ofs;
 -				if (codec->mix[i].mute)
 -					j |= 0x8000;
  				ac97_wrcd(codec, codec->mix[i].reg, j);
  				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
  				j >>= codec->mix[i].ofs;
 -				if (codec->mix[i].reg == AC97_MIX_TONE &&
 -						((j & 0x0001) == 0x0000))
 -					j >>= 1;
 -				for (k = 0; j != 0; k++)
 -					j >>= 1;
 -				for (j = 0; k != 0; j++)
 -					k >>= 1;
 -				if (j != 0) {
 -					codec->mix[i].enable = 1;
 -#if 0
 -					codec->mix[i].bits = j;
 -#endif
 -				} else
 -					codec->mix[i].enable = 0;
 +				codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
 +				for (k = 1; j & (1 << k); k++);
 +				codec->mix[i].bits = j? k : 0;
  			} else
  				codec->mix[i].enable = 0;
  			ac97_wrcd(codec, codec->mix[i].reg, old);

From: Ariff Abdullah <skywizard@MyBSD.org.my>
To: Michael Seyfert <michaels@sdf.lonestar.org>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities
 checking
Date: Thu, 11 Aug 2005 17:21:11 +0800

 On Wed, 10 Aug 2005 23:24:13 +0000
 Michael Seyfert <michaels@sdf.lonestar.org> wrote:
 > No good.. please try this one:
 > 
 > --- sys/dev/sound/pcm/ac97.c.orig	Wed Aug 10 16:25:42 2005
 > +++ sys/dev/sound/pcm/ac97.c	Wed Aug 10 16:25:53 2005
 > @@ -618,25 +618,12 @@
 >  			}
 >  			if ((j & 0x8000)) {
 >  				j = ((1 << 6) - 1) << codec->mix[i].ofs;
 > -				if (codec->mix[i].mute)
 > -					j |= 0x8000;
 >  				ac97_wrcd(codec, codec->mix[i].reg, j);
 >  				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
 >  				j >>= codec->mix[i].ofs;
 > -				if (codec->mix[i].reg == AC97_MIX_TONE &&
 > -						((j & 0x0001) == 0x0000))
 > -					j >>= 1;
 > -				for (k = 0; j != 0; k++)
 > -					j >>= 1;
 > -				for (j = 0; k != 0; j++)
 > -					k >>= 1;
 > -				if (j != 0) {
 > -					codec->mix[i].enable = 1;
 > -#if 0
 > -					codec->mix[i].bits = j;
 > -#endif
 > -				} else
 > -					codec->mix[i].enable = 0;
 > +				codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
 > +				for (k = 1; j & (1 << k); k++);
 > +				codec->mix[i].bits = j? k : 0;
 >  			} else
 >  				codec->mix[i].enable = 0;
 >  			ac97_wrcd(codec, codec->mix[i].reg, old);
 > 
 
 No good for various STAC* / ALC (the reason for why this new detection mechanism).
 Ok.. I think this will do the job for both of us and others too:
 (Sorry, my previous post didn't make it into audit trail.)
 
 
 --- sys/dev/sound/pcm/ac97.c.orig	Thu Aug 11 08:46:32 2005
 +++ sys/dev/sound/pcm/ac97.c	Thu Aug 11 11:41:05 2005
 @@ -74,9 +74,9 @@
  
  static const struct ac97mixtable_entry ac97mixtable_default[32] = {
      /*	[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 },
 -	[SOUND_MIXER_PHONEOUT]	= { AC97_MIX_MONO, 	5, 0, 0, 1, 7, 0, 0 },
 +	[SOUND_MIXER_VOLUME]	= { AC97_MIX_MASTER, 	6, 0, 1, 1, 6, 0, 1 },
 +	[SOUND_MIXER_OGAIN]	= { AC97_MIX_AUXOUT, 	6, 0, 1, 1, 0, 0, 0 },
 +	[SOUND_MIXER_PHONEOUT]	= { AC97_MIX_MONO, 	6, 0, 0, 1, 7, 0, 0 },
  	[SOUND_MIXER_BASS]	= { AC97_MIX_TONE, 	4, 8, 0, 0, 0, 1, 0 },
  	[SOUND_MIXER_TREBLE]	= { AC97_MIX_TONE, 	4, 0, 0, 0, 0, 1, 0 },
  	[SOUND_MIXER_PCM]	= { AC97_MIX_PCM, 	5, 0, 1, 1, 0, 0, 1 },
 @@ -283,7 +283,19 @@
  u_int16_t
  ac97_rdcd(struct ac97_info *codec, int reg)
  {
 -	return AC97_READ(codec->methods, codec->devinfo, reg);
 +	u_int16_t v[2], i = 0;
 +
 +	v[0] = AC97_READ(codec->methods, codec->devinfo, reg);
 +	v[1] = AC97_READ(codec->methods, codec->devinfo, reg);
 +	while (v[0] != v[1] && i < 100)
 +		v[i++ & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
 +#if 0
 +	if (i > 0) {
 +		device_printf(codec->dev, "%s(): Inconsistent register value at"
 +				" 0x%08x (retry: %d)\n", __func__, reg, i);
 +	}
 +#endif
 +	return v[1];
  }
  
  void
 @@ -617,24 +629,25 @@
  				j = ac97_rdcd(codec, codec->mix[i].reg);
  			}
  			if ((j & 0x8000)) {
 -				j = ((1 << 6) - 1) << codec->mix[i].ofs;
 +				j = ((1 << codec->mix[i].bits) - 1) << codec->mix[i].ofs;
  				if (codec->mix[i].mute)
  					j |= 0x8000;
  				ac97_wrcd(codec, codec->mix[i].reg, j);
 -				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
 -				j >>= codec->mix[i].ofs;
 +				k = ac97_rdcd(codec, codec->mix[i].reg) & (j & ~0x8000);
 +				k >>= codec->mix[i].ofs;
  				if (codec->mix[i].reg == AC97_MIX_TONE &&
 -						((j & 0x0001) == 0x0000))
 -					j >>= 1;
 -				for (k = 0; j != 0; k++)
 -					j >>= 1;
 -				for (j = 0; k != 0; j++)
 +						((k & 0x0001) == 0x0000))
  					k >>= 1;
 +				j = 0;
 +				while (k >> j)
 +					j++;
  				if (j != 0) {
 -					codec->mix[i].enable = 1;
  #if 0
 -					codec->mix[i].bits = j;
 +					device_printf(codec->dev, "%d: (%d) %d -> %d\n",
 +							i, k, codec->mix[i].bits, j);
  #endif
 +					codec->mix[i].enable = 1;
 +					codec->mix[i].bits = j;
  				} else
  					codec->mix[i].enable = 0;
  			} else
 
 
 
 --
 
 Ariff Abdullah
 MyBSD
 
 http://www.MyBSD.org.my (IPv6/IPv4)
 http://staff.MyBSD.org.my (IPv6/IPv4)
 http://tomoyo.MyBSD.org.my (IPv6/IPv4)

From: Michael Seyfert <michael.seyfert@gmail.com>
To: skywizard@mybsd.org.my
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities
Date: Thu, 11 Aug 2005 20:33:01 -0600

 > No good for various STAC* / ALC (the reason for why this new detection me=
 chanism).
 > Ok.. I think this will do the job for both of us and others too:
 
 > .......
 
 Umm. I don't get any sound with that patch, I'm not sure why..
 Try this one. I didn't change the functionality of your code, but
 added another read / write to get the control field width..
 
 --- sys/dev/sound/pcm/ac97.c=09Sun Jul 31 08:28:31 2005
 +++ ../ac97.c=09Thu Aug 11 20:12:47 2005
 @@ -622,19 +622,15 @@
  =09=09=09=09=09j |=3D 0x8000;
  =09=09=09=09ac97_wrcd(codec, codec->mix[i].reg, j);
  =09=09=09=09j =3D ac97_rdcd(codec, codec->mix[i].reg) & j;
 -=09=09=09=09j >>=3D codec->mix[i].ofs;
 -=09=09=09=09if (codec->mix[i].reg =3D=3D AC97_MIX_TONE &&
 -=09=09=09=09=09=09((j & 0x0001) =3D=3D 0x0000))
 -=09=09=09=09=09j >>=3D 1;
 -=09=09=09=09for (k =3D 0; j !=3D 0; k++)
 -=09=09=09=09=09j >>=3D 1;
 -=09=09=09=09for (j =3D 0; k !=3D 0; j++)
 -=09=09=09=09=09k >>=3D 1;
  =09=09=09=09if (j !=3D 0) {
  =09=09=09=09=09codec->mix[i].enable =3D 1;
 -#if 0
 -=09=09=09=09=09codec->mix[i].bits =3D j;
 -#endif
 +=09=09=09=09=09/* Get the width of the control field. */
 +=09=09=09=09=09j =3D ((1 << 6) - 1) << codec->mix[i].ofs;
 +=09=09=09=09=09ac97_wrcd(codec, codec->mix[i].reg, j);
 +=09=09=09=09=09j =3D ac97_rdcd(codec, codec->mix[i].reg) & j;
 +=09=09=09=09=09j >>=3D codec->mix[i].ofs;
 +=09=09=09=09=09for (k =3D 1; j & (1 << k); k++);
 +=09=09=09=09=09codec->mix[i].bits =3D k;
  =09=09=09=09} else
  =09=09=09=09=09codec->mix[i].enable =3D 0;
  =09=09=09} else
 
 
 
 
 Note: you do not need these lines, they don't change whether or not j =3D=
 =3D 0
 =09=09=09=09j >>=3D codec->mix[i].ofs;
 =09=09=09=09if (codec->mix[i].reg =3D=3D AC97_MIX_TONE &&
 =09=09=09=09=09=09((j & 0x0001) =3D=3D 0x0000))
 =09=09=09=09=09j >>=3D 1;
 =09=09=09=09for (k =3D 0; j !=3D 0; k++)
 =09=09=09=09=09j >>=3D 1;
 =09=09=09=09for (j =3D 0; k !=3D 0; j++)
 =09=09=09=09=09k >>=3D 1;
 
 The problem with my card is that bits needs to be 6 instead of 5 for
 pcm and vol.. So hopefully that patch will work.

From: Ariff Abdullah <skywizard@MyBSD.org.my>
To: Michael Seyfert <michael.seyfert@gmail.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities
Date: Fri, 12 Aug 2005 11:12:36 +0800

 On Thu, 11 Aug 2005 20:33:01 -0600
 Michael Seyfert <michael.seyfert@gmail.com> wrote:
 > > No good for various STAC* / ALC (the reason for why this new
 > > detection mechanism). Ok.. I think this will do the job for both
 > > of us and others too:
 > 
 > > .......
 > 
 > Umm. I don't get any sound with that patch, I'm not sure why..
 > Try this one. I didn't change the functionality of your code, but
 > added another read / write to get the control field width..
 > 
 > .......
 > 
 > The problem with my card is that bits needs to be 6 instead of 5 for
 > pcm and vol.. So hopefully that patch will work.
 > 
 Things getting messy. There are few codecs did not cooperate well. Can
 you please try these patches, and tell me which one is working for
 you, or none of it:
 
 http://staff.mybsd.org.my/skywizard/FreeBSD/sound/ac97.c.head.diff1
 http://staff.mybsd.org.my/skywizard/FreeBSD/sound/ac97.c.head.diff2
 
 They may look simmilar, but the first one is a little bit aggresive
 against notorious codecs.
 
 (the quest for 'one size fits them all' will carry on and I hope you
 can bear with me)
 
 --
 
 Ariff Abdullah
 MyBSD
 
 http://www.MyBSD.org.my (IPv6/IPv4)
 http://staff.MyBSD.org.my (IPv6/IPv4)
 http://tomoyo.MyBSD.org.my (IPv6/IPv4)

From: Ariff Abdullah <skywizard@MyBSD.org.my>
To: Michael Seyfert <michael.seyfert@gmail.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities
Date: Fri, 12 Aug 2005 13:06:10 +0800

 On Fri, 12 Aug 2005 03:20:13 GMT
 Ariff Abdullah <skywizard@MyBSD.org.my> wrote:
 >  On Thu, 11 Aug 2005 20:33:01 -0600
 >  Michael Seyfert <michael.seyfert@gmail.com> wrote:
 >  > > No good for various STAC* / ALC (the reason for why this new
 >  > > detection mechanism). Ok.. I think this will do the job for
 >  > > both of us and others too:
 >  > 
 >  > > .......
 >  > 
 >  > Umm. I don't get any sound with that patch, I'm not sure why..
 >  > Try this one. I didn't change the functionality of your code, but
 >  > added another read / write to get the control field width..
 >  > 
 >  > .......
 >  > 
 >  > The problem with my card is that bits needs to be 6 instead of 5
 >  > for pcm and vol.. So hopefully that patch will work.
 >  > 
 >  Things getting messy. There are few codecs did not cooperate well.
 >  Can you please try these patches, and tell me which one is working
 >  for you, or none of it:
 >  
 >  http://staff.mybsd.org.my/skywizard/FreeBSD/sound/ac97.c.head.diff1
 >  http://staff.mybsd.org.my/skywizard/FreeBSD/sound/ac97.c.head.diff2
 >  
 ... and also .diff3/4  (from that directory).
 
 --
 
 Ariff Abdullah
 MyBSD
 
 http://www.MyBSD.org.my (IPv6/IPv4)
 http://staff.MyBSD.org.my (IPv6/IPv4)
 http://tomoyo.MyBSD.org.my (IPv6/IPv4)

From: Ariff Abdullah <skywizard@MyBSD.org.my>
To: Michael Seyfert <michael.seyfert@gmail.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities
Date: Fri, 12 Aug 2005 17:28:00 +0800

 On Fri, 12 Aug 2005 05:10:14 GMT
 Ariff Abdullah <skywizard@MyBSD.org.my> wrote:
 >  >  Things getting messy. There are few codecs did not cooperate
 >  >  well. Can you please try these patches, and tell me which one is
 >  >  working for you, or none of it:
 >  >  
 >  >  http://staff.mybsd.org.my/skywizard/FreeBSD/sound/ac97.c.head.diff1
 >  >  http://staff.mybsd.org.my/skywizard/FreeBSD/sound/ac97.c.head.diff2
 >  >  
 >  ... and also .diff3/4  (from that directory).
 >  
 I've uploaded .diff5/6 , please use that instead.
 
 
 --
 
 Ariff Abdullah
 MyBSD
 
 http://www.MyBSD.org.my (IPv6/IPv4)
 http://staff.MyBSD.org.my (IPv6/IPv4)
 http://tomoyo.MyBSD.org.my (IPv6/IPv4)

From: Michael Seyfert <michaels@sdf.lonestar.org>
To: bug-followup@FreeBSD.org
Cc: skywizard@MyBSD.org.my
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities checking
Date: Sun, 14 Aug 2005 20:00:56 +0000

 Sorry I had the wrong encoding in my editor for that patch..
 
 --- sys/dev/sound/pcm/ac97.c	Sun Jul 31 08:28:31 2005
 +++ ../ac97.c	Thu Aug 11 20:12:47 2005
 @@ -622,19 +622,15 @@
  					j |= 0x8000;
  				ac97_wrcd(codec, codec->mix[i].reg, j);
  				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
 -				j >>= codec->mix[i].ofs;
 -				if (codec->mix[i].reg == AC97_MIX_TONE &&
 -						((j & 0x0001) == 0x0000))
 -					j >>= 1;
 -				for (k = 0; j != 0; k++)
 -					j >>= 1;
 -				for (j = 0; k != 0; j++)
 -					k >>= 1;
  				if (j != 0) {
  					codec->mix[i].enable = 1;
 -#if 0
 -					codec->mix[i].bits = j;
 -#endif
 +					/* Get the width of the control field. */
 +					j = ((1 << 6) - 1) << codec->mix[i].ofs;
 +					ac97_wrcd(codec, codec->mix[i].reg, j);
 +					j = ac97_rdcd(codec, codec->mix[i].reg) & j;
 +					j >>= codec->mix[i].ofs;
 +					for (k = 1; j & (1 << k); k++);
 +					codec->mix[i].bits = k;
  				} else
  					codec->mix[i].enable = 0;
  			} else
 
 
 If this doesn't work then I'm giving up.. I tried all of your patches
 in that directory. My sound didn't work at all. Can't we just
 keep it simple?
 Anyways, if I'm the only one affected by this then it's not a big
 deal.

From: Ariff Abdullah <skywizard@MyBSD.org.my>
To: Michael Seyfert <michaels@sdf.lonestar.org>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities
 checking
Date: Mon, 15 Aug 2005 06:26:18 +0800

 On Sun, 14 Aug 2005 20:00:56 +0000
 Michael Seyfert <michaels@sdf.lonestar.org> wrote:
 
 > 
 > If this doesn't work then I'm giving up.. I tried all of your
 > patches in that directory. My sound didn't work at all. Can't we
 > just keep it simple?
 > Anyways, if I'm the only one affected by this then it's not a big
 > deal.
 > 
 No! Please don't given up yet :) I tried so hard to balance between
 buggy codecs, various ac97 version, even wait for your responses for
 more than two days. At least, please try that ac97.c.head.FINAL.diff
 (haven't you?).
 
 
 --
 
 Ariff Abdullah
 MyBSD
 
 http://www.MyBSD.org.my (IPv6/IPv4)
 http://staff.MyBSD.org.my (IPv6/IPv4)
 http://tomoyo.MyBSD.org.my (IPv6/IPv4)

From: Michael Seyfert <michaels@sdf.lonestar.org>
To: Ariff Abdullah <skywizard@MyBSD.org.my>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities checking
Date: Mon, 15 Aug 2005 00:03:47 +0000

 works fine

From: Michael Seyfert <michaels@sdf.lonestar.org>
To: Ariff Abdullah <skywizard@MyBSD.org.my>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities checking
Date: Mon, 15 Aug 2005 06:59:29 +0000

 All I really needed was the check for the number of bits.. I'm not sure
 what the other code is for in that patch, but ac97.c.head.FINAL.diff seems
 to be working.

From: Ariff Abdullah <skywizard@MyBSD.org.my>
To: Michael Seyfert <michaels@sdf.lonestar.org>
Cc: bug-followup@FreeBSD.org, Alexander@Leidinger.net,
 mathew.kanner@gmail.com, davidxu@FreeBSD.org
Subject: Re: kern/84728: [sound] [patch] ac97 broken mixing capabilities
 checking
Date: Mon, 15 Aug 2005 17:16:08 +0800

 On Mon, 15 Aug 2005 06:59:29 +0000
 Michael Seyfert <michaels@sdf.lonestar.org> wrote:
 > All I really needed was the check for the number of bits.. I'm not
 > sure what the other code is for in that patch, but
 > ac97.c.head.FINAL.diff seems to be working.
 > 
 It's a balance between buggy codecs, different ac97 revisions
 (2.1/2.2/2.3), different register/bit offset (you cannot simply
 assume that every mixer register is 6bit long, or you end up
 overflowing it).
 
 Anyway, thanks! I assume *this* should be the true final version!
 (I'm CCing this to other people as well, especially David Xu for
 his 'used to be Creative EV1938 but its no longer true' for
 further validation.
 
 -- DIFF BEGIN --
 --- sys/dev/sound/pcm/ac97.c.orig	Sun Jul 31 22:28:31 2005
 +++ sys/dev/sound/pcm/ac97.c	Mon Aug 15 15:43:24 2005
 @@ -118,6 +118,11 @@
  	{ 0x57454300, "Winbond" },
  	{ 0x574d4c00, "Wolfson" },
  	{ 0x594d4800, "Yamaha" },
 +	/* 
 +	 * XXX This is a fluke, really! The real vendor
 +	 * should be SigmaTel, not this! This should be
 +	 * removed someday!
 +	 */
  	{ 0x01408300, "Creative" },
  	{ 0x00000000, NULL }
  };
 @@ -211,6 +216,11 @@
  	{ 0x594d4800, 0x00, 0, "YMF743",	0 },
  	{ 0x594d4802, 0x00, 0, "YMF752",	0 },
  	{ 0x594d4803, 0x00, 0, "YMF753",	0 },
 +	/* 
 +	 * XXX This is a fluke, really! The real codec
 +	 * should be STAC9704, not this! This should be
 +	 * removed someday!
 +	 */
  	{ 0x01408384, 0x00, 0, "EV1938",	0 },
  	{ 0, 0, 0, NULL, 0 }
  };
 @@ -283,6 +293,21 @@
  u_int16_t
  ac97_rdcd(struct ac97_info *codec, int reg)
  {
 +	if (codec->flags & AC97_F_RDCD_BUG) {
 +		u_int16_t i[2], j = 100;
 +
 +		i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
 +		i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
 +		while (i[0] != i[1] && j)
 +			i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
 +#if 0
 +		if (j < 100) {
 +			device_printf(codec->dev, "%s(): Inconsistent register value at"
 +					" 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
 +		}
 +#endif
 +		return i[!(j & 1)];
 +	}
  	return AC97_READ(codec->methods, codec->devinfo, reg);
  }
  
 @@ -452,14 +477,16 @@
  		 */
  		snd_mtxlock(codec->lock);
  		if (e->mask) {
 -			int cur = ac97_rdcd(codec, e->reg);
 +			int cur = ac97_rdcd(codec, reg);
  			val |= cur & ~(mask);
  		}
  		ac97_wrcd(codec, reg, val);
  		snd_mtxunlock(codec->lock);
  		return left | (right << 8);
  	} else {
 -		/* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
 +#if 0
 +		printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
 +#endif
  		return -1;
  	}
  }
 @@ -536,8 +563,9 @@
  	const char *cname, *vname;
  	char desc[80];
  	u_int8_t model, step;
 -	unsigned i, j, k, old;
 +	unsigned i, j, k, bit, old;
  	u_int32_t id;
 +	int reg;
  
  	snd_mtxlock(codec->lock);
  	codec->count = AC97_INIT(codec->methods, codec->devinfo);
 @@ -552,6 +580,16 @@
  	ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
  
  	i = ac97_rdcd(codec, AC97_REG_RESET);
 +	j = 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) {
 +		codec->flags |= AC97_F_RDCD_BUG;
 +		i = ac97_rdcd(codec, AC97_REG_RESET);
 +	}
  	codec->caps = i & 0x03ff;
  	codec->se =  (i & 0x7c00) >> 10;
  
 @@ -610,36 +648,55 @@
  
  	for (i = 0; i < 32; i++) {
  		k = codec->noext? codec->mix[i].enable : 1;
 -		if (k && (codec->mix[i].reg > 0)) {
 -			j = old = ac97_rdcd(codec, codec->mix[i].reg);
 -			if (!(j & 0x8000)) {
 -				ac97_wrcd(codec, codec->mix[i].reg, j | 0x8000);
 -				j = ac97_rdcd(codec, codec->mix[i].reg);
 -			}
 +		reg = codec->mix[i].reg;
 +		if (reg < 0)
 +			reg = -reg;
 +		if (k && reg) {
 +			j = old = ac97_rdcd(codec, reg);
 +			/*
 +			 * Test for mute bit (except for AC97_MIX_TONE,
 +			 * where we simply assume it as available).
 +			 */
 +			if (codec->mix[i].mute) {
 +				ac97_wrcd(codec, reg, j | 0x8000);
 +				j = ac97_rdcd(codec, reg);
 +			} else
 +				j |= 0x8000;
  			if ((j & 0x8000)) {
 -				j = ((1 << 6) - 1) << codec->mix[i].ofs;
 -				if (codec->mix[i].mute)
 -					j |= 0x8000;
 -				ac97_wrcd(codec, codec->mix[i].reg, j);
 -				j = ac97_rdcd(codec, codec->mix[i].reg) & j;
 -				j >>= codec->mix[i].ofs;
 -				if (codec->mix[i].reg == AC97_MIX_TONE &&
 -						((j & 0x0001) == 0x0000))
 -					j >>= 1;
 -				for (k = 0; j != 0; k++)
 -					j >>= 1;
 -				for (j = 0; k != 0; j++)
 +				/*
 +				 * Test whether the control width should be
 +				 * 4, 5 or 6 bit. For 5bit register, we should
 +				 * test it whether it's really 5 or 6bit. Leave
 +				 * 4bit register alone, because sometimes an
 +				 * attempt to write past 4th bit may cause
 +				 * incorrect result especially for AC97_MIX_BEEP
 +				 * (ac97 2.3).
 +				 */
 +				bit = codec->mix[i].bits;
 +				if (bit == 5)
 +					bit++;
 +				j = ((1 << bit) - 1) << codec->mix[i].ofs;
 +				ac97_wrcd(codec, reg,
 +					j | (codec->mix[i].mute ? 0x8000 : 0));
 +				k = ac97_rdcd(codec, reg) & j;
 +				k >>= codec->mix[i].ofs;
 +				if (reg == AC97_MIX_TONE &&
 +							((k & 0x0001) == 0x0000))
  					k >>= 1;
 +				for (j = 0; k >> j; j++)
 +					;
  				if (j != 0) {
 -					codec->mix[i].enable = 1;
  #if 0
 -					codec->mix[i].bits = j;
 +					device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
 +						i, k, bit, codec->mix[i].bits, j);
  #endif
 +					codec->mix[i].enable = 1;
 +					codec->mix[i].bits = j;
  				} else
  					codec->mix[i].enable = 0;
  			} else
  				codec->mix[i].enable = 0;
 -			ac97_wrcd(codec, codec->mix[i].reg, old);
 +			ac97_wrcd(codec, reg, old);
  		}
  #if 0
  		printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
 @@ -650,6 +707,8 @@
  		      ac97_hw_desc(codec->id, vname, cname, desc));
  
  	if (bootverbose) {
 +		if (codec->flags & AC97_F_RDCD_BUG)
 +			device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
  		device_printf(codec->dev, "Codec features ");
  		for (i = j = 0; i < 10; i++)
  			if (codec->caps & (1 << i))
 --- sys/dev/sound/pcm/ac97.h.orig	Thu Jan  6 09:43:20 2005
 +++ sys/dev/sound/pcm/ac97.h	Mon Aug 15 15:41:42 2005
 @@ -81,6 +81,7 @@
  #define AC97_REG_ID2	0x7e
  
  #define	AC97_F_EAPD_INV		0x00000001
 +#define	AC97_F_RDCD_BUG		0x00000002
  
  #define AC97_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))
  #define AC97_CREATE(dev, devinfo, cls) ac97_create(dev, devinfo, &cls ## _class)
 -- DIFF END --
 
 --
 
 Ariff Abdullah
 MyBSD
 
 http://www.MyBSD.org.my (IPv6/IPv4)
 http://staff.MyBSD.org.my (IPv6/IPv4)
 http://tomoyo.MyBSD.org.my (IPv6/IPv4)
State-Changed-From-To: open->closed 
State-Changed-By: netchild 
State-Changed-When: Sun Sep 11 09:05:32 GMT 2005 
State-Changed-Why:  
Fix committed, thanks. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=84728 
>Unformatted:
