diff options
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/drm_crtc.c | 128 | ||||
| -rw-r--r-- | linux-core/drm_crtc.h | 4 | ||||
| -rw-r--r-- | linux-core/drm_drv.c | 1 | 
3 files changed, 127 insertions, 6 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 2dbe6de1..8e03dd5f 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -302,10 +302,10 @@ bool drm_set_desired_modes(struct drm_device *dev)  			continue;  		memset(&crtc->mode, 0, sizeof(crtc->mode)); -		if (!crtc->desired_mode.crtc_hdisplay) { +		if (!crtc->desired_mode->crtc_hdisplay) {  		} -		if (!drm_crtc_set_mode(crtc, &crtc->desired_mode, +		if (!drm_crtc_set_mode(crtc, crtc->desired_mode,  				       crtc->desired_x, crtc->desired_y))  			return false;  	} @@ -556,7 +556,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow)  				break;  			DRM_DEBUG("Setting desired mode for output %s\n", output->name);  			drm_mode_debug_printmodeline(dev, des_mode); -			output->crtc->desired_mode = *des_mode; +			output->crtc->desired_mode = des_mode;  			output->initial_x = 0;  			output->initial_y = 0;  			use_output = output; @@ -568,7 +568,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow)  				break;  			DRM_DEBUG("Setting desired mode for output %s\n", output->name);  			drm_mode_debug_printmodeline(dev, des_mode); -			output->crtc->desired_mode = *des_mode; +			output->crtc->desired_mode = des_mode;  #endif  			output->initial_x = 0;  			output->initial_y = 0; @@ -596,6 +596,68 @@ void drm_crtc_config_cleanup(drm_device_t *dev)  }  EXPORT_SYMBOL(drm_crtc_config_cleanup); +int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set) +{ +	drm_device_t *dev = crtc->dev; +	struct drm_crtc **save_crtcs, *new_crtc; +	bool save_enabled = crtc->enabled; +	bool changed; +	struct drm_output *output; +	int count = 0, ro; + +	save_crtcs = kzalloc(dev->crtc_config.num_crtc * sizeof(struct drm_crtc *), GFP_KERNEL); +	if (!save_crtcs) +		return -ENOMEM; + +	if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) +		changed = true; + +	if (crtc->mode.mode_id != new_mode->mode_id) +		changed = true; + +	list_for_each_entry(output, &dev->crtc_config.output_list, head) { +		save_crtcs[count++] = output->crtc; + +		if (output->crtc == crtc) +			new_crtc = NULL; +		else +			new_crtc = output->crtc; + +		for (ro = 0; ro < crtc_info->count_outputs; ro++) +		{ +			if (output_set[ro] == output) +				new_crtc = crtc; +		} +		if (new_crtc != output->crtc) { +			changed = true; +			output->crtc = new_crtc; +		} +	} + +	if (changed) { +		crtc->enabled = new_mode != NULL; +		if (new_mode) { +			DRM_DEBUG("attempting to set mode from userspace\n"); +			drm_mode_debug_printmodeline(dev, new_mode); +			if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x, +					       crtc_info->y)) { +				crtc->enabled = save_enabled; +				count = 0; +				list_for_each_entry(output, &dev->crtc_config.output_list, head) +					output->crtc = save_crtcs[count++]; +				kfree(save_crtcs); +				return -EINVAL; +			} +			crtc->desired_x = crtc_info->x; +			crtc->desired_y = crtc_info->y; +			crtc->desired_mode =  new_mode; +		} +		drm_disable_unused_functions(dev); +	} +	kfree(save_crtcs); +	return 0; +} +  void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in)  { @@ -757,7 +819,6 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp,  	drm_device_t *dev = priv->head->dev;  	struct drm_mode_get_output __user *argp = (void __user *)arg;  	struct drm_mode_get_output out_resp; -	struct drm_crtc *crtc;  	struct drm_output *output;  	struct drm_display_mode *mode;  	int mode_count = 0; @@ -800,3 +861,60 @@ done:  	return retcode;  } + + +int drm_mode_setcrtc(struct inode *inode, struct file *filp, +		     unsigned int cmd, unsigned long arg) +{ +	drm_file_t *priv = filp->private_data; +	drm_device_t *dev = priv->head->dev; +	struct drm_mode_crtc __user *argp = (void __user *)arg; +	struct drm_mode_crtc crtc_req; +	struct drm_crtc *crtc; +	struct drm_output **output_set = NULL, *output; +	struct drm_display_mode *mode; +	int retcode = 0; +	int i; + +	if (copy_from_user(&crtc_req, argp, sizeof(crtc_req))) +		return -EFAULT; + +	crtc = idr_find(&dev->crtc_config.crtc_idr, crtc_req.crtc_id); +	if (!crtc || (crtc->id != crtc_req.crtc_id)) +		return -EINVAL; + +	if (crtc_req.mode) { +		mode = idr_find(&dev->crtc_config.crtc_idr, crtc_req.mode); +		if (!mode || (mode->mode_id != crtc_req.mode)) +			return -EINVAL; +	} else +		mode = NULL; + +	if (crtc_req.count_outputs == 0 && mode) +		return -EINVAL; + +	if (crtc_req.count_outputs > 0 && !mode) +		return -EINVAL; + +	if (crtc_req.count_outputs > 0) { +		u32 out_id; +		output_set = kmalloc(crtc_req.count_outputs * sizeof(struct drm_output *), GFP_KERNEL); +		if (!output_set) +			return -ENOMEM; + +		for (i = 0; i < crtc_req.count_outputs; i++) +		{ +			if (get_user(out_id, &crtc_req.set_outputs[i])) +				return -EFAULT; + +			output = idr_find(&dev->crtc_config.crtc_idr, out_id); +			if (!output || (out_id != output->id)) +				return -EINVAL; + +			output_set[i] = output; +		} +	} +		 +	retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set); +	return retcode; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index e608b462..a2c552e6 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -272,7 +272,7 @@ struct drm_crtc {  	struct drm_display_mode mode;  	int x, y; -	struct drm_display_mode desired_mode; +	struct drm_display_mode *desired_mode;  	int desired_x, desired_y;  	const struct drm_crtc_funcs *funcs;  	void *driver_private; @@ -443,5 +443,7 @@ extern int drm_mode_getcrtc(struct inode *inode, struct file *filp,  			    unsigned int cmd, unsigned long arg);  extern int drm_mode_getoutput(struct inode *inode, struct file *filp,  			      unsigned int cmd, unsigned long arg); +extern int drm_mode_setcrtc(struct inode *inode, struct file *filp, +			    unsigned int cmd, unsigned long arg);  #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 7d436f8a..c8ee054f 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -126,6 +126,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {  	[DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY},  	[DRM_IOCTL_NR(DRM_IOCTL_MODE_GETCRTC)] = {drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY},  	[DRM_IOCTL_NR(DRM_IOCTL_MODE_GETOUTPUT)] = {drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY}, +	[DRM_IOCTL_NR(DRM_IOCTL_MODE_SETCRTC)] = {drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY},  };  #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )  | 
