From: James Simmons <jsimmons@infradead.org>

This fixes the bugs that where in mode switch via stty.

The problem was we couldn't set the mode just by using the x and y
resolution.  We use modedb to fill in the rest.  There also was a bug that
allowed you to change the console resolution for drivers with fixed
resolutions.  This would mess up your display.  Now that is fixed.


---

 25-akpm/drivers/char/vt.c               |   12 -
 25-akpm/drivers/video/aty/atyfb_base.c  |    5 
 25-akpm/drivers/video/aty/radeon_base.c |    1 
 25-akpm/drivers/video/console/fbcon.c   |  284 +++++++++++++-------------------
 25-akpm/drivers/video/console/fbcon.h   |    1 
 25-akpm/drivers/video/modedb.c          |   15 -
 25-akpm/drivers/video/radeonfb.c        |    1 
 25-akpm/include/linux/fb.h              |    1 
 8 files changed, 135 insertions(+), 185 deletions(-)

diff -puN drivers/char/vt.c~fbdev-mode-switching-fix drivers/char/vt.c
--- 25/drivers/char/vt.c~fbdev-mode-switching-fix	Wed May 19 15:02:08 2004
+++ 25-akpm/drivers/char/vt.c	Wed May 19 15:02:09 2004
@@ -776,17 +776,17 @@ int vc_resize(int currcons, unsigned int
 	old_row_size = video_size_row;
 	old_screen_size = screenbuf_size;
 
-	video_num_lines = new_rows;
-	video_num_columns = new_cols;
-	video_size_row = new_row_size;
-	screenbuf_size = new_screen_size;
-
 	err = resize_screen(currcons, new_cols, new_rows);
 	if (err) {
 		kfree(newscreen);
 		return err;
 	}
 
+	video_num_lines = new_rows;
+	video_num_columns = new_cols;
+	video_size_row = new_row_size;
+	screenbuf_size = new_screen_size;
+
 	rlth = min(old_row_size, new_row_size);
 	rrem = new_row_size - rlth;
 	old_origin = origin;
@@ -811,8 +811,6 @@ int vc_resize(int currcons, unsigned int
 	screenbuf = newscreen;
 	kmalloced = 1;
 	screenbuf_size = new_screen_size;
-	if (IS_VISIBLE)
-		err = resize_screen(currcons, new_cols, new_rows);
 	set_origin(currcons);
 
 	/* do part of a reset_terminal() */
diff -puN drivers/video/aty/atyfb_base.c~fbdev-mode-switching-fix drivers/video/aty/atyfb_base.c
--- 25/drivers/video/aty/atyfb_base.c~fbdev-mode-switching-fix	Wed May 19 15:02:08 2004
+++ 25-akpm/drivers/video/aty/atyfb_base.c	Wed May 19 15:02:09 2004
@@ -1231,10 +1231,7 @@ static void atyfb_palette(int enter)
 
 	for (i = 0; i < FB_MAX; i++) {
 		info = registered_fb[i];
-		if (info &&
-		    info->fbops == &atyfb_ops &&
-		    info->display_fg &&
-		    info->display_fg->vc_num == i) {
+		if (info && info->fbops == &atyfb_ops) {
 			par = (struct atyfb_par *) info->par;
 			
 			atyfb_save_palette(par, enter);
diff -puN drivers/video/aty/radeon_base.c~fbdev-mode-switching-fix drivers/video/aty/radeon_base.c
--- 25/drivers/video/aty/radeon_base.c~fbdev-mode-switching-fix	Wed May 19 15:02:08 2004
+++ 25-akpm/drivers/video/aty/radeon_base.c	Wed May 19 15:02:09 2004
@@ -1783,7 +1783,6 @@ static int __devinit radeon_set_fbinfo (
 	info->pseudo_palette = rinfo->pseudo_palette;
         info->flags = FBINFO_FLAG_DEFAULT;
         info->fbops = &radeonfb_ops;
-        info->display_fg = NULL;
         info->screen_base = (char *)rinfo->fb_base;
 
 	/* Fill fix common fields */
diff -puN drivers/video/console/fbcon.c~fbdev-mode-switching-fix drivers/video/console/fbcon.c
--- 25/drivers/video/console/fbcon.c~fbdev-mode-switching-fix	Wed May 19 15:02:08 2004
+++ 25-akpm/drivers/video/console/fbcon.c	Wed May 19 15:02:09 2004
@@ -115,6 +115,8 @@ static int softback_lines;
 static int first_fb_vc;
 static int last_fb_vc = MAX_NR_CONSOLES - 1;
 static int fbcon_is_default = 1; 
+/* font data */
+static char fontname[40];
 
 #define REFCOUNT(fd)	(((int *)(fd))[-1])
 #define FNTSIZE(fd)	(((int *)(fd))[-2])
@@ -168,9 +170,7 @@ static int fbcon_scrolldelta(struct vc_d
 /*
  *  Internal routines
  */
-static void fbcon_set_display(struct vc_data *vc, int init, int logo);
 static __inline__ int real_y(struct display *p, int ypos);
-static __inline__ void updatescrollmode(struct display *p, struct vc_data *vc);
 static __inline__ void ywrap_up(struct vc_data *vc, int count);
 static __inline__ void ywrap_down(struct vc_data *vc, int count);
 static __inline__ void ypan_up(struct vc_data *vc, int count);
@@ -233,18 +233,15 @@ static void cursor_timer_handler(unsigne
 
 int __init fb_console_setup(char *this_opt)
 {
-	int unit, i, j;
 	char *options;
+	int i, j;
 
 	if (!this_opt || !*this_opt)
 		return 0;
 
 	while ((options = strsep(&this_opt, ",")) != NULL) {
-		if (!strncmp(options, "font:", 5)) {
-			for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
-				strcpy(fb_display[unit].fontname,
-				       options + 5);
-		}
+		if (!strncmp(options, "font:", 5))
+			strcpy(fontname, options + 5);
 		
 		if (!strncmp(options, "scrollback:", 11)) {
 			options += 11;
@@ -442,11 +439,13 @@ void accel_clear_margins(struct vc_data 
 static const char *fbcon_startup(void)
 {
 	const char *display_desc = "frame buffer device";
+	struct display *p = &fb_display[fg_console];
+	struct vc_data *vc = vc_cons[fg_console].d;
 	struct font_desc *font = NULL;
 	struct module *owner;
 	struct fb_info *info;
-	struct vc_data *vc;
 	static int done = 0;
+	int cols, rows;
 	int irqres;
 
 	irqres = 1;
@@ -493,37 +492,35 @@ static const char *fbcon_startup(void)
 		softback_lines = 0;
 	}
 
-	font = get_default_font(info->var.xres, info->var.yres);	
-
-	vc = (struct vc_data *) kmalloc(sizeof(struct vc_data), GFP_ATOMIC); 
-
-	if (!vc) {
-		if (softback_buf)
-			kfree((void *) softback_buf);
-		return NULL;
-	}
-
 	/* Setup default font */
-	vc->vc_font.data = font->data;
-	vc->vc_font.width = font->width;
-	vc->vc_font.height = font->height;
-	vc->vc_font.charcount = 256; /* FIXME  Need to support more fonts */
-
-	vc->vc_cols = info->var.xres/vc->vc_font.width;
-	vc->vc_rows = info->var.yres/vc->vc_font.height;
+	if (!p->fontdata) {
+		if (!fontname[0] || !(font = find_font(fontname)))
+			font = get_default_font(info->var.xres,
+						   info->var.yres);
+		vc->vc_font.width = font->width;
+		vc->vc_font.height = font->height;
+		vc->vc_font.data = p->fontdata = font->data;
+		vc->vc_font.charcount = 256; /* FIXME  Need to support more fonts */
+	}
 
-	/* We trust the mode the driver supplies. */
+	/*
+	 * We must always set the mode. The mode of the previous console
+	 * driver could be in the same resolution but we are using different
+	 * hardware so we have to initialize the hardware.
+	 */
 	if (info->fbops->fb_set_par)
 		info->fbops->fb_set_par(info);
+	cols = info->var.xres/vc->vc_font.width;
+	rows = info->var.yres/vc->vc_font.height;
+	vc_resize(vc->vc_num, cols, rows);
 
 	DPRINTK("mode:   %s\n", info->fix.id);
 	DPRINTK("visual: %d\n", info->fix.visual);
 	DPRINTK("res:    %dx%d-%d\n", info->var.xres,
 		info->var.yres,
 		info->var.bits_per_pixel);
+	con_set_default_unimap(vc->vc_num);
 
-	info->display_fg = vc;
-	
 #ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
@@ -598,99 +595,60 @@ static const char *fbcon_startup(void)
 
 static void fbcon_init(struct vc_data *vc, int init)
 {
-	int unit = vc->vc_num;
-	struct fb_info *info;
-
-	/* on which frame buffer will we open this console? */
-	info = registered_fb[(int) con2fb_map[unit]];
-	
-	if (info->var.accel_flags)
-		fb_display[unit].scrollmode = SCROLL_YNOMOVE;
-	else
-		fb_display[unit].scrollmode = SCROLL_YREDRAW;
-	con_set_default_unimap(unit);
-	fbcon_set_display(vc, init, !init);
-}
-
-static void fbcon_deinit(struct vc_data *vc)
-{
-	struct display *p = &fb_display[vc->vc_num];
-
-	fbcon_free_font(p);
-}
-
-static __inline__ void updatescrollmode(struct display *p, struct vc_data *vc)
-{
-	struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
-
-	int m;
-	if (p->scrollmode & __SCROLL_YFIXED)
-		return;
-	if (divides(info->fix.ywrapstep, vc->vc_font.height) &&
-	    divides(vc->vc_font.height, info->var.yres_virtual))
-		m = __SCROLL_YWRAP;
-	else if (divides(info->fix.ypanstep, vc->vc_font.height) &&
-		 info->var.yres_virtual >= info->var.yres + vc->vc_font.height)
-		m = __SCROLL_YPAN;
-	else if (p->scrollmode & __SCROLL_YNOMOVE)
-		m = __SCROLL_YREDRAW;
-	else
-		m = __SCROLL_YMOVE;
-	p->scrollmode = (p->scrollmode & ~__SCROLL_YMASK) | m;
-}
-
-static void fbcon_set_display(struct vc_data *vc, int init, int logo)
-{
 	struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
-	int nr_rows, nr_cols, old_rows, old_cols, i, charcnt = 256;
-	struct display *p = &fb_display[vc->vc_num];
+	struct vc_data **default_mode = vc->vc_display_fg;
+	struct display *t, *p = &fb_display[vc->vc_num];
+	int display_fg = (*default_mode)->vc_num;
+	int logo = 1, rows, cols, charcnt = 256;
 	unsigned short *save = NULL, *r, *q;
-	struct font_desc *font;
 
-	if (vc->vc_num != fg_console || (info->flags & FBINFO_FLAG_MODULE) ||
+	if (vc->vc_num != display_fg || (info->flags & FBINFO_FLAG_MODULE) ||
 	    (info->fix.type == FB_TYPE_TEXT))
 		logo = 0;
 
 	info->var.xoffset = info->var.yoffset = p->yscroll = 0;	/* reset wrap/pan */
 
-	for (i = 0; i < MAX_NR_CONSOLES; i++)
-		if (vc && i != vc->vc_num && fb_display[i].fontdata) 
-			break;
-
-	fbcon_free_font(p);
-	if (i < MAX_NR_CONSOLES) {
-		struct display *q = &fb_display[i];
-		struct vc_data *tmp = vc_cons[i].d;
-		
-		/* If we are not the first console on this
-		   fb, copy the font from that console */
-		vc->vc_font.width = tmp->vc_font.width;
-		vc->vc_font.height = tmp->vc_font.height;
-		vc->vc_font.data = p->fontdata = q->fontdata;
-		p->userfont = q->userfont;
-		if (p->userfont) {
-			REFCOUNT(p->fontdata)++;
-			charcnt = FNTCHARCNT(p->fontdata);
-		}
-		con_copy_unimap(vc->vc_num, i);
+	/* If we are not the first console on this
+	   fb, copy the font from that console */
+	t = &fb_display[display_fg];
+	vc->vc_font.width = (*default_mode)->vc_font.width;
+	vc->vc_font.height = (*default_mode)->vc_font.height;
+	vc->vc_font.data = p->fontdata = t->fontdata;
+	p->userfont = t->userfont;
+	if (p->userfont) {
+		REFCOUNT(p->fontdata)++;
+		charcnt = FNTCHARCNT(p->fontdata);
 	}
+	con_copy_unimap(vc->vc_num, display_fg);
 
-	if (!p->fontdata) {
-		if (!p->fontname[0] || !(font = find_font(p->fontname)))
-			font = get_default_font(info->var.xres,
-						   info->var.yres);
-		vc->vc_font.width = font->width;
-		vc->vc_font.height = font->height;
-		vc->vc_font.data = p->fontdata = font->data;
+	vc->vc_can_do_color = info->var.bits_per_pixel != 1;
+	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+	if (charcnt == 256) {
+		vc->vc_hi_font_mask = 0;
+	} else {
+		vc->vc_hi_font_mask = 0x100;
+		if (vc->vc_can_do_color)
+			vc->vc_complement_mask <<= 1;
 	}
 
-	updatescrollmode(p, vc);
+	cols = info->var.xres / vc->vc_font.width;
+	rows = info->var.yres / vc->vc_font.height;
+	vc_resize(vc->vc_num, cols, rows);
 
-	old_cols = vc->vc_cols;
-	old_rows = vc->vc_rows;
+	if (info->var.accel_flags)
+		p->scrollmode = SCROLL_YNOMOVE;
+	else
+		p->scrollmode = SCROLL_YREDRAW;
 
-	nr_cols = info->var.xres / vc->vc_font.width;
-	nr_rows = info->var.yres / vc->vc_font.height;
+	/*
+	 *  ++guenther: console.c:vc_allocate() relies on initializing
+	 *  vc_{cols,rows}, but we must not set those if we are only
+	 *  resizing the console.
+	 */
+	if (init) {
+		vc->vc_cols = cols;
+		vc->vc_rows = rows;
+	}
 
 	if (logo) {
 		/* Need to make room for the logo */
@@ -701,34 +659,28 @@ static void fbcon_set_display(struct vc_
 		logo_lines = (logo_height + vc->vc_font.height - 1) /
 			     vc->vc_font.height;
 		q = (unsigned short *) (vc->vc_origin +
-					vc->vc_size_row * old_rows);
-		step = logo_lines * old_cols;
-		for (r = q - logo_lines * old_cols; r < q; r++)
+					vc->vc_size_row * rows);
+		step = logo_lines * cols;
+		for (r = q - logo_lines * cols; r < q; r++)
 			if (scr_readw(r) != vc->vc_video_erase_char)
 				break;
-		if (r != q && nr_rows >= old_rows + logo_lines) {
-			save =
-			    kmalloc(logo_lines * nr_cols * 2, GFP_KERNEL);
+		if (r != q && rows >= rows + logo_lines) {
+			save = kmalloc(logo_lines * cols * 2, GFP_KERNEL);
 			if (save) {
-				int i =
-				    old_cols <
-				    nr_cols ? old_cols : nr_cols;
 				scr_memsetw(save, vc->vc_video_erase_char,
-					    logo_lines * nr_cols * 2);
+					    logo_lines * cols * 2);
 				r = q - step;
-				for (cnt = 0; cnt < logo_lines;
-				     cnt++, r += i)
-					scr_memcpyw(save + cnt * nr_cols,
-						    r, 2 * i);
+				for (cnt = 0; cnt < logo_lines; cnt++, r += cols)
+					scr_memcpyw(save + cnt * cols, r, 2 * cols);
 				r = q;
 			}
 		}
 		if (r == q) {
 			/* We can scroll screen down */
-			r = q - step - old_cols;
-			for (cnt = old_rows - logo_lines; cnt > 0; cnt--) {
+			r = q - step - cols;
+			for (cnt = rows - logo_lines; cnt > 0; cnt--) {
 				scr_memcpyw(r + step, r, vc->vc_size_row);
-				r -= old_cols;
+				r -= cols;
 			}
 			if (!save) {
 				vc->vc_y += logo_lines;
@@ -738,40 +690,16 @@ static void fbcon_set_display(struct vc_
 		scr_memsetw((unsigned short *) vc->vc_origin,
 			    vc->vc_video_erase_char,
 			    vc->vc_size_row * logo_lines);
-	}
 
-	/*
-	 *  ++guenther: console.c:vc_allocate() relies on initializing
-	 *  vc_{cols,rows}, but we must not set those if we are only
-	 *  resizing the console.
-	 */
-	if (init) {
-		vc->vc_cols = nr_cols;
-		vc->vc_rows = nr_rows;
-	}
-	vc->vc_can_do_color = info->var.bits_per_pixel != 1;
-	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
-	if (charcnt == 256) {
-		vc->vc_hi_font_mask = 0;
-	} else {
-		vc->vc_hi_font_mask = 0x100;
-		if (vc->vc_can_do_color)
-			vc->vc_complement_mask <<= 1;
-	}
-
-	if (logo) {
-		if (vc->vc_cols != nr_cols || vc->vc_rows != nr_rows)
-			vc_resize(vc->vc_num, nr_cols, nr_rows);
-		else if (CON_IS_VISIBLE(vc) &&
-			 vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
+		if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
 			accel_clear_margins(vc, info, 0);
 			update_screen(vc->vc_num);
 		}
 		if (save) {
 			q = (unsigned short *) (vc->vc_origin +
 						vc->vc_size_row *
-						old_rows);
-			scr_memcpyw(q, save, logo_lines * nr_cols * 2);
+						rows);
+			scr_memcpyw(q, save, logo_lines * cols * 2);
 			vc->vc_y += logo_lines;
 			vc->vc_pos += logo_lines * vc->vc_size_row;
 			kfree(save);
@@ -786,7 +714,7 @@ static void fbcon_set_display(struct vc_
 		}
 	}
 
-	if (vc->vc_num == fg_console && softback_buf) {
+	if (vc->vc_num == display_fg && softback_buf) {
 		int l = fbcon_softback_size / vc->vc_size_row;
 		if (l > 5)
 			softback_end = softback_buf + l * vc->vc_size_row;
@@ -798,6 +726,12 @@ static void fbcon_set_display(struct vc_
 	}
 }
 
+static void fbcon_deinit(struct vc_data *vc)
+{
+	struct display *p = &fb_display[vc->vc_num];
+
+	fbcon_free_font(p);
+}
 
 /* ====================================================================== */
 
@@ -1531,6 +1465,25 @@ static void fbcon_bmove_rec(struct vc_da
 			height, width);
 }
 
+static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, struct vc_data *vc)
+{
+	int m;
+
+	if (p->scrollmode & __SCROLL_YFIXED)
+		return;
+	if (divides(info->fix.ywrapstep, vc->vc_font.height) &&
+	    divides(vc->vc_font.height, info->var.yres_virtual))
+		m = __SCROLL_YWRAP;
+	else if (divides(info->fix.ypanstep, vc->vc_font.height) &&
+		 info->var.yres_virtual >= info->var.yres + vc->vc_font.height)
+		m = __SCROLL_YPAN;
+	else if (p->scrollmode & __SCROLL_YNOMOVE)
+		m = __SCROLL_YREDRAW;
+	else
+		m = __SCROLL_YMOVE;
+	p->scrollmode = (p->scrollmode & ~__SCROLL_YMASK) | m;
+}
+
 static int fbcon_resize(struct vc_data *vc, unsigned int width, 
 			unsigned int height)
 {
@@ -1545,22 +1498,30 @@ static int fbcon_resize(struct vc_data *
 	var.yres = height * fh;
 	x_diff = info->var.xres - var.xres;
 	y_diff = info->var.yres - var.yres;
-	if (x_diff < 0 || x_diff > fw ||
-	   (y_diff < 0 || y_diff > fh)) {
-		var.activate = FB_ACTIVATE_TEST;
-		err = fb_set_var(info, &var);
-		if (err || width > var.xres/fw ||
-		    height > var.yres/fh)
+	if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) {
+		char mode[40];
+
+		DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
+		if (!info->fbops->fb_set_par)
+			return -EINVAL;
+
+		sprintf(mode, "%dx%d", var.xres, var.yres);
+		err = fb_find_mode(&var, info, mode, NULL, 0, NULL,
+					info->var.bits_per_pixel);
+		if (!err || width > var.xres/fw || height > var.yres/fh)
 			return -EINVAL;
 		DPRINTK("resize now %ix%i\n", var.xres, var.yres);
-		var.activate = FB_ACTIVATE_NOW;
-		fb_set_var(info, &var);
+		if (CON_IS_VISIBLE(vc)) {
+			var.activate = FB_ACTIVATE_NOW;
+			fb_set_var(info, &var);
+		}
 	}
 	p->vrows = var.yres_virtual/fh;
 	if (var.yres > (fh * (height + 1)))
 		p->vrows -= (var.yres - (fh * height)) / fh;
 	if ((var.yres % fh) && (var.yres_virtual % fh < var.yres % fh))
 		p->vrows--;
+	updatescrollmode(p, info, vc);
 	return 0;
 }
 
@@ -1830,7 +1791,6 @@ static int fbcon_do_set_font(struct vc_d
 	if (resize) {
 		/* reset wrap/pan */
 		info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-		updatescrollmode(p, vc);
 		vc_resize(vc->vc_num, info->var.xres / w, info->var.yres / h);
 		if (CON_IS_VISIBLE(vc) && softback_buf) {
 			int l = fbcon_softback_size / vc->vc_size_row;
diff -puN drivers/video/console/fbcon.h~fbdev-mode-switching-fix drivers/video/console/fbcon.h
--- 25/drivers/video/console/fbcon.h~fbdev-mode-switching-fix	Wed May 19 15:02:09 2004
+++ 25-akpm/drivers/video/console/fbcon.h	Wed May 19 15:02:09 2004
@@ -27,7 +27,6 @@ struct display {
     /* Filled in by the frame buffer device */
     u_short inverse;                /* != 0 text black on white as default */
     /* Filled in by the low-level console driver */
-    char fontname[40];              /* Font associated to this display */	
     u_char *fontdata;
     int userfont;                   /* != 0 if fontdata kmalloc()ed */
     u_short scrollmode;             /* Scroll Method */
diff -puN drivers/video/modedb.c~fbdev-mode-switching-fix drivers/video/modedb.c
--- 25/drivers/video/modedb.c~fbdev-mode-switching-fix	Wed May 19 15:02:09 2004
+++ 25-akpm/drivers/video/modedb.c	Wed May 19 15:02:09 2004
@@ -391,7 +391,7 @@ static int my_atoi(const char *name)
 }
 
 /**
- *	__fb_try_mode - test a video mode
+ *	fb_try_mode - test a video mode
  *	@var: frame buffer user defined part of display
  *	@info: frame buffer info structure
  *	@mode: frame buffer video mode structure
@@ -403,10 +403,10 @@ static int my_atoi(const char *name)
  *
  */
 
-int __fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
 		  const struct fb_videomode *mode, unsigned int bpp)
 {
-    int err = 1;
+    int err = 0;
 
     DPRINTK("Trying mode %s %dx%d-%d@%d\n", mode->name ? mode->name : "noname",
 	    mode->xres, mode->yres, bpp, mode->refresh);
@@ -430,10 +430,9 @@ int __fb_try_mode(struct fb_var_screenin
     if (info->fbops->fb_check_var)
     	err = info->fbops->fb_check_var(var, info);
     var->activate &= ~FB_ACTIVATE_TEST;
-    return !err;
+    return err;
 }
 
-
 /**
  *	fb_find_mode - finds a valid video mode
  *	@var: frame buffer user defined part of display
@@ -536,18 +535,18 @@ done:
 		if ((name_matches(db[j], name, namelen) ||
 		     (res_specified && res_matches(db[j], xres, yres))) &&
 		    (!i || db[j].refresh == refresh) &&
-		    __fb_try_mode(var, info, &db[j], bpp))
+		    !fb_try_mode(var, info, &db[j], bpp))
 		    return 2-i;
 	}
     }
 
     DPRINTK("Trying default video mode\n");
-    if (__fb_try_mode(var, info, default_mode, default_bpp))
+    if (!fb_try_mode(var, info, default_mode, default_bpp))
 	return 3;
 
     DPRINTK("Trying all modes\n");
     for (i = 0; i < dbsize; i++)
-	if (__fb_try_mode(var, info, &db[i], default_bpp))
+	if (!fb_try_mode(var, info, &db[i], default_bpp))
 	    return 4;
 
     DPRINTK("No valid mode found\n");
diff -puN drivers/video/radeonfb.c~fbdev-mode-switching-fix drivers/video/radeonfb.c
--- 25/drivers/video/radeonfb.c~fbdev-mode-switching-fix	Wed May 19 15:02:09 2004
+++ 25-akpm/drivers/video/radeonfb.c	Wed May 19 15:02:09 2004
@@ -2252,7 +2252,6 @@ static int __devinit radeon_set_fbinfo (
 	info->pseudo_palette = rinfo->pseudo_palette;
         info->flags = FBINFO_FLAG_DEFAULT;
         info->fbops = &radeonfb_ops;
-        info->display_fg = NULL;
         info->screen_base = (char *)rinfo->fb_base;
 
 	/* Fill fix common fields */
diff -puN include/linux/fb.h~fbdev-mode-switching-fix include/linux/fb.h
--- 25/include/linux/fb.h~fbdev-mode-switching-fix	Wed May 19 15:02:09 2004
+++ 25-akpm/include/linux/fb.h	Wed May 19 15:02:09 2004
@@ -516,7 +516,6 @@ struct fb_info {
 	struct fb_cmap cmap;		/* Current cmap */
 	struct fb_ops *fbops;
 	char *screen_base;		/* Virtual address */
-	struct vc_data *display_fg;	/* Console visible on this display */
 	int currcon;			/* Current VC. */
 	void *pseudo_palette;		/* Fake palette of 16 colors */ 
 #define FBINFO_STATE_RUNNING	0

_