diff options
Diffstat (limited to 'linux-core')
-rw-r--r-- | linux-core/drm_crtc.c | 207 | ||||
-rw-r--r-- | linux-core/drm_crtc.h | 34 | ||||
-rw-r--r-- | linux-core/drm_drv.c | 1 |
3 files changed, 236 insertions, 6 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bc292703..cd60f522 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -711,6 +711,7 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); + INIT_LIST_HEAD(&dev->mode_config.property_list); INIT_LIST_HEAD(&dev->mode_config.usermode_list); idr_init(&dev->mode_config.crtc_idr); } @@ -944,14 +945,20 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_crtc *crtc, *ct; struct drm_framebuffer *fb, *fbt; struct drm_display_mode *mode, *mt; + struct drm_property *property, *pt; + list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_output_destroy(output); } + list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, head) { + drm_property_destroy(dev, property); + } + list_for_each_entry_safe(mode, mt, &dev->mode_config.usermode_list, head) { drm_mode_destroy(dev, mode); } - + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { if (fb->bo->type != drm_bo_type_kernel) drm_framebuffer_destroy(fb); @@ -1331,6 +1338,7 @@ int drm_mode_getoutput(struct drm_device *dev, struct drm_output *output; struct drm_display_mode *mode; int mode_count = 0; + int props_count = 0; int ret = 0; int copied = 0; int i; @@ -1341,7 +1349,7 @@ int drm_mode_getoutput(struct drm_device *dev, output= idr_find(&dev->mode_config.crtc_idr, out_resp->output); if (!output || (output->id != out_resp->output)) { ret = -EINVAL; - goto done; + goto out; } list_for_each_entry(mode, &output->modes, head) @@ -1351,6 +1359,12 @@ int drm_mode_getoutput(struct drm_device *dev, if (output->user_mode_ids[i] != 0) mode_count++; + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] != 0) { + props_count++; + } + } + strncpy(out_resp->name, output->name, DRM_OUTPUT_NAME_LEN); out_resp->name[DRM_OUTPUT_NAME_LEN-1] = 0; @@ -1365,20 +1379,42 @@ int drm_mode_getoutput(struct drm_device *dev, out_resp->crtcs = output->possible_crtcs; out_resp->clones = output->possible_clones; + if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; list_for_each_entry(mode, &output->modes, head) { out_resp->modes[copied++] = mode->mode_id; } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] != 0) - out_resp->modes[copied++] = output->user_mode_ids[i]; + if (output->user_mode_ids[i] != 0) { + if (put_user(output->user_mode_ids[i], out_resp->modes + copied)) + return -EFAULT; + copied++; + } } - } out_resp->count_modes = mode_count; -done: + if ((out_resp->count_props >= props_count) && props_count) { + copied = 0; + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] != 0) { + if (put_user(output->property_ids[i], out_resp->props + copied)) { + ret = -EFAULT; + goto out; + } + + if (put_user(output->property_values[i], out_resp->prop_values + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + } + out_resp->count_props = props_count; + +out: mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1783,6 +1819,7 @@ int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mo list_for_each_entry(output, &dev->mode_config.output_list, head) { drm_mode_detachmode(dev, output, mode); } + return 0; } EXPORT_SYMBOL(drm_mode_detachmode_crtc); @@ -1949,3 +1986,161 @@ out: mutex_unlock(&dev->mode_config.mutex); return ret; } + +struct drm_property *drm_property_create(struct drm_device *dev, int flags, + const char *name, int num_values) +{ + struct drm_property *property = NULL; + + property = kzalloc(sizeof(struct drm_output), GFP_KERNEL); + if (!property) + return NULL; + + property->values = kzalloc(sizeof(uint32_t)*num_values, GFP_KERNEL); + if (!property->values) + goto fail; + + property->id = drm_idr_get(dev, property); + property->flags = flags; + property->num_values = num_values; + INIT_LIST_HEAD(&property->enum_list); + + if (name) + strncpy(property->name, name, DRM_PROP_NAME_LEN); + + list_add_tail(&property->head, &dev->mode_config.property_list); + return property; +fail: + kfree(property); + return NULL; +} +EXPORT_SYMBOL(drm_property_create); + +int drm_property_add_enum(struct drm_property *property, int index, + uint32_t value, const char *name) +{ + struct drm_property_enum *prop_enum; + + if (!(property->flags & DRM_MODE_PROP_ENUM)) + return -EINVAL; + + if (!list_empty(&property->enum_list)) { + list_for_each_entry(prop_enum, &property->enum_list, head) { + if (prop_enum->value == value) { + strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); + prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; + return 0; + } + } + } + + prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); + if (!prop_enum) + return -ENOMEM; + + strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); + prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; + prop_enum->value = value; + + property->values[index] = value; + list_add_tail(&prop_enum->head, &property->enum_list); + return 0; +} +EXPORT_SYMBOL(drm_property_add_enum); + +void drm_property_destroy(struct drm_device *dev, struct drm_property *property) +{ + struct drm_property_enum *prop_enum, *pt; + + list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { + list_del(&prop_enum->head); + kfree(prop_enum); + } + + kfree(property->values); + drm_idr_put(dev, property->id); + list_del(&property->head); + kfree(property); +} +EXPORT_SYMBOL(drm_property_destroy); + + +int drm_output_attach_property(struct drm_output *output, + struct drm_property *property, int init_val) +{ + int i; + + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] == 0) { + output->property_ids[i] = property->id; + output->property_values[i] = init_val; + break; + } + } + + if (i == DRM_OUTPUT_MAX_PROPERTY) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(drm_output_attach_property); + +int drm_mode_getproperty_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_get_property *out_resp = data; + struct drm_property *property; + int enum_count = 0; + int value_count = 0; + int ret = 0, i; + int copied; + struct drm_property_enum *prop_enum; + + mutex_lock(&dev->mode_config.mutex); + property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); + if (!property || (property->id != out_resp->prop_id)) { + ret = -EINVAL; + goto done; + } + + + list_for_each_entry(prop_enum, &property->enum_list, head) + enum_count++; + + value_count = property->num_values; + + strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); + out_resp->name[DRM_PROP_NAME_LEN-1] = 0; + out_resp->flags = property->flags; + + if ((out_resp->count_values >= value_count) && value_count) { + for (i = 0; i < value_count; i++) { + if (put_user(property->values[i], out_resp->values + i)) { + ret = -EFAULT; + goto done; + } + } + } + out_resp->count_values = value_count; + + if ((out_resp->count_enums >= enum_count) && enum_count) { + copied = 0; + list_for_each_entry(prop_enum, &property->enum_list, head) { + if (put_user(prop_enum->value, &out_resp->enums[copied].value)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user(&out_resp->enums[copied].name, + prop_enum->name, DRM_PROP_NAME_LEN)) { + ret = -EFAULT; + goto done; + } + copied++; + } + } + out_resp->count_enums = enum_count; + +done: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index fc97525d..011903ce 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -233,6 +233,24 @@ struct drm_framebuffer { void *virtual_base; struct list_head filp_head; }; + +struct drm_property_enum { + struct list_head head; + uint32_t value; + unsigned char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_property { + struct list_head head; + int id; /* idr assigned */ + uint32_t flags; + char name[DRM_PROP_NAME_LEN]; + uint32_t num_values; + uint32_t *values; + + struct list_head enum_list; +}; + struct drm_crtc; struct drm_output; @@ -376,6 +394,7 @@ struct drm_output_funcs { }; #define DRM_OUTPUT_MAX_UMODES 16 +#define DRM_OUTPUT_MAX_PROPERTY 16 #define DRM_OUTPUT_LEN 32 /** * drm_output - central DRM output control structure @@ -431,6 +450,8 @@ struct drm_output { u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES]; + u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; + u32 property_values[DRM_OUTPUT_MAX_PROPERTY]; }; /** @@ -464,6 +485,9 @@ struct drm_mode_config { struct list_head crtc_list; struct list_head usermode_list; + + struct list_head property_list; + int min_width, min_height; int max_width, max_height; /* DamagePtr rotationDamage? */ @@ -529,6 +553,14 @@ extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); +extern int drm_output_attach_property(struct drm_output *output, + struct drm_property *property, int init_val); +extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, + const char *name, int num_values); +extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); +extern int drm_property_add_enum(struct drm_property *property, int index, + uint32_t value, const char *name); + /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -554,5 +586,7 @@ extern int drm_mode_attachmode_ioctl(struct drm_device *dev, extern int drm_mode_detachmode_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_getproperty_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 e606bc6a..b3e00e84 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -128,6 +128,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMMODE, drm_mode_rmmode_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), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |