summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/drm_crtc.c92
-rw-r--r--linux-core/drm_crtc.h6
-rw-r--r--linux-core/intel_fb.c65
3 files changed, 104 insertions, 59 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index d5f3a0ed..bc292703 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -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;
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
index a9f6a135..fc97525d 100644
--- a/linux-core/drm_crtc.h
+++ b/linux-core/drm_crtc.h
@@ -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,
diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c
index 3a4ffc7f..5f43f291 100644
--- a/linux-core/intel_fb.c
+++ b/linux-core/intel_fb.c
@@ -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;