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

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

diff -u --recursive --new-file v2.1.90/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
@@ -28,26 +28,17 @@
  *  The low level operations for the various display memory organizations are
  *  now in separate source files.
  *
- *  Currently only the following organizations are supported:
+ *  Currently the following organizations are supported:
  *
- *    - non-accelerated:
- *
- *	  o mfb		 Monochrome
- *	  o ilbm	 Interleaved bitplanes à la Amiga
- *	  o afb		 Bitplanes à la Amiga
- *	  o iplan2p[248] Interleaved bitplanes à la Atari (2, 4 and 8 planes)
- *	  o cfb{8,16}    Packed pixels (8 and 16 bpp)
- *
- *    - accelerated:
- *
- *	  o cyber	 CyberVision64 packed pixels (accelerated)
- *	  o retz3	 Retina Z3 packed pixels (accelerated)
- *	  o mach64	 ATI Mach 64 packed pixels (accelerated)
+ *    o afb			Amiga bitplanes
+ *    o cfb{2,4,8,16,24,32}	Packed pixels
+ *    o ilbm			Amiga interleaved bitplanes
+ *    o iplan2p[248]		Atari interleaved bitplanes
+ *    o mfb			Monochrome
  *
  *  To do:
  *
  *    - Implement 16 plane mode (iplan2p16)
- *    - Add support for 24/32 bit packed pixels (cfb{24,32})
  *    - Hardware cursor
  *
  *
@@ -56,6 +47,8 @@
  *  more details.
  */
 
+#undef FBCONDEBUG
+
 #define SUPPORT_SCROLLBACK	0
 #define FLASHING_CURSOR		1
 
@@ -65,6 +58,7 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
+#include <linux/delay.h>	/* MSch: for IRQ probe */
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
@@ -74,9 +68,6 @@
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/init.h>
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
 
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -88,6 +79,9 @@
 #ifdef CONFIG_ATARI
 #include <asm/atariints.h>
 #endif
+#ifdef CONFIG_MAC
+#include <asm/macints.h>
+#endif
 #ifdef __mc68000__
 #include <asm/machdep.h>
 #include <asm/setup.h>
@@ -95,8 +89,14 @@
 #include <asm/linux_logo.h>
 
 #include "fbcon.h"
+#include "fbcon-mac.h"	/* for 6x11 font on mac */
 #include "font.h"
 
+#ifdef FBCONDEBUG
+#  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
 
 struct display fb_display[MAX_NR_CONSOLES];
 
@@ -112,6 +112,7 @@
 /* # VBL ints between cursor state changes */
 #define AMIGA_CURSOR_BLINK_RATE		(20)
 #define ATARI_CURSOR_BLINK_RATE		(42)
+#define MAC_CURSOR_BLINK_RATE		(32)
 #define DEFAULT_CURSOR_BLINK_RATE	(20)
 
 static int vbl_cursor_cnt = 0;
@@ -146,26 +147,25 @@
 static unsigned long fbcon_startup(unsigned long kmem_start,
 				   const char **display_desc);
 static void fbcon_init(struct vc_data *conp);
-static int fbcon_deinit(struct vc_data *conp);
+static void fbcon_deinit(struct vc_data *conp);
 static int fbcon_changevar(int con);
-static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
+static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
 		       int width);
-static int fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos);
-static int fbcon_putcs(struct vc_data *conp, const char *s, int count,
-		       int ypos, int xpos);
-static int fbcon_cursor(struct vc_data *conp, int mode);
-static int fbcon_scroll(struct vc_data *conp, int t, int b,
-			int dir, int count);
-static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
-		       int height, int width);
+static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos);
+static void fbcon_putcs(struct vc_data *conp, const char *s, int count,
+			int ypos, int xpos);
+static void fbcon_cursor(struct vc_data *conp, int mode);
+static void fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
+			 int count);
+static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+			int height, int width);
 static int fbcon_switch(struct vc_data *conp);
 static int fbcon_blank(int blank);
 static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
 static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data);
 static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
 static int fbcon_scrolldelta(int lines);
-int fbcon_register_driver(struct display_switch *dispsw, int is_accel);
-int fbcon_unregister_driver(struct display_switch *dispsw);
+static int fbcon_set_mode(struct vc_data *conp, int mode);
 
 
 /*
@@ -193,16 +193,23 @@
 				 struct display *p, int count);
 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
 			    int height, int width, u_int y_break);
-static struct display_switch *probe_list(struct display_switch *dispsw,
-					 struct display *disp);
 
-#ifdef CONFIG_KMOD
-static void request_driver(struct display *disp, int is_accel);
-#endif
-static struct display_switch *fbcon_get_driver(struct display *disp);
 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
+ */
+static int vbl_detected = 0;
+
+static void fbcon_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
+{
+      vbl_detected++;
+}
+#endif
+
 static void cursor_timer_handler(unsigned long dev_addr);
 
 static struct timer_list cursor_timer = {
@@ -212,7 +219,7 @@
 static void cursor_timer_handler(unsigned long dev_addr)
 {
       fbcon_vbl_handler(0, NULL, NULL);
-      cursor_timer.expires = jiffies+2;
+      cursor_timer.expires = jiffies+HZ/50;
       cursor_timer.data = 0;
       cursor_timer.next = cursor_timer.next = NULL;
       add_timer(&cursor_timer);
@@ -223,49 +230,8 @@
  *  Low Level Operations
  */
 
-static struct display_switch dispsw_dummy;
-
-#ifdef CONFIG_FBCON_MFB
-extern int fbcon_init_mfb(void);
-#endif
-#ifdef CONFIG_FBCON_ILBM
-extern int fbcon_init_ilbm(void);
-#endif
-#ifdef CONFIG_FBCON_AFB
-extern int fbcon_init_afb(void);
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P2
-extern int fbcon_init_iplan2p2(void);
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P4
-extern int fbcon_init_iplan2p4(void);
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P8
-extern int fbcon_init_iplan2p8(void);
-#endif
-#ifdef CONFIG_FBCON_CFB8
-extern int fbcon_init_cfb8(void);
-#endif
-#ifdef CONFIG_FBCON_CFB16
-extern int fbcon_init_cfb16(void);
-#endif
-#ifdef CONFIG_FBCON_CFB24
-extern int fbcon_init_cfb24(void);
-#endif
-#ifdef CONFIG_FBCON_CFB32
-extern int fbcon_init_cfb32(void);
-#endif
-#ifdef CONFIG_FBCON_CYBER
-extern int fbcon_init_cyber(void);
-#endif
-#ifdef CONFIG_FBCON_RETINAZ3
-extern int fbcon_init_retz3(void);
-#endif
-#ifdef CONFIG_FBCON_MACH64
-extern int fbcon_init_mach64(void);
-#endif
+static struct display_switch fbcon_dummy;
 
-extern int num_registered_fb;
 
 __initfunc(static unsigned long fbcon_startup(unsigned long kmem_start,
 					      const char **display_desc))
@@ -275,49 +241,10 @@
     /* Probe all frame buffer devices */
     kmem_start = probe_framebuffers(kmem_start);
 
-    if (!num_registered_fb)
+    if (!num_registered_fb) {
+            DPRINTK("no framebuffer registered\n");
 	    return kmem_start;
-
-    /* Initialize all built-in low level drivers */
-#ifdef CONFIG_FBCON_RETINAZ3
-    fbcon_init_retz3();
-#endif
-#ifdef CONFIG_FBCON_MFB
-    fbcon_init_mfb();
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P2
-    fbcon_init_iplan2p2();
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P4
-    fbcon_init_iplan2p4();
-#endif
-#ifdef CONFIG_FBCON_IPLAN2P8
-    fbcon_init_iplan2p8();
-#endif
-#ifdef CONFIG_FBCON_ILBM
-    fbcon_init_ilbm();
-#endif
-#ifdef CONFIG_FBCON_AFB
-    fbcon_init_afb();
-#endif
-#ifdef CONFIG_FBCON_CFB8
-    fbcon_init_cfb8();
-#endif
-#ifdef CONFIG_FBCON_CFB16
-    fbcon_init_cfb16();
-#endif
-#ifdef CONFIG_FBCON_CFB24
-    fbcon_init_cfb24();
-#endif
-#ifdef CONFIG_FBCON_CFB32
-    fbcon_init_cfb32();
-#endif
-#ifdef CONFIG_FBCON_CYBER
-    fbcon_init_cyber();
-#endif
-#ifdef CONFIG_FBCON_MACH64
-    fbcon_init_mach64();
-#endif
+    }
 
     *display_desc = "frame buffer device";
 
@@ -335,9 +262,49 @@
 			     "console/cursor", fbcon_vbl_handler);
     }
 #endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_MAC
+    /*
+     * On a Macintoy, the VBL interrupt may or may not be active. 
+     * As interrupt based cursor is more reliable and race free, we 
+     * 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);
+ 
+       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 ?? */
+       }
+    }
+#endif /* CONFIG_MAC */
+
     if (irqres) {
 	cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE;
-	cursor_timer.expires = jiffies+2;
+	cursor_timer.expires = jiffies+HZ/50;
 	cursor_timer.data = 0;
 	cursor_timer.next = cursor_timer.prev = NULL;
 	add_timer(&cursor_timer);
@@ -360,22 +327,24 @@
 
     info->changevar = &fbcon_changevar;
     fb_display[unit] = *(info->disp);	/* copy from default */
+    DPRINTK("mode:   %s\n",info->modename);
+    DPRINTK("visual: %d\n",fb_display[unit].visual);
+    DPRINTK("res:    %dx%d-%d\n",fb_display[unit].var.xres,
+	                     fb_display[unit].var.yres,
+	                     fb_display[unit].var.bits_per_pixel);
     fb_display[unit].conp = conp;
     fb_display[unit].fb_info = info;
     fbcon_setup(unit, 1, 1);
 }
 
 
-static int fbcon_deinit(struct vc_data *conp)
+static void fbcon_deinit(struct vc_data *conp)
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
 
-    if (p->dispsw)
-	    p->dispsw->release();
-    p->dispsw = 0;
+    p->dispsw = NULL;
     p->conp = 0;
-    return(0);
 }
 
 
@@ -405,7 +374,6 @@
     struct display *p = &fb_display[con];
     struct vc_data *conp = p->conp;
     int nr_rows, nr_cols;
-    struct display_switch *old_dispsw, *new_dispsw;
 
     p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
 
@@ -415,9 +383,17 @@
 	getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth,
 		       &p->fontheight, &p->fontdata);
     if (p->fontwidth != 8) {
-	/* ++Geert: changed from panic() to `correct and continue' */
-	printk(KERN_ERR "fbcon_setup: No support for fontwidth != 8");
-	p->fontwidth = 8;
+#ifdef CONFIG_MAC
+	if (MACH_IS_MAC)
+	    /* ++Geert: hack to make 6x11 fonts work on mac */
+	    p->dispsw = &fbcon_mac;
+	else
+#endif
+	{
+	    /* ++Geert: changed from panic() to `correct and continue' */
+	    printk(KERN_ERR "fbcon_setup: No support for fontwidth != 8");
+	    p->dispsw = &fbcon_dummy;
+	}
     }
     updatescrollmode(p);
 
@@ -435,18 +411,12 @@
     p->vrows = p->var.yres_virtual/p->fontheight;
     conp->vc_can_do_color = p->var.bits_per_pixel != 1;
 
-    new_dispsw = fbcon_get_driver(p);
-    if (!new_dispsw) {
+    if (!p->dispsw) {
 	printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
 	       "supported\n", p->type, p->type_aux, p->var.bits_per_pixel);
-	dispsw_dummy.open(p);
-	new_dispsw = &dispsw_dummy;
+	p->dispsw = &fbcon_dummy;
     }
-    /* Be careful when changing dispsw, it might be the current console.  */
-    old_dispsw = p->dispsw;
-    p->dispsw = new_dispsw;
-    if (old_dispsw)
-	old_dispsw->release();
+    p->dispsw->setup(p);
 
     if (setcol) {
 	p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<<p->var.bits_per_pixel)-1;
@@ -492,15 +462,18 @@
 }
 
 
-static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
-			      int width)
+static void fbcon_clear(struct vc_data *conp, int sy, int sx, int height,
+			int width)
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
     u_int y_break;
 
     if (!p->can_soft_blank && console_blanked)
-	return(0);
+	return;
+
+    if (!height || !width)
+	return;
 
     if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
 	(sx <= p->cursor_x) && (p->cursor_x < sx+width))
@@ -515,47 +488,41 @@
 	p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width);
     } else
 	p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width);
-
-    return(0);
 }
 
 
-static int fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos)
+static void fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos)
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
 
     if (!p->can_soft_blank && console_blanked)
-	    return 0;
+	    return;
 
     if ((p->cursor_x == xpos) && (p->cursor_y == ypos))
 	    CURSOR_UNDRAWN();
 
     p->dispsw->putc(conp, p, c, real_y(p, ypos), xpos);
-
-    return 0;
 }
 
 
-static int fbcon_putcs(struct vc_data *conp, const char *s, int count,
+static void fbcon_putcs(struct vc_data *conp, const char *s, int count,
 		       int ypos, int xpos)
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
 
     if (!p->can_soft_blank && console_blanked)
-	    return 0;
+	    return;
 
     if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
 	(p->cursor_x < (xpos + count)))
 	    CURSOR_UNDRAWN();
     p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos);
-
-    return(0);
 }
 
 
-static int fbcon_cursor(struct vc_data *conp, int mode)
+static void fbcon_cursor(struct vc_data *conp, int mode)
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
@@ -563,9 +530,9 @@
     /* Avoid flickering if there's no real change. */
     if (p->cursor_x == conp->vc_x && p->cursor_y == conp->vc_y &&
 	(mode == CM_ERASE) == !cursor_on)
-	return 0;
+	return;
     if (CURSOR_UNDRAWN ())
-	p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
+	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;
 
@@ -580,8 +547,6 @@
 	    cursor_on = 1;
 	    break;
     }
-
-    return(0);
 }
 
 
@@ -598,7 +563,7 @@
 	 * switching code should set vbl_cursor_cnt to an appropriate value.
 	 */
 	p = &fb_display[fg_console];
-	p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y));
+	p->dispsw->revc(p, p->cursor_x, real_y(p, p->cursor_y));
 	cursor_drawn ^= 1;
 	vbl_cursor_cnt = cursor_blink_rate;
     }
@@ -623,7 +588,7 @@
     p->var.xoffset = 0;
     p->var.yoffset = p->yscroll*p->fontheight;
     p->var.vmode |= FB_VMODE_YWRAP;
-    p->fb_info->updatevar(unit);
+    p->fb_info->updatevar(unit, p->fb_info);
 #if SUPPORT_SCROLLBACK
     scrollback_max += count;
     if (scrollback_max > p->vrows-conp->vc_rows)
@@ -646,7 +611,7 @@
     p->var.xoffset = 0;
     p->var.yoffset = p->yscroll*p->fontheight;
     p->var.vmode |= FB_VMODE_YWRAP;
-    p->fb_info->updatevar(unit);
+    p->fb_info->updatevar(unit, p->fb_info);
 #if SUPPORT_SCROLLBACK
     scrollback_max -= count;
     if (scrollback_max < 0)
@@ -668,7 +633,7 @@
     p->var.xoffset = 0;
     p->var.yoffset = p->yscroll*p->fontheight;
     p->var.vmode &= ~FB_VMODE_YWRAP;
-    p->fb_info->updatevar(unit);
+    p->fb_info->updatevar(unit, p->fb_info);
 }
 
 
@@ -684,17 +649,21 @@
     p->var.xoffset = 0;
     p->var.yoffset = p->yscroll*p->fontheight;
     p->var.vmode &= ~FB_VMODE_YWRAP;
-    p->fb_info->updatevar(unit);
+    p->fb_info->updatevar(unit, p->fb_info);
 }
 
 
-static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
+static void fbcon_scroll(struct vc_data *conp, int t, int b, int dir,
+			 int count)
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
 
     if (!p->can_soft_blank && console_blanked)
-	return(0);
+	return;
+
+    if (!count)
+	return;
 
     fbcon_cursor(conp, CM_ERASE);
 
@@ -822,19 +791,20 @@
 	    fbcon_clear(conp, 0, t, conp->vc_rows, count);
 	    break;
     }
-
-    return(0);
 }
 
 
-static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
-		       int height, int width)
+static void fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
+			int height, int width)
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
 
     if (!p->can_soft_blank && console_blanked)
-	return(0);
+	return;
+
+    if (!width || !height)
+	return;
 
     if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
 	 (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
@@ -850,8 +820,6 @@
      *  over again, so we use fbcon_bmove_rec()
      */
     fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
-
-    return(0);
 }
 
 
@@ -894,7 +862,7 @@
     struct fb_info *info = p->fb_info;
 
     if (info && info->switch_con)
-	(*info->switch_con)(conp->vc_num);
+	(*info->switch_con)(conp->vc_num, info);
 #if SUPPORT_SCROLLBACK
     scrollback_max = 0;
     scrollback_current = 0;
@@ -906,11 +874,19 @@
 static int fbcon_blank(int blank)
 {
     struct display *p = &fb_display[fg_console];
+    struct fb_info *info = p->fb_info;
 
     fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
 
     if (!p->can_soft_blank) {
 	if (blank) {
+#ifdef CONFIG_MAC
+	    if (MACH_IS_MAC)
+		mymemset(p->screen_base,
+			 p->var.xres_virtual*p->var.yres_virtual*
+			 p->var.bits_per_pixel>>3);
+	    else
+#endif
 	    if (p->visual == FB_VISUAL_MONO01)
 		mymemset(p->screen_base,
 			 p->var.xres_virtual*p->var.yres_virtual*
@@ -925,7 +901,7 @@
 	    return(1);
 	}
     }
-    (*p->fb_info->blank)(blank);
+    (*info->blank)(blank, info);
     return(0);
 }
 
@@ -975,7 +951,7 @@
 	copy_from_user( name, data, MAX_FONT_NAME );
 	name[sizeof(name)-1] = 0;
 
-	if (!findsoftfont( name, &w, &h, (u_char **)&data ))
+	if (!findsoftfont( name, &w, &h, (u8 **)&data ))
 	    return( -ENOENT );
 	userspace = 0;
     } else if (w == 1) {
@@ -1049,9 +1025,9 @@
     return( 0 );
 }
 
-static unsigned short palette_red[16];
-static unsigned short palette_green[16];
-static unsigned short palette_blue[16];
+static u16 palette_red[16];
+static u16 palette_green[16];
+static u16 palette_blue[16];
 
 static struct fb_cmap palette_cmap  = {
     0, 16, palette_red, palette_green, palette_blue, NULL
@@ -1062,7 +1038,7 @@
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
     int i, j, k;
-    u_char val;
+    u8 val;
 
     if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked))
 	return(-EINVAL);
@@ -1078,7 +1054,7 @@
     palette_cmap.len = 1<<p->var.bits_per_pixel;
     if (palette_cmap.len > 16)
 	palette_cmap.len = 16;
-    return(p->fb_info->setcmap(&palette_cmap, unit));
+    return p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, unit, p->fb_info);
 }
 
 static int fbcon_scrolldelta(int lines)
@@ -1109,13 +1085,27 @@
     p->var.vmode |= FB_VMODE_YWRAP;
     p->var.xoffset = 0;
     p->var.yoffset = offset*p->fontheight;
-    p->fb_info->updatevar(unit);
+    p->fb_info->updatevar(unit, p->fb_info);
 #else
     return -ENOSYS;
 #endif
 }
 
 
+    /*
+     *  Switch between `text' (emulated and accelerated) and `graphics'
+     *  (unaccelerated text) mode
+     */
+
+static int fbcon_set_mode(struct vc_data *conp, int mode)
+{
+    struct display *p = &fb_display[conp->vc_num];
+    struct fb_ops *ops = p->fb_info->fbops;
+
+    return ops->fb_set_mode ? ops->fb_set_mode(mode, p->fb_info) : 0;
+}
+
+
 #define LOGO_H			80
 #define LOGO_W			80
 #define LOGO_LINE	(LOGO_W/8)
@@ -1166,7 +1156,8 @@
 		palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
 		palette_cmap.blue[j]  = (blue[i+j] << 8) | blue[i+j];
 	    }
-	    p->fb_info->setcmap( &palette_cmap, fg_console );
+	    p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console,
+					   p->fb_info);
 	}
 	fb_display[fg_console].cmap.len = old_cmap_len;
     }
@@ -1184,12 +1175,65 @@
 	logo_depth = 1;
     }
 
-#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CYBER) || \
-    defined(CONFIG_FBCON_RETINAZ3)
-    if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR ||
-			     p->visual == FB_VISUAL_DIRECTCOLOR)) {
+#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
+    defined(CONFIG_FBCON_CFB32)
+    if (p->visual == FB_VISUAL_TRUECOLOR) {
+	unsigned int val;		/* max. depth 32! */
+	int bdepth;
+	int redshift, greenshift, blueshift;
+		
+	/* Bug: Doesn't obey msb_right ... (who needs that?) */
+	redshift   = p->var.red.offset;
+	greenshift = p->var.green.offset;
+	blueshift  = p->var.blue.offset;
+
+	if (depth >= 24 && (depth % 8) == 0) {
+	    /* have at least 8 bits per color */
+	    src = logo;
+	    bdepth = depth/8;
+	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
+		dst = fb + y1*line;
+		for( x1 = 0; x1 < LOGO_W; x1++, src++ ) {
+		val = ((linux_logo_red[*src]   & redmask)   << redshift) |
+		      ((linux_logo_green[*src] & greenmask) << greenshift) |
+		      ((linux_logo_blue[*src]  & bluemask)  << blueshift);
+		    for( i = bdepth-1; i >= 0; --i )
+			*dst++ = val >> (i*8);
+		}
+	    }
+	}
+	else if (depth >= 15 && depth <= 23) {
+	    /* have 5..7 bits per color, using 16 color image */
+	    unsigned int pix;
+	    src = linux_logo16;
+	    bdepth = (depth+7)/8;
+	    for( y1 = 0; y1 < LOGO_H; y1++ ) {
+		dst = fb + y1*line;
+		for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) {
+		    pix = (*src >> 4) | 0x10; /* upper nibble */
+		    val = (pix << redshift) |
+			  (pix << greenshift) |
+			  (pix << blueshift);
+		    for( i = 0; i < bdepth; ++i )
+			*dst++ = val >> (i*8);
+		    pix = (*src & 0x0f) | 0x10; /* lower nibble */
+		    val = (pix << redshift) |
+			  (pix << greenshift) |
+			  (pix << blueshift);
+		    for( i = bdepth-1; i >= 0; --i )
+			*dst++ = val >> (i*8);
+		}
+	    }
+	}
+	
+	done = 1;
+    }
+#endif
+#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || \
+    defined(CONFIG_FBCON_CFB32)
+    if ((depth % 8 == 0) && (p->visual == FB_VISUAL_DIRECTCOLOR)) {
 	/* Modes without color mapping, needs special data transformation... */
-	unsigned long val;		/* max. depth 32! */
+	unsigned int val;		/* max. depth 32! */
 	int bdepth = depth/8;
 	unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
 	unsigned char redmask, greenmask, bluemask;
@@ -1218,8 +1262,7 @@
 	done = 1;
     }
 #endif
-#if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CYBER) || \
-    defined(CONFIG_FBCON_RETINAZ3)
+#if defined(CONFIG_FBCON_CFB8)
     if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) {
 	/* depth 8 or more, packed, with color registers */
 		
@@ -1316,153 +1359,23 @@
     fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
     fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
     fbcon_blank, fbcon_get_font, fbcon_set_font, fbcon_set_palette,
-    fbcon_scrolldelta
+    fbcon_scrolldelta, fbcon_set_mode
 };
 
 
 /*
- *  Driver registration
- */
-
-static struct display_switch *drivers = NULL, *accel_drivers = NULL;
-
-int fbcon_register_driver(struct display_switch *dispsw, int is_accel)
-{
-    struct display_switch **list;
-
-    list = is_accel ? &accel_drivers : &drivers;
-    dispsw->next = *list;
-    *list = dispsw;
-    return 0;
-}
-
-int fbcon_unregister_driver(struct display_switch *dispsw)
-{
-    struct display_switch **list;
-
-    for (list = &accel_drivers; *list; list = &(*list)->next)
-	if (*list == dispsw) {
-	    *list = dispsw->next;
-	    dispsw->next = NULL;
-	    return 0;
-	}
-    for (list = &drivers; *list; list = &(*list)->next)
-	if (*list == dispsw) {
-	    *list = dispsw->next;
-	    dispsw->next = NULL;
-	    return 0;
-	}
-    return -EINVAL;
-}
-
-
-static struct display_switch *probe_list(struct display_switch *dispsw,
-					 struct display *disp)
-{
-    while (dispsw) {
-	if (!dispsw->open(disp))
-	    return(dispsw);
-	dispsw = dispsw->next;
-    }
-    return(NULL);
-}
-
-
-#ifdef CONFIG_KMOD
-static void request_driver(struct display *disp, int is_accel)
-{
-    char modname[30];
-    int len;
-    const char *type;
-
-    if (disp->var.bits_per_pixel == 1)
-	type = "mfb";
-    else
-	switch (disp->type) {
-	    case FB_TYPE_INTERLEAVED_PLANES:
-		if (disp->type_aux == 2)
-		    type = "iplan2p%d";
-		else
-		    type = "ilbm";
-		break;
-	    case FB_TYPE_PLANES:
-		type = "afb";
-		break;
-	    case FB_TYPE_PACKED_PIXELS:
-		type = "cfb%d";
-		break;
-	    default:
-		return;
-	}
-    len = sprintf(modname, "fbcon-");
-    len += sprintf(modname+len, type, disp->var.bits_per_pixel);
-    if (is_accel)
-	len += sprintf(modname+len, "-%d", disp->var.accel);
-    request_module(modname);
-}
-#endif /* CONFIG_KMOD */
-
-
-static struct display_switch *fbcon_get_driver(struct display *disp)
-{
-    struct display_switch *dispsw;
-
-    if (disp->var.accel != FB_ACCEL_NONE) {
-	/* First try an accelerated driver */
-	dispsw = probe_list(accel_drivers, disp);
-#ifdef CONFIG_KMOD
-	if (!dispsw) {
-	    request_driver(disp, 1);
-	    dispsw = probe_list(accel_drivers, disp);
-	}
-#endif
-	if (dispsw)
-	    return(dispsw);
-    }
-
-    /* Then try an unaccelerated driver */
-    dispsw = probe_list(drivers, disp);
-#ifdef CONFIG_KMOD
-    if (!dispsw) {
-	request_driver(disp, 0);
-	dispsw = probe_list(drivers, disp);
-    }
-#endif
-    return(dispsw);
-}
-
-
-/*
  *  Dummy Low Level Operations
  */
 
-static int open_dummy(struct display *p)
-{
-    if (p->line_length)
-	p->next_line = p->line_length;
-    else
-	p->next_line = p->var.xres_virtual>>3;
-    p->next_plane = 0;
-    p->var.bits_per_pixel = 1;
-    return 0;
-}
-
-static void misc_dummy(void) {}
-
-static struct display_switch dispsw_dummy = {
-    open_dummy,
-    /* release_dummy */
-    misc_dummy,
-    /* bmove_dummy */
-    (void (*)(struct display *, int, int, int, int, int, int))misc_dummy,
-    /* clear_dummy */
-    (void (*)(struct vc_data *, struct display *, int, int, int, int))misc_dummy,
-    /* putc_dummy */
-    (void (*)(struct vc_data *, struct display *, int, int, int))misc_dummy,
-    /* putcs_dummy */
-    (void (*)(struct vc_data *, struct display *, const char *, int, int, int))misc_dummy,
-    /* rev_char_dummy */
-    (void (*)(struct display *, int, int))misc_dummy,
+static void fbcon_dummy_op(void) {}
+
+static 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 */
+    (void *)fbcon_dummy_op,	/* fbcon_dummy_putc */
+    (void *)fbcon_dummy_op,	/* fbcon_dummy_putcs */
+    (void *)fbcon_dummy_op,	/* fbcon_dummy_revc */
 };
 
 
@@ -1471,5 +1384,3 @@
  */
 
 EXPORT_SYMBOL(fb_display);
-EXPORT_SYMBOL(fbcon_register_driver);
-EXPORT_SYMBOL(fbcon_unregister_driver);

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