aboutsummaryrefslogtreecommitdiff
path: root/drivers/input/serio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/serio')
-rw-r--r--drivers/input/serio/Kconfig183
-rw-r--r--drivers/input/serio/Makefile23
-rw-r--r--drivers/input/serio/ambakmi.c231
-rw-r--r--drivers/input/serio/ct82c710.c225
-rw-r--r--drivers/input/serio/gscps2.c467
-rw-r--r--drivers/input/serio/hil_mlc.c949
-rw-r--r--drivers/input/serio/hp_sdc.c1054
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c358
-rw-r--r--drivers/input/serio/i8042-io.h93
-rw-r--r--drivers/input/serio/i8042-ip22io.h76
-rw-r--r--drivers/input/serio/i8042-jazzio.h69
-rw-r--r--drivers/input/serio/i8042-ppcio.h136
-rw-r--r--drivers/input/serio/i8042-sparcio.h116
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h333
-rw-r--r--drivers/input/serio/i8042.c1116
-rw-r--r--drivers/input/serio/i8042.h133
-rw-r--r--drivers/input/serio/libps2.c305
-rw-r--r--drivers/input/serio/maceps2.c176
-rw-r--r--drivers/input/serio/parkbd.c218
-rw-r--r--drivers/input/serio/pcips2.c234
-rw-r--r--drivers/input/serio/q40kbd.c163
-rw-r--r--drivers/input/serio/rpckbd.c156
-rw-r--r--drivers/input/serio/sa1111ps2.c359
-rw-r--r--drivers/input/serio/serio.c859
-rw-r--r--drivers/input/serio/serio_raw.c403
-rw-r--r--drivers/input/serio/serport.c226
26 files changed, 8661 insertions, 0 deletions
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
new file mode 100644
index 00000000000..b3710733b36
--- /dev/null
+++ b/drivers/input/serio/Kconfig
@@ -0,0 +1,183 @@
+#
+# Input core configuration
+#
+config SERIO
+ tristate "Serial I/O support" if EMBEDDED || !X86
+ default y
+ ---help---
+ Say Yes here if you have any input device that uses serial I/O to
+ communicate with the system. This includes the
+ * standard AT keyboard and PS/2 mouse *
+ as well as serial mice, Sun keyboards, some joysticks and 6dof
+ devices and more.
+
+ If unsure, say Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called serio.
+
+if SERIO
+
+config SERIO_I8042
+ tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
+ default y
+ depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K
+ ---help---
+ i8042 is the chip over which the standard AT keyboard and PS/2
+ mouse are connected to the computer. If you use these devices,
+ you'll need to say Y here.
+
+ If unsure, say Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called i8042.
+
+config SERIO_SERPORT
+ tristate "Serial port line discipline"
+ default y
+ ---help---
+ Say Y here if you plan to use an input device (mouse, joystick,
+ tablet, 6dof) that communicates over the RS232 serial (COM) port.
+
+ More information is available: <file:Documentation/input/input.txt>
+
+ If unsure, say Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called serport.
+
+config SERIO_CT82C710
+ tristate "ct82c710 Aux port controller"
+ depends on X86
+ ---help---
+ Say Y here if you have a Texas Instruments TravelMate notebook
+ equipped with the ct82c710 chip and want to use a mouse connected
+ to the "QuickPort".
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ct82c710.
+
+config SERIO_Q40KBD
+ tristate "Q40 keyboard controller"
+ depends on Q40
+
+config SERIO_PARKBD
+ tristate "Parallel port keyboard adapter"
+ depends on PARPORT
+ ---help---
+ Say Y here if you built a simple parallel port adapter to attach
+ an additional AT keyboard, XT keyboard or PS/2 mouse.
+
+ More information is available: <file:Documentation/input/input.txt>
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called parkbd.
+
+config SERIO_RPCKBD
+ tristate "Acorn RiscPC keyboard controller"
+ depends on ARCH_ACORN || ARCH_CLPS7500
+ default y
+ help
+ Say Y here if you have the Acorn RiscPC and want to use an AT
+ keyboard connected to its keyboard controller.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rpckbd.
+
+config SERIO_AMBAKMI
+ tristate "AMBA KMI keyboard controller"
+ depends on ARM_AMBA
+
+config SERIO_SA1111
+ tristate "Intel SA1111 keyboard controller"
+ depends on SA1111
+
+config SERIO_GSCPS2
+ tristate "HP GSC PS/2 keyboard and PS/2 mouse controller"
+ depends on GSC
+ default y
+ help
+ This driver provides support for the PS/2 ports on PA-RISC machines
+ over which HP PS/2 keyboards and PS/2 mice may be connected.
+ If you use these devices, you'll need to say Y here.
+
+ It's safe to enable this driver, so if unsure, say Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gscps2.
+
+config HP_SDC
+ tristate "HP System Device Controller i8042 Support"
+ depends on GSC && SERIO
+ default y
+ ---help---
+ This option enables supports for the the "System Device
+ Controller", an i8042 carrying microcode to manage a
+ few miscellanous devices on some Hewlett Packard systems.
+ The SDC itself contains a 10ms resolution timer/clock capable
+ of delivering interrupts on a periodic and one-shot basis.
+ The SDC may also be connected to a battery-backed real-time
+ clock, a basic audio waveform generator, and an HP-HIL Master
+ Link Controller serving up to seven input devices.
+
+ By itself this option is rather useless, but enabling it will
+ enable selection of drivers for the abovementioned devices.
+ It is, however, incompatible with the old, reliable HIL keyboard
+ driver, and the new HIL driver is experimental, so if you plan
+ to use a HIL keyboard as your primary keyboard, you may wish
+ to keep using that driver until the new HIL drivers have had
+ more testing.
+
+config HIL_MLC
+ tristate "HIL MLC Support (needed for HIL input devices)"
+ depends on HP_SDC
+
+config SERIO_PCIPS2
+ tristate "PCI PS/2 keyboard and PS/2 mouse controller"
+ depends on PCI
+ help
+ Say Y here if you have a Mobility Docking station with PS/2
+ keyboard and mice ports.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pcips2.
+
+config SERIO_MACEPS2
+ tristate "SGI O2 MACE PS/2 controller"
+ depends on SGI_IP32
+ help
+ Say Y here if you have SGI O2 workstation and want to use its
+ PS/2 ports.
+
+ To compile this driver as a module, choose M here: the
+ module will be called maceps2.
+
+config SERIO_LIBPS2
+ tristate "PS/2 driver library" if EMBEDDED
+ help
+ Say Y here if you are using a driver for device connected
+ to a PS/2 port, such as PS/2 mouse or standard AT keyboard.
+
+ To compile this driver as a module, choose M here: the
+ module will be called libps2.
+
+config SERIO_RAW
+ tristate "Raw access to serio ports"
+ help
+ Say Y here if you want to have raw access to serio ports, such as
+ AUX ports on i8042 keyboard controller. Each serio port that is
+ bound to this driver will be accessible via a char device with
+ major 10 and dynamically allocated minor. The driver will try
+ allocating minor 1 (that historically corresponds to /dev/psaux)
+ first. To bind this driver to a serio port use sysfs interface:
+
+ echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
+
+ To compile this driver as a module, choose M here: the
+ module will be called serio_raw.
+
+endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
new file mode 100644
index 00000000000..678a8599f9f
--- /dev/null
+++ b/drivers/input/serio/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for the input core drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_SERIO) += serio.o
+obj-$(CONFIG_SERIO_I8042) += i8042.o
+obj-$(CONFIG_SERIO_PARKBD) += parkbd.o
+obj-$(CONFIG_SERIO_SERPORT) += serport.o
+obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o
+obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o
+obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o
+obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o
+obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o
+obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o
+obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
+obj-$(CONFIG_HP_SDC) += hp_sdc.o
+obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o
+obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
+obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
+obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
+obj-$(CONFIG_SERIO_RAW) += serio_raw.o
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
new file mode 100644
index 00000000000..9b1ab5e7a98
--- /dev/null
+++ b/drivers/input/serio/ambakmi.c
@@ -0,0 +1,231 @@
+/*
+ * linux/drivers/input/serio/ambakmi.c
+ *
+ * Copyright (C) 2000-2003 Deep Blue Solutions Ltd.
+ * Copyright (C) 2002 Russell King.
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware/amba.h>
+#include <asm/hardware/amba_kmi.h>
+#include <asm/hardware/clock.h>
+
+#define KMI_BASE (kmi->base)
+
+struct amba_kmi_port {
+ struct serio *io;
+ struct clk *clk;
+ void __iomem *base;
+ unsigned int irq;
+ unsigned int divisor;
+ unsigned int open;
+};
+
+static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct amba_kmi_port *kmi = dev_id;
+ unsigned int status = readb(KMIIR);
+ int handled = IRQ_NONE;
+
+ while (status & KMIIR_RXINTR) {
+ serio_interrupt(kmi->io, readb(KMIDATA), 0, regs);
+ status = readb(KMIIR);
+ handled = IRQ_HANDLED;
+ }
+
+ return handled;
+}
+
+static int amba_kmi_write(struct serio *io, unsigned char val)
+{
+ struct amba_kmi_port *kmi = io->port_data;
+ unsigned int timeleft = 10000; /* timeout in 100ms */
+
+ while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--)
+ udelay(10);
+
+ if (timeleft)
+ writeb(val, KMIDATA);
+
+ return timeleft ? 0 : SERIO_TIMEOUT;
+}
+
+static int amba_kmi_open(struct serio *io)
+{
+ struct amba_kmi_port *kmi = io->port_data;
+ unsigned int divisor;
+ int ret;
+
+ ret = clk_use(kmi->clk);
+ if (ret)
+ goto out;
+
+ ret = clk_enable(kmi->clk);
+ if (ret)
+ goto clk_unuse;
+
+ divisor = clk_get_rate(kmi->clk) / 8000000 - 1;
+ writeb(divisor, KMICLKDIV);
+ writeb(KMICR_EN, KMICR);
+
+ ret = request_irq(kmi->irq, amba_kmi_int, 0, "kmi-pl050", kmi);
+ if (ret) {
+ printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq);
+ writeb(0, KMICR);
+ goto clk_disable;
+ }
+
+ writeb(KMICR_EN | KMICR_RXINTREN, KMICR);
+
+ return 0;
+
+ clk_disable:
+ clk_disable(kmi->clk);
+ clk_unuse:
+ clk_unuse(kmi->clk);
+ out:
+ return ret;
+}
+
+static void amba_kmi_close(struct serio *io)
+{
+ struct amba_kmi_port *kmi = io->port_data;
+
+ writeb(0, KMICR);
+
+ free_irq(kmi->irq, kmi);
+ clk_disable(kmi->clk);
+ clk_unuse(kmi->clk);
+}
+
+static int amba_kmi_probe(struct amba_device *dev, void *id)
+{
+ struct amba_kmi_port *kmi;
+ struct serio *io;
+ int ret;
+
+ ret = amba_request_regions(dev, NULL);
+ if (ret)
+ return ret;
+
+ kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
+ io = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!kmi || !io) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(kmi, 0, sizeof(struct amba_kmi_port));
+ memset(io, 0, sizeof(struct serio));
+
+ io->id.type = SERIO_8042;
+ io->write = amba_kmi_write;
+ io->open = amba_kmi_open;
+ io->close = amba_kmi_close;
+ strlcpy(io->name, dev->dev.bus_id, sizeof(io->name));
+ strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys));
+ io->port_data = kmi;
+ io->dev.parent = &dev->dev;
+
+ kmi->io = io;
+ kmi->base = ioremap(dev->res.start, KMI_SIZE);
+ if (!kmi->base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ kmi->clk = clk_get(&dev->dev, "KMIREFCLK");
+ if (IS_ERR(kmi->clk)) {
+ ret = PTR_ERR(kmi->clk);
+ goto unmap;
+ }
+
+ kmi->irq = dev->irq[0];
+ amba_set_drvdata(dev, kmi);
+
+ serio_register_port(kmi->io);
+ return 0;
+
+ unmap:
+ iounmap(kmi->base);
+ out:
+ kfree(kmi);
+ kfree(io);
+ amba_release_regions(dev);
+ return ret;
+}
+
+static int amba_kmi_remove(struct amba_device *dev)
+{
+ struct amba_kmi_port *kmi = amba_get_drvdata(dev);
+
+ amba_set_drvdata(dev, NULL);
+
+ serio_unregister_port(kmi->io);
+ clk_put(kmi->clk);
+ iounmap(kmi->base);
+ kfree(kmi);
+ amba_release_regions(dev);
+ return 0;
+}
+
+static int amba_kmi_resume(struct amba_device *dev)
+{
+ struct amba_kmi_port *kmi = amba_get_drvdata(dev);
+
+ /* kick the serio layer to rescan this port */
+ serio_reconnect(kmi->io);
+
+ return 0;
+}
+
+static struct amba_id amba_kmi_idtable[] = {
+ {
+ .id = 0x00041050,
+ .mask = 0x000fffff,
+ },
+ { 0, 0 }
+};
+
+static struct amba_driver ambakmi_driver = {
+ .drv = {
+ .name = "kmi-pl050",
+ },
+ .id_table = amba_kmi_idtable,
+ .probe = amba_kmi_probe,
+ .remove = amba_kmi_remove,
+ .resume = amba_kmi_resume,
+};
+
+static int __init amba_kmi_init(void)
+{
+ return amba_driver_register(&ambakmi_driver);
+}
+
+static void __exit amba_kmi_exit(void)
+{
+ amba_driver_unregister(&ambakmi_driver);
+}
+
+module_init(amba_kmi_init);
+module_exit(amba_kmi_exit);
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("AMBA KMI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
new file mode 100644
index 00000000000..dd0f5bd9024
--- /dev/null
+++ b/drivers/input/serio/ct82c710.c
@@ -0,0 +1,225 @@
+/*
+ * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 82C710 C&T mouse port chip 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/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("82C710 C&T mouse port chip driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * ct82c710 interface
+ */
+
+#define CT82C710_DEV_IDLE 0x01 /* Device Idle */
+#define CT82C710_RX_FULL 0x02 /* Device Char received */
+#define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */
+#define CT82C710_RESET 0x08 /* Device Reset */
+#define CT82C710_INTS_ON 0x10 /* Device Interrupt On */
+#define CT82C710_ERROR_FLAG 0x20 /* Device Error */
+#define CT82C710_CLEAR 0x40 /* Device Clear */
+#define CT82C710_ENABLE 0x80 /* Device Enable */
+
+#define CT82C710_IRQ 12
+
+#define CT82C710_DATA ct82c710_iores.start
+#define CT82C710_STATUS (ct82c710_iores.start + 1)
+
+static struct serio *ct82c710_port;
+static struct platform_device *ct82c710_device;
+static struct resource ct82c710_iores;
+
+/*
+ * Interrupt handler for the 82C710 mouse port. A character
+ * is waiting in the 82C710.
+ */
+
+static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
+{
+ return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs);
+}
+
+/*
+ * Wait for device to send output char and flush any input char.
+ */
+
+static int ct82c170_wait(void)
+{
+ int timeout = 60000;
+
+ while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE))
+ != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) {
+
+ if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA);
+
+ udelay(1);
+ timeout--;
+ }
+
+ return !timeout;
+}
+
+static void ct82c710_close(struct serio *serio)
+{
+ if (ct82c170_wait())
+ printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
+
+ outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS);
+
+ if (ct82c170_wait())
+ printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
+
+ free_irq(CT82C710_IRQ, NULL);
+}
+
+static int ct82c710_open(struct serio *serio)
+{
+ unsigned char status;
+
+ if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL))
+ return -1;
+
+ status = inb_p(CT82C710_STATUS);
+
+ status |= (CT82C710_ENABLE | CT82C710_RESET);
+ outb_p(status, CT82C710_STATUS);
+
+ status &= ~(CT82C710_RESET);
+ outb_p(status, CT82C710_STATUS);
+
+ status |= CT82C710_INTS_ON;
+ outb_p(status, CT82C710_STATUS); /* Enable interrupts */
+
+ while (ct82c170_wait()) {
+ printk(KERN_ERR "ct82c710: Device busy in open()\n");
+ status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
+ outb_p(status, CT82C710_STATUS);
+ free_irq(CT82C710_IRQ, NULL);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Write to the 82C710 mouse device.
+ */
+
+static int ct82c710_write(struct serio *port, unsigned char c)
+{
+ if (ct82c170_wait()) return -1;
+ outb_p(c, CT82C710_DATA);
+ return 0;
+}
+
+/*
+ * See if we can find a 82C710 device. Read mouse address.
+ */
+
+static int __init ct82c710_probe(void)
+{
+ outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
+ outb_p(0xaa, 0x3fa); /* Inverse of 55 */
+ outb_p(0x36, 0x3fa); /* Address the chip */
+ outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */
+ outb_p(0x1b, 0x2fa); /* Inverse of e4 */
+ outb_p(0x0f, 0x390); /* Write index */
+ if (inb_p(0x391) != 0xe4) /* Config address found? */
+ return -1; /* No: no 82C710 here */
+
+ outb_p(0x0d, 0x390); /* Write index */
+ ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */
+ ct82c710_iores.end = ct82c710_iores.start + 1;
+ ct82c710_iores.flags = IORESOURCE_IO;
+ outb_p(0x0f, 0x390);
+ outb_p(0x0f, 0x391); /* Close config mode */
+
+ return 0;
+}
+
+static struct serio * __init ct82c710_allocate_port(void)
+{
+ struct serio *serio;
+
+ serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ if (serio) {
+ memset(serio, 0, sizeof(struct serio));
+ serio->id.type = SERIO_8042;
+ serio->open = ct82c710_open;
+ serio->close = ct82c710_close;
+ serio->write = ct82c710_write;
+ serio->dev.parent = &ct82c710_device->dev;
+ strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name));
+ snprintf(serio->phys, sizeof(serio->phys), "isa%04lx/serio0", CT82C710_DATA);
+ }
+
+ return serio;
+}
+
+static int __init ct82c710_init(void)
+{
+ if (ct82c710_probe())
+ return -ENODEV;
+
+ ct82c710_device = platform_device_register_simple("ct82c710", -1, &ct82c710_iores, 1);
+ if (IS_ERR(ct82c710_device))
+ return PTR_ERR(ct82c710_device);
+
+ if (!(ct82c710_port = ct82c710_allocate_port())) {
+ platform_device_unregister(ct82c710_device);
+ return -ENOMEM;
+ }
+
+ serio_register_port(ct82c710_port);
+
+ printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n",
+ CT82C710_DATA, CT82C710_IRQ);
+
+ return 0;
+}
+
+static void __exit ct82c710_exit(void)
+{
+ serio_unregister_port(ct82c710_port);
+ platform_device_unregister(ct82c710_device);
+}
+
+module_init(ct82c710_init);
+module_exit(ct82c710_exit);
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
new file mode 100644
index 00000000000..897e4c12b64
--- /dev/null
+++ b/drivers/input/serio/gscps2.c
@@ -0,0 +1,467 @@
+/*
+ * drivers/input/serio/gscps2.c
+ *
+ * Copyright (c) 2004 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
+ * Copyright (c) 2002 Thibaut Varene <varenet@parisc-linux.org>
+ *
+ * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
+ * Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca>
+ * Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
+ * Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
+ *
+ * HP GSC PS/2 port driver, found in PA/RISC Workstations
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * TODO:
+ * - Dino testing (did HP ever shipped a machine on which this port
+ * was usable/enabled ?)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci_ids.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/parisc-device.h>
+
+MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@parisc-linux.org>, Helge Deller <deller@gmx.de>");
+MODULE_DESCRIPTION("HP GSC PS2 port driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
+
+#define PFX "gscps2.c: "
+
+/*
+ * Driver constants
+ */
+
+/* various constants */
+#define ENABLE 1
+#define DISABLE 0
+
+#define GSC_DINO_OFFSET 0x0800 /* offset for DINO controller versus LASI one */
+
+/* PS/2 IO port offsets */
+#define GSC_ID 0x00 /* device ID offset (see: GSC_ID_XXX) */
+#define GSC_RESET 0x00 /* reset port offset */
+#define GSC_RCVDATA 0x04 /* receive port offset */
+#define GSC_XMTDATA 0x04 /* transmit port offset */
+#define GSC_CONTROL 0x08 /* see: Control register bits */
+#define GSC_STATUS 0x0C /* see: Status register bits */
+
+/* Control register bits */
+#define GSC_CTRL_ENBL 0x01 /* enable interface */
+#define GSC_CTRL_LPBXR 0x02 /* loopback operation */
+#define GSC_CTRL_DIAG 0x20 /* directly control clock/data line */
+#define GSC_CTRL_DATDIR 0x40 /* data line direct control */
+#define GSC_CTRL_CLKDIR 0x80 /* clock line direct control */
+
+/* Status register bits */
+#define GSC_STAT_RBNE 0x01 /* Receive Buffer Not Empty */
+#define GSC_STAT_TBNE 0x02 /* Transmit Buffer Not Empty */
+#define GSC_STAT_TERR 0x04 /* Timeout Error */
+#define GSC_STAT_PERR 0x08 /* Parity Error */
+#define GSC_STAT_CMPINTR 0x10 /* Composite Interrupt = irq on any port */
+#define GSC_STAT_DATSHD 0x40 /* Data Line Shadow */
+#define GSC_STAT_CLKSHD 0x80 /* Clock Line Shadow */
+
+/* IDs returned by GSC_ID port register */
+#define GSC_ID_KEYBOARD 0 /* device ID values */
+#define GSC_ID_MOUSE 1
+
+
+static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs);
+
+#define BUFFER_SIZE 0x0f
+
+/* GSC PS/2 port device struct */
+struct gscps2port {
+ struct list_head node;
+ struct parisc_device *padev;
+ struct serio *port;
+ spinlock_t lock;
+ char *addr;
+ u8 act, append; /* position in buffer[] */
+ struct {
+ u8 data;
+ u8 str;
+ } buffer[BUFFER_SIZE+1];
+ int id;
+};
+
+/*
+ * Various HW level routines
+ */
+
+#define gscps2_readb_input(x) readb((x)+GSC_RCVDATA)
+#define gscps2_readb_control(x) readb((x)+GSC_CONTROL)
+#define gscps2_readb_status(x) readb((x)+GSC_STATUS)
+#define gscps2_writeb_control(x, y) writeb((x), (y)+GSC_CONTROL)
+
+
+/*
+ * wait_TBE() - wait for Transmit Buffer Empty
+ */
+
+static int wait_TBE(char *addr)
+{
+ int timeout = 25000; /* device is expected to react within 250 msec */
+ while (gscps2_readb_status(addr) & GSC_STAT_TBNE) {
+ if (!--timeout)
+ return 0; /* This should not happen */
+ udelay(10);
+ }
+ return 1;
+}
+
+
+/*
+ * gscps2_flush() - flush the receive buffer
+ */
+
+static void gscps2_flush(struct gscps2port *ps2port)
+{
+ while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
+ gscps2_readb_input(ps2port->addr);
+ ps2port->act = ps2port->append = 0;
+}
+
+/*
+ * gscps2_writeb_output() - write a byte to the port
+ *
+ * returns 1 on sucess, 0 on error
+ */
+
+static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
+{
+ unsigned long flags;
+ char *addr = ps2port->addr;
+
+ if (!wait_TBE(addr)) {
+ printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data);
+ return 0;
+ }
+
+ while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
+ /* wait */;
+
+ spin_lock_irqsave(&ps2port->lock, flags);
+ writeb(data, addr+GSC_XMTDATA);
+ spin_unlock_irqrestore(&ps2port->lock, flags);
+
+ /* this is ugly, but due to timing of the port it seems to be necessary. */
+ mdelay(6);
+
+ /* make sure any received data is returned as fast as possible */
+ /* this is important e.g. when we set the LEDs on the keyboard */
+ gscps2_interrupt(0, NULL, NULL);
+
+ return 1;
+}
+
+
+/*
+ * gscps2_enable() - enables or disables the port
+ */
+
+static void gscps2_enable(struct gscps2port *ps2port, int enable)
+{
+ unsigned long flags;
+ u8 data;
+
+ /* now enable/disable the port */
+ spin_lock_irqsave(&ps2port->lock, flags);
+ gscps2_flush(ps2port);
+ data = gscps2_readb_control(ps2port->addr);
+ if (enable)
+ data |= GSC_CTRL_ENBL;
+ else
+ data &= ~GSC_CTRL_ENBL;
+ gscps2_writeb_control(data, ps2port->addr);
+ spin_unlock_irqrestore(&ps2port->lock, flags);
+ wait_TBE(ps2port->addr);
+ gscps2_flush(ps2port);
+}
+
+/*
+ * gscps2_reset() - resets the PS/2 port
+ */
+
+static void gscps2_reset(struct gscps2port *ps2port)
+{
+ char *addr = ps2port->addr;
+ unsigned long flags;
+
+ /* reset the interface */
+ spin_lock_irqsave(&ps2port->lock, flags);
+ gscps2_flush(ps2port);
+ writeb(0xff, addr+GSC_RESET);
+ gscps2_flush(ps2port);
+ spin_unlock_irqrestore(&ps2port->lock, flags);
+
+ /* enable it */
+ gscps2_enable(ps2port, ENABLE);
+}
+
+static LIST_HEAD(ps2port_list);
+
+/**
+ * gscps2_interrupt() - Interruption service routine
+ *
+ * This function reads received PS/2 bytes and processes them on
+ * all interfaces.
+ * The problematic part here is, that the keyboard and mouse PS/2 port
+ * share the same interrupt and it's not possible to send data if any
+ * one of them holds input data. To solve this problem we try to receive
+ * the data as fast as possible and handle the reporting to the upper layer
+ * later.
+ */
+
+static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+ struct gscps2port *ps2port;
+
+ list_for_each_entry(ps2port, &ps2port_list, node) {
+
+ unsigned long flags;
+ spin_lock_irqsave(&ps2port->lock, flags);
+
+ while ( (ps2port->buffer[ps2port->append].str =
+ gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) {
+ ps2port->buffer[ps2port->append].data =
+ gscps2_readb_input(ps2port->addr);
+ ps2port->append = ((ps2port->append+1) & BUFFER_SIZE);
+ }
+
+ spin_unlock_irqrestore(&ps2port->lock, flags);
+
+ } /* list_for_each_entry */
+
+ /* all data was read from the ports - now report the data to upper layer */
+
+ list_for_each_entry(ps2port, &ps2port_list, node) {
+
+ while (ps2port->act != ps2port->append) {
+
+ unsigned int rxflags;
+ u8 data, status;
+
+ /* Did new data arrived while we read existing data ?
+ If yes, exit now and let the new irq handler start over again */
+ if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR)
+ return IRQ_HANDLED;
+
+ status = ps2port->buffer[ps2port->act].str;
+ data = ps2port->buffer[ps2port->act].data;
+
+ ps2port->act = ((ps2port->act+1) & BUFFER_SIZE);
+ rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
+ ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 );
+
+ serio_interrupt(ps2port->port, data, rxflags, regs);
+
+ } /* while() */
+
+ } /* list_for_each_entry */
+
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * gscps2_write() -