Like the previous patches.

While at it also kill a stale comment - we've moved hdmi audio
detection from ->get_modes to ->detect and the audio property handling
functions.

v2: Fixup use-after-free in edid caching because I've missed a kfree
somewhere. Dunno how that one escape, because I clearly remember
fixing this while testing the patch :(

v3: Really fix this up.

Signed-Off-by: Daniel Vetter <[email protected]>
---
 drivers/gpu/drm/i915/intel_drv.h  |    1 +
 drivers/gpu/drm/i915/intel_hdmi.c |   49 ++++++++++++++++++++++---------------
 2 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d073623..ddb60bc 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -303,6 +303,7 @@ struct intel_hdmi {
                                struct dip_infoframe *frame);
        void (*set_infoframes)(struct drm_encoder *encoder,
                               struct drm_display_mode *adjusted_mode);
+       struct edid *cached_edid;
 };
 
 static inline struct drm_crtc *
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c 
b/drivers/gpu/drm/i915/intel_hdmi.c
index 69637db..d3dbc32 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -689,22 +689,40 @@ static bool g4x_hdmi_connected(struct intel_hdmi 
*intel_hdmi)
        return I915_READ(PORT_HOTPLUG_STAT) & bit;
 }
 
+struct edid *
+intel_hdmi_get_edid(struct drm_connector *connector)
+{
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+
+       if (!intel_hdmi->cached_edid) {
+               struct i2c_adapter *adapter;
+
+               adapter = intel_gmbus_get_adapter(dev_priv,
+                                                 intel_hdmi->ddc_bus);
+               intel_hdmi->cached_edid = drm_get_edid(connector, adapter);
+       }
+
+       return intel_hdmi->cached_edid;
+}
+
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
        struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
        struct edid *edid;
        enum drm_connector_status status = connector_status_disconnected;
 
        if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi))
                return status;
 
+       /* Clean the edid cache. */
+       kfree(intel_hdmi->cached_edid);
+       intel_hdmi->cached_edid = NULL;
+
        intel_hdmi->has_hdmi_sink = false;
        intel_hdmi->has_audio = false;
-       edid = drm_get_edid(connector,
-                           intel_gmbus_get_adapter(dev_priv,
-                                                   intel_hdmi->ddc_bus));
+       edid = intel_hdmi_get_edid(connector);
 
        if (edid) {
                if (edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -715,7 +733,6 @@ intel_hdmi_detect(struct drm_connector *connector, bool 
force)
                        intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
                }
                connector->display_info.raw_edid = NULL;
-               kfree(edid);
        }
 
        if (status == connector_status_connected) {
@@ -729,35 +746,24 @@ intel_hdmi_detect(struct drm_connector *connector, bool 
force)
 
 static int intel_hdmi_get_modes(struct drm_connector *connector)
 {
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
-
-       /* We should parse the EDID data and find out if it's an HDMI sink so
-        * we can send audio to it.
-        */
+       struct edid *edid;
 
-       return intel_ddc_get_modes(connector,
-                                  intel_gmbus_get_adapter(dev_priv,
-                                                          
intel_hdmi->ddc_bus));
+       edid = intel_hdmi_get_edid(connector);
+       return intel_edid_get_modes(connector, edid);
 }
 
 static bool
 intel_hdmi_detect_audio(struct drm_connector *connector)
 {
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       struct drm_i915_private *dev_priv = connector->dev->dev_private;
        struct edid *edid;
        bool has_audio = false;
 
-       edid = drm_get_edid(connector,
-                           intel_gmbus_get_adapter(dev_priv,
-                                                   intel_hdmi->ddc_bus));
+       edid = intel_hdmi_get_edid(connector);
        if (edid) {
                if (edid->input & DRM_EDID_INPUT_DIGITAL)
                        has_audio = drm_detect_monitor_audio(edid);
 
                connector->display_info.raw_edid = NULL;
-               kfree(edid);
        }
 
        return has_audio;
@@ -820,8 +826,11 @@ done:
 
 static void intel_hdmi_destroy(struct drm_connector *connector)
 {
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
+       kfree(intel_hdmi->cached_edid);
        kfree(connector);
 }
 
-- 
1.7.7.6

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to