ALSA: hda - introduce snd_hda_codec_update_cache()
authorTakashi Iwai <tiwai@suse.de>
Tue, 30 Mar 2010 16:03:44 +0000 (18:03 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 30 Mar 2010 16:03:44 +0000 (18:03 +0200)
Add a new helper, snd_hda_codec_update_cache(), for reducing the unneeded
verbs.  This function checks the cached value and skips if it's identical
with the given one.  Otherwise it works like snd_hda_codec_write_cache().

The alc269 code uses this function as an example.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/patch_realtek.c

index d1424e7b9f3dfffd3b914ed35d5d928c981486ce..a3d638c8c1fd96a407c64b36ee2098d60e087bea 100644 (file)
@@ -1209,8 +1209,7 @@ static void free_hda_cache(struct hda_cache_rec *cache)
 }
 
 /* query the hash.  allocate an entry if not found. */
-static struct hda_cache_head  *get_alloc_hash(struct hda_cache_rec *cache,
-                                             u32 key)
+static struct hda_cache_head  *get_hash(struct hda_cache_rec *cache, u32 key)
 {
        u16 idx = key % (u16)ARRAY_SIZE(cache->hash);
        u16 cur = cache->hash[idx];
@@ -1222,17 +1221,27 @@ static struct hda_cache_head  *get_alloc_hash(struct hda_cache_rec *cache,
                        return info;
                cur = info->next;
        }
+       return NULL;
+}
 
-       /* add a new hash entry */
-       info = snd_array_new(&cache->buf);
-       if (!info)
-               return NULL;
-       cur = snd_array_index(&cache->buf, info);
-       info->key = key;
-       info->val = 0;
-       info->next = cache->hash[idx];
-       cache->hash[idx] = cur;
-
+/* query the hash.  allocate an entry if not found. */
+static struct hda_cache_head  *get_alloc_hash(struct hda_cache_rec *cache,
+                                             u32 key)
+{
+       struct hda_cache_head *info = get_hash(cache, key);
+       if (!info) {
+               u16 idx, cur;
+               /* add a new hash entry */
+               info = snd_array_new(&cache->buf);
+               if (!info)
+                       return NULL;
+               cur = snd_array_index(&cache->buf, info);
+               info->key = key;
+               info->val = 0;
+               idx = key % (u16)ARRAY_SIZE(cache->hash);
+               info->next = cache->hash[idx];
+               cache->hash[idx] = cur;
+       }
        return info;
 }
 
@@ -2721,6 +2730,41 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
 
+/**
+ * snd_hda_codec_update_cache - check cache and write the cmd only when needed
+ * @codec: the HDA codec
+ * @nid: NID to send the command
+ * @direct: direct flag
+ * @verb: the verb to send
+ * @parm: the parameter for the verb
+ *
+ * This function works like snd_hda_codec_write_cache(), but it doesn't send
+ * command if the parameter is already identical with the cached value.
+ * If not, it sends the command and refreshes the cache.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
+                              int direct, unsigned int verb, unsigned int parm)
+{
+       struct hda_cache_head *c;
+       u32 key;
+
+       /* parm may contain the verb stuff for get/set amp */
+       verb = verb | (parm >> 8);
+       parm &= 0xff;
+       key = build_cmd_cache_key(nid, verb);
+       mutex_lock(&codec->bus->cmd_mutex);
+       c = get_hash(&codec->cmd_cache, key);
+       if (c && c->val == parm) {
+               mutex_unlock(&codec->bus->cmd_mutex);
+               return 0;
+       }
+       mutex_unlock(&codec->bus->cmd_mutex);
+       return snd_hda_codec_write_cache(codec, nid, direct, verb, parm);
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache);
+
 /**
  * snd_hda_codec_resume_cache - Resume the all commands from the cache
  * @codec: HD-audio codec
index b75da47571e6e74bef852d2daba390c6747d0b94..49e939e7e5cd1a616b0772ebd7a5d9ff5c0465d8 100644 (file)
@@ -885,9 +885,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
                              int direct, unsigned int verb, unsigned int parm);
 void snd_hda_sequence_write_cache(struct hda_codec *codec,
                                  const struct hda_verb *seq);
+int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
+                             int direct, unsigned int verb, unsigned int parm);
 void snd_hda_codec_resume_cache(struct hda_codec *codec);
 #else
 #define snd_hda_codec_write_cache      snd_hda_codec_write
+#define snd_hda_codec_update_cache     snd_hda_codec_write
 #define snd_hda_sequence_write_cache   snd_hda_sequence_write
 #endif
 
index 9a361c2c7336ca5b0f43dd8c742a768bffc25313..8ae48061e8c7b0105ffbbf8ee9238ad5f0130ff9 100644 (file)
@@ -14012,8 +14012,9 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
                else
                        pinval = 0x20;
                /* mic2 vref pin is used for mute LED control */
-               snd_hda_codec_write(codec, 0x19, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, pinval);
+               snd_hda_codec_update_cache(codec, 0x19, 0,
+                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                          pinval);
        }
        return alc_check_power_status(codec, nid);
 }