Commit ef49e03a authored by Antonino Daplas's avatar Antonino Daplas Committed by Linus Torvalds

[PATCH] Video Mode Handling - Save per-display graphics/display settings

This patch adds the following:

a. convert struct fb_var_screeninfo to struct display and vice versa

b. save settings of graphics card to struct display

c. save settings of display to struct display as a pointer to a struct
   fb_videomode

d. check var in fb_set_var for modes, and if unique, add them to the mode list.
Signed-off-by: default avatarAntonino Daplas <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 80f6ef4a
...@@ -625,6 +625,47 @@ void accel_clear_margins(struct vc_data *vc, struct fb_info *info, ...@@ -625,6 +625,47 @@ void accel_clear_margins(struct vc_data *vc, struct fb_info *info,
* Low Level Operations * Low Level Operations
*/ */
/* NOTE: fbcon cannot be __init: it may be called from take_over_console later */ /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
static int var_to_display(struct display *disp,
struct fb_var_screeninfo *var,
struct fb_info *info)
{
disp->xres_virtual = var->xres_virtual;
disp->yres_virtual = var->yres_virtual;
disp->bits_per_pixel = var->bits_per_pixel;
disp->grayscale = var->grayscale;
disp->nonstd = var->nonstd;
disp->accel_flags = var->accel_flags;
disp->height = var->height;
disp->width = var->width;
disp->red = var->red;
disp->green = var->green;
disp->blue = var->blue;
disp->transp = var->transp;
disp->mode = fb_match_mode(var, &info->monspecs.modelist);
if (disp->mode == NULL)
/* This should not happen */
return -EINVAL;
return 0;
}
static void display_to_var(struct fb_var_screeninfo *var,
struct display *disp)
{
fb_videomode_to_var(var, disp->mode);
var->xres_virtual = disp->xres_virtual;
var->yres_virtual = disp->yres_virtual;
var->bits_per_pixel = disp->bits_per_pixel;
var->grayscale = disp->grayscale;
var->nonstd = disp->nonstd;
var->accel_flags = disp->accel_flags;
var->height = disp->height;
var->width = disp->width;
var->red = disp->red;
var->green = disp->green;
var->blue = disp->blue;
var->transp = disp->transp;
}
static const char *fbcon_startup(void) static const char *fbcon_startup(void)
{ {
const char *display_desc = "frame buffer device"; const char *display_desc = "frame buffer device";
...@@ -798,6 +839,9 @@ static void fbcon_init(struct vc_data *vc, int init) ...@@ -798,6 +839,9 @@ static void fbcon_init(struct vc_data *vc, int init)
info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
if (var_to_display(p, &info->var, info))
return;
/* If we are not the first console on this /* If we are not the first console on this
fb, copy the font from that console */ fb, copy the font from that console */
t = &fb_display[display_fg]; t = &fb_display[display_fg];
...@@ -1174,6 +1218,8 @@ static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc) ...@@ -1174,6 +1218,8 @@ static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc)
int rows, cols, charcnt = 256; int rows, cols, charcnt = 256;
info->var.xoffset = info->var.yoffset = p->yscroll = 0; info->var.xoffset = info->var.yoffset = p->yscroll = 0;
if (var_to_display(p, &info->var, info))
return;
t = &fb_display[display_fg]; t = &fb_display[display_fg];
if (!vc->vc_font.data) { if (!vc->vc_font.data) {
vc->vc_font.data = p->fontdata = t->fontdata; vc->vc_font.data = p->fontdata = t->fontdata;
...@@ -1861,7 +1907,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, ...@@ -1861,7 +1907,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num]; struct display *p = &fb_display[vc->vc_num];
struct fb_var_screeninfo var = info->var; struct fb_var_screeninfo var = info->var;
int err; int x_diff, y_diff; int x_diff, y_diff;
int fw = vc->vc_font.width; int fw = vc->vc_font.width;
int fh = vc->vc_font.height; int fh = vc->vc_font.height;
...@@ -1870,15 +1916,31 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, ...@@ -1870,15 +1916,31 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
x_diff = info->var.xres - var.xres; x_diff = info->var.xres - var.xres;
y_diff = info->var.yres - var.yres; y_diff = info->var.yres - var.yres;
if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) {
char mode[40]; struct fb_videomode *mode;
DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
snprintf(mode, 40, "%ix%i", var.xres, var.yres); mode = fb_find_best_mode(&var, &info->monspecs.modelist);
err = fb_find_mode(&var, info, mode, info->monspecs.modedb, if (mode == NULL)
info->monspecs.modedb_len, NULL, return -EINVAL;
info->var.bits_per_pixel); fb_videomode_to_var(&var, mode);
if (!err || width > var.xres/fw || height > var.yres/fh) if (width > var.xres/fw || height > var.yres/fh)
return -EINVAL; return -EINVAL;
/*
* The following can probably have any value... Do we need to
* set all of them?
*/
var.bits_per_pixel = p->bits_per_pixel;
var.xres_virtual = p->xres_virtual;
var.yres_virtual = p->yres_virtual;
var.accel_flags = p->accel_flags;
var.width = p->width;
var.height = p->height;
var.red = p->red;
var.green = p->green;
var.blue = p->blue;
var.transp = p->transp;
var.nonstd = p->nonstd;
DPRINTK("resize now %ix%i\n", var.xres, var.yres); DPRINTK("resize now %ix%i\n", var.xres, var.yres);
if (CON_IS_VISIBLE(vc)) { if (CON_IS_VISIBLE(vc)) {
var.activate = FB_ACTIVATE_NOW | var.activate = FB_ACTIVATE_NOW |
...@@ -1886,6 +1948,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, ...@@ -1886,6 +1948,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
fb_set_var(info, &var); fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_MODESWITCH; info->flags &= ~FBINFO_MISC_MODESWITCH;
} }
var_to_display(p, &info->var, info);
} }
updatescrollmode(p, info, vc); updatescrollmode(p, info, vc);
return 0; return 0;
...@@ -1895,6 +1958,7 @@ static int fbcon_switch(struct vc_data *vc) ...@@ -1895,6 +1958,7 @@ static int fbcon_switch(struct vc_data *vc)
{ {
struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num]; struct display *p = &fb_display[vc->vc_num];
struct fb_var_screeninfo var;
int i; int i;
if (softback_top) { if (softback_top) {
...@@ -1920,8 +1984,6 @@ static int fbcon_switch(struct vc_data *vc) ...@@ -1920,8 +1984,6 @@ static int fbcon_switch(struct vc_data *vc)
conp2->vc_top = 0; conp2->vc_top = 0;
logo_shown = -1; logo_shown = -1;
} }
if (info)
info->var.yoffset = p->yscroll = 0;
/* /*
* FIXME: If we have multiple fbdev's loaded, we need to * FIXME: If we have multiple fbdev's loaded, we need to
...@@ -1936,7 +1998,18 @@ static int fbcon_switch(struct vc_data *vc) ...@@ -1936,7 +1998,18 @@ static int fbcon_switch(struct vc_data *vc)
registered_fb[i]->currcon = vc->vc_num; registered_fb[i]->currcon = vc->vc_num;
} }
fbcon_resize(vc, vc->vc_cols, vc->vc_rows); memset(&var, 0, sizeof(struct fb_var_screeninfo));
fb_videomode_to_var(&var, p->mode);
display_to_var(&var, p);
var.activate = FB_ACTIVATE_NOW;
/*
* make sure we don't unnecessarily trip the memcmp()
* in fb_set_var()
*/
info->var.activate = var.activate;
info->var.yoffset = info->var.xoffset = p->yscroll = 0;
fb_set_var(info, &var);
if (info->flags & FBINFO_MISC_MODESWITCH) { if (info->flags & FBINFO_MISC_MODESWITCH) {
if (info->fbops->fb_set_par) if (info->fbops->fb_set_par)
...@@ -1944,9 +2017,9 @@ static int fbcon_switch(struct vc_data *vc) ...@@ -1944,9 +2017,9 @@ static int fbcon_switch(struct vc_data *vc)
info->flags &= ~FBINFO_MISC_MODESWITCH; info->flags &= ~FBINFO_MISC_MODESWITCH;
} }
info->var.xoffset = info->var.yoffset = p->yscroll = 0;
vc->vc_can_do_color = (fb_get_color_depth(info) != 1); vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
updatescrollmode(p, info, vc);
switch (p->scrollmode) { switch (p->scrollmode) {
case SCROLL_WRAP_MOVE: case SCROLL_WRAP_MOVE:
...@@ -2575,6 +2648,7 @@ static void fbcon_modechanged(struct fb_info *info) ...@@ -2575,6 +2648,7 @@ static void fbcon_modechanged(struct fb_info *info)
info->var.xoffset = info->var.yoffset = p->yscroll = 0; info->var.xoffset = info->var.yoffset = p->yscroll = 0;
if (CON_IS_VISIBLE(vc)) { if (CON_IS_VISIBLE(vc)) {
var_to_display(p, &info->var, info);
cols = info->var.xres / vc->vc_font.width; cols = info->var.xres / vc->vc_font.width;
rows = info->var.yres / vc->vc_font.height; rows = info->var.yres / vc->vc_font.height;
vc_resize(vc->vc_num, cols, rows); vc_resize(vc->vc_num, cols, rows);
......
...@@ -33,6 +33,19 @@ struct display { ...@@ -33,6 +33,19 @@ struct display {
short yscroll; /* Hardware scrolling */ short yscroll; /* Hardware scrolling */
int vrows; /* number of virtual rows */ int vrows; /* number of virtual rows */
int cursor_shape; int cursor_shape;
u32 xres_virtual;
u32 yres_virtual;
u32 height;
u32 width;
u32 bits_per_pixel;
u32 grayscale;
u32 nonstd;
u32 accel_flags;
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;
struct fb_videomode *mode;
}; };
/* drivers/video/console/fbcon.c */ /* drivers/video/console/fbcon.c */
......
...@@ -1098,6 +1098,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -1098,6 +1098,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
return err; return err;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
struct fb_videomode mode;
info->var = *var; info->var = *var;
if (info->fbops->fb_set_par) if (info->fbops->fb_set_par)
...@@ -1107,6 +1108,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -1107,6 +1108,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
fb_set_cmap(&info->cmap, info); fb_set_cmap(&info->cmap, info);
fb_var_to_videomode(&mode, &info->var);
fb_add_videomode(&mode, &info->monspecs.modelist);
if (info->flags & FBINFO_MISC_MODECHANGEUSER) { if (info->flags & FBINFO_MISC_MODECHANGEUSER) {
info->flags &= ~FBINFO_MISC_MODECHANGEUSER; info->flags &= ~FBINFO_MISC_MODECHANGEUSER;
notifier_call_chain(&fb_notifier_list, notifier_call_chain(&fb_notifier_list,
...@@ -1442,6 +1446,16 @@ register_framebuffer(struct fb_info *fb_info) ...@@ -1442,6 +1446,16 @@ register_framebuffer(struct fb_info *fb_info)
} }
fb_info->sprite.offset = 0; fb_info->sprite.offset = 0;
if (!fb_info->monspecs.modelist.prev ||
!fb_info->monspecs.modelist.next ||
list_empty(&fb_info->monspecs.modelist)) {
struct fb_videomode mode;
INIT_LIST_HEAD(&fb_info->monspecs.modelist);
fb_var_to_videomode(&mode, &fb_info->var);
fb_add_videomode(&mode, &fb_info->monspecs.modelist);
}
registered_fb[i] = fb_info; registered_fb[i] = fb_info;
devfs_mk_cdev(MKDEV(FB_MAJOR, i), devfs_mk_cdev(MKDEV(FB_MAJOR, i),
...@@ -1474,6 +1488,7 @@ unregister_framebuffer(struct fb_info *fb_info) ...@@ -1474,6 +1488,7 @@ unregister_framebuffer(struct fb_info *fb_info)
kfree(fb_info->pixmap.addr); kfree(fb_info->pixmap.addr);
if (fb_info->sprite.addr && (fb_info->sprite.flags & FB_PIXMAP_DEFAULT)) if (fb_info->sprite.addr && (fb_info->sprite.flags & FB_PIXMAP_DEFAULT))
kfree(fb_info->sprite.addr); kfree(fb_info->sprite.addr);
fb_destroy_modelist(&fb_info->monspecs.modelist);
registered_fb[i]=NULL; registered_fb[i]=NULL;
num_registered_fb--; num_registered_fb--;
class_simple_device_remove(MKDEV(FB_MAJOR, i)); class_simple_device_remove(MKDEV(FB_MAJOR, i));
......
...@@ -282,6 +282,7 @@ struct fb_chroma { ...@@ -282,6 +282,7 @@ struct fb_chroma {
struct fb_monspecs { struct fb_monspecs {
struct fb_chroma chroma; struct fb_chroma chroma;
struct fb_videomode *modedb; /* mode database */ struct fb_videomode *modedb; /* mode database */
struct list_head modelist; /* mode list */
__u8 manufacturer[4]; /* Manufacturer */ __u8 manufacturer[4]; /* Manufacturer */
__u8 monitor[14]; /* Monitor String */ __u8 monitor[14]; /* Monitor String */
__u8 serial_no[14]; /* Serial Number */ __u8 serial_no[14]; /* Serial Number */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment