[Intel-gfx] [PATCH 3/4] drm/i915: cache hdmi edid
Daniel Vetter
daniel.vetter at ffwll.ch
Mon Jun 11 09:03:15 CEST 2012
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 <daniel.vetter at ffwll.ch>
---
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
More information about the Intel-gfx
mailing list