summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-03-30 18:03:44 +0200
committerTakashi Iwai <tiwai@suse.de>2010-03-30 18:03:44 +0200
commita68d5a5419d2a15161488b20f740115068e7b666 (patch)
tree75249110bd358f068835ad87d1f47f99f4962038
parentad35879aa192e783db2d41c196f48f3fc059ce22 (diff)
ALSA: hda - introduce snd_hda_codec_update_cache()
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>
-rw-r--r--sound/pci/hda/hda_codec.c68
-rw-r--r--sound/pci/hda/hda_codec.h3
-rw-r--r--sound/pci/hda/patch_realtek.c5
3 files changed, 62 insertions, 14 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index d1424e7b9f3d..a3d638c8c1fd 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -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;
}
@@ -2722,6 +2731,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
*
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index b75da47571e6..49e939e7e5cd 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -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
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 9a361c2c7336..8ae48061e8c7 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -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);
}