patch-2.1.124 linux/drivers/video/fbcon.c

Next file: linux/drivers/video/fbcon.h
Previous file: linux/drivers/video/fbcon-vga.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.123/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
@@ -29,6 +29,8 @@
  *  added by 
  *                         Jakub Jelinek (jj@ultra.linux.cz)
  *
+ *  Random hacking by Martin Mares <mj@ucw.cz>
+ *
  *
  *  The low level operations for the various display memory organizations are
  *  now in separate source files.
@@ -54,8 +56,6 @@
 
 #undef FBCONDEBUG
 
-#define FLASHING_CURSOR		1
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -94,9 +94,9 @@
 #define INCLUDE_LINUX_LOGO_DATA
 #include <asm/linux_logo.h>
 
-#include "fbcon.h"
-#include "fbcon-mac.h"	/* for 6x11 font on mac */
-#include "font.h"
+#include <video/fbcon.h>
+#include <video/fbcon-mac.h>	/* for 6x11 font on mac */
+#include <video/font.h>
 
 #ifdef FBCONDEBUG
 #  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
@@ -112,6 +112,14 @@
 static int logo_lines;
 static int logo_shown = -1;
 
+#define REFCOUNT(fd)	(((int *)(fd))[-1])
+#define FNTSIZE(fd)	(((int *)(fd))[-2])
+#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
+#define FNTSUM(fd)	(((int *)(fd))[-4])
+#define FONT_EXTRA_WORDS 4
+
+static void fbcon_free_font(struct display *p);
+
 /*
  * Emmanuel: fbcon will now use a hardware cursor if the
  * low-level driver provides a non-NULL dispsw->cursor pointer,
@@ -120,12 +128,12 @@
  * if dispsw->cursor is NULL, use Atari alike software cursor
  */
 
-#if FLASHING_CURSOR
 static int cursor_drawn = 0;
 
-#define CURSOR_DRAW_DELAY		(2)
+#define CURSOR_DRAW_DELAY		(1)
 
 /* # VBL ints between cursor state changes */
+#define ARM_CURSOR_BLINK_RATE		(10)
 #define AMIGA_CURSOR_BLINK_RATE		(20)
 #define ATARI_CURSOR_BLINK_RATE		(42)
 #define MAC_CURSOR_BLINK_RATE		(32)
@@ -135,16 +143,12 @@
 static int cursor_on = 0;
 static int cursor_blink_rate;
 
-static __inline__ void CURSOR_UNDRAWN(void)
+static inline void cursor_undrawn(void)
 {
     vbl_cursor_cnt = 0;
     cursor_drawn = 0;
 }
-#endif
 
-/*
- *  Scroll Method
- */
 
 #define divides(a, b)	((!(a) || (b)%(a)) ? 0 : 1)
 
@@ -180,9 +184,7 @@
 
 static void fbcon_setup(int con, int init, int logo);
 static __inline__ int real_y(struct display *p, int ypos);
-#if FLASHING_CURSOR
 static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
-#endif
 static __inline__ void updatescrollmode(struct display *p);
 static __inline__ void ywrap_up(int unit, struct vc_data *conp,
 				struct display *p, int count);
@@ -197,8 +199,6 @@
 
 static int fbcon_show_logo(void);
 
-#if FLASHING_CURSOR
-
 #ifdef CONFIG_MAC
 /*
  * On the Macintoy, there may or may not be a working VBL int. We need to prob
@@ -225,13 +225,12 @@
       cursor_timer.next = cursor_timer.next = NULL;
       add_timer(&cursor_timer);
 }
-#endif
 
 /*
  *  Low Level Operations
  */
 
-static struct display_switch fbcon_dummy;
+struct display_switch fbcon_dummy;
 
 /* NOTE: fbcon cannot be __initfunc: it may be called from take_over_console later */
 
@@ -271,39 +270,43 @@
      * probe for VBL interrupts.
      */
     if (MACH_IS_MAC) {
-       int ct = 0;
-       /*
-        * Probe for VBL: set temp. handler ...
-        */
-       irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_detect, 0,
-                            "console/cursor", fbcon_vbl_detect);
-       /*
-        * ... and spin for 20 ms ...
-        */
-       while (!vbl_detected && ++ct<1000)
-          udelay(20);
+	int ct = 0;
+	/*
+	 * Probe for VBL: set temp. handler ...
+	 */
+	irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_detect, 0,
+			     "console/cursor", fbcon_vbl_detect);
+	vbl_detected = 0;
+
+	/*
+	 * ... and spin for 20 ms ...
+	 */
+	while (!vbl_detected && ++ct<1000)
+	    udelay(20);
  
-       if(ct==1000)
-          printk("fbcon_startup: No VBL detected, using timer based cursor.\n");
+	if(ct==1000)
+	    printk("fbcon_startup: No VBL detected, using timer based cursor.\n");
  
-       if (vbl_detected) {
-         /*
-          * interrupt based cursor ok
-          */
-          cursor_blink_rate = MAC_CURSOR_BLINK_RATE;
-          irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_handler, 0,
-                               "console/cursor", fbcon_vbl_handler);
-       } else {
-          /*
-           * VBL not detected: fall through, use timer based cursor
-           */
-           irqres = 1;
-	   /* free interrupt here ?? */
-       }
+	free_irq(IRQ_MAC_VBL, fbcon_vbl_detect);
+
+	if (vbl_detected) {
+	    /*
+	     * interrupt based cursor ok
+	     */
+	    cursor_blink_rate = MAC_CURSOR_BLINK_RATE;
+	    irqres = request_irq(IRQ_MAC_VBL, fbcon_vbl_handler, 0,
+				 "console/cursor", fbcon_vbl_handler);
+	} else {
+	    /*
+	     * VBL not detected: fall through, use timer based cursor
+	     */
+	    irqres = 1;
+	}
     }
 #endif /* CONFIG_MAC */
 
 #if defined(__arm__) && defined(IRQ_VSYNCPULSE)
+    cursor_blink_rate = ARM_CURSOR_BLINK_RATE;
     irqres = request_irq(IRQ_VSYNCPULSE, fbcon_vbl_handler, SA_SHIRQ,
 			 "console/cursor", fbcon_vbl_handler);
 #endif
@@ -329,9 +332,6 @@
     info = registered_fb[(int)con2fb_map[unit]];
 
     info->changevar = &fbcon_changevar;
-    conp->vc_display_fg = &info->display_fg;
-    if (!info->display_fg)
-        info->display_fg = conp;
     fb_display[unit] = *(info->disp);	/* copy from default */
     DPRINTK("mode:   %s\n",info->modename);
     DPRINTK("visual: %d\n",fb_display[unit].visual);
@@ -340,7 +340,17 @@
 	                     fb_display[unit].var.bits_per_pixel);
     fb_display[unit].conp = conp;
     fb_display[unit].fb_info = info;
+    /* clear out the cmap so we don't have dangling pointers */
+    fb_display[unit].cmap.len = 0;
+    fb_display[unit].cmap.red = 0;
+    fb_display[unit].cmap.green = 0;
+    fb_display[unit].cmap.blue = 0;
+    fb_display[unit].cmap.transp = 0;
     fbcon_setup(unit, init, !init);
+    /* Must be done after fbcon_setup to prevent excess updates */
+    conp->vc_display_fg = &info->display_fg;
+    if (!info->display_fg)
+        info->display_fg = conp;
 }
 
 
@@ -349,7 +359,8 @@
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
 
-    p->dispsw = NULL;
+    fbcon_free_font(p);
+    p->dispsw = &fbcon_dummy;
     p->conp = 0;
 }
 
@@ -364,29 +375,34 @@
 
 static __inline__ void updatescrollmode(struct display *p)
 {
-    if (p->scrollmode == SCROLL_YREDRAW)
+    int m;
+    if (p->scrollmode & __SCROLL_YFIXED)
     	return;
-    if (divides(p->ywrapstep, p->fontheight) &&
-	divides(p->fontheight, p->var.yres_virtual))
-	p->scrollmode = SCROLL_YWRAP;
-    else if (divides(p->ypanstep, p->fontheight) &&
-	     p->var.yres_virtual >= p->var.yres+p->fontheight)
-	p->scrollmode = SCROLL_YPAN;
+    if (divides(p->ywrapstep, fontheight(p)) &&
+	divides(fontheight(p), p->var.yres_virtual))
+	m = __SCROLL_YWRAP;
+    else if (divides(p->ypanstep, fontheight(p)) &&
+	     p->var.yres_virtual >= p->var.yres+fontheight(p))
+	m = __SCROLL_YPAN;
+    else if (p->scrollmode & __SCROLL_YNOMOVE)
+    	m = __SCROLL_YREDRAW;
     else
-	p->scrollmode = SCROLL_YMOVE;
+	m = __SCROLL_YMOVE;
+    p->scrollmode = (p->scrollmode & ~__SCROLL_YMASK) | m;
 }
 
 static void fbcon_font_widths(struct display *p)
 {
     int i;
-    p->fontwidthlog = 0;
+    
+    p->_fontwidthlog = 0;
     for (i = 2; i <= 6; i++)
-    	if (p->fontwidth == (1 << i))
-	    p->fontwidthlog = i;
-    p->fontheightlog = 0;
+    	if (fontwidth(p) == (1 << i))
+	    p->_fontwidthlog = i;
+    p->_fontheightlog = 0;
     for (i = 2; i <= 6; i++)
-    	if (p->fontheight == (1 << i))
-	    p->fontheightlog = i;
+    	if (fontheight(p) == (1 << i))
+	    p->_fontheightlog = i;
 }
 
 #define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))
@@ -398,22 +414,52 @@
     int nr_rows, nr_cols;
     int old_rows, old_cols;
     unsigned short *save = NULL, *r, *q;
-    /* Only if not module */
-    int initmem_freed = 1;
+    int i, charcnt = 256;
     struct fbcon_font_desc *font;
-    if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT)
+    
+    if (con != fg_console || (p->fb_info->flags & FBINFO_FLAG_MODULE) ||
+        p->type == FB_TYPE_TEXT)
     	logo = 0;
 
     p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
+    
+    for (i = 0; i < MAX_NR_CONSOLES; i++)
+    	if (i != con && fb_display[i].fb_info == p->fb_info &&
+    	    fb_display[i].conp && fb_display[i].fontdata)
+    		break;
+
+    fbcon_free_font(p);    
+    if (i < MAX_NR_CONSOLES) {
+    	struct display *q = &fb_display[i];
+
+        if (fontwidthvalid(p,fontwidth(q))) {
+            /* If we are not the first console on this
+               fb, copy the font from that console */
+	    p->_fontwidth = q->_fontwidth;
+	    p->_fontheight = q->_fontheight;
+    	    p->_fontwidthlog = q->_fontwidthlog;
+    	    p->_fontheightlog = q->_fontheightlog;
+    	    p->fontdata = q->fontdata;
+    	    p->userfont = q->userfont; 
+    	    if (p->userfont) {
+    		REFCOUNT(p->fontdata)++;
+    		charcnt = FNTCHARCNT(p->fontdata);
+    	    }
+    	    con_copy_unimap(con, i);
+    	}
+    }
 
-    if (!p->fb_info->fontname[0] ||
-	!(font = fbcon_find_font(p->fb_info->fontname)))
-	    font = fbcon_get_default_font(p->var.xres, p->var.yres);
-    p->fontwidth = font->width;
-    p->fontheight = font->height;
-    p->fontdata = font->data;
-    fbcon_font_widths(p);
-    if (!fontwidthvalid(p,p->fontwidth)) {
+    if (!p->fontdata) {
+        if (!p->fb_info->fontname[0] ||
+	    !(font = fbcon_find_font(p->fb_info->fontname)))
+	        font = fbcon_get_default_font(p->var.xres, p->var.yres);
+        p->_fontwidth = font->width;
+        p->_fontheight = font->height;
+        p->fontdata = font->data;
+        fbcon_font_widths(p);
+    }
+    
+    if (!fontwidthvalid(p,fontwidth(p))) {
 #ifdef CONFIG_MAC
 	if (MACH_IS_MAC)
 	    /* ++Geert: hack to make 6x11 fonts work on mac */
@@ -422,26 +468,26 @@
 #endif
 	{
 	    /* ++Geert: changed from panic() to `correct and continue' */
-	    printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", p->fontwidth);
+	    printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", fontwidth(p));
 	    p->dispsw = &fbcon_dummy;
 	}
     }
     if (p->dispsw->set_font)
-    	p->dispsw->set_font(p, p->fontwidth, p->fontheight);
+    	p->dispsw->set_font(p, fontwidth(p), fontheight(p));
     updatescrollmode(p);
     
     old_cols = conp->vc_cols;
     old_rows = conp->vc_rows;
     
-    nr_cols = p->var.xres/p->fontwidth;
-    nr_rows = p->var.yres/p->fontheight;
+    nr_cols = p->var.xres/fontwidth(p);
+    nr_rows = p->var.yres/fontheight(p);
     
     if (logo) {
     	/* Need to make room for the logo */
 	int cnt;
 	int step;
     
-    	logo_lines = (LOGO_H + p->fontheight - 1) / p->fontheight;
+    	logo_lines = (LOGO_H + fontheight(p) - 1) / fontheight(p);
     	q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
     	step = logo_lines * old_cols;
     	for (r = q - logo_lines * old_cols; r < q; r++)
@@ -454,7 +500,7 @@
     	    	scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2);
     	    	r = q - step;
     	    	for (cnt = 0; cnt < logo_lines; cnt++, r += i)
-    	    		scr_memcpyw(save + cnt * nr_cols, r, 2 * i);
+    	    		scr_memcpyw_to(save + cnt * nr_cols, r, 2 * i);
     	    	r = q;
     	    }
     	}
@@ -483,42 +529,50 @@
 	conp->vc_cols = nr_cols;
 	conp->vc_rows = nr_rows;
     }
-    p->vrows = p->var.yres_virtual/p->fontheight;
+    p->vrows = p->var.yres_virtual/fontheight(p);
     conp->vc_can_do_color = p->var.bits_per_pixel != 1;
-    p->fgshift = 8;
-    p->bgshift = 12;
-    p->charmask = 0xff;
-    conp->vc_hi_font_mask = 0;
+    conp->vc_complement_mask = conp->vc_can_do_color ? 0x7700 : 0x0800;
+    if (charcnt == 256) {
+    	p->conp->vc_hi_font_mask = 0;
+    	p->fgshift = 8;
+    	p->bgshift = 12;
+    	p->charmask = 0xff;
+    } else {
+    	p->conp->vc_hi_font_mask = 0x100;
+    	p->conp->vc_complement_mask <<= 1;
+    	p->fgshift = 9;
+    	p->bgshift = 13;
+    	p->charmask = 0x1ff;
+    }
 
-    if (!p->dispsw) {
+    if (p->dispsw == &fbcon_dummy)
 	printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
 	       "supported\n", p->type, p->type_aux, p->var.bits_per_pixel);
-	p->dispsw = &fbcon_dummy;
-    }
     p->dispsw->setup(p);
 
     p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
     p->bgcol = 0;
 
     if (!init) {
-        if (con == fg_console)
-            set_palette(); /* Unlike vgacon, we have to set palette before resize on directcolor, 
-                              so that it is drawn with correct colors */
-	vc_resize_con(nr_rows, nr_cols, con);
+	if (conp->vc_cols != nr_cols || conp->vc_rows != nr_rows)
+	    vc_resize_con(nr_rows, nr_cols, con);
+	else if (CON_IS_VISIBLE(conp) &&
+		 vt_cons[conp->vc_num]->vc_mode == KD_TEXT) {
+	    if (p->dispsw->clear_margins)
+		p->dispsw->clear_margins(conp, p, 0);
+	    update_screen(con);
+	}
 	if (save) {
     	    q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
-	    scr_memcpyw(q, save, logo_lines * nr_cols * 2);
+	    scr_memcpyw_from(q, save, logo_lines * nr_cols * 2);
 	    conp->vc_y += logo_lines;
     	    conp->vc_pos += logo_lines * conp->vc_size_row;
     	    kfree(save);
 	}
-	if (con == fg_console)
-	    update_screen(con); /* So that we set origin correctly */
     }
 	
     if (logo) {
-    	logo_shown = fg_console;
-    	fbcon_show_logo(); /* This is protected above by initmem_freed */
+	logo_shown = -2;
     	conp->vc_top = logo_lines;
     }
 }
@@ -574,7 +628,7 @@
 
     if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
 	(sx <= p->cursor_x) && (p->cursor_x < sx+width)) {
-	CURSOR_UNDRAWN();
+	cursor_undrawn();
 	redraw_cursor = 1;
     }
 
@@ -601,9 +655,12 @@
 
     if (!p->can_soft_blank && console_blanked)
 	    return;
+	    
+    if (vt_cons[unit]->vc_mode != KD_TEXT)
+    	    return;
 
     if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
-	    CURSOR_UNDRAWN();
+	    cursor_undrawn();
 	    redraw_cursor = 1;
     }
 
@@ -624,9 +681,12 @@
     if (!p->can_soft_blank && console_blanked)
 	    return;
 
+    if (vt_cons[unit]->vc_mode != KD_TEXT)
+    	    return;
+
     if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
 	(p->cursor_x < (xpos + count))) {
-	    CURSOR_UNDRAWN();
+	    cursor_undrawn();
 	    redraw_cursor = 1;
     }
     p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos);
@@ -653,29 +713,28 @@
 	(mode == CM_ERASE) == !cursor_on)
 	return;
 
-	cursor_on = 0;
-	if (cursor_drawn)
-	    p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
-
-	p->cursor_x = conp->vc_x;
-	p->cursor_y = conp->vc_y;
-
-	switch (mode) {
-	    case CM_ERASE:
-	        cursor_drawn = 0;
-	        break;
-	    case CM_MOVE:
-	    case CM_DRAW:
-		if (cursor_drawn)
-		    p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
-		vbl_cursor_cnt = CURSOR_DRAW_DELAY;
-		cursor_on = 1;
-		break;
-	}
+    cursor_on = 0;
+    if (cursor_drawn)
+        p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
+
+    p->cursor_x = conp->vc_x;
+    p->cursor_y = conp->vc_y;
+
+    switch (mode) {
+        case CM_ERASE:
+            cursor_drawn = 0;
+            break;
+        case CM_MOVE:
+        case CM_DRAW:
+            if (cursor_drawn)
+	        p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
+            vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+            cursor_on = 1;
+            break;
+        }
 }
 
 
-#if FLASHING_CURSOR
 static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp)
 {
     struct display *p;
@@ -691,7 +750,6 @@
 	vbl_cursor_cnt = cursor_blink_rate;
     }
 }
-#endif
 
 static int scrollback_phys_max = 0;
 static int scrollback_max = 0;
@@ -704,7 +762,7 @@
     if (p->yscroll >= p->vrows)	/* Deal with wrap */
 	p->yscroll -= p->vrows;
     p->var.xoffset = 0;
-    p->var.yoffset = p->yscroll*p->fontheight;
+    p->var.yoffset = p->yscroll*fontheight(p);
     p->var.vmode |= FB_VMODE_YWRAP;
     p->fb_info->updatevar(unit, p->fb_info);
     scrollback_max += count;
@@ -721,7 +779,7 @@
     if (p->yscroll < 0)		/* Deal with wrap */
 	p->yscroll += p->vrows;
     p->var.xoffset = 0;
-    p->var.yoffset = p->yscroll*p->fontheight;
+    p->var.yoffset = p->yscroll*fontheight(p);
     p->var.vmode |= FB_VMODE_YWRAP;
     p->fb_info->updatevar(unit, p->fb_info);
     scrollback_max -= count;
@@ -741,9 +799,11 @@
 	p->yscroll -= p->vrows-conp->vc_rows;
     }
     p->var.xoffset = 0;
-    p->var.yoffset = p->yscroll*p->fontheight;
+    p->var.yoffset = p->yscroll*fontheight(p);
     p->var.vmode &= ~FB_VMODE_YWRAP;
     p->fb_info->updatevar(unit, p->fb_info);
+    if (p->dispsw->clear_margins)
+	p->dispsw->clear_margins(conp, p, 1);
     scrollback_max += count;
     if (scrollback_max > scrollback_phys_max)
 	scrollback_max = scrollback_phys_max;
@@ -761,9 +821,11 @@
 	p->yscroll += p->vrows-conp->vc_rows;
     }
     p->var.xoffset = 0;
-    p->var.yoffset = p->yscroll*p->fontheight;
+    p->var.yoffset = p->yscroll*fontheight(p);
     p->var.vmode &= ~FB_VMODE_YWRAP;
     p->fb_info->updatevar(unit, p->fb_info);
+    if (p->dispsw->clear_margins)
+	p->dispsw->clear_margins(conp, p, 1);
     scrollback_max -= count;
     if (scrollback_max < 0)
 	scrollback_max = 0;
@@ -777,6 +839,7 @@
     unsigned short *d = (unsigned short *)
 	(conp->vc_origin + conp->vc_size_row * line);
     unsigned short *s = d + offset;
+
     while (count--) {
 	unsigned short *start = s;
 	unsigned short *le = (unsigned short *)
@@ -790,14 +853,16 @@
 	    if (attr != (c & 0xff00)) {
 		attr = c & 0xff00;
 		if (s > start) {
-		    p->dispsw->putcs(conp, p, start, s - start, line, x);
+		    p->dispsw->putcs(conp, p, start, s - start,
+				     real_y(p, line), x);
 		    x += s - start;
 		    start = s;
 		}
 	    }
 	    if (c == scr_readw(d)) {
 	    	if (s > start) {
-	    	    p->dispsw->putcs(conp, p, start, s - start, line, x);
+	    	    p->dispsw->putcs(conp, p, start, s - start,
+				     real_y(p, line), x);
 		    x += s - start + 1;
 		    start = s + 1;
 	    	} else {
@@ -810,7 +875,7 @@
 	    d++;
 	} while (s < le);
 	if (s > start)
-	    p->dispsw->putcs(conp, p, start, s - start, line, x);
+	    p->dispsw->putcs(conp, p, start, s - start, real_y(p, line), x);
 	if (offset > 0)
 		line++;
 	else {
@@ -828,6 +893,7 @@
     if (sy != dy)
     	panic("fbcon_redraw_bmove width sy != dy");
     /* h will be always 1, but it does not matter if we are more generic */
+
     while (h-- > 0) {
 	struct vc_data *conp = p->conp;
 	unsigned short *d = (unsigned short *)
@@ -880,7 +946,7 @@
     if (!p->can_soft_blank && console_blanked)
 	return 0;
 
-    if (!count)
+    if (!count || vt_cons[unit]->vc_mode != KD_TEXT)
 	return 0;
 
     fbcon_cursor(conp, CM_ERASE);
@@ -895,133 +961,119 @@
 	case SM_UP:
 	    if (count > conp->vc_rows)	/* Maximum realistic size */
 		count = conp->vc_rows;
-	    if (vt_cons[unit]->vc_mode == KD_TEXT)
-		switch (p->scrollmode) {
-		    case SCROLL_YWRAP:
-			if (b-t-count > 3*conp->vc_rows>>2) {
-			    if (t > 0)
-				fbcon_bmove(conp, 0, 0, count, 0, t,
-					    conp->vc_cols);
-			    ywrap_up(unit, conp, p, count);
-			    if (conp->vc_rows-b > 0)
-				fbcon_bmove(conp, b-count, 0, b, 0,
-					    conp->vc_rows-b, conp->vc_cols);
-			} else
-			    fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
-					conp->vc_cols);
-			fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
-			break;
-
-		    case SCROLL_YPAN:
-			if (( is_txt && (b-t == conp->vc_rows)) ||
-			    (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) {
-			    if (t > 0)
-				fbcon_bmove(conp, 0, 0, count, 0, t,
-					    conp->vc_cols);
-			    ypan_up(unit, conp, p, count);
-			    if (conp->vc_rows-b > 0)
-				fbcon_bmove(conp, b-count, 0, b, 0,
-					    conp->vc_rows-b, conp->vc_cols);
-			} else
-			    fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
-					conp->vc_cols);
-			fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
-			break;
-
-		    case SCROLL_YMOVE:
-			p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count,
-					 conp->vc_cols);
-			p->dispsw->clear(conp, p, b-count, 0, count,
-					 conp->vc_cols);
-			break;
-		    case SCROLL_YREDRAW:
-		    	fbcon_redraw(conp, p, t, b-t-count, count*conp->vc_cols);
-		    	p->dispsw->clear(conp, p, b-count, 0, count,
-		    			 conp->vc_cols);
-		    	scr_memsetw((unsigned short *)(conp->vc_origin + 
-		    		    conp->vc_size_row * (b-count)), 
-		    		    conp->vc_video_erase_char,
-		    		    conp->vc_size_row * count);
-		    	return 1;
-		}
-	    else {
-		fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols);
+	    switch (p->scrollmode & __SCROLL_YMASK) {
+	    case __SCROLL_YMOVE:
+		p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count,
+				 conp->vc_cols);
+		p->dispsw->clear(conp, p, b-count, 0, count,
+				 conp->vc_cols);
+		break;
+
+	    case __SCROLL_YWRAP:
+		if (b-t-count > 3*conp->vc_rows>>2) {
+		    if (t > 0)
+			fbcon_bmove(conp, 0, 0, count, 0, t,
+				    conp->vc_cols);
+			ywrap_up(unit, conp, p, count);
+		    if (conp->vc_rows-b > 0)
+			fbcon_bmove(conp, b-count, 0, b, 0,
+				    conp->vc_rows-b, conp->vc_cols);
+		} else if (p->scrollmode & __SCROLL_YPANREDRAW)
+		    goto redraw_up;
+		else
+		    fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
+				conp->vc_cols);
+		fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
+		break;
+
+	    case __SCROLL_YPAN:
+		if (( is_txt && (b-t == conp->vc_rows)) ||
+		    (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) {
+		    if (t > 0)
+			fbcon_bmove(conp, 0, 0, count, 0, t,
+				    conp->vc_cols);
+		    ypan_up(unit, conp, p, count);
+		    if (conp->vc_rows-b > 0)
+			fbcon_bmove(conp, b-count, 0, b, 0,
+				    conp->vc_rows-b, conp->vc_cols);
+		} else if (p->scrollmode & __SCROLL_YPANREDRAW)
+		    goto redraw_up;
+		else
+		    fbcon_bmove(conp, t+count, 0, t, 0, b-t-count,
+				conp->vc_cols);
 		fbcon_clear(conp, b-count, 0, count, conp->vc_cols);
+		break;
+
+	    case __SCROLL_YREDRAW:
+	    redraw_up:
+		fbcon_redraw(conp, p, t, b-t-count, count*conp->vc_cols);
+		p->dispsw->clear(conp, p, real_y(p, b-count), 0,
+				 count, conp->vc_cols);
+		scr_memsetw((unsigned short *)(conp->vc_origin + 
+		    	    conp->vc_size_row * (b-count)), 
+		    	    conp->vc_video_erase_char,
+		    	    conp->vc_size_row * count);
+		return 1;
 	    }
 	    break;
 
 	case SM_DOWN:
 	    if (count > conp->vc_rows)	/* Maximum realistic size */
 		count = conp->vc_rows;
-	    if (vt_cons[unit]->vc_mode == KD_TEXT)
-		switch (p->scrollmode) {
-		    case SCROLL_YWRAP:
-			if (b-t-count > 3*conp->vc_rows>>2) {
-			    if (conp->vc_rows-b > 0)
-				fbcon_bmove(conp, b, 0, b-count, 0,
-					    conp->vc_rows-b, conp->vc_cols);
-			    ywrap_down(unit, conp, p, count);
-			    if (t > 0)
-				fbcon_bmove(conp, count, 0, 0, 0, t,
-					    conp->vc_cols);
-			} else
-			    fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
-					conp->vc_cols);
-			fbcon_clear(conp, t, 0, count, conp->vc_cols);
-			break;
-
-		    case SCROLL_YPAN:
-			if (( is_txt && (b-t == conp->vc_rows)) ||
-			    (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) {
-			    if (conp->vc_rows-b > 0)
-				fbcon_bmove(conp, b, 0, b-count, 0,
-					    conp->vc_rows-b, conp->vc_cols);
-			    ypan_down(unit, conp, p, count);
-			    if (t > 0)
-				fbcon_bmove(conp, count, 0, 0, 0, t,
-					    conp->vc_cols);
-			} else
-			    fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
-					conp->vc_cols);
-			fbcon_clear(conp, t, 0, count, conp->vc_cols);
-			break;
-
-		    case SCROLL_YMOVE:
-			p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count,
-					 conp->vc_cols);
-			p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols);
-			break;
-			
-		    case SCROLL_YREDRAW:
-			fbcon_redraw(conp, p, b - 1, b-t-count, -count*conp->vc_cols);
-			p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols);
-		    	scr_memsetw((unsigned short *)(conp->vc_origin + 
-		    		    conp->vc_size_row * t), 
-		    		    conp->vc_video_erase_char,
-		    		    conp->vc_size_row * count);
-		    	return 1;
-		}
-	    else {
-		/*
-		 *  Fixed bmove() should end Arno's frustration with copying?
-		 *  Confucius says:
-		 *	Man who copies in wrong direction, end up with trashed
-		 *	data
-		 */
-		fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols);
+	    switch (p->scrollmode & __SCROLL_YMASK) {
+	    case __SCROLL_YMOVE:
+		p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count,
+				 conp->vc_cols);
+		p->dispsw->clear(conp, p, t, 0,
+				 count, conp->vc_cols);
+		break;
+
+	    case __SCROLL_YWRAP:
+		if (b-t-count > 3*conp->vc_rows>>2) {
+		    if (conp->vc_rows-b > 0)
+			fbcon_bmove(conp, b, 0, b-count, 0,
+				    conp->vc_rows-b, conp->vc_cols);
+		    ywrap_down(unit, conp, p, count);
+		    if (t > 0)
+			fbcon_bmove(conp, count, 0, 0, 0, t,
+				    conp->vc_cols);
+		} else if (p->scrollmode & __SCROLL_YPANREDRAW)
+		    goto redraw_down;
+		else
+		    fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
+				conp->vc_cols);
 		fbcon_clear(conp, t, 0, count, conp->vc_cols);
-	    }
-	    break;
+		break;
 
-	case SM_LEFT:
-	    fbcon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count);
-	    fbcon_clear(conp, 0, b-count, conp->vc_rows, count);
-	    break;
+	    case __SCROLL_YPAN:
+		if (( is_txt && (b-t == conp->vc_rows)) ||
+		    (!is_txt && (b-t-count > 3*conp->vc_rows>>2))) {
+		    if (conp->vc_rows-b > 0)
+			fbcon_bmove(conp, b, 0, b-count, 0,
+				    conp->vc_rows-b, conp->vc_cols);
+		    ypan_down(unit, conp, p, count);
+		    if (t > 0)
+			fbcon_bmove(conp, count, 0, 0, 0, t,
+				    conp->vc_cols);
+		} else if (p->scrollmode & __SCROLL_YPANREDRAW)
+		    goto redraw_down;
+		else
+		    fbcon_bmove(conp, t, 0, t+count, 0, b-t-count,
+				conp->vc_cols);
+		fbcon_clear(conp, t, 0, count, conp->vc_cols);
+		break;
 
-	case SM_RIGHT:
-	    fbcon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count);
-	    fbcon_clear(conp, 0, t, conp->vc_rows, count);
-	    break;
+	    case __SCROLL_YREDRAW:
+	    redraw_down:
+		fbcon_redraw(conp, p, b - 1, b-t-count, -count*conp->vc_cols);
+		p->dispsw->clear(conp, p, real_y(p, t), 0,
+				 count, conp->vc_cols);
+	    	scr_memsetw((unsigned short *)(conp->vc_origin + 
+	    		    conp->vc_size_row * t), 
+	    		    conp->vc_video_erase_char,
+	    		    conp->vc_size_row * count);
+	    	return 1;
+	    }
     }
     return 0;
 }
@@ -1100,12 +1152,12 @@
     		conp2->vc_top = 0;
     	logo_shown = -1;
     }
-    p->var.yoffset = p->yscroll*p->fontheight;
-    switch (p->scrollmode) {
-	case SCROLL_YWRAP:
+    p->var.yoffset = p->yscroll = 0;
+    switch (p->scrollmode & __SCROLL_YMASK) {
+	case __SCROLL_YWRAP:
 	    scrollback_phys_max = p->vrows-conp->vc_rows;
 	    break;
-	case SCROLL_YPAN:
+	case __SCROLL_YPAN:
 	    scrollback_phys_max = p->vrows-2*conp->vc_rows;
 	    if (scrollback_phys_max < 0)
 		scrollback_phys_max = 0;
@@ -1118,9 +1170,17 @@
     scrollback_current = 0;
 
     if (info && info->switch_con)
-	(*info->switch_con)(conp->vc_num, info);
-    if (p->dispsw && p->dispsw->clear_margins)
-	p->dispsw->clear_margins(conp, p);
+	(*info->switch_con)(unit, info);
+    if (p->dispsw->clear_margins && vt_cons[unit]->vc_mode == KD_TEXT)
+	p->dispsw->clear_margins(conp, p, 0);
+    if (logo_shown == -2) {
+	logo_shown = fg_console;
+	fbcon_show_logo(); /* This is protected above by initmem_freed */
+	update_region(fg_console,
+		      conp->vc_origin + conp->vc_size_row * conp->vc_top,
+		      conp->vc_size_row * (conp->vc_bottom - conp->vc_top) / 2);
+	return 0;
+    }
     return 1;
 }
 
@@ -1151,7 +1211,7 @@
 			     p->var.xres_virtual*p->var.yres_virtual*
 			     p->var.bits_per_pixel>>3);
 	     } else
-		 p->dispsw->clear(conp, p, 0, 0, p->conp->vc_rows, p->conp->vc_cols);
+		 p->dispsw->clear(NULL, p, 0, 0, p->conp->vc_rows, p->conp->vc_cols);
 	    return 0;
 	} else {
 	    /* Tell console.c that it has to restore the screen itself */
@@ -1162,67 +1222,73 @@
     return 0;
 }
 
+static void fbcon_free_font(struct display *p)
+{
+    if (p->userfont && p->fontdata &&
+        (--REFCOUNT(p->fontdata) == 0))
+	kfree(p->fontdata - FONT_EXTRA_WORDS*sizeof(int));
+    p->fontdata = NULL;
+    p->userfont = 0;
+}
 
 static inline int fbcon_get_font(int unit, struct console_font_op *op)
 {
     struct display *p = &fb_display[unit];
     u8 *data = op->data;
+    u8 *fontdata = p->fontdata;
     int i, j;
 
 #ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
-    if (p->fontwidth != 8) return -EINVAL;
+    if (fontwidth(p) != 8) return -EINVAL;
 #endif
-    op->width = p->fontwidth;
-    op->height = p->fontheight;
+    op->width = fontwidth(p);
+    op->height = fontheight(p);
     op->charcount = (p->charmask == 0x1ff) ? 512 : 256;
     if (!op->data) return 0;
     
     if (op->width <= 8) {
     	for (i = 0; i < op->charcount; i++) {
-	    for (j = 0; j < p->fontheight; j++)
-		*data++ = p->fontdata[i*p->fontheight+j];
-	    data += 32 - p->fontheight;
+	    for (j = 0; j < fontheight(p); j++)
+		*data++ = *fontdata++;
+	    memset(data, 0, 32-j);
 	}
     }
 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
     else if (op->width <= 16) {
 	for (i = 0; i < op->charcount; i++) {
-	    for (j = 0; j < p->fontheight; j++) {
-		*data++ = ((u16 *)p->fontdata)[i*p->fontheight+j] >> 8;
-		*data++ = ((u16 *)p->fontdata)[i*p->fontheight+j];
+	    for (j = 0; j < fontheight(p); j++) {
+		*data++ = *(u16 *)fontdata >> 8;
+		*data++ = *(u16 *)fontdata;
+		fontdata += sizeof(u16);
 	    }
-	    data += 2 * (32 - p->fontheight);
+	    memset(data, 0, 2*(32-j));
 	}
     } else if (op->width <= 24) {
 	for (i = 0; i < op->charcount; i++) {
-	    for (j = 0; j < p->fontheight; j++) {
-		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24;
-		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16;
-		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8;
+	    for (j = 0; j < fontheight(p); j++) {
+		*data++ = *(u32 *)fontdata >> 24;
+		*data++ = *(u32 *)fontdata >> 16;
+		*data++ = *(u32 *)fontdata >> 8;
+		fontdata += sizeof(u32);
 	    }
-	    data += 3 * (32 - p->fontheight);
+	    memset(data, 0, 3*(32-j));
 	}
     } else {
 	for (i = 0; i < op->charcount; i++) {
-	    for (j = 0; j < p->fontheight; j++) {
-		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24;
-		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16;
-		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8;
-		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j];
+	    for (j = 0; j < fontheight(p); j++) {
+		*data++ = *(u32 *)fontdata >> 24;
+		*data++ = *(u32 *)fontdata >> 16;
+		*data++ = *(u32 *)fontdata >> 8;
+		*data++ = *(u32 *)fontdata;
+		fontdata += sizeof(u32);
 	    }
-	    data += 4 * (32 - p->fontheight);
+	    memset(data, 0, 4*(32-j));
 	}
     }
 #endif
     return 0;
 }
 
-
-#define REFCOUNT(fd)	(((int *)(fd))[-1])
-#define FNTSIZE(fd)	(((int *)(fd))[-2])
-#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
-#define FNTSUM(fd)	(((int *)(fd))[-4])
-
 static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont)
 {
     struct display *p = &fb_display[unit];
@@ -1233,12 +1299,12 @@
     char *old_data = NULL;
 
     if (!fontwidthvalid(p,w)) {
-        if (userfont)
-	    kfree(data);
+        if (userfont && op->op != KD_FONT_OP_COPY)
+	    kfree(data - FONT_EXTRA_WORDS*sizeof(int));
 	return -ENXIO;
     }
 
-    resize = (w != p->fontwidth) || (h != p->fontheight);
+    resize = (w != fontwidth(p)) || (h != fontheight(p));
     if (p->userfont)
         old_data = p->fontdata;
     if (userfont)
@@ -1248,8 +1314,8 @@
     p->fontdata = data;
     if ((p->userfont = userfont))
         REFCOUNT(data)++;
-    p->fontwidth = w;
-    p->fontheight = h;
+    p->_fontwidth = w;
+    p->_fontheight = h;
     if (p->conp->vc_hi_font_mask && cnt == 256) {
     	p->conp->vc_hi_font_mask = 0;
     	p->conp->vc_complement_mask >>= 1;
@@ -1269,18 +1335,21 @@
 	/* reset wrap/pan */
 	p->var.xoffset = p->var.yoffset = p->yscroll = 0;
 	if (!p->dispsw->set_font || 
-	    !p->dispsw->set_font(p, p->fontwidth, p->fontheight)) {
+	    !p->dispsw->set_font(p, fontwidth(p), fontheight(p))) {
 	    /* Adjust the virtual screen-size to fontheight*rows */
 	    p->var.yres_virtual = (p->var.yres/h)*h;
 	}
 	p->vrows = p->var.yres_virtual/h;
 	updatescrollmode(p);
 	vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
-    } else if (unit == fg_console)
-	update_screen( unit );
+    } else if (CON_IS_VISIBLE(p->conp) && vt_cons[unit]->vc_mode == KD_TEXT) {
+	if (p->dispsw->clear_margins)
+	    p->dispsw->clear_margins(p->conp, p, 0);
+	update_screen(unit);
+    }
 
     if (old_data && (--REFCOUNT(old_data) == 0))
-	kfree( old_data - 4*sizeof(int) );
+	kfree(old_data - FONT_EXTRA_WORDS*sizeof(int));
 
     return 0;
 }
@@ -1297,8 +1366,8 @@
     od = &fb_display[h];
     if (od->fontdata == p->fontdata)
         return 0; /* already the same font... */
-    op->width = od->fontwidth;
-    op->height = od->fontheight;
+    op->width = fontwidth(od);
+    op->height = fontheight(od);
     return fbcon_do_set_font(unit, op, od->fontdata, od->userfont);
 }
 
@@ -1309,9 +1378,10 @@
     int size = h;
     int i, j, k;
     u8 *new_data, *data = op->data, c, *p;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
     u32 d;
+#else
 
-#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
     if (w != 8)
     	return -EINVAL;
 #endif
@@ -1327,57 +1397,59 @@
     }
     size *= op->charcount;
        
-    if (!(new_data = kmalloc( 4*sizeof(int)+size, GFP_USER )))
+    if (!(new_data = kmalloc(FONT_EXTRA_WORDS*sizeof(int)+size, GFP_USER)))
         return -ENOMEM;
-    new_data += 4*sizeof(int);
+    new_data += FONT_EXTRA_WORDS*sizeof(int);
     FNTSIZE(new_data) = size;
     FNTCHARCNT(new_data) = op->charcount;
     REFCOUNT(new_data) = 0; /* usage counter */
     k = 0;
-    p = data;
+    p = new_data;
     if (w <= 8) {
 	for (i = 0; i < op->charcount; i++) {
 	    for (j = 0; j < h; j++) {
-	        c = *p++;
+	        c = *data++;
 		k += c;
-		new_data[i*h+j] = c;
+		*p++ = c;
 	    }
-	    p += 32 - h;
+	    data += 32 - h;
 	}
     }
 #ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
     else if (w <= 16) {
 	for (i = 0; i < op->charcount; i++) {
 	    for (j = 0; j < h; j++) {
-	        d = (p[0] << 8) | p[1];
-	        p += 2;
+	        d = (data[0] << 8) | data[1];
+	        data += 2;
 		k += d;
-		((u16 *)new_data)[i*h+j] = d;
+		*(u16 *)p = d;
+		p += sizeof(u16);
 	    }
-	    p += 2*(32 - h);
+	    data += 2*(32 - h);
 	}
     } else {
 	for (i = 0; i < op->charcount; i++) {
 	    for (j = 0; j < h; j++) {
 	    	if (w <= 24) {
-		    d = (p[0] << 24) | 
-			(p[1] << 16) | 
-			(p[2] << 8);
-		    p += 3;
+		    d = (data[0] << 24) | 
+			(data[1] << 16) | 
+			(data[2] << 8);
+		    data += 3;
 		} else {
-		    d = (p[0] << 24) | 
-			(p[1] << 16) | 
-			(p[2] << 8) |
-			p[3];
-		    p += 4;
+		    d = (data[0] << 24) | 
+			(data[1] << 16) | 
+			(data[2] << 8) |
+			data[3];
+		    data += 4;
 		}
 		k += d;
-		((u32 *)new_data)[i*h+j] = d;
+		*(u32 *)p = d;
+		p += sizeof(u32);
 	    }
 	    if (w <= 24)
-	    	p += 3*(32 - h);
+		data += 3*(32 - h);
 	    else
-	        p += 4*(32 - h);
+		data += 4*(32 - h);
 	}
     }
 #endif
@@ -1389,7 +1461,7 @@
     	    FNTSUM(fb_display[i].fontdata) == k &&
     	    FNTSIZE(fb_display[i].fontdata) == size &&
 	    !memcmp(fb_display[i].fontdata, new_data, size)) {
-	    kfree(new_data - 4*sizeof(int));
+	    kfree(new_data - FONT_EXTRA_WORDS*sizeof(int));
 	    new_data = fb_display[i].fontdata;
 	    break;
     	}
@@ -1495,11 +1567,11 @@
 
     offset = p->yscroll-scrollback_current;
     limit = p->vrows;
-    switch (p->scrollmode) {
-	case SCROLL_YWRAP:
+    switch (p->scrollmode && __SCROLL_YMASK) {
+	case __SCROLL_YWRAP:
 	    p->var.vmode |= FB_VMODE_YWRAP;
 	    break;
-	case SCROLL_YPAN:
+	case __SCROLL_YPAN:
 	    limit -= conp->vc_rows;
 	    p->var.vmode &= ~FB_VMODE_YWRAP;
 	    break;
@@ -1509,13 +1581,18 @@
     else if (offset >= limit)
 	offset -= limit;
     p->var.xoffset = 0;
-    p->var.yoffset = offset*p->fontheight;
+    p->var.yoffset = offset*fontheight(p);
     p->fb_info->updatevar(unit, p->fb_info);
     if (!offset)
 	fbcon_cursor(conp, CM_DRAW);
     return 0;
 }
 
+static inline unsigned safe_shift(unsigned d,int n)
+{
+    return n<0 ? d>>-n : d<<n;
+}
+
 __initfunc(static int fbcon_show_logo( void ))
 {
     struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
@@ -1532,10 +1609,10 @@
 	return 0;
 
     /* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
-     * TRUECOLOR */
+     * DIRECTCOLOR */
     if ((p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) ||
-	p->visual == FB_VISUAL_TRUECOLOR) {
-	int is_truecolor = (p->visual == FB_VISUAL_TRUECOLOR);
+	p->visual == FB_VISUAL_DIRECTCOLOR) {
+	int is_truecolor = (p->visual == FB_VISUAL_DIRECTCOLOR);
 	int use_256 = (!is_truecolor && depth >= 8) ||
 		      (is_truecolor && depth >= 24);
 	int first_col = use_256 ? 32 : depth > 4 ? 16 : 0;
@@ -1588,7 +1665,7 @@
     	 
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
     defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
-        if (p->visual == FB_VISUAL_TRUECOLOR) {
+        if (p->visual == FB_VISUAL_DIRECTCOLOR) {
 	    unsigned int val;		/* max. depth 32! */
 	    int bdepth;
 	    int redshift, greenshift, blueshift;
@@ -1629,13 +1706,21 @@
 			val = (pix << redshift) |
 			      (pix << greenshift) |
 			      (pix << blueshift);
+#ifdef __LITTLE_ENDIAN
 			for( i = 0; i < bdepth; ++i )
+#else
+			for( i = bdepth-1; i >= 0; --i )
+#endif
 			    *dst++ = val >> (i*8);
 			pix = (*src & 0x0f) | 0x10; /* lower nibble */
 			val = (pix << redshift) |
 			      (pix << greenshift) |
 			      (pix << blueshift);
+#ifdef __LITTLE_ENDIAN
+			for( i = 0; i < bdepth; ++i )
+#else
 			for( i = bdepth-1; i >= 0; --i )
+#endif
 			    *dst++ = val >> (i*8);
 		    }
 		}
@@ -1645,7 +1730,7 @@
 #endif
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
     defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FB_SBUS)
-	if ((depth % 8 == 0) && (p->visual == FB_VISUAL_DIRECTCOLOR)) {
+	if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR)) {
 	    /* Modes without color mapping, needs special data transformation... */
 	    unsigned int val;		/* max. depth 32! */
 	    int bdepth = depth/8;
@@ -1665,9 +1750,9 @@
 	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
 		dst = fb + y1*line + x*bdepth;
 		for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
-		    val = ((linux_logo_red[*src-32]   & redmask)   << redshift) |
-		          ((linux_logo_green[*src-32] & greenmask) << greenshift) |
-		          ((linux_logo_blue[*src-32]  & bluemask)  << blueshift);
+		    val = safe_shift((linux_logo_red[*src-32]   & redmask), redshift) |
+		          safe_shift((linux_logo_green[*src-32] & greenmask), greenshift) |
+		          safe_shift((linux_logo_blue[*src-32]  & bluemask), blueshift);
 #ifdef __LITTLE_ENDIAN
 		    for( i = 0; i < bdepth; ++i )
 #else
@@ -1766,7 +1851,7 @@
     /* Modes not yet supported: packed pixels with depth != 8 (does such a
      * thing exist in reality?) */
 
-    return done ? (LOGO_H + p->fontheight - 1) / p->fontheight : 0 ;
+    return done ? (LOGO_H + fontheight(p) - 1) / fontheight(p) : 0 ;
 }
 
 /*
@@ -1801,7 +1886,7 @@
 
 static void fbcon_dummy_op(void) {}
 
-static struct display_switch fbcon_dummy = {
+struct display_switch fbcon_dummy = {
     (void *)fbcon_dummy_op,	/* fbcon_dummy_setup */
     (void *)fbcon_dummy_op,	/* fbcon_dummy_bmove */
     (void *)fbcon_dummy_op,	/* fbcon_dummy_clear */
@@ -1818,3 +1903,4 @@
 
 EXPORT_SYMBOL(fb_display);
 EXPORT_SYMBOL(fbcon_redraw_bmove);
+EXPORT_SYMBOL(fbcon_dummy);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov