diff options
author | Takashi Iwai <tiwai@suse.de> | 2007-08-10 17:03:40 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2007-10-16 15:58:41 +0200 |
commit | b3ac56364126f78cae94eb2a75b72d9ea85aca9d (patch) | |
tree | 8f4865f1f888d612697452ab280922440e67e24f /sound/pci/hda/hda_codec.c | |
parent | 01751f54ff23b9d59e07f9c9ef189d4733525463 (diff) | |
download | lwn-b3ac56364126f78cae94eb2a75b72d9ea85aca9d.tar.gz lwn-b3ac56364126f78cae94eb2a75b72d9ea85aca9d.zip |
[ALSA] hda-codec - introduce command register cache
This patch adds the cache for codec command registers.
snd_hda_codec_write_cache() and snd_hda_sequence_write_cache() do
the write operations with caching, which values can be resumed via
snd_hda_codec_resume_cache().
The patch introduces only the framework, and no codec code is using
this cache yet. It'll be implemented in the following patch.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 46f8ab1df874..6652a531980d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -510,6 +510,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) if (codec->patch_ops.free) codec->patch_ops.free(codec); free_hda_cache(&codec->amp_cache); + free_hda_cache(&codec->cmd_cache); kfree(codec->wcaps); kfree(codec); } @@ -548,6 +549,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); + init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); list_add_tail(&codec->list, &bus->codec_list); bus->caddr_tbl[codec_addr] = codec; @@ -840,6 +842,29 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, return 1; } +/* resume the all amp commands from the cache */ +void snd_hda_codec_resume_amp(struct hda_codec *codec) +{ + struct hda_amp_info *buffer = codec->amp_cache.buffer; + int i; + + for (i = 0; i < codec->amp_cache.size; i++, buffer++) { + u32 key = buffer->head.key; + hda_nid_t nid; + unsigned int idx, dir, ch; + if (!key) + continue; + nid = key & 0xff; + idx = (key >> 16) & 0xff; + dir = (key >> 24) & 0xff; + for (ch = 0; ch < 2; ch++) { + if (!(buffer->head.val & INFO_AMP_VOL(ch))) + continue; + put_vol_mute(codec, buffer, nid, ch, dir, idx, + buffer->vol[ch]); + } + } +} /* * AMP control callbacks @@ -1458,6 +1483,72 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) } +/* build a 32bit cache key with the widget id and the command parameter */ +#define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) +#define get_cmd_cache_nid(key) ((key) & 0xff) +#define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) + +/** + * snd_hda_codec_write_cache - send a single command with caching + * @codec: the HDA codec + * @nid: NID to send the command + * @direct: direct flag + * @verb: the verb to send + * @parm: the parameter for the verb + * + * Send a single command without waiting for response. + * + * Returns 0 if successful, or a negative error code. + */ +int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm) +{ + int err; + mutex_lock(&codec->bus->cmd_mutex); + err = codec->bus->ops.command(codec, nid, direct, verb, parm); + if (!err) { + struct hda_cache_head *c; + u32 key = build_cmd_cache_key(nid, verb); + c = get_alloc_hash(&codec->cmd_cache, key); + if (c) + c->val = parm; + } + mutex_unlock(&codec->bus->cmd_mutex); + return err; +} + +/* resume the all commands from the cache */ +void snd_hda_codec_resume_cache(struct hda_codec *codec) +{ + struct hda_cache_head *buffer = codec->cmd_cache.buffer; + int i; + + for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { + u32 key = buffer->key; + if (!key) + continue; + snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, + get_cmd_cache_cmd(key), buffer->val); + } +} + +/** + * snd_hda_sequence_write_cache - sequence writes with caching + * @codec: the HDA codec + * @seq: VERB array to send + * + * Send the commands sequentially from the given array. + * Thte commands are recorded on cache for power-save and resume. + * The array must be terminated with NID=0. + */ +void snd_hda_sequence_write_cache(struct hda_codec *codec, + const struct hda_verb *seq) +{ + for (; seq->nid; seq++) + snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, + seq->param); +} + /* * set power state of the codec */ |