checkpoint commit: implement SetCrtc so modes can in theory be set from user
authorDave Airlie <airlied@linux.ie>
Thu, 5 Apr 2007 08:01:02 +0000 (18:01 +1000)
committerDave Airlie <airlied@linux.ie>
Thu, 5 Apr 2007 08:01:02 +0000 (18:01 +1000)
This hooks up the userspace mode set it "seems" to work.

libdrm/xf86drmMode.c
linux-core/drm_crtc.c
linux-core/drm_crtc.h
linux-core/drm_drv.c
shared-core/drm.h

index b48ca83..c4403b1 100644 (file)
@@ -286,7 +286,7 @@ err_allocs:
        return 0;
 }
 
-#if 0
+
 int drmModeSetCrtc(
                int fd, uint32_t crtcId, uint32_t bufferId,
                uint32_t x, uint32_t y, uint32_t modeId,
@@ -302,15 +302,16 @@ int drmModeSetCrtc(
 
        crtc.x             = x;
        crtc.y             = y;
-       crtc.crtcId        = crtcId;
-       crtc.bufferId      = bufferId;
+       crtc.crtc_id        = crtcId;
+       crtc.fb_id      = bufferId;
        crtc.set_outputs   = outputs;
        crtc.count_outputs = count;
        crtc.mode          = modeId;
 
-       //      return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
+       return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
 }
 
+#if 0
 drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtc, int *count)
 {
        /* TODO impl */
index 2dbe6de..8e03dd5 100644 (file)
@@ -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;
+}
index e608b46..a2c552e 100644 (file)
@@ -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__ */
 
index 7d436f8..c8ee054 100644 (file)
@@ -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 )
index 1af0be3..49bc41b 100644 (file)
@@ -1036,7 +1036,7 @@ struct drm_mode_get_output {
 #define DRM_IOCTL_MODE_GETRESOURCES     DRM_IOWR(0xA0, struct drm_mode_card_res)
 #define DRM_IOCTL_MODE_GETCRTC          DRM_IOWR(0xA1, struct drm_mode_crtc)
 #define DRM_IOCTL_MODE_GETOUTPUT        DRM_IOWR(0xA2, struct drm_mode_get_output)
-
+#define DRM_IOCTL_MODE_SETCRTC          DRM_IOWR(0xA3, struct drm_mode_crtc)
 /*@}*/
 
 /**