From 67f6eb1eb8d3dc5bb5fdb097655d3da326f637c1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 10:44:51 +1000 Subject: add property blobs and edid reporting support --- libdrm/xf86drmMode.c | 41 ++++++++++++++++++++++++++ libdrm/xf86drmMode.h | 3 ++ linux-core/drm_crtc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++---- linux-core/drm_crtc.h | 8 ++++-- linux-core/drm_drv.c | 1 + linux-core/intel_crt.c | 1 - linux-core/intel_modes.c | 1 + shared-core/drm.h | 13 +++++---- tests/mode/modetest.c | 9 ++++-- 9 files changed, 134 insertions(+), 18 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index f4ec004c..03bd15f1 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -470,3 +470,44 @@ void drmModeFreeProperty(drmModePropertyPtr ptr) drmFree(ptr->enums); drmFree(ptr); } + +drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id) +{ + struct drm_mode_get_blob blob; + drmModePropertyBlobPtr r; + + blob.length = 0; + blob.data = 0; + blob.blob_id = blob_id; + + if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) + return NULL; + + if (blob.length) + blob.data = VOID2U64(drmMalloc(blob.length)); + + if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) { + r = NULL; + goto err_allocs; + } + + if (!(r = drmMalloc(sizeof(*r)))) + return NULL; + + r->id = blob.blob_id; + r->length = blob.length; + r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length); + +err_allocs: + drmFree(U642VOID(blob.data)); + return r; +} + +void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->data); + drmFree(ptr); +} diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index e936044b..6fcf6a19 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -220,3 +220,6 @@ extern int drmModeDetachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId); extern void drmModeFreeProperty(drmModePropertyPtr ptr); + +extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id); +extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a3aa783b..70844237 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -590,6 +590,8 @@ struct drm_output *drm_output_create(struct drm_device *dev, list_add_tail(&output->head, &dev->mode_config.output_list); dev->mode_config.num_output++; + drm_output_attach_property(output, dev->mode_config.edid_property, 0); + mutex_unlock(&dev->mode_config.mutex); return output; @@ -1935,7 +1937,6 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) } EXPORT_SYMBOL(drm_property_destroy); - int drm_output_attach_property(struct drm_output *output, struct drm_property *property, uint64_t init_val) { @@ -1955,6 +1956,24 @@ int drm_output_attach_property(struct drm_output *output, } EXPORT_SYMBOL(drm_output_attach_property); +int drm_output_property_set_value(struct drm_output *output, + struct drm_property *property, uint64_t value) +{ + int i; + + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] == property->id) { + output->property_values[i] = value; + break; + } + } + + if (i == DRM_OUTPUT_MAX_PROPERTY) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(drm_output_property_set_value); + int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -2052,17 +2071,17 @@ done: return ret; } -static int drm_property_create_blob(struct drm_device *dev, int length, - void *data) +static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, + void *data) { struct drm_property_blob *blob; if (!length || !data) - return -EINVAL; + return NULL; blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); if (!blob) - return -EINVAL; + return NULL; blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob)); blob->length = length; @@ -2072,7 +2091,7 @@ static int drm_property_create_blob(struct drm_device *dev, int length, blob->id = drm_idr_get(dev, blob); list_add_tail(&blob->head, &dev->mode_config.property_blob_list); - return blob->id; + return blob; } static void drm_property_destroy_blob(struct drm_device *dev, @@ -2082,3 +2101,47 @@ static void drm_property_destroy_blob(struct drm_device *dev, list_del(&blob->head); kfree(blob); } + +int drm_mode_getblob_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_get_blob *out_resp = data; + struct drm_property_blob *blob; + int ret = 0; + void *blob_ptr; + + mutex_lock(&dev->mode_config.mutex); + + blob = idr_find(&dev->mode_config.crtc_idr, out_resp->blob_id); + if (!blob || (blob->id != out_resp->blob_id)) { + ret = -EINVAL; + goto done; + } + + if (out_resp->length == blob->length) { + blob_ptr = (void *)(unsigned long)out_resp->data; + if (copy_to_user(blob_ptr, blob->data, blob->length)){ + ret = -EFAULT; + goto done; + } + } + out_resp->length = blob->length; + +done: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +int drm_mode_output_update_edid_property(struct drm_output *output, unsigned char *edid) +{ + struct drm_device *dev = output->dev; + int ret = 0; + if (output->edid_blob_ptr) + drm_property_destroy_blob(dev, output->edid_blob_ptr); + + output->edid_blob_ptr = drm_property_create_blob(output->dev, 128, edid); + + ret = drm_output_property_set_value(output, dev->mode_config.edid_property, output->edid_blob_ptr->id); + return ret; +} +EXPORT_SYMBOL(drm_mode_output_update_edid_property); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d028f75f..2c77d9d7 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -236,8 +236,8 @@ struct drm_framebuffer { struct drm_property_blob { struct list_head head; - unsigned int id; unsigned int length; + unsigned int id; void *data; }; @@ -456,7 +456,7 @@ struct drm_output { void *driver_private; struct list_head user_modes; - + struct drm_property_blob *edid_blob_ptr; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; }; @@ -547,7 +547,7 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); extern void drm_mode_output_list_update(struct drm_output *output); - +extern int drm_mode_output_update_edid_property(struct drm_output *output, unsigned char *edid); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, @@ -594,5 +594,7 @@ extern int drm_mode_detachmode_ioctl(struct drm_device *dev, extern int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_getblob_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index a88ae8b5..f8665be7 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -125,6 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY), diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index d3ad4654..2ab6a27b 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -246,5 +246,4 @@ void intel_crt_init(struct drm_device *dev) output->interlace_allowed = 0; output->doublescan_allowed = 0; - drm_output_attach_property(output, dev->mode_config.edid_property, 0); } diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c index 346cf1ac..f8bf496c 100644 --- a/linux-core/intel_modes.c +++ b/linux-core/intel_modes.c @@ -55,6 +55,7 @@ int intel_ddc_get_modes(struct drm_output *output) edid = drm_get_edid(output, &intel_output->ddc_bus->adapter); if (edid) { + drm_mode_output_update_edid_property(output, edid); ret = drm_add_edid_modes(output, edid); kfree(edid); } diff --git a/shared-core/drm.h b/shared-core/drm.h index 7649abd6..0c66f85c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -980,11 +980,6 @@ struct drm_mode_property_enum { unsigned char name[DRM_PROP_NAME_LEN]; }; -struct drm_mode_property_blob { - uint64_t data_ptr; - uint32_t length; -}; - struct drm_mode_get_property { uint64_t values_ptr; /* values and blob lengths */ uint64_t enum_blob_ptr; /* enum and blob id ptrs */ @@ -997,6 +992,12 @@ struct drm_mode_get_property { int count_enum_blobs; }; +struct drm_mode_get_blob { + uint32_t blob_id; + uint32_t length; + uint64_t data; +}; + struct drm_mode_fb_cmd { unsigned int buffer_id; unsigned int width, height; @@ -1111,7 +1112,7 @@ struct drm_mode_mode_cmd { #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) -#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_propblob) +#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_blob) #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 46f88d82..c396da41 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -75,9 +75,14 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) printf("%d ", props->values[j]); printf("\n\tenums %d: \n", props->count_enums); + + if (props->flags & DRM_MODE_PROP_BLOB) { + drmModePropertyBlobPtr blob; - if (prop->flags & DRM_MODE_PROP_BLOB) { - + blob = drmModeGetPropertyBlob(fd, output->prop_values[i]); + + printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); + drmModeFreePropertyBlob(blob); } else { for (j = 0; j < props->count_enums; j++) { -- cgit v1.2.3