fb: make fb interface use user mode attach/detach for adding modes

This commit is contained in:
Dave Airlie 2007-11-26 15:06:42 +11:00
parent 362f428320
commit f9ac54b031
3 changed files with 104 additions and 59 deletions

View 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;

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

View 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;