[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>
This commit is contained in:
parent
01751f54ff
commit
b3ac563641
|
@ -510,6 +510,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
||||||
if (codec->patch_ops.free)
|
if (codec->patch_ops.free)
|
||||||
codec->patch_ops.free(codec);
|
codec->patch_ops.free(codec);
|
||||||
free_hda_cache(&codec->amp_cache);
|
free_hda_cache(&codec->amp_cache);
|
||||||
|
free_hda_cache(&codec->cmd_cache);
|
||||||
kfree(codec->wcaps);
|
kfree(codec->wcaps);
|
||||||
kfree(codec);
|
kfree(codec);
|
||||||
}
|
}
|
||||||
|
@ -548,6 +549,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
||||||
codec->addr = codec_addr;
|
codec->addr = codec_addr;
|
||||||
mutex_init(&codec->spdif_mutex);
|
mutex_init(&codec->spdif_mutex);
|
||||||
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
|
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);
|
list_add_tail(&codec->list, &bus->codec_list);
|
||||||
bus->caddr_tbl[codec_addr] = codec;
|
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;
|
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
|
* 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
|
* set power state of the codec
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -570,6 +570,7 @@ struct hda_codec {
|
||||||
u32 *wcaps;
|
u32 *wcaps;
|
||||||
|
|
||||||
struct hda_cache_rec amp_cache; /* cache for amp access */
|
struct hda_cache_rec amp_cache; /* cache for amp access */
|
||||||
|
struct hda_cache_rec cmd_cache; /* cache for other commands */
|
||||||
|
|
||||||
struct mutex spdif_mutex;
|
struct mutex spdif_mutex;
|
||||||
unsigned int spdif_status; /* IEC958 status bits */
|
unsigned int spdif_status; /* IEC958 status bits */
|
||||||
|
@ -620,6 +621,13 @@ void snd_hda_sequence_write(struct hda_codec *codec,
|
||||||
/* unsolicited event */
|
/* unsolicited event */
|
||||||
int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
|
int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
|
||||||
|
|
||||||
|
/* cached write */
|
||||||
|
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);
|
||||||
|
void snd_hda_codec_resume_cache(struct hda_codec *codec);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mixer
|
* Mixer
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -84,6 +84,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
|
||||||
int direction, int index);
|
int direction, int index);
|
||||||
int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
|
int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
|
||||||
int direction, int idx, int mask, int val);
|
int direction, int idx, int mask, int val);
|
||||||
|
void snd_hda_codec_resume_amp(struct hda_codec *codec);
|
||||||
|
|
||||||
/* mono switch binding multiple inputs */
|
/* mono switch binding multiple inputs */
|
||||||
#define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \
|
#define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \
|
||||||
|
|
Loading…
Reference in New Issue