diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/video/psionwfb.c linux-2.4.19-rmk2/drivers/video/psionwfb.c
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/video/psionwfb.c linux-2.4.19-rmk2/drivers/video/psionwfb.c
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/video/psionwfb.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/video/psionwfb.c	2002-10-02 22:07:30.000000000 -0700
@@ -0,0 +1,942 @@
+/*
+ *  linux/drivers/video/psionwfb.c
+ *  
+ *  Copyright (C) 2001 Shane Nay <shane@place.org>
+ *  Copyright (C) 2001 Tony Lindgren <tony@atomide.com>
+ * 
+ *  Based on the EP7212 driver, some portions of code  
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/ioport.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/hardware/psionw.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/psionw-power.h>
+
+#include "psionwfb.h"
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int
+psionwfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		   u_int transp, struct fb_info *info)
+{
+	unsigned int level, val, previous;
+	int bpp = info->var.bits_per_pixel;
+
+	/* 
+	 * These are the colormaps Epoc uses. By default Linux
+	 * produces white on black text. Inverting everything
+	 * would invert the graphics too, AFAIK. So we our own
+	 * text-only inversion by overriding the key text output
+	 * functions. Maybe there is some way of doing all this
+	 * already in the fb support? Let me know if there's an
+	 * easier way to do this.
+	 */
+	int pal_1bpp[] = { 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+	};
+
+	int pal_2bpp[] = { 0xf, 0xa, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0,
+		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+	};
+
+	int pal_4bpp[] = { 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7,
+		0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0
+	};
+
+	if (regno >= CMAP_SIZE)
+		return 1;
+
+	/*
+	 * FIXME5MX: The graylevel calculation does not quite 
+	 * produce the right colors. Deal with this later.
+	 */
+
+	/* gray = 0.30*R + 0.58*G + 0.11*B */
+	//level = (red * 77 + green * 151 + blue * 28) >> 20;
+
+	/* 
+	 * We need to invert the colors to produce Epoc like
+	 * colormap. Otherwise the logo colors get inverted.
+	 */
+	level = (15 - level);
+
+	switch (bpp) {
+	case 1:
+		/* Just use a fixed map */
+		val = pal_1bpp[regno];
+		break;
+	case 2:
+		/* Just use a fixed map */
+		val = pal_2bpp[regno];
+		break;
+	default:
+		/* Use the calculated level */
+		//val = level;
+		/* Use a fixed map */
+		val = pal_4bpp[regno];
+	}
+
+	// The first entry in the palette contains the bpp value
+	if (regno == 0) {
+		val |= ((bpp >> 1) << 12);
+	}
+	// The LCD controller registers are 16-bit wide
+	if (regno & 0x1) {
+		previous = *(volatile uint *) (LCD_PAL_START + (regno - 1) * 2);
+		val = (val << 16);
+		val = val | previous;
+		*(volatile uint *) (LCD_PAL_START + (regno - 1) * 2) = val;
+	} else {
+		*(volatile uint *) (LCD_PAL_START + regno * 2) = val;
+	}
+
+#ifdef DEBUG
+	if (regno == 0xf) {
+		/* Dump the color palette to serial terminal */
+		dump_pal();
+	}
+#endif
+
+	return 0;
+}
+
+/*
+ * Set the colormap
+ */
+static int
+psionwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	struct psionwfb_info *cfb = (struct psionwfb_info *) info;
+	struct fb_cmap *dcmap = &fb_display[con].cmap;
+	int err = 0;
+
+	/* no colormap allocated? */
+
+	if (!dcmap->len)
+		err = fb_alloc_cmap(dcmap, CMAP_SIZE, 0);
+
+	if (!err && con == cfb->currcon) {
+		err = fb_set_cmap(cmap, kspc, psionwfb_setcolreg, &cfb->fb);
+		dcmap = &cfb->fb.cmap;
+	}
+
+	if (!err)
+		fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
+
+	return err;
+}
+
+/*
+ *    Set the User Defined Part of the Display
+ */
+static int
+psionwfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct display *display;
+	int chgvar = 0;
+	int syscon = 0, lcdcon = 0;
+
+	if (var->activate & FB_ACTIVATE_TEST)
+		return 0;
+
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+		return -EINVAL;
+
+	if (cfb->fb.var.xres != var->xres)
+		chgvar = 1;
+	if (cfb->fb.var.yres != var->yres)
+		chgvar = 1;
+	if (cfb->fb.var.xres_virtual != var->xres_virtual)
+		chgvar = 1;
+	if (cfb->fb.var.yres_virtual != var->yres_virtual)
+		chgvar = 1;
+	if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
+		chgvar = 1;
+
+	if (con < 0) {
+		display = cfb->fb.disp;
+		chgvar = 0;
+	} else {
+		display = fb_display + con;
+	}
+
+	var->transp.msb_right = 0;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->red.msb_right = 0;
+	var->red.offset = 0;
+	var->red.length = var->bits_per_pixel;
+	var->green = var->red;
+	var->blue = var->red;
+
+	switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_MFB
+	case 1:
+		cfb->fb.fix.visual = FB_VISUAL_MONO01;
+		display->dispsw = &fbcon_mfb_psionw;	/* We override */
+		display->dispsw_data = NULL;
+		display->inverse = 0;	/* We do our own text-only inversion */
+		break;
+#endif
+#ifdef FBCON_HAS_CFB2
+	case 2:
+		cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		display->dispsw = &fbcon_cfb2_psionw;	/* We override */
+		display->dispsw_data = NULL;
+		display->inverse = 0;	/* We do our own text-only inversion */
+		break;
+#endif
+#ifdef FBCON_HAS_CFB4
+	case 4:
+		cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		display->dispsw = &fbcon_cfb4_psionw;	/* We override */
+		display->dispsw_data = NULL;
+		display->inverse = 0;	/* We do our own text-only inversion */
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	display->screen_base = cfb->fb.screen_base;
+	display->line_length = var->xres * var->bits_per_pixel / 8;
+	display->next_line = display->line_length;
+	cfb->fb.fix.line_length = display->line_length;
+
+	display->visual = cfb->fb.fix.visual;
+	display->type = cfb->fb.fix.type;
+	display->type_aux = cfb->fb.fix.type_aux;
+	display->ypanstep = cfb->fb.fix.ypanstep;
+	display->ywrapstep = cfb->fb.fix.ywrapstep;
+	display->can_soft_blank = 1;
+	display->inverse = 0;
+
+	cfb->fb.var = *var;
+	cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
+
+	/*
+	 * Update the old var.  The fbcon drivers still use this.
+	 * Once they are using cfb->fb.var, this can be dropped.
+	 *                                      --rmk
+	 */
+	display->var = cfb->fb.var;
+
+	/*
+	 * If we are setting all the virtual consoles, also set the
+	 * defaults used to create new consoles.
+	 */
+	if (var->activate & FB_ACTIVATE_ALL)
+		cfb->fb.disp->var = cfb->fb.var;
+
+	if (chgvar && info && cfb->fb.changevar)
+		cfb->fb.changevar(con);
+
+	psionwfb_set_timings(var->xres, var->yres, var->pixclock);
+
+	fb_set_cmap(&cfb->fb.cmap, 1, psionwfb_setcolreg, &cfb->fb);
+
+	return 0;
+}
+
+/*
+ * Get the currently displayed virtual consoles colormap.
+ */
+static int
+gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);
+	return 0;
+}
+
+/*
+ * Get the currently displayed virtual consoles fixed part of the display.
+ */
+static int
+gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	*fix = info->fix;
+	return 0;
+}
+
+/*
+ * Get the current user defined part of the display.
+ */
+static int
+gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	*var = info->var;
+	return 0;
+}
+
+static struct fb_ops psionwfb_ops = {
+	owner:THIS_MODULE,
+	fb_set_var:psionwfb_set_var,
+	fb_set_cmap:psionwfb_set_cmap,
+	fb_get_fix:gen_get_fix,
+	fb_get_var:gen_get_var,
+	fb_get_cmap:gen_get_cmap,
+};
+
+static int
+psionwfb_switch(int con, struct fb_info *info)
+{
+	struct psionwfb_info *cfb = (struct psionwfb_info *) info;
+	struct display *disp;
+	struct fb_cmap *cmap;
+
+	if (cfb->currcon >= 0) {
+		disp = fb_display + cfb->currcon;
+
+		/*
+		 * Save the old colormap and video mode.
+		 */
+
+		disp->var = cfb->fb.var;
+		if (disp->cmap.len)
+			fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);
+	}
+
+	cfb->currcon = con;
+	disp = fb_display + con;
+
+	/*
+	 * Install the new colormap and change the video mode.  By default,
+	 * fbcon sets all the colormaps and video modes to the default
+	 * values at bootup.
+	 */
+
+	if (disp->cmap.len)
+		cmap = &disp->cmap;
+	else
+		cmap = fb_default_cmap(CMAP_SIZE);
+
+	fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
+
+	cfb->fb.var = disp->var;
+	cfb->fb.var.activate = FB_ACTIVATE_NOW;
+
+	psionwfb_set_var(&cfb->fb.var, con, &cfb->fb);
+
+	return 0;
+}
+
+static int
+psionwfb_updatevar(int con, struct fb_info *info)
+{
+	return -EINVAL;
+}
+
+static void
+psionwfb_blank(int blank, struct fb_info *info)
+{
+	if (blank) {
+		psionw_lcd_powerdown(1);
+	} else {
+		psionw_lcd_powerup(1);
+	}
+}
+
+static inline int get_pcd(unsigned int pixclock)
+{
+	unsigned int pcd;
+	if (pixclock) {
+		pcd = psionw_get_cpu_speed(0) / 100;
+		pcd *= pixclock;
+		pcd /= 10000000;
+		pcd += 1;	/* make up for integer math truncations */		
+	} else {
+		printk(KERN_WARNING "Zero pixclock detected\n");
+	}
+	return pcd;
+}
+
+/*
+ * LCD Interrupt handler
+ */
+static void
+psionwfb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned int lcderr;
+
+	//printk("LCD interrupt\n");
+
+	lcderr = psionw_readl(LCDCTL);
+	lcderr &= ~LCDCTL_DONE;	// Clear bit 3, done mask
+	lcderr &= ~LCDCTL_NEXT;	// Clear bit 4, next mask
+	lcderr &= ~LCDCTL_ERR;	// Clear bit 5, error mask
+	psionw_writel(lcderr, LCDCTL);
+	lcderr = psionw_readl(LCDST);
+	lcderr |= LCDST_NEXT;	// Set next frame
+	lcderr &= ~LCDST_BER;	// Clear bus error
+	lcderr &= ~LCDST_ABC;	// Clear AC bias
+	lcderr &= ~LCDST_FUF;	// Clear FIFO underflow
+	psionw_writel(lcderr, LCDST);
+}
+
+
+int __init
+psionwfb_init(void)
+{
+	int err = -ENOMEM, ret = 0;
+
+	cfb = kmalloc(sizeof (*cfb) + sizeof (struct display), GFP_KERNEL);
+	if (!cfb)
+		goto out;
+
+	memset(cfb, 0, sizeof (*cfb) + sizeof (struct display));
+
+	/* 
+	 * See also arm/arch/mm/init.c to poke a hole to the bootmem.
+	 * This request_mem_region call does not add the data 
+	 * currently to the /proc/iomem, but it may later on.
+	 */
+	//request_mem_region(LCD_MEM_START, LCD_MEM_SIZE, "psionwfb");
+	request_region(LCD_MEM_START, LCD_MEM_SIZE, "psionwfb");
+
+	memset((void *) LCD_PAL_START, 0, LCD_PAL_SIZE);
+	memset((void *) LCD_BUF_START, 0, LCD_BUF_SIZE);
+
+	cfb->fb.screen_base = (void *) (LCD_BUF_START);
+	cfb->fb.fix.smem_start = LCD_BUF_START;
+	printk("Using LCD memory address 0x%x\n", cfb->fb.screen_base);
+
+	cfb->currcon = -1;
+	strcpy(cfb->fb.fix.id, "psionw");
+	cfb->fb.fix.smem_len = LCD_BUF_SIZE;
+
+	cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+	cfb->fb.fix.type_aux = 0;
+	cfb->fb.fix.xpanstep = 0;
+	cfb->fb.fix.ypanstep = 0;
+	cfb->fb.fix.ywrapstep = 0;
+	cfb->fb.fix.accel = FB_ACCEL_NONE;
+
+	cfb->fb.var.nonstd = 0;
+	cfb->fb.var.activate = FB_ACTIVATE_NOW;
+	cfb->fb.var.height = -1;
+	cfb->fb.var.width = -1;
+	cfb->fb.var.accel_flags = 0;
+	cfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
+
+	cfb->fb.var.xres = PSION_LCD_W;
+	cfb->fb.var.xres_virtual = PSION_LCD_W;
+	cfb->fb.var.yres = PSION_LCD_H;
+	cfb->fb.var.yres_virtual = PSION_LCD_H;
+	cfb->fb.var.bits_per_pixel = 4;
+	cfb->fb.var.pixclock = 288;
+	cfb->fb.var.grayscale = 1;
+
+	cfb->fb.fbops = &psionwfb_ops;
+	cfb->fb.changevar = NULL;
+	cfb->fb.switch_con = psionwfb_switch;
+	cfb->fb.updatevar = psionwfb_updatevar;
+	cfb->fb.blank = psionwfb_blank;
+	cfb->fb.flags = FBINFO_FLAG_DEFAULT;
+	cfb->fb.disp = (struct display *) (cfb + 1);
+	cfb->fb.pseudo_palette = (void *) (cfb->fb.disp + 1);
+
+	fb_alloc_cmap(&cfb->fb.cmap, CMAP_SIZE, 0);
+
+	/*
+	 * Power up the LCD
+	 */
+	psionw_lcd_disable();
+	psionw_lcd_init_hw();
+	psionw_lcd_enable();
+
+	ret = request_irq(IRQ_LCDINT, psionwfb_handle_irq, SA_INTERRUPT, "psionwfb", NULL);
+
+	if (ret) {
+		printk(KERN_ERR "psionwfb: request_irq failed: %d\n", ret);
+	}
+
+	psionwfb_set_var(&cfb->fb.var, -1, &cfb->fb);
+	err = register_framebuffer(&cfb->fb);
+
+      out:return err;
+}
+
+static void __exit
+psionwfb_exit(void)
+{
+	unregister_framebuffer(&cfb->fb);
+	kfree(cfb);
+
+	/*
+	 * Power down the LCD
+	 */
+}
+
+void
+psionw_lcd_disable()
+{
+	int lcdstate;
+
+	/* 
+	 * DC to DC converted may not be enabled, and clearing
+	 * PDDR_LCD_PWR without DC to DC converted causes the
+	 * screen not to come up on 5mx Pro.
+	 */
+	start_pump(1);
+
+	psionw_writeb(psionw_readb(PDDR) & ~PDDR_LCD_PWR, PDDR);
+
+	lcdstate = psionw_readl(LCDCTL);
+	lcdstate &= ~LCDCTL_EN;
+	psionw_writel(lcdstate, LCDCTL);
+}
+
+void
+psionw_lcd_enable()
+{
+	int lcdstate;
+
+	lcdstate = psionw_readl(LCDCTL);
+	lcdstate |= LCDCTL_BW;
+	lcdstate |= LCDCTL_EN;
+	psionw_writel(lcdstate, LCDCTL);
+
+	mdelay(30);
+
+	psionw_writeb(psionw_readb(PDDR) | PDDR_LCD_PWR, PDDR);
+}
+
+void
+psionwfb_set_timings(int xres, int yres, int pixclock)
+{
+	int lcdt0 = 0, lcdt1 = 0, lcdt2 = 0;
+
+	/* LCD horizontal timing */
+	lcdt0 |= PSION_HSW | PSION_HFP | PSION_HBP;
+	lcdt0 |= (xres - 16);
+	psionw_writel(lcdt0, LCDT0);
+
+	/* LCD vertical timing */
+	lcdt1 |= PSION_VSW | PSION_VFP | PSION_VBP;
+	lcdt1 |= (yres - 1);
+	psionw_writel(lcdt1, LCDT1);
+
+	/* Pixel clock and AC-bias frequency */
+	lcdt2 = psionw_readl(LCDT2);
+	lcdt2 &= ~0xff;
+	lcdt2 |= get_pcd(pixclock);
+	lcdt2 |= PSION_ACB;
+	psionw_writel(lcdt2, LCDT2);
+}
+
+void
+psionw_lcd_init_hw(void)
+{
+	int lcdstate;
+
+	/* Start DC to DC converter if not started */
+	start_pump(1);
+	
+	/* Set the default contrast */
+	psionw_writeb(psionw_readb(PBDR) | LCD_DEF_CMASK, PBDR);
+	
+	/* Write the current address to the LCD controller */
+	psionw_writel(LCD_MEM_START, LCD_DBAR1);
+}
+
+void
+psionw_lcd_powerdown(int lock)
+{
+	/* Turn off the LCD backlight. */
+	psionw_writeb(psionw_readb(PCDR) & ~PCDR_LIGHT, PCDR);
+
+	/* Turn off the LCD power */
+	psionw_writeb(psionw_readb(PDDR) & ~PDDR_LCD_PWR, PDDR);
+
+	/* Power down the LCD controller */
+	psionw_writel(psionw_readl(LCDCTL) & ~LCDCTL_EN, LCDCTL);
+}
+
+void
+psionw_lcd_powerup(int lock)
+{
+	psionw_lcd_disable();
+	psionw_lcd_init_hw();
+	psionw_lcd_enable();
+}
+
+#ifdef FBCON_HAS_MFB
+/*
+ * We need to override some fbcon_mbf functions to
+ * keep text colors black on white instead of white on black.
+ */
+struct display_switch fbcon_mfb_psionw = {
+	setup:fbcon_mfb_setup,
+	bmove:fbcon_mfb_bmove,
+	clear:fbcon_mfb_clear_psionw,
+	putc:fbcon_mfb_putc_psionw,
+	putcs:fbcon_mfb_putcs_psionw,
+	revc:fbcon_mfb_revc,
+	clear_margins:fbcon_mfb_clear_margins,
+	fontwidthmask:FONTWIDTH(8)
+};
+
+void
+fbcon_mfb_clear_psionw(struct vc_data *conp, struct display *p,
+		       int sy, int sx, int height, int width)
+{
+	u8 *dest;
+	u_int rows;
+	int inverse = conp ? attr_reverse(p, conp->vc_video_erase_char) : 0;
+
+	dest = p->screen_base + sy * fontheight(p) * p->next_line + sx;
+
+	if (sx == 0 && width == p->next_line) {
+		if (inverse)
+			fb_memclear(dest, height * fontheight(p) * width);
+		else
+			fb_memset255(dest, height * fontheight(p) * width);
+	} else
+		for (rows = height * fontheight(p); rows--;
+		     dest += p->next_line)
+			if (inverse)
+				fb_memclear_small(dest, width);
+			else
+				fb_memset255(dest, width);
+}
+
+void
+fbcon_mfb_putc_psionw(struct vc_data *conp, struct display *p,
+		      int c, int yy, int xx)
+{
+	u8 *dest, *cdat;
+	u_int rows, bold, revs, underl;
+	u8 d;
+
+	dest = p->screen_base + yy * fontheight(p) * p->next_line + xx;
+	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+	bold = attr_bold(p, c);
+	revs = attr_reverse(p, c);
+	underl = attr_underline(p, c);
+
+	for (rows = fontheight(p); rows--; dest += p->next_line) {
+		d = *cdat++;
+		if (underl && !rows)
+			d = 0xff;
+		else if (bold)
+			d |= d >> 1;
+		if (!revs)
+			d = ~d;
+		fb_writeb(d, dest);
+	}
+}
+
+/* Modified to reverse the bits for Psion */
+void
+fbcon_mfb_putcs_psionw(struct vc_data *conp, struct display *p,
+		       const unsigned short *s, int count, int yy, int xx)
+{
+	u8 *dest, *dest0, *cdat;
+	u_int rows, bold, revs, underl;
+	u8 d;
+	u16 c;
+
+	dest0 = p->screen_base + yy * fontheight(p) * p->next_line + xx;
+	c = scr_readw(s);
+	bold = attr_bold(p, c);
+	revs = attr_reverse(p, c);
+	underl = attr_underline(p, c);
+
+	while (count--) {
+		c = scr_readw(s++) & p->charmask;
+		dest = dest0++;
+		cdat = p->fontdata + c * fontheight(p);
+		for (rows = fontheight(p); rows--; dest += p->next_line) {
+			d = *cdat++;
+
+			// Must reverse the bits for Psion
+			d = bi_reverse(d, 8);
+
+			if (underl && !rows)
+				d = 0xff;
+			else if (bold)
+				d |= d >> 1;
+
+			if (!revs)
+				d = ~d;
+			fb_writeb(d, dest);
+		}
+	}
+}
+#endif				/* FBCON_HAS_MFB */
+
+#ifdef FBCON_HAS_CFB2
+/*
+ * We need to override some fbcon_cfb4 functions to
+ * keep text colors black on white instead of white on black.
+ */
+struct display_switch fbcon_cfb2_psionw = {
+	setup:fbcon_cfb2_setup,
+	bmove:fbcon_cfb2_bmove,
+	clear:fbcon_cfb2_clear_psionw,
+	putc:fbcon_cfb2_putc_psionw,
+	putcs:fbcon_cfb2_putcs_psionw,
+	revc:fbcon_cfb2_revc,
+	fontwidthmask:FONTWIDTH(8)
+};
+
+void
+fbcon_cfb2_clear_psionw(struct vc_data *conp, struct display *p, int sy, int sx,
+			int height, int width)
+{
+	u8 *dest0, *dest;
+	int bytes = p->next_line, lines = height * fontheight(p), rows, i;
+	u32 bgx;
+
+	dest = p->screen_base + sy * fontheight(p) * bytes + sx * 2;
+
+	bgx = attr_bgcol_ec(p, conp);
+	bgx |= (bgx << 2);	/* expand the colour to 16 bits */
+	bgx |= (bgx << 4);
+	bgx |= (bgx << 8);
+
+	if (sx == 0 && width * 2 == bytes) {
+		for (i = 0; i < lines * width; i++) {
+			fb_writew(bgx ^ 0xffff, dest);
+			dest += 2;
+		}
+	} else {
+		dest0 = dest;
+		for (rows = lines; rows--; dest0 += bytes) {
+			dest = dest0;
+			for (i = 0; i < width; i++) {
+				/* memset ?? */
+				fb_writew(bgx ^ 0xffff, dest);
+				dest += 2;
+			}
+		}
+	}
+}
+
+void
+fbcon_cfb2_putc_psionw(struct vc_data *conp, struct display *p, int c, int yy,
+		       int xx)
+{
+	u8 *dest, *cdat;
+	int bytes = p->next_line, rows;
+	u32 eorx, fgx, bgx;
+
+	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 2;
+	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+
+	fgx = 3;		/*attr_fgcol(p,c); */
+	bgx = attr_bgcol(p, c);
+	fgx |= (fgx << 2);	/* expand color to 8 bits */
+	fgx |= (fgx << 4);
+	bgx |= (bgx << 2);
+	bgx |= (bgx << 4);
+	eorx = fgx ^ bgx;
+
+	for (rows = fontheight(p); rows--; dest += bytes) {
+		fb_writeb(((nibbletab_cfb2_psionw[*cdat >> 4] & eorx) ^ bgx) ^
+			  0xff, dest + 0);
+		fb_writeb(((nibbletab_cfb2_psionw[*cdat++ & 0xf] & eorx) ^ bgx)
+			  ^ 0xff, dest + 1);
+	}
+}
+
+/* Modify the inverse functionality for Psion */
+void
+fbcon_cfb2_putcs_psionw(struct vc_data *conp, struct display *p,
+			const unsigned short *s, int count, int yy, int xx)
+{
+	u8 *cdat, *dest, *dest0;
+	u16 c;
+	int rows, bytes = p->next_line;
+	u32 eorx, fgx, bgx;
+
+	dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 2;
+	c = scr_readw(s);
+
+	/*
+	 * This part is commented out in the original fbcon_cfb2_putcs.
+	 * NOTE: Some inversion does not work, like typing a wrong 
+	 * character in top.
+	 */
+	fgx = attr_fgcol(p, c);
+
+	bgx = attr_bgcol(p, c);
+	fgx |= (fgx << 2);
+	fgx |= (fgx << 4);
+	bgx |= (bgx << 2);
+	bgx |= (bgx << 4);
+	eorx = fgx ^ bgx;
+	while (count--) {
+		c = scr_readw(s++) & p->charmask;
+		cdat = p->fontdata + c * fontheight(p);
+
+		for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
+			fb_writeb(((nibbletab_cfb2_psionw[*cdat >> 4] & eorx) ^
+				   bgx) ^ 0xff, dest + 0);
+			fb_writeb(((nibbletab_cfb2_psionw[*cdat++ & 0xf] & eorx)
+				   ^ bgx) ^ 0xff, dest + 1);
+		}
+		dest0 += 2;
+	}
+}
+#endif				/* FBCON_HAS_CFB2 */
+
+#ifdef FBCON_HAS_CFB4
+/*
+ * We need to override some fbcon_cfb4 functions to
+ * keep text colors black on white instead of white on black.
+ */
+struct display_switch fbcon_cfb4_psionw = {
+	setup:fbcon_cfb4_setup,
+	bmove:fbcon_cfb4_bmove,
+	clear:fbcon_cfb4_clear_psionw,
+	putc:fbcon_cfb4_putc_psionw,
+	putcs:fbcon_cfb4_putcs_psionw,
+	revc:fbcon_cfb4_revc,
+	fontwidthmask:FONTWIDTH(8)
+};
+
+/*
+ * Slightly modified from the fbcon_cfb4_clear. We need to reverse 
+ * the background color to keep the text background white.
+ */
+void
+fbcon_cfb4_clear_psionw(struct vc_data *conp, struct display *p, int sy, int sx,
+			int height, int width)
+{
+	u8 *dest0, *dest;
+	int bytes = p->next_line, lines = height * fontheight(p), rows, i;
+	u32 bgx;
+
+	dest = p->screen_base + sy * fontheight(p) * bytes + sx * 4;
+
+	bgx = attr_bgcol_ec(p, conp);
+	bgx |= (bgx << 4);	/* expand the colour to 32bits */
+	bgx |= (bgx << 8);
+	bgx |= (bgx << 16);
+
+	if (sx == 0 && width * 4 == bytes) {
+		for (i = 0; i < lines * width; i++) {
+			fb_writel(bgx ^ 0xffffffff, dest);
+			dest += 4;
+		}
+	} else {
+		dest0 = dest;
+		for (rows = lines; rows--; dest0 += bytes) {
+			dest = dest0;
+			for (i = 0; i < width; i++) {
+				/* memset ?? */
+				fb_writel(bgx ^ 0xffffffff, dest);
+				dest += 4;
+			}
+		}
+	}
+}
+
+/*
+ * Slightly modified from the fbcon_cfb4_putc. We want to keep the 
+ * character color as black on white instead of white on black.
+ */
+void
+fbcon_cfb4_putc_psionw(struct vc_data *conp, struct display *p, int c, int yy,
+		       int xx)
+{
+	u8 *dest, *cdat;
+	int bytes = p->next_line, rows;
+	u32 eorx, fgx, bgx;
+
+	dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
+	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
+
+	fgx = attr_fgcol(p, c);
+	bgx = attr_bgcol(p, c);
+	fgx |= (fgx << 4);
+	fgx |= (fgx << 8);
+	bgx |= (bgx << 4);
+	bgx |= (bgx << 8);
+	eorx = fgx ^ bgx;
+
+	for (rows = fontheight(p); rows--; dest += bytes) {
+		fb_writew(((nibbletab_cfb4_psionw[*cdat >> 4] & eorx) ^ bgx) ^
+			  0xff, dest + 0);
+		fb_writew(((nibbletab_cfb4_psionw[*cdat++ & 0xf] & eorx) ^ bgx)
+			  ^ 0xff, dest + 2);
+	}
+}
+
+/*
+ * Slightly modified from the fbcon_cfb4_putcs. We want to keep the 
+ * string color as black on white instead of white on black.
+ */
+void
+fbcon_cfb4_putcs_psionw(struct vc_data *conp, struct display *p,
+			const unsigned short *s, int count, int yy, int xx)
+{
+	u8 *cdat, *dest, *dest0;
+	u16 c;
+	int rows, bytes = p->next_line;
+	u32 eorx, fgx, bgx;
+
+	dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
+	c = scr_readw(s);
+	fgx = attr_fgcol(p, c);
+	bgx = attr_bgcol(p, c);
+	fgx |= (fgx << 4);
+	fgx |= (fgx << 8);
+	fgx |= (fgx << 16);
+	bgx |= (bgx << 4);
+	bgx |= (bgx << 8);
+	bgx |= (bgx << 16);
+
+	eorx = fgx ^ bgx;
+	while (count--) {
+		c = scr_readw(s++) & p->charmask;
+		cdat = p->fontdata + c * fontheight(p);
+
+		for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
+			fb_writew(((nibbletab_cfb4_psionw[*cdat >> 4] & eorx) ^
+				   bgx) ^ 0xffffffff, dest + 0);
+			fb_writew(((nibbletab_cfb4_psionw[*cdat++ & 0xf] & eorx)
+				   ^ bgx) ^ 0xffffffff, dest + 2);
+		}
+		dest0 += 4;
+	}
+}
+#endif				/* FBCON_HAS_CFB4 */
+
+#ifdef MODULE
+module_init(psionwfb_init);
+#endif
+module_exit(psionwfb_exit);
