diff options
author | Ma Ling <ling.ma@intel.com> | 2009-03-26 07:26:23 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-03-29 04:31:49 -0400 |
commit | f23c20c83d523e5f8cda1f8f7ed52fe6afffbe29 (patch) | |
tree | c0888eeee7f76b46151264294222bf74190b385c | |
parent | dba5ed0cd12d8db5c0d2e1c869c2a50c5bcf6743 (diff) |
drm: detect hdmi monitor by hdmi identifier (v3)
Sometime we need to communicate with HDMI monitor by sending audio or video
info frame, so we have to know monitor type. However if user utilize HDMI-DVI adapter to connect DVI monitor, hardware detection will incorrectly show the monitor is HDMI. HDMI spec tell us that any device containing IEEE registration Identifier will be treated as HDMI device. The patch intends to detect HDMI monitor by this rule.
Signed-off-by: Ma Ling <ling.ma@intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 62 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 1 |
2 files changed, 63 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index fab2bdf9c423..c67400067b85 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -742,6 +742,68 @@ end: | |||
742 | } | 742 | } |
743 | EXPORT_SYMBOL(drm_get_edid); | 743 | EXPORT_SYMBOL(drm_get_edid); |
744 | 744 | ||
745 | #define HDMI_IDENTIFIER 0x000C03 | ||
746 | #define VENDOR_BLOCK 0x03 | ||
747 | /** | ||
748 | * drm_detect_hdmi_monitor - detect whether monitor is hdmi. | ||
749 | * @edid: monitor EDID information | ||
750 | * | ||
751 | * Parse the CEA extension according to CEA-861-B. | ||
752 | * Return true if HDMI, false if not or unknown. | ||
753 | */ | ||
754 | bool drm_detect_hdmi_monitor(struct edid *edid) | ||
755 | { | ||
756 | char *edid_ext = NULL; | ||
757 | int i, hdmi_id, edid_ext_num; | ||
758 | int start_offset, end_offset; | ||
759 | bool is_hdmi = false; | ||
760 | |||
761 | /* No EDID or EDID extensions */ | ||
762 | if (edid == NULL || edid->extensions == 0) | ||
763 | goto end; | ||
764 | |||
765 | /* Chose real EDID extension number */ | ||
766 | edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ? | ||
767 | MAX_EDID_EXT_NUM : edid->extensions; | ||
768 | |||
769 | /* Find CEA extension */ | ||
770 | for (i = 0; i < edid_ext_num; i++) { | ||
771 | edid_ext = (char *)edid + EDID_LENGTH * (i + 1); | ||
772 | /* This block is CEA extension */ | ||
773 | if (edid_ext[0] == 0x02) | ||
774 | break; | ||
775 | } | ||
776 | |||
777 | if (i == edid_ext_num) | ||
778 | goto end; | ||
779 | |||
780 | /* Data block offset in CEA extension block */ | ||
781 | start_offset = 4; | ||
782 | end_offset = edid_ext[2]; | ||
783 | |||
784 | /* | ||
785 | * Because HDMI identifier is in Vendor Specific Block, | ||
786 | * search it from all data blocks of CEA extension. | ||
787 | */ | ||
788 | for (i = start_offset; i < end_offset; | ||
789 | /* Increased by data block len */ | ||
790 | i += ((edid_ext[i] & 0x1f) + 1)) { | ||
791 | /* Find vendor specific block */ | ||
792 | if ((edid_ext[i] >> 5) == VENDOR_BLOCK) { | ||
793 | hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) | | ||
794 | edid_ext[i + 3] << 16; | ||
795 | /* Find HDMI identifier */ | ||
796 | if (hdmi_id == HDMI_IDENTIFIER) | ||
797 | is_hdmi = true; | ||
798 | break; | ||
799 | } | ||
800 | } | ||
801 | |||
802 | end: | ||
803 | return is_hdmi; | ||
804 | } | ||
805 | EXPORT_SYMBOL(drm_detect_hdmi_monitor); | ||
806 | |||
745 | /** | 807 | /** |
746 | * drm_add_edid_modes - add modes from EDID data, if available | 808 | * drm_add_edid_modes - add modes from EDID data, if available |
747 | * @connector: connector we're probing | 809 | * @connector: connector we're probing |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 9022b2468182..3c1924c010e8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -732,4 +732,5 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, | |||
732 | void *data, struct drm_file *file_priv); | 732 | void *data, struct drm_file *file_priv); |
733 | extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, | 733 | extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, |
734 | void *data, struct drm_file *file_priv); | 734 | void *data, struct drm_file *file_priv); |
735 | extern bool drm_detect_hdmi_monitor(struct edid *edid); | ||
735 | #endif /* __DRM_CRTC_H__ */ | 736 | #endif /* __DRM_CRTC_H__ */ |