Hi,

Attached you will find a patch implementing support for the Xilinx PS/2
keyboard and mouse ports. It was tested on a Xilinx virtex2pro
implementation.

Comments welcome,

Peter.
-------------- next part --------------
diff -urN -x CVS -x config -x modules -x mtd -x jffs2 -x jffs 
linuxppc_2_4_clean/drivers/char/Makefile 
linuxppc_2_4_xseg2.new.clean2/drivers/char/Makefile
--- linuxppc_2_4_clean/drivers/char/Makefile    2002-07-20 12:04:11.000000000 
+0200
+++ linuxppc_2_4_xseg2.new.clean2/drivers/char/Makefile 2002-09-01 
17:10:57.000000000 +0200
@@ -71,6 +71,10 @@
   SERIAL = serial.o
 endif

+ifdef CONFIG_XSEG2
+  KEYBD = xilinx_keyb.o
+endif
+
 ifeq ($(ARCH),arm)
   ifneq ($(CONFIG_PC_KEYMAP),y)
     KEYMAP   =
diff -urN -x CVS -x config -x modules -x mtd -x jffs2 -x jffs 
linuxppc_2_4_clean/drivers/char/xilinx_keyb.c 
linuxppc_2_4_xseg2.new.clean2/drivers/char/xilinx_keyb.c
--- linuxppc_2_4_clean/drivers/char/xilinx_keyb.c       1970-01-01 
01:00:00.000000000 +0100
+++ linuxppc_2_4_xseg2.new.clean2/drivers/char/xilinx_keyb.c    2002-09-01 
16:23:56.000000000 +0200
@@ -0,0 +1,687 @@
+/*
+ * xilinx_keyb.c: A driver for Xilinx PS/2 keyboard and mouse interface core
+ *
+ * Copyright 2002 Mind NV
+ *
+ * http://www.mind.be/
+ *
+ * Author : Peter De Schrijver (p2 at mind.be)
+ *
+ * Derived from : drivers/char/q40_keyb.c
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL) version 2, incorporated herein by
+ * reference. Drivers based on or derived from this code fall under the GPL
+ * and must retain the authorship, copyright and this license notice. This
+ * file is not a complete program and may only be used when the entire
+ * operating system is licensed under the GPL.
+ *
+ */
+
+#include <linux/config.h>
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/keyboard.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/kbd_kern.h>
+#include <linux/delay.h>
+#include <linux/sysrq.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/pc_keyb.h>
+
+#include <asm/xilinx_keyb.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+
+
+/* Simple translation table for the SysRq keys */
+
+#define SYSRQ_KEY 0x54
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char xilinx_kbd_sysrq_xlate[128] =
+       "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
+       "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
+       "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
+       "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
+       "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
+       "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 
0x50 - 0x5f */
+       "\r\000/";                                      /* 0x60 - 0x6f */
+#endif
+
+/* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/
+/* 0x00 means not a valid entry or no conversion known                    */
+
+unsigned static char xilinx_kbd_cl[256] =
+{/* 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   a,   b,   c,   d,   e,   
f, */
+ 
0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00,
     /* 0x00 - 0x0f */
+ 
0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00,
     /* 0x10 - 0x1f */
+ 
0x00,0x2e,0x2d,0x20,0x12,0x05,0x04,0x00,0x21,0x39,0x2f,0x21,0x14,0x13,0x06,0x00,
     /* 0x20 - 0x2f  'f' is at 0x2b, what is 0x28 ???*/
+ 
0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00,
     /* 0x30 - 0x3f */
+ 
0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00,
     /* 0x40 - 0x4f */
+ 
0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00,
     /* 0x50 - 0x5f*/
+ 
0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,
     /* 0x60 - 0x6f */
+ 
0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00,
     /* 0x70 - 0x7f */
+ 
0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0x80 - 0x8f  0x84/0x37 is SySrq*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0x90 - 0x9f */
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xa0 - 0xaf */
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xb0 - 0xbf */
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xc0 - 0xcf */
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xd0 - 0xdf */
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xe0 - 0xef */
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xf0 - 0xff */
+};
+
+/* another table, AT 0xe0 codes to PC 0xe0 codes,
+   0xff special entry for SysRq - DROPPED right now  */
+static unsigned char xilinx_kbd_ecl[]=
+{/* 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   a,   b,   c,   d,   e,   
f, */
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0x00 - 0x0f*/
+ 
0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,
     /* 0x10 - 0x1f */
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,
     /* 0x20 - 0x2f*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,
     /* 0x30 - 0x3f*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00,
     /* 0x40 - 0x4f*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,
     /* 0x50 - 0x5f*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,
     /* 0x60 - 0x6f*/
+ 
0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00,
     /* 0x70 - 0x7f*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0x80 - 0x8f*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0x90 - 0x9f*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xa0 - 0xaf*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xb0 - 0xbf*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xc0 - 0xcf*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xd0 - 0xdf*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     /* 0xe0 - 0xef*/
+ 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 
     /* 0xf0 - 0xff*/
+};
+
+
+static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t mouse_controller_lock = SPIN_LOCK_UNLOCKED;
+
+static unsigned int kbd_base=0xe0040000;
+static unsigned int mouse_base=0xe0041000;
+
+static struct aux_queue *queue; /* Mouse data buffer. */
+static int aux_count;
+static atomic_t mouse_reply_expected;
+
+static int __init psaux_init(void);
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL   97
+#define E0_KPSLASH 98
+#define E0_PRSCR   99
+#define E0_RALT    100
+#define E0_BREAK   101  /* (control-pause) */
+#define E0_HOME    102
+#define E0_UP      103
+#define E0_PGUP    104
+#define E0_LEFT    105
+#define E0_RIGHT   106
+#define E0_END     107
+#define E0_DOWN    108
+#define E0_PGDN    109
+#define E0_INS     110
+#define E0_DEL     111
+
+#define E1_PAUSE   119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85           /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86     124
+/* tfj at olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
+  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
+  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
+  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
+  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO   112
+/* LK450 */
+#define E0_F13     113
+#define E0_F14     114
+#define E0_HELP    115
+#define E0_DO      116
+#define E0_F17     117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for  the "OMNI" key and the
+ * right alt key does nada. [kkoller at nyx10.cs.du.edu]
+ */
+#define E0_OK  124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW        125
+#define E0_MSRW        126
+#define E0_MSTM        127
+
+/* this can be changed using setkeys : */
+static unsigned char e0_keys[128] = {
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x00-0x07 */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x08-0x0f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x10-0x17 */
+  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,            /* 0x18-0x1f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x20-0x27 */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x28-0x2f */
+  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,            /* 0x30-0x37 */
+  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,              /* 0x38-0x3f */
+  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,              /* 0x40-0x47 */
+  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 
0x48-0x4f */
+  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,              /* 0x50-0x57 */
+  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,          /* 0x58-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
+  0, 0, 0, 0, 0, 0, 0, E0_MACRO,                     /* 0x68-0x6f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x70-0x77 */
+  0, 0, 0, 0, 0, 0, 0, 0                             /* 0x78-0x7f */
+};
+
+
+int xilinx_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+       if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+         return -EINVAL;
+       if (scancode < 128)
+         high_keys[scancode - SC_LIM] = keycode;
+       else
+         e0_keys[scancode - 128] = keycode;
+       return 0;
+}
+
+int xilinx_kbd_getkeycode(unsigned int scancode)
+{
+       return
+         (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+         (scancode < 128) ? high_keys[scancode - SC_LIM] :
+           e0_keys[scancode - 128];
+}
+
+
+#define disable_keyboard()
+#define enable_keyboard()
+
+
+
+
+int xilinx_kbd_translate(unsigned char scancode, unsigned char *keycode,
+                   char raw_mode)
+{
+       static int prev_scancode;
+
+       /* special prefix scancodes.. */
+       if (scancode == 0xe0 || scancode == 0xe1) {
+               prev_scancode = scancode;
+               return 0;
+       }
+
+       /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
+       if (scancode == 0x00 || scancode == 0xff) {
+               prev_scancode = 0;
+               return 0;
+       }
+
+       scancode &= 0x7f;
+
+       if (prev_scancode) {
+         /*
+          * usually it will be 0xe0, but a Pause key generates
+          * e1 1d 45 e1 9d c5 when pressed, and nothing when released
+          */
+         if (prev_scancode != 0xe0) {
+             if (prev_scancode == 0xe1 && scancode == 0x1d) {
+                 prev_scancode = 0x100;
+                 return 0;
+             } else if (prev_scancode == 0x100 && scancode == 0x45) {
+                 *keycode = E1_PAUSE;
+                 prev_scancode = 0;
+             } else {
+#ifdef KBD_REPORT_UNKN
+                 if (!raw_mode)
+                   printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+#endif
+                 prev_scancode = 0;
+                 return 0;
+             }
+         } else {
+             prev_scancode = 0;
+             /*
+              *  The keyboard maintains its own internal caps lock and
+              *  num lock statuses. In caps lock mode E0 AA precedes make
+              *  code and E0 2A follows break code. In num lock mode,
+              *  E0 2A precedes make code and E0 AA follows break code.
+              *  We do our own book-keeping, so we will just ignore these.
+              */
+             /*
+              *  For my keyboard there is no caps lock mode, but there are
+              *  both Shift-L and Shift-R modes. The former mode generates
+              *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+              *  So, we should also ignore the latter. - aeb at cwi.nl
+              */
+             if (scancode == 0x2a || scancode == 0x36)
+               return 0;
+
+             if (e0_keys[scancode])
+               *keycode = e0_keys[scancode];
+             else {
+#ifdef KBD_REPORT_UNKN
+                 if (!raw_mode)
+                   printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+                          scancode);
+#endif
+                 return 0;
+             }
+         }
+       } else if (scancode >= SC_LIM) {
+           /* This happens with the FOCUS 9000 keyboard
+              Its keys PF1..PF12 are reported to generate
+              55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
+              Moreover, unless repeated, they do not generate
+              key-down events, so we have to zero up_flag below */
+           /* Also, Japanese 86/106 keyboards are reported to
+              generate 0x73 and 0x7d for \ - and \ | respectively. */
+           /* Also, some Brazilian keyboard is reported to produce
+              0x73 and 0x7e for \ ? and KP-dot, respectively. */
+
+         *keycode = high_keys[scancode - SC_LIM];
+
+         if (!*keycode) {
+             if (!raw_mode) {
+#ifdef KBD_REPORT_UNKN
+                 printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+                        " - ignored\n", scancode);
+#endif
+             }
+             return 0;
+         }
+       } else
+         *keycode = scancode;
+       return 1;
+}
+
+char xilinx_kbd_unexpected_up(unsigned char keycode)
+{
+       /* unexpected, but this can happen: maybe this was a key release for a
+          FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
+       if (keycode >= SC_LIM || keycode == 85)
+           return 0;
+       else
+           return 0200;
+}
+
+static int keyup=0;
+static int qprev=0;
+
+static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       unsigned char status;
+       static unsigned char prev_mousebyte;
+
+       spin_lock(&kbd_controller_lock);
+
+       status = readb(mouse_base + INTSTAT);
+       while(status & RX_FULL) {
+
+               unsigned char mousebyte;
+
+               mousebyte=readb(mouse_base + RXREG);
+
+               if (atomic_read(&mouse_reply_expected)) {
+                       if (mousebyte == AUX_ACK) {
+                               atomic_dec(&mouse_reply_expected);
+                               return;
+                       }
+                       atomic_set(&mouse_reply_expected,0);
+               }
+
+               prev_mousebyte=mousebyte;
+               add_mouse_randomness(mousebyte);
+               if(aux_count) {
+                       int head = queue->head;
+
+                       queue->buf[head] = mousebyte;
+                       head = (head + 1) & (AUX_BUF_SIZE-1);
+                       if (head != queue->tail) {
+                               queue->head = head;
+                               kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+                               wake_up_interruptible(&queue->proc_list);
+                       }
+               }
+
+               writeb(status,mouse_base+INTCLR);
+               status=readb(mouse_base + INTSTAT);
+       }
+}
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       unsigned char status;
+
+       spin_lock(&kbd_controller_lock);
+       kbd_pt_regs = regs;
+
+       status = readb(kbd_base + INTSTAT);
+       while(status & RX_FULL) {
+           unsigned char scancode,qcode;
+
+           qcode = readb(kbd_base + RXREG);
+
+           if (qcode != 0xf0)
+             {
+               if (qcode == 0xe0)
+                 {
+                   qprev=0xe0;
+                   handle_scancode(qprev , 1);
+                   goto exit;
+                 }
+
+               scancode=qprev ? xilinx_kbd_ecl[qcode] : xilinx_kbd_cl[qcode];
+               qprev=0;
+               if (!scancode)
+                 {
+                   printk("unknown scancode %x\n",qcode);
+                       writeb(status,kbd_base+INTCLR);
+                   goto exit;
+                 }
+               if (scancode==0xff)  /* SySrq */
+                 scancode=SYSRQ_KEY;
+
+               handle_scancode(scancode, ! keyup );
+               keyup=0;
+               tasklet_schedule(&keyboard_tasklet);
+             }
+           else
+             keyup=1;
+
+               writeb(status,kbd_base+INTCLR);
+           status = readb(kbd_base + INTSTAT);
+
+       }
+exit:
+       spin_unlock(&kbd_controller_lock);
+}
+
+
+#define KBD_NO_DATA    (-1)    /* No data */
+#define KBD_BAD_DATA   (-2)    /* Parity or other error */
+
+void __init xilinx_kbd_init_hw(void)
+{
+
+       /* Reset the keyboard controller */
+       writeb(1,kbd_base+RESET);
+       writeb(0,kbd_base+RESET);
+
+       request_irq(27, keyboard_interrupt, 0, "keyboard", NULL);
+
+       writeb(0x38, kbd_base+INTMSET);
+
+       psaux_init();
+
+}
+
+
+/*
+ * Send a byte to the mouse.
+ */
+
+static inline void aux_write_dev(int val)
+{
+       writeb(val, mouse_base+TXREG);
+}
+
+/*
+ * Send a byte to the mouse & handle returned ack
+ */
+
+static inline void aux_write_ack(int val)
+{
+       aux_write_dev(val);
+       atomic_inc(&mouse_reply_expected);
+}
+
+static unsigned char get_from_queue(void)
+{
+       unsigned char result;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mouse_controller_lock, flags);
+       result = queue->buf[queue->tail];
+       queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+       spin_unlock_irqrestore(&mouse_controller_lock, flags);
+       return result;
+}
+
+static inline int queue_empty(void)
+{
+       return queue->head == queue->tail;
+}
+
+static int fasync_aux(int fd, struct file *filp, int on)
+{
+       int retval;
+
+       retval = fasync_helper(fd, filp, on, &queue->fasync);
+       if (retval < 0)
+               return retval;
+
+       return 0;
+}
+
+
+/*
+ *  * Random magic cookie for the aux device
+ *   */
+#define AUX_DEV ((void *)queue)
+
+static int release_aux(struct inode * inode, struct file * file)
+{
+    lock_kernel();
+    fasync_aux(-1, file, 0);
+    if (--aux_count) {
+        unlock_kernel();
+        return 0;
+    }
+    writeb(0x3f, mouse_base+INTMCLR);  /* Disable controller ints */
+    free_irq(26,AUX_DEV);
+    unlock_kernel();
+    return 0;
+}
+
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+       if (aux_count++) {
+               return 0;
+       }
+       queue->head = queue->tail = 0;      /* Flush input queue */
+       if(request_irq(26, mouse_interrupt, 0, "mouse", AUX_DEV)) {
+               aux_count--;
+               return -EBUSY;
+       }
+    /* Reset the mouse controller */
+    writeb(1,mouse_base+RESET);
+    writeb(0,mouse_base+RESET);
+
+       writeb(0x38, mouse_base+INTMSET);
+
+       aux_write_ack(AUX_ENABLE_DEV);
+       mdelay(2);
+
+       return 0;
+}
+
+/*
+ * Put bytes from input queue to buffer.
+ */
+
+static ssize_t read_aux(struct file * file, char * buffer,
+                                           size_t count, loff_t *ppos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       ssize_t i = count;
+       unsigned char c;
+
+       if (queue_empty()) {
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               add_wait_queue(&queue->proc_list, &wait);
+repeat:
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (queue_empty() && !signal_pending(current)) {
+                               schedule();
+                       goto repeat;
+               }
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&queue->proc_list, &wait);
+       }
+       while (i > 0 && !queue_empty()) {
+               c = get_from_queue();
+               put_user(c, buffer++);
+               i--;
+       }
+       if (count-i) {
+               file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+               return count-i;
+       }
+       if (signal_pending(current))
+               return -ERESTARTSYS;
+       return 0;
+}
+
+/*
+ * Write to the aux device.
+ */
+
+static ssize_t write_aux(struct file * file, const char * buffer,
+                                            size_t count, loff_t *ppos)
+{
+       ssize_t retval = 0;
+
+    if (count) {
+        ssize_t written = 0;
+               if (count > 32)
+               count = 32; /* Limit to 32 bytes. */
+               do {
+                       char c;
+                       get_user(c, buffer++);
+                       aux_write_dev(c);
+                       written++;
+               } while (--count);
+               retval = -EIO;
+               if (written) {
+                       retval = written;
+                       file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+               }
+       }
+
+       return retval;
+}
+
+/* No kernel lock held - fine */
+static unsigned int aux_poll(struct file *file, poll_table * wait)
+{
+    poll_wait(file, &queue->proc_list, wait);
+    if (!queue_empty())
+        return POLLIN | POLLRDNORM;
+    return 0;
+}
+
+struct file_operations psaux_fops = {
+    read:       read_aux,
+    write:      write_aux,
+    poll:       aux_poll,
+    open:       open_aux,
+    release:    release_aux,
+    fasync:     fasync_aux,
+};
+
+static struct miscdevice psaux_mouse = {
+    PSMOUSE_MINOR, "psaux", &psaux_fops
+};
+
+static int __init psaux_init(void) {
+
+       int retval;
+
+       if ((retval = misc_register(&psaux_mouse)))
+               return retval;
+
+    queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+    if (queue == NULL) {
+        printk(KERN_ERR "psaux_init(): out of memory\n");
+        misc_deregister(&psaux_mouse);
+        return -ENOMEM;
+    }
+
+       memset(queue, 0, sizeof(*queue));
+       queue->head = queue->tail = 0;
+       init_waitqueue_head(&queue->proc_list);
+
+       aux_write_ack(AUX_SET_SAMPLE);
+       aux_write_ack(100);
+       aux_write_ack(AUX_SET_RES);
+       aux_write_ack(3);
+       aux_write_ack(AUX_SET_SCALE21);
+       writeb(0x3f,mouse_base + INTMCLR);
+       return 0;
+}
diff -urN -x CVS -x config -x modules -x mtd -x jffs2 -x jffs 
linuxppc_2_4_clean/include/asm-ppc/xilinx_keyb.h 
linuxppc_2_4_xseg2.new.clean2/include/asm-ppc/xilinx_keyb.h
--- linuxppc_2_4_clean/include/asm-ppc/xilinx_keyb.h    1970-01-01 
01:00:00.000000000 +0100
+++ linuxppc_2_4_xseg2.new.clean2/include/asm-ppc/xilinx_keyb.h 2002-09-04 
21:39:11.000000000 +0200
@@ -0,0 +1,43 @@
+/*
+ * xilinx_keyb.h: A driver for Xilinx PS/2 keyboard and mouse interface core
+ *
+ * Copyright 2002 Mind NV
+ *
+ * http://www.mind.be/
+ *
+ * Author : Peter De Schrijver (p2 at mind.be)
+ *
+ * Derived from : drivers/char/q40_keyb.c
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL) version 2, incorporated herein by
+ * reference. Drivers based on or derived from this code fall under the GPL
+ * and must retain the authorship, copyright and this license notice. This
+ * file is not a complete program and may only be used when the entire
+ * operating system is licensed under the GPL.
+ *
+ */
+#ifndef _XILINX_KEYB_H
+#define _XILINX_KEYB_H
+
+/* PS/2 controller register offsets */
+
+#define RESET  0
+#define STATUS 4
+#define RXREG  8
+#define TXREG  12
+#define INTSTAT 16
+#define INTCLR 20
+#define INTMSET        24
+#define INTMCLR        28
+
+/* PS/2 controller interrupt bits */
+
+#define WDTIMEOUT      1
+#define        TX_NOACK        2
+#define TX_ACK         4
+#define RX_OVER                8
+#define RX_ERR         16
+#define RX_FULL                32
+
+#endif

Reply via email to