]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Takashi Iwai <tiwai@suse.de> |
2 | Subject: ALSA: hda - Support sync after writing a verb | |
3 | Patch-mainline: | |
4 | References: bnc#502903 | |
5 | ||
6 | This patch adds a debug mode to make the codec communication | |
7 | synchronous. Define SND_HDA_SUPPORT_SYNC_WRITE in hda_codec.c, | |
8 | and the call of snd_hda_codec_write*() will become synchronous, | |
9 | i.e. wait for the reply from the codec at each time issuing a verb. | |
10 | ||
11 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
12 | ||
13 | --- | |
14 | sound/pci/hda/hda_codec.c | 87 +++++++++++++++++++++++++--------------------- | |
15 | 1 file changed, 49 insertions(+), 38 deletions(-) | |
16 | ||
17 | --- a/sound/pci/hda/hda_codec.c | |
18 | +++ b/sound/pci/hda/hda_codec.c | |
19 | @@ -176,6 +176,27 @@ | |
20 | >> AC_DEFCFG_DEVICE_SHIFT]; | |
21 | } | |
22 | ||
23 | +/* | |
24 | + * Send and receive a verb | |
25 | + */ | |
26 | +static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, | |
27 | + unsigned int *res) | |
28 | +{ | |
29 | + struct hda_bus *bus = codec->bus; | |
30 | + int err; | |
31 | + | |
32 | + if (res) | |
33 | + *res = -1; | |
34 | + snd_hda_power_up(codec); | |
35 | + mutex_lock(&bus->cmd_mutex); | |
36 | + err = bus->ops.command(bus, cmd); | |
37 | + if (!err && res) | |
38 | + *res = bus->ops.get_response(bus); | |
39 | + mutex_unlock(&bus->cmd_mutex); | |
40 | + snd_hda_power_down(codec); | |
41 | + return err; | |
42 | +} | |
43 | + | |
44 | /** | |
45 | * snd_hda_codec_read - send a command and get the response | |
46 | * @codec: the HDA codec | |
47 | @@ -192,21 +213,17 @@ | |
48 | int direct, | |
49 | unsigned int verb, unsigned int parm) | |
50 | { | |
51 | - struct hda_bus *bus = codec->bus; | |
52 | + unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); | |
53 | unsigned int res; | |
54 | - | |
55 | - res = make_codec_cmd(codec, nid, direct, verb, parm); | |
56 | - snd_hda_power_up(codec); | |
57 | - mutex_lock(&bus->cmd_mutex); | |
58 | - if (!bus->ops.command(bus, res)) | |
59 | - res = bus->ops.get_response(bus); | |
60 | - else | |
61 | - res = (unsigned int)-1; | |
62 | - mutex_unlock(&bus->cmd_mutex); | |
63 | - snd_hda_power_down(codec); | |
64 | + codec_exec_verb(codec, cmd, &res); | |
65 | return res; | |
66 | } | |
67 | ||
68 | +/* Define the below to send and receive verbs synchronously. | |
69 | + * If you often get any codec communication errors, this is worth to try. | |
70 | + */ | |
71 | +#define SND_HDA_SUPPORT_SYNC_WRITE | |
72 | + | |
73 | /** | |
74 | * snd_hda_codec_write - send a single command without waiting for response | |
75 | * @codec: the HDA codec | |
76 | @@ -222,17 +239,13 @@ | |
77 | int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, | |
78 | unsigned int verb, unsigned int parm) | |
79 | { | |
80 | - struct hda_bus *bus = codec->bus; | |
81 | + unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); | |
82 | +#ifdef SND_HDA_SUPPORT_SYNC_WRITE | |
83 | unsigned int res; | |
84 | - int err; | |
85 | - | |
86 | - res = make_codec_cmd(codec, nid, direct, verb, parm); | |
87 | - snd_hda_power_up(codec); | |
88 | - mutex_lock(&bus->cmd_mutex); | |
89 | - err = bus->ops.command(bus, res); | |
90 | - mutex_unlock(&bus->cmd_mutex); | |
91 | - snd_hda_power_down(codec); | |
92 | - return err; | |
93 | + return codec_exec_verb(codec, cmd, &res); | |
94 | +#else | |
95 | + return codec_exec_verb(codec, cmd, NULL); | |
96 | +#endif | |
97 | } | |
98 | ||
99 | /** | |
100 | @@ -1876,24 +1889,22 @@ | |
101 | int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | |
102 | int direct, unsigned int verb, unsigned int parm) | |
103 | { | |
104 | - struct hda_bus *bus = codec->bus; | |
105 | - unsigned int res; | |
106 | - int err; | |
107 | + int err = snd_hda_codec_write(codec, nid, direct, verb, parm); | |
108 | + struct hda_cache_head *c; | |
109 | + u32 key; | |
110 | ||
111 | - res = make_codec_cmd(codec, nid, direct, verb, parm); | |
112 | - snd_hda_power_up(codec); | |
113 | - mutex_lock(&bus->cmd_mutex); | |
114 | - err = bus->ops.command(bus, res); | |
115 | - if (!err) { | |
116 | - struct hda_cache_head *c; | |
117 | - u32 key = build_cmd_cache_key(nid, verb); | |
118 | - c = get_alloc_hash(&codec->cmd_cache, key); | |
119 | - if (c) | |
120 | - c->val = parm; | |
121 | - } | |
122 | - mutex_unlock(&bus->cmd_mutex); | |
123 | - snd_hda_power_down(codec); | |
124 | - return err; | |
125 | + if (err < 0) | |
126 | + return err; | |
127 | + /* parm may contain the verb stuff for get/set amp */ | |
128 | + verb = verb | (parm >> 8); | |
129 | + parm &= 0xff; | |
130 | + key = build_cmd_cache_key(nid, verb); | |
131 | + mutex_lock(&codec->bus->cmd_mutex); | |
132 | + c = get_alloc_hash(&codec->cmd_cache, key); | |
133 | + if (c) | |
134 | + c->val = parm; | |
135 | + mutex_unlock(&codec->bus->cmd_mutex); | |
136 | + return 0; | |
137 | } | |
138 | ||
139 | /* resume the all commands from the cache */ |