diff options
Diffstat (limited to 'drivers/gpu/drm/drm_displayid.c')
| -rw-r--r-- | drivers/gpu/drm/drm_displayid.c | 62 | 
1 files changed, 53 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 38ea8203df45..9edc111be7ee 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -7,13 +7,29 @@  #include <drm/drm_edid.h>  #include <drm/drm_print.h> -static int validate_displayid(const u8 *displayid, int length, int idx) +static const struct displayid_header * +displayid_get_header(const u8 *displayid, int length, int index) +{ +	const struct displayid_header *base; + +	if (sizeof(*base) > length - index) +		return ERR_PTR(-EINVAL); + +	base = (const struct displayid_header *)&displayid[index]; + +	return base; +} + +static const struct displayid_header * +validate_displayid(const u8 *displayid, int length, int idx)  {  	int i, dispid_length;  	u8 csum = 0;  	const struct displayid_header *base; -	base = (const struct displayid_header *)&displayid[idx]; +	base = displayid_get_header(displayid, length, idx); +	if (IS_ERR(base)) +		return base;  	DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",  		      base->rev, base->bytes, base->prod_id, base->ext_count); @@ -21,16 +37,16 @@ static int validate_displayid(const u8 *displayid, int length, int idx)  	/* +1 for DispID checksum */  	dispid_length = sizeof(*base) + base->bytes + 1;  	if (dispid_length > length - idx) -		return -EINVAL; +		return ERR_PTR(-EINVAL);  	for (i = 0; i < dispid_length; i++)  		csum += displayid[idx + i];  	if (csum) {  		DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum); -		return -EINVAL; +		return ERR_PTR(-EINVAL);  	} -	return 0; +	return base;  }  static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid, @@ -39,7 +55,6 @@ static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid,  {  	const u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index);  	const struct displayid_header *base; -	int ret;  	if (!displayid)  		return NULL; @@ -48,11 +63,10 @@ static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid,  	*length = EDID_LENGTH - 1;  	*idx = 1; -	ret = validate_displayid(displayid, *length, *idx); -	if (ret) +	base = validate_displayid(displayid, *length, *idx); +	if (IS_ERR(base))  		return NULL; -	base = (const struct displayid_header *)&displayid[*idx];  	*length = *idx + sizeof(*base) + base->bytes;  	return displayid; @@ -109,6 +123,9 @@ __displayid_iter_next(struct displayid_iter *iter)  	}  	for (;;) { +		/* The first section we encounter is the base section */ +		bool base_section = !iter->section; +  		iter->section = drm_find_displayid_extension(iter->drm_edid,  							     &iter->length,  							     &iter->idx, @@ -118,6 +135,18 @@ __displayid_iter_next(struct displayid_iter *iter)  			return NULL;  		} +		/* Save the structure version and primary use case. */ +		if (base_section) { +			const struct displayid_header *base; + +			base = displayid_get_header(iter->section, iter->length, +						    iter->idx); +			if (!IS_ERR(base)) { +				iter->version = base->rev; +				iter->primary_use = base->prod_id; +			} +		} +  		iter->idx += sizeof(struct displayid_header);  		block = displayid_iter_block(iter); @@ -130,3 +159,18 @@ void displayid_iter_end(struct displayid_iter *iter)  {  	memset(iter, 0, sizeof(*iter));  } + +/* DisplayID Structure Version/Revision from the Base Section. */ +u8 displayid_version(const struct displayid_iter *iter) +{ +	return iter->version; +} + +/* + * DisplayID Primary Use Case (2.0+) or Product Type Identifier (1.0-1.3) from + * the Base Section. + */ +u8 displayid_primary_use(const struct displayid_iter *iter) +{ +	return iter->primary_use; +}  | 
