diff options
author | Wu, Fengguang <fengguang.wu@intel.com> | 2008-11-04 22:16:56 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-11-05 01:54:03 -0500 |
commit | 91504877c50a792412e2043a1c2099f054d7254a (patch) | |
tree | 5f49fbc695424851bc0852091aef70d3d178f0eb /sound/pci | |
parent | bfc5c26fb692fa7a196108c3b23d9c747d105c00 (diff) |
ALSA: hda - Intel HDMI audio support
Add support for Intel G45 integrated HDMI audio codecs.
This initial release supports:
- 2 channel stereo sound output
- report monitor's ELD information
Signed-off-by: Wu Fengguang <wfg@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/Kconfig | 8 | ||||
-rw-r--r-- | sound/pci/hda/Makefile | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 3 | ||||
-rw-r--r-- | sound/pci/hda/hda_patch.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_intelhdmi.c | 926 |
5 files changed, 940 insertions, 0 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7e408908b755..21e9327a0ef4 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -574,6 +574,14 @@ config SND_HDA_CODEC_NVHDMI | |||
574 | Say Y here to include NVIDIA HDMI HD-audio codec support in | 574 | Say Y here to include NVIDIA HDMI HD-audio codec support in |
575 | snd-hda-intel driver, such as NVIDIA MCP78 HDMI. | 575 | snd-hda-intel driver, such as NVIDIA MCP78 HDMI. |
576 | 576 | ||
577 | config SND_HDA_CODEC_INTELHDMI | ||
578 | bool "Build INTEL HDMI HD-audio codec support" | ||
579 | depends on SND_HDA_INTEL | ||
580 | default y | ||
581 | help | ||
582 | Say Y here to include INTEL HDMI HD-audio codec support in | ||
583 | snd-hda-intel driver, such as Eaglelake integrated HDMI. | ||
584 | |||
577 | config SND_HDA_CODEC_CONEXANT | 585 | config SND_HDA_CODEC_CONEXANT |
578 | bool "Build Conexant HD-audio codec support" | 586 | bool "Build Conexant HD-audio codec support" |
579 | depends on SND_HDA_INTEL | 587 | depends on SND_HDA_INTEL |
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 1980c6d207e7..6fb5add1e39a 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
@@ -16,5 +16,6 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o | |||
16 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o | 16 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o |
17 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o | 17 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o |
18 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o | 18 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o |
19 | snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o | ||
19 | 20 | ||
20 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o | 21 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3e7cda9c3de5..45695d608c76 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -98,6 +98,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = { | |||
98 | #ifdef CONFIG_SND_HDA_CODEC_NVHDMI | 98 | #ifdef CONFIG_SND_HDA_CODEC_NVHDMI |
99 | snd_hda_preset_nvhdmi, | 99 | snd_hda_preset_nvhdmi, |
100 | #endif | 100 | #endif |
101 | #ifdef CONFIG_SND_HDA_CODEC_INTELHDMI | ||
102 | snd_hda_preset_intelhdmi, | ||
103 | #endif | ||
101 | NULL | 104 | NULL |
102 | }; | 105 | }; |
103 | 106 | ||
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index dfbcfa88da44..38212c1020a6 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h | |||
@@ -20,3 +20,5 @@ extern struct hda_codec_preset snd_hda_preset_conexant[]; | |||
20 | extern struct hda_codec_preset snd_hda_preset_via[]; | 20 | extern struct hda_codec_preset snd_hda_preset_via[]; |
21 | /* NVIDIA HDMI codecs */ | 21 | /* NVIDIA HDMI codecs */ |
22 | extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; | 22 | extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; |
23 | /* INTEL HDMI codecs */ | ||
24 | extern struct hda_codec_preset snd_hda_preset_intelhdmi[]; | ||
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c new file mode 100644 index 000000000000..8059102dd862 --- /dev/null +++ b/sound/pci/hda/patch_intelhdmi.c | |||
@@ -0,0 +1,926 @@ | |||
1 | /* | ||
2 | * | ||
3 | * patch_intelhdmi.c - Patch for Intel HDMI codecs | ||
4 | * | ||
5 | * Copyright(c) 2008 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * Authors: | ||
8 | * Jiang Zhe <zhe.jiang@intel.com> | ||
9 | * Wu Fengguang <wfg@linux.intel.com> | ||
10 | * | ||
11 | * Maintained by: | ||
12 | * Wu Fengguang <wfg@linux.intel.com> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify it | ||
15 | * under the terms of the GNU General Public License as published by the Free | ||
16 | * Software Foundation; either version 2 of the License, or (at your option) | ||
17 | * any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
21 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
22 | * for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software Foundation, | ||
26 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
27 | */ | ||
28 | |||
29 | #include <linux/init.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <sound/core.h> | ||
33 | #include <asm/unaligned.h> | ||
34 | #include "hda_codec.h" | ||
35 | #include "hda_local.h" | ||
36 | #include "hda_patch.h" | ||
37 | |||
38 | #define CVT_NID 0x02 /* audio converter */ | ||
39 | #define PIN_NID 0x03 /* HDMI output pin */ | ||
40 | |||
41 | #define INTEL_HDMI_EVENT_TAG 0x08 | ||
42 | |||
43 | /* | ||
44 | * CEA Short Audio Descriptor data | ||
45 | */ | ||
46 | struct cea_sad { | ||
47 | int channels; | ||
48 | int format; /* (format == 0) indicates invalid SAD */ | ||
49 | int rates; | ||
50 | int sample_bits; /* for LPCM */ | ||
51 | int max_bitrate; /* for AC3...ATRAC */ | ||
52 | int profile; /* for WMAPRO */ | ||
53 | }; | ||
54 | |||
55 | #define ELD_FIXED_BYTES 20 | ||
56 | #define ELD_MAX_MNL 16 | ||
57 | #define ELD_MAX_SAD 16 | ||
58 | |||
59 | /* | ||
60 | * ELD: EDID Like Data | ||
61 | */ | ||
62 | struct sink_eld { | ||
63 | int eld_size; | ||
64 | int baseline_len; | ||
65 | int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ | ||
66 | int cea_edid_ver; | ||
67 | char monitor_name[ELD_MAX_MNL + 1]; | ||
68 | int manufacture_id; | ||
69 | int product_id; | ||
70 | u64 port_id; | ||
71 | int support_hdcp; | ||
72 | int support_ai; | ||
73 | int conn_type; | ||
74 | int aud_synch_delay; | ||
75 | int spk_alloc; | ||
76 | int sad_count; | ||
77 | struct cea_sad sad[ELD_MAX_SAD]; | ||
78 | }; | ||
79 | |||
80 | struct intel_hdmi_spec { | ||
81 | struct hda_multi_out multiout; | ||
82 | struct hda_pcm pcm_rec; | ||
83 | struct sink_eld sink; | ||
84 | }; | ||
85 | |||
86 | static struct hda_verb pinout_enable_verb[] = { | ||
87 | {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
88 | {} /* terminator */ | ||
89 | }; | ||
90 | |||
91 | static struct hda_verb pinout_disable_verb[] = { | ||
92 | {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, | ||
93 | {} | ||
94 | }; | ||
95 | |||
96 | static struct hda_verb unsolicited_response_verb[] = { | ||
97 | {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | | ||
98 | INTEL_HDMI_EVENT_TAG}, | ||
99 | {} | ||
100 | }; | ||
101 | |||
102 | static struct hda_verb def_chan_map[] = { | ||
103 | {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00}, | ||
104 | {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11}, | ||
105 | {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22}, | ||
106 | {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33}, | ||
107 | {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44}, | ||
108 | {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55}, | ||
109 | {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66}, | ||
110 | {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77}, | ||
111 | {} | ||
112 | }; | ||
113 | |||
114 | |||
115 | struct hdmi_audio_infoframe { | ||
116 | u8 type; /* 0x84 */ | ||
117 | u8 ver; /* 0x01 */ | ||
118 | u8 len; /* 0x0a */ | ||
119 | |||
120 | u8 checksum; /* PB0 */ | ||
121 | u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ | ||
122 | u8 SS01_SF24; | ||
123 | u8 CXT04; | ||
124 | u8 CA; | ||
125 | u8 LFEPBL01_LSV36_DM_INH7; | ||
126 | u8 reserved[5]; /* PB6 - PB10 */ | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * SS1:SS0 index => sample size | ||
131 | */ | ||
132 | static int cea_sample_sizes[4] = { | ||
133 | 0, /* 0: Refer to Stream Header */ | ||
134 | AC_SUPPCM_BITS_16, /* 1: 16 bits */ | ||
135 | AC_SUPPCM_BITS_20, /* 2: 20 bits */ | ||
136 | AC_SUPPCM_BITS_24, /* 3: 24 bits */ | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * SF2:SF1:SF0 index => sampling frequency | ||
141 | */ | ||
142 | static int cea_sampling_frequencies[8] = { | ||
143 | 0, /* 0: Refer to Stream Header */ | ||
144 | SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ | ||
145 | SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ | ||
146 | SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ | ||
147 | SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ | ||
148 | SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ | ||
149 | SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ | ||
150 | SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ | ||
151 | }; | ||
152 | |||
153 | enum eld_versions { | ||
154 | ELD_VER_CEA_861D = 2, | ||
155 | ELD_VER_PARTIAL = 31, | ||
156 | }; | ||
157 | |||
158 | static char *eld_versoin_names[32] = { | ||
159 | "0-reserved", | ||
160 | "1-reserved", | ||
161 | "CEA-861D or below", | ||
162 | "3-reserved", | ||
163 | [4 ... 30] = "reserved", | ||
164 | [31] = "partial" | ||
165 | }; | ||
166 | |||
167 | enum cea_edid_versions { | ||
168 | CEA_EDID_VER_NONE = 0, | ||
169 | CEA_EDID_VER_CEA861 = 1, | ||
170 | CEA_EDID_VER_CEA861A = 2, | ||
171 | CEA_EDID_VER_CEA861BCD = 3, | ||
172 | CEA_EDID_VER_RESERVED = 4, | ||
173 | }; | ||
174 | |||
175 | static char *cea_edid_version_names[8] = { | ||
176 | "no CEA EDID Timing Extension block present", | ||
177 | "CEA-861", | ||
178 | "CEA-861-A", | ||
179 | "CEA-861-B, C or D", | ||
180 | "4-reserved", | ||
181 | [5 ... 7] = "reserved" | ||
182 | }; | ||
183 | |||
184 | /* | ||
185 | * CEA Speaker Allocation data block bits | ||
186 | */ | ||
187 | #define CEA_SA_FLR (0 << 0) | ||
188 | #define CEA_SA_LFE (1 << 1) | ||
189 | #define CEA_SA_FC (1 << 2) | ||
190 | #define CEA_SA_RLR (1 << 3) | ||
191 | #define CEA_SA_RC (1 << 4) | ||
192 | #define CEA_SA_FLRC (1 << 5) | ||
193 | #define CEA_SA_RLRC (1 << 6) | ||
194 | /* the following are not defined in ELD yet */ | ||
195 | #define CEA_SA_FLRW (1 << 7) | ||
196 | #define CEA_SA_FLRH (1 << 8) | ||
197 | #define CEA_SA_TC (1 << 9) | ||
198 | #define CEA_SA_FCH (1 << 10) | ||
199 | |||
200 | static char *cea_speaker_allocation_names[] = { | ||
201 | /* 0 */ "FL/FR", | ||
202 | /* 1 */ "LFE", | ||
203 | /* 2 */ "FC", | ||
204 | /* 3 */ "RL/RR", | ||
205 | /* 4 */ "RC", | ||
206 | /* 5 */ "FLC/FRC", | ||
207 | /* 6 */ "RLC/RRC", | ||
208 | /* 7 */ "FLW/FRW", | ||
209 | /* 8 */ "FLH/FRH", | ||
210 | /* 9 */ "TC", | ||
211 | /* 10 */ "FCH", | ||
212 | }; | ||
213 | |||
214 | static char *eld_connection_type_names[4] = { | ||
215 | "HDMI", | ||
216 | "Display Port", | ||
217 | "2-reserved", | ||
218 | "3-reserved" | ||
219 | }; | ||
220 | |||
221 | enum cea_audio_coding_types { | ||
222 | AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, | ||
223 | AUDIO_CODING_TYPE_LPCM = 1, | ||
224 | AUDIO_CODING_TYPE_AC3 = 2, | ||
225 | AUDIO_CODING_TYPE_MPEG1 = 3, | ||
226 | AUDIO_CODING_TYPE_MP3 = 4, | ||
227 | AUDIO_CODING_TYPE_MPEG2 = 5, | ||
228 | AUDIO_CODING_TYPE_AACLC = 6, | ||
229 | AUDIO_CODING_TYPE_DTS = 7, | ||
230 | AUDIO_CODING_TYPE_ATRAC = 8, | ||
231 | AUDIO_CODING_TYPE_SACD = 9, | ||
232 | AUDIO_CODING_TYPE_EAC3 = 10, | ||
233 | AUDIO_CODING_TYPE_DTS_HD = 11, | ||
234 | AUDIO_CODING_TYPE_MLP = 12, | ||
235 | AUDIO_CODING_TYPE_DST = 13, | ||
236 | AUDIO_CODING_TYPE_WMAPRO = 14, | ||
237 | AUDIO_CODING_TYPE_REF_CXT = 15, | ||
238 | /* also include valid xtypes below */ | ||
239 | AUDIO_CODING_TYPE_HE_AAC = 15, | ||
240 | AUDIO_CODING_TYPE_HE_AAC2 = 16, | ||
241 | AUDIO_CODING_TYPE_MPEG_SURROUND = 17, | ||
242 | }; | ||
243 | |||
244 | enum cea_audio_coding_xtypes { | ||
245 | AUDIO_CODING_XTYPE_HE_REF_CT = 0, | ||
246 | AUDIO_CODING_XTYPE_HE_AAC = 1, | ||
247 | AUDIO_CODING_XTYPE_HE_AAC2 = 2, | ||
248 | AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, | ||
249 | AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, | ||
250 | }; | ||
251 | |||
252 | static char *cea_audio_coding_type_names[] = { | ||
253 | /* 0 */ "undefined", | ||
254 | /* 1 */ "LPCM", | ||
255 | /* 2 */ "AC-3", | ||
256 | /* 3 */ "MPEG1", | ||
257 | /* 4 */ "MP3", | ||
258 | /* 5 */ "MPEG2", | ||
259 | /* 6 */ "AAC-LC", | ||
260 | /* 7 */ "DTS", | ||
261 | /* 8 */ "ATRAC", | ||
262 | /* 9 */ "DSD(1-bit audio)", | ||
263 | /* 10 */ "Dolby Digital Plus(E-AC-3/DD+)", | ||
264 | /* 11 */ "DTS-HD", | ||
265 | /* 12 */ "Dolby TrueHD(MLP)", | ||
266 | /* 13 */ "DST", | ||
267 | /* 14 */ "WMAPro", | ||
268 | /* 15 */ "HE-AAC", | ||
269 | /* 16 */ "HE-AACv2", | ||
270 | /* 17 */ "MPEG Surround", | ||
271 | }; | ||
272 | |||
273 | |||
274 | /* | ||
275 | * HDMI routines | ||
276 | */ | ||
277 | |||
278 | static int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) | ||
279 | { | ||
280 | return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, | ||
281 | AC_DIPSIZE_ELD_BUF); | ||
282 | } | ||
283 | |||
284 | static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, | ||
285 | int *packet_index, int *byte_index) | ||
286 | { | ||
287 | int val; | ||
288 | |||
289 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); | ||
290 | |||
291 | *packet_index = val >> 5; | ||
292 | *byte_index = val & 0x1f; | ||
293 | } | ||
294 | |||
295 | static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, | ||
296 | int packet_index, int byte_index) | ||
297 | { | ||
298 | int val; | ||
299 | |||
300 | val = (packet_index << 5) | (byte_index & 0x1f); | ||
301 | |||
302 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); | ||
303 | } | ||
304 | |||
305 | static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, | ||
306 | unsigned char val) | ||
307 | { | ||
308 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); | ||
309 | } | ||
310 | |||
311 | static void hdmi_enable_output(struct hda_codec *codec) | ||
312 | { | ||
313 | /* Enable pin out and unmute */ | ||
314 | snd_hda_sequence_write(codec, pinout_enable_verb); | ||
315 | if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) | ||
316 | snd_hda_codec_write(codec, PIN_NID, 0, | ||
317 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | ||
318 | |||
319 | /* Enable Audio InfoFrame Transmission */ | ||
320 | hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); | ||
321 | snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, | ||
322 | AC_DIPXMIT_BEST); | ||
323 | } | ||
324 | |||
325 | static void hdmi_disable_output(struct hda_codec *codec) | ||
326 | { | ||
327 | snd_hda_sequence_write(codec, pinout_disable_verb); | ||
328 | if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) | ||
329 | snd_hda_codec_write(codec, PIN_NID, 0, | ||
330 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
331 | |||
332 | /* | ||
333 | * FIXME: noises may arise when playing music after reloading the | ||
334 | * kernel module, until the next X restart or monitor repower. | ||
335 | */ | ||
336 | } | ||
337 | |||
338 | static int hdmi_get_channel_count(struct hda_codec *codec) | ||
339 | { | ||
340 | return 1 + snd_hda_codec_read(codec, CVT_NID, 0, | ||
341 | AC_VERB_GET_CVT_CHAN_COUNT, 0); | ||
342 | } | ||
343 | |||
344 | static void hdmi_set_channel_count(struct hda_codec *codec, int chs) | ||
345 | { | ||
346 | snd_hda_codec_write(codec, CVT_NID, 0, | ||
347 | AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); | ||
348 | |||
349 | if (chs != hdmi_get_channel_count(codec)) | ||
350 | snd_printd(KERN_INFO "Channel count expect=%d, real=%d\n", | ||
351 | chs, hdmi_get_channel_count(codec)); | ||
352 | } | ||
353 | |||
354 | static void hdmi_debug_slot_mapping(struct hda_codec *codec) | ||
355 | { | ||
356 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
357 | int i; | ||
358 | int slot; | ||
359 | |||
360 | for (i = 0; i < 8; i++) { | ||
361 | slot = snd_hda_codec_read(codec, CVT_NID, 0, | ||
362 | AC_VERB_GET_HDMI_CHAN_SLOT, i); | ||
363 | printk(KERN_DEBUG "ASP channel %d => slot %d\n", | ||
364 | slot >> 4, slot & 0x7); | ||
365 | } | ||
366 | #endif | ||
367 | } | ||
368 | |||
369 | static void hdmi_setup_channel_mapping(struct hda_codec *codec) | ||
370 | { | ||
371 | snd_hda_sequence_write(codec, def_chan_map); | ||
372 | hdmi_debug_slot_mapping(codec); | ||
373 | } | ||
374 | |||
375 | |||
376 | /* | ||
377 | * ELD(EDID Like Data) routines | ||
378 | */ | ||
379 | |||
380 | static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) | ||
381 | { | ||
382 | return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); | ||
383 | } | ||
384 | |||
385 | static void hdmi_debug_present_sense(struct hda_codec *codec) | ||
386 | { | ||
387 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
388 | int eldv; | ||
389 | int present; | ||
390 | |||
391 | present = hdmi_present_sense(codec, PIN_NID); | ||
392 | eldv = (present & AC_PINSENSE_ELDV); | ||
393 | present = (present & AC_PINSENSE_PRESENCE); | ||
394 | |||
395 | printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); | ||
396 | #endif | ||
397 | } | ||
398 | |||
399 | static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, int byte_index) | ||
400 | { | ||
401 | unsigned int val; | ||
402 | |||
403 | val = snd_hda_codec_read(codec, PIN_NID, 0, | ||
404 | AC_VERB_GET_HDMI_ELDD, byte_index); | ||
405 | |||
406 | #ifdef BE_PARANOID | ||
407 | printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); | ||
408 | #endif | ||
409 | |||
410 | if ((val & AC_ELDD_ELD_VALID) == 0) { | ||
411 | snd_printd(KERN_INFO "Invalid ELD data byte %d\n", | ||
412 | byte_index); | ||
413 | val = 0; | ||
414 | } | ||
415 | |||
416 | return val & AC_ELDD_ELD_DATA; | ||
417 | } | ||
418 | |||
419 | static inline unsigned char grab_bits(const unsigned char *buf, | ||
420 | int byte, int lowbit, int bits) | ||
421 | { | ||
422 | BUG_ON(lowbit > 7); | ||
423 | BUG_ON(bits > 8); | ||
424 | BUG_ON(bits <= 0); | ||
425 | |||
426 | return (buf[byte] >> lowbit) & ((1 << bits) - 1); | ||
427 | } | ||
428 | |||
429 | static void hdmi_update_short_audio_desc(struct cea_sad *a, | ||
430 | const unsigned char *buf) | ||
431 | { | ||
432 | int i; | ||
433 | int val; | ||
434 | |||
435 | val = grab_bits(buf, 1, 0, 7); | ||
436 | a->rates = 0; | ||
437 | for (i = 0; i < 7; i++) | ||
438 | if (val & (1 << i)) | ||
439 | a->rates |= cea_sampling_frequencies[i + 1]; | ||
440 | |||
441 | a->channels = grab_bits(buf, 0, 0, 3); | ||
442 | a->channels++; | ||
443 | |||
444 | a->format = grab_bits(buf, 0, 3, 4); | ||
445 | switch (a->format) { | ||
446 | case AUDIO_CODING_TYPE_REF_STREAM_HEADER: | ||
447 | snd_printd(KERN_INFO | ||
448 | "audio coding type 0 not expected in ELD\n"); | ||
449 | break; | ||
450 | |||
451 | case AUDIO_CODING_TYPE_LPCM: | ||
452 | val = grab_bits(buf, 2, 0, 3); | ||
453 | a->sample_bits = 0; | ||
454 | for (i = 0; i < 3; i++) | ||
455 | if (val & (1 << i)) | ||
456 | a->sample_bits |= cea_sample_sizes[i + 1]; | ||
457 | break; | ||
458 | |||
459 | case AUDIO_CODING_TYPE_AC3: | ||
460 | case AUDIO_CODING_TYPE_MPEG1: | ||
461 | case AUDIO_CODING_TYPE_MP3: | ||
462 | case AUDIO_CODING_TYPE_MPEG2: | ||
463 | case AUDIO_CODING_TYPE_AACLC: | ||
464 | case AUDIO_CODING_TYPE_DTS: | ||
465 | case AUDIO_CODING_TYPE_ATRAC: | ||
466 | a->max_bitrate = grab_bits(buf, 2, 0, 8); | ||
467 | a->max_bitrate *= 8000; | ||
468 | break; | ||
469 | |||
470 | case AUDIO_CODING_TYPE_SACD: | ||
471 | break; | ||
472 | |||
473 | case AUDIO_CODING_TYPE_EAC3: | ||
474 | break; | ||
475 | |||
476 | case AUDIO_CODING_TYPE_DTS_HD: | ||
477 | break; | ||
478 | |||
479 | case AUDIO_CODING_TYPE_MLP: | ||
480 | break; | ||
481 | |||
482 | case AUDIO_CODING_TYPE_DST: | ||
483 | break; | ||
484 | |||
485 | case AUDIO_CODING_TYPE_WMAPRO: | ||
486 | a->profile = grab_bits(buf, 2, 0, 3); | ||
487 | break; | ||
488 | |||
489 | case AUDIO_CODING_TYPE_REF_CXT: | ||
490 | a->format = grab_bits(buf, 2, 3, 5); | ||
491 | if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || | ||
492 | a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { | ||
493 | snd_printd(KERN_INFO | ||
494 | "audio coding xtype %d not expected in ELD\n", | ||
495 | a->format); | ||
496 | a->format = 0; | ||
497 | } else | ||
498 | a->format += AUDIO_CODING_TYPE_HE_AAC - | ||
499 | AUDIO_CODING_XTYPE_HE_AAC; | ||
500 | break; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | static int hdmi_update_sink_eld(struct hda_codec *codec, | ||
505 | const unsigned char *buf, int size) | ||
506 | { | ||
507 | struct intel_hdmi_spec *spec = codec->spec; | ||
508 | struct sink_eld *e = &spec->sink; | ||
509 | int mnl; | ||
510 | int i; | ||
511 | |||
512 | e->eld_ver = grab_bits(buf, 0, 3, 5); | ||
513 | if (e->eld_ver != ELD_VER_CEA_861D && | ||
514 | e->eld_ver != ELD_VER_PARTIAL) { | ||
515 | snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); | ||
516 | goto out_fail; | ||
517 | } | ||
518 | |||
519 | e->eld_size = size; | ||
520 | e->baseline_len = grab_bits(buf, 2, 0, 8); | ||
521 | mnl = grab_bits(buf, 4, 0, 5); | ||
522 | e->cea_edid_ver = grab_bits(buf, 4, 5, 3); | ||
523 | |||
524 | e->support_hdcp = grab_bits(buf, 5, 0, 1); | ||
525 | e->support_ai = grab_bits(buf, 5, 1, 1); | ||
526 | e->conn_type = grab_bits(buf, 5, 2, 2); | ||
527 | e->sad_count = grab_bits(buf, 5, 4, 4); | ||
528 | |||
529 | e->aud_synch_delay = grab_bits(buf, 6, 0, 8); | ||
530 | e->spk_alloc = grab_bits(buf, 7, 0, 7); | ||
531 | |||
532 | e->port_id = get_unaligned_le64(buf + 8); | ||
533 | |||
534 | /* not specified, but the spec's tendency is little endian */ | ||
535 | e->manufacture_id = get_unaligned_le16(buf + 16); | ||
536 | e->product_id = get_unaligned_le16(buf + 18); | ||
537 | |||
538 | if (mnl > ELD_MAX_MNL) { | ||
539 | snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); | ||
540 | goto out_fail; | ||
541 | } else if (ELD_FIXED_BYTES + mnl > size) { | ||
542 | snd_printd(KERN_INFO "out of range MNL %d\n", mnl); | ||
543 | goto out_fail; | ||
544 | } else | ||
545 | strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); | ||
546 | |||
547 | for (i = 0; i < e->sad_count; i++) { | ||
548 | if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { | ||
549 | snd_printd(KERN_INFO "out of range SAD %d\n", i); | ||
550 | goto out_fail; | ||
551 | } | ||
552 | hdmi_update_short_audio_desc(e->sad + i, | ||
553 | buf + ELD_FIXED_BYTES + mnl + 3 * i); | ||
554 | } | ||
555 | |||
556 | return 0; | ||
557 | |||
558 | out_fail: | ||
559 | e->eld_ver = 0; | ||
560 | return -EINVAL; | ||
561 | } | ||
562 | |||
563 | static int hdmi_get_eld(struct hda_codec *codec) | ||
564 | { | ||
565 | int i; | ||
566 | int ret; | ||
567 | int size; | ||
568 | unsigned char *buf; | ||
569 | |||
570 | i = hdmi_present_sense(codec, PIN_NID) & AC_PINSENSE_ELDV; | ||
571 | if (!i) | ||
572 | return -ENOENT; | ||
573 | |||
574 | size = hdmi_get_eld_size(codec, PIN_NID); | ||
575 | if (size == 0) { | ||
576 | /* wfg: workaround for ASUS P5E-VM HDMI board */ | ||
577 | snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); | ||
578 | size = 128; | ||
579 | } | ||
580 | if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { | ||
581 | snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); | ||
582 | return -ERANGE; | ||
583 | } | ||
584 | |||
585 | buf = kmalloc(size, GFP_KERNEL); | ||
586 | if (!buf) | ||
587 | return -ENOMEM; | ||
588 | |||
589 | for (i = 0; i < size; i++) | ||
590 | buf[i] = hdmi_get_eld_byte(codec, i); | ||
591 | |||
592 | ret = hdmi_update_sink_eld(codec, buf, size); | ||
593 | |||
594 | kfree(buf); | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | static void hdmi_show_short_audio_desc(struct cea_sad *a) | ||
599 | { | ||
600 | printk(KERN_INFO "coding type: %s\n", | ||
601 | cea_audio_coding_type_names[a->format]); | ||
602 | printk(KERN_INFO "channels: %d\n", a->channels); | ||
603 | printk(KERN_INFO "sampling frequencies: 0x%x\n", a->rates); | ||
604 | |||
605 | if (a->format == AUDIO_CODING_TYPE_LPCM) | ||
606 | printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); | ||
607 | |||
608 | if (a->max_bitrate) | ||
609 | printk(KERN_INFO "max bitrate: %d HZ\n", a->max_bitrate); | ||
610 | |||
611 | if (a->profile) | ||
612 | printk(KERN_INFO "profile: %d\n", a->profile); | ||
613 | } | ||
614 | |||
615 | static void hdmi_show_eld(struct hda_codec *codec) | ||
616 | { | ||
617 | int i; | ||
618 | int j; | ||
619 | struct intel_hdmi_spec *spec = codec->spec; | ||
620 | struct sink_eld *e = &spec->sink; | ||
621 | char buf[80]; | ||
622 | |||
623 | printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); | ||
624 | printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); | ||
625 | printk(KERN_INFO "vendor block len is %d\n", | ||
626 | e->eld_size - e->baseline_len * 4 - 4); | ||
627 | printk(KERN_INFO "ELD version is %s\n", | ||
628 | eld_versoin_names[e->eld_ver]); | ||
629 | printk(KERN_INFO "CEA EDID version is %s\n", | ||
630 | cea_edid_version_names[e->cea_edid_ver]); | ||
631 | printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); | ||
632 | printk(KERN_INFO "product id is 0x%x\n", e->product_id); | ||
633 | printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); | ||
634 | printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); | ||
635 | printk(KERN_INFO "AI support is %d\n", e->support_ai); | ||
636 | printk(KERN_INFO "SAD count is %d\n", e->sad_count); | ||
637 | printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); | ||
638 | printk(KERN_INFO "connection type is %s\n", | ||
639 | eld_connection_type_names[e->conn_type]); | ||
640 | printk(KERN_INFO "monitor name is %s\n", e->monitor_name); | ||
641 | |||
642 | j = 0; | ||
643 | for (i = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { | ||
644 | if (e->spk_alloc & (1 << i)) | ||
645 | j += snprintf(buf + j, sizeof(buf) - j, " %s", | ||
646 | cea_speaker_allocation_names[i]); | ||
647 | } | ||
648 | buf[j] = '\0'; /* necessary when j == 0 */ | ||
649 | printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); | ||
650 | |||
651 | for (i = 0; i < e->sad_count; i++) | ||
652 | hdmi_show_short_audio_desc(e->sad + i); | ||
653 | } | ||
654 | |||
655 | /* | ||
656 | * Be careful, ELD buf could be totally rubbish! | ||
657 | */ | ||
658 | static void hdmi_parse_eld(struct hda_codec *codec) | ||
659 | { | ||
660 | hdmi_debug_present_sense(codec); | ||
661 | |||
662 | if (!hdmi_get_eld(codec)) | ||
663 | hdmi_show_eld(codec); | ||
664 | } | ||
665 | |||
666 | |||
667 | /* | ||
668 | * Audio Infoframe routines | ||
669 | */ | ||
670 | |||
671 | static void hdmi_debug_dip_size(struct hda_codec *codec) | ||
672 | { | ||
673 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
674 | int i; | ||
675 | int size; | ||
676 | |||
677 | size = hdmi_get_eld_size(codec, PIN_NID); | ||
678 | printk(KERN_DEBUG "ELD buf size is %d\n", size); | ||
679 | |||
680 | for (i = 0; i < 8; i++) { | ||
681 | size = snd_hda_codec_read(codec, PIN_NID, 0, | ||
682 | AC_VERB_GET_HDMI_DIP_SIZE, i); | ||
683 | printk(KERN_DEBUG "DIP GP[%d] buf size is %d\n", i, size); | ||
684 | } | ||
685 | #endif | ||
686 | } | ||
687 | |||
688 | static void hdmi_clear_dip_buffers(struct hda_codec *codec) | ||
689 | { | ||
690 | #ifdef BE_PARANOID | ||
691 | int i, j; | ||
692 | int size; | ||
693 | int pi, bi; | ||
694 | for (i = 0; i < 8; i++) { | ||
695 | size = snd_hda_codec_read(codec, PIN_NID, 0, | ||
696 | AC_VERB_GET_HDMI_DIP_SIZE, i); | ||
697 | if (size == 0) | ||
698 | continue; | ||
699 | |||
700 | hdmi_set_dip_index(codec, PIN_NID, i, 0x0); | ||
701 | for (j = 1; j < 1000; j++) { | ||
702 | hdmi_write_dip_byte(codec, PIN_NID, 0x0); | ||
703 | hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); | ||
704 | if (pi != i) | ||
705 | snd_printd(KERN_INFO "dip index %d: %d != %d\n", | ||
706 | bi, pi, i); | ||
707 | if (bi == 0) /* byte index wrapped around */ | ||
708 | break; | ||
709 | } | ||
710 | snd_printd(KERN_INFO | ||
711 | "DIP GP[%d] buf reported size=%d, written=%d\n", | ||
712 | i, size, j); | ||
713 | } | ||
714 | #endif | ||
715 | } | ||
716 | |||
717 | static void hdmi_setup_audio_infoframe(struct hda_codec *codec, | ||
718 | struct snd_pcm_substream *substream) | ||
719 | { | ||
720 | struct hdmi_audio_infoframe audio_infoframe = { | ||
721 | .type = 0x84, | ||
722 | .ver = 0x01, | ||
723 | .len = 0x0a, | ||
724 | .CC02_CT47 = substream->runtime->channels - 1, | ||
725 | }; | ||
726 | u8 *params = (u8 *)&audio_infoframe; | ||
727 | int i; | ||
728 | |||
729 | hdmi_debug_dip_size(codec); | ||
730 | hdmi_clear_dip_buffers(codec); /* be paranoid */ | ||
731 | |||
732 | hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); | ||
733 | for (i = 0; i < sizeof(audio_infoframe); i++) | ||
734 | hdmi_write_dip_byte(codec, PIN_NID, params[i]); | ||
735 | } | ||
736 | |||
737 | |||
738 | /* | ||
739 | * Unsolicited events | ||
740 | */ | ||
741 | |||
742 | static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) | ||
743 | { | ||
744 | int pind = !!(res & AC_UNSOL_RES_PD); | ||
745 | int eldv = !!(res & AC_UNSOL_RES_ELDV); | ||
746 | |||
747 | printk(KERN_INFO "HDMI intrinsic event: PD=%d ELDV=%d\n", pind, eldv); | ||
748 | |||
749 | if (pind && eldv) { | ||
750 | hdmi_parse_eld(codec); | ||
751 | /* TODO: do real things about ELD */ | ||
752 | } | ||
753 | } | ||
754 | |||
755 | static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) | ||
756 | { | ||
757 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | ||
758 | int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); | ||
759 | int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); | ||
760 | |||
761 | printk(KERN_INFO "HDMI non-intrinsic event: " | ||
762 | "SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", | ||
763 | subtag, | ||
764 | cp_state, | ||
765 | cp_ready); | ||
766 | |||
767 | /* who cares? */ | ||
768 | if (cp_state) | ||
769 | ; | ||
770 | if (cp_ready) | ||
771 | ; | ||
772 | } | ||
773 | |||
774 | |||
775 | static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) | ||
776 | { | ||
777 | int tag = res >> AC_UNSOL_RES_TAG_SHIFT; | ||
778 | int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; | ||
779 | |||
780 | if (tag != INTEL_HDMI_EVENT_TAG) { | ||
781 | snd_printd(KERN_INFO | ||
782 | "Unexpected HDMI unsolicited event tag 0x%x\n", | ||
783 | tag); | ||
784 | return; | ||
785 | } | ||
786 | |||
787 | if (subtag == 0) | ||
788 | hdmi_intrinsic_event(codec, res); | ||
789 | else | ||
790 | hdmi_non_intrinsic_event(codec, res); | ||
791 | } | ||
792 | |||
793 | /* | ||
794 | * Callbacks | ||
795 | */ | ||
796 | |||
797 | static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
798 | struct hda_codec *codec, | ||
799 | struct snd_pcm_substream *substream) | ||
800 | { | ||
801 | struct intel_hdmi_spec *spec = codec->spec; | ||
802 | |||
803 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
804 | } | ||
805 | |||
806 | static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
807 | struct hda_codec *codec, | ||
808 | struct snd_pcm_substream *substream) | ||
809 | { | ||
810 | struct intel_hdmi_spec *spec = codec->spec; | ||
811 | |||
812 | hdmi_disable_output(codec); | ||
813 | |||
814 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
815 | } | ||
816 | |||
817 | static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
818 | struct hda_codec *codec, | ||
819 | unsigned int stream_tag, | ||
820 | unsigned int format, | ||
821 | struct snd_pcm_substream *substream) | ||
822 | { | ||
823 | struct intel_hdmi_spec *spec = codec->spec; | ||
824 | |||
825 | snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | ||
826 | format, substream); | ||
827 | |||
828 | hdmi_set_channel_count(codec, substream->runtime->channels); | ||
829 | |||
830 | /* wfg: channel mapping not supported by DEVCTG */ | ||
831 | hdmi_setup_channel_mapping(codec); | ||
832 | |||
833 | hdmi_setup_audio_infoframe(codec, substream); | ||
834 | |||
835 | hdmi_enable_output(codec); | ||
836 | |||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | static struct hda_pcm_stream intel_hdmi_pcm_playback = { | ||
841 | .substreams = 1, | ||
842 | .channels_min = 2, | ||
843 | .channels_max = 8, | ||
844 | .nid = CVT_NID, /* NID to query formats and rates and setup streams */ | ||
845 | .ops = { | ||
846 | .open = intel_hdmi_playback_pcm_open, | ||
847 | .close = intel_hdmi_playback_pcm_close, | ||
848 | .prepare = intel_hdmi_playback_pcm_prepare | ||
849 | }, | ||
850 | }; | ||
851 | |||
852 | static int intel_hdmi_build_pcms(struct hda_codec *codec) | ||
853 | { | ||
854 | struct intel_hdmi_spec *spec = codec->spec; | ||
855 | struct hda_pcm *info = &spec->pcm_rec; | ||
856 | |||
857 | codec->num_pcms = 1; | ||
858 | codec->pcm_info = info; | ||
859 | |||
860 | info->name = "INTEL HDMI"; | ||
861 | info->pcm_type = HDA_PCM_TYPE_HDMI; | ||
862 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; | ||
863 | |||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | static int intel_hdmi_build_controls(struct hda_codec *codec) | ||
868 | { | ||
869 | struct intel_hdmi_spec *spec = codec->spec; | ||
870 | int err; | ||
871 | |||
872 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | ||
873 | if (err < 0) | ||
874 | return err; | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static int intel_hdmi_init(struct hda_codec *codec) | ||
880 | { | ||
881 | /* disable audio output as early as possible */ | ||
882 | hdmi_disable_output(codec); | ||
883 | |||
884 | snd_hda_sequence_write(codec, unsolicited_response_verb); | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static void intel_hdmi_free(struct hda_codec *codec) | ||
890 | { | ||
891 | kfree(codec->spec); | ||
892 | } | ||
893 | |||
894 | static struct hda_codec_ops intel_hdmi_patch_ops = { | ||
895 | .init = intel_hdmi_init, | ||
896 | .free = intel_hdmi_free, | ||
897 | .build_pcms = intel_hdmi_build_pcms, | ||
898 | .build_controls = intel_hdmi_build_controls, | ||
899 | .unsol_event = intel_hdmi_unsol_event, | ||
900 | }; | ||
901 | |||
902 | static int patch_intel_hdmi(struct hda_codec *codec) | ||
903 | { | ||
904 | struct intel_hdmi_spec *spec; | ||
905 | |||
906 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
907 | if (spec == NULL) | ||
908 | return -ENOMEM; | ||
909 | |||
910 | spec->multiout.num_dacs = 0; /* no analog */ | ||
911 | spec->multiout.max_channels = 8; | ||
912 | spec->multiout.dig_out_nid = CVT_NID; | ||
913 | |||
914 | codec->spec = spec; | ||
915 | codec->patch_ops = intel_hdmi_patch_ops; | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | struct hda_codec_preset snd_hda_preset_intelhdmi[] = { | ||
921 | { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi }, | ||
922 | { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, | ||
923 | { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, | ||
924 | { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi }, | ||
925 | {} /* terminator */ | ||
926 | }; | ||