summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdrm/xf86drmMode.c77
-rw-r--r--libdrm/xf86drmMode.h17
-rw-r--r--linux-core/drm_crtc.c207
-rw-r--r--linux-core/drm_crtc.h34
-rw-r--r--linux-core/drm_drv.c1
-rw-r--r--shared-core/drm.h29
-rw-r--r--tests/mode/modetest.c34
7 files changed, 387 insertions, 12 deletions
diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c
index e400f219..f697232d 100644
--- a/libdrm/xf86drmMode.c
+++ b/libdrm/xf86drmMode.c
@@ -316,7 +316,7 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id)
{
struct drm_mode_get_output out;
- drmModeOutputPtr r = 0;
+ drmModeOutputPtr r = NULL;
out.output = output_id;
out.count_crtcs = 0;
@@ -325,18 +325,27 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id)
out.clones = 0;
out.count_modes = 0;
out.modes = 0;
+ out.count_props = 0;
+ out.props = NULL;
+ out.prop_values = NULL;
if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out))
return 0;
+ if (out.count_props) {
+ out.props = drmMalloc(out.count_props*sizeof(uint32_t));
+ out.prop_values = drmMalloc(out.count_props*sizeof(uint32_t));
+ }
+
if (out.count_modes)
out.modes = drmMalloc(out.count_modes*sizeof(uint32_t));
if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out))
goto err_allocs;
- if(!(r = drmMalloc(sizeof(*r))))
- return 0;
+ if(!(r = drmMalloc(sizeof(*r)))) {
+ goto err_allocs;
+ }
r->output_id = out.output;
r->crtc = out.crtc;
@@ -350,15 +359,19 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id)
/* TODO we should test if these alloc & cpy fails. */
r->crtcs = out.crtcs;
r->clones = out.clones;
+ r->count_props = out.count_props;
+ r->props = drmAllocCpy(out.props, out.count_props, sizeof(uint32_t));
+ r->prop_values = drmAllocCpy(out.prop_values, out.count_props, sizeof(uint32_t));
r->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(uint32_t));
strncpy(r->name, out.name, DRM_OUTPUT_NAME_LEN);
r->name[DRM_OUTPUT_NAME_LEN-1] = 0;
- return r;
err_allocs:
+ drmFree(out.prop_values);
+ drmFree(out.props);
drmFree(out.modes);
- return 0;
+ return r;
}
uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *mode_info)
@@ -396,3 +409,57 @@ int drmModeDetachMode(int fd, uint32_t output_id, uint32_t mode_id)
}
+drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
+{
+ struct drm_mode_get_property prop;
+ drmModePropertyPtr r;
+
+ prop.prop_id = property_id;
+ prop.count_enums = 0;
+ prop.count_values = 0;
+ prop.flags = 0;
+ prop.enums = NULL;
+ prop.values = NULL;
+
+ if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
+ return 0;
+
+ if (prop.count_values)
+ prop.values = drmMalloc(prop.count_values * sizeof(uint32_t));
+
+ if (prop.count_enums)
+ prop.enums = drmMalloc(prop.count_enums * sizeof(struct drm_mode_property_enum));
+
+ if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
+ r = NULL;
+ goto err_allocs;
+ }
+
+ if (!(r = drmMalloc(sizeof(*r))))
+ return NULL;
+
+ r->prop_id = prop.prop_id;
+ r->count_values = prop.count_values;
+ r->count_enums = prop.count_enums;
+
+ r->values = drmAllocCpy(prop.values, prop.count_values, sizeof(uint32_t));
+ r->enums = drmAllocCpy(prop.enums, prop.count_enums, sizeof(struct drm_mode_property_enum));
+ strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
+ r->name[DRM_PROP_NAME_LEN-1] = 0;
+
+err_allocs:
+ drmFree(prop.values);
+ drmFree(prop.enums);
+
+ return r;
+}
+
+void drmModeFreeProperty(drmModePropertyPtr ptr)
+{
+ if (!ptr)
+ return;
+
+ drmFree(ptr->values);
+ drmFree(ptr->enums);
+ drmFree(ptr);
+}
diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h
index be9d84af..5e966e95 100644
--- a/libdrm/xf86drmMode.h
+++ b/libdrm/xf86drmMode.h
@@ -70,6 +70,17 @@ typedef struct _drmModeRes {
typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr;
+typedef struct _drmModeProperty {
+ unsigned int prop_id;
+ unsigned int flags;
+ unsigned char name[DRM_PROP_NAME_LEN];
+ int count_values;
+ uint32_t *values;
+ int count_enums;
+ struct drm_mode_property_enum *enums;
+
+} drmModePropertyRes, *drmModePropertyPtr;
+
typedef struct _drmModeCrtc {
unsigned int crtc_id;
unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/
@@ -121,6 +132,10 @@ typedef struct _drmModeOutput {
int count_modes;
uint32_t *modes; /**< List of modes ids */
+ int count_props;
+ uint32_t *props; /**< List of property ids */
+ uint32_t *prop_values; /**< List of property values */
+
} drmModeOutput, *drmModeOutputPtr;
@@ -207,3 +222,5 @@ extern int drmModeAttachMode(int fd, uint32_t outputId, uint32_t modeId);
*/
extern int drmModeDetachMode(int fd, uint32_t outputId, uint32_t modeId);
+extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId);
+extern void drmModeFreeProperty(drmModePropertyPtr ptr);
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),
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 55675d2f..9219b456 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -897,6 +897,7 @@ struct drm_mm_init_arg {
#define DRM_DISPLAY_INFO_LEN 32
#define DRM_OUTPUT_NAME_LEN 32
#define DRM_DISPLAY_MODE_LEN 32
+#define DRM_PROP_NAME_LEN 32
#define DRM_MODE_TYPE_BUILTIN (1<<0)
#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN)
@@ -976,6 +977,32 @@ struct drm_mode_get_output {
int count_modes;
unsigned int __user *modes; /**< list of modes it supports */
+ int count_props;
+ unsigned int __user *props;
+ unsigned int __user *prop_values;
+};
+
+#define DRM_MODE_PROP_PENDING (1<<0)
+#define DRM_MODE_PROP_RANGE (1<<1)
+#define DRM_MODE_PROP_IMMUTABLE (1<<2)
+#define DRM_MODE_PROP_ENUM (1<<3) // enumerated type with text strings
+
+struct drm_mode_property_enum {
+ uint32_t value;
+ unsigned char name[DRM_PROP_NAME_LEN];
+};
+
+struct drm_mode_get_property {
+
+ unsigned int prop_id;
+ unsigned int flags;
+ unsigned char name[DRM_PROP_NAME_LEN];
+
+ int count_values;
+ uint32_t __user *values;
+
+ int count_enums;
+ struct drm_mode_property_enum *enums;
};
struct drm_mode_fb_cmd {
@@ -1096,6 +1123,8 @@ struct drm_mode_mode_cmd {
#define DRM_IOCTL_MODE_RMMODE DRM_IOWR(0xA8, unsigned int)
#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)
+
+#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property)
/*@}*/
/**
diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c
index 8f151758..50271af9 100644
--- a/tests/mode/modetest.c
+++ b/tests/mode/modetest.c
@@ -57,8 +57,10 @@ int printMode(struct drm_mode_modeinfo *mode)
int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id)
{
- int i = 0;
+ int i = 0, j;
struct drm_mode_modeinfo *mode = NULL;
+ drmModePropertyPtr props;
+ unsigned char *name = NULL;
printf("Output: %s\n", output->name);
printf("\tid : %i\n", id);
@@ -70,6 +72,36 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id)
printf("\tcount_clones : %i\n", output->count_clones);
printf("\tclones : %i\n", output->clones);
printf("\tcount_modes : %i\n", output->count_modes);
+ printf("\tcount_props : %i\n", output->count_props);
+
+ for (i = 0; i < output->count_props; i++) {
+ props = drmModeGetProperty(fd, output->props[i]);
+ name = NULL;
+ if (props) {
+ printf("Property: %s\n", props->name);
+ printf("\tid: %i\n", props->prop_id);
+ printf("\tflags: %i\n", props->flags);
+ printf("\tvalues %d: ", props->count_values);
+ for (j = 0; j < props->count_values; j++)
+ printf("%d ", props->values[j]);
+
+ printf("\n\tenums %d: \n", props->count_enums);
+
+ for (j = 0; j < props->count_enums; j++) {
+ if (output->prop_values[i] == props->enums[j].value)
+ name = props->enums[j].name;
+ printf("\t\t%d = %s\n", props->enums[j].value, props->enums[j].name);
+ }
+
+ if (props->count_enums && name) {
+ printf("\toutput property name %s %s\n", props->name, name);
+ } else {
+ printf("\toutput property id %s %i\n", props->name, output->prop_values[i]);
+ }
+
+ drmModeFreeProperty(props);
+ }
+ }
for (i = 0; i < output->count_modes; i++) {
mode = findMode(res, output->modes[i]);