[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