Remap and virtualize mixer controls for HP nx6110 with AD1981B AC97 codec,
authorHasso Tepper <hasso@dragonflybsd.org>
Fri, 30 Nov 2007 07:59:56 +0000 (07:59 +0000)
committerHasso Tepper <hasso@dragonflybsd.org>
Fri, 30 Nov 2007 07:59:56 +0000 (07:59 +0000)
unifying master volume control.

  * Remap "phout" --> SOUND_MIXER_VOLUME (internal speakers)
  * Virtual "vol" --> { "phout", "ogain" (headphone) }

Obtained-from: FreeBSD

sys/dev/sound/pcm/ac97.c

index c92585b..3edbe41 100644 (file)
@@ -23,8 +23,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/sound/pcm/ac97.c,v 1.53.2.5 2007/05/13 20:53:39 ariff Exp $
- * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.25 2007/06/16 20:07:22 dillon Exp $
+ * $FreeBSD: src/sys/dev/sound/pcm/ac97.c,v 1.53.2.6 2007/10/31 04:00:07 ariff Exp $
+ * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.26 2007/11/30 07:59:56 hasso Exp $
  */
 
 #include <dev/sound/pcm/sound.h>
@@ -35,7 +35,7 @@
 
 #include "mixer_if.h"
 
-SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.25 2007/06/16 20:07:22 dillon Exp $");
+SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.26 2007/11/30 07:59:56 hasso Exp $");
 
 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
 
@@ -574,38 +574,6 @@ ac97_fix_tone(struct ac97_info *codec)
        }
 }
 
-static void
-ac97_fix_volume(struct ac97_info *codec)
-{
-       struct snddev_info *d = device_get_softc(codec->dev);
-
-#if 0
-       /* XXX For the sake of debugging purposes */
-       ac97_wrcd(codec, AC97_MIX_PCM, 0);
-       bzero(&codec->mix[SOUND_MIXER_PCM],
-               sizeof(codec->mix[SOUND_MIXER_PCM]));
-       if (d)
-               d->flags |= SD_F_SOFTPCMVOL;
-       return;
-#endif
-       switch (codec->id) {
-               case 0x434d4941:        /* CMI9738 */
-               case 0x434d4961:        /* CMI9739 */
-               case 0x434d4978:        /* CMI9761 */
-               case 0x434d4982:        /* CMI9761 */
-               case 0x434d4983:        /* CMI9761 */
-                       ac97_wrcd(codec, AC97_MIX_PCM, 0);
-                       break;
-               default:
-                       return;
-                       break;
-       }
-       bzero(&codec->mix[SOUND_MIXER_PCM],
-                       sizeof(codec->mix[SOUND_MIXER_PCM]));
-       if (d)
-               d->flags |= SD_F_SOFTPCMVOL;
-}
-
 static const char*
 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
 {
@@ -714,7 +682,6 @@ ac97_initmixer(struct ac97_info *codec)
        }
        ac97_fix_auxout(codec);
        ac97_fix_tone(codec);
-       ac97_fix_volume(codec);
        if (codec_patch)
                codec_patch(codec);
 
@@ -911,6 +878,79 @@ ac97mix_init(struct snd_mixer *m)
        if (ac97_initmixer(codec))
                return -1;
 
+       switch (codec->id) {
+       case 0x41445374:        /* AD1981B */
+               switch (codec->subvendor) {
+               case 0x02d91014:
+                       /*
+                        * IBM Thinkcentre:
+                        *
+                        * Tie "ogain" and "phout" to "vol" since its
+                        * master volume is basically useless and can't
+                        * control anything.
+                        */
+                       mask = 0;
+                       if (codec->mix[SOUND_MIXER_OGAIN].enable)
+                               mask |= SOUND_MASK_OGAIN;
+                       if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
+                               mask |= SOUND_MASK_PHONEOUT;
+                       if (codec->mix[SOUND_MIXER_VOLUME].enable)
+                               mix_setparentchild(m, SOUND_MIXER_VOLUME,
+                                   mask);
+                       else {
+                               mix_setparentchild(m, SOUND_MIXER_VOLUME,
+                                   mask);
+                               mix_setrealdev(m, SOUND_MIXER_VOLUME,
+                                   SOUND_MIXER_NONE);
+                       }
+                       break;
+               case 0x099c103c:
+                       /*
+                        * HP nx6110:
+                        *
+                        * By default, "vol" is controlling internal speakers
+                        * (not a master volume!) and "ogain" is controlling
+                        * headphone. Enable dummy "phout" so it can be
+                        * remapped to internal speakers and virtualize
+                        * "vol" to control both.
+                        */
+                       codec->mix[SOUND_MIXER_OGAIN].enable = 1;
+                       codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
+                       mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
+                           SOUND_MIXER_VOLUME);
+                       mix_setrealdev(m, SOUND_MIXER_VOLUME,
+                           SOUND_MIXER_NONE);
+                       mix_setparentchild(m, SOUND_MIXER_VOLUME,
+                           SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case 0x434d4941:        /* CMI9738 */
+       case 0x434d4961:        /* CMI9739 */
+       case 0x434d4978:        /* CMI9761 */
+       case 0x434d4982:        /* CMI9761 */
+       case 0x434d4983:        /* CMI9761 */
+               ac97_wrcd(codec, AC97_MIX_PCM, 0);
+               bzero(&codec->mix[SOUND_MIXER_PCM],
+                   sizeof(codec->mix[SOUND_MIXER_PCM]));
+               pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
+                   SD_F_SOFTPCMVOL);
+               /* XXX How about master volume ? */
+               break;
+       default:
+               break;
+       }
+
+#if 0
+       /* XXX For the sake of debugging purposes */
+       mix_setparentchild(m, SOUND_MIXER_VOLUME,
+           SOUND_MASK_PCM | SOUND_MASK_CD);
+       mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
+       ac97_wrcd(codec, AC97_MIX_MASTER, 0);
+#endif
+
        mask = 0;
        for (i = 0; i < 32; i++)
                mask |= codec->mix[i].enable? 1 << i : 0;