diff options
-rw-r--r-- | libdrm/xf86drmMode.c | 77 | ||||
-rw-r--r-- | libdrm/xf86drmMode.h | 17 | ||||
-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 | ||||
-rw-r--r-- | shared-core/drm.h | 29 | ||||
-rw-r--r-- | tests/mode/modetest.c | 34 |
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]); |