]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Takashi Iwai <tiwai@suse.de> |
2 | Subject: ALSA: Add Intel HDMI support | |
3 | Patch-mainline: 2.6.29 | |
4 | References: bnc#485768 | |
5 | ||
6 | Add the support for Intel HDMI devices. | |
7 | ||
8 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
9 | ||
10 | --- | |
11 | sound/pci/Kconfig | 12 | |
12 | sound/pci/hda/Makefile | 2 | |
13 | sound/pci/hda/hda_codec.c | 87 +++++ | |
14 | sound/pci/hda/hda_codec.h | 7 | |
15 | sound/pci/hda/hda_eld.c | 592 ++++++++++++++++++++++++++++++++++ | |
16 | sound/pci/hda/hda_intel.c | 18 - | |
17 | sound/pci/hda/hda_local.h | 68 +++ | |
18 | sound/pci/hda/hda_patch.h | 2 | |
19 | sound/pci/hda/hda_proc.c | 75 ---- | |
20 | sound/pci/hda/patch_atihdmi.c | 9 | |
21 | sound/pci/hda/patch_intelhdmi.c | 694 ++++++++++++++++++++++++++++++++++++++++ | |
22 | sound/pci/hda/patch_nvhdmi.c | 7 | |
23 | 12 files changed, 1504 insertions(+), 69 deletions(-) | |
24 | ||
25 | --- a/sound/pci/Kconfig | |
26 | +++ b/sound/pci/Kconfig | |
27 | @@ -573,6 +573,18 @@ config SND_HDA_CODEC_NVHDMI | |
28 | Say Y here to include NVIDIA HDMI HD-audio codec support in | |
29 | snd-hda-intel driver, such as NVIDIA MCP78 HDMI. | |
30 | ||
31 | +config SND_HDA_CODEC_INTELHDMI | |
32 | + bool "Build INTEL HDMI HD-audio codec support" | |
33 | + depends on SND_HDA_INTEL | |
34 | + default y | |
35 | + help | |
36 | + Say Y here to include INTEL HDMI HD-audio codec support in | |
37 | + snd-hda-intel driver, such as Eaglelake integrated HDMI. | |
38 | + | |
39 | +config SND_HDA_ELD | |
40 | + def_bool y | |
41 | + depends on SND_HDA_CODEC_INTELHDMI | |
42 | + | |
43 | config SND_HDA_CODEC_CONEXANT | |
44 | bool "Build Conexant HD-audio codec support" | |
45 | depends on SND_HDA_INTEL | |
46 | --- a/sound/pci/hda/Makefile | |
47 | +++ b/sound/pci/hda/Makefile | |
48 | @@ -16,5 +16,7 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATI | |
49 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o | |
50 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o | |
51 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o | |
52 | +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o | |
53 | +snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o | |
54 | ||
55 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o | |
56 | --- a/sound/pci/hda/hda_codec.c | |
57 | +++ b/sound/pci/hda/hda_codec.c | |
58 | @@ -55,6 +55,7 @@ static struct hda_vendor_id hda_vendor_i | |
59 | { 0x1002, "ATI" }, | |
60 | { 0x1057, "Motorola" }, | |
61 | { 0x1095, "Silicon Image" }, | |
62 | + { 0x10de, "Nvidia" }, | |
63 | { 0x10ec, "Realtek" }, | |
64 | { 0x1106, "VIA" }, | |
65 | { 0x111d, "IDT" }, | |
66 | @@ -64,7 +65,9 @@ static struct hda_vendor_id hda_vendor_i | |
67 | { 0x14f1, "Conexant" }, | |
68 | { 0x17e8, "Chrontel" }, | |
69 | { 0x1854, "LG" }, | |
70 | + { 0x1aec, "Wolfson Microelectronics" }, | |
71 | { 0x434d, "C-Media" }, | |
72 | + { 0x8086, "Intel" }, | |
73 | { 0x8384, "SigmaTel" }, | |
74 | {} /* terminator */ | |
75 | }; | |
76 | @@ -97,6 +100,9 @@ static const struct hda_codec_preset *hd | |
77 | #ifdef CONFIG_SND_HDA_CODEC_NVHDMI | |
78 | snd_hda_preset_nvhdmi, | |
79 | #endif | |
80 | +#ifdef CONFIG_SND_HDA_CODEC_INTELHDMI | |
81 | + snd_hda_preset_intelhdmi, | |
82 | +#endif | |
83 | NULL | |
84 | }; | |
85 | ||
86 | @@ -124,6 +130,52 @@ make_codec_cmd(struct hda_codec *codec, | |
87 | return val; | |
88 | } | |
89 | ||
90 | +const char *snd_hda_get_jack_location(u32 cfg) | |
91 | +{ | |
92 | + static char *bases[7] = { | |
93 | + "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", | |
94 | + }; | |
95 | + static unsigned char specials_idx[] = { | |
96 | + 0x07, 0x08, | |
97 | + 0x17, 0x18, 0x19, | |
98 | + 0x37, 0x38 | |
99 | + }; | |
100 | + static char *specials[] = { | |
101 | + "Rear Panel", "Drive Bar", | |
102 | + "Riser", "HDMI", "ATAPI", | |
103 | + "Mobile-In", "Mobile-Out" | |
104 | + }; | |
105 | + int i; | |
106 | + cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; | |
107 | + if ((cfg & 0x0f) < 7) | |
108 | + return bases[cfg & 0x0f]; | |
109 | + for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { | |
110 | + if (cfg == specials_idx[i]) | |
111 | + return specials[i]; | |
112 | + } | |
113 | + return "UNKNOWN"; | |
114 | +} | |
115 | + | |
116 | +const char *snd_hda_get_jack_connectivity(u32 cfg) | |
117 | +{ | |
118 | + static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; | |
119 | + | |
120 | + return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; | |
121 | +} | |
122 | + | |
123 | +const char *snd_hda_get_jack_type(u32 cfg) | |
124 | +{ | |
125 | + static char *jack_types[16] = { | |
126 | + "Line Out", "Speaker", "HP Out", "CD", | |
127 | + "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", | |
128 | + "Line In", "Aux", "Mic", "Telephony", | |
129 | + "SPDIF In", "Digitial In", "Reserved", "Other" | |
130 | + }; | |
131 | + | |
132 | + return jack_types[(cfg & AC_DEFCFG_DEVICE) | |
133 | + >> AC_DEFCFG_DEVICE_SHIFT]; | |
134 | +} | |
135 | + | |
136 | /** | |
137 | * snd_hda_codec_read - send a command and get the response | |
138 | * @codec: the HDA codec | |
139 | @@ -1636,6 +1688,8 @@ int snd_hda_create_spdif_out_ctls(struct | |
140 | } | |
141 | for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { | |
142 | kctl = snd_ctl_new1(dig_mix, codec); | |
143 | + if (!kctl) | |
144 | + return -ENOMEM; | |
145 | kctl->id.index = idx; | |
146 | kctl->private_value = nid; | |
147 | err = snd_ctl_add(codec->bus->card, kctl); | |
148 | @@ -1783,6 +1837,8 @@ int snd_hda_create_spdif_in_ctls(struct | |
149 | } | |
150 | for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { | |
151 | kctl = snd_ctl_new1(dig_mix, codec); | |
152 | + if (!kctl) | |
153 | + return -ENOMEM; | |
154 | kctl->private_value = nid; | |
155 | err = snd_ctl_add(codec->bus->card, kctl); | |
156 | if (err < 0) | |
157 | @@ -3263,3 +3319,34 @@ int snd_hda_codecs_inuse(struct hda_bus | |
158 | } | |
159 | #endif | |
160 | #endif | |
161 | + | |
162 | +/* | |
163 | + * used by hda_proc.c and hda_eld.c | |
164 | + */ | |
165 | +void snd_print_pcm_rates(int pcm, char *buf, int buflen) | |
166 | +{ | |
167 | + static unsigned int rates[] = { | |
168 | + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, | |
169 | + 96000, 176400, 192000, 384000 | |
170 | + }; | |
171 | + int i, j; | |
172 | + | |
173 | + for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) | |
174 | + if (pcm & (1 << i)) | |
175 | + j += snprintf(buf + j, buflen - j, " %d", rates[i]); | |
176 | + | |
177 | + buf[j] = '\0'; /* necessary when j == 0 */ | |
178 | +} | |
179 | + | |
180 | +void snd_print_pcm_bits(int pcm, char *buf, int buflen) | |
181 | +{ | |
182 | + static unsigned int bits[] = { 8, 16, 20, 24, 32 }; | |
183 | + int i, j; | |
184 | + | |
185 | + for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) | |
186 | + if (pcm & (AC_SUPPCM_BITS_8 << i)) | |
187 | + j += snprintf(buf + j, buflen - j, " %d", bits[i]); | |
188 | + | |
189 | + buf[j] = '\0'; /* necessary when j == 0 */ | |
190 | +} | |
191 | + | |
192 | --- a/sound/pci/hda/hda_codec.h | |
193 | +++ b/sound/pci/hda/hda_codec.h | |
194 | @@ -832,6 +832,13 @@ int snd_hda_resume(struct hda_bus *bus); | |
195 | #endif | |
196 | ||
197 | /* | |
198 | + * get widget information | |
199 | + */ | |
200 | +const char *snd_hda_get_jack_connectivity(u32 cfg); | |
201 | +const char *snd_hda_get_jack_type(u32 cfg); | |
202 | +const char *snd_hda_get_jack_location(u32 cfg); | |
203 | + | |
204 | +/* | |
205 | * power saving | |
206 | */ | |
207 | #ifdef CONFIG_SND_HDA_POWER_SAVE | |
208 | --- /dev/null | |
209 | +++ b/sound/pci/hda/hda_eld.c | |
210 | @@ -0,0 +1,592 @@ | |
211 | +/* | |
212 | + * Generic routines and proc interface for ELD(EDID Like Data) information | |
213 | + * | |
214 | + * Copyright(c) 2008 Intel Corporation. | |
215 | + * | |
216 | + * Authors: | |
217 | + * Wu Fengguang <wfg@linux.intel.com> | |
218 | + * | |
219 | + * This driver is free software; you can redistribute it and/or modify | |
220 | + * it under the terms of the GNU General Public License as published by | |
221 | + * the Free Software Foundation; either version 2 of the License, or | |
222 | + * (at your option) any later version. | |
223 | + * | |
224 | + * This driver is distributed in the hope that it will be useful, | |
225 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
226 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
227 | + * GNU General Public License for more details. | |
228 | + * | |
229 | + * You should have received a copy of the GNU General Public License | |
230 | + * along with this program; if not, write to the Free Software | |
231 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
232 | + */ | |
233 | + | |
234 | +#include <linux/init.h> | |
235 | +#include <sound/core.h> | |
236 | +#include <asm/unaligned.h> | |
237 | +#include "hda_codec.h" | |
238 | +#include "hda_local.h" | |
239 | + | |
240 | +enum eld_versions { | |
241 | + ELD_VER_CEA_861D = 2, | |
242 | + ELD_VER_PARTIAL = 31, | |
243 | +}; | |
244 | + | |
245 | +enum cea_edid_versions { | |
246 | + CEA_EDID_VER_NONE = 0, | |
247 | + CEA_EDID_VER_CEA861 = 1, | |
248 | + CEA_EDID_VER_CEA861A = 2, | |
249 | + CEA_EDID_VER_CEA861BCD = 3, | |
250 | + CEA_EDID_VER_RESERVED = 4, | |
251 | +}; | |
252 | + | |
253 | +static char *cea_speaker_allocation_names[] = { | |
254 | + /* 0 */ "FL/FR", | |
255 | + /* 1 */ "LFE", | |
256 | + /* 2 */ "FC", | |
257 | + /* 3 */ "RL/RR", | |
258 | + /* 4 */ "RC", | |
259 | + /* 5 */ "FLC/FRC", | |
260 | + /* 6 */ "RLC/RRC", | |
261 | + /* 7 */ "FLW/FRW", | |
262 | + /* 8 */ "FLH/FRH", | |
263 | + /* 9 */ "TC", | |
264 | + /* 10 */ "FCH", | |
265 | +}; | |
266 | + | |
267 | +static char *eld_connection_type_names[4] = { | |
268 | + "HDMI", | |
269 | + "DisplayPort", | |
270 | + "2-reserved", | |
271 | + "3-reserved" | |
272 | +}; | |
273 | + | |
274 | +enum cea_audio_coding_types { | |
275 | + AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, | |
276 | + AUDIO_CODING_TYPE_LPCM = 1, | |
277 | + AUDIO_CODING_TYPE_AC3 = 2, | |
278 | + AUDIO_CODING_TYPE_MPEG1 = 3, | |
279 | + AUDIO_CODING_TYPE_MP3 = 4, | |
280 | + AUDIO_CODING_TYPE_MPEG2 = 5, | |
281 | + AUDIO_CODING_TYPE_AACLC = 6, | |
282 | + AUDIO_CODING_TYPE_DTS = 7, | |
283 | + AUDIO_CODING_TYPE_ATRAC = 8, | |
284 | + AUDIO_CODING_TYPE_SACD = 9, | |
285 | + AUDIO_CODING_TYPE_EAC3 = 10, | |
286 | + AUDIO_CODING_TYPE_DTS_HD = 11, | |
287 | + AUDIO_CODING_TYPE_MLP = 12, | |
288 | + AUDIO_CODING_TYPE_DST = 13, | |
289 | + AUDIO_CODING_TYPE_WMAPRO = 14, | |
290 | + AUDIO_CODING_TYPE_REF_CXT = 15, | |
291 | + /* also include valid xtypes below */ | |
292 | + AUDIO_CODING_TYPE_HE_AAC = 15, | |
293 | + AUDIO_CODING_TYPE_HE_AAC2 = 16, | |
294 | + AUDIO_CODING_TYPE_MPEG_SURROUND = 17, | |
295 | +}; | |
296 | + | |
297 | +enum cea_audio_coding_xtypes { | |
298 | + AUDIO_CODING_XTYPE_HE_REF_CT = 0, | |
299 | + AUDIO_CODING_XTYPE_HE_AAC = 1, | |
300 | + AUDIO_CODING_XTYPE_HE_AAC2 = 2, | |
301 | + AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, | |
302 | + AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, | |
303 | +}; | |
304 | + | |
305 | +static char *cea_audio_coding_type_names[] = { | |
306 | + /* 0 */ "undefined", | |
307 | + /* 1 */ "LPCM", | |
308 | + /* 2 */ "AC-3", | |
309 | + /* 3 */ "MPEG1", | |
310 | + /* 4 */ "MP3", | |
311 | + /* 5 */ "MPEG2", | |
312 | + /* 6 */ "AAC-LC", | |
313 | + /* 7 */ "DTS", | |
314 | + /* 8 */ "ATRAC", | |
315 | + /* 9 */ "DSD (One Bit Audio)", | |
316 | + /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", | |
317 | + /* 11 */ "DTS-HD", | |
318 | + /* 12 */ "MLP (Dolby TrueHD)", | |
319 | + /* 13 */ "DST", | |
320 | + /* 14 */ "WMAPro", | |
321 | + /* 15 */ "HE-AAC", | |
322 | + /* 16 */ "HE-AACv2", | |
323 | + /* 17 */ "MPEG Surround", | |
324 | +}; | |
325 | + | |
326 | +/* | |
327 | + * The following two lists are shared between | |
328 | + * - HDMI audio InfoFrame (source to sink) | |
329 | + * - CEA E-EDID Extension (sink to source) | |
330 | + */ | |
331 | + | |
332 | +/* | |
333 | + * SS1:SS0 index => sample size | |
334 | + */ | |
335 | +static int cea_sample_sizes[4] = { | |
336 | + 0, /* 0: Refer to Stream Header */ | |
337 | + AC_SUPPCM_BITS_16, /* 1: 16 bits */ | |
338 | + AC_SUPPCM_BITS_20, /* 2: 20 bits */ | |
339 | + AC_SUPPCM_BITS_24, /* 3: 24 bits */ | |
340 | +}; | |
341 | + | |
342 | +/* | |
343 | + * SF2:SF1:SF0 index => sampling frequency | |
344 | + */ | |
345 | +static int cea_sampling_frequencies[8] = { | |
346 | + 0, /* 0: Refer to Stream Header */ | |
347 | + SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ | |
348 | + SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ | |
349 | + SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ | |
350 | + SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ | |
351 | + SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ | |
352 | + SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ | |
353 | + SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ | |
354 | +}; | |
355 | + | |
356 | +static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, | |
357 | + int byte_index) | |
358 | +{ | |
359 | + unsigned int val; | |
360 | + | |
361 | + val = snd_hda_codec_read(codec, nid, 0, | |
362 | + AC_VERB_GET_HDMI_ELDD, byte_index); | |
363 | + | |
364 | +#ifdef BE_PARANOID | |
365 | + printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); | |
366 | +#endif | |
367 | + | |
368 | + if ((val & AC_ELDD_ELD_VALID) == 0) { | |
369 | + snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", | |
370 | + byte_index); | |
371 | + val = 0; | |
372 | + } | |
373 | + | |
374 | + return val & AC_ELDD_ELD_DATA; | |
375 | +} | |
376 | + | |
377 | +#define GRAB_BITS(buf, byte, lowbit, bits) \ | |
378 | +({ \ | |
379 | + BUILD_BUG_ON(lowbit > 7); \ | |
380 | + BUILD_BUG_ON(bits > 8); \ | |
381 | + BUILD_BUG_ON(bits <= 0); \ | |
382 | + \ | |
383 | + (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ | |
384 | +}) | |
385 | + | |
386 | +static void hdmi_update_short_audio_desc(struct cea_sad *a, | |
387 | + const unsigned char *buf) | |
388 | +{ | |
389 | + int i; | |
390 | + int val; | |
391 | + | |
392 | + val = GRAB_BITS(buf, 1, 0, 7); | |
393 | + a->rates = 0; | |
394 | + for (i = 0; i < 7; i++) | |
395 | + if (val & (1 << i)) | |
396 | + a->rates |= cea_sampling_frequencies[i + 1]; | |
397 | + | |
398 | + a->channels = GRAB_BITS(buf, 0, 0, 3); | |
399 | + a->channels++; | |
400 | + | |
401 | + a->format = GRAB_BITS(buf, 0, 3, 4); | |
402 | + switch (a->format) { | |
403 | + case AUDIO_CODING_TYPE_REF_STREAM_HEADER: | |
404 | + snd_printd(KERN_INFO | |
405 | + "HDMI: audio coding type 0 not expected\n"); | |
406 | + break; | |
407 | + | |
408 | + case AUDIO_CODING_TYPE_LPCM: | |
409 | + val = GRAB_BITS(buf, 2, 0, 3); | |
410 | + a->sample_bits = 0; | |
411 | + for (i = 0; i < 3; i++) | |
412 | + if (val & (1 << i)) | |
413 | + a->sample_bits |= cea_sample_sizes[i + 1]; | |
414 | + break; | |
415 | + | |
416 | + case AUDIO_CODING_TYPE_AC3: | |
417 | + case AUDIO_CODING_TYPE_MPEG1: | |
418 | + case AUDIO_CODING_TYPE_MP3: | |
419 | + case AUDIO_CODING_TYPE_MPEG2: | |
420 | + case AUDIO_CODING_TYPE_AACLC: | |
421 | + case AUDIO_CODING_TYPE_DTS: | |
422 | + case AUDIO_CODING_TYPE_ATRAC: | |
423 | + a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); | |
424 | + a->max_bitrate *= 8000; | |
425 | + break; | |
426 | + | |
427 | + case AUDIO_CODING_TYPE_SACD: | |
428 | + break; | |
429 | + | |
430 | + case AUDIO_CODING_TYPE_EAC3: | |
431 | + break; | |
432 | + | |
433 | + case AUDIO_CODING_TYPE_DTS_HD: | |
434 | + break; | |
435 | + | |
436 | + case AUDIO_CODING_TYPE_MLP: | |
437 | + break; | |
438 | + | |
439 | + case AUDIO_CODING_TYPE_DST: | |
440 | + break; | |
441 | + | |
442 | + case AUDIO_CODING_TYPE_WMAPRO: | |
443 | + a->profile = GRAB_BITS(buf, 2, 0, 3); | |
444 | + break; | |
445 | + | |
446 | + case AUDIO_CODING_TYPE_REF_CXT: | |
447 | + a->format = GRAB_BITS(buf, 2, 3, 5); | |
448 | + if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || | |
449 | + a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { | |
450 | + snd_printd(KERN_INFO | |
451 | + "HDMI: audio coding xtype %d not expected\n", | |
452 | + a->format); | |
453 | + a->format = 0; | |
454 | + } else | |
455 | + a->format += AUDIO_CODING_TYPE_HE_AAC - | |
456 | + AUDIO_CODING_XTYPE_HE_AAC; | |
457 | + break; | |
458 | + } | |
459 | +} | |
460 | + | |
461 | +/* | |
462 | + * Be careful, ELD buf could be totally rubbish! | |
463 | + */ | |
464 | +static int hdmi_update_eld(struct hdmi_eld *e, | |
465 | + const unsigned char *buf, int size) | |
466 | +{ | |
467 | + int mnl; | |
468 | + int i; | |
469 | + | |
470 | + e->eld_ver = GRAB_BITS(buf, 0, 3, 5); | |
471 | + if (e->eld_ver != ELD_VER_CEA_861D && | |
472 | + e->eld_ver != ELD_VER_PARTIAL) { | |
473 | + snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", | |
474 | + e->eld_ver); | |
475 | + goto out_fail; | |
476 | + } | |
477 | + | |
478 | + e->eld_size = size; | |
479 | + e->baseline_len = GRAB_BITS(buf, 2, 0, 8); | |
480 | + mnl = GRAB_BITS(buf, 4, 0, 5); | |
481 | + e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); | |
482 | + | |
483 | + e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); | |
484 | + e->support_ai = GRAB_BITS(buf, 5, 1, 1); | |
485 | + e->conn_type = GRAB_BITS(buf, 5, 2, 2); | |
486 | + e->sad_count = GRAB_BITS(buf, 5, 4, 4); | |
487 | + | |
488 | + e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; | |
489 | + e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); | |
490 | + | |
491 | + e->port_id = get_unaligned_le64(buf + 8); | |
492 | + | |
493 | + /* not specified, but the spec's tendency is little endian */ | |
494 | + e->manufacture_id = get_unaligned_le16(buf + 16); | |
495 | + e->product_id = get_unaligned_le16(buf + 18); | |
496 | + | |
497 | + if (mnl > ELD_MAX_MNL) { | |
498 | + snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl); | |
499 | + goto out_fail; | |
500 | + } else if (ELD_FIXED_BYTES + mnl > size) { | |
501 | + snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl); | |
502 | + goto out_fail; | |
503 | + } else | |
504 | + strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); | |
505 | + | |
506 | + for (i = 0; i < e->sad_count; i++) { | |
507 | + if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { | |
508 | + snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); | |
509 | + goto out_fail; | |
510 | + } | |
511 | + hdmi_update_short_audio_desc(e->sad + i, | |
512 | + buf + ELD_FIXED_BYTES + mnl + 3 * i); | |
513 | + } | |
514 | + | |
515 | + return 0; | |
516 | + | |
517 | +out_fail: | |
518 | + e->eld_ver = 0; | |
519 | + return -EINVAL; | |
520 | +} | |
521 | + | |
522 | +static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) | |
523 | +{ | |
524 | + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); | |
525 | +} | |
526 | + | |
527 | +static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) | |
528 | +{ | |
529 | + int eldv; | |
530 | + int present; | |
531 | + | |
532 | + present = hdmi_present_sense(codec, nid); | |
533 | + eldv = (present & AC_PINSENSE_ELDV); | |
534 | + present = (present & AC_PINSENSE_PRESENCE); | |
535 | + | |
536 | +#ifdef CONFIG_SND_DEBUG_VERBOSE | |
537 | + printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n", | |
538 | + !!present, !!eldv); | |
539 | +#endif | |
540 | + | |
541 | + return eldv && present; | |
542 | +} | |
543 | + | |
544 | +int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) | |
545 | +{ | |
546 | + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, | |
547 | + AC_DIPSIZE_ELD_BUF); | |
548 | +} | |
549 | + | |
550 | +int snd_hdmi_get_eld(struct hdmi_eld *eld, | |
551 | + struct hda_codec *codec, hda_nid_t nid) | |
552 | +{ | |
553 | + int i; | |
554 | + int ret; | |
555 | + int size; | |
556 | + unsigned char *buf; | |
557 | + | |
558 | + if (!hdmi_eld_valid(codec, nid)) | |
559 | + return -ENOENT; | |
560 | + | |
561 | + size = snd_hdmi_get_eld_size(codec, nid); | |
562 | + if (size == 0) { | |
563 | + /* wfg: workaround for ASUS P5E-VM HDMI board */ | |
564 | + snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); | |
565 | + size = 128; | |
566 | + } | |
567 | + if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { | |
568 | + snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); | |
569 | + return -ERANGE; | |
570 | + } | |
571 | + | |
572 | + buf = kmalloc(size, GFP_KERNEL); | |
573 | + if (!buf) | |
574 | + return -ENOMEM; | |
575 | + | |
576 | + for (i = 0; i < size; i++) | |
577 | + buf[i] = hdmi_get_eld_byte(codec, nid, i); | |
578 | + | |
579 | + ret = hdmi_update_eld(eld, buf, size); | |
580 | + | |
581 | + kfree(buf); | |
582 | + return ret; | |
583 | +} | |
584 | + | |
585 | +static void hdmi_show_short_audio_desc(struct cea_sad *a) | |
586 | +{ | |
587 | + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; | |
588 | + char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; | |
589 | + | |
590 | + if (!a->format) | |
591 | + return; | |
592 | + | |
593 | + snd_print_pcm_rates(a->rates, buf, sizeof(buf)); | |
594 | + | |
595 | + if (a->format == AUDIO_CODING_TYPE_LPCM) | |
596 | + snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); | |
597 | + else if (a->max_bitrate) | |
598 | + snprintf(buf2, sizeof(buf2), | |
599 | + ", max bitrate = %d", a->max_bitrate); | |
600 | + else | |
601 | + buf2[0] = '\0'; | |
602 | + | |
603 | + printk(KERN_INFO "HDMI: supports coding type %s:" | |
604 | + " channels = %d, rates =%s%s\n", | |
605 | + cea_audio_coding_type_names[a->format], | |
606 | + a->channels, | |
607 | + buf, | |
608 | + buf2); | |
609 | +} | |
610 | + | |
611 | +void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) | |
612 | +{ | |
613 | + int i, j; | |
614 | + | |
615 | + for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { | |
616 | + if (spk_alloc & (1 << i)) | |
617 | + j += snprintf(buf + j, buflen - j, " %s", | |
618 | + cea_speaker_allocation_names[i]); | |
619 | + } | |
620 | + buf[j] = '\0'; /* necessary when j == 0 */ | |
621 | +} | |
622 | + | |
623 | +void snd_hdmi_show_eld(struct hdmi_eld *e) | |
624 | +{ | |
625 | + int i; | |
626 | + | |
627 | + printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n", | |
628 | + e->monitor_name, | |
629 | + eld_connection_type_names[e->conn_type]); | |
630 | + | |
631 | + if (e->spk_alloc) { | |
632 | + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; | |
633 | + snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); | |
634 | + printk(KERN_INFO "HDMI: available speakers:%s\n", buf); | |
635 | + } | |
636 | + | |
637 | + for (i = 0; i < e->sad_count; i++) | |
638 | + hdmi_show_short_audio_desc(e->sad + i); | |
639 | +} | |
640 | + | |
641 | +#ifdef CONFIG_PROC_FS | |
642 | + | |
643 | +static void hdmi_print_sad_info(int i, struct cea_sad *a, | |
644 | + struct snd_info_buffer *buffer) | |
645 | +{ | |
646 | + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; | |
647 | + | |
648 | + snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", | |
649 | + i, a->format, cea_audio_coding_type_names[a->format]); | |
650 | + snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); | |
651 | + | |
652 | + snd_print_pcm_rates(a->rates, buf, sizeof(buf)); | |
653 | + snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); | |
654 | + | |
655 | + if (a->format == AUDIO_CODING_TYPE_LPCM) { | |
656 | + snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); | |
657 | + snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", | |
658 | + i, a->sample_bits, buf); | |
659 | + } | |
660 | + | |
661 | + if (a->max_bitrate) | |
662 | + snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", | |
663 | + i, a->max_bitrate); | |
664 | + | |
665 | + if (a->profile) | |
666 | + snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); | |
667 | +} | |
668 | + | |
669 | +static void hdmi_print_eld_info(struct snd_info_entry *entry, | |
670 | + struct snd_info_buffer *buffer) | |
671 | +{ | |
672 | + struct hdmi_eld *e = entry->private_data; | |
673 | + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; | |
674 | + int i; | |
675 | + static char *eld_versoin_names[32] = { | |
676 | + "reserved", | |
677 | + "reserved", | |
678 | + "CEA-861D or below", | |
679 | + [3 ... 30] = "reserved", | |
680 | + [31] = "partial" | |
681 | + }; | |
682 | + static char *cea_edid_version_names[8] = { | |
683 | + "no CEA EDID Timing Extension block present", | |
684 | + "CEA-861", | |
685 | + "CEA-861-A", | |
686 | + "CEA-861-B, C or D", | |
687 | + [4 ... 7] = "reserved" | |
688 | + }; | |
689 | + | |
690 | + snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); | |
691 | + snd_iprintf(buffer, "connection_type\t\t%s\n", | |
692 | + eld_connection_type_names[e->conn_type]); | |
693 | + snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, | |
694 | + eld_versoin_names[e->eld_ver]); | |
695 | + snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, | |
696 | + cea_edid_version_names[e->cea_edid_ver]); | |
697 | + snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); | |
698 | + snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); | |
699 | + snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); | |
700 | + snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); | |
701 | + snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); | |
702 | + snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); | |
703 | + | |
704 | + snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); | |
705 | + snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); | |
706 | + | |
707 | + snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); | |
708 | + | |
709 | + for (i = 0; i < e->sad_count; i++) | |
710 | + hdmi_print_sad_info(i, e->sad + i, buffer); | |
711 | +} | |
712 | + | |
713 | +static void hdmi_write_eld_info(struct snd_info_entry *entry, | |
714 | + struct snd_info_buffer *buffer) | |
715 | +{ | |
716 | + struct hdmi_eld *e = entry->private_data; | |
717 | + char line[64]; | |
718 | + char name[64]; | |
719 | + char *sname; | |
720 | + long long val; | |
721 | + int n; | |
722 | + | |
723 | + while (!snd_info_get_line(buffer, line, sizeof(line))) { | |
724 | + if (sscanf(line, "%s %llx", name, &val) != 2) | |
725 | + continue; | |
726 | + /* | |
727 | + * We don't allow modification to these fields: | |
728 | + * monitor_name manufacture_id product_id | |
729 | + * eld_version edid_version | |
730 | + */ | |
731 | + if (!strcmp(name, "connection_type")) | |
732 | + e->conn_type = val; | |
733 | + else if (!strcmp(name, "port_id")) | |
734 | + e->port_id = val; | |
735 | + else if (!strcmp(name, "support_hdcp")) | |
736 | + e->support_hdcp = val; | |
737 | + else if (!strcmp(name, "support_ai")) | |
738 | + e->support_ai = val; | |
739 | + else if (!strcmp(name, "audio_sync_delay")) | |
740 | + e->aud_synch_delay = val; | |
741 | + else if (!strcmp(name, "speakers")) | |
742 | + e->spk_alloc = val; | |
743 | + else if (!strcmp(name, "sad_count")) | |
744 | + e->sad_count = val; | |
745 | + else if (!strncmp(name, "sad", 3)) { | |
746 | + sname = name + 4; | |
747 | + n = name[3] - '0'; | |
748 | + if (name[4] >= '0' && name[4] <= '9') { | |
749 | + sname++; | |
750 | + n = 10 * n + name[4] - '0'; | |
751 | + } | |
752 | + if (n < 0 || n > 31) /* double the CEA limit */ | |
753 | + continue; | |
754 | + if (!strcmp(sname, "_coding_type")) | |
755 | + e->sad[n].format = val; | |
756 | + else if (!strcmp(sname, "_channels")) | |
757 | + e->sad[n].channels = val; | |
758 | + else if (!strcmp(sname, "_rates")) | |
759 | + e->sad[n].rates = val; | |
760 | + else if (!strcmp(sname, "_bits")) | |
761 | + e->sad[n].sample_bits = val; | |
762 | + else if (!strcmp(sname, "_max_bitrate")) | |
763 | + e->sad[n].max_bitrate = val; | |
764 | + else if (!strcmp(sname, "_profile")) | |
765 | + e->sad[n].profile = val; | |
766 | + if (n >= e->sad_count) | |
767 | + e->sad_count = n + 1; | |
768 | + } | |
769 | + } | |
770 | +} | |
771 | + | |
772 | + | |
773 | +int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) | |
774 | +{ | |
775 | + char name[32]; | |
776 | + struct snd_info_entry *entry; | |
777 | + int err; | |
778 | + | |
779 | + snprintf(name, sizeof(name), "eld#%d", codec->addr); | |
780 | + err = snd_card_proc_new(codec->bus->card, name, &entry); | |
781 | + if (err < 0) | |
782 | + return err; | |
783 | + | |
784 | + snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); | |
785 | + entry->c.text.write = hdmi_write_eld_info; | |
786 | + entry->mode |= S_IWUSR; | |
787 | + eld->proc_entry = entry; | |
788 | + | |
789 | + return 0; | |
790 | +} | |
791 | + | |
792 | +void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) | |
793 | +{ | |
794 | +#if 0 /* we don't support hwdep reconfig yet */ | |
795 | + if (!codec->bus->shutdown && eld->proc_entry) { | |
796 | + snd_device_free(codec->bus->card, eld->proc_entry); | |
797 | + eld->proc_entry = NULL; | |
798 | + } | |
799 | +#endif | |
800 | +} | |
801 | + | |
802 | +#endif /* CONFIG_PROC_FS */ | |
803 | --- a/sound/pci/hda/hda_intel.c | |
804 | +++ b/sound/pci/hda/hda_intel.c | |
805 | @@ -292,6 +292,8 @@ enum { | |
806 | /* Define VIA HD Audio Device ID*/ | |
807 | #define VIA_HDAC_DEVICE_ID 0x3288 | |
808 | ||
809 | +/* HD Audio class code */ | |
810 | +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 | |
811 | ||
812 | /* | |
813 | */ | |
814 | @@ -418,6 +420,7 @@ enum { | |
815 | AZX_DRIVER_ULI, | |
816 | AZX_DRIVER_NVIDIA, | |
817 | AZX_DRIVER_TERA, | |
818 | + AZX_DRIVER_GENERIC, | |
819 | AZX_NUM_DRIVERS, /* keep this as last entry */ | |
820 | }; | |
821 | ||
822 | @@ -431,6 +434,7 @@ static char *driver_short_names[] __devi | |
823 | [AZX_DRIVER_ULI] = "HDA ULI M5461", | |
824 | [AZX_DRIVER_NVIDIA] = "HDA NVidia", | |
825 | [AZX_DRIVER_TERA] = "HDA Teradici", | |
826 | + [AZX_DRIVER_GENERIC] = "HD-Audio Generic", | |
827 | }; | |
828 | ||
829 | /* | |
830 | @@ -2321,6 +2325,7 @@ static int __devinit azx_create(struct s | |
831 | chip->playback_streams = ATIHDMI_NUM_PLAYBACK; | |
832 | chip->capture_streams = ATIHDMI_NUM_CAPTURE; | |
833 | break; | |
834 | + case AZX_DRIVER_GENERIC: | |
835 | default: | |
836 | chip->playback_streams = ICH6_NUM_PLAYBACK; | |
837 | chip->capture_streams = ICH6_NUM_CAPTURE; | |
838 | @@ -2530,12 +2535,17 @@ static struct pci_device_id azx_ids[] = | |
839 | { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, | |
840 | { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, | |
841 | { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, | |
842 | - { PCI_DEVICE(0x10de, 0x0bd4), .driver_data = AZX_DRIVER_NVIDIA }, | |
843 | - { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA }, | |
844 | - { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA }, | |
845 | - { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, | |
846 | + { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, | |
847 | + { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, | |
848 | + { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, | |
849 | + { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, | |
850 | /* Teradici */ | |
851 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, | |
852 | + /* AMD Generic, PCI class code and Vendor ID for HD Audio */ | |
853 | + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), | |
854 | + .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, | |
855 | + .class_mask = 0xffffff, | |
856 | + .driver_data = AZX_DRIVER_GENERIC }, | |
857 | { 0, } | |
858 | }; | |
859 | MODULE_DEVICE_TABLE(pci, azx_ids); | |
860 | --- a/sound/pci/hda/hda_local.h | |
861 | +++ b/sound/pci/hda/hda_local.h | |
862 | @@ -284,6 +284,12 @@ int snd_hda_codec_proc_new(struct hda_co | |
863 | static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } | |
864 | #endif | |
865 | ||
866 | +#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 | |
867 | +void snd_print_pcm_rates(int pcm, char *buf, int buflen); | |
868 | + | |
869 | +#define SND_PRINT_BITS_ADVISED_BUFSIZE 16 | |
870 | +void snd_print_pcm_bits(int pcm, char *buf, int buflen); | |
871 | + | |
872 | /* | |
873 | * Misc | |
874 | */ | |
875 | @@ -436,4 +442,66 @@ int snd_hda_check_amp_list_power(struct | |
876 | #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) | |
877 | #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) | |
878 | ||
879 | +/* | |
880 | + * CEA Short Audio Descriptor data | |
881 | + */ | |
882 | +struct cea_sad { | |
883 | + int channels; | |
884 | + int format; /* (format == 0) indicates invalid SAD */ | |
885 | + int rates; | |
886 | + int sample_bits; /* for LPCM */ | |
887 | + int max_bitrate; /* for AC3...ATRAC */ | |
888 | + int profile; /* for WMAPRO */ | |
889 | +}; | |
890 | + | |
891 | +#define ELD_FIXED_BYTES 20 | |
892 | +#define ELD_MAX_MNL 16 | |
893 | +#define ELD_MAX_SAD 16 | |
894 | + | |
895 | +/* | |
896 | + * ELD: EDID Like Data | |
897 | + */ | |
898 | +struct hdmi_eld { | |
899 | + int eld_size; | |
900 | + int baseline_len; | |
901 | + int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ | |
902 | + int cea_edid_ver; | |
903 | + char monitor_name[ELD_MAX_MNL + 1]; | |
904 | + int manufacture_id; | |
905 | + int product_id; | |
906 | + u64 port_id; | |
907 | + int support_hdcp; | |
908 | + int support_ai; | |
909 | + int conn_type; | |
910 | + int aud_synch_delay; | |
911 | + int spk_alloc; | |
912 | + int sad_count; | |
913 | + struct cea_sad sad[ELD_MAX_SAD]; | |
914 | +#ifdef CONFIG_PROC_FS | |
915 | + struct snd_info_entry *proc_entry; | |
916 | +#endif | |
917 | +}; | |
918 | + | |
919 | +int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); | |
920 | +int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); | |
921 | +void snd_hdmi_show_eld(struct hdmi_eld *eld); | |
922 | + | |
923 | +#ifdef CONFIG_PROC_FS | |
924 | +int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); | |
925 | +void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); | |
926 | +#else | |
927 | +static inline int snd_hda_eld_proc_new(struct hda_codec *codec, | |
928 | + struct hdmi_eld *eld) | |
929 | +{ | |
930 | + return 0; | |
931 | +} | |
932 | +static inline void snd_hda_eld_proc_free(struct hda_codec *codec, | |
933 | + struct hdmi_eld *eld) | |
934 | +{ | |
935 | +} | |
936 | +#endif | |
937 | + | |
938 | +#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 | |
939 | +void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); | |
940 | + | |
941 | #endif /* __SOUND_HDA_LOCAL_H */ | |
942 | --- a/sound/pci/hda/hda_patch.h | |
943 | +++ b/sound/pci/hda/hda_patch.h | |
944 | @@ -20,3 +20,5 @@ extern struct hda_codec_preset snd_hda_p | |
945 | extern struct hda_codec_preset snd_hda_preset_via[]; | |
946 | /* NVIDIA HDMI codecs */ | |
947 | extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; | |
948 | +/* Intel HDMI codecs */ | |
949 | +extern struct hda_codec_preset snd_hda_preset_intelhdmi[]; | |
950 | --- a/sound/pci/hda/hda_proc.c | |
951 | +++ b/sound/pci/hda/hda_proc.c | |
952 | @@ -91,31 +91,21 @@ static void print_amp_vals(struct snd_in | |
953 | ||
954 | static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) | |
955 | { | |
956 | - static unsigned int rates[] = { | |
957 | - 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, | |
958 | - 96000, 176400, 192000, 384000 | |
959 | - }; | |
960 | - int i; | |
961 | + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; | |
962 | ||
963 | pcm &= AC_SUPPCM_RATES; | |
964 | snd_iprintf(buffer, " rates [0x%x]:", pcm); | |
965 | - for (i = 0; i < ARRAY_SIZE(rates); i++) | |
966 | - if (pcm & (1 << i)) | |
967 | - snd_iprintf(buffer, " %d", rates[i]); | |
968 | - snd_iprintf(buffer, "\n"); | |
969 | + snd_print_pcm_rates(pcm, buf, sizeof(buf)); | |
970 | + snd_iprintf(buffer, "%s\n", buf); | |
971 | } | |
972 | ||
973 | static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) | |
974 | { | |
975 | - static unsigned int bits[] = { 8, 16, 20, 24, 32 }; | |
976 | - int i; | |
977 | + char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; | |
978 | ||
979 | - pcm = (pcm >> 16) & 0xff; | |
980 | - snd_iprintf(buffer, " bits [0x%x]:", pcm); | |
981 | - for (i = 0; i < ARRAY_SIZE(bits); i++) | |
982 | - if (pcm & (1 << i)) | |
983 | - snd_iprintf(buffer, " %d", bits[i]); | |
984 | - snd_iprintf(buffer, "\n"); | |
985 | + snd_iprintf(buffer, " bits [0x%x]:", (pcm >> 16) & 0xff); | |
986 | + snd_print_pcm_bits(pcm, buf, sizeof(buf)); | |
987 | + snd_iprintf(buffer, "%s\n", buf); | |
988 | } | |
989 | ||
990 | static void print_pcm_formats(struct snd_info_buffer *buffer, | |
991 | @@ -145,32 +135,6 @@ static void print_pcm_caps(struct snd_in | |
992 | print_pcm_formats(buffer, stream); | |
993 | } | |
994 | ||
995 | -static const char *get_jack_location(u32 cfg) | |
996 | -{ | |
997 | - static char *bases[7] = { | |
998 | - "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", | |
999 | - }; | |
1000 | - static unsigned char specials_idx[] = { | |
1001 | - 0x07, 0x08, | |
1002 | - 0x17, 0x18, 0x19, | |
1003 | - 0x37, 0x38 | |
1004 | - }; | |
1005 | - static char *specials[] = { | |
1006 | - "Rear Panel", "Drive Bar", | |
1007 | - "Riser", "HDMI", "ATAPI", | |
1008 | - "Mobile-In", "Mobile-Out" | |
1009 | - }; | |
1010 | - int i; | |
1011 | - cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; | |
1012 | - if ((cfg & 0x0f) < 7) | |
1013 | - return bases[cfg & 0x0f]; | |
1014 | - for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { | |
1015 | - if (cfg == specials_idx[i]) | |
1016 | - return specials[i]; | |
1017 | - } | |
1018 | - return "UNKNOWN"; | |
1019 | -} | |
1020 | - | |
1021 | static const char *get_jack_connection(u32 cfg) | |
1022 | { | |
1023 | static char *names[16] = { | |
1024 | @@ -206,13 +170,6 @@ static void print_pin_caps(struct snd_in | |
1025 | int *supports_vref) | |
1026 | { | |
1027 | static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; | |
1028 | - static char *jack_types[16] = { | |
1029 | - "Line Out", "Speaker", "HP Out", "CD", | |
1030 | - "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", | |
1031 | - "Line In", "Aux", "Mic", "Telephony", | |
1032 | - "SPDIF In", "Digitial In", "Reserved", "Other" | |
1033 | - }; | |
1034 | - static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; | |
1035 | unsigned int caps, val; | |
1036 | ||
1037 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | |
1038 | @@ -236,8 +193,6 @@ static void print_pin_caps(struct snd_in | |
1039 | else | |
1040 | snd_iprintf(buffer, " HDMI"); | |
1041 | } | |
1042 | - if (caps & AC_PINCAP_LR_SWAP) | |
1043 | - snd_iprintf(buffer, " R/L"); | |
1044 | if (caps & AC_PINCAP_TRIG_REQ) | |
1045 | snd_iprintf(buffer, " Trigger"); | |
1046 | if (caps & AC_PINCAP_IMP_SENSE) | |
1047 | @@ -276,9 +231,9 @@ static void print_pin_caps(struct snd_in | |
1048 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | |
1049 | snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, | |
1050 | jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], | |
1051 | - jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], | |
1052 | - jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], | |
1053 | - get_jack_location(caps)); | |
1054 | + snd_hda_get_jack_type(caps), | |
1055 | + snd_hda_get_jack_connectivity(caps), | |
1056 | + snd_hda_get_jack_location(caps)); | |
1057 | snd_iprintf(buffer, " Conn = %s, Color = %s\n", | |
1058 | get_jack_connection(caps), | |
1059 | get_jack_color(caps)); | |
1060 | @@ -444,7 +399,10 @@ static void print_conn_list(struct snd_i | |
1061 | { | |
1062 | int c, curr = -1; | |
1063 | ||
1064 | - if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) | |
1065 | + if (conn_len > 1 && | |
1066 | + wid_type != AC_WID_AUD_MIX && | |
1067 | + wid_type != AC_WID_VOL_KNB && | |
1068 | + wid_type != AC_WID_POWER) | |
1069 | curr = snd_hda_codec_read(codec, nid, 0, | |
1070 | AC_VERB_GET_CONNECT_SEL, 0); | |
1071 | snd_iprintf(buffer, " Connection: %d\n", conn_len); | |
1072 | @@ -502,12 +460,13 @@ static void print_gpio(struct snd_info_b | |
1073 | for (i = 0; i < max; ++i) | |
1074 | snd_iprintf(buffer, | |
1075 | " IO[%d]: enable=%d, dir=%d, wake=%d, " | |
1076 | - "sticky=%d, data=%d\n", i, | |
1077 | + "sticky=%d, data=%d, unsol=%d\n", i, | |
1078 | (enable & (1<<i)) ? 1 : 0, | |
1079 | (direction & (1<<i)) ? 1 : 0, | |
1080 | (wake & (1<<i)) ? 1 : 0, | |
1081 | (sticky & (1<<i)) ? 1 : 0, | |
1082 | - (data & (1<<i)) ? 1 : 0); | |
1083 | + (data & (1<<i)) ? 1 : 0, | |
1084 | + (unsol & (1<<i)) ? 1 : 0); | |
1085 | /* FIXME: add GPO and GPI pin information */ | |
1086 | } | |
1087 | ||
1088 | --- a/sound/pci/hda/patch_atihdmi.c | |
1089 | +++ b/sound/pci/hda/patch_atihdmi.c | |
1090 | @@ -188,12 +188,11 @@ static int patch_atihdmi(struct hda_code | |
1091 | * patch entries | |
1092 | */ | |
1093 | struct hda_codec_preset snd_hda_preset_atihdmi[] = { | |
1094 | - { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, | |
1095 | - { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, | |
1096 | - { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, | |
1097 | - { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, | |
1098 | + { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, | |
1099 | + { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, | |
1100 | + { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, | |
1101 | + { .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, | |
1102 | { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi }, | |
1103 | - { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi }, | |
1104 | { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, | |
1105 | {} /* terminator */ | |
1106 | }; | |
1107 | --- /dev/null | |
1108 | +++ b/sound/pci/hda/patch_intelhdmi.c | |
1109 | @@ -0,0 +1,694 @@ | |
1110 | +/* | |
1111 | + * | |
1112 | + * patch_intelhdmi.c - Patch for Intel HDMI codecs | |
1113 | + * | |
1114 | + * Copyright(c) 2008 Intel Corporation. All rights reserved. | |
1115 | + * | |
1116 | + * Authors: | |
1117 | + * Jiang Zhe <zhe.jiang@intel.com> | |
1118 | + * Wu Fengguang <wfg@linux.intel.com> | |
1119 | + * | |
1120 | + * Maintained by: | |
1121 | + * Wu Fengguang <wfg@linux.intel.com> | |
1122 | + * | |
1123 | + * This program is free software; you can redistribute it and/or modify it | |
1124 | + * under the terms of the GNU General Public License as published by the Free | |
1125 | + * Software Foundation; either version 2 of the License, or (at your option) | |
1126 | + * any later version. | |
1127 | + * | |
1128 | + * This program is distributed in the hope that it will be useful, but | |
1129 | + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
1130 | + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
1131 | + * for more details. | |
1132 | + * | |
1133 | + * You should have received a copy of the GNU General Public License | |
1134 | + * along with this program; if not, write to the Free Software Foundation, | |
1135 | + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
1136 | + */ | |
1137 | + | |
1138 | +#include <linux/init.h> | |
1139 | +#include <linux/delay.h> | |
1140 | +#include <linux/slab.h> | |
1141 | +#include <sound/core.h> | |
1142 | +#include "hda_codec.h" | |
1143 | +#include "hda_local.h" | |
1144 | +#include "hda_patch.h" | |
1145 | + | |
1146 | +#define CVT_NID 0x02 /* audio converter */ | |
1147 | +#define PIN_NID 0x03 /* HDMI output pin */ | |
1148 | + | |
1149 | +#define INTEL_HDMI_EVENT_TAG 0x08 | |
1150 | + | |
1151 | +struct intel_hdmi_spec { | |
1152 | + struct hda_multi_out multiout; | |
1153 | + struct hda_pcm pcm_rec; | |
1154 | + struct hdmi_eld sink_eld; | |
1155 | +}; | |
1156 | + | |
1157 | +static struct hda_verb pinout_enable_verb[] = { | |
1158 | + {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | |
1159 | + {} /* terminator */ | |
1160 | +}; | |
1161 | + | |
1162 | +static struct hda_verb unsolicited_response_verb[] = { | |
1163 | + {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | | |
1164 | + INTEL_HDMI_EVENT_TAG}, | |
1165 | + {} | |
1166 | +}; | |
1167 | + | |
1168 | +static struct hda_verb def_chan_map[] = { | |
1169 | + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00}, | |
1170 | + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11}, | |
1171 | + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22}, | |
1172 | + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33}, | |
1173 | + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44}, | |
1174 | + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55}, | |
1175 | + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66}, | |
1176 | + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77}, | |
1177 | + {} | |
1178 | +}; | |
1179 | + | |
1180 | + | |
1181 | +struct hdmi_audio_infoframe { | |
1182 | + u8 type; /* 0x84 */ | |
1183 | + u8 ver; /* 0x01 */ | |
1184 | + u8 len; /* 0x0a */ | |
1185 | + | |
1186 | + u8 checksum; /* PB0 */ | |
1187 | + u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ | |
1188 | + u8 SS01_SF24; | |
1189 | + u8 CXT04; | |
1190 | + u8 CA; | |
1191 | + u8 LFEPBL01_LSV36_DM_INH7; | |
1192 | + u8 reserved[5]; /* PB6 - PB10 */ | |
1193 | +}; | |
1194 | + | |
1195 | +/* | |
1196 | + * CEA speaker placement: | |
1197 | + * | |
1198 | + * FLH FCH FRH | |
1199 | + * FLW FL FLC FC FRC FR FRW | |
1200 | + * | |
1201 | + * LFE | |
1202 | + * TC | |
1203 | + * | |
1204 | + * RL RLC RC RRC RR | |
1205 | + * | |
1206 | + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to | |
1207 | + * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. | |
1208 | + */ | |
1209 | +enum cea_speaker_placement { | |
1210 | + FL = (1 << 0), /* Front Left */ | |
1211 | + FC = (1 << 1), /* Front Center */ | |
1212 | + FR = (1 << 2), /* Front Right */ | |
1213 | + FLC = (1 << 3), /* Front Left Center */ | |
1214 | + FRC = (1 << 4), /* Front Right Center */ | |
1215 | + RL = (1 << 5), /* Rear Left */ | |
1216 | + RC = (1 << 6), /* Rear Center */ | |
1217 | + RR = (1 << 7), /* Rear Right */ | |
1218 | + RLC = (1 << 8), /* Rear Left Center */ | |
1219 | + RRC = (1 << 9), /* Rear Right Center */ | |
1220 | + LFE = (1 << 10), /* Low Frequency Effect */ | |
1221 | + FLW = (1 << 11), /* Front Left Wide */ | |
1222 | + FRW = (1 << 12), /* Front Right Wide */ | |
1223 | + FLH = (1 << 13), /* Front Left High */ | |
1224 | + FCH = (1 << 14), /* Front Center High */ | |
1225 | + FRH = (1 << 15), /* Front Right High */ | |
1226 | + TC = (1 << 16), /* Top Center */ | |
1227 | +}; | |
1228 | + | |
1229 | +/* | |
1230 | + * ELD SA bits in the CEA Speaker Allocation data block | |
1231 | + */ | |
1232 | +static int eld_speaker_allocation_bits[] = { | |
1233 | + [0] = FL | FR, | |
1234 | + [1] = LFE, | |
1235 | + [2] = FC, | |
1236 | + [3] = RL | RR, | |
1237 | + [4] = RC, | |
1238 | + [5] = FLC | FRC, | |
1239 | + [6] = RLC | RRC, | |
1240 | + /* the following are not defined in ELD yet */ | |
1241 | + [7] = FLW | FRW, | |
1242 | + [8] = FLH | FRH, | |
1243 | + [9] = TC, | |
1244 | + [10] = FCH, | |
1245 | +}; | |
1246 | + | |
1247 | +struct cea_channel_speaker_allocation { | |
1248 | + int ca_index; | |
1249 | + int speakers[8]; | |
1250 | + | |
1251 | + /* derived values, just for convenience */ | |
1252 | + int channels; | |
1253 | + int spk_mask; | |
1254 | +}; | |
1255 | + | |
1256 | +/* | |
1257 | + * This is an ordered list! | |
1258 | + * | |
1259 | + * The preceding ones have better chances to be selected by | |
1260 | + * hdmi_setup_channel_allocation(). | |
1261 | + */ | |
1262 | +static struct cea_channel_speaker_allocation channel_allocations[] = { | |
1263 | +/* channel: 8 7 6 5 4 3 2 1 */ | |
1264 | +{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, | |
1265 | + /* 2.1 */ | |
1266 | +{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, | |
1267 | + /* Dolby Surround */ | |
1268 | +{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, | |
1269 | +{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, | |
1270 | +{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, | |
1271 | +{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, | |
1272 | +{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, | |
1273 | +{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, | |
1274 | +{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, | |
1275 | +{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, | |
1276 | +{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, | |
1277 | + /* 5.1 */ | |
1278 | +{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, | |
1279 | +{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, | |
1280 | +{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, | |
1281 | +{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, | |
1282 | + /* 6.1 */ | |
1283 | +{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, | |
1284 | +{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, | |
1285 | +{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, | |
1286 | +{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, | |
1287 | + /* 7.1 */ | |
1288 | +{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, | |
1289 | +{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, | |
1290 | +{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, | |
1291 | +{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, | |
1292 | +{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, | |
1293 | +{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, | |
1294 | +{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, | |
1295 | +{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, | |
1296 | +{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, | |
1297 | +{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, | |
1298 | +{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, | |
1299 | +{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, | |
1300 | +{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, | |
1301 | +{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, | |
1302 | +{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, | |
1303 | +{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, | |
1304 | +{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, | |
1305 | +{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, | |
1306 | +{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, | |
1307 | +{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, | |
1308 | +{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, | |
1309 | +{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, | |
1310 | +{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, | |
1311 | +{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, | |
1312 | +{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, | |
1313 | +{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, | |
1314 | +{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, | |
1315 | +{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, | |
1316 | +{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, | |
1317 | +{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, | |
1318 | +{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, | |
1319 | +}; | |
1320 | + | |
1321 | +/* | |
1322 | + * HDMI routines | |
1323 | + */ | |
1324 | + | |
1325 | +#ifdef BE_PARANOID | |
1326 | +static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, | |
1327 | + int *packet_index, int *byte_index) | |
1328 | +{ | |
1329 | + int val; | |
1330 | + | |
1331 | + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); | |
1332 | + | |
1333 | + *packet_index = val >> 5; | |
1334 | + *byte_index = val & 0x1f; | |
1335 | +} | |
1336 | +#endif | |
1337 | + | |
1338 | +static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, | |
1339 | + int packet_index, int byte_index) | |
1340 | +{ | |
1341 | + int val; | |
1342 | + | |
1343 | + val = (packet_index << 5) | (byte_index & 0x1f); | |
1344 | + | |
1345 | + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); | |
1346 | +} | |
1347 | + | |
1348 | +static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, | |
1349 | + unsigned char val) | |
1350 | +{ | |
1351 | + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); | |
1352 | +} | |
1353 | + | |
1354 | +static void hdmi_enable_output(struct hda_codec *codec) | |
1355 | +{ | |
1356 | + /* Unmute */ | |
1357 | + if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) | |
1358 | + snd_hda_codec_write(codec, PIN_NID, 0, | |
1359 | + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | |
1360 | + /* Enable pin out */ | |
1361 | + snd_hda_sequence_write(codec, pinout_enable_verb); | |
1362 | +} | |
1363 | + | |
1364 | +/* | |
1365 | + * Enable Audio InfoFrame Transmission | |
1366 | + */ | |
1367 | +static void hdmi_start_infoframe_trans(struct hda_codec *codec) | |
1368 | +{ | |
1369 | + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); | |
1370 | + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, | |
1371 | + AC_DIPXMIT_BEST); | |
1372 | +} | |
1373 | + | |
1374 | +/* | |
1375 | + * Disable Audio InfoFrame Transmission | |
1376 | + */ | |
1377 | +static void hdmi_stop_infoframe_trans(struct hda_codec *codec) | |
1378 | +{ | |
1379 | + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); | |
1380 | + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, | |
1381 | + AC_DIPXMIT_DISABLE); | |
1382 | +} | |
1383 | + | |
1384 | +static int hdmi_get_channel_count(struct hda_codec *codec) | |
1385 | +{ | |
1386 | + return 1 + snd_hda_codec_read(codec, CVT_NID, 0, | |
1387 | + AC_VERB_GET_CVT_CHAN_COUNT, 0); | |
1388 | +} | |
1389 | + | |
1390 | +static void hdmi_set_channel_count(struct hda_codec *codec, int chs) | |
1391 | +{ | |
1392 | + snd_hda_codec_write(codec, CVT_NID, 0, | |
1393 | + AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); | |
1394 | + | |
1395 | + if (chs != hdmi_get_channel_count(codec)) | |
1396 | + snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", | |
1397 | + chs, hdmi_get_channel_count(codec)); | |
1398 | +} | |
1399 | + | |
1400 | +static void hdmi_debug_channel_mapping(struct hda_codec *codec) | |
1401 | +{ | |
1402 | +#ifdef CONFIG_SND_DEBUG_VERBOSE | |
1403 | + int i; | |
1404 | + int slot; | |
1405 | + | |
1406 | + for (i = 0; i < 8; i++) { | |
1407 | + slot = snd_hda_codec_read(codec, CVT_NID, 0, | |
1408 | + AC_VERB_GET_HDMI_CHAN_SLOT, i); | |
1409 | + printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", | |
1410 | + slot >> 4, slot & 0x7); | |
1411 | + } | |
1412 | +#endif | |
1413 | +} | |
1414 | + | |
1415 | +static void hdmi_parse_eld(struct hda_codec *codec) | |
1416 | +{ | |
1417 | + struct intel_hdmi_spec *spec = codec->spec; | |
1418 | + struct hdmi_eld *eld = &spec->sink_eld; | |
1419 | + | |
1420 | + if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) | |
1421 | + snd_hdmi_show_eld(eld); | |
1422 | +} | |
1423 | + | |
1424 | + | |
1425 | +/* | |
1426 | + * Audio InfoFrame routines | |
1427 | + */ | |
1428 | + | |
1429 | +static void hdmi_debug_dip_size(struct hda_codec *codec) | |
1430 | +{ | |
1431 | +#ifdef CONFIG_SND_DEBUG_VERBOSE | |
1432 | + int i; | |
1433 | + int size; | |
1434 | + | |
1435 | + size = snd_hdmi_get_eld_size(codec, PIN_NID); | |
1436 | + printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); | |
1437 | + | |
1438 | + for (i = 0; i < 8; i++) { | |
1439 | + size = snd_hda_codec_read(codec, PIN_NID, 0, | |
1440 | + AC_VERB_GET_HDMI_DIP_SIZE, i); | |
1441 | + printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); | |
1442 | + } | |
1443 | +#endif | |
1444 | +} | |
1445 | + | |
1446 | +static void hdmi_clear_dip_buffers(struct hda_codec *codec) | |
1447 | +{ | |
1448 | +#ifdef BE_PARANOID | |
1449 | + int i, j; | |
1450 | + int size; | |
1451 | + int pi, bi; | |
1452 | + for (i = 0; i < 8; i++) { | |
1453 | + size = snd_hda_codec_read(codec, PIN_NID, 0, | |
1454 | + AC_VERB_GET_HDMI_DIP_SIZE, i); | |
1455 | + if (size == 0) | |
1456 | + continue; | |
1457 | + | |
1458 | + hdmi_set_dip_index(codec, PIN_NID, i, 0x0); | |
1459 | + for (j = 1; j < 1000; j++) { | |
1460 | + hdmi_write_dip_byte(codec, PIN_NID, 0x0); | |
1461 | + hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); | |
1462 | + if (pi != i) | |
1463 | + snd_printd(KERN_INFO "dip index %d: %d != %d\n", | |
1464 | + bi, pi, i); | |
1465 | + if (bi == 0) /* byte index wrapped around */ | |
1466 | + break; | |
1467 | + } | |
1468 | + snd_printd(KERN_INFO | |
1469 | + "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", | |
1470 | + i, size, j); | |
1471 | + } | |
1472 | +#endif | |
1473 | +} | |
1474 | + | |
1475 | +static void hdmi_fill_audio_infoframe(struct hda_codec *codec, | |
1476 | + struct hdmi_audio_infoframe *ai) | |
1477 | +{ | |
1478 | + u8 *params = (u8 *)ai; | |
1479 | + u8 sum = 0; | |
1480 | + int i; | |
1481 | + | |
1482 | + hdmi_debug_dip_size(codec); | |
1483 | + hdmi_clear_dip_buffers(codec); /* be paranoid */ | |
1484 | + | |
1485 | + for (i = 0; i < sizeof(ai); i++) | |
1486 | + sum += params[i]; | |
1487 | + ai->checksum = - sum; | |
1488 | + | |
1489 | + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); | |
1490 | + for (i = 0; i < sizeof(ai); i++) | |
1491 | + hdmi_write_dip_byte(codec, PIN_NID, params[i]); | |
1492 | +} | |
1493 | + | |
1494 | +/* | |
1495 | + * Compute derived values in channel_allocations[]. | |
1496 | + */ | |
1497 | +static void init_channel_allocations(void) | |
1498 | +{ | |
1499 | + int i, j; | |
1500 | + struct cea_channel_speaker_allocation *p; | |
1501 | + | |
1502 | + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { | |
1503 | + p = channel_allocations + i; | |
1504 | + p->channels = 0; | |
1505 | + p->spk_mask = 0; | |
1506 | + for (j = 0; j < ARRAY_SIZE(p->speakers); j++) | |
1507 | + if (p->speakers[j]) { | |
1508 | + p->channels++; | |
1509 | + p->spk_mask |= p->speakers[j]; | |
1510 | + } | |
1511 | + } | |
1512 | +} | |
1513 | + | |
1514 | +/* | |
1515 | + * The transformation takes two steps: | |
1516 | + * | |
1517 | + * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask | |
1518 | + * spk_mask => (channel_allocations[]) => ai->CA | |
1519 | + * | |
1520 | + * TODO: it could select the wrong CA from multiple candidates. | |
1521 | +*/ | |
1522 | +static int hdmi_setup_channel_allocation(struct hda_codec *codec, | |
1523 | + struct hdmi_audio_infoframe *ai) | |
1524 | +{ | |
1525 | + struct intel_hdmi_spec *spec = codec->spec; | |
1526 | + struct hdmi_eld *eld = &spec->sink_eld; | |
1527 | + int i; | |
1528 | + int spk_mask = 0; | |
1529 | + int channels = 1 + (ai->CC02_CT47 & 0x7); | |
1530 | + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; | |
1531 | + | |
1532 | + /* | |
1533 | + * CA defaults to 0 for basic stereo audio | |
1534 | + */ | |
1535 | + if (channels <= 2) | |
1536 | + return 0; | |
1537 | + | |
1538 | + /* | |
1539 | + * HDMI sink's ELD info cannot always be retrieved for now, e.g. | |
1540 | + * in console or for audio devices. Assume the highest speakers | |
1541 | + * configuration, to _not_ prohibit multi-channel audio playback. | |
1542 | + */ | |
1543 | + if (!eld->spk_alloc) | |
1544 | + eld->spk_alloc = 0xffff; | |
1545 | + | |
1546 | + /* | |
1547 | + * expand ELD's speaker allocation mask | |
1548 | + * | |
1549 | + * ELD tells the speaker mask in a compact(paired) form, | |
1550 | + * expand ELD's notions to match the ones used by Audio InfoFrame. | |
1551 | + */ | |
1552 | + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { | |
1553 | + if (eld->spk_alloc & (1 << i)) | |
1554 | + spk_mask |= eld_speaker_allocation_bits[i]; | |
1555 | + } | |
1556 | + | |
1557 | + /* search for the first working match in the CA table */ | |
1558 | + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { | |
1559 | + if (channels == channel_allocations[i].channels && | |
1560 | + (spk_mask & channel_allocations[i].spk_mask) == | |
1561 | + channel_allocations[i].spk_mask) { | |
1562 | + ai->CA = channel_allocations[i].ca_index; | |
1563 | + break; | |
1564 | + } | |
1565 | + } | |
1566 | + | |
1567 | + snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); | |
1568 | + snd_printdd(KERN_INFO | |
1569 | + "HDMI: select CA 0x%x for %d-channel allocation: %s\n", | |
1570 | + ai->CA, channels, buf); | |
1571 | + | |
1572 | + return ai->CA; | |
1573 | +} | |
1574 | + | |
1575 | +static void hdmi_setup_channel_mapping(struct hda_codec *codec, | |
1576 | + struct hdmi_audio_infoframe *ai) | |
1577 | +{ | |
1578 | + if (!ai->CA) | |
1579 | + return; | |
1580 | + | |
1581 | + /* | |
1582 | + * TODO: adjust channel mapping if necessary | |
1583 | + * ALSA sequence is front/surr/clfe/side? | |
1584 | + */ | |
1585 | + | |
1586 | + snd_hda_sequence_write(codec, def_chan_map); | |
1587 | + hdmi_debug_channel_mapping(codec); | |
1588 | +} | |
1589 | + | |
1590 | + | |
1591 | +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | |
1592 | + struct snd_pcm_substream *substream) | |
1593 | +{ | |
1594 | + struct hdmi_audio_infoframe ai = { | |
1595 | + .type = 0x84, | |
1596 | + .ver = 0x01, | |
1597 | + .len = 0x0a, | |
1598 | + .CC02_CT47 = substream->runtime->channels - 1, | |
1599 | + }; | |
1600 | + | |
1601 | + hdmi_setup_channel_allocation(codec, &ai); | |
1602 | + hdmi_setup_channel_mapping(codec, &ai); | |
1603 | + | |
1604 | + hdmi_fill_audio_infoframe(codec, &ai); | |
1605 | + hdmi_start_infoframe_trans(codec); | |
1606 | +} | |
1607 | + | |
1608 | + | |
1609 | +/* | |
1610 | + * Unsolicited events | |
1611 | + */ | |
1612 | + | |
1613 | +static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | |
1614 | +{ | |
1615 | + int pind = !!(res & AC_UNSOL_RES_PD); | |
1616 | + int eldv = !!(res & AC_UNSOL_RES_ELDV); | |
1617 | + | |
1618 | + printk(KERN_INFO | |
1619 | + "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", | |
1620 | + pind, eldv); | |
1621 | + | |
1622 | + if (pind && eldv) { | |
1623 | + hdmi_parse_eld(codec); | |
1624 | + /* TODO: do real things about ELD */ | |
1625 | + } | |
1626 | +} | |
1627 | + | |
1628 | +static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | |
1629 | +{ | |
1630 | + int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | |
1631 | + int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); | |
1632 | + int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); | |
1633 | + | |
1634 | + printk(KERN_INFO | |
1635 | + "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", | |
1636 | + subtag, | |
1637 | + cp_state, | |
1638 | + cp_ready); | |
1639 | + | |
1640 | + /* TODO */ | |
1641 | + if (cp_state) | |
1642 | + ; | |
1643 | + if (cp_ready) | |
1644 | + ; | |
1645 | +} | |
1646 | + | |
1647 | + | |
1648 | +static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) | |
1649 | +{ | |
1650 | + int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | |
1651 | + int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | |
1652 | + | |
1653 | + if (tag != INTEL_HDMI_EVENT_TAG) { | |
1654 | + snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); | |
1655 | + return; | |
1656 | + } | |
1657 | + | |
1658 | + if (subtag == 0) | |
1659 | + hdmi_intrinsic_event(codec, res); | |
1660 | + else | |
1661 | + hdmi_non_intrinsic_event(codec, res); | |
1662 | +} | |
1663 | + | |
1664 | +/* | |
1665 | + * Callbacks | |
1666 | + */ | |
1667 | + | |
1668 | +static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, | |
1669 | + struct hda_codec *codec, | |
1670 | + struct snd_pcm_substream *substream) | |
1671 | +{ | |
1672 | + struct intel_hdmi_spec *spec = codec->spec; | |
1673 | + | |
1674 | + return snd_hda_multi_out_dig_open(codec, &spec->multiout); | |
1675 | +} | |
1676 | + | |
1677 | +static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, | |
1678 | + struct hda_codec *codec, | |
1679 | + struct snd_pcm_substream *substream) | |
1680 | +{ | |
1681 | + struct intel_hdmi_spec *spec = codec->spec; | |
1682 | + | |
1683 | + hdmi_stop_infoframe_trans(codec); | |
1684 | + | |
1685 | + return snd_hda_multi_out_dig_close(codec, &spec->multiout); | |
1686 | +} | |
1687 | + | |
1688 | +static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |
1689 | + struct hda_codec *codec, | |
1690 | + unsigned int stream_tag, | |
1691 | + unsigned int format, | |
1692 | + struct snd_pcm_substream *substream) | |
1693 | +{ | |
1694 | + struct intel_hdmi_spec *spec = codec->spec; | |
1695 | + | |
1696 | + snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | |
1697 | + format, substream); | |
1698 | + | |
1699 | + hdmi_set_channel_count(codec, substream->runtime->channels); | |
1700 | + | |
1701 | + hdmi_setup_audio_infoframe(codec, substream); | |
1702 | + | |
1703 | + return 0; | |
1704 | +} | |
1705 | + | |
1706 | +static struct hda_pcm_stream intel_hdmi_pcm_playback = { | |
1707 | + .substreams = 1, | |
1708 | + .channels_min = 2, | |
1709 | + .channels_max = 8, | |
1710 | + .nid = CVT_NID, /* NID to query formats and rates and setup streams */ | |
1711 | + .ops = { | |
1712 | + .open = intel_hdmi_playback_pcm_open, | |
1713 | + .close = intel_hdmi_playback_pcm_close, | |
1714 | + .prepare = intel_hdmi_playback_pcm_prepare | |
1715 | + }, | |
1716 | +}; | |
1717 | + | |
1718 | +static int intel_hdmi_build_pcms(struct hda_codec *codec) | |
1719 | +{ | |
1720 | + struct intel_hdmi_spec *spec = codec->spec; | |
1721 | + struct hda_pcm *info = &spec->pcm_rec; | |
1722 | + | |
1723 | + codec->num_pcms = 1; | |
1724 | + codec->pcm_info = info; | |
1725 | + | |
1726 | + info->name = "INTEL HDMI"; | |
1727 | + info->pcm_type = HDA_PCM_TYPE_HDMI; | |
1728 | + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; | |
1729 | + | |
1730 | + return 0; | |
1731 | +} | |
1732 | + | |
1733 | +static int intel_hdmi_build_controls(struct hda_codec *codec) | |
1734 | +{ | |
1735 | + struct intel_hdmi_spec *spec = codec->spec; | |
1736 | + int err; | |
1737 | + | |
1738 | + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | |
1739 | + if (err < 0) | |
1740 | + return err; | |
1741 | + | |
1742 | + return 0; | |
1743 | +} | |
1744 | + | |
1745 | +static int intel_hdmi_init(struct hda_codec *codec) | |
1746 | +{ | |
1747 | + hdmi_enable_output(codec); | |
1748 | + | |
1749 | + snd_hda_sequence_write(codec, unsolicited_response_verb); | |
1750 | + | |
1751 | + return 0; | |
1752 | +} | |
1753 | + | |
1754 | +static void intel_hdmi_free(struct hda_codec *codec) | |
1755 | +{ | |
1756 | + struct intel_hdmi_spec *spec = codec->spec; | |
1757 | + | |
1758 | + snd_hda_eld_proc_free(codec, &spec->sink_eld); | |
1759 | + kfree(spec); | |
1760 | +} | |
1761 | + | |
1762 | +static struct hda_codec_ops intel_hdmi_patch_ops = { | |
1763 | + .init = intel_hdmi_init, | |
1764 | + .free = intel_hdmi_free, | |
1765 | + .build_pcms = intel_hdmi_build_pcms, | |
1766 | + .build_controls = intel_hdmi_build_controls, | |
1767 | + .unsol_event = intel_hdmi_unsol_event, | |
1768 | +}; | |
1769 | + | |
1770 | +static int patch_intel_hdmi(struct hda_codec *codec) | |
1771 | +{ | |
1772 | + struct intel_hdmi_spec *spec; | |
1773 | + | |
1774 | + spec = kzalloc(sizeof(*spec), GFP_KERNEL); | |
1775 | + if (spec == NULL) | |
1776 | + return -ENOMEM; | |
1777 | + | |
1778 | + spec->multiout.num_dacs = 0; /* no analog */ | |
1779 | + spec->multiout.max_channels = 8; | |
1780 | + spec->multiout.dig_out_nid = CVT_NID; | |
1781 | + | |
1782 | + codec->spec = spec; | |
1783 | + codec->patch_ops = intel_hdmi_patch_ops; | |
1784 | + | |
1785 | + snd_hda_eld_proc_new(codec, &spec->sink_eld); | |
1786 | + | |
1787 | + init_channel_allocations(); | |
1788 | + | |
1789 | + return 0; | |
1790 | +} | |
1791 | + | |
1792 | +/* | |
1793 | + * patch entries | |
1794 | + */ | |
1795 | +struct hda_codec_preset snd_hda_preset_intelhdmi[] = { | |
1796 | + { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, | |
1797 | + { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, | |
1798 | + { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, | |
1799 | + { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, | |
1800 | + { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, | |
1801 | + { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, | |
1802 | + {} /* terminator */ | |
1803 | +}; | |
1804 | --- a/sound/pci/hda/patch_nvhdmi.c | |
1805 | +++ b/sound/pci/hda/patch_nvhdmi.c | |
1806 | @@ -159,7 +159,10 @@ static int patch_nvhdmi(struct hda_codec | |
1807 | * patch entries | |
1808 | */ | |
1809 | struct hda_codec_preset snd_hda_preset_nvhdmi[] = { | |
1810 | - { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, | |
1811 | - { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, | |
1812 | + { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, | |
1813 | + { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, | |
1814 | + { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, | |
1815 | + { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, | |
1816 | + { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi }, | |
1817 | {} /* terminator */ | |
1818 | }; |