Psion patch for linux/drivers/ files

This patch contains updates to the following files:
./drivers/char/Config.in
./drivers/char/Makefile
./drivers/char/keyboard_psion.c
./drivers/char/keyboard_psion.h
./drivers/char/keymap_psion.map
./drivers/char/psionw-rtc.c
./drivers/char/psionw_procfs.c


diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/Config.in linux-2.4.19-rmk2/drivers/char/Config.in
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/Config.in linux-2.4.19-rmk2/drivers/char/Config.in
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/Config.in	2002-10-02 22:05:14.000000000 -0700
+++ linux-2.4.19-rmk2/drivers/char/Config.in	2002-10-06 15:09:08.000000000 -0700
@@ -118,6 +118,18 @@
    tristate 'Anakin touchscreen support' CONFIG_TOUCHSCREEN_ANAKIN
 fi
 
+if [ "$CONFIG_ARCH_PSIONW" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Psion Windermere Keyboard Locale'
+   choice 'Psion-Windermere Keyboard Locale'   \
+        "Psion-UK-Keyboard CONFIG_PSION_KBD_UK \
+         Psion-US-Keyboard CONFIG_PSION_KBD_US \
+         Psion-DE-Keyboard CONFIG_PSION_KBD_DE \
+         Psion-FR-Keyboard CONFIG_PSION_KBD_FR" CONFIG_PSION_KBD_UK
+   endmenu
+   bool '/proc/psionw support' CONFIG_PROCFS_PSION
+fi
+
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
    int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
@@ -238,6 +250,9 @@
 if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
    tristate 'SA1100 Real Time Clock' CONFIG_SA1100_RTC
 fi
+if [ "$CONFIG_ARCH_PSIONW" = "y" ]; then
+   tristate 'Psion Windermere Real Time Clock' CONFIG_PSIONW_RTC
+fi
 
 tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
 tristate 'Siemens R3964 line discipline' CONFIG_R3964
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/Makefile linux-2.4.19-rmk2/drivers/char/Makefile
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/Makefile linux-2.4.19-rmk2/drivers/char/Makefile
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/Makefile	2002-10-02 22:05:14.000000000 -0700
+++ linux-2.4.19-rmk2/drivers/char/Makefile	2002-10-06 15:11:25.000000000 -0700
@@ -229,6 +229,7 @@
 obj-$(CONFIG_RTC) += rtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o
+obj-$(CONFIG_PSIONW_RTC) += psionw-rtc.o
 ifeq ($(CONFIG_PPC),)
   obj-$(CONFIG_NVRAM) += nvram.o
 endif
@@ -303,6 +304,31 @@
 obj-y		+= ../acorn/char/acorn-char.o
 endif
 
+ifeq ($(CONFIG_ARCH_PSIONW),y)
+  KEYBD    =keyboard_psion.o
+  CONSOLE  =console.o
+  obj-y += keyboard_psion.o
+  ifeq ($(CONFIG_PSION_KBD_UK),y)
+    KEYMAP =keymap_psion.o
+    obj-y += keymap_psion.o
+  endif
+  ifeq ($(CONFIG_PSION_KBD_US),y)
+    KEYMAP =keymap_psion_us.o
+    obj-y += keymap_psion_us.o
+  endif
+  ifeq ($(CONFIG_PSION_KBD_DE),y)
+    KEYMAP =keymap_psion_de.o
+    obj-y += keymap_psion_de.o
+  endif
+  ifeq ($(CONFIG_PSION_KBD_FR),y)
+    KEYMAP =keymap_psion_fr.o
+    obj-y += keymap_psion_fr.o
+  endif
+  ifeq ($(CONFIG_PROCFS_PSION),y)
+   obj-y += psionw_procfs.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 fastdep:
@@ -322,3 +348,16 @@
 
 qtronixmap.c: qtronixmap.map
 	set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+
+keymap_psion.c: keymap_psion.map
+	set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+
+keymap_psion_us.c: keymap_psion_us.map
+	set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+
+keymap_psion_de.c: keymap_psion_de.map
+	set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+
+keymap_psion_fr.c: keymap_psion_fr.map
+	set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keyboard_psion.c linux-2.4.19-rmk2/drivers/char/keyboard_psion.c
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keyboard_psion.c linux-2.4.19-rmk2/drivers/char/keyboard_psion.c
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keyboard_psion.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/char/keyboard_psion.c	2002-10-02 22:07:30.000000000 -0700
@@ -0,0 +1,337 @@
+/*
+ * arch/arm/drivers/char/keyboard_psion.c - Keyboard Driver for Psion
+ *
+ * Copyright (C) 1998 Roger Gammans
+ * Copyright (C) 2001 Tony Lindgren <tony@atomide.com>
+ *
+ * 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/config.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/arch/keyboard.h>
+#include <linux/tqueue.h>
+#include <linux/kbd_ll.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/hardware/psionw.h>
+#include "keyboard_psion.h"
+
+/* callback function for auto sleep */
+void (*psion_sleep_set_callback)(void);
+
+extern void psionw_lcd_powerdown(int lock);
+extern void psionw_lcd_powerup(int lock);
+
+unsigned int kbd_delay[] = KB_DELAY;
+static int keysdown = 0;
+static struct tq_struct kbdhw_task;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char kbdpsion_sysrq_xlate[] =
+    "\000" "6"	  "5"	 "4"	"3"    "2"    "1"    "\000"
+    "\000" "'"	  "\000" "0"	"9"    "8"    "7"    "\000"
+    "\000" "y"	  "t"	 "r"	"e"    "w"    "q"    "\000"
+    "\000" "\012" "l"	 "p"	"o"    "i"    "u"    "\000"
+    "\000" "g"	  "f"	 "d"	"s"    "a"    "\011" "\000"
+    "\000" "\000" "."	 "m"	"k"    "j"    "h"    "\000"
+    "\000" "n"	  "b"	 "v"	"c"    "x"    "z"    "\000"
+    "\000" "\000" "\000" ","	"\000" " "    "\000";
+#endif
+
+void psion_cleartable(void) 
+{
+	int key;
+	unsigned int t;
+
+	for (key = 0; key < NR_KEYCODES; key++) {
+		if (!kbdstate[key].in)
+			continue;
+
+		/*
+		 * dont worry these ops are commutative and
+		 * assoicative 
+		 */
+		t = (jiffies - kbdstate[key].jif) & KB_JIFMASK; 
+		if (t>KB_DEB_JIFFY) {
+
+			/* Keboard could have changed meanwhile */
+			kbdstate[key].in = 0;
+			keysdown--;
+			/* printk("Releasing key:%x\n",key); */
+			handle_scancode(key, 0);
+		}
+	}
+}
+
+static void kbd_press(int keycode)
+{
+	unsigned char newpress = 0;
+
+	if (!kbdstate[keycode].in) {
+		keysdown++; 
+		newpress = 1;
+		/* printk("Keycode: %d (0x%x)\n", keycode, keycode); */
+	}
+
+	/*
+	 * We approximate a retriggable monostable
+	 * action.
+	 */
+	kbdstate[keycode].in=1;
+
+	/* We only need to ensure keysdown consistent */
+	kbdstate[keycode].jif = jiffies & KB_JIFMASK;
+	if (newpress) {
+		handle_scancode(keycode, 1);
+		if (psion_sleep_set_callback != 0)
+			(*psion_sleep_set_callback)();
+	}
+}
+
+static void psion_tick(void* dummy)
+{
+	int col,row;
+	int rowd;
+	int count=0;
+	unsigned char state;
+
+	/*
+	 * Check if any keys are depressed
+	 */
+	for (col = 0; col < 8; col++) {
+		udelay(kbd_delay[8]);
+		state =	 psionw_readl(KSCAN);
+		state &= ~KBDSCAN;
+		state |= (KBSC_COL0 + col);
+		psionw_writel(state, KSCAN);
+		udelay(kbd_delay[col]);
+		rowd = psionw_readl(PADR) & 0xff;
+		if (!rowd)
+			continue;
+		for (row=0; row < KB_LASTROW; row++) {
+			if (rowd & KB_ROWMASK(row)) {
+				kbd_press(KEYCODE(row,col));
+				count++;
+			}
+		}
+	};
+ 
+	if (count != keysdown) {
+		psion_cleartable();
+	}
+
+	/*
+	 * Re-queue ourselves
+	 */
+	queue_task(&kbdhw_task,&tq_timer);
+}
+
+void kbdpsion_hw_init(void)
+{ 
+	kbdhw_task.routine = psion_tick;
+	kbdhw_task.sync = 0;
+	queue_task(&kbdhw_task,&tq_timer);
+}
+
+int kbdpsion_translate(unsigned char scancode, unsigned char *keycode_p)
+{
+	*keycode_p = scancode & ~(KBDOWN | KBUP);
+	return 1;
+}
+
+#if defined(CONFIG_VT) && defined(CONFIG_MAGIC_SYSRQ)
+extern int sysrq_pressed;
+#endif
+
+void psion_arch_handler(unsigned char value, char up_flag)
+{
+#if defined(CONFIG_VT) && defined(CONFIG_MAGIC_SYSRQ)
+	if (value == 1) {
+		sysrq_pressed = !up_flag;
+		return;
+	}
+#endif
+	if (up_flag) return;
+	switch (value) {
+
+#ifdef KBD_ARCHKEY_2
+		case 2:
+			KBD_ARCHKEY_2;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_3
+		case 3:
+			KBD_ARCHKEY_3;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_4
+		case 4:
+			KBD_ARCHKEY_4;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_5
+		case 5:
+			KBD_ARCHKEY_5;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_6
+		case 6:
+			KBD_ARCHKEY_6;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_7
+		case 7:
+			KBD_ARCHKEY_7;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_8
+		case 8:
+			KBD_ARCHKEY_8;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_9
+		case 9:
+			KBD_ARCHKEY_9;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_10
+		case 10:
+			KBD_ARCHKEY_10;
+			break;
+#endif
+#ifdef KBD_ARCHKEY_11
+		case 11:
+			KBD_ARCHKEY_11;
+			break;
+#endif
+
+		default:
+			return;
+	}
+}
+
+void psion_toggle_backlight()
+{
+	int pcdr;
+	long flags;
+
+	if ((psionw_readl(LCDCTL) & LCDCTL_EN) == 0)
+		psionw_lcd_powerup(1);
+
+	save_flags_cli(flags);
+	pcdr = psionw_readl(PCDR);
+	pcdr ^= PCDR_LIGHT;
+	psionw_writel(pcdr, PCDR);
+	restore_flags(flags);
+}
+
+/*
+ * Contrast table. Upper four bits: output value, lower four bits: direction
+ * (0 = in = Z)
+ */
+#define V0 0
+#define V1 1
+#define VZ 0
+#define D0 1
+#define D1 1
+#define DZ 0
+
+#define C(a,b,c,d) \
+	((V##a << 7) | (V##b << 6) | (V##c << 5) | (V##d << 4) | \
+	(D##a << 3) | (D##b << 2) | (D##c << 1) | D##d)
+    
+static __u8 contrast_table[] = {
+	C(1,1,1,1), C(1,1,1,Z), C(1,1,1,0), C(1,1,Z,1),	/*  1- 4 */
+	C(1,1,Z,Z), C(1,1,0,1), C(1,1,Z,0), C(1,Z,1,1),	/*  5- 8 */
+	C(1,1,0,0), C(1,Z,1,Z), C(1,Z,1,0), C(1,Z,Z,1),	/*  9-12 */
+	C(1,0,1,1), C(1,Z,Z,Z), C(1,Z,0,1), C(1,0,1,Z),	/* 13-16 */
+	C(1,0,1,0), C(1,0,Z,1), C(1,Z,0,0), C(Z,1,1,Z),	/* 17-20 */
+	C(1,0,Z,Z), C(1,0,0,1), C(1,0,Z,0), C(1,0,0,Z),	/* 21-24 */
+	C(Z,1,Z,Z), C(1,0,0,0), C(Z,1,Z,0), C(Z,1,0,Z),	/* 25-28 */
+	C(Z,1,0,0), C(Z,Z,1,Z), C(Z,Z,1,0), C(Z,Z,Z,1),	/* 29-32 */
+	C(0,1,1,0), C(0,1,Z,1), C(Z,Z,0,1), C(Z,0,1,Z),	/* 33-36 */
+	C(0,1,Z,Z), C(Z,Z,0,Z), C(0,1,Z,0), C(Z,Z,0,0),	/* 37-40 */
+	C(0,1,0,Z), C(Z,0,Z,Z), C(0,1,0,0), C(Z,0,Z,0),	/* 41-44 */
+	C(0,Z,1,0), C(0,Z,Z,1), C(Z,0,0,0), C(0,0,1,1),	/* 45-48 */
+	C(0,Z,Z,Z), C(0,Z,0,1), C(0,Z,Z,0), C(0,0,1,0),	/* 49-52 */
+	C(0,0,Z,1), C(0,Z,0,0), C(0,0,Z,Z), C(0,0,0,1),	/* 53-56 */
+	C(0,0,Z,0), C(0,0,0,Z), C(0,0,0,0)		/* 57-60 */
+};
+
+static int contrast = 40;
+
+int psion_get_contrast(void)
+{
+	return contrast;
+}
+
+int psion_set_contrast(int new_contrast, int lock)
+{
+	long flags = 0;
+
+	if ((new_contrast >= 0) && (new_contrast < sizeof(contrast_table))) {
+		contrast = new_contrast;
+	}
+	else {
+		printk("Bad contrast value: %i, should be between 0 - %d\n",
+		       new_contrast, sizeof(contrast_table) - 1);
+		return -EINVAL;
+	}
+
+	if (lock)
+		save_flags_cli(flags);
+
+        psionw_writeb((psionw_readb(PBDR) & ~PBDR_VLD_MASK) |
+                      ((contrast_table[contrast] >> 4) << PBDR_VLD_SHIFT),
+                      PBDR);
+        psionw_writeb((psionw_readb(PBDDR) & ~PBDR_VLD_MASK) |
+                      ((contrast_table[contrast] & 0xf) << PBDR_VLD_SHIFT),
+                      PBDDR);
+
+	if (lock)
+		restore_flags(flags);
+
+	return 0;
+}
+
+void psion_contrast(int increase)
+{
+
+	if (increase)
+		if (contrast == sizeof(contrast_table)-1) return;
+		else contrast++;
+	else if (!contrast) return;
+	else contrast--;
+
+	psion_set_contrast(contrast, 1);
+}
+
+void debug_gpio(void)
+{
+	printk("\nPADR=0x%02x PBDR=0x%02x PCDR=0x%02x PDDR=0x%02x PEDR=0x%02x ",
+	       psionw_readb(PADR),
+	       psionw_readb(PBDR),
+	       psionw_readb(PCDR),
+	       psionw_readb(PDDR),
+	       psionw_readb(PEDR));
+
+	printk("PADDR=0x%02x PBDDR=0x%02x\n",
+	       psionw_readb(PADDR),
+	       psionw_readb(PBDDR));
+}
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keyboard_psion.h linux-2.4.19-rmk2/drivers/char/keyboard_psion.h
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keyboard_psion.h linux-2.4.19-rmk2/drivers/char/keyboard_psion.h
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keyboard_psion.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/char/keyboard_psion.h	2002-10-06 14:29:23.000000000 -0700
@@ -0,0 +1,127 @@
+/*
+ *  arch/arm/drivers/char/keyboard_psion.h
+ *
+ *  Psion keyboard definitions.
+ *
+ *  Copyright (C) 1998 Roger Gammans
+ *  Copyright (C) 2000 Tony Lindgren <tony@atomide.com>
+ *
+ * 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
+ */
+
+#ifndef __ASM_ARCH_PSION_H
+#define __ASM_ARCH_PSION_H
+
+#include <asm/arch/hardware.h>
+
+#define KBDSCAN         0x0000000f	/* Keyboard scan */
+#define KBSC_HI         0x0             /* All driven high */
+#define KBSC_LO         0x1             /* All driven low */
+#define KBSC_X          0x2             /* All high impedance */
+#define KBSC_COL0       0x8             /* Col 0 high, others high impedance */
+#define KBSC_COL1       0x9             /* Col 1 high, others high impedance */
+#define KBSC_COL2       0xa             /* Col 2 high, others high impedance */
+#define KBSC_COL3       0xb             /* Col 3 high, others high impedance */
+#define KBSC_COL4       0xc             /* Col 4 high, others high impedance */
+#define KBSC_COL5       0xd             /* Col 5 high, others high impedance */
+#define KBSC_COL6       0xe             /* Col 6 high, others high impedance */
+#define KBSC_COL7       0xf             /* Col 7 high, others high impedance */
+
+#define KB_JIFMASK	(127)
+
+/*
+ * Arm's keyboard is active high row select...
+ *  (must try to remember)
+ */
+#define KB_ALLCOLS   KBSC_HI
+#define KB_DISCHARGE KBSC_LO
+#define KB_LASTROW   7
+
+#define KBUP			(0x80)
+#define KBDOWN			(0)
+
+/*
+ * Later on we'll try a struct of
+ * two arrays then the existing keyboard.c can
+ * test our array directly but until then....
+ */
+typedef struct {
+	int in:1;		/* If the key down */
+	int jif:7;		/* how long has key been down for (approx) */
+} kbd_keyinfo;
+
+static kbd_keyinfo kbdstate[NR_KEYCODES];
+
+#ifdef KB_DELAY
+extern unsigned int kbd_delay[];
+#endif
+
+/*
+ *  Be sure to change the if you increase the
+ *  number of kbd rows...
+ */
+#define KEYCODE(r,c)  ( ((c)<<3) + (r)+1)
+#define KB_ROWMASK(r) (1 << (r))
+
+/*
+ * KB_DELAY is used to allow the matrix 
+ * to stabilize.., value is determined via
+ * experimentation. 
+ */
+
+#define KB_DELAY   {16 ,16 ,16 ,16 ,16 ,16 ,16 ,16 ,16}
+
+/*
+ * Not sure whether this trick works yet!
+ * 
+ */
+#undef KBD_SUPPORTS_WIREOR
+
+/*
+ * treat debounce monostable as 30ms
+ */
+
+#define KB_DEB_JIFFY (30/HZ)
+
+extern void psion_off(void);
+void psion_toggle_backlight(void);
+void psion_contrast(int increase);
+void psion_debug_cf(void);
+
+/*
+ * Architecture-specific keys. Value 0 is invalid. 1 is SysRq.
+ * Ctrl-Alt = Ctrl-Menu on Psion, For example: SysRq = Ctrl-Menu-,
+ */
+#define KBD_ARCHKEY_2	psion_off()			/* Fn-Off */
+#define KBD_ARCHKEY_3	psion_toggle_backlight()	/* Fn-Space */
+#define KBD_ARCHKEY_4	psion_contrast(0)		/* Fn-- */
+#define KBD_ARCHKEY_5	psion_contrast(1)		/* Fn-+ */
+
+/* KBD_ARCHKEY_6 to KBD_ARCHKEY_11 reserved for debugging */
+#define KBD_ARCHKEY_6	0			/* Ctrl-Menu-z */
+
+#ifdef CONFIG_PCMCIA_ETNA
+extern void psion_debug_etna(void);
+#define KBD_ARCHKEY_7	psion_debug_etna()	/* Ctrl-Menu-x */
+#else
+#define KBD_ARCHKEY_7	debug_gpio()		/* Ctrl-Menu-x */
+#endif
+
+#define KBD_ARCHKEY_8	0			/* Ctrl-Menu-c */
+#define KBD_ARCHKEY_9	0			/* Ctrl-Menu-v */
+#define KBD_ARCHKEY_8	0
+#define KBD_ARCHKEY_9	0
+
+#endif
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keymap_psion.map linux-2.4.19-rmk2/drivers/char/keymap_psion.map
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keymap_psion.map linux-2.4.19-rmk2/drivers/char/keymap_psion.map
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/keymap_psion.map	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/char/keymap_psion.map	2002-10-02 22:07:30.000000000 -0700
@@ -0,0 +1,234 @@
+# arch/arm/drivers/char/keymap_psion.map - UK (default) keyboard map
+#
+# Written 1998,1999 by Werner Almesberger
+#
+# based on keymap_geo.map, string and compose def's taken from 
+# drivers/char/defkeymap.map
+#
+# Special keys:
+# F13	REC		F14	STOP		F15	PLAY
+# F16	Contrast--	F17	Contrast++	F18	Backlight
+
+# Default kernel keymap. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+
+	keycode	  1 = six		asciicircum
+alt	keycode	  1 = Console_6
+altgr	keycode	  1 = greater
+control	keycode	  1 = Control_asciicircum
+	keycode	  2 = five		percent
+alt	keycode	  2 = Console_5
+altgr	keycode	  2 = less
+	keycode	  3 = four		dollar
+alt	keycode	  3 = Console_4
+altgr	keycode	  3 = at
+	keycode	  4 = three		sterling
+alt	keycode	  4 = Console_3
+altgr	keycode	  4 = backslash
+control	keycode	  4 = Control_backslash
+	keycode	  5 = two		quotedbl
+alt	keycode	  5 = Console_2
+altgr	keycode	  5 = numbersign
+	keycode	  6 = one		exclam
+alt	keycode	  6 = Console_1
+altgr	keycode	  6 = underscore
+control	keycode	  6 = Control_underscore
+	keycode   7 = F13				# REC
+
+	keycode   8 = VoidSymbol
+	keycode	  9 = apostrophe	asciitilde
+altgr	keycode	  9 = colon
+	keycode	 10 = Delete
+alt	keycode	 10 = Remove
+altgr	keycode  10 = grave
+control alt keycode 10 = Boot
+	keycode	 11 = zero		parenright
+alt	keycode	 11 = Console_10
+altgr	keycode  11 = braceright
+	keycode  12 = nine		parenleft
+alt	keycode	 12 = Console_9
+altgr	keycode  12 = braceleft
+	keycode  13 = eight		asterisk
+alt	keycode	 13 = Console_8
+altgr	keycode  13 = bracketright
+control	keycode  13 = Control_bracketright
+	keycode  14 = seven		ampersand
+alt	keycode	 14 = Console_7
+altgr	keycode  14 = bracketleft
+control	keycode  14 = Escape
+	keycode	 15 = F15				# PLAY
+
+	keycode  16 = VoidSymbol
+	keycode	 17 = y
+altgr	keycode  17 = KP_Multiply
+	keycode	 18 = t
+altgr	keycode	 18 = bar
+	keycode	 19 = r
+	keycode	 20 = e
+	keycode	 21 = w
+	keycode	 22 = q
+	keycode	 23 = Escape		Escape
+alt	keycode	 23 = Meta_Escape
+altgr	keycode  23 = 0xf02				# OFF
+
+	keycode  24 = VoidSymbol
+	keycode	 25 = Return
+	keycode  26 = l
+altgr	keycode  26 = semicolon
+	keycode  27 = p
+altgr	keycode  27 = equal
+	keycode  28 = o
+altgr	keycode  28 = minus
+	keycode  29 = i
+altgr	keycode  29 = plus
+	keycode  30 = u
+altgr	keycode  30 = KP_Divide
+	keycode	 31 = SAlt				# Menu
+
+	keycode  32 = VoidSymbol
+	keycode	 33 = g
+	keycode	 34 = f
+	keycode	 35 = d
+	keycode	 36 = s
+	keycode	 37 = a
+	keycode	 38 = Tab
+altgr	keycode	 38 = Caps_Lock
+	keycode	 39 = SControl
+
+	keycode  40 = VoidSymbol
+	keycode  41 = Down		Scroll_Backward
+altgr	keycode	 41 = Prior
+	keycode	 42 = period		question
+altgr	keycode  42 = 0xf05				# Contrast++
+	keycode	 43 = m
+altgr	keycode	 43 = 0xf04				# Contrast--
+	keycode	 44 = k
+	keycode	 45 = j
+	keycode	 46 = h
+	keycode	 47 = SAltGr				# Fn
+
+	keycode  48 = VoidSymbol
+	keycode	 49 = n
+control alt keycode 49 = 0xf0b				# Debug 5
+	keycode	 50 = b
+control alt keycode 50 = 0xf0a				# Debug 4
+	keycode	 51 = v
+control alt keycode 51 = 0xf09				# Debug 3
+	keycode	 52 = c
+control alt keycode 52 = 0xf08				# Debug 2
+	keycode	 53 = x
+control alt keycode 53 = 0xf07				# Debug 1
+	keycode	 54 = z
+control alt keycode 54 = 0xf06				# Debug 0
+	keycode	 55 = SShift
+
+	keycode  56 = VoidSymbol
+	keycode	 57 = Right
+altgr	keycode  57 = Select				# End
+	keycode  58 = Left
+altgr	keycode  58 = Find				# Home
+	keycode  59 = comma		slash
+control alt keycode 59 = 0xf01				# SysRq
+	keycode  60 = Up		Scroll_Forward
+altgr	keycode  60 = Next
+	keycode	 61 = space
+altgr	keycode  61 = 0xf03				# Backlight
+	keycode  62 = F14				# STOP
+	keycode  63 = SShift
+
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/psionw-rtc.c linux-2.4.19-rmk2/drivers/char/psionw-rtc.c
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/psionw-rtc.c linux-2.4.19-rmk2/drivers/char/psionw-rtc.c
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/psionw-rtc.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/char/psionw-rtc.c	2002-10-02 22:07:30.000000000 -0700
@@ -0,0 +1,445 @@
+/*
+ * Real Time Clock interface for Psion Windermere
+ *
+ * Copyright (c) 2002 Tony Lindgren <tony@atomide.com>
+ *
+ * Modified from the sa1100-rtc.c.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <linux/rtc.h>
+#include <asm/io.h>
+#include <asm/hardware/psionw.h>
+
+#define	DRIVER_VERSION		"1.00"
+
+#define TIMER_FREQ		3686400
+
+#define RTC_DEF_DIVIDER		32768 - 1
+#define RTC_DEF_TRIM		0
+
+/* Those are the bits from a classic RTC we want to mimic */
+#define RTC_IRQF		0x80	/* any of the following 3 is active */
+#define RTC_PF			0x40
+#define RTC_AF			0x20
+#define RTC_UF			0x10
+
+static unsigned long rtc_status;
+static unsigned long rtc_irq_data;
+static unsigned long rtc_freq = 1024;
+
+static struct fasync_struct *rtc_async_queue;
+static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
+
+extern spinlock_t rtc_lock;
+
+static const unsigned char days_in_mo[] =
+	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+#define is_leap(year) \
+	((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+/*
+ * Converts seconds since 1970-01-01 00:00:00 to Gregorian date.
+ */
+static void decodetime (unsigned int t, struct rtc_time *tval)
+{
+	unsigned int days, month, year, rem;
+
+	days = t / 86400;
+	rem = t % 86400;
+	tval->tm_hour = rem / 3600;
+	rem %= 3600;
+	tval->tm_min = rem / 60;
+	tval->tm_sec = rem % 60;
+	tval->tm_wday = (4 + days) % 7;
+
+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
+
+	year = 1970 + days / 365;
+	days -= ((year - 1970) * 365
+			+ LEAPS_THRU_END_OF (year - 1)
+			- LEAPS_THRU_END_OF (1970 - 1));
+	if (days < 0) {
+		year -= 1;
+		days += 365 + is_leap(year);
+	}
+	tval->tm_year = year - 1900;
+	tval->tm_yday = days + 1;
+
+	month = 0;
+	if (days >= 31) {
+		days -= 31;
+		month++;
+		if (days >= (28 + is_leap(year))) {
+			days -= (28 + is_leap(year));
+			month++;
+			while (days >= days_in_mo[month]) {
+				days -= days_in_mo[month];
+				month++;
+			}
+		}
+	}
+	tval->tm_mon = month;
+	tval->tm_mday = days + 1;
+}
+
+static void timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/*
+	 * If we match for the first time, the periodic interrupt flag won't
+	 * be set.  If it is, then we did wrap around (very unlikely but
+	 * still possible) and compute the amount of missed periods.
+	 * The match reg is updated only when the data is actually retrieved
+	 * to avoid unnecessary interrupts.
+	 */
+	if (rtc_irq_data & RTC_PF) {
+		rtc_irq_data += (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))) << 8;
+	} else {
+		rtc_irq_data += (0x100|RTC_PF|RTC_IRQF);
+	}
+
+	wake_up_interruptible(&rtc_wait);
+	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
+}
+
+static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* update irq data & counter */
+	rtc_irq_data |= (RTC_AF|RTC_IRQF);
+	rtc_irq_data += 0x100;
+
+	/* wake up waiting process */
+	wake_up_interruptible(&rtc_wait);
+	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
+}
+
+static int rtc_set_timer(int frequency) {
+	unsigned int timer = 0;
+	unsigned int multiplier = 2000;
+
+	if (frequency == 0) {
+		psionw_writel(0, TC1CTRL);
+		psionw_writel(0, TC1LOAD);
+		return 0;
+	}
+
+	timer = psionw_readl(TC1CTRL);
+	timer |= TC_MODE;		/* Periodic mode */
+	
+	if (frequency > 1900) {
+		multiplier = 512000;
+		timer |= TC_CLKSEL;	/* 512kHz mode */
+	} else {
+		timer &= ~TC_CLKSEL;   	/* 2kHz mode */
+	}
+
+	timer |= TC_ENABLE;
+	psionw_writel(timer, TC1CTRL);
+
+	psionw_writel((multiplier / frequency) - 1, TC1LOAD);
+
+	return 0;
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit (1, &rtc_status))
+		return -EBUSY;
+	rtc_irq_data = 0;
+	return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+	spin_lock_irq (&rtc_lock);
+	rtc_set_timer(0);
+	spin_unlock_irq (&rtc_lock);
+	rtc_status = 0;
+	return 0;
+}
+
+static int rtc_fasync (int fd, struct file *filp, int on)
+{
+	return fasync_helper (fd, filp, on, &rtc_async_queue);
+}
+
+static unsigned int rtc_poll(struct file *file, poll_table *wait)
+{
+	poll_wait (file, &rtc_wait, wait);
+	return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM;
+}
+
+static loff_t rtc_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t retval;
+
+	if (count < sizeof(unsigned long))
+		return -EINVAL;
+
+	add_wait_queue(&rtc_wait, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	for (;;) {
+		spin_lock_irq (&rtc_lock);
+		data = rtc_irq_data;
+		if (data != 0) {
+			rtc_irq_data = 0;
+			break;
+		}
+		spin_unlock_irq (&rtc_lock);
+
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		}
+
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+
+		schedule();
+	}
+
+#if 0
+	if (data & RTC_PF) {
+		/* interpolate missed periods and set match for the next one */
+		unsigned long period = TIMER_FREQ/rtc_freq;
+		unsigned long oscr = OSCR;
+		unsigned long osmr1 = OSMR1;
+		unsigned long missed = (oscr - osmr1)/period;
+		data += missed << 8;
+		OSSR = OSSR_M1;	/* clear match on timer 1 */
+		OSMR1 = osmr1 + (missed + 1)*period;
+		/* ensure we didn't miss another match in the mean time */
+		while( (signed long)((osmr1 = OSMR1) - OSCR) <= 0 ) {
+			data += 0x100;
+			OSSR = OSSR_M1;	/* clear match on timer 1 */
+			OSMR1 = osmr1 + period;
+		}
+	}
+#endif
+	spin_unlock_irq (&rtc_lock);
+
+	data -= 0x100;	/* the first IRQ wasn't actually missed */
+
+	retval = put_user(data, (unsigned long *)buf);
+	if (!retval)
+		retval = sizeof(unsigned long);
+
+out:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rtc_wait, &wait);
+	return retval;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct rtc_time tm, tm2;
+
+	switch (cmd) {
+	case RTC_AIE_OFF:
+		spin_lock_irq(&rtc_lock);
+		rtc_irq_data = 0;
+		spin_unlock_irq(&rtc_lock);
+		return 0;
+	case RTC_AIE_ON:
+		spin_lock_irq(&rtc_lock);
+		rtc_irq_data = 0;
+		spin_unlock_irq(&rtc_lock);
+		return 0;
+	case RTC_UIE_OFF:
+		spin_lock_irq(&rtc_lock);
+		rtc_set_timer(0);
+		rtc_irq_data = 0;
+		spin_unlock_irq(&rtc_lock);
+		return 0;
+	case RTC_UIE_ON:
+		spin_lock_irq(&rtc_lock);
+		rtc_set_timer(1);
+		rtc_irq_data = 0;
+		spin_unlock_irq(&rtc_lock);
+		return 0;
+	case RTC_PIE_OFF:
+		spin_lock_irq(&rtc_lock);
+		rtc_set_timer(0);
+		rtc_irq_data = 0;
+		spin_unlock_irq(&rtc_lock);
+		return 0;
+	case RTC_PIE_ON:
+		if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
+			return -EACCES;
+		spin_lock_irq(&rtc_lock);
+		rtc_set_timer(rtc_freq);
+		rtc_irq_data = 0;
+		spin_unlock_irq(&rtc_lock);
+		return 0;
+	case RTC_ALM_READ:
+		decodetime(psionw_read_rtc_alarm(), &tm);
+		break;
+	case RTC_ALM_SET:
+		if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2)))
+			return -EFAULT;
+		decodetime(psionw_read_rtc(), &tm);
+		if ((unsigned)tm2.tm_hour < 24)
+			tm.tm_hour = tm2.tm_hour;
+		if ((unsigned)tm2.tm_min < 60)
+			tm.tm_min = tm2.tm_min;
+		if ((unsigned)tm2.tm_sec < 60)
+			tm.tm_sec = tm2.tm_sec;
+		psionw_write_rtc_alarm(mktime(tm.tm_year + 1900, tm.tm_mon + 1, 
+					      tm.tm_mday, tm.tm_hour, 
+					      tm.tm_min, tm.tm_sec));
+		return 0;
+	case RTC_RD_TIME:
+		decodetime(psionw_read_rtc(), &tm);
+		break;
+	case RTC_SET_TIME:
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+		if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm)))
+			return -EFAULT;
+		tm.tm_year += 1900;
+		if (tm.tm_year < 1970 || (unsigned)tm.tm_mon >= 12 ||
+		    tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] +
+				(tm.tm_mon == 1 && is_leap(tm.tm_year))) ||
+		    (unsigned)tm.tm_hour >= 24 ||
+		    (unsigned)tm.tm_min >= 60 ||
+		    (unsigned)tm.tm_sec >= 60)
+			return -EINVAL;
+		psionw_write_rtc(mktime(tm.tm_year, tm.tm_mon + 1, 
+					tm.tm_mday, tm.tm_hour, 
+					tm.tm_min, tm.tm_sec));
+		return 0;
+	case RTC_IRQP_READ:
+		return put_user(rtc_freq, (unsigned long *)arg);
+	case RTC_IRQP_SET:
+		if (arg < 1 || arg > TIMER_FREQ)
+				return -EINVAL;
+		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
+				return -EACCES;
+		rtc_freq = arg;
+		return 0;
+	case RTC_EPOCH_READ:
+		return put_user (1970, (unsigned long *)arg);
+	default:
+		return -EINVAL;
+	}
+	return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0;
+}
+
+static struct file_operations rtc_fops = {
+	owner:		THIS_MODULE,
+	llseek:		rtc_llseek,
+	read:		rtc_read,
+	poll:		rtc_poll,
+	ioctl:		rtc_ioctl,
+	open:		rtc_open,
+	release:	rtc_release,
+	fasync:		rtc_fasync,
+};
+
+static struct miscdevice psionwrtc_miscdev = {
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	char *p = page;
+	int len;
+	struct rtc_time tm;
+
+	decodetime(psionw_read_rtc(), &tm);
+	p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n"
+			"rtc_date\t: %04d-%02d-%02d\n"
+			"rtc_epoch\t: %04d\n",
+			tm.tm_hour, tm.tm_min, tm.tm_sec,
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1970);
+	decodetime(psionw_read_rtc_alarm(), &tm);
+	p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n"
+			"alrm_date\t: %04d-%02d-%02d\n",
+			tm.tm_hour, tm.tm_min, tm.tm_sec,
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+	////p += sprintf(p, "trim/divider\t: 0x%08x\n", RTTR);
+	////p += sprintf(p, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" );
+	////p += sprintf(p, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no");
+	////p += sprintf(p, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no");
+	p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq);
+
+	len = (p - page) - off;
+	if (len < 0)
+		len = 0;
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static int __init rtc_init(void)
+{
+	int ret;
+
+	misc_register (&psionwrtc_miscdev);
+	create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);
+
+	ret = request_irq (IRQ_TC1OI, timer1_interrupt, SA_INTERRUPT, "rtc timer", NULL);
+	if (ret) {
+		printk (KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_TC1OI);
+		goto IRQ_TC1OI_failed;
+	}
+
+	ret = request_irq (IRQ_RTCMI, rtc_interrupt, SA_INTERRUPT, "rtc alarm", NULL);
+	if (ret) {
+		printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTCMI);
+		goto IRQ_RTCMI_failed;
+	}
+
+	rtc_set_timer(0);
+
+	printk (KERN_INFO "Psion Windermere Real Time Clock driver v" DRIVER_VERSION "\n");
+
+	return 0;
+
+IRQ_RTCMI_failed:
+	free_irq (IRQ_TC1OI, NULL);
+IRQ_TC1OI_failed:
+	remove_proc_entry ("driver/rtc", NULL);
+	misc_deregister (&psionwrtc_miscdev);
+	return ret;
+}
+
+static void __exit rtc_exit(void)
+{
+	rtc_set_timer(0);
+	free_irq (IRQ_TC1OI, NULL);
+	free_irq (IRQ_RTCMI, NULL);
+	remove_proc_entry ("driver/rtc", NULL);
+	misc_deregister (&psionwrtc_miscdev);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+
+MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
+MODULE_DESCRIPTION("Psion Windermere Realtime Clock Driver (RTC)");
+EXPORT_NO_SYMBOLS;
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/psionw_procfs.c linux-2.4.19-rmk2/drivers/char/psionw_procfs.c
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/psionw_procfs.c linux-2.4.19-rmk2/drivers/char/psionw_procfs.c
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/char/psionw_procfs.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/char/psionw_procfs.c	2002-10-02 22:07:30.000000000 -0700
@@ -0,0 +1,666 @@
+/*
+ *  linux/drivers/chars/psionw_utils.c
+ *
+ * Psion procfs entries for manipulating backlight, contrast, power off 
+ * and auto-sleep on Psion Windmere based Computers (Psion5mx(Pro), 
+ * Revo(Plus), Mako).
+ *
+ * Copyright (C) 2002 Thilo Hille <thilo@resourcery.de>
+ *                    Vaclav Kulakovsky <vaclav.kulakovsky@definity.cz>
+ *                    Tony Lindgren <tony@atomide.com>
+ *                    Simon Howard <sdh300@ecs.soton.ac.uk>
+ *
+ * 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/init.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+
+#include <asm/hardware/psionw.h>
+#include <../drivers/pcmcia/psion_etna.h>
+
+#define MODULE_VERSION "0.2"
+#define MODULE_NAME "procfs_psionw"
+#define MODULE_DIR_NAME "psionw"
+#define COREAD 3
+
+extern void psion_off(void);
+extern void psion_lcd_powerdown(int lock);
+extern void psion_lcd_powerup(int lock);
+extern int psion_get_contrast(void);
+extern int psion_set_contrast(int new_contrast, int lock);
+extern unsigned int psionw_get_cpu_speed(int cpu);
+extern void psionw_set_cpu_speed(int speed);
+
+/* Psion sleep variables */
+
+//#define PSLEEP_DEBUG 1
+#ifdef PSLEEP_DEBUG
+	#define DEBUG_PSLEEP(x...) printk(x)
+#else
+	#define DEBUG_PSLEEP(x...)                do { ; } while(0)
+#endif
+
+#define PROC_SLEEP_MAX_LEN 8
+
+static struct timer_list psion_sleep_timer;
+static int psionblankinterval = 0;
+
+struct fb_data_t {
+	char name[PROC_SLEEP_MAX_LEN + 1];
+	char value[PROC_SLEEP_MAX_LEN + 1];
+};
+
+struct fb_data_t psion_sleep_data;
+
+static struct proc_dir_entry *psion_sleep_file;
+extern void (*psion_sleep_set_callback)(void);
+void psion_sleep_set(void);
+
+static int psionw_proc_lcdpower_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data);
+static int psionw_proc_lcdpower_write(struct file *file,
+		const char *buffer, unsigned long count, void *data);
+
+static int psionw_proc_backlight_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data);
+static int psionw_proc_backlight_write(struct file *file,
+		const char *buffer, unsigned long count, void *data);
+static int psionw_proc_contrast_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data);
+static int psionw_proc_contrast_write(struct file *file,
+		const char *buffer, unsigned long count, void *data);
+static int psionw_proc_state_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data);
+static int psionw_proc_state_write(struct file *file,
+		const char *buffer, unsigned long count, void *data);
+static int psionw_proc_uart_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data);
+static int psionw_proc_uart_write(struct file *file,
+		const char *buffer, unsigned long count, void *data);
+static int psionw_proc_cpu_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data);
+static int psionw_proc_cpu_write(struct file *file,
+		const char *buffer, unsigned long count, void *data);
+
+static struct proc_dir_entry *psionw_proc_dir,
+	*psionw_lcdpower_proc_entry,
+	*psionw_backlight_proc_entry,
+	*psionw_contrast_proc_entry,
+	*psionw_state_proc_entry,
+	*psionw_uart1_proc_entry,
+	*psionw_uart2_proc_entry,
+	*psionw_mains_proc_entry,
+	*psionw_case_proc_entry;
+
+struct uart_data_t {
+	short uart;
+};
+
+struct uart_data_t uart1_data, uart2_data;
+
+static int
+psionw_proc_lcdpower_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	return sprintf(page, "%d\n",
+		(psionw_readl(LCDCTL) & LCDCTL_EN)? 1 : 0 );
+}
+
+static int
+psionw_proc_lcdpower_write(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+	unsigned char char_value;
+	int value;
+
+	if (count < 1) {
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&char_value, buffer, 1))
+		return -EFAULT;
+
+	value = char_value - '0';
+
+        if (value) {
+                psionw_lcd_powerup(1);
+        } else {
+                psionw_lcd_powerdown(1);
+	}
+
+	return count;
+}
+
+static int
+psionw_proc_contrast_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	return	sprintf(page, "%i\n", psion_get_contrast());
+}
+
+static int damn_atoi(const char *name)
+{
+    int val = 0;
+
+    for (;; name++) {
+        switch (*name) {
+            case '0'...'9':
+                val = 10*val+(*name-'0');
+                break;
+            default:
+                return val;
+        }
+    }
+}
+
+static int
+psionw_proc_contrast_write(struct file *file, const char *buffer,
+                unsigned long count, void *data)
+{
+        char rbuffer[COREAD + 1];
+	int new_contrast;
+	int len;
+
+        if (count < 1)
+                return -EINVAL;
+
+        if (count > COREAD){
+		len = COREAD;
+	}
+	else {
+		len = count;
+	}
+
+        if (copy_from_user(&rbuffer, buffer, len))
+                return -EFAULT;
+
+        rbuffer[len]='\0';
+	new_contrast = damn_atoi(rbuffer);
+
+	psion_set_contrast(new_contrast, 1);
+
+	return len;
+}
+
+
+static int
+psionw_proc_backlight_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	return sprintf(page, "%d\n",
+		(psionw_readl(PCDR) & PCDR_LIGHT)? 1 : 0 );
+}
+
+static int
+psionw_proc_backlight_write(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+	unsigned char char_value;
+	int value;
+	int pcdr;
+	long flags;
+
+	if (count < 1) {
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&char_value, buffer, 1))
+		return -EFAULT;
+
+	value = char_value - '0';
+
+	save_flags_cli(flags);
+        pcdr = psionw_readl(PCDR);
+        if (value) {
+                pcdr |= PCDR_LIGHT;
+        } else {
+                pcdr &= ~PCDR_LIGHT;
+	}
+        psionw_writel(pcdr, PCDR);
+	restore_flags(flags);
+
+	return count;
+}
+
+static int
+psionw_proc_uart_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	int psionw_proc_uart_state;
+	struct uart_data_t *uart_data = (struct uart_data_t *)data;
+	int pcdr;
+
+	if (uart_data->uart == 1) {
+	 	pcdr = PCDR_UART1;
+	}
+	else if (uart_data->uart == 2) {
+	 	pcdr = PCDR_UART2;
+	}
+	else
+		return -EINVAL;
+
+	psionw_proc_uart_state = (psionw_readb(PCDR) & pcdr);
+
+	return sprintf(page, "%i\n",(psionw_proc_uart_state) ? 1 : 0);
+}
+
+static int
+psionw_proc_uart_write(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+	struct uart_data_t *uart_data = (struct uart_data_t *)data;
+	unsigned char char_value;
+	int value;
+	int pcdr;
+	long flags;
+
+	if (copy_from_user(&char_value, buffer, 1))
+		return -EFAULT;
+
+	value = char_value - '0';
+	if (count < 1) {
+		return -EINVAL;
+	}
+	if (uart_data->uart==1){
+	 	pcdr=PCDR_UART1;
+	}
+	else if (uart_data->uart==2){
+	 	pcdr=PCDR_UART2;
+	}
+	else
+		return -EINVAL;
+
+	save_flags_cli(flags);
+	if (value) {
+	 	printk("uart%i: powerup: \n",uart_data->uart);
+		psionw_writeb(psionw_readb(PCDR) | pcdr, PCDR);
+	}
+	else {
+	 	printk("uart%i: powerdown: \n",uart_data->uart);
+		psionw_writeb(psionw_readb(PCDR) & ~pcdr, PCDR);
+	}
+	restore_flags(flags);
+
+	return count;
+}
+
+static int
+psionw_proc_state_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+/*
+ * SlothAttack!
+ * If i had invented the refrigerator, their lights would remain on even with their door closed .
+ * We should output 0 if the machine is in sleepmode. But since noone will ever be able to read it
+ * it always sends 1
+ */
+	return sprintf(page, "1\n");
+
+}
+
+static int
+psionw_proc_state_write(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+	unsigned char char_value;
+	int value;
+	int pcdr;
+
+	if (count < 1) {
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&char_value, buffer, 1))
+		return -EFAULT;
+
+	value = char_value - '0';
+
+        pcdr = psionw_readl(PCDR);
+        if (!value){
+	 	psion_off();
+	}
+
+	return count;
+}
+
+static int
+psionw_proc_cpu_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	int speed = 0;
+	
+	speed = psionw_get_cpu_speed(0) / 100000;	
+	return sprintf(page, "%d.%d\n", speed/10, speed%10);
+}
+
+static int
+psionw_proc_cpu_write(struct file *file, const char *buffer,
+		unsigned long count, void *data)
+{
+	unsigned char char_value;
+	int value;
+	int pcdr;
+
+	if (count < 1) {
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&char_value, buffer, 1))
+		return -EFAULT;
+
+	value = char_value - '0';
+
+	psionw_set_cpu_speed(value);
+
+	return count;
+}
+
+static void psion_sleep_timer_func(unsigned long dummy)
+{
+	psion_off();
+	psion_sleep_set();
+}
+
+/* Called from keyboard_psion.c on a key press */
+void psion_sleep_set(void)
+{
+	/* modify timer*/
+	psion_sleep_timer.function = psion_sleep_timer_func;
+	if (psionblankinterval) {
+		mod_timer(&psion_sleep_timer, jiffies + psionblankinterval);
+	} else {
+		del_timer(&psion_sleep_timer);
+	}	
+}
+
+static int psion_sleep_proc_read(char *page, char **start,
+			    off_t off, int count, 
+			    int *eof, void *data)
+{
+	int len;
+	struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+	len = sprintf(page, "%s\n", fb_data->value);
+	return len;
+}
+
+static int psion_sleep_proc_write(struct file *file,
+			     const char *buffer,
+			     unsigned long count, 
+			     void *data)
+{
+	int len, interval;
+	struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+	if (count > PROC_SLEEP_MAX_LEN) len = PROC_SLEEP_MAX_LEN;
+	else len = count;
+
+	if (copy_from_user(fb_data->value, buffer, len)) {
+		return 0;
+	}
+	fb_data->value[len] = '\0';
+	
+	/* read new timeout */
+	sscanf( fb_data->value, "%d", &interval );
+	if( interval ) 
+		if( interval < 10 ) {
+			interval = 10;
+			printk( "Minimal sleep inerval is 10 sec.\n" );
+		}
+	snprintf(fb_data->value, PROC_SLEEP_MAX_LEN, "%d", interval);
+	fb_data->value[len] = '\0';
+	
+	psionblankinterval = interval * HZ;
+	psion_sleep_set();
+	DEBUG_PSLEEP("Psion sleep after %d s. \n", psionblankinterval/HZ );
+
+	return len;
+}
+
+
+static int psionw_proc_mains_read(char *page, char **start,
+				  off_t off, int count,
+				  int *eof, void *data) {
+	return sprintf(page, "%i\n", (psionw_readb(PWRSR) & DCDET) != 0);
+}
+
+static int psionw_proc_mains_write(struct file *file,
+				   const char *buffer,
+				   unsigned long count,
+				   void *data) {
+	/* i cant do that */
+	return 0;
+}
+
+static int psionw_proc_case_read(char *page, char **start,
+				 off_t off, int count,
+				 int *eof, void *data) {
+
+	/* Make sure the data direction is set for read */
+	if (psionw_readb(PBDDR) & PBDR_OPEN) {
+		long flags;
+		save_flags_cli(flags);
+		psionw_writeb(psionw_readb(PBDDR) & ~PBDR_OPEN, PBDDR);
+		restore_flags(flags);
+	}
+
+	/* 0 on PBDR_OPEN = open, 1 = closed, invert this
+	   (seems more intuitive this way) */
+	return sprintf(page, "%i\n", (psionw_readb(PBDR) & PBDR_OPEN) == 0);
+}
+
+static int psionw_proc_case_write(struct file *file,
+				  const char *buffer,
+				  unsigned long count,
+				  void *data) {
+	/* i cant close the case for you! */
+	return 0;
+}
+
+
+int __init psionwbl_init(void)
+{
+	int rv = 0;
+
+	/* Create directory */
+	psionw_proc_dir = proc_mkdir(MODULE_DIR_NAME, NULL);
+	if(psionw_proc_dir == NULL) {
+		printk("Couldn't create the procfs dir for psionw \n");
+		rv = -ENOMEM;
+		goto out;
+	}
+	psionw_proc_dir->owner = THIS_MODULE;
+
+	/* Register the /proc/psionw/lcd entry */
+	psionw_lcdpower_proc_entry = create_proc_entry("lcd", 0444,
+						       psionw_proc_dir);
+	if (psionw_lcdpower_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for lcd. \n");
+		rv = -EINVAL;
+		goto out;
+	}
+	psionw_lcdpower_proc_entry->read_proc =
+		&psionw_proc_lcdpower_read;
+	psionw_lcdpower_proc_entry->write_proc =
+		&psionw_proc_lcdpower_write;
+
+	/* Register the /proc/psionw/backlight entry. */
+	psionw_backlight_proc_entry = create_proc_entry("backlight", 0444,
+							psionw_proc_dir);
+	if (psionw_backlight_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for backlight.\n");
+		rv = -EINVAL;
+		goto out;
+	}
+        psionw_backlight_proc_entry->read_proc =
+                &psionw_proc_backlight_read;
+        psionw_backlight_proc_entry->write_proc =
+                &psionw_proc_backlight_write;
+
+	/* Register the /proc/psionw/contrast entry. */
+	psionw_contrast_proc_entry = create_proc_entry("contrast", 0444,
+		psionw_proc_dir);
+	if (psionw_contrast_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for the psionw-contrast.\n");
+		rv = -EINVAL;
+		goto out;
+	}
+
+	psionw_contrast_proc_entry->read_proc =
+		&psionw_proc_contrast_read;
+	psionw_contrast_proc_entry->write_proc =
+		&psionw_proc_contrast_write;
+
+	/* Register the /proc/psionw/state entry. */
+	psionw_state_proc_entry = create_proc_entry("state", 0444,
+		psionw_proc_dir);
+	if (psionw_state_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for the psionw-state.\n");
+		rv = -EINVAL;
+		goto out;
+	}
+	psionw_state_proc_entry->read_proc =
+		&psionw_proc_state_read;
+	psionw_state_proc_entry->write_proc =
+		&psionw_proc_state_write;
+
+	/* Register the /proc/psionw/cpu entry. */
+	psionw_state_proc_entry = create_proc_entry("cpu", 0644,
+		psionw_proc_dir);
+	if (psionw_state_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for the psionw-cpu.\n");
+		rv = -EINVAL;
+		goto out;
+	}
+	psionw_state_proc_entry->read_proc =
+		&psionw_proc_cpu_read;
+	psionw_state_proc_entry->write_proc =
+		&psionw_proc_cpu_write;
+
+	/* Register the /proc/psionw/sleep entry. */
+	psion_sleep_file = create_proc_entry("sleep", 0644, psionw_proc_dir );
+	if( psion_sleep_file == NULL) {
+		printk("Couldn't create the procfs entry for the psionw-sleep.\n");
+	} else {
+		strcpy(psion_sleep_data.name, "sleep");
+		strcpy(psion_sleep_data.value, "0");
+		psion_sleep_file->data = &psion_sleep_data;
+		psion_sleep_file->read_proc = psion_sleep_proc_read;
+		psion_sleep_file->write_proc = psion_sleep_proc_write;
+		psion_sleep_file->owner = THIS_MODULE;
+	}
+
+	/* Init timer */
+	psion_sleep_set();
+
+	/* Autosleep is initialised from keyboard_psion.c */
+	psion_sleep_set_callback = psion_sleep_set;
+	DEBUG_PSLEEP("SLEEP: Callback registered.\n");
+	
+	/* Register the /proc/psionw/uart entries for uart1 */
+	psionw_uart1_proc_entry = create_proc_entry("uart1", 0444,
+		psionw_proc_dir);
+	if (psionw_uart1_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for the psionw-uart1.\n");
+		rv = -EINVAL;
+		goto out;
+	}
+	uart1_data.uart = 1;
+	psionw_uart1_proc_entry->data = &uart1_data;
+	psionw_uart1_proc_entry->read_proc =
+		&psionw_proc_uart_read;
+	psionw_uart1_proc_entry->write_proc =
+		&psionw_proc_uart_write;
+
+	/* Uart2 */
+	psionw_uart2_proc_entry = create_proc_entry("uart2", 0444,
+		psionw_proc_dir);
+	if (psionw_uart2_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for the psionw-uart2.\n");
+		rv = -EINVAL;
+		goto out;
+	}
+	uart2_data.uart = 2;
+	psionw_uart2_proc_entry->data = &uart2_data;
+	psionw_uart2_proc_entry->read_proc =
+		&psionw_proc_uart_read;
+	psionw_uart2_proc_entry->write_proc =
+		&psionw_proc_uart_write;
+
+	psionw_mains_proc_entry = create_proc_entry("mains", 0444,
+		psionw_proc_dir);
+
+	if (psionw_mains_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for mains\n");
+		rv = -EINVAL;
+		goto out;
+	} else {
+		psionw_mains_proc_entry->read_proc = &psionw_proc_mains_read;
+		psionw_mains_proc_entry->write_proc = &psionw_proc_mains_write;
+	}
+
+	psionw_case_proc_entry = create_proc_entry("case", 0444,
+		psionw_proc_dir);
+
+	if (psionw_case_proc_entry == NULL) {
+		printk("Couldn't create the procfs entry for case\n");
+		rv = -EINVAL;
+		goto out;
+	} else {
+		psionw_case_proc_entry->read_proc = &psionw_proc_case_read;
+		psionw_case_proc_entry->write_proc = &psionw_proc_case_write;
+	}
+
+	return 0;
+	out:
+		return rv;
+}
+
+static void __exit psionwbl_exit(void)
+{
+	del_timer(&psion_sleep_timer);
+
+	/* Unregister sleep callback function */
+	psion_sleep_set_callback = 0;
+
+	remove_proc_entry("lcd", psionw_proc_dir);
+	remove_proc_entry("backlight", psionw_proc_dir);
+	remove_proc_entry("contrast", psionw_proc_dir);
+	remove_proc_entry("state", psionw_proc_dir);
+	remove_proc_entry("cpu", psionw_proc_dir);
+	remove_proc_entry("sleep", psionw_proc_dir);
+	remove_proc_entry("uart1", psionw_proc_dir);
+	remove_proc_entry("uart2", psionw_proc_dir);
+	remove_proc_entry("mains", psionw_proc_dir);
+	remove_proc_entry("case", psionw_proc_dir);
+
+	remove_proc_entry(MODULE_NAME, NULL);
+}
+
+module_init(psionwbl_init);
+module_exit(psionwbl_exit);
+MODULE_AUTHOR("Thilo Hille/Vaclac Kulakovsky");
+MODULE_DESCRIPTION("procfs utils for Psion5mx(Pro)/Revo(Plus)/Mako");
+EXPORT_NO_SYMBOLS;
+
