aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-08-10 11:03:40 -0400
committerJaroslav Kysela <perex@perex.cz>2007-10-16 09:58:41 -0400
commitb3ac56364126f78cae94eb2a75b72d9ea85aca9d (patch)
tree8f4865f1f888d612697452ab280922440e67e24f /sound/pci/hda
parent01751f54ff23b9d59e07f9c9ef189d4733525463 (diff)
[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')
-rw-r--r--sound/pci/hda/hda_codec.c91
-rw-r--r--sound/pci/hda/hda_codec.h8
-rw-r--r--sound/pci/hda/hda_local.h1
3 files changed, 100 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)
510 if (codec->patch_ops.free) 510 if (codec->patch_ops.free)
511 codec->patch_ops.free(codec); 511 codec->patch_ops.free(codec);
512 free_hda_cache(&codec->amp_cache); 512 free_hda_cache(&codec->amp_cache);
513 free_hda_cache(&codec->cmd_cache);
513 kfree(codec->wcaps); 514 kfree(codec->wcaps);
514 kfree(codec); 515 kfree(codec);
515} 516}
@@ -548,6 +549,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
548 codec->addr = codec_addr; 549 codec->addr = codec_addr;
549 mutex_init(&codec->spdif_mutex); 550 mutex_init(&codec->spdif_mutex);
550 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); 551 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
552 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
551 553
552 list_add_tail(&codec->list, &bus->codec_list); 554 list_add_tail(&codec->list, &bus->codec_list);
553 bus->caddr_tbl[codec_addr] = codec; 555 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,
840 return 1; 842 return 1;
841} 843}
842 844
845/* resume the all amp commands from the cache */
846void snd_hda_codec_resume_amp(struct hda_codec *codec)
847{
848 struct hda_amp_info *buffer = codec->amp_cache.buffer;
849 int i;
850
851 for (i = 0; i < codec->amp_cache.size; i++, buffer++) {
852 u32 key = buffer->head.key;
853 hda_nid_t nid;
854 unsigned int idx, dir, ch;
855 if (!key)
856 continue;
857 nid = key & 0xff;
858 idx = (key >> 16) & 0xff;
859 dir = (key >> 24) & 0xff;
860 for (ch = 0; ch < 2; ch++) {
861 if (!(buffer->head.val & INFO_AMP_VOL(ch)))
862 continue;
863 put_vol_mute(codec, buffer, nid, ch, dir, idx,
864 buffer->vol[ch]);
865 }
866 }
867}
843 868
844/* 869/*
845 * AMP control callbacks 870 * AMP control callbacks
@@ -1458,6 +1483,72 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
1458} 1483}
1459 1484
1460 1485
1486/* build a 32bit cache key with the widget id and the command parameter */
1487#define build_cmd_cache_key(nid, verb) ((verb << 8) | nid)
1488#define get_cmd_cache_nid(key) ((key) & 0xff)
1489#define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff)
1490
1491/**
1492 * snd_hda_codec_write_cache - send a single command with caching
1493 * @codec: the HDA codec
1494 * @nid: NID to send the command
1495 * @direct: direct flag
1496 * @verb: the verb to send
1497 * @parm: the parameter for the verb
1498 *
1499 * Send a single command without waiting for response.
1500 *
1501 * Returns 0 if successful, or a negative error code.
1502 */
1503int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
1504 int direct, unsigned int verb, unsigned int parm)
1505{
1506 int err;
1507 mutex_lock(&codec->bus->cmd_mutex);
1508 err = codec->bus->ops.command(codec, nid, direct, verb, parm);
1509 if (!err) {
1510 struct hda_cache_head *c;
1511 u32 key = build_cmd_cache_key(nid, verb);
1512 c = get_alloc_hash(&codec->cmd_cache, key);
1513 if (c)
1514 c->val = parm;
1515 }
1516 mutex_unlock(&codec->bus->cmd_mutex);
1517 return err;
1518}
1519
1520/* resume the all commands from the cache */
1521void snd_hda_codec_resume_cache(struct hda_codec *codec)
1522{
1523 struct hda_cache_head *buffer = codec->cmd_cache.buffer;
1524 int i;
1525
1526 for (i = 0; i < codec->cmd_cache.size; i++, buffer++) {
1527 u32 key = buffer->key;
1528 if (!key)
1529 continue;
1530 snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0,
1531 get_cmd_cache_cmd(key), buffer->val);
1532 }
1533}
1534
1535/**
1536 * snd_hda_sequence_write_cache - sequence writes with caching
1537 * @codec: the HDA codec
1538 * @seq: VERB array to send
1539 *
1540 * Send the commands sequentially from the given array.
1541 * Thte commands are recorded on cache for power-save and resume.
1542 * The array must be terminated with NID=0.
1543 */
1544void snd_hda_sequence_write_cache(struct hda_codec *codec,
1545 const struct hda_verb *seq)
1546{
1547 for (; seq->nid; seq++)
1548 snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb,
1549 seq->param);
1550}
1551
1461/* 1552/*
1462 * set power state of the codec 1553 * set power state of the codec
1463 */ 1554 */
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 1a69743160ce..ef94c9122c6d 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -570,6 +570,7 @@ struct hda_codec {
570 u32 *wcaps; 570 u32 *wcaps;
571 571
572 struct hda_cache_rec amp_cache; /* cache for amp access */ 572 struct hda_cache_rec amp_cache; /* cache for amp access */
573 struct hda_cache_rec cmd_cache; /* cache for other commands */
573 574
574 struct mutex spdif_mutex; 575 struct mutex spdif_mutex;
575 unsigned int spdif_status; /* IEC958 status bits */ 576 unsigned int spdif_status; /* IEC958 status bits */
@@ -620,6 +621,13 @@ void snd_hda_sequence_write(struct hda_codec *codec,
620/* unsolicited event */ 621/* unsolicited event */
621int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); 622int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
622 623
624/* cached write */
625int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
626 int direct, unsigned int verb, unsigned int parm);
627void snd_hda_sequence_write_cache(struct hda_codec *codec,
628 const struct hda_verb *seq);
629void snd_hda_codec_resume_cache(struct hda_codec *codec);
630
623/* 631/*
624 * Mixer 632 * Mixer
625 */ 633 */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index fafcffe6fc79..51208974c2da 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -84,6 +84,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
84 int direction, int index); 84 int direction, int index);
85int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, 85int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
86 int direction, int idx, int mask, int val); 86 int direction, int idx, int mask, int val);
87void snd_hda_codec_resume_amp(struct hda_codec *codec);
87 88
88/* mono switch binding multiple inputs */ 89/* mono switch binding multiple inputs */
89#define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ 90#define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \