]> git.neil.brown.name Git - history.git/commitdiff
Add keyboard, mouse and touchscreen drivers.
authorVojtech Pavlik <vojtech@twilight.ucw.cz>
Wed, 3 Jul 2002 17:08:45 +0000 (19:08 +0200)
committerVojtech Pavlik <vojtech@twilight.ucw.cz>
Wed, 3 Jul 2002 17:08:45 +0000 (19:08 +0200)
Add tsdev, power and evbug event handlers.

30 files changed:
drivers/input/Config.help
drivers/input/Config.in
drivers/input/Makefile
drivers/input/evbug.c [new file with mode: 0644]
drivers/input/keyboard/Config.help [new file with mode: 0644]
drivers/input/keyboard/Config.in [new file with mode: 0644]
drivers/input/keyboard/Makefile [new file with mode: 0644]
drivers/input/keyboard/amikbd.c [new file with mode: 0644]
drivers/input/keyboard/atkbd.c [new file with mode: 0644]
drivers/input/keyboard/maple_keyb.c [new file with mode: 0644]
drivers/input/keyboard/ps2serkbd.c [new file with mode: 0644]
drivers/input/keyboard/sunkbd.c [new file with mode: 0644]
drivers/input/keyboard/xtkbd.c [new file with mode: 0644]
drivers/input/mouse/Config.help [new file with mode: 0644]
drivers/input/mouse/Config.in [new file with mode: 0644]
drivers/input/mouse/Makefile [new file with mode: 0644]
drivers/input/mouse/amimouse.c [new file with mode: 0644]
drivers/input/mouse/inport.c [new file with mode: 0644]
drivers/input/mouse/logibm.c [new file with mode: 0644]
drivers/input/mouse/maplemouse.c [new file with mode: 0644]
drivers/input/mouse/pc110pad.c [new file with mode: 0644]
drivers/input/mouse/psmouse.c [new file with mode: 0644]
drivers/input/mouse/rpcmouse.c [new file with mode: 0644]
drivers/input/mouse/sermouse.c [new file with mode: 0644]
drivers/input/power.c [new file with mode: 0644]
drivers/input/touchscreen/Config.help [new file with mode: 0644]
drivers/input/touchscreen/Config.in [new file with mode: 0644]
drivers/input/touchscreen/Makefile [new file with mode: 0644]
drivers/input/touchscreen/gunze.c [new file with mode: 0644]
drivers/input/tsdev.c [new file with mode: 0644]

index 15bc1aab59bdea0298327c97d263a93888d735cb..e75624d0917d48e75f85adb81099b27f0463cd1a 100644 (file)
@@ -64,6 +64,18 @@ CONFIG_INPUT_JOYDEV
   The module will be called joydev.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_INPUT_TSDEV
+  Say Y here if you have an application that only can understand the
+  Compaq touchscreen protocol for absolute pointer data. This is
+  useful namely for embedded configurations.
+
+  If unsure, say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tsdev.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 CONFIG_INPUT_EVDEV
   Say Y here if you want your input device events be accessible
   under char device 13:64+ - /dev/input/eventX in a generic way.
@@ -72,3 +84,17 @@ CONFIG_INPUT_EVDEV
   inserted in and removed from the running kernel whenever you want).
   The module will be called evdev.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_EVBUG
+  Say Y here if you have a problem with the input subsystem and
+  want all events (keypresses, mouse movements), to be output to
+  the system log. While this is useful for debugging, it's also
+  a security threat - your keypresses include your passwords, of
+  course.
+
+  If unsure, say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called joydev.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
index 66b2aa72897eb8490a976776596fa7f81a3a0573..7105ceb2f7a6f0e2e9032c31e952864ec73147c7 100644 (file)
@@ -6,20 +6,34 @@ mainmenu_option next_comment
 comment 'Input device support'
 
 tristate 'Input core support' CONFIG_INPUT
+
+comment 'Userland interfaces'
 dep_tristate '  Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
 dep_tristate '  Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
+dep_mbool '    Provide legacy /dev/psaux device' CONFIG_INPUT_MOUSEDEV_PSAUX $CONFIG_INPUT
 if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
    int '   Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
    int '   Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
 fi
 dep_tristate '  Joystick interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
+dep_tristate '  Touchscreen interface' CONFIG_INPUT_TSDEV $CONFIG_INPUT
+if [ "$CONFIG_INPUT_TSDEV" != "n" ]; then
+   int '   Horizontal screen resolution' CONFIG_INPUT_TSDEV_SCREEN_X 240
+   int '   Vertical screen resolution' CONFIG_INPUT_TSDEV_SCREEN_Y 320 
+fi
 dep_tristate '  Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+dep_tristate '  Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT
 
+comment 'Input I/O drivers'
 source drivers/input/gameport/Config.in
 source drivers/input/serio/Config.in
 
+comment 'Input Device Drivers'
 if [ "$CONFIG_INPUT" != "n" ]; then
+   source drivers/input/keyboard/Config.in
+   source drivers/input/mouse/Config.in
    source drivers/input/joystick/Config.in
+   source drivers/input/touchscreen/Config.in
 fi
 
 endmenu
index bdb70aa4a9969a82fab7e6fd8f69e37a78cc1de7..d6a6478764562514a2bc739c6a0d99ce10ac29c8 100644 (file)
@@ -13,8 +13,14 @@ obj-$(CONFIG_INPUT_KEYBDEV)  += keybdev.o
 obj-$(CONFIG_INPUT_MOUSEDEV)   += mousedev.o
 obj-$(CONFIG_INPUT_JOYDEV)     += joydev.o
 obj-$(CONFIG_INPUT_EVDEV)      += evdev.o
+obj-$(CONFIG_INPUT_TSDEV)      += tsdev.o
+obj-$(CONFIG_INPUT_POWER)      += power.o
+obj-$(CONFIG_INPUT_EVBUG)      += evbug.o
 
+obj-$(CONFIG_INPUT_KEYBOARD)   += keyboard/
+obj-$(CONFIG_INPUT_MOUSE)      += mouse/
 obj-$(CONFIG_INPUT_JOYSTICK)   += joystick/
+obj-$(CONFIG_INPUT_TOUCHSCREEN)        += touchscreen/
 
 # The global Rules.make.
 
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
new file mode 100644 (file)
index 0000000..1b91f24
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * $Id: evbug.c,v 1.10 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ *  Input driver event debug module - dumps all events into syslog
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Input driver event debug module"); 
+MODULE_LICENSE("GPL");
+
+static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+{
+       printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
+}
+
+static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
+{
+       struct input_handle *handle;
+
+       if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+               return NULL;
+       memset(handle, 0, sizeof(struct input_handle));
+
+       handle->dev = dev;
+       handle->handler = handler;
+
+       input_open_device(handle);
+
+       printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
+
+       return handle;
+}
+
+static void evbug_disconnect(struct input_handle *handle)
+{
+       printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
+       
+       input_close_device(handle);
+
+       kfree(handle);
+}
+
+static struct input_device_id evbug_ids[] = {
+       { driver_info: 1 },     /* Matches all devices */
+       { },                    /* Terminating zero entry */
+};
+
+MODULE_DEVICE_TABLE(input, evbug_ids);
+       
+static struct input_handler evbug_handler = {
+       event:          evbug_event,
+       connect:        evbug_connect,
+       disconnect:     evbug_disconnect,
+       name:           "evbug",
+       id_table:       evbug_ids,
+};
+
+int __init evbug_init(void)
+{
+       input_register_handler(&evbug_handler);
+       return 0;
+}
+
+void __exit evbug_exit(void)
+{
+       input_unregister_handler(&evbug_handler);
+}
+
+module_init(evbug_init);
+module_exit(evbug_exit);
diff --git a/drivers/input/keyboard/Config.help b/drivers/input/keyboard/Config.help
new file mode 100644 (file)
index 0000000..3d7df5a
--- /dev/null
@@ -0,0 +1,66 @@
+CONFIG_INPUT_KEYBOARD
+  Say Y here, and a list of supported keyboards will be displayed.
+  This option doesn't affect the kernel.
+
+  If unsure, say Y.
+
+CONFIG_KEYBOARD_ATKBD
+  Say Y here if you want to use the standard AT keyboard. Usually
+  you'll need this, unless you have a different type keyboard (USB,
+  ADB or other).
+
+  If unsure, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called atkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_SUNKBD
+  Say Y here if you want to use a Sun Type 4 or Type 5 keyboard,
+  connected either to the Sun keyboard connector or to an serial
+  (RS-232) port via a simple adapter.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called sunkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_PS2SERKBD
+  Say Y here if you want to use a PS/2 to Serial converter with a
+  keyboard attached to it.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ps2serkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_XTKBD
+  Say Y here if you want to use the old IBM PC/XT keyboard (or
+  compatible) on your system. This is only possible with a
+  parallel port keyboard adapter, you cannot connect it to the
+  keyboard port on a PC that runs Linux. 
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called xtkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_MAPLE  
+  Say Y here if you have a DreamCast console running Linux and have
+  a keyboard attached to its Maple bus.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called maple_keyb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_AMIGA
+  Say Y here if you are running Linux on any AMIGA and have a keyboard
+  attached.    
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called amikbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
diff --git a/drivers/input/keyboard/Config.in b/drivers/input/keyboard/Config.in
new file mode 100644 (file)
index 0000000..f7f7128
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Input core configuration
+#
+
+bool 'Keyboards' CONFIG_INPUT_KEYBOARD
+
+dep_tristate '  AT keyboard support' CONFIG_KEYBOARD_ATKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate '  Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate '  PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate '  XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+   dep_tristate '  Maple bus keyboard support' CONFIG_KEYBOARD_MAPLE $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_MAPLE
+fi
+
+if [ "$CONFIG_AMIGA" = "y" ]; then
+   dep_tristate '  Amiga keyboard' CONFIG_KEYBOARD_AMIGA $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD
+fi
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
new file mode 100644 (file)
index 0000000..5b6796b
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Makefile for the input core drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET       := keybdrv.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_KEYBOARD_ATKBD)           += atkbd.o
+obj-$(CONFIG_KEYBOARD_MAPLE)           += maple_keyb.o
+obj-$(CONFIG_KEYBOARD_PS2SERKBD)       += ps2serkbd.o
+obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
+obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
+obj-$(CONFIG_KEYBOARD_AMIGA)           += amikbd.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
new file mode 100644 (file)
index 0000000..330b336
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *     Hamish Macdonald
+ */
+
+/*
+ * Amiga keyboard driver for Linux/m68k
+ */
+
+/*
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Amiga keyboard driver");
+MODULE_LICENSE("GPL");
+
+static unsigned char amikbd_keycode[0x78] = {
+        41,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 43,  0, 82,
+        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,  0, 79, 80, 81,
+        30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  0,  0, 75, 76, 77,
+         0, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,  0, 83, 71, 72, 73,
+        57, 14, 15, 96, 28,  1,111,  0,  0,  0, 74,  0,103,108,106,105,
+        59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 98, 55, 78, 87,
+        42, 54, 58, 29, 56,100
+}
+
+static char *amikbd_messages[] = {
+       KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",
+       KERN_WARNING "amikbd: keyboard lost sync\n",
+       KERN_WARNING "amikbd: keyboard buffer overflow\n",
+       KERN_WARNING "amikbd: keyboard controller failure\n",
+       KERN_ERR "amikbd: keyboard selftest failure\n",
+       KERN_INFO "amikbd: initiate power-up key stream\n",
+       KERN_INFO "amikbd: terminate power-up key stream\n",
+       KERN_WARNING "amikbd: keyboard interrupt\n"
+};
+
+static struct input_dev amikbd_dev;
+
+static char *amikbd_name = "Amiga keyboard";
+static char *amikbd_phys = "amikbd/input0";
+
+static void amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+       unsigned char scancode, down;
+
+       scancode = ~ciaa.sdr;           /* get and invert scancode (keyboard is active low) */
+       ciaa.cra |= 0x40;               /* switch SP pin to output for handshake */
+       udelay(85);                     /* wait until 85 us have expired */
+       ciaa.cra &= ~0x40;              /* switch CIA serial port to input mode */
+
+       down = scancode & 1;            /* lowest bit is release bit */
+       scancode = scancode >> 1;
+
+       if (scancode < 0x78) {          /* scancodes < 0x78 are keys */
+
+               scancode = amikbd_keycode[scancode];
+       
+               if (scancode == KEY_CAPS) {     /* CapsLock is a toggle switch key on Amiga */
+                       input_report_key(&amikbd_dev, scancode, 1);
+                       input_report_key(&amikbd_dev, scancode, 0);
+                       return;
+               }
+               
+               input_report_key(&amikbd_dev, scancode, down);
+
+               return;
+       }
+
+       printk(amikbd_messages[scancode - 0x78]);       /* scancodes >= 0x78 are error codes */
+}
+
+static int __init amikbd_init(void)
+{
+       int i;
+
+       if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
+               return -EIO;
+
+       if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))   
+               return -EBUSY;
+
+       amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);        
+       amikbd_dev.keycode = amikbd_keycode;
+       
+       for (i = 0; i < 0x78; i++)
+               if (amikbd_keycode[i])
+                       set_bit(amikbd_keycode[i], amikbd_dev.keybit);
+
+       ciaa.cra &= ~0x41;       /* serial data in, turn off TA */
+       request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", NULL);
+
+       amikbd_dev.name = amikbd_name;
+       amikbd_dev.phys = amikbd_phys;
+       amikbd_dev.idbus = BUS_AMIGA;
+       amikbd_dev.idvendor = 0x0001;
+       amikbd_dev.idproduct = 0x0001;
+       amikbd_dev.idversion = 0x0100;
+
+       input_register_device(&amikbd_dev);
+
+       printk(KERN_INFO "input: %s\n", amikbd_name);
+
+       return 0;
+}
+
+static void __exit amikbd_exit(void)
+{
+       input_unregister_device(&amikbd_dev);
+       free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
+       release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100);
+}
+
+module_init(amikbd_init);
+module_exit(amikbd_exit);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
new file mode 100644 (file)
index 0000000..5a8f6b9
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * $Id: atkbd.c,v 1.31 2002/01/27 01:48:54 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
+MODULE_PARM(atkbd_set, "1i");
+MODULE_LICENSE("GPL");
+
+static int atkbd_set = 2;
+
+/*
+ * Scancode to keycode tables. These are just the default setting, and
+ * are loadable via an userland utility.
+ */
+
+static unsigned char atkbd_set2_keycode[512] = {
+         0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41, 85,
+         0, 56, 42,  0, 29, 16,  2, 89,  0,  0, 44, 31, 30, 17,  3, 90,
+         0, 46, 45, 32, 18,  5,  4, 91,  0, 57, 47, 33, 20, 19,  6,  0,
+         0, 49, 48, 35, 34, 21,  7,  0,  0,  0, 50, 36, 22,  8,  9,  0,
+         0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
+       122, 89, 40,120, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0,  0,
+        85, 86, 90, 91, 92, 93, 14, 94, 95, 79,  0, 75, 71,121,  0,123,
+        82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+       252,  0,  0, 65, 99,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,251,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       252,253,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       254,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,255,
+         0,  0, 92, 90, 85,  0,137,  0,  0,  0,  0, 91, 89,144,115,  0,
+       136,100,255,  0, 97,149,164,  0,156,  0,  0,140,115,  0,  0,125,
+         0,150,  0,154,152,163,151,126,112,166,  0,140,  0,147,  0,127,
+       159,167,139,160,163,  0,  0,116,158,  0,150,165,  0,  0,  0,142,
+       157,  0,114,166,168,  0,  0,  0,155,  0, 98,113,  0,148,  0,138,
+         0,  0,  0,  0,  0,  0,153,140,  0,255, 96,  0,  0,  0,143,  0,
+       133,  0,116,  0,143,  0,174,133,  0,107,  0,105,102,  0,  0,112,
+       110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119
+};
+
+static unsigned char atkbd_set3_keycode[512] = {
+         0,  0,  0,  0,  0,  0,  0, 59,  1,138,128,129,130, 15, 41, 60,
+       131, 29, 42, 86, 58, 16,  2, 61,133, 56, 44, 31, 30, 17,  3, 62,
+       134, 46, 45, 32, 18,  5,  4, 63,135, 57, 47, 33, 20, 19,  6, 64,
+       136, 49, 48, 35, 34, 21,  7, 65,137,100, 50, 36, 22,  8,  9, 66,
+       125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,
+       113,114, 40, 84, 26, 13, 87, 99,100, 54, 28, 27, 43, 84, 88, 70,
+       108,105,119,103,111,107, 14,110,  0, 79,106, 75, 71,109,102,104,
+        82, 83, 80, 76, 77, 72, 69, 98,  0, 96, 81,  0, 78, 73, 55, 85,
+        89, 90, 91, 92, 74,  0,  0,  0,  0,  0,  0,125,126,127,112,  0,
+         0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,
+       148,149,147,140,  0,  0,  0,  0,  0,  0,251,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       252,253,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+       254,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,255
+};
+
+#define ATKBD_CMD_SETLEDS      0x10ed
+#define ATKBD_CMD_GSCANSET     0x11f0
+#define ATKBD_CMD_SSCANSET     0x10f0
+#define ATKBD_CMD_GETID                0x02f2
+#define ATKBD_CMD_ENABLE       0x00f4
+#define ATKBD_CMD_RESET_DIS    0x00f5
+#define ATKBD_CMD_SETALL_MB    0x00f8
+#define ATKBD_CMD_EX_ENABLE    0x10ea
+#define ATKBD_CMD_EX_SETLEDS   0x20eb
+
+#define ATKBD_RET_ACK          0xfa
+#define ATKBD_RET_NAK          0xfe
+
+#define ATKBD_KEY_UNKNOWN        0
+#define ATKBD_KEY_BAT          251
+#define ATKBD_KEY_EMUL0                252
+#define ATKBD_KEY_EMUL1                253
+#define ATKBD_KEY_RELEASE      254
+#define ATKBD_KEY_NULL         255
+
+/*
+ * The atkbd control structure
+ */
+
+struct atkbd {
+       unsigned char keycode[512];
+       struct input_dev dev;
+       struct serio *serio;
+       char name[64];
+       char phys[32];
+       struct tq_struct tq;
+       unsigned char cmdbuf[4];
+       unsigned char cmdcnt;
+       unsigned char set;
+       char release;
+       char ack;
+       char emul;
+       char error;
+       unsigned short id;
+};
+
+/*
+ * atkbd_interrupt(). Here takes place processing of data received from
+ * the keyboard into events.
+ */
+
+static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+       struct atkbd *atkbd = serio->private;
+       int code = data;
+
+#ifdef ATKBD_DEBUG
+       printk(KERN_DEBUG "atkbd.c: Received %02x\n", data);
+#endif
+
+       switch (code) {
+               case ATKBD_RET_ACK:
+                       atkbd->ack = 1;
+                       return;
+               case ATKBD_RET_NAK:
+                       atkbd->ack = -1;
+                       return;
+       }
+
+       if (atkbd->cmdcnt) {
+               atkbd->cmdbuf[--atkbd->cmdcnt] = code;
+               return;
+       }
+
+       switch (atkbd->keycode[code]) {
+               case ATKBD_KEY_BAT:
+                       queue_task(&atkbd->tq, &tq_immediate);
+                       mark_bh(IMMEDIATE_BH);
+                       return;
+               case ATKBD_KEY_EMUL0:
+                       atkbd->emul = 1;
+                       return;
+               case ATKBD_KEY_EMUL1:
+                       atkbd->emul = 2;
+                       return;
+               case ATKBD_KEY_RELEASE:
+                       atkbd->release = 1;
+                       return;
+       }
+
+       if (atkbd->emul) {
+               if (--atkbd->emul) return;
+               code |= 0x100;
+       }
+
+       switch (atkbd->keycode[code]) {
+               case ATKBD_KEY_NULL:
+                       break;
+               case ATKBD_KEY_UNKNOWN:
+                       printk(KERN_WARNING "atkbd.c: Unknown key (set %d, scancode %#x, on %s) %s.\n",
+                               atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed");
+                       break;
+               default:
+                       input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release);
+       }
+               
+       atkbd->release = 0;
+}
+
+/*
+ * atkbd_sendbyte() sends a byte to the keyboard, and waits for
+ * acknowledge. It doesn't handle resends according to the keyboard
+ * protocol specs, because if these are needed, the keyboard needs
+ * replacement anyway, and they only make a mess in the protocol.
+ */
+
+static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
+{
+       int timeout = 1000; /* 10 msec */
+       atkbd->ack = 0;
+
+#ifdef ATKBD_DEBUG
+       printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
+#endif
+       serio_write(atkbd->serio, byte);
+       while (!atkbd->ack && timeout--) udelay(10);
+
+       return -(atkbd->ack <= 0);
+}
+
+/*
+ * atkbd_command() sends a command, and its parameters to the keyboard,
+ * then waits for the response and puts it in the param array.
+ */
+
+static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
+{
+       int timeout = 10000; /* 100 msec */
+       int send = (command >> 12) & 0xf;
+       int receive = (command >> 8) & 0xf;
+       int i;
+
+       atkbd->cmdcnt = receive;
+       
+       if (command & 0xff)
+               if (atkbd_sendbyte(atkbd, command & 0xff))
+                       return (atkbd->cmdcnt = 0) - 1;
+
+       for (i = 0; i < send; i++)
+               if (atkbd_sendbyte(atkbd, param[i]))
+                       return (atkbd->cmdcnt = 0) - 1;
+
+       while (atkbd->cmdcnt && timeout--) udelay(10);
+
+       for (i = 0; i < receive; i++)
+               param[i] = atkbd->cmdbuf[(receive - 1) - i];
+
+       if (atkbd->cmdcnt) 
+               return (atkbd->cmdcnt = 0) - 1;
+
+       return 0;
+}
+
+/*
+ * Event callback from the input module. Events that change the state of
+ * the hardware are processed here.
+ */
+
+static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+       struct atkbd *atkbd = dev->private;
+       char param[2];
+
+       switch (type) {
+
+               case EV_LED:
+
+                       *param = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
+                              | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
+                              | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
+                       atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS);
+
+                       if (atkbd->set == 4) {
+                               param[0] = 0;
+                               param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
+                                        | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
+                                        | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
+                                        | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
+                               atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
+                       }
+
+                       return 0;
+       }
+
+       return -1;
+}
+
+/*
+ * atkbd_set_3 checks if a keyboard has a working Set 3 support, and
+ * sets it into that. Unfortunately there are keyboards that can be switched
+ * to Set 3, but don't work well in that (BTC Multimedia ...)
+ */
+
+static int atkbd_set_3(struct atkbd *atkbd)
+{
+       unsigned char param;
+
+/*
+ * For known special keyboards we can go ahead and set the correct set.
+ */
+
+       if (atkbd->id == 0xaca1) {
+               param = 3;
+               atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET);
+               return 3;
+       }
+
+/*
+ * We check for the extra keys on an some keyboards that need extra
+ * command to get enabled. This shouldn't harm any keyboards not
+ * knowing the command.
+ */
+
+       param = 0x71;
+       if (!atkbd_command(atkbd, &param, ATKBD_CMD_EX_ENABLE))
+               return 4;
+
+/*
+ * Try to set the set we want.
+ */
+
+       param = atkbd_set;
+       if (atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET))
+               return 2;
+
+/*
+ * Read set number. Beware here. Some keyboards always send '2'
+ * or some other number regardless into what mode they have been
+ * attempted to be set. Other keyboards treat the '0' command as
+ * 'set to set 0', and not 'report current set' as they should.
+ * In that case we time out, and return 2.
+ */
+
+       param = 0;
+       if (atkbd_command(atkbd, &param, ATKBD_CMD_GSCANSET))
+               return 2;
+
+/*
+ * Here we return the set number the keyboard reports about
+ * itself.
+ */
+
+       return (param == 3) ? 3 : 2;
+}
+
+/*
+ * atkbd_probe() probes for an AT keyboard on a serio port.
+ */
+
+static int atkbd_probe(struct atkbd *atkbd)
+{
+       unsigned char param[2];
+
+/*
+ * Full reset with selftest can on some keyboards be annoyingly slow,
+ * so we just do a reset-and-disable on the keyboard, which
+ * is considerably faster, but doesn't have to reset everything.
+ */
+
+       if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS))
+               return -1;
+
+/*
+ * Next, we check if it's a keyboard. It should send 0xab83
+ * (0xab84 on IBM ThinkPad, and 0xaca1 on a NCD Sun layout keyboard,
+ * 0xab02 on unxlated i8042 and 0xab03 on unxlated ThinkPad, 0xab7f
+ * on Fujitsu Lifebook).
+ * If it's a mouse, it'll only send 0x00 (0x03 if it's MS mouse),
+ * and we'll time out here, and report an error.
+ */
+
+       param[0] = param[1] = 0;
+
+       if (atkbd_command(atkbd, param, ATKBD_CMD_GETID))
+               return -1;
+
+       atkbd->id = (param[0] << 8) | param[1];
+
+       if (atkbd->id != 0xab83 && atkbd->id != 0xab84 && atkbd->id != 0xaca1 &&
+           atkbd->id != 0xab7f && atkbd->id != 0xab02 && atkbd->id != 0xab03)
+               printk(KERN_WARNING "atkbd.c: Unusual keyboard ID: %#x on %s\n",
+                       atkbd->id, atkbd->serio->phys);
+
+       return 0;
+}
+
+/*
+ * atkbd_initialize() sets the keyboard into a sane state.
+ */
+
+static void atkbd_initialize(struct atkbd *atkbd)
+{
+       unsigned char param;    
+
+/*
+ * Disable autorepeat. We don't need it, as we do it in software anyway,
+ * because that way can get faster repeat, and have less system load
+ * (less accesses to the slow ISA hardware). If this fails, we don't care,
+ * and will just ignore the repeated keys.
+ */
+
+       atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB);
+
+/*
+ * We also shut off all the leds. The console code will turn them back on,
+ * if needed.
+ */
+
+       param = 0;
+       atkbd_command(atkbd, &param, ATKBD_CMD_SETLEDS);
+
+/*
+ * Last, we enable the keyboard so that we get keypresses from it.
+ */
+
+       if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE))
+               printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
+                       atkbd->serio->phys);
+}
+
+/*
+ * atkbd_disconnect() cleans up behind us ...
+ */
+
+static void atkbd_disconnect(struct serio *serio)
+{
+       struct atkbd *atkbd = serio->private;
+       input_unregister_device(&atkbd->dev);
+       serio_close(serio);
+       kfree(atkbd);
+}
+
+/*
+ * atkbd_powerup() is called when the keyboard sends the 0xaa character,
+ * meaning that it was disconnected and reconnected. We close the port
+ * in that case and let the upper layer find an appropriate driver for
+ * the device that was connected. It may be a mouse, or a keyboard, we
+ * don't know yet.
+ */
+
+static void atkbd_powerup(void *data)
+{
+       struct atkbd *atkbd = data;
+       mdelay(40); /* FIXME!!! Wait some nicer way */
+       serio_rescan(atkbd->serio);
+}
+
+/*
+ * atkbd_connect() is called when the serio module finds and interface
+ * that isn't handled yet by an appropriate device driver. We check if
+ * there is an AT keyboard out there and if yes, we register ourselves
+ * to the input module.
+ */
+
+static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+       struct atkbd *atkbd;
+       int i;
+
+       if ((serio->type & SERIO_TYPE) != SERIO_8042)
+               return;
+
+       if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL)))
+               return;
+
+       memset(atkbd, 0, sizeof(struct atkbd));
+
+       atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+       atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+
+       atkbd->serio = serio;
+
+       atkbd->dev.keycode = atkbd->keycode;
+       atkbd->dev.event = atkbd_event;
+       atkbd->dev.private = atkbd;
+
+       atkbd->tq.routine = atkbd_powerup;
+       atkbd->tq.data = atkbd;
+
+       serio->private = atkbd;
+
+       if (serio_open(serio, dev)) {
+               kfree(atkbd);
+               return;
+       }
+
+       if (atkbd_probe(atkbd)) {
+               serio_close(serio);
+               kfree(atkbd);
+               return;
+       }
+       
+       atkbd->set = atkbd_set_3(atkbd);
+
+       if (atkbd->set == 4) {
+               atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE);
+               sprintf(atkbd->name, "AT Set 2 Extended keyboard\n");
+       } else
+               sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set);
+
+       sprintf(atkbd->phys, "%s/input0", serio->phys);
+
+       if (atkbd->set == 3)
+               memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
+       else
+               memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
+
+       atkbd->dev.name = atkbd->name;
+       atkbd->dev.phys = atkbd->phys;
+       atkbd->dev.idbus = BUS_I8042;
+       atkbd->dev.idvendor = 0x0001;
+       atkbd->dev.idproduct = atkbd->set;
+       atkbd->dev.idversion = atkbd->id;
+
+       for (i = 0; i < 512; i++)
+               if (atkbd->keycode[i] && atkbd->keycode[i] <= 250)
+                       set_bit(atkbd->keycode[i], atkbd->dev.keybit);
+
+       input_register_device(&atkbd->dev);
+
+       printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
+
+       atkbd_initialize(atkbd);
+}
+
+
+static struct serio_dev atkbd_dev = {
+       interrupt:      atkbd_interrupt,
+       connect:        atkbd_connect,
+       disconnect:     atkbd_disconnect
+};
+
+/*
+ * Module init and exit.
+ */
+
+void __init atkbd_setup(char *str, int *ints)
+{
+       if (!ints[0]) atkbd_set = ints[1];
+}
+
+int __init atkbd_init(void)
+{
+       serio_register_device(&atkbd_dev);
+       return 0;
+}
+
+void __exit atkbd_exit(void)
+{
+       serio_unregister_device(&atkbd_dev);
+}
+
+module_init(atkbd_init);
+module_exit(atkbd_exit);
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
new file mode 100644 (file)
index 0000000..feaea91
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *     $Id: maple_keyb.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $
+ *     SEGA Dreamcast keyboard driver
+ *     Based on drivers/usb/usbkbd.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/maple.h>
+
+MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
+MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
+
+static unsigned char dc_kbd_keycode[256] = {
+         0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+        50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+         4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+        27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+        65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+       105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+        72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,
+       120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
+       115,114,  0,  0,  0,124,  0,181,182,183,184,185,186,187,188,189,
+       190,191,192,193,194,195,196,197,198,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+        29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+       150,158,159,128,136,177,178,176,142,152,173,140
+};
+
+
+struct dc_kbd {
+       struct input_dev dev;
+       unsigned char new[8];
+       unsigned char old[8];
+       int open;
+};
+
+
+static void dc_scan_kbd(struct dc_kbd *kbd)
+{
+       int i;
+       struct input_dev *dev = &kbd->dev;
+
+       for(i=0; i<8; i++)
+               input_report_key(dev,
+                                dc_kbd_keycode[i+224],
+                                (kbd->new[0]>>i)&1);
+
+       for(i=2; i<8; i++) {
+
+               if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) {
+                       if(dc_kbd_keycode[kbd->old[i]])
+                               input_report_key(dev,
+                                                dc_kbd_keycode[kbd->old[i]],
+                                                0);
+                       else
+                               printk("Unknown key (scancode %#x) released.",
+                                      kbd->old[i]);
+               }
+
+               if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) {
+                       if(dc_kbd_keycode[kbd->new[i]])
+                               input_report_key(dev,
+                                                dc_kbd_keycode[kbd->new[i]],
+                                                1);
+                       else
+                               printk("Unknown key (scancode %#x) pressed.",
+                                      kbd->new[i]);
+               }
+       }
+
+       memcpy(kbd->old, kbd->new, 8);
+}
+
+
+static void dc_kbd_callback(struct mapleq *mq)
+{
+       struct maple_device *mapledev = mq->dev;
+       struct dc_kbd *kbd = mapledev->private_data;
+       unsigned long *buf = mq->recvbuf;
+
+       if (buf[1] == mapledev->function) {
+               memcpy(kbd->new, buf+2, 8);
+               dc_scan_kbd(kbd);
+       }
+}
+
+
+static int dc_kbd_open(struct input_dev *dev)
+{
+       struct dc_kbd *kbd = dev->private;
+       kbd->open++;
+       return 0;
+}
+
+
+static void dc_kbd_close(struct input_dev *dev)
+{
+       struct dc_kbd *kbd = dev->private;
+       kbd->open--;
+}
+
+
+static int dc_kbd_connect(struct maple_device *dev)
+{
+       int i;
+       unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
+       struct dc_kbd *kbd;
+
+       if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL)))
+               return -1;
+       memset(kbd, 0, sizeof(struct dc_kbd));
+
+       dev->private_data = kbd;
+
+       kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+       for (i=0; i<255; i++)
+               set_bit(dc_kbd_keycode[i], kbd->dev.keybit);
+       clear_bit(0, kbd->dev.keybit);
+
+       kbd->dev.private = kbd;
+       kbd->dev.open = dc_kbd_open;
+       kbd->dev.close = dc_kbd_close;
+       kbd->dev.event = NULL;
+
+       kbd->dev.name = dev->product_name;
+       kbd->dev.idbus = BUS_MAPLE;
+       
+       input_register_device(&kbd->dev);
+
+       maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD);
+
+       printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n",
+              kbd->dev.number, data, kbd->dev.name);
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+
+static void dc_kbd_disconnect(struct maple_device *dev)
+{
+       struct dc_kbd *kbd = dev->private_data;
+
+       input_unregister_device(&kbd->dev);
+
+       kfree(kbd);
+
+       MOD_DEC_USE_COUNT;
+}
+
+
+static struct maple_driver dc_kbd_driver = {
+       function:       MAPLE_FUNC_KEYBOARD,
+       name:           "Dreamcast keyboard",
+       connect:        dc_kbd_connect,
+       disconnect:     dc_kbd_disconnect,
+};
+
+
+static int __init dc_kbd_init(void)
+{
+       maple_register_driver(&dc_kbd_driver);
+       return 0;
+}
+
+
+static void __exit dc_kbd_exit(void)
+{
+       maple_unregister_driver(&dc_kbd_driver);
+}
+
+
+module_init(dc_kbd_init);
+module_exit(dc_kbd_exit);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/input/keyboard/ps2serkbd.c b/drivers/input/keyboard/ps2serkbd.c
new file mode 100644 (file)
index 0000000..afa4c10
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * based on: sunkbd.c and ps2serkbd.c
+ *
+ * $Id: ps2serkbd.c,v 1.5 2001/09/25 10:12:07 vojtech Exp $
+ */
+
+/*
+ * PS/2 keyboard via adapter at serial port driver for Linux
+ */
+
+/*
+ * 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/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/tqueue.h>
+
+#define ATKBD_CMD_SETLEDS      0x10ed
+#define ATKBD_CMD_GSCANSET     0x11f0
+#define ATKBD_CMD_SSCANSET     0x10f0
+#define ATKBD_CMD_GETID                0x02f2
+#define ATKBD_CMD_ENABLE       0x00f4
+#define ATKBD_CMD_RESET_DIS    0x00f5
+#define ATKBD_CMD_SETALL_MB    0x00f8
+#define ATKBD_CMD_EX_ENABLE    0x10ea
+#define ATKBD_CMD_EX_SETLEDS   0x20eb
+
+#define ATKBD_RET_ACK          0xfa
+#define ATKBD_RET_NAK          0xfe
+
+#define ATKBD_KEY_UNKNOWN        0
+#define ATKBD_KEY_BAT          251
+#define ATKBD_KEY_EMUL0                252
+#define ATKBD_KEY_EMUL1                253
+#define ATKBD_KEY_RELEASE      254
+#define ATKBD_KEY_NULL         255
+
+static unsigned char ps2serkbd_set2_keycode[512] = {
+    0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
+    0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
+    0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
+    0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
+    0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
+    122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0,
+    85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123,
+    82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+    252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,
+    0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0,
+    136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125,
+    0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127,
+    159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142,
+    157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138,
+    0, 0, 0, 0, 0, 0,153,140, 0, 0, 96, 0, 0, 0,143, 0,
+    133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112,
+    110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119
+};
+
+/*
+ * Per-keyboard data.
+ */
+
+struct ps2serkbd {
+    unsigned char keycode[512];
+    struct input_dev dev;
+    struct serio *serio;
+    char name[64];
+    char phys[32];
+    struct tq_struct tq;
+    unsigned char cmdbuf[4];
+    unsigned char cmdcnt;
+    unsigned char set;
+    char release;
+    char ack;
+    char emul;
+    char error;
+    unsigned short id;
+};
+
+/*
+ * ps2serkbd_interrupt() is called by the low level driver when a character
+ * is received.
+ */
+
+static void ps2serkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+    static int event_count=0;
+    struct ps2serkbd* ps2serkbd = serio->private;
+    int code=data;
+
+#if 0
+    printk(KERN_WARNING "ps2serkbd.c(%8d): (scancode %#x)\n", event_count, data);
+#endif
+    event_count++;
+
+    switch (code) {
+    case ATKBD_RET_ACK:
+        ps2serkbd->ack = 1;
+        return;
+    case ATKBD_RET_NAK:
+        ps2serkbd->ack = -1;
+        return;
+    }
+
+    if (ps2serkbd->cmdcnt) {
+        ps2serkbd->cmdbuf[--ps2serkbd->cmdcnt] = code;
+        return;
+    }
+
+    switch (ps2serkbd->keycode[code]) {
+    case ATKBD_KEY_BAT:
+        queue_task(&ps2serkbd->tq, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+        return;
+    case ATKBD_KEY_EMUL0:
+        ps2serkbd->emul = 1;
+        return;
+    case ATKBD_KEY_EMUL1:
+        ps2serkbd->emul = 2;
+        return;
+    case ATKBD_KEY_RELEASE:
+        ps2serkbd->release = 1;
+        return;
+    }
+
+    if (ps2serkbd->emul) {
+        if (--ps2serkbd->emul) return;
+        code |= 0x100;
+    }
+
+    switch (ps2serkbd->keycode[code]) {
+    case ATKBD_KEY_NULL:
+        break;
+    case ATKBD_KEY_UNKNOWN:
+        printk(KERN_WARNING "ps2serkbd.c: Unknown key (set %d, scancode %#x) %s.\n",
+        ps2serkbd->set, code, ps2serkbd->release ? "released" : "pressed");
+        break;
+    default:
+        input_report_key(&ps2serkbd->dev, ps2serkbd->keycode[code], !ps2serkbd->release);
+    }
+
+    ps2serkbd->release = 0;
+}
+
+/*
+ * ps2serkbd_event() handles events from the input module.
+ */
+
+static int ps2serkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+    switch (type) {
+
+    case EV_LED:
+
+        return 0;
+    }
+
+    return -1;
+}
+
+static int ps2serkbd_initialize(struct ps2serkbd *ps2serkbd) 
+{
+    return 0;
+}
+
+static void ps2serkbd_reinit(void *data) 
+{
+}
+
+
+static void ps2serkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+    struct ps2serkbd *ps2serkbd;
+    int i;
+
+    if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+        return;
+
+    if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_PS2SER)
+        return;
+
+
+    if (!(ps2serkbd = kmalloc(sizeof(struct ps2serkbd), GFP_KERNEL)))
+        return;
+
+    memset(ps2serkbd, 0, sizeof(struct ps2serkbd));
+
+    ps2serkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+    ps2serkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+
+    ps2serkbd->serio = serio;
+
+    ps2serkbd->dev.keycode = ps2serkbd->keycode;
+    ps2serkbd->dev.event = ps2serkbd_event;
+    ps2serkbd->dev.private = ps2serkbd;
+
+    ps2serkbd->tq.routine = ps2serkbd_reinit;
+    ps2serkbd->tq.data = ps2serkbd;
+
+    serio->private = ps2serkbd;
+
+    if (serio_open(serio, dev)) {
+        kfree(ps2serkbd);
+        return;
+    }
+
+    if (ps2serkbd_initialize(ps2serkbd) < 0) {
+        serio_close(serio);
+        kfree(ps2serkbd);
+        return;
+    }
+
+    ps2serkbd->set = 4;
+
+    if (ps2serkbd->set == 4) {
+        ps2serkbd->dev.ledbit[0] |= 0;
+        sprintf(ps2serkbd->name, "AT Set 2 Extended keyboard\n");
+    }
+    memcpy(ps2serkbd->keycode, ps2serkbd_set2_keycode, sizeof(ps2serkbd->keycode));
+
+    sprintf(ps2serkbd->phys, "%s/input0", serio->phys);
+
+    ps2serkbd->dev.name = ps2serkbd->name;
+    ps2serkbd->dev.phys = ps2serkbd->phys;
+    ps2serkbd->dev.idbus = BUS_RS232; 
+    ps2serkbd->dev.idvendor = SERIO_PS2SER;
+    ps2serkbd->dev.idproduct = ps2serkbd->set;
+    ps2serkbd->dev.idversion = ps2serkbd->id;
+
+    for (i = 0; i < 512; i++)
+        if (ps2serkbd->keycode[i] && ps2serkbd->keycode[i] <= 250)
+            set_bit(ps2serkbd->keycode[i], ps2serkbd->dev.keybit);
+
+    input_register_device(&ps2serkbd->dev);
+}
+
+/*
+ * ps2serkbd_disconnect() unregisters and closes behind us.
+ */
+
+static void ps2serkbd_disconnect(struct serio *serio)
+{
+    struct ps2serkbd *ps2serkbd = serio->private;
+    input_unregister_device(&ps2serkbd->dev);
+    serio_close(serio);
+    kfree(ps2serkbd);
+}
+
+static struct serio_dev ps2serkbd_dev = {
+interrupt:
+    ps2serkbd_interrupt,
+connect:
+    ps2serkbd_connect,
+disconnect:
+    ps2serkbd_disconnect
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+
+int __init ps2serkbd_init(void)
+{
+    serio_register_device(&ps2serkbd_dev);
+    return 0;
+}
+
+void __exit ps2serkbd_exit(void)
+{
+    serio_unregister_device(&ps2serkbd_dev);
+}
+
+module_init(ps2serkbd_init);
+module_exit(ps2serkbd_exit);
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
new file mode 100644 (file)
index 0000000..901567c
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * Sun keyboard driver for Linux
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Sun keyboard driver");
+MODULE_LICENSE("GPL");
+
+static unsigned char sunkbd_keycode[128] = {
+         0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,  0,
+        65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106,  1,  2,  3,
+         4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
+       116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+        26, 27,111,127, 71, 72, 73, 74,134,135,107,  0, 29, 30, 31, 32,
+        33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136,
+       104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101,
+        79, 80, 81,  0,  0,  0,138, 58,125, 57,126,109, 86, 78
+};
+
+#define SUNKBD_CMD_RESET       0x1
+#define SUNKBD_CMD_BELLON      0x2
+#define SUNKBD_CMD_BELLOFF     0x3
+#define SUNKBD_CMD_CLICK       0xa
+#define SUNKBD_CMD_NOCLICK     0xb
+#define SUNKBD_CMD_SETLED      0xe
+#define SUNKBD_CMD_LAYOUT      0xf
+
+#define SUNKBD_RET_RESET       0xff
+#define SUNKBD_RET_ALLUP       0x7f
+#define SUNKBD_RET_LAYOUT      0xfe
+
+#define SUNKBD_LAYOUT_5_MASK   0x20
+#define SUNKBD_RELEASE         0x80
+#define SUNKBD_KEY             0x7f
+
+/*
+ * Per-keyboard data.
+ */
+
+struct sunkbd {
+       unsigned char keycode[128];
+       struct input_dev dev;
+       struct serio *serio;
+       struct tq_struct tq;
+       char name[64];
+       char phys[32];
+       char type;
+       char reset;
+       char layout;
+};
+
+/*
+ * sunkbd_interrupt() is called by the low level driver when a character
+ * is received.
+ */
+
+static void sunkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+       struct sunkbd* sunkbd = serio->private;
+
+       if (sunkbd->reset <= -1) {              /* If cp[i] is 0xff, sunkbd->reset will stay -1. */
+               sunkbd->reset = data;           /* The keyboard sends 0xff 0xff 0xID on powerup */
+               return;
+       }
+
+       if (sunkbd->layout == -1) {
+               sunkbd->layout = data;
+               return;
+       }
+
+       switch (data) {
+
+               case SUNKBD_RET_RESET:
+                       queue_task(&sunkbd->tq, &tq_immediate);
+                       mark_bh(IMMEDIATE_BH);
+                       sunkbd->reset = -1;
+                       return;
+
+               case SUNKBD_RET_LAYOUT:
+                       sunkbd->layout = -1;
+                       return;
+
+               case SUNKBD_RET_ALLUP: /* All keys released */
+                       return;
+
+               default:
+                       if (sunkbd->keycode[data & SUNKBD_KEY]) {
+                                input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
+                        } else {
+                                printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n",
+                                        data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed");
+                        }
+       }
+}
+
+/*
+ * sunkbd_event() handles events from the input module.
+ */
+
+static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+       struct sunkbd *sunkbd = dev->private;
+
+       switch (type) {
+
+               case EV_LED:
+
+                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
+                       sunkbd->serio->write(sunkbd->serio, 
+                               (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) |
+                               (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led));
+                       return 0;
+
+               case EV_SND:
+
+                       switch (code) {
+
+                               case SND_CLICK:
+                                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
+                                       return 0;
+       
+                               case SND_BELL:
+                                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
+                                       return 0;
+                       }
+
+                       break;
+       }
+
+       return -1;
+}
+
+/*
+ * sunkbd_initialize() checks for a Sun keyboard attached, and determines
+ * its type.
+ */
+
+static int sunkbd_initialize(struct sunkbd *sunkbd)
+{
+       int t;
+
+       t = 1000;
+       sunkbd->reset = -2;
+       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
+       while (sunkbd->reset < 0 && --t) mdelay(1);
+       if (!t) return -1;
+
+       sunkbd->type = sunkbd->reset;
+
+       if (sunkbd->type == 4) {        /* Type 4 keyboard */
+               t = 250;
+               sunkbd->layout = -2;
+               sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
+               while (sunkbd->layout < 0 && --t) mdelay(1);
+               if (!t) return -1;
+               if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5;
+       }
+
+       return 0;
+}
+
+/*
+ * sunkbd_reinit() sets leds and beeps to a state the computer remembers they
+ * were in.
+ */
+
+static void sunkbd_reinit(void *data)
+{
+       struct sunkbd *sunkbd = data;
+       int t = 1000;
+
+       while (sunkbd->reset < 0 && --t) mdelay(1);
+
+       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
+       sunkbd->serio->write(sunkbd->serio, 
+               (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) |
+               (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led));
+       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd));
+       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd));
+}
+
+/*
+ * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
+ */
+
+static void sunkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+       struct sunkbd *sunkbd;
+       int i;
+
+       if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+               return;
+
+       if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD)
+               return;
+       
+       if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL)))
+               return;
+
+       memset(sunkbd, 0, sizeof(struct sunkbd));
+
+       sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
+       sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML);
+       sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL);
+
+       sunkbd->serio = serio;
+
+       sunkbd->tq.routine = sunkbd_reinit;
+       sunkbd->tq.data = sunkbd;
+
+       sunkbd->dev.keycode = sunkbd->keycode;
+       sunkbd->dev.event = sunkbd_event;
+       sunkbd->dev.private = sunkbd;
+
+       serio->private = sunkbd;
+
+       if (serio_open(serio, dev)) {
+               kfree(sunkbd);
+               return;
+       }
+
+       if (sunkbd_initialize(sunkbd) < 0) {
+               serio_close(serio);
+               kfree(sunkbd);
+               return;
+       }
+
+       sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type);
+
+       memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
+       for (i = 0; i < 255; i++)
+               set_bit(sunkbd->keycode[i], sunkbd->dev.keybit);
+       clear_bit(0, sunkbd->dev.keybit);
+
+       sprintf(sunkbd->name, "%s/input", serio->phys);
+
+       sunkbd->dev.name = sunkbd->name;
+       sunkbd->dev.phys = sunkbd->phys;
+       sunkbd->dev.idbus = BUS_RS232;
+       sunkbd->dev.idvendor = SERIO_SUNKBD;
+       sunkbd->dev.idproduct = sunkbd->type;
+       sunkbd->dev.idversion = 0x0100;
+
+       input_register_device(&sunkbd->dev);
+
+       printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys);
+}
+
+/*
+ * sunkbd_disconnect() unregisters and closes behind us.
+ */
+
+static void sunkbd_disconnect(struct serio *serio)
+{
+       struct sunkbd *sunkbd = serio->private;
+       input_unregister_device(&sunkbd->dev);
+       serio_close(serio);
+       kfree(sunkbd);
+}
+
+static struct serio_dev sunkbd_dev = {
+       interrupt:      sunkbd_interrupt,
+       connect:        sunkbd_connect,
+       disconnect:     sunkbd_disconnect
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+
+int __init sunkbd_init(void)
+{
+       serio_register_device(&sunkbd_dev);
+       return 0;
+}
+
+void __exit sunkbd_exit(void)
+{
+       serio_unregister_device(&sunkbd_dev);
+}
+
+module_init(sunkbd_init);
+module_exit(sunkbd_exit);
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
new file mode 100644 (file)
index 0000000..6f0b241
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * $Id: xtkbd.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * XT keyboard driver for Linux
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("XT keyboard driver");
+MODULE_LICENSE("GPL");
+
+#define XTKBD_EMUL0    0xe0
+#define XTKBD_EMUL1    0xe1
+#define XTKBD_KEY      0x7f
+#define XTKBD_RELEASE  0x80
+
+static unsigned char xtkbd_keycode[256] = {     
+         0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+        80, 81, 82, 83,  0,  0,  0, 87, 88,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0, 87, 88,  0,  0,  0,  0,110,111,103,108,105,
+       106
+};
+
+static char *xtkbd_name = "XT Keyboard";
+
+struct xtkbd {
+       unsigned char keycode[256];
+       struct input_dev dev;
+       struct serio *serio;
+       char phys[32];
+};
+
+void xtkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+       struct xtkbd *xtkbd = serio->private;
+
+       switch (data) {
+               case XTKBD_EMUL0:
+               case XTKBD_EMUL1:
+                       return;
+               default:
+
+                       if (xtkbd->keycode[data & XTKBD_KEY]) {
+                               input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE));
+                       } else {
+                               printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n",
+                                       data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed");
+                       }
+               }
+}
+
+void xtkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+       struct xtkbd *xtkbd;
+       int i;
+
+       if ((serio->type & SERIO_TYPE) != SERIO_XT)
+               return;
+
+       if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL)))
+               return;
+
+       memset(xtkbd, 0, sizeof(struct xtkbd));
+       
+       xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+       xtkbd->serio = serio;
+
+       xtkbd->dev.keycode = xtkbd->keycode;
+       xtkbd->dev.private = xtkbd;
+
+       serio->private = xtkbd;
+
+       if (serio_open(serio, dev)) {
+               kfree(xtkbd);
+               return;
+       }
+
+       memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode));
+       for (i = 0; i < 255; i++)
+               set_bit(xtkbd->keycode[i], xtkbd->dev.keybit);
+       clear_bit(0, xtkbd->dev.keybit);
+
+       sprintf(xtkbd->phys, "%s/input0", serio->phys);
+
+       xtkbd->dev.name = xtkbd_name;
+       xtkbd->dev.phys = xtkbd->phys;
+       xtkbd->dev.idbus = BUS_XTKBD;
+       xtkbd->dev.idvendor = 0x0001;
+       xtkbd->dev.idproduct = 0x0001;
+       xtkbd->dev.idversion = 0x0100;
+
+       input_register_device(&xtkbd->dev);
+
+       printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys);
+}
+
+void xtkbd_disconnect(struct serio *serio)
+{
+       struct xtkbd *xtkbd = serio->private;
+       input_unregister_device(&xtkbd->dev);
+       serio_close(serio);
+       kfree(xtkbd);
+}
+
+struct serio_dev xtkbd_dev = {
+       interrupt:      xtkbd_interrupt,
+       connect:        xtkbd_connect,
+       disconnect:     xtkbd_disconnect
+};
+
+int __init xtkbd_init(void)
+{
+       serio_register_device(&xtkbd_dev);
+       return 0;
+}
+
+void __exit xtkbd_exit(void)
+{
+       serio_unregister_device(&xtkbd_dev);
+}
+
+module_init(xtkbd_init);
+module_exit(xtkbd_exit);
diff --git a/drivers/input/mouse/Config.help b/drivers/input/mouse/Config.help
new file mode 100644 (file)
index 0000000..c60ae83
--- /dev/null
@@ -0,0 +1,87 @@
+CONFIG_INPUT_MOUSE
+  Say Y here, and a list of supported mice will be displayed.
+  This option doesn't affect the kernel.
+
+  If unsure, say Y.
+
+CONFIG_MOUSE_PS2
+  Say Y here if you have a PS/2 mouse connected to your system. This
+  includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
+  mice with wheels and extra buttons, Microsoft, Logitech or Genius
+  compatible.
+
+  If unsure, say Y.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called psmouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MOUSE_SERIAL
+  Say Y here if you have a serial (RS-232, COM port) mouse connected
+  to your system. This includes Sun, MouseSystems, Microsoft,
+  Logitech and all other compatible serial mice.
+
+  If unsure, say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called sermouse.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MOUSE_INPORT
+  Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
+  They are rather rare these days.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called inport.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_ATIXL
+  Say Y here if your mouse is of the ATI XL variety.
+
+CONFIG_MOUSE_LOGIBM
+  Say Y here if you have a Logitech busmouse.
+  They are rather rare these days.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called logibm.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_PC110PAD
+  Say Y if you have the IBM PC-110 micro-notebook and want its
+  touchscreen supported.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pc110pad.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_MAPLE
+  Say Y if you have a DreamCast console and a mouse attached to
+  its Maple bus.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called maplemouse.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_AMIGA
+  Say Y here if you have an Amiga and want its native mouse
+  supported by the kernel.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called amimouse.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_ACORN
+  Say Y here if you have the Acorn RiscPC computer and want its
+  native mouse supported.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called rpcmouse.o. If you want to compile it as a
+  module, say M here and read <file.:Documentation/modules.txt>.
diff --git a/drivers/input/mouse/Config.in b/drivers/input/mouse/Config.in
new file mode 100644 (file)
index 0000000..d740c41
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Mouse driver configuration
+#
+
+bool 'Mice' CONFIG_INPUT_MOUSE
+
+dep_tristate '  PS/2 mouse' CONFIG_MOUSE_PS2 $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO
+dep_tristate '  Serial mouse' CONFIG_MOUSE_SERIAL $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO
+
+dep_tristate '  InPort/MS/ATIXL busmouse' CONFIG_MOUSE_INPORT $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+if [ "$CONFIG_MOUSE_INPORT" != "n" ]; then
+   bool '  ATI XL variant' CONFIG_MOUSE_ATIXL
+fi
+dep_tristate '  Logitech busmouse' CONFIG_MOUSE_LOGIBM $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+dep_tristate '  IBM PC110 touchpad' CONFIG_MOUSE_PC110PAD $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+  dep_tristate '  Maple bus mouse' CONFIG_MOUSE_MAPLE $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_MAPLE
+fi
+if [ "$CONFIG_AMIGA" = "y" ]; then
+   dep_tristate '  Amiga mouse' CONFIG_MOUSE_AMIGA $CONFIG_INPUT $CONFIG_INPUT_MOUSE
+fi
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+   dep_tristate '  Acorn RiscPC mouse' CONFIG_MOUSE_ACORN $CONFIG_INPUT $CONFIG_INPUT_MOUSE
+fi
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
new file mode 100644 (file)
index 0000000..ba44f73
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# Makefile for the mouse drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET       := mousedrv.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_MOUSE_AMIGA)      += amimouse.o
+obj-$(CONFIG_MOUSE_ACORN)      += rpcmouse.o
+obj-$(CONFIG_MOUSE_INPORT)     += inport.o
+obj-$(CONFIG_MOUSE_LOGIBM)     += logibm.o
+obj-$(CONFIG_MOUSE_MAPLE)      += maplemouse.o
+obj-$(CONFIG_MOUSE_PC110PAD)   += pc110pad.o
+obj-$(CONFIG_MOUSE_PS2)                += psmouse.o
+obj-$(CONFIG_MOUSE_SERIAL)     += sermouse.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
new file mode 100644 (file)
index 0000000..819d968
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * $Id: amimouse.c,v 1.9 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *     Michael Rausch          James Banks
+ *     Matther Dillon          David Giller
+ *     Nathan Laredo           Linus Torvalds
+ *     Johan Myreen            Jes Sorensen
+ *     Russel King
+ */
+
+/*
+ * Amiga mouse driver for Linux/m68k
+ */
+
+/*
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Amiga mouse driver");
+MODULE_LICENSE("GPL");
+
+static int amimouse_used = 0;
+static int amimouse_lastx, amimouse_lasty;
+static struct input_dev amimouse_dev;
+
+static char *amimouse_name = "Amiga mouse";
+static char *amimouse_phys = "amimouse/input0";
+
+static void amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+       unsigned short joy0dat, potgor;
+       int nx, ny, dx, dy;
+
+       joy0dat = custom.joy0dat;
+
+       nx = joy0dat & 0xff;
+       ny = joy0dat >> 8;
+
+       dx = nx - amimouse_lastx;
+       dy = ny - amimouse_lasty;
+
+       if (dx < -127) dx = (256 + nx) - lastx;
+       if (dx >  127) dx = (nx - 256) - lastx;
+       if (dy < -127) dy = (256 + ny) - lasty;
+       if (dy >  127) dy = (ny - 256) - lasty;
+
+       amimouse_lastx = nx;
+       amimouse_lasty = ny;
+
+       potgor = custom.potgor;
+
+       input_report_rel(&amimouse_dev, REL_X, dx);
+       input_report_rel(&amimouse_dev, REL_Y, dy);
+       
+       input_report_key(&amimouse_dev, BTN_LEFT,   ciaa.pra & 0x40);
+       input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
+       input_report_key(&amimouse_dev, BTN_RIGHT,  potgor & 0x0400);
+}
+
+static int amimouse_open(struct input_dev *dev)
+{
+       unsigned short joy0dat;
+
+        if (amimouse_used++)
+                return 0;
+
+       joy0dat = custom.joy0dat;
+
+       amimouse_lastx = joy0dat & 0xff;
+       amimouse_lasty = joy0dat >> 8;
+
+       if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", NULL)) {
+                amimouse_used--;
+                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", amimouse_irq);
+                return -EBUSY;
+        }
+
+        return 0;
+}
+
+static void amimouse_close(struct input_dev *dev)
+{
+        if (!--amimouse_used)
+               free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+}
+
+static int __init amimouse_init(void)
+{
+       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
+               return -ENODEV;
+
+       amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+       amimouse_dev.open = amimouse_open;
+       amimouse_dev.close = amimouse_close;
+
+       amimouse_dev.name = amimouse_name;
+       amimouse_dev.phys = amimouse_phys;
+       amimouse_dev.idbus = BUS_AMIGA;
+       amimouse_dev.idvendor = 0x0001;
+       amimouse_dev.idproduct = 0x0002;
+       amimouse_dev.idversion = 0x0100;
+        
+       input_register_device(&amimouse_dev);
+
+        printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name);
+}
+
+static void __exit amimouse_exit(void)
+{
+        input_unregister_device(&amimouse_dev);
+}
+
+module_init(amimouse_init);
+module_exit(amimouse_exit);
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
new file mode 100644 (file)
index 0000000..9931ff9
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * $Id: inport.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *     Teemu Rantanen          Derrick Cole
+ *     Peter Cervasio          Christoph Niemann
+ *     Philip Blundell         Russell King
+ *     Bob Harris
+ */
+
+/*
+ * Inport (ATI XL and Microsoft) busmouse driver for Linux
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
+MODULE_LICENSE("GPL");
+
+#define INPORT_BASE            0x23c
+#define INPORT_EXTENT          4
+
+#define INPORT_CONTROL_PORT    INPORT_BASE + 0
+#define INPORT_DATA_PORT       INPORT_BASE + 1
+#define INPORT_SIGNATURE_PORT  INPORT_BASE + 2
+
+#define INPORT_REG_BTNS        0x00
+#define INPORT_REG_X           0x01
+#define INPORT_REG_Y           0x02
+#define INPORT_REG_MODE                0x07
+#define INPORT_RESET           0x80
+
+#ifdef CONFIG_INPUT_ATIXL
+#define INPORT_NAME            "ATI XL Mouse"
+#define INPORT_VENDOR          0x0002
+#define INPORT_SPEED_30HZ      0x01
+#define INPORT_SPEED_50HZ      0x02
+#define INPORT_SPEED_100HZ     0x03
+#define INPORT_SPEED_200HZ     0x04
+#define INPORT_MODE_BASE       INPORT_SPEED_100HZ
+#define INPORT_MODE_IRQ                0x08
+#else
+#define INPORT_NAME            "Microsoft InPort Mouse"
+#define INPORT_VENDOR          0x0001
+#define INPORT_MODE_BASE       0x10
+#define INPORT_MODE_IRQ                0x01
+#endif
+#define INPORT_MODE_HOLD       0x20
+
+#define INPORT_IRQ             5
+
+MODULE_PARM(inport_irq, "i");
+
+static int inport_irq = INPORT_IRQ;
+static int inport_used = 0;
+
+static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static int inport_open(struct input_dev *dev)
+{
+       if (!inport_used++) {
+               if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
+                       return -EBUSY;
+               outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+               outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
+       }
+
+       return 0;
+}
+
+static void inport_close(struct input_dev *dev)
+{
+       if (!--inport_used) {
+               outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+               outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+               free_irq(inport_irq, NULL);
+       }
+}
+
+static struct input_dev inport_dev = {
+       evbit:          { BIT(EV_KEY) | BIT(EV_REL) },
+       keybit:         { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
+       relbit:         { BIT(REL_X) | BIT(REL_Y) },
+       open:           inport_open,
+       close:          inport_close,
+       name:           INPORT_NAME,
+       phys:           "isa023c/input0",
+       idbus:          BUS_ISA,
+       idvendor:       INPORT_VENDOR,
+       idproduct:      0x0001,
+       idversion:      0x0100,
+};
+
+static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       unsigned char buttons;
+
+       outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+       outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
+
+       outb(INPORT_REG_X, INPORT_CONTROL_PORT);
+       input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT));
+
+       outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
+       input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT));
+
+       outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
+       buttons = inb(INPORT_DATA_PORT);
+
+       input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1);
+       input_report_key(&inport_dev, BTN_LEFT,   buttons & 2);
+       input_report_key(&inport_dev, BTN_RIGHT,  buttons & 4);
+
+       outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+       outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
+}
+
+#ifndef MODULE
+static int __init inport_setup(char *str)
+{
+        int ints[4];
+        str = get_options(str, ARRAY_SIZE(ints), ints);
+        if (ints[0] > 0) inport_irq = ints[1];
+        return 1;
+}
+__setup("inport_irq=", inport_setup);
+#endif
+
+static int __init inport_init(void)
+{
+       unsigned char a,b,c;
+
+       if (check_region(INPORT_BASE, INPORT_EXTENT))
+               return -EBUSY;
+
+       a = inb(INPORT_SIGNATURE_PORT);
+       b = inb(INPORT_SIGNATURE_PORT);
+       c = inb(INPORT_SIGNATURE_PORT);
+       if (( a == b ) || ( a != c ))
+               return -ENODEV;
+
+       outb(INPORT_RESET, INPORT_CONTROL_PORT);
+       outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+       outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+
+       request_region(INPORT_BASE, INPORT_EXTENT, "inport");
+
+       input_register_device(&inport_dev);
+
+       printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n",
+               INPORT_BASE, inport_irq);
+
+       return 0;
+}
+
+static void __exit inport_exit(void)
+{
+       input_unregister_device(&inport_dev);
+       release_region(INPORT_BASE, INPORT_EXTENT);
+}
+
+module_init(inport_init);
+module_exit(inport_exit);
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
new file mode 100644 (file)
index 0000000..f1b3434
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * $Id: logibm.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *     James Banks             Matthew Dillon
+ *     David Giller            Nathan Laredo
+ *     Linus Torvalds          Johan Myreen
+ *     Cliff Matthews          Philip Blundell
+ *     Russell King
+ */
+
+/*
+ * Logitech Bus Mouse Driver for Linux
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Logitech busmouse driver");
+MODULE_LICENSE("GPL");
+
+#define        LOGIBM_BASE             0x23c
+#define        LOGIBM_EXTENT           4
+
+#define        LOGIBM_DATA_PORT        LOGIBM_BASE + 0
+#define        LOGIBM_SIGNATURE_PORT   LOGIBM_BASE + 1
+#define        LOGIBM_CONTROL_PORT     LOGIBM_BASE + 2
+#define        LOGIBM_CONFIG_PORT      LOGIBM_BASE + 3
+
+#define        LOGIBM_ENABLE_IRQ       0x00
+#define        LOGIBM_DISABLE_IRQ      0x10
+#define        LOGIBM_READ_X_LOW       0x80
+#define        LOGIBM_READ_X_HIGH      0xa0
+#define        LOGIBM_READ_Y_LOW       0xc0
+#define        LOGIBM_READ_Y_HIGH      0xe0
+
+#define LOGIBM_DEFAULT_MODE    0x90
+#define LOGIBM_CONFIG_BYTE     0x91
+#define LOGIBM_SIGNATURE_BYTE  0xa5
+
+#define LOGIBM_IRQ             5
+
+MODULE_PARM(logibm_irq, "i");
+
+static int logibm_irq = LOGIBM_IRQ;
+static int logibm_used = 0;
+
+static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static int logibm_open(struct input_dev *dev)
+{
+       if (logibm_used++)
+               return 0;
+       if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
+               logibm_used--;
+               printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
+               return -EBUSY;
+       }
+       outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
+       return 0;
+}
+
+static void logibm_close(struct input_dev *dev)
+{
+       if (--logibm_used)
+               return;
+       outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
+       free_irq(logibm_irq, NULL);
+}
+
+static struct input_dev logibm_dev = {
+       evbit:          { BIT(EV_KEY) | BIT(EV_REL) },
+       keybit:         { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
+       relbit:         { BIT(REL_X) | BIT(REL_Y) },
+       open:           logibm_open,
+       close:          logibm_close,
+       name:           "Logitech bus mouse",
+       phys:           "isa023c/input0",
+       idbus:          BUS_ISA,
+       idvendor:       0x0003,
+       idproduct:      0x0001,
+       idversion:      0x0100,
+};
+
+static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       char dx, dy;
+       unsigned char buttons;
+
+       outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT);
+       dx = (inb(LOGIBM_DATA_PORT) & 0xf);
+       outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT);
+       dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4;
+       outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT);
+       dy = (inb(LOGIBM_DATA_PORT) & 0xf);
+       outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT);
+       buttons = inb(LOGIBM_DATA_PORT);
+       dy |= (buttons & 0xf) << 4;
+       buttons = ~buttons;
+
+       input_report_rel(&logibm_dev, REL_X, dx);
+       input_report_rel(&logibm_dev, REL_Y, 255 - dy);
+       input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 1);
+       input_report_key(&logibm_dev, BTN_LEFT,   buttons & 2);
+       input_report_key(&logibm_dev, BTN_RIGHT,  buttons & 4);
+}
+
+#ifndef MODULE
+static int __init logibm_setup(char *str)
+{
+        int ints[4];
+        str = get_options(str, ARRAY_SIZE(ints), ints);
+        if (ints[0] > 0) logibm_irq = ints[1];
+        return 1;
+}
+__setup("logibm_irq=", logibm_setup);
+#endif
+
+static int __init logibm_init(void)
+{
+       if (request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) {
+               printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE);
+               return -EBUSY;
+       }
+
+       outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT);
+       outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT);
+       udelay(100);
+
+       if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) {
+               release_region(LOGIBM_BASE, LOGIBM_EXTENT);
+               printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE);
+               return -ENODEV;
+       }
+
+       outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT);
+       outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
+
+       input_register_device(&logibm_dev);
+
+       printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
+
+       return 0;
+}
+
+static void __exit logibm_exit(void)
+{
+       input_unregister_device(&logibm_dev);
+       release_region(LOGIBM_BASE, LOGIBM_EXTENT);
+}
+
+module_init(logibm_init);
+module_exit(logibm_exit);
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
new file mode 100644 (file)
index 0000000..34d9020
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *     $Id: maplemouse.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $
+ *     SEGA Dreamcast mouse driver
+ *     Based on drivers/usb/usbmouse.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/maple.h>
+
+MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
+MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
+
+struct dc_mouse {
+       struct input_dev dev;
+       int open;
+};
+
+
+static void dc_mouse_callback(struct mapleq *mq)
+{
+       int buttons, relx, rely, relz;
+       struct maple_device *mapledev = mq->dev;
+       struct dc_mouse *mouse = mapledev->private_data;
+       struct input_dev *dev = &mouse->dev;
+       unsigned char *res = mq->recvbuf;
+
+       buttons = ~res[8];
+       relx=*(unsigned short *)(res+12)-512;
+       rely=*(unsigned short *)(res+14)-512;
+       relz=*(unsigned short *)(res+16)-512;
+
+       input_report_key(dev, BTN_LEFT,   buttons&4);
+       input_report_key(dev, BTN_MIDDLE, buttons&9);
+       input_report_key(dev, BTN_RIGHT,  buttons&2);
+       input_report_rel(dev, REL_X,      relx);
+       input_report_rel(dev, REL_Y,      rely);
+       input_report_rel(dev, REL_WHEEL,  relz);
+}
+
+
+static int dc_mouse_open(struct input_dev *dev)
+{
+       struct dc_mouse *mouse = dev->private;
+       mouse->open++;
+       return 0;
+}
+
+
+static void dc_mouse_close(struct input_dev *dev)
+{
+       struct dc_mouse *mouse = dev->private;
+       mouse->open--;
+}
+
+
+static int dc_mouse_connect(struct maple_device *dev)
+{
+       unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
+       struct dc_mouse *mouse;
+
+       if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
+               return -1;
+       memset(mouse, 0, sizeof(struct dc_mouse));
+
+       dev->private_data = mouse;
+
+       mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+
+       mouse->dev.private = mouse;
+       mouse->dev.open = dc_mouse_open;
+       mouse->dev.close = dc_mouse_close;
+       mouse->dev.event = NULL;
+
+       mouse->dev.name = dev->product_name;
+       mouse->dev.idbus = BUS_MAPLE;
+       
+       input_register_device(&mouse->dev);
+
+       maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
+
+       printk(KERN_INFO "input%d: mouse(0x%lx): %s\n",
+              mouse->dev.number, data, mouse->dev.name);
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+
+static void dc_mouse_disconnect(struct maple_device *dev)
+{
+       struct dc_mouse *mouse = dev->private_data;
+
+       input_unregister_device(&mouse->dev);
+
+       kfree(mouse);
+
+       MOD_DEC_USE_COUNT;
+}
+
+
+static struct maple_driver dc_mouse_driver = {
+       function:       MAPLE_FUNC_MOUSE,
+       name:           "Dreamcast mouse",
+       connect:        dc_mouse_connect,
+       disconnect:     dc_mouse_disconnect,
+};
+
+
+static int __init dc_mouse_init(void)
+{
+       maple_register_driver(&dc_mouse_driver);
+       return 0;
+}
+
+
+static void __exit dc_mouse_exit(void)
+{
+       maple_unregister_driver(&dc_mouse_driver);
+}
+
+
+module_init(dc_mouse_init);
+module_exit(dc_mouse_exit);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
new file mode 100644 (file)
index 0000000..61ee966
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *     Alan Cox        Robin O'Leary   
+ */
+
+/*
+ * IBM PC110 touchpad driver for Linux
+ */
+
+/*
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/input.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("IBM PC110 touchpad driver");
+MODULE_LICENSE("GPL");
+
+#define PC110PAD_OFF   0x30
+#define PC110PAD_ON    0x38
+
+static int pc110pad_irq = 10;
+static int pc110pad_io = 0x15e0;
+
+static struct input_dev pc110pad_dev;
+static int pc110pad_data[3];
+static int pc110pad_count;
+static int pc110pad_used;
+
+static char *pc110pad_name = "IBM PC110 TouchPad";
+static char *pc110pad_phys = "isa15e0/input0";
+
+static void pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+       int value     = inb_p(pc110pad_io);
+       int handshake = inb_p(pc110pad_io + 2);
+
+       outb_p(handshake |  1, pc110pad_io + 2);
+       outb_p(handshake & ~1, pc110pad_io + 2);
+       inb_p(0x64);
+
+       pc110pad_data[pc110pad_count++] = value;
+
+       if (pc110pad_count < 3) return;
+       
+       input_report_key(&pc110pad_dev, BTN_TOUCH,
+               pc110pad_data[0] & 0x01);
+       input_report_abs(&pc110pad_dev, ABS_X,
+               pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100));
+       input_report_abs(&pc110pad_dev, ABS_Y,
+               pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80));
+
+       pc110pad_count = 0;
+}
+
+static void pc110pad_close(struct input_dev *dev)
+{
+       if (!--pc110pad_used)
+               outb(PC110PAD_OFF, pc110pad_io + 2);
+}
+
+static int pc110pad_open(struct input_dev *dev)
+{
+       unsigned long flags;
+       
+       if (pc110pad_used++)
+               return 0;
+
+       save_flags(flags);
+       cli();
+       pc110pad_interrupt(0,0,0);
+       pc110pad_interrupt(0,0,0);
+       pc110pad_interrupt(0,0,0);
+       outb(PC110PAD_ON, pc110pad_io + 2);
+       pc110pad_count = 0;
+       restore_flags(flags);
+
+       return 0;
+}
+
+static int __init pc110pad_init(void)
+{
+       if (request_region(pc110pad_io, 4, "pc110pad"))
+       {
+               printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", pc110pad_io, pc110pad_io + 4);
+               return -EBUSY;
+       }
+
+       outb(PC110PAD_OFF, pc110pad_io + 2);
+
+       if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", 0))
+       {
+               release_region(pc110pad_io, 4);
+               printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq);
+               return -EBUSY;
+       }
+
+        pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+        pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+        pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+       pc110pad_dev.absmax[ABS_X] = 0x1ff;
+       pc110pad_dev.absmax[ABS_Y] = 0x0ff;
+        
+       pc110pad_dev.open = pc110pad_open;
+        pc110pad_dev.close = pc110pad_close;
+
+       pc110pad_dev.name = pc110pad_name;
+       pc110pad_dev.phys = pc110pad_phys;
+       pc110pad_dev.idbus = BUS_ISA;
+       pc110pad_dev.idvendor = 0x0003;
+       pc110pad_dev.idproduct = 0x0001;
+       pc110pad_dev.idversion = 0x0100;
+
+       input_register_device(&pc110pad_dev);   
+
+       printk(KERN_INFO "input: %s at %#x irq %d\n",
+               pc110pad_name, pc110pad_io, pc110pad_irq);
+       
+       return 0;
+}
+static void __exit pc110pad_exit(void)
+{
+       input_unregister_device(&pc110pad_dev); 
+
+       outb(PC110PAD_OFF, pc110pad_io + 2);
+
+       free_irq(pc110pad_irq, 0);
+       release_region(pc110pad_io, 4);
+}
+
+module_init(pc110pad_init);
+module_exit(pc110pad_exit);
diff --git a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
new file mode 100644 (file)
index 0000000..3b3e545
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * $Id: psmouse.c,v 1.16 2002/01/26 19:20:36 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("PS/2 mouse driver");
+MODULE_LICENSE("GPL");
+
+#define PSMOUSE_CMD_SETSCALE11 0x00e6
+#define PSMOUSE_CMD_SETRES     0x10e8
+#define PSMOUSE_CMD_GETINFO    0x03e9
+#define PSMOUSE_CMD_SETSTREAM  0x00ea
+#define PSMOUSE_CMD_POLL       0x03eb  
+#define PSMOUSE_CMD_GETID      0x01f2
+#define PSMOUSE_CMD_SETRATE    0x10f3
+#define PSMOUSE_CMD_ENABLE     0x00f4
+#define PSMOUSE_CMD_RESET_DIS  0x00f6
+
+#define PSMOUSE_RET_BAT                0xaa
+#define PSMOUSE_RET_ACK                0xfa
+#define PSMOUSE_RET_NAK                0xfe
+
+struct psmouse {
+       struct input_dev dev;
+       struct serio *serio;
+       char *vendor;
+       char *name;
+       struct tq_struct tq;
+       unsigned char cmdbuf[8];
+       unsigned char packet[8];
+       unsigned char cmdcnt;
+       unsigned char pktcnt;
+       unsigned char type;
+       unsigned long last;
+       char acking;
+       char ack;
+       char error;
+       char devname[64];
+       char phys[32];
+};
+
+#define PSMOUSE_PS2    1
+#define PSMOUSE_PS2PP  2
+#define PSMOUSE_PS2TPP 3
+#define PSMOUSE_GENPS  4
+#define PSMOUSE_IMPS   5
+#define PSMOUSE_IMEX   6
+
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" };
+
+/*
+ * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
+ * reports relevant events to the input module.
+ */
+
+static void psmouse_process_packet(struct psmouse *psmouse)
+{
+       struct input_dev *dev = &psmouse->dev;
+       unsigned char *packet = psmouse->packet;
+
+/*
+ * The PS2++ protocol is a little bit complex
+ */
+
+       if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) {
+
+               if ((packet[0] & 0x40) == 0x40 && (int) packet[1] - (int) ((packet[0] & 0x10) << 4) > 191 ) {
+
+                       switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)) {
+
+                       case 1: /* Mouse extra info */
+
+                               input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
+                                       (int) (packet[2] & 7) - (int) (packet[2] & 8));
+                               input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
+                               input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
+                                       
+                               break;
+
+                       case 3: /* TouchPad extra info */
+
+                               input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
+                                       (int) ((packet[2] >> 4) & 7) - (int) ((packet[2] >> 4) & 8));
+                               packet[0] = packet[2] | 0x08;
+
+                               break;
+
+                       default:
+
+                               printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
+                                       ((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0));
+
+                       }
+
+               packet[0] &= 0x0f;
+               packet[1] = 0;
+               packet[2] = 0;
+
+               }
+       }
+
+/*
+ * Scroll wheel on IntelliMice, scroll buttons on NetMice
+ */
+
+       if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS)
+               input_report_rel(dev, REL_WHEEL, (signed char) packet[3]);
+
+/*
+ * Scroll wheel and buttons on IntelliMouse Explorer
+ */
+
+       if (psmouse->type == PSMOUSE_IMEX) {
+               input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 7) - (int) (packet[2] & 8));
+               input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
+               input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+       }
+
+/*
+ * Extra buttons on Genius NewNet 3D
+ */
+
+       if (psmouse->type == PSMOUSE_GENPS) {
+               input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
+               input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
+       }
+
+/*
+ * Generic PS/2 Mouse
+ */
+
+       input_report_key(dev, BTN_LEFT,    packet[0]       & 1);
+       input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
+       input_report_key(dev, BTN_RIGHT,  (packet[0] >> 1) & 1);
+
+       input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
+       input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
+
+}
+
+/*
+ * psmouse_interrupt() handles incoming characters, either gathering them into
+ * packets or passing them to the command routine as command output.
+ */
+
+static void psmouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+       struct psmouse *psmouse = serio->private;
+
+       if (psmouse->acking) {
+               switch (data) {
+                       case PSMOUSE_RET_ACK:
+                               psmouse->ack = 1;
+                               break;
+                       case PSMOUSE_RET_NAK:
+                               psmouse->ack = -1;
+                               break;
+                       default:
+                               psmouse->ack = 1;       /* Workaround for mice which don't ACK the Get ID command */
+                               if (psmouse->cmdcnt)
+                                       psmouse->cmdbuf[--psmouse->cmdcnt] = data;
+                               break;
+               }
+               psmouse->acking = 0;
+               return;
+       }
+
+       if (psmouse->cmdcnt) {
+               psmouse->cmdbuf[--psmouse->cmdcnt] = data;
+               return;
+       }
+
+       if (psmouse->pktcnt && jiffies - psmouse->last > 2) {
+               printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
+               psmouse->pktcnt = 0;
+       }
+       
+       psmouse->last = jiffies;
+       psmouse->packet[psmouse->pktcnt++] = data;
+
+       if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
+               if ((psmouse->packet[0] & 0x08) == 0x08) psmouse_process_packet(psmouse);
+               psmouse->pktcnt = 0;
+               return;
+       }
+
+       if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
+               queue_task(&psmouse->tq, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+               return;
+       }       
+}
+
+/*
+ * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because when there would
+ * be need for retransmissions, the mouse has to be replaced anyway.
+ */
+
+static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
+{
+       int timeout = 1000; /* 10 msec */
+       psmouse->ack = 0;
+       psmouse->acking = 1;
+
+       serio_write(psmouse->serio, byte);
+       while (!psmouse->ack && timeout--) udelay(10);
+
+       return -(psmouse->ack <= 0);
+}
+
+/*
+ * psmouse_command() sends a command and its parameters to the mouse,
+ * then waits for the response and puts it in the param array.
+ */
+
+static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
+{
+       int timeout = 100000; /* 100 msec */
+       int send = (command >> 12) & 0xf;
+       int receive = (command >> 8) & 0xf;
+       int i;
+
+       psmouse->cmdcnt = receive;
+
+       if (command & 0xff)
+               if (psmouse_sendbyte(psmouse, command & 0xff))
+                       return (psmouse->cmdcnt = 0) - 1;
+
+       for (i = 0; i < send; i++)
+               if (psmouse_sendbyte(psmouse, param[i]))
+                       return (psmouse->cmdcnt = 0) - 1;
+
+       while (psmouse->cmdcnt && timeout--) udelay(1);
+
+       for (i = 0; i < receive; i++)
+               param[i] = psmouse->cmdbuf[(receive - 1) - i];
+
+       if (psmouse->cmdcnt) 
+               return (psmouse->cmdcnt = 0) - 1;
+
+       return 0;
+}
+
+/*
+ * psmouse_ps2pp_cmd() sends a PS2++ command, sliced into two bit
+ * pieces through the SETRES command. This is needed to send extended
+ * commands to mice on notebooks that try to understand the PS/2 protocol
+ * Ugly.
+ */
+
+static int psmouse_ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
+{
+       unsigned char d;
+       int i;
+
+       if (psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11))
+               return -1;
+
+       for (i = 6; i >= 0; i -= 2) {
+               d = (command >> i) & 3;
+               if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+                       return -1;
+       }
+
+       if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
+               return -1;
+
+       return 0;
+}
+
+/*
+ * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
+ * the mouse may have.
+ */
+
+static int psmouse_extensions(struct psmouse *psmouse)
+{
+       unsigned char param[4];
+
+       param[0] = 0;
+       psmouse->vendor = "Generic";
+       psmouse->name = "Mouse";
+
+/*
+ * Try Genius NetMouse magic init.
+ */
+
+       param[0] = 3;
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+       psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+       psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+       psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+       psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+
+       if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) {
+               psmouse->vendor = "Genius";
+               psmouse->name = "Mouse";
+
+               set_bit(BTN_EXTRA, psmouse->dev.keybit);
+               set_bit(BTN_SIDE, psmouse->dev.keybit);
+               set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+               return PSMOUSE_GENPS;
+       }
+
+/*
+ * Try Logitech magic ID.
+ */
+
+       param[0] = 0;
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+       psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+       psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+       psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+       psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+
+       if (param[1]) {
+
+               int i;
+               static int logitech_4btn[] = { 12, 40, 41, 42, 43, 73, 80, -1 };
+               static int logitech_wheel[] = { 75, 76, 80, 81, 83, 88, -1 };
+               static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
+                                                       76, 80, 81, 83, 88, 96, 97, -1 };
+
+               int devicetype = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
+
+               psmouse->vendor = "Logitech";
+               psmouse->name = "Mouse";
+
+               if (param[1] < 3)
+                       clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
+               if (param[1] < 2)
+                       clear_bit(BTN_RIGHT, psmouse->dev.keybit);
+
+               psmouse->type = PSMOUSE_PS2;
+
+               for (i = 0; logitech_ps2pp[i] != -1; i++)
+                       if (logitech_ps2pp[i] == devicetype) psmouse->type = PSMOUSE_PS2PP;
+
+               if (psmouse->type != PSMOUSE_PS2PP) return PSMOUSE_PS2;
+
+               for (i = 0; logitech_4btn[i] != -1; i++)
+                       if (logitech_4btn[i] == devicetype) set_bit(BTN_SIDE, psmouse->dev.keybit);
+
+               for (i = 0; logitech_wheel[i] != -1; i++)
+                       if (logitech_wheel[i] == devicetype) set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+/*
+ * Do Logitech PS2++ / PS2T++ magic init.
+ */
+
+               if (devicetype == 97) { /* TouchPad 3 */
+
+                       set_bit(REL_WHEEL, psmouse->dev.relbit);
+                       set_bit(REL_HWHEEL, psmouse->dev.relbit);
+
+                       param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */
+                       psmouse_command(psmouse, param, 0x30d1);
+                       param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */
+                       psmouse_command(psmouse, param, 0x30d1);
+                       param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */
+                       psmouse_command(psmouse, param, 0x30d1);
+
+                       param[0] = 0;
+                       if (!psmouse_command(psmouse, param, 0x13d1) &&
+                               param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14)
+                               return PSMOUSE_PS2TPP;
+
+               } else {
+                       psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
+                       psmouse_ps2pp_cmd(psmouse, param, 0xDB);
+
+                       if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 &&
+                               (param[2] & 3) == ((param[1] >> 2) & 3))
+                                       return PSMOUSE_PS2PP;
+               }
+
+       }
+
+/*
+ * Try IntelliMouse magic init.
+ */
+
+       param[0] = 200;
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+       param[0] = 100;
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+       param[0] =  80;
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+       psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
+       
+       if (param[0] == 3) {
+
+               set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+/*
+ * Try IntelliMouse Explorer magic init.
+ */
+
+               param[0] = 200;
+               psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+               param[0] = 200;
+               psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+               param[0] =  80;
+               psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+               psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
+
+               if (param[0] == 4) {
+
+                       psmouse->vendor = "Microsoft";
+                       psmouse->name = "IntelliMouse Explorer";
+
+                       set_bit(BTN_SIDE, psmouse->dev.keybit);
+                       set_bit(BTN_EXTRA, psmouse->dev.keybit);
+
+                       return PSMOUSE_IMEX;
+               }
+
+               psmouse->vendor = "Microsoft";
+               psmouse->name = "IntelliMouse";
+
+               return PSMOUSE_IMPS;
+       }
+
+/*
+ * Okay, all failed, we have a standard mouse here. The number of the buttons is
+ * still a question, though.
+ */
+
+       psmouse->vendor = "Generic";
+       psmouse->name = "Mouse";
+
+       return PSMOUSE_PS2;
+}
+
+/*
+ * psmouse_probe() probes for a PS/2 mouse.
+ */
+
+static int psmouse_probe(struct psmouse *psmouse)
+{
+       unsigned char param[2];
+
+/*
+ * First we reset and disable the mouse.
+ */
+
+       if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
+               return -1;
+
+/*
+ * Next, we check if it's a mouse. It should send 0x00 or 0x03
+ * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
+ */
+
+       param[0] = param[1] = 0xa5;
+
+       if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
+               return -1;
+
+       if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
+               return -1;
+
+/*
+ * And here we try to determine if it has any extensions over the
+ * basic PS/2 3-button mouse.
+ */
+
+       return psmouse->type = psmouse_extensions(psmouse);
+}
+
+/*
+ * psmouse_initialize() initializes the mouse to a sane state.
+ */
+
+static void psmouse_initialize(struct psmouse *psmouse)
+{
+       unsigned char param[2];
+
+/*
+ * We set the mouse report rate to a highest possible value.
+ * We try 100 first in case mouse fails to set 200.
+ */
+
+       param[0] = 100;
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+
+       param[0] = 200;
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+
+/*
+ * We also set the resolution and scaling.
+ */
+
+       param[0] = 3;
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+       psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+
+/*
+ * We set the mouse into streaming mode.
+ */
+
+       psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+
+/*
+ * Last, we enable the mouse so that we get reports from it.
+ */
+
+       if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) {
+               printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
+       }
+
+}
+
+/*
+ * psmouse_disconnect() cleans up after we don't want talk
+ * to the mouse anymore.
+ */
+
+static void psmouse_disconnect(struct serio *serio)
+{
+       struct psmouse *psmouse = serio->private;
+       input_unregister_device(&psmouse->dev);
+       serio_close(serio);
+       kfree(psmouse);
+}
+
+/*
+ * psmouse_powerup() is called when we get the powerup
+ * sequence - 0xaa [0x00], so that the mouse/kbd is re-probed.
+ */
+
+static void psmouse_powerup(void *data)
+{
+        struct psmouse *psmouse = data;
+
+       if (psmouse->packet[0] == PSMOUSE_RET_BAT && (psmouse->pktcnt == 1 ||
+          (psmouse->pktcnt == 2 && psmouse->packet[1] == 0x00))) {
+               mdelay(40); /* FIXME!!! Wait some nicer way */
+               serio_rescan(psmouse->serio);
+       }
+}
+
+/*
+ * psmouse_connect() is a callback form the serio module when
+ * an unhandled serio port is found.
+ */
+
+static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
+{
+       struct psmouse *psmouse;
+       
+       if ((serio->type & SERIO_TYPE) != SERIO_8042)
+               return;
+
+       if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
+               return;
+
+       memset(psmouse, 0, sizeof(struct psmouse));
+
+       psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+       psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+       psmouse->serio = serio;
+       psmouse->dev.private = psmouse;
+       psmouse->tq.routine = psmouse_powerup;
+       psmouse->tq.data = psmouse;
+
+       serio->private = psmouse;
+
+       if (serio_open(serio, dev)) {
+               kfree(psmouse);
+               return;
+       }
+
+       if (psmouse_probe(psmouse) <= 0) {
+               serio_close(serio);
+               kfree(psmouse);
+               return;
+       }
+       
+       sprintf(psmouse->devname, "%s %s %s",
+               psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
+       sprintf(psmouse->phys, "%s/input0",
+               serio->phys);
+
+       psmouse->dev.name = psmouse->devname;
+       psmouse->dev.phys = psmouse->phys;
+       psmouse->dev.idbus = BUS_I8042;
+       psmouse->dev.idvendor = psmouse->type;
+       psmouse->dev.idproduct = 0x0002;
+       psmouse->dev.idversion = 0x0100;
+
+       input_register_device(&psmouse->dev);
+       
+       printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
+
+       psmouse_initialize(psmouse);
+}
+
+static struct serio_dev psmouse_dev = {
+       interrupt:      psmouse_interrupt,
+       connect:        psmouse_connect,
+       disconnect:     psmouse_disconnect
+};
+
+int __init psmouse_init(void)
+{
+       serio_register_device(&psmouse_dev);
+       return 0;
+}
+
+void __exit psmouse_exit(void)
+{
+       serio_unregister_device(&psmouse_dev);
+}
+
+module_init(psmouse_init);
+module_exit(psmouse_exit);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
new file mode 100644 (file)
index 0000000..04d16de
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * $Id: rpcmouse.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *      Russel King
+ */
+
+/*
+ * Acorn RiscPC mouse driver for Linux/ARM
+ */
+
+/*
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/iomd.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
+MODULE_LICENSE("GPL");
+
+#define IOMD_MOUSEBTN  0x800C4000
+
+static short rpcmouse_lastx, rpcmouse_lasty;
+
+static struct input_dev rpcmouse_dev = {
+       evbit:          { BIT(EV_KEY) | BIT(EV_REL) },
+       keybit:         { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
+       relbit:         { BIT(REL_X) | BIT(REL_Y) },
+       name:           "Acorn RiscPC Mouse",
+       phys:           "rpcmouse/input0",
+       idbus:          BUS_ISA,
+       idvendor:       0x0005,
+       idproduct:      0x0001,
+       idversion:      0x0100,
+};
+
+static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       short x, y, dx, dy, b;
+
+       x = (short) inl(IOMD_MOUSEX);
+       y = (short) inl(IOMD_MOUSEY);
+       b = (short) inl(IOMD_MOUSEBTN);
+
+       dx = x - rpcmouse_lastx;
+       dy = y - rpcmouse_lasty; 
+
+       rpcmouse_lastx = x;
+       rpcmouse_lasty = y;
+
+       input_report_rel(&rpcmouse_dev, REL_X, dx);
+       input_report_rel(&rpcmouse_dev, REL_Y, dy);
+
+       input_report_key(&amimouse_dev, BTN_LEFT,   buttons & 0x10);
+       input_report_key(&amimouse_dev, BTN_MIDDLE, buttons & 0x20);
+       input_report_key(&amimouse_dev, BTN_RIGHT,  buttons & 0x40);
+}
+
+static int __init rpcmouse_init(void)
+{
+       rpcmouse_lastx = (short) inl(IOMD_MOUSEX);
+       rpcmouse_lasty = (short) inl(IOMD_MOUSEY);
+
+       if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", NULL)) {
+               printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
+               return -1;
+       }
+
+       input_register_device(&rpcmouse_dev);
+       printk(KERN_INFO "input%d: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE);
+
+       return 0;
+}
+
+static void __exit rpcmouse_exit(void)
+{
+       input_unregister_device(&rpcmouse_dev);
+       free_irq(IRQ_VSYNCPULSE, NULL);
+}
+
+module_init(rpcmouse_init);
+module_exit(rpcmouse_exit);
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
new file mode 100644 (file)
index 0000000..0b084b4
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * $Id: sermouse.c,v 1.15 2001/10/09 22:34:17 jsimmons Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ *  Serial mouse driver for Linux
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/config.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Serial mouse driver");
+MODULE_LICENSE("GPL");
+
+static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
+                                       "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
+                                       "Logitech MZ++ Mouse"};
+
+struct sermouse {
+       struct input_dev dev;
+       signed char buf[8];
+       unsigned char count;
+       unsigned char type;
+       unsigned long last;
+       char phys[32];
+};
+
+/*
+ * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and
+ * applies some prediction to the data, resulting in 96 updates per
+ * second, which is as good as a PS/2 or USB mouse.
+ */
+
+static void sermouse_process_msc(struct sermouse *sermouse, signed char data)
+{
+       struct input_dev *dev = &sermouse->dev;
+       signed char *buf = sermouse->buf;
+
+       switch (sermouse->count) {
+
+               case 0:
+                       if ((data & 0xf8) != 0x80) return;
+                       input_report_key(dev, BTN_LEFT,   !(data & 4)); 
+                       input_report_key(dev, BTN_RIGHT,  !(data & 1));
+                       input_report_key(dev, BTN_MIDDLE, !(data & 2));
+                       break;
+
+               case 1: 
+               case 3: 
+                       input_report_rel(dev, REL_X, data / 2);
+                       input_report_rel(dev, REL_Y, -buf[1]);
+                       buf[0] = data - data / 2;
+                       break;
+
+               case 2: 
+               case 4:
+                       input_report_rel(dev, REL_X, buf[0]);
+                       input_report_rel(dev, REL_Y, buf[1] - data);
+                       buf[1] = data / 2;
+                       break;
+       }
+
+       if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1)))
+               sermouse->count = 0;
+}
+
+/*
+ * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and
+ * generates events. With prediction it gets 80 updates/sec, assuming
+ * standard 3-byte packets and 1200 bps.
+ */
+
+static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
+{
+       struct input_dev *dev = &sermouse->dev;
+       signed char *buf = sermouse->buf;
+
+       if (data & 0x40) sermouse->count = 0;
+
+       switch (sermouse->count) {
+
+               case 0:
+                       buf[1] = data;
+                       input_report_key(dev, BTN_LEFT,   (data >> 5) & 1);
+                       input_report_key(dev, BTN_RIGHT,  (data >> 4) & 1);
+                       break;
+
+               case 1:
+                       buf[2] = data;
+                       data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f));
+                       input_report_rel(dev, REL_X, data / 2);
+                       input_report_rel(dev, REL_Y, buf[4]);
+                       buf[3] = data - data / 2;
+                       break;
+
+               case 2:
+                       /* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */
+                       if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1]))
+                               input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key));
+                       buf[0] = buf[1];
+
+                       data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f));
+                       input_report_rel(dev, REL_X, buf[3]);
+                       input_report_rel(dev, REL_Y, data - buf[4]);
+                       buf[4] = data / 2;
+                       break;
+
+               case 3:
+
+                       switch (sermouse->type) {
+                       
+                               case SERIO_MS:
+                                        sermouse->type = SERIO_MP;
+
+                               case SERIO_MP:
+                                       if ((data >> 2) & 3) break;     /* M++ Wireless Extension packet. */
+                                       input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1);
+                                       input_report_key(dev, BTN_SIDE,   (data >> 4) & 1);
+                                       break;
+
+                               case SERIO_MZP:
+                               case SERIO_MZPP:
+                                       input_report_key(dev, BTN_SIDE,   (data >> 5) & 1);
+
+                               case SERIO_MZ:
+                                       input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
+                                       input_report_rel(dev, REL_WHEEL, (data & 7) - (data & 8));
+                                       break;
+                       }
+                                       
+                       break;
+
+               case 4:
+               case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */
+                       buf[1] = (data >> 2) & 0x0f;
+                       break;
+
+               case 5:
+               case 7: /* Ignore anything besides MZ++ */
+                       if (sermouse->type != SERIO_MZPP) break;
+
+                       switch (buf[1]) {
+
+                               case 1: /* Extra mouse info */
+
+                                       input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
+                                       input_report_key(dev, BTN_EXTRA, (data >> 5) & 1);
+                                       input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8));
+
+                                       break;
+
+                               default: /* We don't decode anything else yet. */
+
+                                       printk(KERN_WARNING
+                                               "sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]);
+                                       break;
+                       }
+
+                       break;
+       }
+
+       sermouse->count++;
+}
+
+/*
+ * sermouse_interrupt() handles incoming characters, either gathering them into
+ * packets or passing them to the command routine as command output.
+ */
+
+static void sermouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+       struct sermouse *sermouse = serio->private;
+
+       if (jiffies - sermouse->last > 2) sermouse->count = 0;
+       sermouse->last = jiffies;
+
+       if (sermouse->type > SERIO_SUN)
+               sermouse_process_ms(sermouse, data);
+       else
+               sermouse_process_msc(sermouse, data);
+}
+
+/*
+ * sermouse_disconnect() cleans up after we don't want talk
+ * to the mouse anymore.
+ */
+
+static void sermouse_disconnect(struct serio *serio)
+{
+       struct sermouse *sermouse = serio->private;
+       input_unregister_device(&sermouse->dev);
+       serio_close(serio);
+       kfree(sermouse);
+}
+
+/*
+ * sermouse_connect() is a callback form the serio module when
+ * an unhandled serio port is found.
+ */
+
+static void sermouse_connect(struct serio *serio, struct serio_dev *dev)
+{
+       struct sermouse *sermouse;
+       unsigned char c;
+       
+       if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+               return;
+
+       if (!(serio->type & SERIO_PROTO) || ((serio->type & SERIO_PROTO) > SERIO_MZPP))
+               return;
+
+       if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL)))
+               return;
+
+       memset(sermouse, 0, sizeof(struct sermouse));
+
+       sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+       sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       sermouse->dev.private = sermouse;
+
+       serio->private = sermouse;
+
+       sermouse->type = serio->type & SERIO_PROTO;
+       c = (serio->type & SERIO_EXTRA) >> 16;
+
+       if (c & 0x01) set_bit(BTN_MIDDLE, &sermouse->dev.keybit);
+       if (c & 0x02) set_bit(BTN_SIDE, &sermouse->dev.keybit);
+       if (c & 0x04) set_bit(BTN_EXTRA, &sermouse->dev.keybit);
+       if (c & 0x10) set_bit(REL_WHEEL, &sermouse->dev.relbit);
+       if (c & 0x20) set_bit(REL_HWHEEL, &sermouse->dev.relbit);
+
+       sprintf(sermouse->phys, "%s/input0", serio->phys);
+
+       sermouse->dev.name = sermouse_protocols[sermouse->type];
+       sermouse->dev.phys = sermouse->phys;
+       sermouse->dev.idbus = BUS_RS232;
+       sermouse->dev.idvendor = sermouse->type;
+       sermouse->dev.idproduct = c;
+       sermouse->dev.idversion = 0x0100;
+
+       if (serio_open(serio, dev)) {
+               kfree(sermouse);
+               return;
+       }
+
+       input_register_device(&sermouse->dev);
+       
+       printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
+}
+
+static struct serio_dev sermouse_dev = {
+       interrupt:      sermouse_interrupt,
+       connect:        sermouse_connect,
+       disconnect:     sermouse_disconnect
+};
+
+int __init sermouse_init(void)
+{
+       serio_register_device(&sermouse_dev);
+       return 0;
+}
+
+void __exit sermouse_exit(void)
+{
+       serio_unregister_device(&sermouse_dev);
+}
+
+module_init(sermouse_init);
+module_exit(sermouse_exit);
diff --git a/drivers/input/power.c b/drivers/input/power.c
new file mode 100644 (file)
index 0000000..84af6b3
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $
+ *
+ *  Copyright (c) 2001 "Crazy" James Simmons  
+ *
+ *  Input driver Power Management.
+ *
+ *  Sponsored by Transvirtual Technology.
+ */
+
+/*
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <jsimmons@transvirtual.com>.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+static struct input_handler power_handler;
+
+/*
+ * Power management can't be done in a interrupt context. So we have to
+ * use keventd.
+ */
+static int suspend_button_pushed = 0;
+static void suspend_button_task_handler(void *data)
+{
+        //extern void pm_do_suspend(void);
+        udelay(200); /* debounce */
+        //pm_do_suspend();
+        suspend_button_pushed = 0;
+}
+
+static struct tq_struct suspend_button_task = {
+        routine: suspend_button_task_handler
+};
+
+static void power_event(struct input_handle *handle, unsigned int type, 
+                       unsigned int code, int down)
+{
+       struct input_dev *dev = handle->dev;
+
+       printk("Entering power_event\n");
+
+       if (type != EV_KEY || type != EV_PWR) return;
+
+       if (type == EV_PWR) {
+               switch (code) {
+                       case KEY_SUSPEND:
+                               printk("Powering down entire device\n");
+
+                               //pm_send_all(PM_SUSPEND, dev);
+
+                               if (!suspend_button_pushed) {
+                                       suspend_button_pushed = 1;
+                                       schedule_task(&suspend_button_task);
+                               }
+                               break;
+                       case KEY_POWER:
+                               /* Hum power down the machine. */
+                               break;
+                       default:        
+                               return;
+               }
+       } else {
+               switch (code) {
+                       case KEY_SUSPEND:
+                               printk("Powering down input device\n");
+                               /* This is risky. See pm.h for details. */
+                               if (dev->state != PM_RESUME)
+                                       dev->state = PM_RESUME;
+                               else 
+                                       dev->state = PM_SUSPEND;        
+                               pm_send(dev->pm_dev, dev->state, dev);  
+                               break;
+                       case KEY_POWER:
+                               /* Turn the input device off completely ? */
+                               break;
+                       default:
+                               return;
+               }
+       }
+       return;
+}
+
+static struct input_handle *power_connect(struct input_handler *handler, 
+                                         struct input_dev *dev, 
+                                         struct input_device_id *id)
+{
+       struct input_handle *handle;
+
+       if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit))
+               return NULL;    
+
+       if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit)))
+               return NULL;
+
+       if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+               return NULL;
+       memset(handle, 0, sizeof(struct input_handle));
+
+       handle->dev = dev;
+       handle->handler = handler;
+
+       input_open_device(handle);
+
+       printk(KERN_INFO "power.c: Adding power management to input layer\n");
+       return handle;
+}
+
+static void power_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       kfree(handle);
+}
+
+static struct input_device_id power_ids[] = {
+       {
+               flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+               evbit: { BIT(EV_KEY) },
+               keybit: { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) }
+       },      
+       {
+               flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+               evbit: { BIT(EV_KEY) },
+               keybit: { [LONG(KEY_POWER)] = BIT(KEY_POWER) }
+       },      
+       {
+               flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+               evbit: { BIT(EV_PWR) },
+       },      
+       { },    /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, power_ids);
+       
+static struct input_handler power_handler = {
+       event:          power_event,
+       connect:        power_connect,
+       disconnect:     power_disconnect,
+       name:           "power",
+       id_table:       power_ids,
+};
+
+static int __init power_init(void)
+{
+       input_register_handler(&power_handler);
+       return 0;
+}
+
+static void __exit power_exit(void)
+{
+       input_unregister_handler(&power_handler);
+}
+
+module_init(power_init);
+module_exit(power_exit);
+
+MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
+MODULE_DESCRIPTION("Input Power Management driver");
diff --git a/drivers/input/touchscreen/Config.help b/drivers/input/touchscreen/Config.help
new file mode 100644 (file)
index 0000000..d31ba33
--- /dev/null
@@ -0,0 +1,16 @@
+CONFIG_INPUT_TOUCHSCREEN
+  Say Y here, and a list of supported touchscreens will be displayed.
+  This option doesn't affect the kernel.
+
+  If unsure, say Y.
+
+CONFIG_TOUCHSCREEN_GUNZE
+  Say Y here if you have the Gunze AHL-51 touchscreen connected to
+  your system.
+
+  If unsure, say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called gunze.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff --git a/drivers/input/touchscreen/Config.in b/drivers/input/touchscreen/Config.in
new file mode 100644 (file)
index 0000000..f48cbd5
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Mouse driver configuration
+#
+
+bool 'Touchscreens' CONFIG_INPUT_TOUCHSCREEN
+
+dep_tristate '  Gunze AHL-51S touchscreen' CONFIG_TOUCHSCREEN_GUNZE $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
new file mode 100644 (file)
index 0000000..1acd962
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Makefile for the mouse drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET       := tsdrv.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_TOUCHSCREEN_GUNZE)        += gunze.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
new file mode 100644 (file)
index 0000000..8ea3050
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * $Id: gunze.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ */
+
+/*
+ * Gunze AHL-51S touchscreen driver for Linux
+ */
+
+/*
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define        GUNZE_MAX_LENGTH        10
+
+static char *gunze_name = "Gunze AHL-51S TouchScreen";
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct gunze {
+       struct input_dev dev;
+       struct serio *serio;
+       int idx;
+       unsigned char data[GUNZE_MAX_LENGTH];
+       char phys[32];
+};
+
+static void gunze_process_packet(struct gunze* gunze)
+{
+       struct input_dev *dev = &gunze->dev;
+
+       if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
+               (gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
+               gunze->data[10] = 0;
+               printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data);
+               return;
+       }
+
+       input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4);
+       input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3);
+       input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
+}
+
+static void gunze_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+       struct gunze* gunze = serio->private;
+
+       if (data == '\r') {
+               gunze_process_packet(gunze);
+               gunze->idx = 0;
+       } else {
+               if (gunze->idx < GUNZE_MAX_LENGTH)
+                       gunze->data[gunze->idx++] = data;
+       } 
+}
+
+/*
+ * gunze_disconnect() is the opposite of gunze_connect()
+ */
+
+static void gunze_disconnect(struct serio *serio)
+{
+       struct gunze* gunze = serio->private;
+       input_unregister_device(&gunze->dev);
+       serio_close(serio);
+       kfree(gunze);
+}
+
+/*
+ * gunze_connect() is the routine that is called when someone adds a
+ * new serio device. It looks whether it was registered as a Gunze touchscreen
+ * and if yes, registers it as an input device.
+ */
+
+static void gunze_connect(struct serio *serio, struct serio_dev *dev)
+{
+       struct gunze *gunze;
+
+       if (serio->type != (SERIO_RS232 | SERIO_GUNZE))
+               return;
+
+       if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL)))
+               return;
+
+       memset(gunze, 0, sizeof(struct gunze));
+
+       gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);        
+       gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+       gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+       gunze->dev.absmin[ABS_X] = 96;   gunze->dev.absmin[ABS_Y] = 72;
+       gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000;
+
+       gunze->serio = serio;
+       serio->private = gunze;
+
+       sprintf(gunze->phys, "%s/input0", serio->phys);
+
+       gunze->dev.private = gunze;
+       gunze->dev.name = gunze_name;
+       gunze->dev.phys = gunze->phys;
+       gunze->dev.idbus = BUS_RS232;
+       gunze->dev.idvendor = SERIO_GUNZE;
+       gunze->dev.idproduct = 0x0051;
+       gunze->dev.idversion = 0x0100;
+
+       if (serio_open(serio, dev)) {
+               kfree(gunze);
+               return;
+       }
+
+       input_register_device(&gunze->dev);
+
+       printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev gunze_dev = {
+       interrupt:      gunze_interrupt,
+       connect:        gunze_connect,
+       disconnect:     gunze_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init gunze_init(void)
+{
+       serio_register_device(&gunze_dev);
+       return 0;
+}
+
+void __exit gunze_exit(void)
+{
+       serio_unregister_device(&gunze_dev);
+}
+
+module_init(gunze_init);
+module_exit(gunze_exit);
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
new file mode 100644 (file)
index 0000000..50d2387
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
+ *
+ *  Copyright (c) 2001 "Crazy" james Simmons 
+ *
+ *  Input driver to Touchscreen device driver module.
+ *
+ *  Sponsored by Transvirtual Technology
+ */
+
+/*
+ * 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
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <jsimmons@transvirtual.com>.
+ */
+
+#define TSDEV_MINOR_BASE       128
+#define TSDEV_MINORS           32
+#define TSDEV_BUFFER_SIZE      64
+
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/config.h>
+#include <linux/smp_lock.h>
+#include <linux/random.h>
+#include <linux/time.h>
+
+#ifndef CONFIG_INPUT_TSDEV_SCREEN_X
+#define CONFIG_INPUT_TSDEV_SCREEN_X    240
+#endif
+#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
+#define CONFIG_INPUT_TSDEV_SCREEN_Y    320
+#endif
+
+struct tsdev {
+       int exist;
+       int open;
+       int minor;
+       char name[16];
+       wait_queue_head_t wait;
+       struct tsdev_list *list;
+       struct input_handle handle;
+       devfs_handle_t devfs;
+};
+
+/* From Compaq's Touch Screen Specification version 0.2 (draft) */
+typedef struct {
+       short pressure;
+       short x;
+       short y;
+       short millisecs;
+} TS_EVENT;
+
+struct tsdev_list {
+       struct fasync_struct *fasync;
+       struct tsdev_list *next;
+       struct tsdev *tsdev;
+       int head, tail;
+       int oldx, oldy, pendown;
+       TS_EVENT event[TSDEV_BUFFER_SIZE];
+};
+
+static struct input_handler tsdev_handler;
+
+static struct tsdev *tsdev_table[TSDEV_MINORS];
+
+static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
+static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
+
+static int tsdev_fasync(int fd, struct file *file, int on)
+{
+       struct tsdev_list *list = file->private_data;
+       int retval;
+
+       retval = fasync_helper(fd, file, on, &list->fasync);
+       return retval < 0 ? retval : 0;
+}
+
+static int tsdev_open(struct inode *inode, struct file *file)
+{
+       int i = minor(inode->i_rdev) - TSDEV_MINOR_BASE;
+       struct tsdev_list *list;
+
+       if (i >= TSDEV_MINORS || !tsdev_table[i])
+               return -ENODEV;
+
+       if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
+               return -ENOMEM;
+       memset(list, 0, sizeof(struct tsdev_list));
+
+       list->tsdev = tsdev_table[i];
+       list->next = tsdev_table[i]->list;
+       tsdev_table[i]->list = list;
+       file->private_data = list;
+
+       if (!list->tsdev->open++)
+               if (list->tsdev->exist)
+                       input_open_device(&list->tsdev->handle);
+       return 0;
+}
+
+static int tsdev_release(struct inode *inode, struct file *file)
+{
+       struct tsdev_list *list = file->private_data;
+       struct tsdev_list **listptr;
+
+       listptr = &list->tsdev->list;
+       tsdev_fasync(-1, file, 0);
+
+       while (*listptr && (*listptr != list))
+               listptr = &((*listptr)->next);
+       *listptr = (*listptr)->next;
+
+       if (!--list->tsdev->open) {
+               if (list->tsdev->exist) {
+                       input_close_device(&list->tsdev->handle);
+               } else {
+                       input_unregister_minor(list->tsdev->devfs);
+                       tsdev_table[list->tsdev->minor] = NULL;
+                       kfree(list->tsdev);
+               }
+       }
+       kfree(list);
+       return 0;
+}
+
+static ssize_t tsdev_read(struct file *file, char *buffer, size_t count,
+                         loff_t * ppos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       struct tsdev_list *list = file->private_data;
+       int retval = 0;
+
+       if (list->head == list->tail) {
+               add_wait_queue(&list->tsdev->wait, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               while (list->head == list->tail) {
+                       if (!list->tsdev->exist) {
+                               retval = -ENODEV;
+                               break;
+                       }
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+               }
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&list->tsdev->wait, &wait);
+       }
+
+       if (retval)
+               return retval;
+
+       while (list->head != list->tail
+              && retval + sizeof(TS_EVENT) <= count) {
+               if (copy_to_user
+                   (buffer + retval, list->event + list->tail,
+                    sizeof(TS_EVENT)))
+                       return -EFAULT;
+               list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
+               retval += sizeof(TS_EVENT);
+       }
+       return retval;
+}
+
+/* No kernel lock - fine */
+static unsigned int tsdev_poll(struct file *file, poll_table * wait)
+{
+       struct tsdev_list *list = file->private_data;
+
+       poll_wait(file, &list->tsdev->wait, wait);
+       if (list->head != list->tail)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static int tsdev_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+/*
+       struct tsdev_list *list = file->private_data;
+        struct tsdev *evdev = list->tsdev;
+        struct input_dev *dev = tsdev->handle.dev;
+        int retval;
+       
+       switch (cmd) {
+               case HHEHE:
+                       return 0;
+               case hjff:
+                       return 0;
+               default:
+                       return 0;
+       }
+*/
+       return -EINVAL;
+}
+
+struct file_operations tsdev_fops = {
+       owner:          THIS_MODULE,
+       open:           tsdev_open,
+       release:        tsdev_release,
+       read:           tsdev_read,
+       poll:           tsdev_poll,
+       fasync:         tsdev_fasync,
+       ioctl:          tsdev_ioctl,
+};
+
+static void tsdev_event(struct input_handle *handle, unsigned int type,
+                       unsigned int code, int value)
+{
+       struct tsdev *tsdev = handle->private;
+       struct tsdev_list *list = tsdev->list;
+       struct timeval time;
+       int size;
+
+       while (list) {
+               switch (type) {
+               case EV_ABS:
+                       switch (code) {
+                       case ABS_X:
+                               if (!list->pendown)
+                                       return;
+
+                               size =
+                                   handle->dev->absmax[ABS_X] -
+                                   handle->dev->absmin[ABS_X];
+                               if (size > 0)
+                                       list->oldx =
+                                           ((value -
+                                             handle->dev->absmin[ABS_X]) *
+                                            xres / size);
+                               else
+                                       list->oldx =
+                                           ((value -
+                                             handle->dev->absmin[ABS_X]));
+                               break;
+                       case ABS_Y:
+                               if (!list->pendown)
+                                       return;
+
+                               size =
+                                   handle->dev->absmax[ABS_Y] -
+                                   handle->dev->absmin[ABS_Y];
+                               if (size > 0)
+                                       list->oldy =
+                                           ((value -
+                                             handle->dev->absmin[ABS_Y]) *
+                                            yres / size);
+                               else
+                                       list->oldy =
+                                           ((value -
+                                             handle->dev->absmin[ABS_Y]));
+                               break;
+                       case ABS_PRESSURE:
+                               list->pendown =
+                                   ((value >
+                                     handle->dev->
+                                     absmin[ABS_PRESSURE])) ? value -
+                                   handle->dev->absmin[ABS_PRESSURE] : 0;
+                               break;
+                       }
+                       break;
+
+               case EV_REL:
+                       switch (code) {
+                       case REL_X:
+                               if (!list->pendown)
+                                       return;
+
+                               list->oldx += value;
+                               if (list->oldx < 0)
+                                       list->oldx = 0;
+                               else if (list->oldx > xres)
+                                       list->oldx = xres;
+                               break;
+                       case REL_Y:
+                               if (!list->pendown)
+                                       return;
+
+                               list->oldy += value;
+                               if (list->oldy < 0)
+                                       list->oldy = 0;
+                               else if (list->oldy > xres)
+                                       list->oldy = xres;
+                               break;
+                       }
+                       break;
+
+               case EV_KEY:
+                       if (code == BTN_TOUCH || code == BTN_MOUSE) {
+                               switch (value) {
+                               case 0:
+                                       list->pendown = 0;
+                                       break;
+                               case 1:
+                                       if (!list->pendown)
+                                               list->pendown = 1;
+                                       break;
+                               case 2:
+                                       return;
+                               }
+                       } else
+                               return;
+                       break;
+               }
+               do_gettimeofday(&time);
+               list->event[list->head].millisecs = time.tv_usec / 100;
+               list->event[list->head].pressure = list->pendown;
+               list->event[list->head].x = list->oldx;
+               list->event[list->head].y = list->oldy;
+               list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
+               kill_fasync(&list->fasync, SIGIO, POLL_IN);
+               list = list->next;
+       }
+       wake_up_interruptible(&tsdev->wait);
+}
+
+static struct input_handle *tsdev_connect(struct input_handler *handler,
+                                         struct input_dev *dev,
+                                         struct input_device_id *id)
+{
+       struct tsdev *tsdev;
+       int minor;
+
+       for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor];
+            minor++);
+       if (minor == TSDEV_MINORS) {
+               printk(KERN_ERR
+                      "tsdev: You have way too many touchscreens\n");
+               return NULL;
+       }
+
+       if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL)))
+               return NULL;
+       memset(tsdev, 0, sizeof(struct tsdev));
+       init_waitqueue_head(&tsdev->wait);
+
+       tsdev->minor = minor;
+       tsdev_table[minor] = tsdev;
+       sprintf(tsdev->name, "ts%d", minor);
+
+       tsdev->handle.dev = dev;
+       tsdev->handle.name = tsdev->name;
+       tsdev->handle.handler = handler;
+       tsdev->handle.private = tsdev;
+
+       tsdev->devfs =
+           input_register_minor("ts%d", minor, TSDEV_MINOR_BASE);
+
+       tsdev->exist = 1;
+
+       return &tsdev->handle;
+}
+
+static void tsdev_disconnect(struct input_handle *handle)
+{
+       struct tsdev *tsdev = handle->private;
+
+       tsdev->exist = 0;
+
+       if (tsdev->open) {
+               input_close_device(handle);
+               wake_up_interruptible(&tsdev->wait);
+       } else {
+               input_unregister_minor(tsdev->devfs);
+               tsdev_table[tsdev->minor] = NULL;
+               kfree(tsdev);
+       }
+}
+
+static struct input_device_id tsdev_ids[] = {
+       {
+             flags:    INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
+             evbit:    { BIT(EV_KEY) | BIT(EV_REL) },
+             keybit:   { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
+             relbit:   { BIT(REL_X) | BIT(REL_Y) },
+        },/* A mouse like device, at least one button, two relative axes */
+
+       {
+             flags:    INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+             evbit:    { BIT(EV_KEY) | BIT(EV_ABS) },
+             keybit:   { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+             absbit:   { BIT(ABS_X) | BIT(ABS_Y) },
+        },/* A tablet like device, at least touch detection, two absolute axes */
+
+       {},/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, tsdev_ids);
+
+static struct input_handler tsdev_handler = {
+       event:          tsdev_event,
+       connect:        tsdev_connect,
+       disconnect:     tsdev_disconnect,
+       fops:           &tsdev_fops,
+       minor:          TSDEV_MINOR_BASE,
+       name:           "tsdev",
+       id_table:       tsdev_ids,
+};
+
+static int __init tsdev_init(void)
+{
+       input_register_handler(&tsdev_handler);
+       printk(KERN_INFO "ts: Compaq touchscreen protocol output\n");
+       return 0;
+}
+
+static void __exit tsdev_exit(void)
+{
+       input_unregister_handler(&tsdev_handler);
+}
+
+module_init(tsdev_init);
+module_exit(tsdev_exit);
+
+MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
+MODULE_DESCRIPTION("Input driver to touchscreen converter");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal screen resolution");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical screen resolution");