[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cdi-devel] [PATCH 6/9] hdaudio: Fix hda_set_volume() scaling



hda_set_volume() scaled the volume (which is between 0 and 255 in the
CDI interface) to something between 0 and 127. That's not generally what
the hardware wants. The number of "steps" are given in the amplifier
capabilities parameter and this is what we need to scale to.

Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
 hdaudio/device.h |  1 +
 hdaudio/main.c   | 14 +++++++++-----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/hdaudio/device.h b/hdaudio/device.h
index b9cedb6..c9fc3d1 100644
--- a/hdaudio/device.h
+++ b/hdaudio/device.h
@@ -107,6 +107,7 @@ struct hda_output {
     uint16_t    nid;
 
     uint32_t    sample_rate;
+    int         amp_gain_steps;
     int         num_channels;
 };
 
diff --git a/hdaudio/main.c b/hdaudio/main.c
index 5bc0e54..98e2a8a 100644
--- a/hdaudio/main.c
+++ b/hdaudio/main.c
@@ -266,6 +266,7 @@ static void widget_init(struct hda_device* hda, int codec, int nid)
 {
     uint32_t widget_cap;
     enum widget_type type;
+    uint32_t amp_cap;
 
     widget_cap = codec_query(hda, codec, nid,
                              VERB_GET_PARAMETER | PARAM_AUDIO_WID_CAP);
@@ -275,10 +276,12 @@ static void widget_init(struct hda_device* hda, int codec, int nid)
 
     type = (widget_cap & WIDGET_CAP_TYPE_MASK) >> WIDGET_CAP_TYPE_SHIFT;
 
+    amp_cap = codec_query(hda, codec, nid,
+                          VERB_GET_PARAMETER | PARAM_OUT_AMP_CAP);
+
 #ifdef DEBUG
     uint32_t eapd_btl;
     uint32_t amp_gain;
-    uint32_t amp_cap;
     const char* s;
 
     switch (type) {
@@ -297,8 +300,6 @@ static void widget_init(struct hda_device* hda, int codec, int nid)
     amp_gain = codec_query(hda, codec, nid,
                            VERB_GET_AMP_GAIN_MUTE | 0x8000) << 8;
     amp_gain |= codec_query(hda, codec, nid, VERB_GET_AMP_GAIN_MUTE | 0xa000);
-    amp_cap = codec_query(hda, codec, nid,
-                          VERB_GET_PARAMETER | PARAM_OUT_AMP_CAP);
     eapd_btl = codec_query(hda, codec, nid, VERB_GET_EAPD_BTL);
 
     DPRINTF("    %s at ID %d; cap %x, eapd %x, amp %x/%x\n",
@@ -338,6 +339,7 @@ static void widget_init(struct hda_device* hda, int codec, int nid)
                 DPRINTF("    * Using output at ID %d!\n", nid);
                 hda->output.codec = codec;
                 hda->output.nid = nid;
+                hda->output.amp_gain_steps = (amp_cap >> 8) & 0x7f;
             }
             break;
         }
@@ -583,12 +585,14 @@ static void hda_set_volume(struct cdi_audio_stream* stream, uint8_t volume)
     struct hda_device* hda = (struct hda_device*) stream->device;
     int meta = 0xb000; /* Output Amp, Left and Right */
 
+    DPRINTF("hda_set_volume: %d\n", volume);
+
     if (volume == 0) {
         /* Set the mute bit */
         volume = 0x80;
     } else {
-        /* Scale to 7-bit value */
-        volume >>= 1;
+        /* Scale to NumSteps */
+        volume = volume * hda->output.amp_gain_steps / 255;
     }
 
     codec_query(hda, hda->output.codec, hda->output.nid,
-- 
2.1.4