Commit 29886383 authored by Vojtech Pavlik's avatar Vojtech Pavlik

Add keyboard, mouse and touchscreen drivers.

Add tsdev, power and evbug event handlers.
parent b65e5bd5
...@@ -64,6 +64,18 @@ CONFIG_INPUT_JOYDEV ...@@ -64,6 +64,18 @@ CONFIG_INPUT_JOYDEV
The module will be called joydev.o. If you want to compile it as a 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>. 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 CONFIG_INPUT_EVDEV
Say Y here if you want your input device events be accessible Say Y here if you want your input device events be accessible
under char device 13:64+ - /dev/input/eventX in a generic way. under char device 13:64+ - /dev/input/eventX in a generic way.
...@@ -72,3 +84,17 @@ CONFIG_INPUT_EVDEV ...@@ -72,3 +84,17 @@ CONFIG_INPUT_EVDEV
inserted in and removed from the running kernel whenever you want). 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 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>. 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>.
...@@ -6,20 +6,34 @@ mainmenu_option next_comment ...@@ -6,20 +6,34 @@ mainmenu_option next_comment
comment 'Input device support' comment 'Input device support'
tristate 'Input core support' CONFIG_INPUT tristate 'Input core support' CONFIG_INPUT
comment 'Userland interfaces'
dep_tristate ' Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT dep_tristate ' Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
dep_tristate ' Mouse interface' CONFIG_INPUT_MOUSEDEV $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 if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
fi fi
dep_tristate ' Joystick interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT 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 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/gameport/Config.in
source drivers/input/serio/Config.in source drivers/input/serio/Config.in
comment 'Input Device Drivers'
if [ "$CONFIG_INPUT" != "n" ]; then 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/joystick/Config.in
source drivers/input/touchscreen/Config.in
fi fi
endmenu endmenu
...@@ -13,8 +13,14 @@ obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o ...@@ -13,8 +13,14 @@ obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.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_JOYSTICK) += joystick/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
# The global Rules.make. # The global Rules.make.
......
/*
* $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);
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>.
#
# 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
#
# 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
/*
* $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);
/*
* $Id: atkbd.c,v 1.31 2002/01/27 01:48:54 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/tqueue.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
MODULE_PARM(atkbd_set, "1i");
MODULE_LICENSE("GPL");
static int atkbd_set = 2;
/*
* Scancode to keycode tables. These are just the default setting, and
* are loadable via an userland utility.
*/
static unsigned char atkbd_set2_keycode[512] = {
0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0,
85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123,
82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,
0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0,
136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125,
0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127,
159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142,
157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138,
0, 0, 0, 0, 0, 0,153,140, 0,255, 96, 0, 0, 0,143, 0,
133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112,
110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119
};
static unsigned char atkbd_set3_keycode[512] = {
0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64,
136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66,
125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,
113,114, 40, 84, 26, 13, 87, 99,100, 54, 28, 27, 43, 84, 88, 70,
108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104,
82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55, 85,
89, 90, 91, 92, 74, 0, 0, 0, 0, 0, 0,125,126,127,112, 0,
0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,
148,149,147,140, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255
};
#define ATKBD_CMD_SETLEDS 0x10ed
#define ATKBD_CMD_GSCANSET 0x11f0
#define ATKBD_CMD_SSCANSET 0x10f0
#define ATKBD_CMD_GETID 0x02f2
#define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5
#define ATKBD_CMD_SETALL_MB 0x00f8
#define ATKBD_CMD_EX_ENABLE 0x10ea
#define ATKBD_CMD_EX_SETLEDS 0x20eb
#define ATKBD_RET_ACK 0xfa
#define ATKBD_RET_NAK 0xfe
#define ATKBD_KEY_UNKNOWN 0
#define ATKBD_KEY_BAT 251
#define ATKBD_KEY_EMUL0 252
#define ATKBD_KEY_EMUL1 253
#define ATKBD_KEY_RELEASE 254
#define ATKBD_KEY_NULL 255
/*
* The atkbd control structure
*/
struct atkbd {
unsigned char keycode[512];
struct input_dev dev;
struct serio *serio;
char name[64];
char phys[32];
struct tq_struct tq;
unsigned char cmdbuf[4];
unsigned char cmdcnt;
unsigned char set;
char release;
char ack;
char emul;
char error;
unsigned short id;
};
/*
* atkbd_interrupt(). Here takes place processing of data received from
* the keyboard into events.
*/
static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
{
struct atkbd *atkbd = serio->private;
int code = data;
#ifdef ATKBD_DEBUG
printk(KERN_DEBUG "atkbd.c: Received %02x\n", data);
#endif
switch (code) {
case ATKBD_RET_ACK:
atkbd->ack = 1;
return;
case ATKBD_RET_NAK:
atkbd->ack = -1;
return;
}
if (atkbd->cmdcnt) {
atkbd->cmdbuf[--atkbd->cmdcnt] = code;
return;
}
switch (atkbd->keycode[code]) {
case ATKBD_KEY_BAT:
queue_task(&atkbd->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
return;
case ATKBD_KEY_EMUL0:
atkbd->emul = 1;
return;
case ATKBD_KEY_EMUL1:
atkbd->emul = 2;
return;
case ATKBD_KEY_RELEASE:
atkbd->release = 1;
return;
}
if (atkbd->emul) {
if (--atkbd->emul) return;
code |= 0x100;
}
switch (atkbd->keycode[code]) {
case ATKBD_KEY_NULL:
break;
case ATKBD_KEY_UNKNOWN:
printk(KERN_WARNING "atkbd.c: Unknown key (set %d, scancode %#x, on %s) %s.\n",
atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed");
break;
default:
input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release);
}
atkbd->release = 0;
}
/*
* atkbd_sendbyte() sends a byte to the keyboard, and waits for
* acknowledge. It doesn't handle resends according to the keyboard
* protocol specs, because if these are needed, the keyboard needs
* replacement anyway, and they only make a mess in the protocol.
*/
static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
{
int timeout = 1000; /* 10 msec */
atkbd->ack = 0;
#ifdef ATKBD_DEBUG
printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
#endif
serio_write(atkbd->serio, byte);
while (!atkbd->ack && timeout--) udelay(10);
return -(atkbd->ack <= 0);
}
/*
* atkbd_command() sends a command, and its parameters to the keyboard,
* then waits for the response and puts it in the param array.
*/
static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
{
int timeout = 10000; /* 100 msec */
int send = (command >> 12) & 0xf;
int receive = (command >> 8) & 0xf;
int i;
atkbd->cmdcnt = receive;
if (command & 0xff)
if (atkbd_sendbyte(atkbd, command & 0xff))
return (atkbd->cmdcnt = 0) - 1;
for (i = 0; i < send; i++)
if (atkbd_sendbyte(atkbd, param[i]))
return (atkbd->cmdcnt = 0) - 1;
while (atkbd->cmdcnt && timeout--) udelay(10);
for (i = 0; i < receive; i++)
param[i] = atkbd->cmdbuf[(receive - 1) - i];
if (atkbd->cmdcnt)
return (atkbd->cmdcnt = 0) - 1;
return 0;
}
/*
* Event callback from the input module. Events that change the state of
* the hardware are processed here.
*/
static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct atkbd *atkbd = dev->private;
char param[2];
switch (type) {
case EV_LED:
*param = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
| (test_bit(LED_NUML, dev->led) ? 2 : 0)
| (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS);
if (atkbd->set == 4) {
param[0] = 0;
param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
| (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
| (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
| (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
}
return 0;
}
return -1;
}
/*
* atkbd_set_3 checks if a keyboard has a working Set 3 support, and
* sets it into that. Unfortunately there are keyboards that can be switched
* to Set 3, but don't work well in that (BTC Multimedia ...)
*/
static int atkbd_set_3(struct atkbd *atkbd)
{
unsigned char param;
/*
* For known special keyboards we can go ahead and set the correct set.
*/
if (atkbd->id == 0xaca1) {
param = 3;
atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET);
return 3;
}
/*
* We check for the extra keys on an some keyboards that need extra
* command to get enabled. This shouldn't harm any keyboards not
* knowing the command.
*/
param = 0x71;
if (!atkbd_command(atkbd, &param, ATKBD_CMD_EX_ENABLE))
return 4;
/*
* Try to set the set we want.
*/
param = atkbd_set;
if (atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET))
return 2;
/*
* Read set number. Beware here. Some keyboards always send '2'
* or some other number regardless into what mode they have been
* attempted to be set. Other keyboards treat the '0' command as
* 'set to set 0', and not 'report current set' as they should.
* In that case we time out, and return 2.
*/
param = 0;
if (atkbd_command(atkbd, &param, ATKBD_CMD_GSCANSET))
return 2;
/*
* Here we return the set number the keyboard reports about
* itself.
*/
return (param == 3) ? 3 : 2;
}
/*
* atkbd_probe() probes for an AT keyboard on a serio port.
*/
static int atkbd_probe(struct atkbd *atkbd)
{
unsigned char param[2];
/*
* Full reset with selftest can on some keyboards be annoyingly slow,
* so we just do a reset-and-disable on the keyboard, which
* is considerably faster, but doesn't have to reset everything.
*/
if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS))
return -1;
/*
* Next, we check if it's a keyboard. It should send 0xab83
* (0xab84 on IBM ThinkPad, and 0xaca1 on a NCD Sun layout keyboard,
* 0xab02 on unxlated i8042 and 0xab03 on unxlated ThinkPad, 0xab7f
* on Fujitsu Lifebook).
* If it's a mouse, it'll only send 0x00 (0x03 if it's MS mouse),
* and we'll time out here, and report an error.
*/
param[0] = param[1] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_GETID))
return -1;
atkbd->id = (param[0] << 8) | param[1];
if (atkbd->id != 0xab83 && atkbd->id != 0xab84 && atkbd->id != 0xaca1 &&
atkbd->id != 0xab7f && atkbd->id != 0xab02 && atkbd->id != 0xab03)
printk(KERN_WARNING "atkbd.c: Unusual keyboard ID: %#x on %s\n",
atkbd->id, atkbd->serio->phys);
return 0;
}
/*
* atkbd_initialize() sets the keyboard into a sane state.
*/
static void atkbd_initialize(struct atkbd *atkbd)
{
unsigned char param;
/*
* Disable autorepeat. We don't need it, as we do it in software anyway,
* because that way can get faster repeat, and have less system load
* (less accesses to the slow ISA hardware). If this fails, we don't care,
* and will just ignore the repeated keys.
*/
atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB);
/*
* We also shut off all the leds. The console code will turn them back on,
* if needed.
*/
param = 0;
atkbd_command(atkbd, &param, ATKBD_CMD_SETLEDS);
/*
* Last, we enable the keyboard so that we get keypresses from it.
*/
if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE))
printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
atkbd->serio->phys);
}
/*
* atkbd_disconnect() cleans up behind us ...
*/
static void atkbd_disconnect(struct serio *serio)
{
struct atkbd *atkbd = serio->private;
input_unregister_device(&atkbd->dev);
serio_close(serio);
kfree(atkbd);
}
/*
* atkbd_powerup() is called when the keyboard sends the 0xaa character,
* meaning that it was disconnected and reconnected. We close the port
* in that case and let the upper layer find an appropriate driver for
* the device that was connected. It may be a mouse, or a keyboard, we
* don't know yet.
*/
static void atkbd_powerup(void *data)
{
struct atkbd *atkbd = data;
mdelay(40); /* FIXME!!! Wait some nicer way */
serio_rescan(atkbd->serio);
}
/*
* atkbd_connect() is called when the serio module finds and interface
* that isn't handled yet by an appropriate device driver. We check if
* there is an AT keyboard out there and if yes, we register ourselves
* to the input module.
*/
static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
{
struct atkbd *atkbd;
int i;
if ((serio->type & SERIO_TYPE) != SERIO_8042)
return;
if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL)))
return;
memset(atkbd, 0, sizeof(struct atkbd));
atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
atkbd->serio = serio;
atkbd->dev.keycode = atkbd->keycode;
atkbd->dev.event = atkbd_event;
atkbd->dev.private = atkbd;
atkbd->tq.routine = atkbd_powerup;
atkbd->tq.data = atkbd;
serio->private = atkbd;
if (serio_open(serio, dev)) {
kfree(atkbd);
return;
}
if (atkbd_probe(atkbd)) {
serio_close(serio);
kfree(atkbd);
return;
}
atkbd->set = atkbd_set_3(atkbd);
if (atkbd->set == 4) {
atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE);
sprintf(atkbd->name, "AT Set 2 Extended keyboard\n");
} else
sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set);
sprintf(atkbd->phys, "%s/input0", serio->phys);
if (atkbd->set == 3)
memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
else
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
atkbd->dev.name = atkbd->name;
atkbd->dev.phys = atkbd->phys;
atkbd->dev.idbus = BUS_I8042;
atkbd->dev.idvendor = 0x0001;
atkbd->dev.idproduct = atkbd->set;
atkbd->dev.idversion = atkbd->id;
for (i = 0; i < 512; i++)
if (atkbd->keycode[i] && atkbd->keycode[i] <= 250)
set_bit(atkbd->keycode[i], atkbd->dev.keybit);
input_register_device(&atkbd->dev);
printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
atkbd_initialize(atkbd);
}
static struct serio_dev atkbd_dev = {
interrupt: atkbd_interrupt,
connect: atkbd_connect,
disconnect: atkbd_disconnect
};
/*
* Module init and exit.
*/
void __init atkbd_setup(char *str, int *ints)
{
if (!ints[0]) atkbd_set = ints[1];
}
int __init atkbd_init(void)
{
serio_register_device(&atkbd_dev);
return 0;
}
void __exit atkbd_exit(void)
{
serio_unregister_device(&atkbd_dev);
}
module_init(atkbd_init);
module_exit(atkbd_exit);
/*
* $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:
*/
/*
* 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);
/*
* $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);
/*
* $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);
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>.
#
# 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
#
# 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
/*
* $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);
/*
* $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);
/*
* $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);
/*
* $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:
*/
/*
* $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);
/*
* $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);
/*
* $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);
/*
* $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);
/*
* $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");
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>.
#
# Mouse driver configuration
#
bool 'Touchscreens' CONFIG_INPUT_TOUCHSCREEN
dep_tristate ' Gunze AHL-51S touchscreen' CONFIG_TOUCHSCREEN_GUNZE $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
#
# 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
/*
* $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);
/*
* $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");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment