fb: make fb interface use user mode attach/detach for adding modes
authorDave Airlie <airlied@redhat.com>
Mon, 26 Nov 2007 04:06:42 +0000 (15:06 +1100)
committerDave Airlie <airlied@redhat.com>
Mon, 26 Nov 2007 04:06:42 +0000 (15:06 +1100)
linux-core/drm_crtc.c
linux-core/drm_crtc.h
linux-core/intel_fb.c

index d5f3a0e..bc29270 100644 (file)
@@ -1722,6 +1722,70 @@ int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode)
 }
 EXPORT_SYMBOL(drm_mode_rmmode);
 
+static int drm_mode_attachmode(struct drm_device *dev,
+                              struct drm_output *output,
+                              struct drm_display_mode *mode)
+{
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
+               if (output->user_mode_ids[i] == 0) {
+                       output->user_mode_ids[i] = mode->mode_id;
+                       mode->output_count++;
+                       break;
+               }
+       }
+
+       if (i == DRM_OUTPUT_MAX_UMODES)
+               ret = -ENOSPC;
+
+       return ret;
+}
+
+int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
+                            struct drm_display_mode *mode)
+{
+       struct drm_output *output;
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               if (output->crtc == crtc)
+                       drm_mode_attachmode(dev, output, mode);
+       }
+}
+EXPORT_SYMBOL(drm_mode_attachmode_crtc);
+
+static int drm_mode_detachmode(struct drm_device *dev,
+                              struct drm_output *output,
+                              struct drm_display_mode *mode)
+{
+       int found = 0;
+       int ret = 0, i;
+
+       for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
+               if (output->user_mode_ids[i] == mode->mode_id) {
+                       output->user_mode_ids[i] = 0;
+                       mode->output_count--;
+                       found = 1;
+               }
+       }
+
+       if (!found)
+               ret = -EINVAL;
+
+       return ret;
+}
+
+int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode)
+{
+       struct drm_output *output;
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               drm_mode_detachmode(dev, output, mode);
+       }
+}
+EXPORT_SYMBOL(drm_mode_detachmode_crtc);
+
 /**
  * drm_fb_addmode - adds a user defined mode
  * @inode: inode from the ioctl
@@ -1822,7 +1886,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
        struct drm_mode_mode_cmd *mode_cmd = data;
        struct drm_output *output;
        struct drm_display_mode *mode;
-       int i, ret = 0;
+       int ret = 0;
 
        mutex_lock(&dev->mode_config.mutex);
 
@@ -1838,17 +1902,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
                goto out;
        }
 
-       for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
-               if (output->user_mode_ids[i] == 0) {
-                       output->user_mode_ids[i] = mode->mode_id;
-                       mode->output_count++;
-                       break;
-               }
-       }
-
-       if (i == DRM_OUTPUT_MAX_UMODES)
-               ret = -ENOSPC;
-
+       ret = drm_mode_attachmode(dev, output, mode);
 out:
        mutex_unlock(&dev->mode_config.mutex);
        return ret;
@@ -1873,7 +1927,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
        struct drm_mode_mode_cmd *mode_cmd = data;
        struct drm_output *output;
        struct drm_display_mode *mode;
-       int i, found = 0, ret = 0;
+       int ret = 0;
 
        mutex_lock(&dev->mode_config.mutex);
 
@@ -1890,17 +1944,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
        }
 
 
-       for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) {
-               if (output->user_mode_ids[i] == mode->mode_id) {
-                       output->user_mode_ids[i] = 0;
-                       mode->output_count--;
-                       found = 1;
-               }
-       }
-
-       if (!found)
-               ret = -EINVAL;
-
+       ret = drm_mode_detachmode(dev, output, mode);
 out:          
        mutex_unlock(&dev->mode_config.mutex);
        return ret;
index a9f6a13..fc97525 100644 (file)
@@ -497,6 +497,12 @@ extern void drm_disable_unused_functions(struct drm_device *dev);
 extern void drm_mode_addmode(struct drm_device *dev, struct drm_display_mode *user_mode);
 extern int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode);
 
+/* for us by fb module */
+extern int drm_mode_attachmode_crtc(struct drm_device *dev,
+                                   struct drm_crtc *crtc,
+                                   struct drm_display_mode *mode);
+extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode);
+
 extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
 extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
 extern void drm_mode_list_concat(struct list_head *head,
index 3a4ffc7..5f43f29 100644 (file)
@@ -223,7 +223,7 @@ static int intelfb_set_par(struct fb_info *info)
        struct intelfb_par *par = info->par;
        struct drm_framebuffer *fb = par->crtc->fb;
        struct drm_device *dev = par->dev;
-        struct drm_display_mode *drm_mode;
+        struct drm_display_mode *drm_mode, *search_mode;
         struct drm_output *output;
         struct fb_var_screeninfo *var = &info->var;
        int found = 0;
@@ -248,34 +248,7 @@ static int intelfb_set_par(struct fb_info *info)
 
         info->screen_size = info->fix.smem_len; /* ??? */
 
-        /* Should we walk the output's modelist or just create our own ???
-         * For now, we create and destroy a mode based on the incoming 
-         * parameters. But there's commented out code below which scans 
-         * the output list too.
-         */
-#if 0
-        list_for_each_entry(output, &dev->mode_config.output_list, head) {
-                if (output->crtc == par->crtc)
-                        break;
-        }
-    
-        list_for_each_entry(drm_mode, &output->modes, head) {
-                if (drm_mode->hdisplay == var->xres &&
-                    drm_mode->vdisplay == var->yres &&
-                    (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) &&
-                    (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) {
-                       found = 1;
-                       break;
-               }
-        }
-
-       if (!found) {
-               DRM_ERROR("Couldn't find a mode for requested %dx%d-%d\n",
-                       var->xres,var->yres,var_to_refresh(var));
-               return -EINVAL;
-       }
-#else
-       
+       /* create a drm mode */
         drm_mode = drm_mode_create(dev);
         drm_mode->hdisplay = var->xres;
         drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
@@ -289,14 +262,36 @@ static int intelfb_set_par(struct fb_info *info)
         drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
         drm_mode_set_name(drm_mode);
        drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
-#endif
 
-       drm_mode_addmode(dev, drm_mode);
-       if (par->fb_mode)
-               drm_mode_rmmode(dev, par->fb_mode);
+        list_for_each_entry(output, &dev->mode_config.output_list, head) {
+                if (output->crtc == par->crtc)
+                        break;
+        }
+
+       drm_mode_debug_printmodeline(dev, drm_mode);    
+        list_for_each_entry(search_mode, &output->modes, head) {
+               DRM_ERROR("mode %s : %s\n", drm_mode->name, search_mode->name);
+               drm_mode_debug_printmodeline(dev, search_mode);
+               if (drm_mode_equal(drm_mode, search_mode)) {
+                       drm_mode_destroy(dev, drm_mode);
+                       drm_mode = search_mode;
+                       found = 1;
+                       break;
+               }
+       }
        
-       par->fb_mode = drm_mode;
-       drm_mode_debug_printmodeline(dev, drm_mode);
+       if (!found) {
+               drm_mode_addmode(dev, drm_mode);
+               if (par->fb_mode) {
+                       drm_mode_detachmode_crtc(dev, par->fb_mode);
+                       drm_mode_rmmode(dev, par->fb_mode);
+               }
+       
+               par->fb_mode = drm_mode;
+               drm_mode_debug_printmodeline(dev, drm_mode);
+               /* attach mode */
+               drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode);
+       }
 
         if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
                 return -EINVAL;