diff options
author | Takashi Iwai <tiwai@suse.de> | 2007-08-10 11:03:40 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2007-10-16 09:58:41 -0400 |
commit | b3ac56364126f78cae94eb2a75b72d9ea85aca9d (patch) | |
tree | 8f4865f1f888d612697452ab280922440e67e24f /sound | |
parent | 01751f54ff23b9d59e07f9c9ef189d4733525463 (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')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 91 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 8 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 1 |
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 */ | ||
846 | void 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 | */ | ||
1503 | int 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 */ | ||
1521 | void 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 | */ | ||
1544 | void 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 */ |
621 | int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); | 622 | int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); |
622 | 623 | ||
624 | /* cached write */ | ||
625 | int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | ||
626 | int direct, unsigned int verb, unsigned int parm); | ||
627 | void snd_hda_sequence_write_cache(struct hda_codec *codec, | ||
628 | const struct hda_verb *seq); | ||
629 | void 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); |
85 | int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | 85 | int 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); |
87 | void 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) \ |