[Intel-gfx] [PATCH] drm: read EDID extensions from monitor (v2)

Eric Anholt eric at anholt.net
Fri Mar 20 21:17:10 CET 2009


On Fri, 2009-03-20 at 14:09 +0800, Ma Ling wrote:
> Usually drm read basic EDID, that is enough for us, but because digital display in introduced
> i.e. HDMI monitor, sometime we need to interact with monitor by EDID extension information,
> including audio/video data block, speaker allocation and vendor specific data block...
> This patch intends to read EDID extensions(max 4) from digital monitor for user.
> 
> Signed-off-by: Ma Ling <ling.ma at intel.com>

This looks fine to me.  airlied, you want to pick this up for next, or
should I?

> ---
> In this version drm will read max number if the number of edid extensions is over max number.
> 
>  drivers/gpu/drm/drm_edid.c |  121 +++++++++++++++++++++++++++++++++----------
>  include/drm/drm_crtc.h     |    3 +-
>  2 files changed, 95 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index a839a28..fab2bdf 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -550,11 +550,20 @@ static int add_detailed_info(struct drm_connector *connector,
>  }
>  
>  #define DDC_ADDR 0x50
> -
> -unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
> +/**
> + * Get EDID information via I2C.
> + *
> + * \param adapter : i2c device adaptor
> + * \param buf     : EDID data buffer to be filled
> + * \param len     : EDID data buffer length
> + * \return 0 on success or -1 on failure.
> + *
> + * Try to fetch EDID information by calling i2c driver function.
> + */
> +int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
> +			  unsigned char *buf, int len)
>  {
>  	unsigned char start = 0x0;
> -	unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
>  	struct i2c_msg msgs[] = {
>  		{
>  			.addr	= DDC_ADDR,
> @@ -564,31 +573,36 @@ unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
>  		}, {
>  			.addr	= DDC_ADDR,
>  			.flags	= I2C_M_RD,
> -			.len	= EDID_LENGTH,
> +			.len	= len,
>  			.buf	= buf,
>  		}
>  	};
>  
> -	if (!buf) {
> -		dev_warn(&adapter->dev, "unable to allocate memory for EDID "
> -			 "block.\n");
> -		return NULL;
> -	}
> -
>  	if (i2c_transfer(adapter, msgs, 2) == 2)
> -		return buf;
> +		return 0;
>  
>  	dev_info(&adapter->dev, "unable to read EDID block.\n");
> -	kfree(buf);
> -	return NULL;
> +	return -1;
>  }
>  EXPORT_SYMBOL(drm_do_probe_ddc_edid);
>  
> -static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
> +/**
> + * Get EDID information.
> + *
> + * \param adapter : i2c device adaptor.
> + * \param buf     : EDID data buffer to be filled
> + * \param len     : EDID data buffer length
> + * \return 0 on success or -1 on failure.
> + *
> + * Initialize DDC, then fetch EDID information
> + * by calling drm_do_probe_ddc_edid function.
> + */
> +static int drm_ddc_read(struct i2c_adapter *adapter,
> +			unsigned char *buf, int len)
>  {
>  	struct i2c_algo_bit_data *algo_data = adapter->algo_data;
> -	unsigned char *edid = NULL;
>  	int i, j;
> +	int ret = -1;
>  
>  	algo_data->setscl(algo_data->data, 1);
>  
> @@ -616,7 +630,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
>  		msleep(15);
>  
>  		/* Do the real work */
> -		edid = drm_do_probe_ddc_edid(adapter);
> +		ret = drm_do_probe_ddc_edid(adapter, buf, len);
>  		algo_data->setsda(algo_data->data, 0);
>  		algo_data->setscl(algo_data->data, 0);
>  		msleep(15);
> @@ -632,7 +646,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
>  		msleep(15);
>  		algo_data->setscl(algo_data->data, 0);
>  		algo_data->setsda(algo_data->data, 0);
> -		if (edid)
> +		if (ret == 0)
>  			break;
>  	}
>  	/* Release the DDC lines when done or the Apple Cinema HD display
> @@ -641,9 +655,31 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
>  	algo_data->setsda(algo_data->data, 1);
>  	algo_data->setscl(algo_data->data, 1);
>  
> -	return edid;
> +	return ret;
> +}
> +
> +static int drm_ddc_read_edid(struct drm_connector *connector,
> +			     struct i2c_adapter *adapter,
> +			     char *buf, int len)
> +{
> +	int ret;
> +
> +	ret = drm_ddc_read(adapter, buf, len);
> +	if (ret != 0) {
> +		dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
> +			 drm_get_connector_name(connector));
> +		goto end;
> +	}
> +	if (!edid_is_valid((struct edid *)buf)) {
> +		dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
> +			 drm_get_connector_name(connector));
> +		ret = -1;
> +	}
> +end:
> +	return ret;
>  }
>  
> +#define MAX_EDID_EXT_NUM 4
>  /**
>   * drm_get_edid - get EDID data, if available
>   * @connector: connector we're probing
> @@ -656,24 +692,53 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
>  struct edid *drm_get_edid(struct drm_connector *connector,
>  			  struct i2c_adapter *adapter)
>  {
> +	int ret;
>  	struct edid *edid;
>  
> -	edid = (struct edid *)drm_ddc_read(adapter);
> -	if (!edid) {
> -		dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
> -			 drm_get_connector_name(connector));
> -		return NULL;
> +	edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
> +		       GFP_KERNEL);
> +	if (edid == NULL) {
> +		dev_warn(&connector->dev->pdev->dev,
> +			 "Failed to allocate EDID\n");
> +		goto end;
>  	}
> -	if (!edid_is_valid(edid)) {
> -		dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
> -			 drm_get_connector_name(connector));
> -		kfree(edid);
> -		return NULL;
> +
> +	/* Read first EDID block */
> +	ret = drm_ddc_read_edid(connector, adapter,
> +				(unsigned char *)edid, EDID_LENGTH);
> +	if (ret != 0)
> +		goto clean_up;
> +
> +	/* There are EDID extensions to be read */
> +	if (edid->extensions != 0) {
> +		int edid_ext_num = edid->extensions;
> +
> +		if (edid_ext_num > MAX_EDID_EXT_NUM) {
> +			dev_warn(&connector->dev->pdev->dev,
> +				 "The number of extension(%d) is "
> +				 "over max (%d), actually read number (%d)\n",
> +				 edid_ext_num, MAX_EDID_EXT_NUM,
> +				 MAX_EDID_EXT_NUM);
> +			/* Reset EDID extension number to be read */
> +			edid_ext_num = MAX_EDID_EXT_NUM;
> +		}
> +		/* Read EDID including extensions too */
> +		ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
> +					EDID_LENGTH * (edid_ext_num + 1));
> +		if (ret != 0)
> +			goto clean_up;
> +
>  	}
>  
>  	connector->display_info.raw_edid = (char *)edid;
> +	goto end;
>  
> +clean_up:
> +	kfree(edid);
> +	edid = NULL;
> +end:
>  	return edid;
> +
>  }
>  EXPORT_SYMBOL(drm_get_edid);
>  
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 5ded1ac..5d73adb 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -613,7 +613,8 @@ extern void drm_fb_release(struct drm_file *file_priv);
>  extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
>  extern struct edid *drm_get_edid(struct drm_connector *connector,
>  				 struct i2c_adapter *adapter);
> -extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter);
> +extern int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
> +				 unsigned char *buf, int len);
>  extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
>  extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
>  extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);
-- 
Eric Anholt
eric at anholt.net                         eric.anholt at intel.com


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 197 bytes
Desc: This is a digitally signed message part
URL: <http://lists.freedesktop.org/archives/intel-gfx/attachments/20090320/505c2376/attachment.sig>


More information about the Intel-gfx mailing list