* [RFC][PATCH] ELD routines and proc interface
@ 2008-11-13 2:21 Wu Fengguang
2008-11-13 7:26 ` Takashi Iwai
[not found] ` <20081119071135.GA17733@csy.ca>
0 siblings, 2 replies; 20+ messages in thread
From: Wu Fengguang @ 2008-11-13 2:21 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
Create hda_eld.c for ELD routines and proc interface.
ELD handling routines can be shared by all HDMI codecs,
and they are large enough to make a standalone source file.
Some notes on the code:
- Shall we show an empty file if the ELD content is not valid?
Well it's not that simple. There could be partially populated ELD,
and there may be malformed ELD provided by buggy drivers/monitors.
So I tend to expose ELD as it is.
- hdmi_show_eld() and hdmi_print_eld_info() are somehow duplicated
The plan is to shrink hdmi_show_eld()/hdmi_show_short_audio_desc(), and to
show a compact message at monitor hotplug and driver initialization time.
- The ELD retrieval routines rely on the Intel HDA interface,
others are/could be universal and independent ones.
- The ELD proc interface code could be moved to hda_proc.c if necessary.
- How do we name the proc file?
If there are going to be two HDMI pins per codec, then the current naming
scheme (eld#<codec no>) will fail.
- The ELD proc file content is designed to be easy for scripts and human reading.
Its lines all have the pattern:
<item_name>\t[\t]*<item_value>
where <item_name> is a keyword in c language, while <item_value> could be any
contents, including white spaces. <item_value> could also be a null value.
Signed-off-by: Wu Fengguang <wfg@linux.intel.com>
---
sound/pci/Kconfig | 4
sound/pci/hda/Makefile | 1
sound/pci/hda/hda_eld.c | 532 ++++++++++++++++++++++++++++++
sound/pci/hda/hda_local.h | 62 ++-
sound/pci/hda/patch_intelhdmi.c | 484 ---------------------------
5 files changed, 600 insertions(+), 483 deletions(-)
--- sound-2.6.orig/sound/pci/hda/patch_intelhdmi.c
+++ sound-2.6/sound/pci/hda/patch_intelhdmi.c
@@ -30,7 +30,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <sound/core.h>
-#include <asm/unaligned.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_patch.h"
@@ -40,43 +39,6 @@
#define INTEL_HDMI_EVENT_TAG 0x08
-/*
- * CEA Short Audio Descriptor data
- */
-struct cea_sad {
- int channels;
- int format; /* (format == 0) indicates invalid SAD */
- int rates;
- int sample_bits; /* for LPCM */
- int max_bitrate; /* for AC3...ATRAC */
- int profile; /* for WMAPRO */
-};
-
-#define ELD_FIXED_BYTES 20
-#define ELD_MAX_MNL 16
-#define ELD_MAX_SAD 16
-
-/*
- * ELD: EDID Like Data
- */
-struct sink_eld {
- int eld_size;
- int baseline_len;
- int eld_ver; /* (eld_ver == 0) indicates invalid ELD */
- int cea_edid_ver;
- char monitor_name[ELD_MAX_MNL + 1];
- int manufacture_id;
- int product_id;
- u64 port_id;
- int support_hdcp;
- int support_ai;
- int conn_type;
- int aud_synch_delay;
- int spk_alloc;
- int sad_count;
- struct cea_sad sad[ELD_MAX_SAD];
-};
-
struct intel_hdmi_spec {
struct hda_multi_out multiout;
struct hda_pcm pcm_rec;
@@ -127,160 +89,9 @@ struct hdmi_audio_infoframe {
};
/*
- * SS1:SS0 index => sample size
- */
-static int cea_sample_sizes[4] = {
- 0, /* 0: Refer to Stream Header */
- AC_SUPPCM_BITS_16, /* 1: 16 bits */
- AC_SUPPCM_BITS_20, /* 2: 20 bits */
- AC_SUPPCM_BITS_24, /* 3: 24 bits */
-};
-
-/*
- * SF2:SF1:SF0 index => sampling frequency
- */
-static int cea_sampling_frequencies[8] = {
- 0, /* 0: Refer to Stream Header */
- SNDRV_PCM_RATE_32000, /* 1: 32000Hz */
- SNDRV_PCM_RATE_44100, /* 2: 44100Hz */
- SNDRV_PCM_RATE_48000, /* 3: 48000Hz */
- SNDRV_PCM_RATE_88200, /* 4: 88200Hz */
- SNDRV_PCM_RATE_96000, /* 5: 96000Hz */
- SNDRV_PCM_RATE_176400, /* 6: 176400Hz */
- SNDRV_PCM_RATE_192000, /* 7: 192000Hz */
-};
-
-enum eld_versions {
- ELD_VER_CEA_861D = 2,
- ELD_VER_PARTIAL = 31,
-};
-
-static char *eld_versoin_names[32] = {
- "0-reserved",
- "1-reserved",
- "CEA-861D or below",
- "3-reserved",
- [4 ... 30] = "reserved",
- [31] = "partial"
-};
-
-enum cea_edid_versions {
- CEA_EDID_VER_NONE = 0,
- CEA_EDID_VER_CEA861 = 1,
- CEA_EDID_VER_CEA861A = 2,
- CEA_EDID_VER_CEA861BCD = 3,
- CEA_EDID_VER_RESERVED = 4,
-};
-
-static char *cea_edid_version_names[8] = {
- "no CEA EDID Timing Extension block present",
- "CEA-861",
- "CEA-861-A",
- "CEA-861-B, C or D",
- "4-reserved",
- [5 ... 7] = "reserved"
-};
-
-/*
- * CEA Speaker Allocation data block bits
- */
-#define CEA_SA_FLR (0 << 0)
-#define CEA_SA_LFE (1 << 1)
-#define CEA_SA_FC (1 << 2)
-#define CEA_SA_RLR (1 << 3)
-#define CEA_SA_RC (1 << 4)
-#define CEA_SA_FLRC (1 << 5)
-#define CEA_SA_RLRC (1 << 6)
-/* the following are not defined in ELD yet */
-#define CEA_SA_FLRW (1 << 7)
-#define CEA_SA_FLRH (1 << 8)
-#define CEA_SA_TC (1 << 9)
-#define CEA_SA_FCH (1 << 10)
-
-static char *cea_speaker_allocation_names[] = {
- /* 0 */ "FL/FR",
- /* 1 */ "LFE",
- /* 2 */ "FC",
- /* 3 */ "RL/RR",
- /* 4 */ "RC",
- /* 5 */ "FLC/FRC",
- /* 6 */ "RLC/RRC",
- /* 7 */ "FLW/FRW",
- /* 8 */ "FLH/FRH",
- /* 9 */ "TC",
- /* 10 */ "FCH",
-};
-
-static char *eld_connection_type_names[4] = {
- "HDMI",
- "Display Port",
- "2-reserved",
- "3-reserved"
-};
-
-enum cea_audio_coding_types {
- AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0,
- AUDIO_CODING_TYPE_LPCM = 1,
- AUDIO_CODING_TYPE_AC3 = 2,
- AUDIO_CODING_TYPE_MPEG1 = 3,
- AUDIO_CODING_TYPE_MP3 = 4,
- AUDIO_CODING_TYPE_MPEG2 = 5,
- AUDIO_CODING_TYPE_AACLC = 6,
- AUDIO_CODING_TYPE_DTS = 7,
- AUDIO_CODING_TYPE_ATRAC = 8,
- AUDIO_CODING_TYPE_SACD = 9,
- AUDIO_CODING_TYPE_EAC3 = 10,
- AUDIO_CODING_TYPE_DTS_HD = 11,
- AUDIO_CODING_TYPE_MLP = 12,
- AUDIO_CODING_TYPE_DST = 13,
- AUDIO_CODING_TYPE_WMAPRO = 14,
- AUDIO_CODING_TYPE_REF_CXT = 15,
- /* also include valid xtypes below */
- AUDIO_CODING_TYPE_HE_AAC = 15,
- AUDIO_CODING_TYPE_HE_AAC2 = 16,
- AUDIO_CODING_TYPE_MPEG_SURROUND = 17,
-};
-
-enum cea_audio_coding_xtypes {
- AUDIO_CODING_XTYPE_HE_REF_CT = 0,
- AUDIO_CODING_XTYPE_HE_AAC = 1,
- AUDIO_CODING_XTYPE_HE_AAC2 = 2,
- AUDIO_CODING_XTYPE_MPEG_SURROUND = 3,
- AUDIO_CODING_XTYPE_FIRST_RESERVED = 4,
-};
-
-static char *cea_audio_coding_type_names[] = {
- /* 0 */ "undefined",
- /* 1 */ "LPCM",
- /* 2 */ "AC-3",
- /* 3 */ "MPEG1",
- /* 4 */ "MP3",
- /* 5 */ "MPEG2",
- /* 6 */ "AAC-LC",
- /* 7 */ "DTS",
- /* 8 */ "ATRAC",
- /* 9 */ "DSD(1-bit audio)",
- /* 10 */ "Dolby Digital Plus(E-AC-3/DD+)",
- /* 11 */ "DTS-HD",
- /* 12 */ "Dolby TrueHD(MLP)",
- /* 13 */ "DST",
- /* 14 */ "WMAPro",
- /* 15 */ "HE-AAC",
- /* 16 */ "HE-AACv2",
- /* 17 */ "MPEG Surround",
-};
-
-
-/*
* HDMI routines
*/
-static int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
-{
- return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
- AC_DIPSIZE_ELD_BUF);
-}
-
#ifdef BE_PARANOID
static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid,
int *packet_index, int *byte_index)
@@ -375,294 +186,13 @@ static void hdmi_setup_channel_mapping(s
}
-/*
- * ELD(EDID Like Data) routines
- */
-
-static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid)
-{
- return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0);
-}
-
-static void hdmi_debug_present_sense(struct hda_codec *codec)
-{
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- int eldv;
- int present;
-
- present = hdmi_present_sense(codec, PIN_NID);
- eldv = (present & AC_PINSENSE_ELDV);
- present = (present & AC_PINSENSE_PRESENCE);
-
- printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv);
-#endif
-}
-
-static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, int byte_index)
-{
- unsigned int val;
-
- val = snd_hda_codec_read(codec, PIN_NID, 0,
- AC_VERB_GET_HDMI_ELDD, byte_index);
-
-#ifdef BE_PARANOID
- printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val);
-#endif
-
- if ((val & AC_ELDD_ELD_VALID) == 0) {
- snd_printd(KERN_INFO "Invalid ELD data byte %d\n",
- byte_index);
- val = 0;
- }
-
- return val & AC_ELDD_ELD_DATA;
-}
-
-static inline unsigned char grab_bits(const unsigned char *buf,
- int byte, int lowbit, int bits)
-{
- BUG_ON(lowbit > 7);
- BUG_ON(bits > 8);
- BUG_ON(bits <= 0);
-
- return (buf[byte] >> lowbit) & ((1 << bits) - 1);
-}
-
-static void hdmi_update_short_audio_desc(struct cea_sad *a,
- const unsigned char *buf)
-{
- int i;
- int val;
-
- val = grab_bits(buf, 1, 0, 7);
- a->rates = 0;
- for (i = 0; i < 7; i++)
- if (val & (1 << i))
- a->rates |= cea_sampling_frequencies[i + 1];
-
- a->channels = grab_bits(buf, 0, 0, 3);
- a->channels++;
-
- a->format = grab_bits(buf, 0, 3, 4);
- switch (a->format) {
- case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
- snd_printd(KERN_INFO
- "audio coding type 0 not expected in ELD\n");
- break;
-
- case AUDIO_CODING_TYPE_LPCM:
- val = grab_bits(buf, 2, 0, 3);
- a->sample_bits = 0;
- for (i = 0; i < 3; i++)
- if (val & (1 << i))
- a->sample_bits |= cea_sample_sizes[i + 1];
- break;
-
- case AUDIO_CODING_TYPE_AC3:
- case AUDIO_CODING_TYPE_MPEG1:
- case AUDIO_CODING_TYPE_MP3:
- case AUDIO_CODING_TYPE_MPEG2:
- case AUDIO_CODING_TYPE_AACLC:
- case AUDIO_CODING_TYPE_DTS:
- case AUDIO_CODING_TYPE_ATRAC:
- a->max_bitrate = grab_bits(buf, 2, 0, 8);
- a->max_bitrate *= 8000;
- break;
-
- case AUDIO_CODING_TYPE_SACD:
- break;
-
- case AUDIO_CODING_TYPE_EAC3:
- break;
-
- case AUDIO_CODING_TYPE_DTS_HD:
- break;
-
- case AUDIO_CODING_TYPE_MLP:
- break;
-
- case AUDIO_CODING_TYPE_DST:
- break;
-
- case AUDIO_CODING_TYPE_WMAPRO:
- a->profile = grab_bits(buf, 2, 0, 3);
- break;
-
- case AUDIO_CODING_TYPE_REF_CXT:
- a->format = grab_bits(buf, 2, 3, 5);
- if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT ||
- a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) {
- snd_printd(KERN_INFO
- "audio coding xtype %d not expected in ELD\n",
- a->format);
- a->format = 0;
- } else
- a->format += AUDIO_CODING_TYPE_HE_AAC -
- AUDIO_CODING_XTYPE_HE_AAC;
- break;
- }
-}
-
-static int hdmi_update_sink_eld(struct hda_codec *codec,
- const unsigned char *buf, int size)
-{
- struct intel_hdmi_spec *spec = codec->spec;
- struct sink_eld *e = &spec->sink;
- int mnl;
- int i;
-
- e->eld_ver = grab_bits(buf, 0, 3, 5);
- if (e->eld_ver != ELD_VER_CEA_861D &&
- e->eld_ver != ELD_VER_PARTIAL) {
- snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver);
- goto out_fail;
- }
-
- e->eld_size = size;
- e->baseline_len = grab_bits(buf, 2, 0, 8);
- mnl = grab_bits(buf, 4, 0, 5);
- e->cea_edid_ver = grab_bits(buf, 4, 5, 3);
-
- e->support_hdcp = grab_bits(buf, 5, 0, 1);
- e->support_ai = grab_bits(buf, 5, 1, 1);
- e->conn_type = grab_bits(buf, 5, 2, 2);
- e->sad_count = grab_bits(buf, 5, 4, 4);
-
- e->aud_synch_delay = grab_bits(buf, 6, 0, 8);
- e->spk_alloc = grab_bits(buf, 7, 0, 7);
-
- e->port_id = get_unaligned_le64(buf + 8);
-
- /* not specified, but the spec's tendency is little endian */
- e->manufacture_id = get_unaligned_le16(buf + 16);
- e->product_id = get_unaligned_le16(buf + 18);
-
- if (mnl > ELD_MAX_MNL) {
- snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl);
- goto out_fail;
- } else if (ELD_FIXED_BYTES + mnl > size) {
- snd_printd(KERN_INFO "out of range MNL %d\n", mnl);
- goto out_fail;
- } else
- strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl);
-
- for (i = 0; i < e->sad_count; i++) {
- if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
- snd_printd(KERN_INFO "out of range SAD %d\n", i);
- goto out_fail;
- }
- hdmi_update_short_audio_desc(e->sad + i,
- buf + ELD_FIXED_BYTES + mnl + 3 * i);
- }
-
- return 0;
-
-out_fail:
- e->eld_ver = 0;
- return -EINVAL;
-}
-
-static int hdmi_get_eld(struct hda_codec *codec)
-{
- int i;
- int ret;
- int size;
- unsigned char *buf;
-
- i = hdmi_present_sense(codec, PIN_NID) & AC_PINSENSE_ELDV;
- if (!i)
- return -ENOENT;
-
- size = hdmi_get_eld_size(codec, PIN_NID);
- if (size == 0) {
- /* wfg: workaround for ASUS P5E-VM HDMI board */
- snd_printd(KERN_INFO "ELD buf size is 0, force 128\n");
- size = 128;
- }
- if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) {
- snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size);
- return -ERANGE;
- }
-
- buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- for (i = 0; i < size; i++)
- buf[i] = hdmi_get_eld_byte(codec, i);
-
- ret = hdmi_update_sink_eld(codec, buf, size);
-
- kfree(buf);
- return ret;
-}
-
-static void hdmi_show_short_audio_desc(struct cea_sad *a)
-{
- printk(KERN_INFO "coding type: %s\n",
- cea_audio_coding_type_names[a->format]);
- printk(KERN_INFO "channels: %d\n", a->channels);
- printk(KERN_INFO "sampling frequencies: 0x%x\n", a->rates);
-
- if (a->format == AUDIO_CODING_TYPE_LPCM)
- printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits);
-
- if (a->max_bitrate)
- printk(KERN_INFO "max bitrate: %d HZ\n", a->max_bitrate);
-
- if (a->profile)
- printk(KERN_INFO "profile: %d\n", a->profile);
-}
-
-static void hdmi_show_eld(struct hda_codec *codec)
-{
- int i;
- int j;
- struct intel_hdmi_spec *spec = codec->spec;
- struct sink_eld *e = &spec->sink;
- char buf[80];
-
- printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size);
- printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len);
- printk(KERN_INFO "vendor block len is %d\n",
- e->eld_size - e->baseline_len * 4 - 4);
- printk(KERN_INFO "ELD version is %s\n",
- eld_versoin_names[e->eld_ver]);
- printk(KERN_INFO "CEA EDID version is %s\n",
- cea_edid_version_names[e->cea_edid_ver]);
- printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id);
- printk(KERN_INFO "product id is 0x%x\n", e->product_id);
- printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id);
- printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp);
- printk(KERN_INFO "AI support is %d\n", e->support_ai);
- printk(KERN_INFO "SAD count is %d\n", e->sad_count);
- printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay);
- printk(KERN_INFO "connection type is %s\n",
- eld_connection_type_names[e->conn_type]);
- printk(KERN_INFO "monitor name is %s\n", e->monitor_name);
-
- j = 0;
- for (i = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
- if (e->spk_alloc & (1 << i))
- j += snprintf(buf + j, sizeof(buf) - j, " %s",
- cea_speaker_allocation_names[i]);
- }
- buf[j] = '\0'; /* necessary when j == 0 */
- printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf);
-
- for (i = 0; i < e->sad_count; i++)
- hdmi_show_short_audio_desc(e->sad + i);
-}
-
-/*
- * Be careful, ELD buf could be totally rubbish!
- */
static void hdmi_parse_eld(struct hda_codec *codec)
{
- hdmi_debug_present_sense(codec);
+ struct intel_hdmi_spec *spec = codec->spec;
+ struct sink_eld *eld = &spec->sink;
- if (!hdmi_get_eld(codec))
- hdmi_show_eld(codec);
+ if (!hdmi_get_eld(eld, codec, PIN_NID))
+ hdmi_show_eld(eld);
}
@@ -880,6 +410,11 @@ static int intel_hdmi_build_controls(str
static int intel_hdmi_init(struct hda_codec *codec)
{
+ struct intel_hdmi_spec *spec = codec->spec;
+ struct sink_eld *eld = &spec->sink;
+
+ snd_hda_eld_proc_new(codec, eld);
+
/* disable audio output as early as possible */
hdmi_disable_output(codec);
@@ -927,3 +462,4 @@ struct hda_codec_preset snd_hda_preset_i
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
{} /* terminator */
};
+
--- /dev/null
+++ sound-2.6/sound/pci/hda/hda_eld.c
@@ -0,0 +1,532 @@
+/*
+ * Generic routines and proc interface for ELD(EDID Like Data) information
+ *
+ * Copyright(c) 2008 Intel Corporation.
+ *
+ * Authors:
+ * Wu Fengguang <wfg@linux.intel.com>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <sound/core.h>
+#include <asm/unaligned.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+enum eld_versions {
+ ELD_VER_CEA_861D = 2,
+ ELD_VER_PARTIAL = 31,
+};
+
+static char *eld_versoin_names[32] = {
+ "reserved",
+ "reserved",
+ "CEA-861D or below",
+ [3 ... 30] = "reserved",
+ [31] = "partial"
+};
+
+enum cea_edid_versions {
+ CEA_EDID_VER_NONE = 0,
+ CEA_EDID_VER_CEA861 = 1,
+ CEA_EDID_VER_CEA861A = 2,
+ CEA_EDID_VER_CEA861BCD = 3,
+ CEA_EDID_VER_RESERVED = 4,
+};
+
+static char *cea_edid_version_names[8] = {
+ "no CEA EDID Timing Extension block present",
+ "CEA-861",
+ "CEA-861-A",
+ "CEA-861-B, C or D",
+ [4 ... 7] = "reserved"
+};
+
+/*
+ * CEA Speaker Allocation data block bits
+ */
+#define CEA_SA_FLR (0 << 0)
+#define CEA_SA_LFE (1 << 1)
+#define CEA_SA_FC (1 << 2)
+#define CEA_SA_RLR (1 << 3)
+#define CEA_SA_RC (1 << 4)
+#define CEA_SA_FLRC (1 << 5)
+#define CEA_SA_RLRC (1 << 6)
+/* the following are not defined in ELD yet */
+#define CEA_SA_FLRW (1 << 7)
+#define CEA_SA_FLRH (1 << 8)
+#define CEA_SA_TC (1 << 9)
+#define CEA_SA_FCH (1 << 10)
+
+static char *cea_speaker_allocation_names[] = {
+ /* 0 */ "FL/FR",
+ /* 1 */ "LFE",
+ /* 2 */ "FC",
+ /* 3 */ "RL/RR",
+ /* 4 */ "RC",
+ /* 5 */ "FLC/FRC",
+ /* 6 */ "RLC/RRC",
+ /* 7 */ "FLW/FRW",
+ /* 8 */ "FLH/FRH",
+ /* 9 */ "TC",
+ /* 10 */ "FCH",
+};
+
+static char *eld_connection_type_names[4] = {
+ "HDMI",
+ "Display Port",
+ "2-reserved",
+ "3-reserved"
+};
+
+enum cea_audio_coding_types {
+ AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0,
+ AUDIO_CODING_TYPE_LPCM = 1,
+ AUDIO_CODING_TYPE_AC3 = 2,
+ AUDIO_CODING_TYPE_MPEG1 = 3,
+ AUDIO_CODING_TYPE_MP3 = 4,
+ AUDIO_CODING_TYPE_MPEG2 = 5,
+ AUDIO_CODING_TYPE_AACLC = 6,
+ AUDIO_CODING_TYPE_DTS = 7,
+ AUDIO_CODING_TYPE_ATRAC = 8,
+ AUDIO_CODING_TYPE_SACD = 9,
+ AUDIO_CODING_TYPE_EAC3 = 10,
+ AUDIO_CODING_TYPE_DTS_HD = 11,
+ AUDIO_CODING_TYPE_MLP = 12,
+ AUDIO_CODING_TYPE_DST = 13,
+ AUDIO_CODING_TYPE_WMAPRO = 14,
+ AUDIO_CODING_TYPE_REF_CXT = 15,
+ /* also include valid xtypes below */
+ AUDIO_CODING_TYPE_HE_AAC = 15,
+ AUDIO_CODING_TYPE_HE_AAC2 = 16,
+ AUDIO_CODING_TYPE_MPEG_SURROUND = 17,
+};
+
+enum cea_audio_coding_xtypes {
+ AUDIO_CODING_XTYPE_HE_REF_CT = 0,
+ AUDIO_CODING_XTYPE_HE_AAC = 1,
+ AUDIO_CODING_XTYPE_HE_AAC2 = 2,
+ AUDIO_CODING_XTYPE_MPEG_SURROUND = 3,
+ AUDIO_CODING_XTYPE_FIRST_RESERVED = 4,
+};
+
+static char *cea_audio_coding_type_names[] = {
+ /* 0 */ "undefined",
+ /* 1 */ "LPCM",
+ /* 2 */ "AC-3",
+ /* 3 */ "MPEG1",
+ /* 4 */ "MP3",
+ /* 5 */ "MPEG2",
+ /* 6 */ "AAC-LC",
+ /* 7 */ "DTS",
+ /* 8 */ "ATRAC",
+ /* 9 */ "DSD(1-bit audio)",
+ /* 10 */ "Dolby Digital Plus(E-AC-3/DD+)",
+ /* 11 */ "DTS-HD",
+ /* 12 */ "Dolby TrueHD(MLP)",
+ /* 13 */ "DST",
+ /* 14 */ "WMAPro",
+ /* 15 */ "HE-AAC",
+ /* 16 */ "HE-AACv2",
+ /* 17 */ "MPEG Surround",
+};
+
+/*
+ * The following two lists are shared between
+ * - HDMI audio infoframe (source to sink)
+ * - CEA E-EDID extension (sink to source)
+ */
+
+/*
+ * SS1:SS0 index => sample size
+ */
+static int cea_sample_sizes[4] = {
+ 0, /* 0: Refer to Stream Header */
+ AC_SUPPCM_BITS_16, /* 1: 16 bits */
+ AC_SUPPCM_BITS_20, /* 2: 20 bits */
+ AC_SUPPCM_BITS_24, /* 3: 24 bits */
+};
+
+/*
+ * SF2:SF1:SF0 index => sampling frequency
+ */
+static int cea_sampling_frequencies[8] = {
+ 0, /* 0: Refer to Stream Header */
+ SNDRV_PCM_RATE_32000, /* 1: 32000Hz */
+ SNDRV_PCM_RATE_44100, /* 2: 44100Hz */
+ SNDRV_PCM_RATE_48000, /* 3: 48000Hz */
+ SNDRV_PCM_RATE_88200, /* 4: 88200Hz */
+ SNDRV_PCM_RATE_96000, /* 5: 96000Hz */
+ SNDRV_PCM_RATE_176400, /* 6: 176400Hz */
+ SNDRV_PCM_RATE_192000, /* 7: 192000Hz */
+};
+
+static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
+ int byte_index)
+{
+ unsigned int val;
+
+ val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_HDMI_ELDD, byte_index);
+
+#ifdef BE_PARANOID
+ printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val);
+#endif
+
+ if ((val & AC_ELDD_ELD_VALID) == 0) {
+ snd_printd(KERN_INFO "Invalid ELD data byte %d\n",
+ byte_index);
+ val = 0;
+ }
+
+ return val & AC_ELDD_ELD_DATA;
+}
+
+static inline unsigned char grab_bits(const unsigned char *buf,
+ int byte, int lowbit, int bits)
+{
+ BUG_ON(lowbit > 7);
+ BUG_ON(bits > 8);
+ BUG_ON(bits <= 0);
+
+ return (buf[byte] >> lowbit) & ((1 << bits) - 1);
+}
+
+static void hdmi_update_short_audio_desc(struct cea_sad *a,
+ const unsigned char *buf)
+{
+ int i;
+ int val;
+
+ val = grab_bits(buf, 1, 0, 7);
+ a->rates = 0;
+ for (i = 0; i < 7; i++)
+ if (val & (1 << i))
+ a->rates |= cea_sampling_frequencies[i + 1];
+
+ a->channels = grab_bits(buf, 0, 0, 3);
+ a->channels++;
+
+ a->format = grab_bits(buf, 0, 3, 4);
+ switch (a->format) {
+ case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
+ snd_printd(KERN_INFO
+ "audio coding type 0 not expected in ELD\n");
+ break;
+
+ case AUDIO_CODING_TYPE_LPCM:
+ val = grab_bits(buf, 2, 0, 3);
+ a->sample_bits = 0;
+ for (i = 0; i < 3; i++)
+ if (val & (1 << i))
+ a->sample_bits |= cea_sample_sizes[i + 1];
+ break;
+
+ case AUDIO_CODING_TYPE_AC3:
+ case AUDIO_CODING_TYPE_MPEG1:
+ case AUDIO_CODING_TYPE_MP3:
+ case AUDIO_CODING_TYPE_MPEG2:
+ case AUDIO_CODING_TYPE_AACLC:
+ case AUDIO_CODING_TYPE_DTS:
+ case AUDIO_CODING_TYPE_ATRAC:
+ a->max_bitrate = grab_bits(buf, 2, 0, 8);
+ a->max_bitrate *= 8000;
+ break;
+
+ case AUDIO_CODING_TYPE_SACD:
+ break;
+
+ case AUDIO_CODING_TYPE_EAC3:
+ break;
+
+ case AUDIO_CODING_TYPE_DTS_HD:
+ break;
+
+ case AUDIO_CODING_TYPE_MLP:
+ break;
+
+ case AUDIO_CODING_TYPE_DST:
+ break;
+
+ case AUDIO_CODING_TYPE_WMAPRO:
+ a->profile = grab_bits(buf, 2, 0, 3);
+ break;
+
+ case AUDIO_CODING_TYPE_REF_CXT:
+ a->format = grab_bits(buf, 2, 3, 5);
+ if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT ||
+ a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) {
+ snd_printd(KERN_INFO
+ "audio coding xtype %d not expected in ELD\n",
+ a->format);
+ a->format = 0;
+ } else
+ a->format += AUDIO_CODING_TYPE_HE_AAC -
+ AUDIO_CODING_XTYPE_HE_AAC;
+ break;
+ }
+}
+
+/*
+ * Be careful, ELD buf could be totally rubbish!
+ */
+static int hdmi_update_sink_eld(struct sink_eld *e,
+ const unsigned char *buf, int size)
+{
+ int mnl;
+ int i;
+
+ e->eld_ver = grab_bits(buf, 0, 3, 5);
+ if (e->eld_ver != ELD_VER_CEA_861D &&
+ e->eld_ver != ELD_VER_PARTIAL) {
+ snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver);
+ goto out_fail;
+ }
+
+ e->eld_size = size;
+ e->baseline_len = grab_bits(buf, 2, 0, 8);
+ mnl = grab_bits(buf, 4, 0, 5);
+ e->cea_edid_ver = grab_bits(buf, 4, 5, 3);
+
+ e->support_hdcp = grab_bits(buf, 5, 0, 1);
+ e->support_ai = grab_bits(buf, 5, 1, 1);
+ e->conn_type = grab_bits(buf, 5, 2, 2);
+ e->sad_count = grab_bits(buf, 5, 4, 4);
+
+ e->aud_synch_delay = grab_bits(buf, 6, 0, 8) * 2;
+ e->spk_alloc = grab_bits(buf, 7, 0, 7);
+
+ e->port_id = get_unaligned_le64(buf + 8);
+
+ /* not specified, but the spec's tendency is little endian */
+ e->manufacture_id = get_unaligned_le16(buf + 16);
+ e->product_id = get_unaligned_le16(buf + 18);
+
+ if (mnl > ELD_MAX_MNL) {
+ snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl);
+ goto out_fail;
+ } else if (ELD_FIXED_BYTES + mnl > size) {
+ snd_printd(KERN_INFO "out of range MNL %d\n", mnl);
+ goto out_fail;
+ } else
+ strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl);
+
+ for (i = 0; i < e->sad_count; i++) {
+ if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
+ snd_printd(KERN_INFO "out of range SAD %d\n", i);
+ goto out_fail;
+ }
+ hdmi_update_short_audio_desc(e->sad + i,
+ buf + ELD_FIXED_BYTES + mnl + 3 * i);
+ }
+
+ return 0;
+
+out_fail:
+ e->eld_ver = 0;
+ return -EINVAL;
+}
+
+static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid)
+{
+ return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0);
+}
+
+static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
+{
+ int eldv;
+ int present;
+
+ present = hdmi_present_sense(codec, nid);
+ eldv = (present & AC_PINSENSE_ELDV);
+ present = (present & AC_PINSENSE_PRESENCE);
+
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv);
+#endif
+
+ return eldv && present;
+}
+
+int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
+{
+ return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
+ AC_DIPSIZE_ELD_BUF);
+}
+
+int hdmi_get_eld(struct sink_eld *eld,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ int i;
+ int ret;
+ int size;
+ unsigned char *buf;
+
+ if (!hdmi_eld_valid(codec, nid))
+ return -ENOENT;
+
+ size = hdmi_get_eld_size(codec, nid);
+ if (size == 0) {
+ /* wfg: workaround for ASUS P5E-VM HDMI board */
+ snd_printd(KERN_INFO "ELD buf size is 0, force 128\n");
+ size = 128;
+ }
+ if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) {
+ snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size);
+ return -ERANGE;
+ }
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < size; i++)
+ buf[i] = hdmi_get_eld_byte(codec, nid, i);
+
+ ret = hdmi_update_sink_eld(eld, buf, size);
+
+ kfree(buf);
+ return ret;
+}
+
+static void hdmi_show_short_audio_desc(struct cea_sad *a)
+{
+ printk(KERN_INFO "coding type: %s\n",
+ cea_audio_coding_type_names[a->format]);
+ printk(KERN_INFO "channels: %d\n", a->channels);
+ printk(KERN_INFO "sampling frequencies: 0x%x\n", a->rates);
+
+ if (a->format == AUDIO_CODING_TYPE_LPCM)
+ printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits);
+
+ if (a->max_bitrate)
+ printk(KERN_INFO "max bitrate: %d HZ\n", a->max_bitrate);
+
+ if (a->profile)
+ printk(KERN_INFO "profile: %d\n", a->profile);
+}
+
+static void hdmi_print_speaker_allocations(int spk_alloc, char *buf, int buflen)
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
+ if (spk_alloc & (1 << i))
+ j += snprintf(buf + j, buflen - j, " %s",
+ cea_speaker_allocation_names[i]);
+ }
+ buf[j] = '\0'; /* necessary when j == 0 */
+}
+
+void hdmi_show_eld(struct sink_eld *e)
+{
+ int i;
+ char buf[80];
+
+ printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size);
+ printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len);
+ printk(KERN_INFO "vendor block len is %d\n",
+ e->eld_size - e->baseline_len * 4 - 4);
+ printk(KERN_INFO "ELD version is %s\n",
+ eld_versoin_names[e->eld_ver]);
+ printk(KERN_INFO "CEA EDID version is %s\n",
+ cea_edid_version_names[e->cea_edid_ver]);
+ printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id);
+ printk(KERN_INFO "product id is 0x%x\n", e->product_id);
+ printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id);
+ printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp);
+ printk(KERN_INFO "AI support is %d\n", e->support_ai);
+ printk(KERN_INFO "SAD count is %d\n", e->sad_count);
+ printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay);
+ printk(KERN_INFO "connection type is %s\n",
+ eld_connection_type_names[e->conn_type]);
+ printk(KERN_INFO "monitor name is %s\n", e->monitor_name);
+
+ hdmi_print_speaker_allocations(e->spk_alloc, buf, sizeof(buf));
+ printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf);
+
+ for (i = 0; i < e->sad_count; i++)
+ hdmi_show_short_audio_desc(e->sad + i);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void hdmi_print_sad_info(int i, struct cea_sad *a,
+ struct snd_info_buffer *buffer)
+{
+ snd_iprintf(buffer, "sad%d_coding_type\t%s\n",
+ i, cea_audio_coding_type_names[a->format]);
+ snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels);
+ snd_iprintf(buffer, "sad%d_sampling_rates\t0x%x\n", i, a->rates);
+
+ if (a->format == AUDIO_CODING_TYPE_LPCM)
+ snd_iprintf(buffer, "sad%d_sample_bits\t0x%x\n", i, a->sample_bits);
+
+ if (a->max_bitrate)
+ snd_iprintf(buffer, "sad%d_max_bitrate\t%d HZ\n",
+ i, a->max_bitrate);
+
+ if (a->profile)
+ snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
+}
+
+static void hdmi_print_eld_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct sink_eld *e = entry->private_data;
+ char buf[80];
+ int i;
+
+ snd_iprintf(buffer, "monitor name\t\t%s\n", e->monitor_name);
+ snd_iprintf(buffer, "connection_type\t\t%s\n",
+ eld_connection_type_names[e->conn_type]);
+ snd_iprintf(buffer, "eld_version\t\t%d:%s\n", e->eld_ver,
+ eld_versoin_names[e->eld_ver]);
+ snd_iprintf(buffer, "edid_version\t\t%d:%s\n", e->cea_edid_ver,
+ cea_edid_version_names[e->cea_edid_ver]);
+ snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
+ snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id);
+ snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id);
+ snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp);
+ snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai);
+ snd_iprintf(buffer, "audio_sync_delay\t%d ms\n", e->aud_synch_delay);
+
+ hdmi_print_speaker_allocations(e->spk_alloc, buf, sizeof(buf));
+ snd_iprintf(buffer, "speakers\t\t%s\n", buf);
+
+ snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
+
+ for (i = 0; i < e->sad_count; i++)
+ hdmi_print_sad_info(i, e->sad + i, buffer);
+}
+
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld)
+{
+ char name[32];
+ struct snd_info_entry *entry;
+ int err;
+
+ snprintf(name, sizeof(name), "eld#%d", codec->addr);
+ err = snd_card_proc_new(codec->bus->card, name, &entry);
+ if (err < 0)
+ return err;
+
+ snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
+ return 0;
+}
+
+#endif
--- sound-2.6.orig/sound/pci/Kconfig
+++ sound-2.6/sound/pci/Kconfig
@@ -582,6 +582,10 @@ config SND_HDA_CODEC_INTELHDMI
Say Y here to include INTEL HDMI HD-audio codec support in
snd-hda-intel driver, such as Eaglelake integrated HDMI.
+config SND_HDA_ELD
+ def_bool y
+ depends on SND_HDA_CODEC_INTELHDMI
+
config SND_HDA_CODEC_CONEXANT
bool "Build Conexant HD-audio codec support"
depends on SND_HDA_INTEL
--- sound-2.6.orig/sound/pci/hda/Makefile
+++ sound-2.6/sound/pci/hda/Makefile
@@ -4,6 +4,7 @@ snd-hda-intel-y := hda_intel.o
# designed to be individual modules
snd-hda-intel-y += hda_codec.o
snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
+snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o
snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
--- sound-2.6.orig/sound/pci/hda/hda_local.h
+++ sound-2.6/sound/pci/hda/hda_local.h
@@ -276,15 +276,6 @@ static inline int snd_hda_parse_generic_
#endif
/*
- * generic proc interface
- */
-#ifdef CONFIG_PROC_FS
-int snd_hda_codec_proc_new(struct hda_codec *codec);
-#else
-static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
-#endif
-
-/*
* Misc
*/
int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
@@ -440,4 +431,57 @@ int snd_hda_check_amp_list_power(struct
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
+/*
+ * CEA Short Audio Descriptor data
+ */
+struct cea_sad {
+ int channels;
+ int format; /* (format == 0) indicates invalid SAD */
+ int rates;
+ int sample_bits; /* for LPCM */
+ int max_bitrate; /* for AC3...ATRAC */
+ int profile; /* for WMAPRO */
+};
+
+#define ELD_FIXED_BYTES 20
+#define ELD_MAX_MNL 16
+#define ELD_MAX_SAD 16
+
+/*
+ * ELD: EDID Like Data
+ */
+struct sink_eld {
+ int eld_size;
+ int baseline_len;
+ int eld_ver; /* (eld_ver == 0) indicates invalid ELD */
+ int cea_edid_ver;
+ char monitor_name[ELD_MAX_MNL + 1];
+ int manufacture_id;
+ int product_id;
+ u64 port_id;
+ int support_hdcp;
+ int support_ai;
+ int conn_type;
+ int aud_synch_delay;
+ int spk_alloc;
+ int sad_count;
+ struct cea_sad sad[ELD_MAX_SAD];
+};
+
+int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
+int hdmi_get_eld(struct sink_eld *eld, struct hda_codec *codec, hda_nid_t nid);
+void hdmi_show_eld(struct sink_eld *eld);
+
+/*
+ * generic proc interface
+ */
+#ifdef CONFIG_PROC_FS
+int snd_hda_codec_proc_new(struct hda_codec *codec);
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld);
+#else
+static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
+static inline int snd_hda_eld_proc_new(struct hda_codec *codec,
+ struct sink_eld *eld) { return 0; }
+#endif
+
#endif /* __SOUND_HDA_LOCAL_H */
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
[not found] <20081113022153.GB6844@mail.ustc.edu.cn>
@ 2008-11-13 2:36 ` Wu Fengguang
0 siblings, 0 replies; 20+ messages in thread
From: Wu Fengguang @ 2008-11-13 2:36 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
On Thu, Nov 13, 2008 at 10:21:53AM +0800, Wu Fengguang wrote:
> Create hda_eld.c for ELD routines and proc interface.
Here is a simple example of the proc interface, in which the ELD data
structure has not been populated yet:
# cat /proc/asound/card0/eld\#3
monitor name
connection_type HDMI
eld_version 0:reserved
edid_version 0:no CEA EDID Timing Extension block present
manufacture_id 0x0
product_id 0x0
port_id 0x0
support_hdcp 0
support_ai 0
audio_sync_delay 0
speakers
sad_count 0
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
2008-11-13 2:21 [RFC][PATCH] ELD routines and proc interface Wu Fengguang
@ 2008-11-13 7:26 ` Takashi Iwai
2008-11-14 1:34 ` Wu Fengguang
[not found] ` <20081119071135.GA17733@csy.ca>
1 sibling, 1 reply; 20+ messages in thread
From: Takashi Iwai @ 2008-11-13 7:26 UTC (permalink / raw)
To: Wu Fengguang; +Cc: alsa-devel
At Thu, 13 Nov 2008 10:21:53 +0800,
Wu Fengguang wrote:
>
> Create hda_eld.c for ELD routines and proc interface.
Thanks for the patch!
> ELD handling routines can be shared by all HDMI codecs,
> and they are large enough to make a standalone source file.
>
> Some notes on the code:
>
> - Shall we show an empty file if the ELD content is not valid?
> Well it's not that simple. There could be partially populated ELD,
> and there may be malformed ELD provided by buggy drivers/monitors.
> So I tend to expose ELD as it is.
Fair enough.
> - hdmi_show_eld() and hdmi_print_eld_info() are somehow duplicated
> The plan is to shrink hdmi_show_eld()/hdmi_show_short_audio_desc(), and to
> show a compact message at monitor hotplug and driver initialization time.
You can create a common print function to accept the callback, such
as,
static void hdmi_print(void (*print)(void *, const char *line), void *data,
const char *fmt, ...)
{
char line[80];
va_list ap;
va_start(fp, fmt);
vsnprintf(line, sizeof(line), fmt, ap);
va_end(ap);
print(data, line);
}
static void hdmi_print_eld(void (*print)(void *, const char *), void *data,
struct sink_eld *e)
{
hdmi_print(print, data, "monitor name\t\t%s\n", e->monitor_name);
...
}
static void print_proc(void *data, const char *line)
{
snd_iprintf(data, "%s", line);
}
static void hdmi_print_eld_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
hdmi_print_eld(print_proc, buffer, entry->private_data);
}
static void print_console(void *data, const char *line)
{
printk(KERN_DEBUG "%s", line);
}
void snd_hdmi_show_eld(struct sink_eld *e)
{
hdmi_print_eld(print_console, NULL, e);
}
Just an idea, though.
> - The ELD retrieval routines rely on the Intel HDA interface,
> others are/could be universal and independent ones.
>
> - The ELD proc interface code could be moved to hda_proc.c if necessary.
> - How do we name the proc file?
> If there are going to be two HDMI pins per codec, then the current naming
> scheme (eld#<codec no>) will fail.
In theory, yes, but I don't think this would happen.
If this is needed, the currently existing codec#* proc must be fixed,
too. So, we can use eld#codec as the simplest way.
Some review comments below:
> --- sound-2.6.orig/sound/pci/hda/patch_intelhdmi.c
> +++ sound-2.6/sound/pci/hda/patch_intelhdmi.c
...
> @@ -880,6 +410,11 @@ static int intel_hdmi_build_controls(str
>
> static int intel_hdmi_init(struct hda_codec *codec)
> {
> + struct intel_hdmi_spec *spec = codec->spec;
> + struct sink_eld *eld = &spec->sink;
> +
> + snd_hda_eld_proc_new(codec, eld);
The proc creation should be rather in patch_intelhdmi().
The init callback is called also at suspend/resume usually.
> /* disable audio output as early as possible */
> hdmi_disable_output(codec);
>
> @@ -927,3 +462,4 @@ struct hda_codec_preset snd_hda_preset_i
> { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
> {} /* terminator */
> };
> +
Useless space addition.
> --- /dev/null
> +++ sound-2.6/sound/pci/hda/hda_eld.c
> +static inline unsigned char grab_bits(const unsigned char *buf,
> + int byte, int lowbit, int bits)
> +{
> + BUG_ON(lowbit > 7);
> + BUG_ON(bits > 8);
> + BUG_ON(bits <= 0);
Can it be rather BUILD_BUG_ON(), BTW?
Or, hmm, doesn't work if it's an inline function?
> +int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
I prefer snd_ prefix for global functions to avoid any potential name
crashes.
> +int hdmi_get_eld(struct sink_eld *eld,
> + struct hda_codec *codec, hda_nid_t nid)
Ditto.
> +void hdmi_show_eld(struct sink_eld *e)
Ditto.
> --- sound-2.6.orig/sound/pci/hda/Makefile
> +++ sound-2.6/sound/pci/hda/Makefile
> @@ -4,6 +4,7 @@ snd-hda-intel-y := hda_intel.o
> # designed to be individual modules
> snd-hda-intel-y += hda_codec.o
> snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
> +snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o
> snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
> snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
> snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
> --- sound-2.6.orig/sound/pci/hda/hda_local.h
> +++ sound-2.6/sound/pci/hda/hda_local.h
> @@ -276,15 +276,6 @@ static inline int snd_hda_parse_generic_
> #endif
>
> /*
> - * generic proc interface
> - */
> -#ifdef CONFIG_PROC_FS
> -int snd_hda_codec_proc_new(struct hda_codec *codec);
> -#else
> -static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
> -#endif
...
> +/*
> + * generic proc interface
> + */
> +#ifdef CONFIG_PROC_FS
> +int snd_hda_codec_proc_new(struct hda_codec *codec);
> +int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld);
I'd put these two declarations rather separately, since
snd_hda_proc_new() has nothing to do with ELD. Keep it in the
original place.
thanks,
Takashi
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
2008-11-13 7:26 ` Takashi Iwai
@ 2008-11-14 1:34 ` Wu Fengguang
2008-11-14 7:25 ` Takashi Iwai
0 siblings, 1 reply; 20+ messages in thread
From: Wu Fengguang @ 2008-11-14 1:34 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
On Thu, Nov 13, 2008 at 08:26:48AM +0100, Takashi Iwai wrote:
> At Thu, 13 Nov 2008 10:21:53 +0800,
> Wu Fengguang wrote:
> >
> > Create hda_eld.c for ELD routines and proc interface.
>
> Thanks for the patch!
I take it as my responsibility :)
> > ELD handling routines can be shared by all HDMI codecs,
> > and they are large enough to make a standalone source file.
> >
> > Some notes on the code:
> >
> > - Shall we show an empty file if the ELD content is not valid?
> > Well it's not that simple. There could be partially populated ELD,
> > and there may be malformed ELD provided by buggy drivers/monitors.
> > So I tend to expose ELD as it is.
>
> Fair enough.
>
> > - hdmi_show_eld() and hdmi_print_eld_info() are somehow duplicated
> > The plan is to shrink hdmi_show_eld()/hdmi_show_short_audio_desc(), and to
> > show a compact message at monitor hotplug and driver initialization time.
>
> You can create a common print function to accept the callback, such
> as,
>
> static void hdmi_print(void (*print)(void *, const char *line), void *data,
> const char *fmt, ...)
> {
> char line[80];
> va_list ap;
> va_start(fp, fmt);
> vsnprintf(line, sizeof(line), fmt, ap);
> va_end(ap);
> print(data, line);
> }
>
> static void hdmi_print_eld(void (*print)(void *, const char *), void *data,
> struct sink_eld *e)
> {
> hdmi_print(print, data, "monitor name\t\t%s\n", e->monitor_name);
> ...
> }
>
> static void print_proc(void *data, const char *line)
> {
> snd_iprintf(data, "%s", line);
> }
>
> static void hdmi_print_eld_info(struct snd_info_entry *entry,
> struct snd_info_buffer *buffer)
> {
> hdmi_print_eld(print_proc, buffer, entry->private_data);
> }
>
> static void print_console(void *data, const char *line)
> {
> printk(KERN_DEBUG "%s", line);
> }
>
> void snd_hdmi_show_eld(struct sink_eld *e)
> {
> hdmi_print_eld(print_console, NULL, e);
> }
>
> Just an idea, though.
Wow, it would be really nice trick for a big project!
But in this case, it seems to create more code than it can reduce...
Anyway my point is that, there seems to pointless to show full
detailed ELD info in dmesg.
> > - The ELD retrieval routines rely on the Intel HDA interface,
> > others are/could be universal and independent ones.
> >
> > - The ELD proc interface code could be moved to hda_proc.c if necessary.
>
> > - How do we name the proc file?
> > If there are going to be two HDMI pins per codec, then the current naming
> > scheme (eld#<codec no>) will fail.
>
> In theory, yes, but I don't think this would happen.
> If this is needed, the currently existing codec#* proc must be fixed,
> too. So, we can use eld#codec as the simplest way.
I mean one HDMI codec equipped with two output converters and two HDMI pins.
In this case there could be two HDMI sinks mapped to one single codec.
Or it would be trivial to do the rename in the future anyway?
> Some review comments below:
>
> > --- sound-2.6.orig/sound/pci/hda/patch_intelhdmi.c
> > +++ sound-2.6/sound/pci/hda/patch_intelhdmi.c
> ...
> > @@ -880,6 +410,11 @@ static int intel_hdmi_build_controls(str
> >
> > static int intel_hdmi_init(struct hda_codec *codec)
> > {
> > + struct intel_hdmi_spec *spec = codec->spec;
> > + struct sink_eld *eld = &spec->sink;
> > +
> > + snd_hda_eld_proc_new(codec, eld);
>
> The proc creation should be rather in patch_intelhdmi().
> The init callback is called also at suspend/resume usually.
OK, fixed.
> > /* disable audio output as early as possible */
> > hdmi_disable_output(codec);
> >
> > @@ -927,3 +462,4 @@ struct hda_codec_preset snd_hda_preset_i
> > { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
> > {} /* terminator */
> > };
> > +
>
> Useless space addition.
Fixed, wondering how it slipped in.
>
> > --- /dev/null
> > +++ sound-2.6/sound/pci/hda/hda_eld.c
> > +static inline unsigned char grab_bits(const unsigned char *buf,
> > + int byte, int lowbit, int bits)
> > +{
> > + BUG_ON(lowbit > 7);
> > + BUG_ON(bits > 8);
> > + BUG_ON(bits <= 0);
>
> Can it be rather BUILD_BUG_ON(), BTW?
> Or, hmm, doesn't work if it's an inline function?
Yes, converted to BUILD_BUG_ON() and it compiles OK.
> > +int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
>
> I prefer snd_ prefix for global functions to avoid any potential name
> crashes.
OK.
> > +int hdmi_get_eld(struct sink_eld *eld,
> > + struct hda_codec *codec, hda_nid_t nid)
>
> Ditto.
>
> > +void hdmi_show_eld(struct sink_eld *e)
>
> Ditto.
Three renames done.
> > --- sound-2.6.orig/sound/pci/hda/Makefile
> > +++ sound-2.6/sound/pci/hda/Makefile
> > @@ -4,6 +4,7 @@ snd-hda-intel-y := hda_intel.o
> > # designed to be individual modules
> > snd-hda-intel-y += hda_codec.o
> > snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
> > +snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o
> > snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
> > snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
> > snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
> > --- sound-2.6.orig/sound/pci/hda/hda_local.h
> > +++ sound-2.6/sound/pci/hda/hda_local.h
> > @@ -276,15 +276,6 @@ static inline int snd_hda_parse_generic_
> > #endif
> >
> > /*
> > - * generic proc interface
> > - */
> > -#ifdef CONFIG_PROC_FS
> > -int snd_hda_codec_proc_new(struct hda_codec *codec);
> > -#else
> > -static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
> > -#endif
> ...
> > +/*
> > + * generic proc interface
> > + */
> > +#ifdef CONFIG_PROC_FS
> > +int snd_hda_codec_proc_new(struct hda_codec *codec);
> > +int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld);
>
> I'd put these two declarations rather separately, since
> snd_hda_proc_new() has nothing to do with ELD. Keep it in the
> original place.
OK.
Thank you,
Fengguang
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
2008-11-14 1:34 ` Wu Fengguang
@ 2008-11-14 7:25 ` Takashi Iwai
2008-11-14 7:38 ` Wu Fengguang
0 siblings, 1 reply; 20+ messages in thread
From: Takashi Iwai @ 2008-11-14 7:25 UTC (permalink / raw)
To: Wu Fengguang; +Cc: alsa-devel
At Fri, 14 Nov 2008 09:34:32 +0800,
Wu Fengguang wrote:
>
> > > - How do we name the proc file?
> > > If there are going to be two HDMI pins per codec, then the current naming
> > > scheme (eld#<codec no>) will fail.
> >
> > In theory, yes, but I don't think this would happen.
> > If this is needed, the currently existing codec#* proc must be fixed,
> > too. So, we can use eld#codec as the simplest way.
>
> I mean one HDMI codec equipped with two output converters and two HDMI pins.
> In this case there could be two HDMI sinks mapped to one single codec.
>
> Or it would be trivial to do the rename in the future anyway?
Ah, OK, understood. One easy solution is to name the proc file with
either pin of audio-out widget NID.
But I'm not sure whether it's worth. The proc file naming isn't
strict, so I'd leave it as is.
> > > --- /dev/null
> > > +++ sound-2.6/sound/pci/hda/hda_eld.c
> > > +static inline unsigned char grab_bits(const unsigned char *buf,
> > > + int byte, int lowbit, int bits)
> > > +{
> > > + BUG_ON(lowbit > 7);
> > > + BUG_ON(bits > 8);
> > > + BUG_ON(bits <= 0);
> >
> > Can it be rather BUILD_BUG_ON(), BTW?
> > Or, hmm, doesn't work if it's an inline function?
>
> Yes, converted to BUILD_BUG_ON() and it compiles OK.
The question is whether this really triggers the build error
properly. Could you check it, simply by changing the caller of
grab_bits() with some invalid values? Then you should get a compile
error.
thanks,
Takashi
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
2008-11-14 7:25 ` Takashi Iwai
@ 2008-11-14 7:38 ` Wu Fengguang
2008-11-14 7:43 ` Takashi Iwai
0 siblings, 1 reply; 20+ messages in thread
From: Wu Fengguang @ 2008-11-14 7:38 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
On Fri, Nov 14, 2008 at 08:25:51AM +0100, Takashi Iwai wrote:
> At Fri, 14 Nov 2008 09:34:32 +0800,
> Wu Fengguang wrote:
> >
> > > > - How do we name the proc file?
> > > > If there are going to be two HDMI pins per codec, then the current naming
> > > > scheme (eld#<codec no>) will fail.
> > >
> > > In theory, yes, but I don't think this would happen.
> > > If this is needed, the currently existing codec#* proc must be fixed,
> > > too. So, we can use eld#codec as the simplest way.
> >
> > I mean one HDMI codec equipped with two output converters and two HDMI pins.
> > In this case there could be two HDMI sinks mapped to one single codec.
> >
> > Or it would be trivial to do the rename in the future anyway?
>
> Ah, OK, understood. One easy solution is to name the proc file with
> either pin of audio-out widget NID.
>
> But I'm not sure whether it's worth. The proc file naming isn't
> strict, so I'd leave it as is.
OK, I'll leave it as is: there should be no many dependencies on it.
> > > > --- /dev/null
> > > > +++ sound-2.6/sound/pci/hda/hda_eld.c
> > > > +static inline unsigned char grab_bits(const unsigned char *buf,
> > > > + int byte, int lowbit, int bits)
> > > > +{
> > > > + BUG_ON(lowbit > 7);
> > > > + BUG_ON(bits > 8);
> > > > + BUG_ON(bits <= 0);
> > >
> > > Can it be rather BUILD_BUG_ON(), BTW?
> > > Or, hmm, doesn't work if it's an inline function?
> >
> > Yes, converted to BUILD_BUG_ON() and it compiles OK.
>
> The question is whether this really triggers the build error
> properly. Could you check it, simply by changing the caller of
> grab_bits() with some invalid values? Then you should get a compile
> error.
BUILD_BUG_ON() won't emit errors! So use BUG_ON()?
Thank you,
Fengguang
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
2008-11-14 7:38 ` Wu Fengguang
@ 2008-11-14 7:43 ` Takashi Iwai
2008-11-14 7:47 ` Wu Fengguang
0 siblings, 1 reply; 20+ messages in thread
From: Takashi Iwai @ 2008-11-14 7:43 UTC (permalink / raw)
To: Wu Fengguang; +Cc: alsa-devel
At Fri, 14 Nov 2008 15:38:56 +0800,
Wu Fengguang wrote:
>
> > > > > --- /dev/null
> > > > > +++ sound-2.6/sound/pci/hda/hda_eld.c
> > > > > +static inline unsigned char grab_bits(const unsigned char *buf,
> > > > > + int byte, int lowbit, int bits)
> > > > > +{
> > > > > + BUG_ON(lowbit > 7);
> > > > > + BUG_ON(bits > 8);
> > > > > + BUG_ON(bits <= 0);
> > > >
> > > > Can it be rather BUILD_BUG_ON(), BTW?
> > > > Or, hmm, doesn't work if it's an inline function?
> > >
> > > Yes, converted to BUILD_BUG_ON() and it compiles OK.
> >
> > The question is whether this really triggers the build error
> > properly. Could you check it, simply by changing the caller of
> > grab_bits() with some invalid values? Then you should get a compile
> > error.
>
> BUILD_BUG_ON() won't emit errors! So use BUG_ON()?
Try to make grab_bits() a macro and check whether BUILD_BUG_ON()
works. I think it won't be too bad to use a macro for such a pretty
simple case. If the resultant code looks too ugly, we should switch
back to BUG_ON().
The difference is that BUILD_BUG_ON() would add no real code while
BUG_ON() is a pure run-time check.
thanks,
Takashi
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
2008-11-14 7:43 ` Takashi Iwai
@ 2008-11-14 7:47 ` Wu Fengguang
2008-11-14 7:50 ` Takashi Iwai
0 siblings, 1 reply; 20+ messages in thread
From: Wu Fengguang @ 2008-11-14 7:47 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
On Fri, Nov 14, 2008 at 08:43:59AM +0100, Takashi Iwai wrote:
> At Fri, 14 Nov 2008 15:38:56 +0800,
> Wu Fengguang wrote:
> >
> > > > > > --- /dev/null
> > > > > > +++ sound-2.6/sound/pci/hda/hda_eld.c
> > > > > > +static inline unsigned char grab_bits(const unsigned char *buf,
> > > > > > + int byte, int lowbit, int bits)
> > > > > > +{
> > > > > > + BUG_ON(lowbit > 7);
> > > > > > + BUG_ON(bits > 8);
> > > > > > + BUG_ON(bits <= 0);
> > > > >
> > > > > Can it be rather BUILD_BUG_ON(), BTW?
> > > > > Or, hmm, doesn't work if it's an inline function?
> > > >
> > > > Yes, converted to BUILD_BUG_ON() and it compiles OK.
> > >
> > > The question is whether this really triggers the build error
> > > properly. Could you check it, simply by changing the caller of
> > > grab_bits() with some invalid values? Then you should get a compile
> > > error.
> >
> > BUILD_BUG_ON() won't emit errors! So use BUG_ON()?
>
> Try to make grab_bits() a macro and check whether BUILD_BUG_ON()
> works. I think it won't be too bad to use a macro for such a pretty
> simple case. If the resultant code looks too ugly, we should switch
> back to BUG_ON().
OK, I'm fine with a macro.
> The difference is that BUILD_BUG_ON() would add no real code while
> BUG_ON() is a pure run-time check.
But the code should be optimize away by gcc when the constant
expression is false?
Thanks,
Fengguang
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
2008-11-14 7:47 ` Wu Fengguang
@ 2008-11-14 7:50 ` Takashi Iwai
2008-11-14 8:02 ` Wu Fengguang
0 siblings, 1 reply; 20+ messages in thread
From: Takashi Iwai @ 2008-11-14 7:50 UTC (permalink / raw)
To: Wu Fengguang; +Cc: alsa-devel
At Fri, 14 Nov 2008 15:47:37 +0800,
Wu Fengguang wrote:
>
> On Fri, Nov 14, 2008 at 08:43:59AM +0100, Takashi Iwai wrote:
> > At Fri, 14 Nov 2008 15:38:56 +0800,
> > Wu Fengguang wrote:
> > >
> > > > > > > --- /dev/null
> > > > > > > +++ sound-2.6/sound/pci/hda/hda_eld.c
> > > > > > > +static inline unsigned char grab_bits(const unsigned char *buf,
> > > > > > > + int byte, int lowbit, int bits)
> > > > > > > +{
> > > > > > > + BUG_ON(lowbit > 7);
> > > > > > > + BUG_ON(bits > 8);
> > > > > > > + BUG_ON(bits <= 0);
> > > > > >
> > > > > > Can it be rather BUILD_BUG_ON(), BTW?
> > > > > > Or, hmm, doesn't work if it's an inline function?
> > > > >
> > > > > Yes, converted to BUILD_BUG_ON() and it compiles OK.
> > > >
> > > > The question is whether this really triggers the build error
> > > > properly. Could you check it, simply by changing the caller of
> > > > grab_bits() with some invalid values? Then you should get a compile
> > > > error.
> > >
> > > BUILD_BUG_ON() won't emit errors! So use BUG_ON()?
> >
> > Try to make grab_bits() a macro and check whether BUILD_BUG_ON()
> > works. I think it won't be too bad to use a macro for such a pretty
> > simple case. If the resultant code looks too ugly, we should switch
> > back to BUG_ON().
>
> OK, I'm fine with a macro.
>
> > The difference is that BUILD_BUG_ON() would add no real code while
> > BUG_ON() is a pure run-time check.
>
> But the code should be optimize away by gcc when the constant
> expression is false?
Well, I think BUG_ON() code remains in this case because it's no
constant check as it's in a function (although inlined). Otherwise
BUILD_BUG_ON() should have worked.
Takashi
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
2008-11-14 7:50 ` Takashi Iwai
@ 2008-11-14 8:02 ` Wu Fengguang
0 siblings, 0 replies; 20+ messages in thread
From: Wu Fengguang @ 2008-11-14 8:02 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
On Fri, Nov 14, 2008 at 08:50:44AM +0100, Takashi Iwai wrote:
> At Fri, 14 Nov 2008 15:47:37 +0800,
> Wu Fengguang wrote:
> >
> > On Fri, Nov 14, 2008 at 08:43:59AM +0100, Takashi Iwai wrote:
> > > At Fri, 14 Nov 2008 15:38:56 +0800,
> > > Wu Fengguang wrote:
> > > >
> > > > > > > > --- /dev/null
> > > > > > > > +++ sound-2.6/sound/pci/hda/hda_eld.c
> > > > > > > > +static inline unsigned char grab_bits(const unsigned char *buf,
> > > > > > > > + int byte, int lowbit, int bits)
> > > > > > > > +{
> > > > > > > > + BUG_ON(lowbit > 7);
> > > > > > > > + BUG_ON(bits > 8);
> > > > > > > > + BUG_ON(bits <= 0);
> > > > > > >
> > > > > > > Can it be rather BUILD_BUG_ON(), BTW?
> > > > > > > Or, hmm, doesn't work if it's an inline function?
> > > > > >
> > > > > > Yes, converted to BUILD_BUG_ON() and it compiles OK.
> > > > >
> > > > > The question is whether this really triggers the build error
> > > > > properly. Could you check it, simply by changing the caller of
> > > > > grab_bits() with some invalid values? Then you should get a compile
> > > > > error.
> > > >
> > > > BUILD_BUG_ON() won't emit errors! So use BUG_ON()?
> > >
> > > Try to make grab_bits() a macro and check whether BUILD_BUG_ON()
> > > works. I think it won't be too bad to use a macro for such a pretty
> > > simple case. If the resultant code looks too ugly, we should switch
> > > back to BUG_ON().
> >
> > OK, I'm fine with a macro.
> >
> > > The difference is that BUILD_BUG_ON() would add no real code while
> > > BUG_ON() is a pure run-time check.
> >
> > But the code should be optimize away by gcc when the constant
> > expression is false?
>
> Well, I think BUG_ON() code remains in this case because it's no
> constant check as it's in a function (although inlined). Otherwise
> BUILD_BUG_ON() should have worked.
Hehe, not so ugly as a macro:
#define GRAB_BITS(buf, byte, lowbit, bits) \
({ \
BUILD_BUG_ON(lowbit > 7); \
BUILD_BUG_ON(bits > 8); \
BUILD_BUG_ON(bits <= 0); \
\
(buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \
})
Cheers,
Fengguang
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
[not found] ` <20081119071135.GA17733@csy.ca>
@ 2008-11-19 7:17 ` Wu Fengguang
[not found] ` <20081119075545.GA19833@csy.ca>
0 siblings, 1 reply; 20+ messages in thread
From: Wu Fengguang @ 2008-11-19 7:17 UTC (permalink / raw)
To: Shane W; +Cc: alsa-devel
On Tue, Nov 18, 2008 at 11:11:35PM -0800, Shane W wrote:
> On Thu, Nov 13, 2008 at 10:21:53AM +0800, Wu Fengguang wrote:
> > Create hda_eld.c for ELD routines and proc interface.
>
> Hi,
Hi Shane,
> Just testing this and your multichannel HDMI code over here
> but it doesn't seem to get ELD data for my setup. Intel
> g45-id board with an Yamaha RX-v1800 receiver which is HDMI
> 1.3 capable.
Do you run the latest xorg intel driver? Also dmesg should tell us
something if anything goes wrong with ELD retrieving/parsing.
> shane@chintoka:~$ cat /proc/asound/Intel/eld#3
> monitor name
> connection_type HDMI
> eld_version [0x0] reserved
> edid_version [0x0] no CEA EDID Timing Extension
> block present
> manufacture_id 0x0
> product_id 0x0
> port_id 0x0
> support_hdcp 0
> support_ai 0
> audio_sync_delay 0
> speakers [0x0]
> sad_count 0
>
> 2ch audio is coming through just fine over HDMI though so
> the connection itself is there.
Yes. Obviously the ELD stuct has not been populated yet.
Thanks,
Fengguang
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
[not found] ` <20081119075545.GA19833@csy.ca>
@ 2008-11-19 8:08 ` Wu Fengguang
2008-11-19 9:39 ` [alsa-devel] " Wu Fengguang
0 siblings, 1 reply; 20+ messages in thread
From: Wu Fengguang @ 2008-11-19 8:08 UTC (permalink / raw)
To: Shane W; +Cc: alsa-devel
On Tue, Nov 18, 2008 at 11:55:45PM -0800, Shane W wrote:
> On Wed, Nov 19, 2008 at 03:17:57PM +0800, Wu Fengguang wrote:
> > On Tue, Nov 18, 2008 at 11:11:35PM -0800, Shane W wrote:
> > > On Thu, Nov 13, 2008 at 10:21:53AM +0800, Wu Fengguang wrote:
> > > > Create hda_eld.c for ELD routines and proc interface.
> >
> > > Just testing this and your multichannel HDMI code over here
> > > but it doesn't seem to get ELD data for my setup. Intel
> > > g45-id board with an Yamaha RX-v1800 receiver which is HDMI
> > > 1.3 capable.
> >
> > Do you run the latest xorg intel driver? Also dmesg should tell us
> > something if anything goes wrong with ELD retrieving/parsing.
>
> Yes though Xorg wasn't running when I was doing the audio
> tests. Pure console at that point but I fired up Xorg
> which is latest git as of today but still no ELD
Yeah sorry I missed one note. The xorg git tree only contains the
audio output enabling patches, but not yet ELD transferring patches.
(the ELD data flow is monitor => video driver => audio driver)
I called for the Xorg ELD enabling patches from Ma Ling just after
replying to your email. He should send the patches soon.
> population. When Xorg starts, I get this in dmesg:
> [drm] Initialized i915 1.6.0 20080730 on minor 0
> [drm:i915_gem_object_bind_to_gtt] *ERROR* GTT full, but LRU
> list empty
> [drm:i915_gem_object_pin] *ERROR* Failure to bind:
> -12<6>HDMI intrinsic event: PD=1 ELDV=1
This last dmesg line is funny. The ELDV(i.e. ELD Valid) is true,
but the video driver obviously has no ELD data prepared for us.
Thanks,
Fengguang
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [alsa-devel] [RFC][PATCH] ELD routines and proc interface
2008-11-19 8:08 ` Wu Fengguang
@ 2008-11-19 9:39 ` Wu Fengguang
[not found] ` <20081119200201.GA23246@csy.ca>
0 siblings, 1 reply; 20+ messages in thread
From: Wu Fengguang @ 2008-11-19 9:39 UTC (permalink / raw)
To: Shane W; +Cc: Ma, Ling, Fu, Michael, alsa-devel, intel-gfx, xorg
[-- Attachment #1: Type: text/plain, Size: 1491 bytes --]
On Wed, Nov 19, 2008 at 04:08:00PM +0800, Wu Fengguang wrote:
> On Tue, Nov 18, 2008 at 11:55:45PM -0800, Shane W wrote:
> > On Wed, Nov 19, 2008 at 03:17:57PM +0800, Wu Fengguang wrote:
> > > On Tue, Nov 18, 2008 at 11:11:35PM -0800, Shane W wrote:
> > > > On Thu, Nov 13, 2008 at 10:21:53AM +0800, Wu Fengguang wrote:
> > > > > Create hda_eld.c for ELD routines and proc interface.
> > >
> > > > Just testing this and your multichannel HDMI code over here
> > > > but it doesn't seem to get ELD data for my setup. Intel
> > > > g45-id board with an Yamaha RX-v1800 receiver which is HDMI
> > > > 1.3 capable.
> > >
> > > Do you run the latest xorg intel driver? Also dmesg should tell us
> > > something if anything goes wrong with ELD retrieving/parsing.
> >
> > Yes though Xorg wasn't running when I was doing the audio
> > tests. Pure console at that point but I fired up Xorg
> > which is latest git as of today but still no ELD
>
> Yeah sorry I missed one note. The xorg git tree only contains the
> audio output enabling patches, but not yet ELD transferring patches.
> (the ELD data flow is monitor => video driver => audio driver)
> I called for the Xorg ELD enabling patches from Ma Ling just after
> replying to your email. He should send the patches soon.
Hi Shane,
I managed to update the last working Xorg ELD patches to the latest
git tree, and they compile flawlessly. The attached 2 patches are for
xf86-video-intel/ and xserver/ respectively.
Thanks,
Fengguang
[-- Attachment #2: xorg-eld-intel.patch --]
[-- Type: text/x-diff, Size: 12845 bytes --]
---
src/i810_reg.h | 13 ++-
src/i830.h | 3
src/i830_hdmi.c | 64 +++++++++++++++
src/i830_modes.c | 189 +++++++++++++++++++++++++++++++++++++++++++++
src/i830_sdvo.c | 49 ++++++++++-
src/i830_sdvo.h | 2
6 files changed, 313 insertions(+), 7 deletions(-)
--- xf86-video-intel.orig/src/i810_reg.h
+++ xf86-video-intel/src/i810_reg.h
@@ -1240,6 +1240,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
# define HDMID_HOTPLUG_INT_EN (1 << 27)
# define SDVOB_HOTPLUG_INT_EN (1 << 26)
# define SDVOC_HOTPLUG_INT_EN (1 << 25)
+# define AUDIO_HOTPLUG_INT_EN (1 << 24)
# define TV_HOTPLUG_INT_EN (1 << 18)
# define CRT_HOTPLUG_INT_EN (1 << 9)
# define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8)
@@ -1271,7 +1272,17 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
# define CRT_HOTPLUG_MONITOR_NONE (0 << 8)
# define SDVOC_HOTPLUG_INT_STATUS (1 << 7)
# define SDVOB_HOTPLUG_INT_STATUS (1 << 6)
-
+#define AUDIO_VENDOR_DEVICE_ID 0x62020
+#define INTEL_AUDIO_DEVCL 0x808629FB
+#define INTEL_AUDIO_DEVBLC 0x80862801
+#define INTEL_AUDIO_DEVCTG 0x80862802
+
+#define AUDIO_CNTL_STATUS 0x620B4
+#define AUDIO_ELD_VALID_DEVCL_DEVBLC (1 << 13)
+#define AUDIO_ELD_VALID_DEVCTG (1 << 14)
+#define AUDIO_ELD_ADDR (0xf << 5)
+#define AUDIO_ELD_ACK (1 << 4)
+#define AUDIO_HDMIW_HDMIEDID 0x6210C
#define SDVOB 0x61140
#define SDVOC 0x61160
#define SDVO_ENABLE (1 << 31)
--- xf86-video-intel.orig/src/i830.h
+++ xf86-video-intel/src/i830.h
@@ -887,7 +887,8 @@ Bool I830UnbindAGPMemory(ScrnInfoPtr pSc
/* i830_modes.c */
DisplayModePtr i830_ddc_get_modes(xf86OutputPtr output);
-
+int i830_handle_cea_like_data(xf86OutputPtr output,Uchar **buf);
+unsigned long i830_extract_max_tmds_clock(xf86OutputPtr output);
/* i830_tv.c */
void i830_tv_init(ScrnInfoPtr pScrn);
--- xf86-video-intel.orig/src/i830_hdmi.c
+++ xf86-video-intel/src/i830_hdmi.c
@@ -45,12 +45,17 @@ struct i830_hdmi_priv {
static int
i830_hdmi_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
{
+ unsigned long tmds_max_clock = i830_extract_max_tmds_clock(output);
+
if (mode->Clock > 165000)
return MODE_CLOCK_HIGH;
if (mode->Clock < 20000)
return MODE_CLOCK_LOW;
+ if( 0 < tmds_max_clock && tmds_max_clock < mode->Clock)
+ return MODE_CLOCK_HIGH;
+
return MODE_OK;
}
@@ -64,6 +69,60 @@ i830_hdmi_mode_fixup(xf86OutputPtr outpu
return TRUE;
}
+static uint32_t i830_hdmi_get_eld_flag(I830Ptr pI830 )
+{
+ uint32_t ar ;
+
+ ar = INREG(AUDIO_VENDOR_DEVICE_ID);
+
+ if (INTEL_AUDIO_DEVBLC == ar || INTEL_AUDIO_DEVCL == ar) {
+ ar = AUDIO_ELD_VALID_DEVCL_DEVBLC;
+ } else {
+ ar = AUDIO_ELD_VALID_DEVCTG;
+ }
+
+ return ar;
+
+}
+
+static void i830_hdmi_set_edid_like_data(xf86OutputPtr output)
+{
+ I830Ptr pI830 = I830PTR(output->scrn);
+ uint32_t *eld;
+ int eld_len;
+ uint32_t ar;
+ uint32_t flag;
+ int i;
+
+
+ eld = NULL;
+ eld_len = i830_extract_cea_like_data(output, (Uchar **)&eld);
+ eld_len = eld_len / sizeof(uint32_t);
+
+ if (NULL == eld) {
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "HDMI failed to get ELD \n");
+ goto end;
+ }
+
+ flag = i830_hdmi_get_eld_flag(pI830);
+
+ ar = INREG(AUDIO_CNTL_STATUS);
+ ar &= ~(flag | AUDIO_ELD_ADDR);
+ OUTREG(AUDIO_CNTL_STATUS, ar);
+
+ for (i = 0; i < eld_len; i = i + 1)
+ OUTREG(AUDIO_HDMIW_HDMIEDID, eld[i]);
+
+ ar = INREG(AUDIO_CNTL_STATUS);
+ ar |= flag ;
+ OUTREG(AUDIO_CNTL_STATUS, ar);
+
+end:
+ if (NULL != eld )
+ xfree(eld);
+}
+
static void
i830_hdmi_mode_set(xf86OutputPtr output, DisplayModePtr mode,
DisplayModePtr adjusted_mode)
@@ -76,6 +135,8 @@ i830_hdmi_mode_set(xf86OutputPtr output,
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
uint32_t sdvox;
+ i830_hdmi_set_edid_like_data(output);
+
sdvox = SDVO_ENCODING_HDMI |
SDVO_BORDER_ENABLE |
SDVO_VSYNC_ACTIVE_HIGH |
@@ -165,7 +226,8 @@ i830_hdmi_detect(xf86OutputPtr output)
temp |
HDMIB_HOTPLUG_INT_EN |
HDMIC_HOTPLUG_INT_EN |
- HDMID_HOTPLUG_INT_EN);
+ HDMID_HOTPLUG_INT_EN |
+ AUDIO_HOTPLUG_INT_EN);
POSTING_READ(PORT_HOTPLUG_EN);
--- xf86-video-intel.orig/src/i830_modes.c
+++ xf86-video-intel/src/i830_modes.c
@@ -54,6 +54,195 @@
#include "xf86Modes.h"
#include <randrstr.h>
+#define CEA_LIKE_DATA_MAX_LEN 48
+struct eld_header{
+ Uchar rsv_0 :3;
+ Uchar ELD_ver :5;
+ Uchar rsv_1;
+ Uchar baseline_ELD_len;
+ Uchar rsv_3;
+}__attribute__ ((packed));
+
+struct eld_data_fixed_fields {
+ struct eld_header header;
+
+ /* byte 1 */
+ Uchar MNL :5;
+ Uchar CEA_EDID_ver :3;
+
+ /* byte 2 */
+ Uchar HDCP :1;
+ Uchar S_AI :1;
+ Uchar Conn_Type :2;
+ Uchar SAD_Count :4;
+
+ /* byte 3 */
+ Uchar Aud_Synch_Delay;
+
+ /* byte 4 */
+ Uchar FLR :1;
+ Uchar LFE :1;
+ Uchar FC :1;
+ Uchar RLR :1;
+ Uchar RC :1;
+ Uchar FLRC :1;
+ Uchar RLRC :1;
+ Uchar rsv_7 :1;
+
+ /* byte 5-12 */
+ Uchar Port_ID[8]; /* little endian */
+
+ /* byte 13-14 */
+ Uchar Manufacture_Name[2];
+ /* byte 15-16 */
+ Uchar Product_Code[2];
+
+ /* byte 17 len MNL */
+ char Monitor_Name[0];
+} __attribute__ ((packed));
+
+unsigned long i830_extract_max_tmds_clock(xf86OutputPtr output)
+{
+ struct cea_data_blk *blk ;
+ struct extension_type type;
+
+ unsigned long ret = 0;
+
+ if (0 == (EDID_CEA_EXTENSION_FLG & output->MonInfo->flags)) {
+ goto end;
+ }
+
+ type.body_type = CEA_EXT;
+ type.data_type = CEA_VENDOR_BLK;
+ blk = (struct cea_data_blk *)xf86DDCGetCEA( output->MonInfo,&type);
+
+ if (NULL != blk) {
+ if (VENDOR_OFFSET(struct cea_vendor_blk, hdmi.Max_TMDS_Clock) <=
+ blk->len) {
+ ret = blk->u.vendor.hdmi.Max_TMDS_Clock * HDMI_MAX_TMDS_UNIT;
+ }
+ }
+end:
+ return ret;
+}
+
+int i830_extract_cea_like_data(xf86OutputPtr output, Uchar **buf)
+{
+ struct eld_data_fixed_fields *eld;
+ struct cea_data_blk *blk ;
+ struct cea_audio_blk *audio;
+ struct extension_type type;
+ Uchar *name ;
+ int i;
+ int eld_len;
+ int SAD_Count;
+
+
+ if (0 == (EDID_CEA_EXTENSION_FLG & output->MonInfo->flags)) {
+ eld = NULL;
+ eld_len = 0;
+ goto end;
+ }
+
+ name = NULL;
+ audio = NULL;
+
+ eld_len = sizeof(struct eld_data_fixed_fields);
+
+ type.body_type = CEA_EXT;
+ type.data_type = CEA_AUDIO_BLK;
+ blk = (struct cea_data_blk *)xf86DDCGetCEA(output->MonInfo, &type);
+
+ SAD_Count = 0;
+ if (NULL != blk) {
+ audio = (struct cea_audio_blk *)&blk->u.audio;
+ eld_len = eld_len + blk->len;
+ SAD_Count = blk->len/3; // SAD_Count is multiple of 3 bytes
+ }
+
+ for (i=0; i<output->MonInfo->det_mon_num; i++) {
+ if (0xfc == output->MonInfo->det_mon[i].type){
+ eld_len = eld_len + EDID_DET_NAME_LEN ;
+ name = output->MonInfo->det_mon[i].section.name;
+ break;
+ }
+ }
+ /* The item need to be multiple of 8 because sdvo write 8 bytes one time */
+ eld_len = (eld_len + 7)/8;
+ eld_len = eld_len * 8;
+ eld = (struct eld_data_fixed_fields *)xcalloc(1, eld_len);
+
+ if (NULL == eld) {
+ eld_len = 0;
+ goto end;
+ }
+
+ memset((Uchar *)eld, 0, eld_len);
+ /* The item need to be multiple of 4 */
+ eld->header.baseline_ELD_len = (eld_len - sizeof(struct eld_header))/4;
+ eld->header.ELD_ver = CEA_EXT;
+ eld->HDCP = 0;
+ eld->CEA_EDID_ver = output->MonInfo->ver.version;
+ if (NULL != name) {
+ eld->MNL = EDID_DET_NAME_LEN;
+ }
+ eld->SAD_Count = SAD_Count;
+ type.body_type = CEA_EXT;
+ type.data_type = CEA_VENDOR_BLK;
+ blk = (struct cea_data_blk *)xf86DDCGetCEA( output->MonInfo,&type);
+
+ eld->Conn_Type = 0;
+ /* Currently do not consider about Interlaced mode.
+ * Because the member hdmi of vendor data block is extension part,
+ * it's length is flexible, we need to guarantee the boundary
+ * prior to fetching data.
+ */
+
+ if (NULL != blk) {
+ if (VENDOR_OFFSET(struct cea_vendor_blk, hdmi.Support_flags) <=
+ blk->len)
+ eld->S_AI = VENDOR_SUPPORT_AI(blk->u.vendor.hdmi.Support_flags);
+
+ if (VENDOR_OFFSET(struct cea_vendor_blk, hdmi.Audio_Latency) <=
+ blk->len) {
+ if (VENDOR_LATENCY_PRESENT(blk->u.vendor.hdmi.Latency_Present)) {
+ if(blk->u.vendor.hdmi.Audio_Latency)
+ eld->Aud_Synch_Delay = blk->u.vendor.hdmi.Audio_Latency - 1;
+ }
+ }
+ }
+
+ type.body_type = CEA_EXT;
+ type.data_type = CEA_SPEAKER_ALLOC_BLK;
+ blk = (struct cea_data_blk *)xf86DDCGetCEA(output->MonInfo,&type);
+ if (NULL != blk) {
+ eld->FLR = blk->u.speaker.FLR;
+ eld->LFE = blk->u.speaker.LFE;
+ eld->FC = blk->u.speaker.FC;
+ eld->RLR = blk->u.speaker.RLR;
+ eld->RC = blk->u.speaker.RC;
+ eld->FLRC = blk->u.speaker.FLRC;
+ eld->RLRC = blk->u.speaker.RLRC;
+ }
+
+ //eld->Port_ID /*TBD XXX*/
+ eld->Manufacture_Name[0] = output->MonInfo->vendor.name[0];
+ eld->Manufacture_Name[1] = output->MonInfo->vendor.name[1];
+ eld->Product_Code[0] = output->MonInfo->vendor.prod_id & 0xff;
+ eld->Product_Code[1] = output->MonInfo->vendor.prod_id >> 8;
+
+ if (NULL != name) {
+ memcpy(eld->Monitor_Name, name, EDID_DET_NAME_LEN);
+ }
+ if (NULL != audio) {
+ memcpy(eld->Monitor_Name + EDID_DET_NAME_LEN, audio,SAD_Count * 3);
+ }
+
+end:
+ *buf = eld;
+ return eld_len <= CEA_LIKE_DATA_MAX_LEN ? eld_len:CEA_LIKE_DATA_MAX_LEN ;
+}
+
DisplayModePtr
i830_ddc_get_modes (xf86OutputPtr output)
{
--- xf86-video-intel.orig/src/i830_sdvo.c
+++ xf86-video-intel/src/i830_sdvo.c
@@ -36,6 +36,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
* this code doesn't deal with either ganged mode or more than one SDVO output.
*/
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -889,10 +890,13 @@ struct dip_infoframe {
union {
struct {
/* Packet Byte #1 */
- uint8_t S:2;
- uint8_t B:2;
+ uint8_t S0: 1;
+ uint8_t S1:1;
+ uint8_t B0:1;
+ uint8_t B1:1;
uint8_t A:1;
- uint8_t Y:2;
+ uint8_t Y0:1;
+ uint8_t Y1:1;
uint8_t rsvd1:1;
/* Packet Byte #2 */
uint8_t R:4;
@@ -954,6 +958,36 @@ static void i830_sdvo_set_avi_infoframe(
SDVO_HBUF_TX_VSYNC);
}
+static void i830_sdvo_set_edid_like_data(xf86OutputPtr output)
+{
+ Uchar *eld;
+ int eld_len;
+ Uchar av_split;
+ Uchar eld_pre;
+
+ eld = NULL;
+ eld_len = i830_extract_cea_like_data(output, &eld);
+ if (NULL == eld)
+ goto end;
+
+ av_split = 7;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_AV_SPLIT,
+ &av_split, sizeof(Uchar));
+ av_split = 0;
+ i830_sdvo_set_hdmi_buf(output, av_split, eld, eld_len,
+ SDVO_HBUF_TX_DISABLED);
+
+ eld_pre = SDVO_ELD_PRESENT | SDVO_ELD_VALID;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_AUDIO_STAT,
+ &eld_pre, sizeof(Uchar));
+end:
+ if (NULL != eld)
+ xfree(eld);
+
+}
+
static Bool
i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
DisplayModePtr adjusted_mode)
@@ -1025,6 +1059,8 @@ i830_sdvo_mode_set(xf86OutputPtr output,
struct i830_sdvo_dtd input_dtd;
uint8_t status;
+ sdvox = 0;
+
if (!mode)
return;
@@ -1043,6 +1079,7 @@ i830_sdvo_mode_set(xf86OutputPtr output,
if (dev_priv->is_hdmi) {
i830_sdvo_set_avi_infoframe(output, mode);
+ i830_sdvo_set_edid_like_data(output);
sdvox |= SDVO_AUDIO_ENABLE;
}
@@ -1118,7 +1155,7 @@ i830_sdvo_mode_set(xf86OutputPtr output,
} else {
sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
}
-
+ sdvox = sdvox ;
i830_sdvo_write_sdvox(output, sdvox);
}
@@ -1264,6 +1301,7 @@ i830_sdvo_mode_valid(xf86OutputPtr outpu
{
I830OutputPrivatePtr intel_output = output->driver_private;
struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
+ unsigned long tmds_max_clock = i830_extract_max_tmds_clock(output);
if (pMode->Flags & V_DBLSCAN)
return MODE_NO_DBLESCAN;
@@ -1274,6 +1312,9 @@ i830_sdvo_mode_valid(xf86OutputPtr outpu
if (dev_priv->pixel_clock_max < pMode->Clock)
return MODE_CLOCK_HIGH;
+ if(0 != dev_priv->is_hdmi && 0 < tmds_max_clock && tmds_max_clock < pMode->Clock)
+ return MODE_CLOCK_HIGH;
+
return MODE_OK;
}
--- xf86-video-intel.orig/src/i830_sdvo.h
+++ xf86-video-intel/src/i830_sdvo.h
@@ -24,6 +24,8 @@
* Eric Anholt <eric@anholt.net>
*
*/
+#define SDVO_ELD_PRESENT (1 << 0)
+#define SDVO_ELD_VALID (1 << 1)
Bool
i830_sdvo_init(ScrnInfoPtr pScrn, int output_device);
[-- Attachment #3: xorg-eld-xserver.patch --]
[-- Type: text/x-diff, Size: 24641 bytes --]
---
hw/xfree86/ddc/edid.h | 101 ++++++++++++++++++++++++-
hw/xfree86/ddc/interpret_edid.c | 102 ++++++++++++++++++++++++-
hw/xfree86/ddc/print_edid.c | 9 +-
hw/xfree86/ddc/xf86DDC.c | 41 +++++++---
hw/xfree86/ddc/xf86DDC.h | 4 +
hw/xfree86/modes/xf86Crtc.c | 2
hw/xfree86/modes/xf86EdidModes.c | 114 +++++++++++++++++++++++++++--
7 files changed, 342 insertions(+), 31 deletions(-)
--- xserver.orig/hw/xfree86/ddc/edid.h
+++ xserver/hw/xfree86/ddc/edid.h
@@ -20,7 +20,7 @@
#define STD_TIMINGS 8
#define DET_TIMINGS 4
-
+#define EDID_DET_NAME_LEN 13
#ifdef _PARSE_EDID_
/* header: 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 */
@@ -519,9 +519,9 @@ struct detailed_monitor_section {
int type;
union {
struct detailed_timings d_timings; /* 56 */
- Uchar serial[13];
- Uchar ascii_data[13];
- Uchar name[13];
+ Uchar serial[EDID_DET_NAME_LEN];
+ Uchar ascii_data[EDID_DET_NAME_LEN];
+ Uchar name[EDID_DET_NAME_LEN];
struct monitor_ranges ranges; /* 56 */
struct std_timings std_t[5]; /* 80 */
struct whitePoints wp[2]; /* 32 */
@@ -533,6 +533,96 @@ struct detailed_monitor_section {
/* flags */
#define EDID_COMPLETE_RAWDATA 0x1
+#define EDID_CEA_EXTENSION_FLG 0x2
+
+#define CEA_EXT 2
+#define CEA_EXT_MIN_DATA_OFFSET 4
+#define CEA_EXT_MAX_DATA_OFFSET 127
+
+#define IEEE_ID_HDMI 0x000C03
+#define CEA_AUDIO_BLK 1
+#define CEA_VIDEO_BLK 2
+#define CEA_VENDOR_BLK 3
+#define CEA_SPEAKER_ALLOC_BLK 4
+#define CEA_VESA_DTC_BLK 5
+
+#define VENDOR_OFFSET(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#define VENDOR_SUPPORT_AI(x) (x >> 7)
+#define VENDOR_SUPPORT_DC_48bit(x) ( ( x >> 6) & 0x01)
+#define VENDOR_SUPPORT_DC_36bit(x) ( ( x >> 5) & 0x01)
+#define VENDOR_SUPPORT_DC_30bit(x) ( ( x >> 4) & 0x01)
+#define VENDOR_SUPPORT_DC_Y444(x) ( ( x >> 3) & 0x01)
+#define VENDOR_LATENCY_PRESENT(x) ( ( x >> 7) )
+#define VENDOR_LATENCY_PRESENT_I(x) ( ( x >> 6) & 0x01)
+#define HDMI_MAX_TMDS_UNIT (5000)
+struct cea_video_blk {
+ Uchar video_code; /* point to raw EDID data block */
+}__attribute__ ((packed));
+
+
+struct cea_audio_blk {
+ Uchar descs[3];
+}__attribute__ ((packed));
+struct hdmi {
+ Uchar Support_flags;
+ Uchar Max_TMDS_Clock;
+ Uchar Latency_Present;
+ Uchar Video_Latency;
+ Uchar Audio_Latency;
+ Uchar Interlaced_Video_Latency;
+ Uchar Interlaced_Audio_Latency;
+
+}__attribute__ ((packed));
+struct cea_vendor_blk {
+ unsigned char ieee_id[3];
+ Uchar Port_Addr[2];
+ struct hdmi hdmi;
+}__attribute__ ((packed));
+
+struct cea_speaker_blk
+{
+ Uchar FLR:1;
+ Uchar LFE:1;
+ Uchar FC:1;
+ Uchar RLR:1;
+ Uchar RC:1;
+ Uchar FLRC:1;
+ Uchar RLRC:1;
+ Uchar FLRW:1;
+ Uchar FLRH:1;
+ Uchar TC:1;
+ Uchar FCH:1;
+ Uchar Resv:5;
+ Uchar Resv_Byte;
+}__attribute__ ((packed));
+
+struct cea_data_blk {
+ Uchar len:5;
+ Uchar tag:3;
+union{
+ struct cea_video_blk video;
+ struct cea_audio_blk audio;
+ struct cea_vendor_blk vendor;
+ struct cea_speaker_blk speaker;
+ }u;
+}__attribute__ ((packed));
+struct cea_ext {
+ Uchar tag;
+ Uchar rev;
+ Uchar dt_offset;
+ Uchar flags;
+ struct cea_data_blk data_collection;
+}__attribute__ ((packed));
+struct extension_block {
+ union{
+ struct cea_ext cea;
+ }u;
+}__attribute__ ((packed));
+struct extension_type {
+ int body_type;
+ int data_type;
+}__attribute__ ((packed));
typedef struct {
int scrnIndex;
@@ -541,7 +631,8 @@ typedef struct {
struct disp_features features;
struct established_timings timings1;
struct std_timings timings2[8];
- struct detailed_monitor_section det_mon[4];
+ struct detailed_monitor_section det_mon[10];
+ int det_mon_num;
unsigned long flags;
int no_sections;
Uchar *rawData;
--- xserver.orig/hw/xfree86/ddc/interpret_edid.c
+++ xserver/hw/xfree86/ddc/interpret_edid.c
@@ -42,7 +42,7 @@ static void get_established_timing_secti
static void get_std_timing_section(Uchar*, struct std_timings *,
struct edid_version *);
static void get_dt_md_section(Uchar *, struct edid_version *,
- struct detailed_monitor_section *det_mon);
+ struct detailed_monitor_section *det_mon,int det_mon_num);
static void copy_string(Uchar *, Uchar *);
static void get_dst_timing_section(Uchar *, struct std_timings *,
struct edid_version *);
@@ -64,10 +64,10 @@ handle_edid_quirks(xf86MonPtr m)
* similar. Strictly we should refuse to round up too far, but let's
* see how well this works.
*/
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < m->det_mon_num; i++) {
if (m->det_mon[i].type == DS_RANGES) {
ranges = &m->det_mon[i].section.ranges;
- for (j = 0; j < 4; j++) {
+ for (j = 0; j < m->det_mon_num; j++) {
if (m->det_mon[j].type == DT) {
preferred_timing = &m->det_mon[j].section.d_timings;
if (!ranges->max_clock) continue; /* zero is legal */
@@ -99,7 +99,7 @@ handle_edid_quirks(xf86MonPtr m)
float target_aspect, timing_aspect;
target_aspect = (float)m->features.hsize / (float)m->features.vsize;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < m->det_mon_num; i++) {
if (m->det_mon[i].type == DT) {
struct detailed_timings *timing;
timing = &m->det_mon[i].section.d_timings;
@@ -132,6 +132,79 @@ handle_edid_quirks(xf86MonPtr m)
}
}
+Uchar * xf86DDCGetCEA(xf86MonPtr MonPtr, struct extension_type *type)
+{
+ struct extension_block *blk;
+ struct cea_ext *cea_blk;
+ struct cea_data_blk *data_collection;
+ Uchar *ret;
+ int data_len ;
+ int data_type;
+ int i;
+
+ ret = NULL;
+ blk = (struct extension_block *) (MonPtr->rawData + EDID1_LEN) ;
+
+ for (i = 0; i < MonPtr->no_sections; i++) {
+
+ if (CEA_EXT == blk ->u.cea.tag) {
+ ret = (Uchar *)&blk->u.cea;
+ if (CEA_EXT == type->body_type && 0 == type->data_type) {
+ goto end;
+ }
+ break;
+ }
+ blk =(struct extension_block *) ((Uchar * )blk + EDID1_LEN);
+ }
+
+ if (NULL == ret)
+ goto end;
+
+ cea_blk = (struct cea_ext *)ret;
+
+ ret = NULL;
+
+ if (CEA_EXT_MIN_DATA_OFFSET >= cea_blk->dt_offset)
+ goto end;
+
+ data_collection = &cea_blk->data_collection ;
+ data_len = 0;
+ while (data_len < cea_blk->dt_offset) {
+ if (type->data_type == data_collection->tag) {
+ ret = (unsigned char *)data_collection;
+ goto end;
+ }
+ data_len = data_len + data_collection->len + 1;
+ data_collection = (unsigned char *)data_collection + data_len ;
+ }
+
+
+end:
+ return ret;
+}
+
+static void get_cea_detail_timing(xf86MonPtr m, Uchar *blk )
+{
+ int dt_offset = ((struct cea_ext *)blk)->dt_offset;
+
+ if (CEA_EXT_MIN_DATA_OFFSET < dt_offset) {
+ goto end;
+ }
+
+ while (dt_offset < (CEA_EXT_MAX_DATA_OFFSET - DET_TIMING_INFO_LEN )) {
+
+ get_dt_md_section(blk + dt_offset, &m->ver,
+ m->det_mon + m->det_mon_num, 1);
+
+ m->det_mon_num = m->det_mon_num + 1 ;
+
+ _NEXT_DT_MD_SECTION(dt_offset);
+ }
+
+end:
+ return;
+}
+
xf86MonPtr
xf86InterpretEDID(int scrnIndex, Uchar *block)
{
@@ -151,9 +224,24 @@ xf86InterpretEDID(int scrnIndex, Uchar *
&m->timings1);
get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2,
&m->ver);
- get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon);
+ get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon,4);
+ m->det_mon_num = 4;
m->no_sections = (int)*(char *)SECTION(NO_EDID,block);
+
+ if (0 != m->no_sections) {
+ unsigned char *blk;
+ struct extension_type type;
+
+ type.body_type = CEA_EXT;
+ type.data_type = 0;
+ blk = xf86DDCGetCEA(m, &type) ;
+ if (NULL != blk) {
+ get_cea_detail_timing(m, blk);
+ m->flags = EDID_CEA_EXTENSION_FLG;
+ }
+ }
+
handle_edid_quirks(m);
return (m);
@@ -286,11 +374,11 @@ get_std_timing_section(Uchar *c, struct
static void
get_dt_md_section(Uchar *c, struct edid_version *ver,
- struct detailed_monitor_section *det_mon)
+ struct detailed_monitor_section *det_mon,int det_mon_num)
{
int i;
- for (i=0;i<DET_TIMINGS;i++) {
+ for (i=0;i<det_mon_num;i++) {
if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
switch (MONITOR_DESC_TYPE) {
--- xserver.orig/hw/xfree86/ddc/print_edid.c
+++ xserver/hw/xfree86/ddc/print_edid.c
@@ -335,11 +335,12 @@ print_detailed_timings(int scrnIndex, st
static void
print_detailed_monitor_section(int scrnIndex,
- struct detailed_monitor_section *m)
+ struct detailed_monitor_section *m,
+ int det_mon_num)
{
int i,j;
- for (i=0;i<DET_TIMINGS;i++) {
+ for (i=0;i<det_mon_num;i++) {
switch (m[i].type) {
case DT:
print_detailed_timings(scrnIndex,&m[i].section.d_timings);
@@ -473,12 +474,12 @@ xf86PrintEDID(xf86MonPtr m)
print_display(m->scrnIndex, &m->features, &m->ver);
print_established_timings(m->scrnIndex, &m->timings1);
print_std_timings(m->scrnIndex, m->timings2);
- print_detailed_monitor_section(m->scrnIndex, m->det_mon);
+ print_detailed_monitor_section(m->scrnIndex, m->det_mon, m->det_mon_num);
print_number_sections(m->scrnIndex, m->no_sections);
/* extension block section stuff */
- xf86DrvMsg(m->scrnIndex, X_INFO, "EDID (in hex):\n");
+ xf86DrvMsg(m->scrnIndex, X_INFO, "EDID (in hex): flags is <%d>\n",m->no_sections);
n = 128;
if (m->flags & EDID_COMPLETE_RAWDATA)
--- xserver.orig/hw/xfree86/ddc/xf86DDC.c
+++ xserver/hw/xfree86/ddc/xf86DDC.c
@@ -213,6 +213,7 @@ xf86DoEEDID(int scrnIndex, I2CBusPtr pBu
unsigned char *EDID_block = NULL;
xf86MonPtr tmp = NULL;
I2CDevPtr dev = NULL;
+ int i,n;
/* Default DDC and DDC2 to enabled. */
Bool noddc = FALSE, noddc2 = FALSE;
OptionInfoPtr options;
@@ -237,21 +238,41 @@ xf86DoEEDID(int scrnIndex, I2CBusPtr pBu
if (!EDID_block)
return NULL;
- if (DDC2Read(dev, 0, EDID_block)) {
- int i, n = EDID_block[0x7e];
-
- if (complete && n) {
- EDID_block = xrealloc(EDID_block, EDID1_LEN * (1+n));
-
- for (i = 0; i < n; i++)
- DDC2Read(dev, i+1, EDID_block + (EDID1_LEN * (1+i)));
+ if(FALSE == DDC2Read(dev, 0, EDID_block)){
+ xfree(EDID_block);
+ return NULL;
+ }
+
+
+ n = EDID_block[0x7e];
+
+ if (complete && n) {
+ int ret;
+
+ EDID_block = xrealloc(EDID_block, EDID1_LEN * (1+n));
+
+ if (!EDID_block)
+ return NULL;
+
+ for (i = 0; i < n; i++){
+ ret = DDC2Read(dev, i+1, EDID_block + (EDID1_LEN * (1+i)));
+ if(FALSE == ret){
+ xfree(EDID_block);
+ return NULL;
+ }
}
tmp = xf86InterpretEEDID(scrnIndex, EDID_block);
- }
- if (tmp && complete)
+ if(NULL == tmp){
+ xfree(EDID_block);
+ return NULL;
+ }
+ }
+
+ if (tmp && complete){
tmp->flags |= EDID_COMPLETE_RAWDATA;
+ }
return tmp;
}
--- xserver.orig/hw/xfree86/ddc/xf86DDC.h
+++ xserver/hw/xfree86/ddc/xf86DDC.h
@@ -44,6 +44,10 @@ extern xf86MonPtr xf86PrintEDID(
extern xf86MonPtr xf86InterpretEDID(
int screenIndex, Uchar *block
);
+extern unsigned char * xf86DDCGetCEA(
+ xf86MonPtr MonPtr,
+ struct extension_type *type
+);
extern xf86MonPtr xf86InterpretEEDID(
int screenIndex, Uchar *block
--- xserver.orig/hw/xfree86/modes/xf86Crtc.c
+++ xserver/hw/xfree86/modes/xf86Crtc.c
@@ -2683,7 +2683,7 @@ xf86OutputSetEDID (xf86OutputPtr output,
if (edid_mon)
{
/* Pull out a phyiscal size from a detailed timing if available. */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < edid_mon->det_mon_num; i++) {
if (edid_mon->det_mon[i].type == DT &&
edid_mon->det_mon[i].section.d_timings.h_size != 0 &&
edid_mon->det_mon[i].section.d_timings.v_size != 0)
--- xserver.orig/hw/xfree86/modes/xf86EdidModes.c
+++ xserver/hw/xfree86/modes/xf86EdidModes.c
@@ -51,7 +51,7 @@ xf86MonitorSupportsReducedBlanking(xf86M
/* EDID 1.4 explicitly defines RB support */
if (DDC->ver.revision >= 4) {
int i;
- for (i = 0; i < DET_TIMINGS; i++) {
+ for (i = 0; i < DDC->det_mon_num; i++) {
struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
if (det_mon->type == DS_RANGES)
if (det_mon->section.ranges.supported_blanking & CVT_REDUCED)
@@ -498,6 +498,107 @@ DDCModesFromStandardTiming(struct std_ti
return Modes;
}
+#define CEA_VIDEO_MODES_NUM 64
+static const DisplayModeRec CEAVideoModes[CEA_VIDEO_MODES_NUM] = {
+ { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 1:640x480@60Hz */
+ { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 2:720x480@60Hz */
+ { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 3:720x480@60Hz */
+ { MODEPREFIX, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 4: 1280x720@60Hz */
+ { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 5:1920x1080i@60Hz */
+ { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 6:1440x480i@60Hz */
+ { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 7:1440x480i@60Hz */
+ { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 8:1440x240@60Hz */
+ { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 9:1440x240@60Hz */
+ { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 10:2880x480i@60Hz */
+ { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 11:2880x480i@60Hz */
+ { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 12:2880x240@60Hz */
+ { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 13:2880x240@60Hz */
+ { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 14:1440x480@60Hz */
+ { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 15:1440x480@60Hz */
+ { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 16:1920x1080@60Hz */
+ { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 17:720x576@50Hz */
+ { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 18:720x576@50Hz */
+ { MODEPREFIX, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 19: 1280x720@50Hz */
+ { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 20:1920x1080i@50Hz */
+ { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 21:1440x576i@50Hz */
+ { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 22:1440x576i@50Hz */
+ { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 23:1440x288@50Hz */
+ { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 24:1440x288@50Hz */
+ { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 25:2880x576i@50Hz */
+ { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 26:2880x576i@50Hz */
+ { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 27:2880x288@50Hz */
+ { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 28:2880x288@50Hz */
+ { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 29:1440x576@50Hz */
+ { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 30:1440x576@50Hz */
+ { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 31:1920x1080@50Hz */
+ { MODEPREFIX, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 32:1920x1080@24Hz */
+ { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 33:1920x1080@25Hz */
+ { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 34:1920x1080@30Hz */
+ { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 35:2880x480@60Hz */
+ { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 36:2880x480@60Hz */
+ { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 37:2880x576@50Hz */
+ { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 38:2880x576@50Hz */
+ { MODEPREFIX, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, V_PHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 39:1920x1080i@50Hz */
+ { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 40:1920x1080i@100Hz */
+ { MODEPREFIX, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 41:1280x720@100Hz */
+ { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 42:720x576@100Hz */
+ { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 43:720x576@100Hz */
+ { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 44:1440x576i@100Hz */
+ { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 45:1440x576i@100Hz */
+ { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 46:1920x1080i@120Hz */
+ { MODEPREFIX, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 47:1280x720@120Hz */
+ { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 48:720x480@120Hz */
+ { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 49:720x480@120Hz */
+ { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 50:1440x480i@120Hz */
+ { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 51:1440x480i@120Hz */
+ { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 52:720x576@200Hz */
+ { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 53:720x576@200Hz */
+ { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 54:1440x576i@200Hz */
+ { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 55:1440x576i@200Hz */
+ { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 56:720x480@240Hz */
+ { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 57:720x480@240Hz */
+ { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 58:1440x480i@240 */
+ { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 59:1440x480i@240 */
+ { MODEPREFIX, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 60: 1280x720@24Hz */
+ { MODEPREFIX, 74250, 3700, 3740, 1430, 3960, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 61: 1280x720@25Hz */
+ { MODEPREFIX, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 62: 1280x720@30Hz */
+ { MODEPREFIX, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 63: 1920x1080@120Hz */
+ { MODEPREFIX, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 64:1920x1080@100Hz */
+};
+
+static DisplayModePtr
+DDCModesFromCeaExtension(int idx, xf86MonPtr MonPtr)
+{
+ DisplayModePtr Modes = NULL, Mode = NULL;
+ struct extension_type type;
+ struct cea_data_blk *data_collection;
+ struct cea_video_blk *video;
+ int num ;
+ int vid;
+
+ type.body_type = CEA_EXT ;
+ type.data_type = CEA_VIDEO_BLK;
+
+ data_collection = (struct cea_data_blk *)xf86DDCGetCEA(MonPtr, &type);
+ if (NULL == data_collection)
+ goto end;
+
+ video = &data_collection->u.video;
+ num = 0;
+
+ while (num < (data_collection->len/sizeof(struct cea_video_blk))) {
+ vid = video[num].video_code & 0x7f;
+
+ if(vid < CEA_VIDEO_MODES_NUM){
+ Mode = xf86DuplicateMode(CEAVideoModes + vid );
+ Modes = xf86ModesAdd(Modes, Mode);
+ }
+ num = num + 1;
+ }
+
+end:
+ return Modes;
+}
/*
*
@@ -699,7 +800,7 @@ xf86DDCApplyQuirks(int scrnIndex, xf86Mo
ddc_quirk_t quirks = xf86DDCDetectQuirks (scrnIndex, DDC, FALSE);
int i;
- for (i = 0; i < DET_TIMINGS; i++) {
+ for (i = 0; i < DDC->det_mon_num; i++) {
struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
if (det_mon->type != DT)
@@ -785,7 +886,7 @@ xf86DDCGetModes(int scrnIndex, xf86MonPt
timing_level = MonitorStandardTimingLevel(DDC);
- for (i = 0; i < DET_TIMINGS; i++) {
+ for (i = 0; i < DDC->det_mon_num; i++) {
struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
switch (det_mon->type) {
@@ -821,6 +922,11 @@ xf86DDCGetModes(int scrnIndex, xf86MonPt
Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb);
Modes = xf86ModesAdd(Modes, Mode);
+ if(EDID_CEA_EXTENSION_FLG & DDC->flags){
+ Mode = DDCModesFromCeaExtension(scrnIndex,DDC);
+ Modes = xf86ModesAdd(Modes, Mode);
+ }
+
if (quirks & DDC_QUIRK_PREFER_LARGE_60)
xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60);
@@ -863,7 +969,7 @@ xf86DDCMonitorSet(int scrnIndex, MonPtr
have_maxpixclock = (Monitor->maxPixClock != 0);
/* Go through the detailed monitor sections */
- for (i = 0; i < DET_TIMINGS; i++) {
+ for (i = 0; i < DDC->det_mon_num; i++) {
switch (DDC->det_mon[i].type) {
case DS_RANGES:
if (!have_hsync) {
[-- Attachment #4: Type: text/plain, Size: 143 bytes --]
_______________________________________________
xorg mailing list
xorg@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/xorg
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC][PATCH] ELD routines and proc interface
[not found] ` <20081120200606.GA4164@csy.ca>
@ 2008-11-21 1:36 ` Wu Fengguang
2008-11-21 1:42 ` [PATCH] properly print ELD sample bits Wu Fengguang
[not found] ` <20081121014649.GA12072@csy.ca>
0 siblings, 2 replies; 20+ messages in thread
From: Wu Fengguang @ 2008-11-21 1:36 UTC (permalink / raw)
To: Shane W; +Cc: alsa-devel, Ma, Ling, intel-gfx, Takashi Iwai, xorg, Fu, Michael
Hi Shane,
On Thu, Nov 20, 2008 at 12:06:06PM -0800, Shane W wrote:
> Hi,
>
> Ok, it appears to be the kernel I was using. Going to a
> 2.6.27 kernel rather than 2.6.28-rc fixed the segfault. So
> now I get ELD data though 5.1 PCM isn't quite there yet.
> Here's the ELD info.
Thanks.
> HDMI intrinsic event: PD=1 ELDV=1
> detected monitor Haier TV*** at connection type HDMI
> supports coding type LPCM: channels = 2, rates = 44100
> 48000 88200 176400 192000 384000, bits =
> supports coding type LPCM: channels = 8, rates = 44100
> 48000 88200 176400 192000 384000, bits =
It reveals bugs in showing the bits field. Will fix it in a following
email.
> supports coding type AC-3: channels = 6, rates = 44100
> 48000 88200, max bitrate = 640000
> supports coding type DTS: channels = 7, rates = 44100 48000
> 88200 176400 192000, max bitrate = 1536000
> supports coding type DSD (One Bit Audio): channels = 6,
> rates = 48000
It's weird that DTS supports 7 channels while DSD supports 6.
DTS is simple the compressed form of DSD.
> set status page addr 0x08360000
> [drm:i915_getparam] *ERROR* Unknown parameter 5
>
> shane@chintoka:~$ cat /proc/asound/Intel/eld#3
> monitor name Haier TV***
> connection_type HDMI
> eld_version [0x2] CEA-861D or below
> edid_version [0x1] CEA-861
> manufacture_id 0x4148
> product_id 0xb01
> port_id 0x0
> support_hdcp 0
> support_ai 0
> audio_sync_delay 0
> speakers [0x0]
> sad_count 8
> sad0_coding_type [0x1] LPCM
> sad0_channels 2
> sad0_rates [0x1ee0] 44100 48000 88200 176400
> 192000 384000
> sad0_bits [0xe0000]
> sad1_coding_type [0x1] LPCM
> sad1_channels 8
> sad1_rates [0x1ee0] 44100 48000 88200 176400
> 192000 384000
> sad1_bits [0xe0000]
> sad2_coding_type [0x2] AC-3
> sad2_channels 6
> sad2_rates [0xe0] 44100 48000 88200
> sad2_max_bitrate 640000
> sad3_coding_type [0x7] DTS
> sad3_channels 7
> sad3_rates [0x6e0] 44100 48000 88200 176400
> 192000
> sad3_max_bitrate 1536000
> sad4_coding_type [0x9] DSD (One Bit Audio)
> sad4_channels 6
> sad4_rates [0x40] 48000
> sad5_coding_type [0x0] undefined
> sad5_channels 1
> sad5_rates [0x0]
> sad6_coding_type [0x0] undefined
> sad6_channels 1
> sad6_rates [0x0]
> sad7_coding_type [0x0] undefined
> sad7_channels 1
> sad7_rates [0x0]
I wonder why the monitor report these zero valued SADs?
> The speakers 0 line is a bit confusing, not sure if that's
Yes it's unexpected. Do you know its real speaker numbers and
allocations? Does it provide some number of line-out ports?
> what's doing it. I am using:
> aplay 51test.wav
>
> which I have put here:
> http://www.csy.ca/~shane/51test.wav
I hear only "front left" and "front right" in my T61 :-)
Thanks,
Fengguang
---
>
> Shane
> On Thu, Nov 20, 2008 at 09:02:04AM +0800, Wu Fengguang wrote:
> > Thanks Shane!
> >
> > Ma Ling: do you have a quick fix for it? Or shall I look into it?
> >
> > Thank you,
> > Fengguang
> >
> > On Wed, Nov 19, 2008 at 12:02:01PM -0800, Shane W wrote:
> > > On Wed, Nov 19, 2008 at 05:39:40PM +0800, Wu Fengguang wrote:
> > > > I managed to update the last working Xorg ELD patches to the latest
> > > > git tree, and they compile flawlessly. The attached 2 patches are for
> > > > xf86-video-intel/ and xserver/ respectively.
> > >
> > > They do compile but I can't get them to run. Here's the
> > > Xorg backtrace when starting. I'm having trouble
> > > generating a core but I'll work on getting gdb output if
> > > needed.
> > >
> > > Backtrace:
> > > 0: /opt/gfx-test/bin/Xorg(xorg_backtrace+0x26) [0x4ebbb6]
> > > 1: /opt/gfx-test/bin/Xorg(xf86SigHandler+0x39) [0x495b49]
> > > 2: /lib/libc.so.6 [0x7f2d1648bf60]
> > > 3:
> > > /opt/gfx-test/lib/xorg/modules/drivers//intel_drv.so(gen4_render_state_cleanup+0x1c)
> > > [0x7f2d14ebab9c]
> > > 4: /opt/gfx-test/lib/xorg/modules/drivers//intel_drv.so
> > > [0x7f2d14e92dfd]
> > > 5: /opt/gfx-test/bin/Xorg(AbortDDX+0x8d) [0x4690fd]
> > > 6: /opt/gfx-test/bin/Xorg(AbortServer+0x1d) [0x4f505d]
> > > 7: /opt/gfx-test/bin/Xorg(LogVMessageVerb+0) [0x4f5700]
> > > 8:
> > > /opt/gfx-test/lib/xorg/modules/drivers//intel_drv.so(i830_bind_all_memory+0x102)
> > > [0x7f2d14e99592]
> > > 9: /opt/gfx-test/lib/xorg/modules/drivers//intel_drv.so
> > > [0x7f2d14e93ad0]
> > > 10: /opt/gfx-test/lib/xorg/modules/drivers//intel_drv.so
> > > [0x7f2d14e950f8]
> > > 11: /opt/gfx-test/bin/Xorg(AddScreen+0x1c6) [0x431086]
> > > 12: /opt/gfx-test/bin/Xorg(InitOutput+0x241) [0x469ae1]
> > > 13: /opt/gfx-test/bin/Xorg(main+0x205) [0x431795]
> > > 14: /lib/libc.so.6(__libc_start_main+0xe6) [0x7f2d164781a6]
> > > 15: /opt/gfx-test/bin/Xorg [0x430dd9]
> > >
> > > It seems to be the xserver patch that's doing it. When they
> > > are both unapplied, X starts fine, when the Xserver patch
> > > is applied, we segfault, when the intel is applied alone,
> > > it starts fine and when both are applied the segfault
> > > returns.
> > >
> > > Shane
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH] properly print ELD sample bits
2008-11-21 1:36 ` Wu Fengguang
@ 2008-11-21 1:42 ` Wu Fengguang
2008-11-21 7:41 ` Takashi Iwai
[not found] ` <20081121014649.GA12072@csy.ca>
1 sibling, 1 reply; 20+ messages in thread
From: Wu Fengguang @ 2008-11-21 1:42 UTC (permalink / raw)
To: Shane W, Takashi Iwai; +Cc: Ma, Ling, Fu, Michael, alsa-devel, intel-gfx, xorg
Fix bugs on printing the ELD sample bits.
Signed-off-by: Wu Fengguang <wfg@linux.intel.com>
---
sound/pci/hda/hda_eld.c | 2 +-
sound/pci/hda/hda_proc.c | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)
--- sound-2.6.orig/sound/pci/hda/hda_eld.c
+++ sound-2.6/sound/pci/hda/hda_eld.c
@@ -397,7 +397,7 @@ static void hdmi_show_short_audio_desc(s
snd_print_pcm_rates(a->rates, buf, sizeof(buf));
if (a->format == AUDIO_CODING_TYPE_LPCM)
- snd_print_pcm_rates(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
+ snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
else if (a->max_bitrate)
snprintf(buf2, sizeof(buf2),
", max bitrate = %d", a->max_bitrate);
--- sound-2.6.orig/sound/pci/hda/hda_proc.c
+++ sound-2.6/sound/pci/hda/hda_proc.c
@@ -120,7 +120,7 @@ void snd_print_pcm_bits(int pcm, char *b
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++)
- if (pcm & (1 << i))
+ if (pcm & (AC_SUPPCM_BITS_8 << i))
j += snprintf(buf + j, buflen - j, " %d", bits[i]);
buf[j] = '\0'; /* necessary when j == 0 */
@@ -130,7 +130,6 @@ static void print_pcm_bits(struct snd_in
{
char buf[SND_PRINT_BITS_ADVISED_BUFSIZE];
- pcm = (pcm >> 16) & 0xff;
snd_iprintf(buffer, " bits [0x%x]:", pcm);
snd_print_pcm_bits(pcm, buf, sizeof(buf));
snd_iprintf(buffer, "%s\n", buf);
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Intel-gfx] [RFC][PATCH] ELD routines and proc interface
[not found] ` <20081121014649.GA12072@csy.ca>
@ 2008-11-21 1:59 ` Wu Fengguang
2008-11-21 3:41 ` Wu Fengguang
1 sibling, 0 replies; 20+ messages in thread
From: Wu Fengguang @ 2008-11-21 1:59 UTC (permalink / raw)
To: Shane W; +Cc: alsa-devel, Ma, Ling, intel-gfx, Takashi Iwai, xorg, Fu, Michael
On Thu, Nov 20, 2008 at 05:46:49PM -0800, Shane W wrote:
> On Fri, Nov 21, 2008 at 09:36:55AM +0800, Wu Fengguang wrote:
> >
> > > supports coding type AC-3: channels = 6, rates = 44100
> > > 48000 88200, max bitrate = 640000
> > > supports coding type DTS: channels = 7, rates = 44100 48000
> > > 88200 176400 192000, max bitrate = 1536000
> > > supports coding type DSD (One Bit Audio): channels = 6,
> > > rates = 48000
> >
> > It's weird that DTS supports 7 channels while DSD supports 6.
> > DTS is simple the compressed form of DSD.
>
> Hmm, I thought DTS was just another way of compressing PCM
> whereas DSD is the format used on SACD disks, IE 6 channel.
> http://en.wikipedia.org/wiki/Direct_Stream_Digital
Well my source is a bit different ;-)
http://en.wikipedia.org/wiki/Super_Audio_CD
DST
To reduce the space and bandwidth requirements of DSD (2.8 Mbit/s per
channel), a lossless data compression method called Direct Stream
Transfer (DST) is used — DST compression is compulsory for
multi-channel regions and optional for stereo regions. This typically
compresses by a factor of between two and three, allowing a disc to
contain 80 minutes of both 2-channel and 5.1-channel sound.
> > > The speakers 0 line is a bit confusing, not sure if that's
> >
> > Yes it's unexpected. Do you know its real speaker numbers and
> > allocations? Does it provide some number of line-out ports?
>
> There are six speakers connected, fl, ct, fr, rl, rr and
> lfe.
Takashi, I'd suggest to support writing to the ELD proc interface to
alter the internal ELD struct. This could let users debug/fix quicks
conveniently. But sure these fixes should eventually be incorporated
into the kernel so that it just works.
> > > what's doing it. I am using:
> > > aplay 51test.wav
> > >
> > > which I have put here:
> > > http://www.csy.ca/~shane/51test.wav
> >
> > I hear only "front left" and "front right" in my T61 :-)
>
> Yeah, you should get:
> Front left
> Center
> Rear left
> Rear right
> and a little boom from the sub
>
> If you encode 51test.wav to ac3 and stream through hdmi
> directly, it does this properly.
OK, so 5.1 AC3 audio plays properly on HDMI?
Thanks,
Fengguang
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Intel-gfx] [RFC][PATCH] ELD routines and proc interface
[not found] ` <20081121014649.GA12072@csy.ca>
2008-11-21 1:59 ` [Intel-gfx] [RFC][PATCH] ELD routines and proc interface Wu Fengguang
@ 2008-11-21 3:41 ` Wu Fengguang
2008-11-21 7:44 ` Takashi Iwai
1 sibling, 1 reply; 20+ messages in thread
From: Wu Fengguang @ 2008-11-21 3:41 UTC (permalink / raw)
To: Shane W; +Cc: alsa-devel, Ma, Ling, intel-gfx, Takashi Iwai, xorg, Fu, Michael
On Thu, Nov 20, 2008 at 05:46:49PM -0800, Shane W wrote:
> On Fri, Nov 21, 2008 at 09:36:55AM +0800, Wu Fengguang wrote:
> > Yes it's unexpected. Do you know its real speaker numbers and
> > allocations? Does it provide some number of line-out ports?
>
> There are six speakers connected, fl, ct, fr, rl, rr and lfe.
Hi Shane,
Apply this patch and run "echo speakers f > /proc/asound/card0/eld\#3".
That will make the ELD "speakers" field right.
Thanks,
Fengguang
---
support writing to the ELD proc file
Allow users to fix quicks of ELD ROMs by writing new values to the ELD proc
interface. The format is one or more lines of "name hex_value".
Users can add/remove/modify up to 32 SAD(Short Audio Descriptor) entries.
Signed-off-by: Wu Fengguang <wfg@linux.intel.com>
---
sound/pci/hda/hda_eld.c | 56 ++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
--- sound-2.6.orig/sound/pci/hda/hda_eld.c
+++ sound-2.6/sound/pci/hda/hda_eld.c
@@ -500,6 +500,59 @@ static void hdmi_print_eld_info(struct s
hdmi_print_sad_info(i, e->sad + i, buffer);
}
+static void hdmi_write_eld_item(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdmi_eld *e = entry->private_data;
+ char line[64];
+ char name[64];
+ char *sname;
+ long long val;
+ int n;
+
+ while (!snd_info_get_line(buffer, line, sizeof(line))) {
+ if (sscanf(line, "%s %llx", name, &val) != 2)
+ continue;
+ if (!strcmp(name, "connection_type"))
+ e->conn_type = val;
+ else if (!strcmp(name, "port_id"))
+ e->port_id = val;
+ else if (!strcmp(name, "support_hdcp"))
+ e->support_hdcp = val;
+ else if (!strcmp(name, "support_ai"))
+ e->support_ai = val;
+ else if (!strcmp(name, "audio_sync_delay"))
+ e->aud_synch_delay = val;
+ else if (!strcmp(name, "speakers"))
+ e->spk_alloc = val;
+ else if (!strcmp(name, "sad_count"))
+ e->sad_count = val;
+ else if (!strncmp(name, "sad", 3)) {
+ sname = name + 4;
+ n = name[3] - '0';
+ if (name[4] >= '0' && name[4] <= '9') {
+ sname++;
+ n = 10 * n + name[4] - '0';
+ }
+ if (n < 0 || n > 31) /* double the CEA limit */
+ continue;
+ if (!strcmp(sname, "_coding_type"))
+ e->sad[n].format = val;
+ else if (!strcmp(sname, "_channels"))
+ e->sad[n].channels = val;
+ else if (!strcmp(sname, "_rates"))
+ e->sad[n].rates = val;
+ else if (!strcmp(sname, "_bits"))
+ e->sad[n].sample_bits = val;
+ else if (!strcmp(sname, "_max_bitrate"))
+ e->sad[n].max_bitrate = val;
+ if (n >= e->sad_count)
+ e->sad_count = n + 1;
+ }
+ }
+}
+
+
int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld)
{
char name[32];
@@ -512,6 +565,9 @@ int snd_hda_eld_proc_new(struct hda_code
return err;
snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
+ entry->c.text.write = hdmi_write_eld_item;
+ entry->mode |= S_IWUSR;
+
return 0;
}
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] properly print ELD sample bits
2008-11-21 1:42 ` [PATCH] properly print ELD sample bits Wu Fengguang
@ 2008-11-21 7:41 ` Takashi Iwai
0 siblings, 0 replies; 20+ messages in thread
From: Takashi Iwai @ 2008-11-21 7:41 UTC (permalink / raw)
To: Wu Fengguang; +Cc: alsa-devel, Ma, Ling, intel-gfx, Shane W, xorg, Fu, Michael
At Fri, 21 Nov 2008 09:42:59 +0800,
Wu Fengguang wrote:
>
> Fix bugs on printing the ELD sample bits.
>
> Signed-off-by: Wu Fengguang <wfg@linux.intel.com>
Applied now.
Takashi
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Intel-gfx] [RFC][PATCH] ELD routines and proc interface
2008-11-21 3:41 ` Wu Fengguang
@ 2008-11-21 7:44 ` Takashi Iwai
2008-11-21 7:47 ` Wu Fengguang
0 siblings, 1 reply; 20+ messages in thread
From: Takashi Iwai @ 2008-11-21 7:44 UTC (permalink / raw)
To: Wu Fengguang; +Cc: alsa-devel, Ma, Ling, intel-gfx, Shane W, xorg, Fu, Michael
At Fri, 21 Nov 2008 11:41:50 +0800,
Wu Fengguang wrote:
>
> On Thu, Nov 20, 2008 at 05:46:49PM -0800, Shane W wrote:
> > On Fri, Nov 21, 2008 at 09:36:55AM +0800, Wu Fengguang wrote:
>
> > > Yes it's unexpected. Do you know its real speaker numbers and
> > > allocations? Does it provide some number of line-out ports?
> >
> > There are six speakers connected, fl, ct, fr, rl, rr and lfe.
>
> Hi Shane,
>
> Apply this patch and run "echo speakers f > /proc/asound/card0/eld\#3".
> That will make the ELD "speakers" field right.
>
> Thanks,
> Fengguang
> ---
> support writing to the ELD proc file
>
> Allow users to fix quicks of ELD ROMs by writing new values to the ELD proc
> interface. The format is one or more lines of "name hex_value".
>
> Users can add/remove/modify up to 32 SAD(Short Audio Descriptor) entries.
>
> Signed-off-by: Wu Fengguang <wfg@linux.intel.com>
This is a nice feature, so I applied now as is.
Please give an incremental patch if you need more fixes.
thanks,
Takashi
> ---
> sound/pci/hda/hda_eld.c | 56 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 56 insertions(+)
>
> --- sound-2.6.orig/sound/pci/hda/hda_eld.c
> +++ sound-2.6/sound/pci/hda/hda_eld.c
> @@ -500,6 +500,59 @@ static void hdmi_print_eld_info(struct s
> hdmi_print_sad_info(i, e->sad + i, buffer);
> }
>
> +static void hdmi_write_eld_item(struct snd_info_entry *entry,
> + struct snd_info_buffer *buffer)
> +{
> + struct hdmi_eld *e = entry->private_data;
> + char line[64];
> + char name[64];
> + char *sname;
> + long long val;
> + int n;
> +
> + while (!snd_info_get_line(buffer, line, sizeof(line))) {
> + if (sscanf(line, "%s %llx", name, &val) != 2)
> + continue;
> + if (!strcmp(name, "connection_type"))
> + e->conn_type = val;
> + else if (!strcmp(name, "port_id"))
> + e->port_id = val;
> + else if (!strcmp(name, "support_hdcp"))
> + e->support_hdcp = val;
> + else if (!strcmp(name, "support_ai"))
> + e->support_ai = val;
> + else if (!strcmp(name, "audio_sync_delay"))
> + e->aud_synch_delay = val;
> + else if (!strcmp(name, "speakers"))
> + e->spk_alloc = val;
> + else if (!strcmp(name, "sad_count"))
> + e->sad_count = val;
> + else if (!strncmp(name, "sad", 3)) {
> + sname = name + 4;
> + n = name[3] - '0';
> + if (name[4] >= '0' && name[4] <= '9') {
> + sname++;
> + n = 10 * n + name[4] - '0';
> + }
> + if (n < 0 || n > 31) /* double the CEA limit */
> + continue;
> + if (!strcmp(sname, "_coding_type"))
> + e->sad[n].format = val;
> + else if (!strcmp(sname, "_channels"))
> + e->sad[n].channels = val;
> + else if (!strcmp(sname, "_rates"))
> + e->sad[n].rates = val;
> + else if (!strcmp(sname, "_bits"))
> + e->sad[n].sample_bits = val;
> + else if (!strcmp(sname, "_max_bitrate"))
> + e->sad[n].max_bitrate = val;
> + if (n >= e->sad_count)
> + e->sad_count = n + 1;
> + }
> + }
> +}
> +
> +
> int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld)
> {
> char name[32];
> @@ -512,6 +565,9 @@ int snd_hda_eld_proc_new(struct hda_code
> return err;
>
> snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
> + entry->c.text.write = hdmi_write_eld_item;
> + entry->mode |= S_IWUSR;
> +
> return 0;
> }
>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Intel-gfx] [RFC][PATCH] ELD routines and proc interface
2008-11-21 7:44 ` Takashi Iwai
@ 2008-11-21 7:47 ` Wu Fengguang
0 siblings, 0 replies; 20+ messages in thread
From: Wu Fengguang @ 2008-11-21 7:47 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel, Ma, Ling, intel-gfx, Shane W, xorg, Fu, Michael
On Fri, Nov 21, 2008 at 08:44:18AM +0100, Takashi Iwai wrote:
> At Fri, 21 Nov 2008 11:41:50 +0800,
> Wu Fengguang wrote:
> >
> > On Thu, Nov 20, 2008 at 05:46:49PM -0800, Shane W wrote:
> > > On Fri, Nov 21, 2008 at 09:36:55AM +0800, Wu Fengguang wrote:
> >
> > > > Yes it's unexpected. Do you know its real speaker numbers and
> > > > allocations? Does it provide some number of line-out ports?
> > >
> > > There are six speakers connected, fl, ct, fr, rl, rr and lfe.
> >
> > Hi Shane,
> >
> > Apply this patch and run "echo speakers f > /proc/asound/card0/eld\#3".
> > That will make the ELD "speakers" field right.
> >
> > Thanks,
> > Fengguang
> > ---
> > support writing to the ELD proc file
> >
> > Allow users to fix quicks of ELD ROMs by writing new values to the ELD proc
> > interface. The format is one or more lines of "name hex_value".
> >
> > Users can add/remove/modify up to 32 SAD(Short Audio Descriptor) entries.
> >
> > Signed-off-by: Wu Fengguang <wfg@linux.intel.com>
>
> This is a nice feature, so I applied now as is.
> Please give an incremental patch if you need more fixes.
OK, thank you!
Fengguang
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2008-11-21 7:47 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-13 2:21 [RFC][PATCH] ELD routines and proc interface Wu Fengguang
2008-11-13 7:26 ` Takashi Iwai
2008-11-14 1:34 ` Wu Fengguang
2008-11-14 7:25 ` Takashi Iwai
2008-11-14 7:38 ` Wu Fengguang
2008-11-14 7:43 ` Takashi Iwai
2008-11-14 7:47 ` Wu Fengguang
2008-11-14 7:50 ` Takashi Iwai
2008-11-14 8:02 ` Wu Fengguang
[not found] ` <20081119071135.GA17733@csy.ca>
2008-11-19 7:17 ` Wu Fengguang
[not found] ` <20081119075545.GA19833@csy.ca>
2008-11-19 8:08 ` Wu Fengguang
2008-11-19 9:39 ` [alsa-devel] " Wu Fengguang
[not found] ` <20081119200201.GA23246@csy.ca>
[not found] ` <20081120010204.GA25454@localhost>
[not found] ` <20081120200606.GA4164@csy.ca>
2008-11-21 1:36 ` Wu Fengguang
2008-11-21 1:42 ` [PATCH] properly print ELD sample bits Wu Fengguang
2008-11-21 7:41 ` Takashi Iwai
[not found] ` <20081121014649.GA12072@csy.ca>
2008-11-21 1:59 ` [Intel-gfx] [RFC][PATCH] ELD routines and proc interface Wu Fengguang
2008-11-21 3:41 ` Wu Fengguang
2008-11-21 7:44 ` Takashi Iwai
2008-11-21 7:47 ` Wu Fengguang
[not found] <20081113022153.GB6844@mail.ustc.edu.cn>
2008-11-13 2:36 ` Wu Fengguang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.