summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drm_crtc.c207
-rw-r--r--linux-core/drm_crtc.h34
-rw-r--r--linux-core/drm_drv.c1
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),