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...@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 e...@anholt.net eric.anh...@intel.com
signature.asc
Description: This is a digitally signed message part
------------------------------------------------------------------------------ Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are powering Web 2.0 with engaging, cross-platform capabilities. Quickly and easily build your RIAs with Flex Builder, the Eclipse(TM)based development software that enables intelligent coding and step-through debugging. Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
-- _______________________________________________ Dri-devel mailing list Dri-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/dri-devel