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), | 
