This allow the user to retrieve a list of properties for an output.
Properties can either be 32-bit values or an enum with an associated name.
Range properties are to be supported.
This API is probably not all correct, I may make properties part of the general
resource get when I think about it some more.
So basically you can create properties and attached them to whatever outputs you want,
so it should be possible to create some generics and just attach them to every output.
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;
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;
/* 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)
}
+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);
+}
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*/
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;
*/
extern int drmModeDetachMode(int fd, uint32_t outputId, uint32_t modeId);
+extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId);
+extern void drmModeFreeProperty(drmModePropertyPtr ptr);
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);
}
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);
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;
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)
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;
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;
}
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);
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;
+}
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;
};
#define DRM_OUTPUT_MAX_UMODES 16
+#define DRM_OUTPUT_MAX_PROPERTY 16
#define DRM_OUTPUT_LEN 32
/**
* drm_output - central DRM output control structure
u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES];
+ u32 property_ids[DRM_OUTPUT_MAX_PROPERTY];
+ u32 property_values[DRM_OUTPUT_MAX_PROPERTY];
};
/**
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? */
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);
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__ */
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),
#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)
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 {
#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)
/*@}*/
/**
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);
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]);