Add tsdev, power and evbug event handlers.
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.
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>.
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
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.
--- /dev/null
+/*
+ * $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);
--- /dev/null
+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>.
+
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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, ¶m, 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, ¶m, ATKBD_CMD_EX_ENABLE))
+ return 4;
+
+/*
+ * Try to set the set we want.
+ */
+
+ param = atkbd_set;
+ if (atkbd_command(atkbd, ¶m, 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, ¶m, 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, ¶m, 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);
--- /dev/null
+/*
+ * $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:
+ */
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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);
--- /dev/null
+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>.
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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:
+ */
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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");
--- /dev/null
+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>.
--- /dev/null
+#
+# Mouse driver configuration
+#
+
+bool 'Touchscreens' CONFIG_INPUT_TOUCHSCREEN
+
+dep_tristate ' Gunze AHL-51S touchscreen' CONFIG_TOUCHSCREEN_GUNZE $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * $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);
--- /dev/null
+/*
+ * $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");