Commit b65e5bd5 authored by Vojtech Pavlik's avatar Vojtech Pavlik

Add new serio modules for PS/2 AUX/KBD.

parent 07b8fb25
......@@ -12,6 +12,18 @@ CONFIG_SERIO
The module will be called serio.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
CONFIG_SERIO_I8042
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.
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 i8042.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
CONFIG_SERIO_SERPORT
Say Y here if you plan to use an input device (mouse, joystick,
tablet, 6dof) that communicates over the RS232 serial (COM) port.
......@@ -24,3 +36,38 @@ CONFIG_SERIO_SERPORT
inserted in and removed from the running kernel whenever you want).
The module will be called serport.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_SERIO_CT82C710
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.
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 ct82c710.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_SERIO_PARKBD
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.
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 parkbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_SERIO_ACORN
Say Y here if you have the Acorn RiscPC and want to use an AT
keyboard connected to its keyboard controller.
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 rpckbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
......@@ -4,4 +4,16 @@
tristate 'Serial i/o support' CONFIG_SERIO
dep_tristate ' i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO $CONFIG_ISA
if [ "$CONFIG_INPUT_I8042" != "n" ]; then
hex ' Register Base Address' CONFIG_I8042_REG_BASE 60
int ' PS/2 Keyboard IRQ' CONFIG_I8042_KBD_IRQ 1
int ' PS/2 AUX IRQ' CONFIG_I8042_AUX_IRQ 12
fi
dep_tristate ' Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO
dep_tristate ' ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO $CONFIG_ISA
dep_tristate ' Parallel port keyboard adapter' CONFIG_SERIO_PARKBD $CONFIG_SERIO $CONFIG_PARPORT
if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
dep_tristate ' Acorn RiscPC keyboard controller' CONFIG_SERIO_ACORN $CONFIG_SERIO
fi
......@@ -9,7 +9,11 @@ export-objs := serio.o
# 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
# The global Rules.make.
......
/*
* $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 <asm/io.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/sched.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("82C710 C&T mouse port chip driver");
MODULE_LICENSE("GPL");
static char ct82c710_name[] = "C&T 82c710 mouse port";
static char ct82c710_phys[16];
/*
* 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
static int ct82c710_data = 0;
static int ct82c710_status = 0;
static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * 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;
}
static struct serio ct82c710_port =
{
type: SERIO_8042,
name: ct82c710_name,
phys: ct82c710_phys,
write: ct82c710_write,
open: ct82c710_open,
close: ct82c710_close,
};
/*
* Interrupt handler for the 82C710 mouse port. A character
* is waiting in the 82C710.
*/
static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
{
if (ct82c710_port.dev)
ct82c710_port.dev->interrupt(&ct82c710_port, inb(ct82c710_data), 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_data = inb_p(0x391) << 2; /* Get mouse I/O address */
ct82c710_status = ct82c710_data + 1;
outb_p(0x0f, 0x390);
outb_p(0x0f, 0x391); /* Close config mode */
return 0;
}
int __init ct82c710_init(void)
{
if (ct82c710_probe())
return -ENODEV;
if (request_region(ct82c710_data, 2, "ct82c710"))
return -EBUSY;
sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data);
serio_register_port(&ct82c710_port);
printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n",
ct82c710_data, CT82C710_IRQ);
return 0;
}
void __exit ct82c710_exit(void)
{
serio_unregister_port(&ct82c710_port);
release_region(ct82c710_data, 2);
}
module_init(ct82c710_init);
module_exit(ct82c710_exit);
This diff is collapsed.
#ifndef _I8042_H
#define _I8042_H
/*
* $Id: i8042.h,v 1.6 2001/10/05 22:48:09 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
*/
/*
* If you want to reset your i8042 upon boot, define this.
*/
#undef I8042_RESET
/*
* If you want to trace all the i/o the i8042 module does for
* debugging purposes, define this.
*/
#undef I8042_DEBUG_IO
/*
* On most PC based systems the keyboard IRQ is 1.
*/
#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ
/*
* On most PC based systems the aux port IRQ is 12. There are exceptions,
* though. Unfortunately IRQ probing is not possible without touching
* the device attached to the port.
*/
#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ
/*
* This is in 50us units, the time we wait for the i8042 to react. This
* has to be long enough for the i8042 itself to timeout on sending a byte
* to a non-existent mouse.
*/
#define I8042_CTL_TIMEOUT 10000
/*
* Register numbers.
*/
#define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4
#define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4
#define I8042_DATA_REG CONFIG_I8042_REG_BASE
/*
* Status register bits.
*/
#define I8042_STR_PARITY 0x80
#define I8042_STR_TIMEOUT 0x40
#define I8042_STR_AUXDATA 0x20
#define I8042_STR_KEYLOCK 0x10
#define I8042_STR_CMDDAT 0x08
#define I8042_STR_IBF 0x02
#define I8042_STR_OBF 0x01
/*
* Control register bits.
*/
#define I8042_CTR_KBDINT 0x01
#define I8042_CTR_AUXINT 0x02
#define I8042_CTR_IGNKEYLOCK 0x08
#define I8042_CTR_KBDDIS 0x10
#define I8042_CTR_AUXDIS 0x20
#define I8042_CTR_XLATE 0x40
/*
* Commands.
*/
#define I8042_CMD_CTL_RCTR 0x0120
#define I8042_CMD_CTL_WCTR 0x1060
#define I8042_CMD_CTL_TEST 0x01aa
#define I8042_CMD_KBD_DISABLE 0x00ad
#define I8042_CMD_KBD_ENABLE 0x00ae
#define I8042_CMD_KBD_TEST 0x01ab
#define I8042_CMD_KBD_LOOP 0x11d2
#define I8042_CMD_AUX_DISABLE 0x00a7
#define I8042_CMD_AUX_ENABLE 0x00a8
#define I8042_CMD_AUX_TEST 0x01a9
#define I8042_CMD_AUX_SEND 0x10d4
#define I8042_CMD_AUX_LOOP 0x11d3
/*
* Return codes.
*/
#define I8042_RET_CTL_TEST 0x55
/*
* Expected maximum internal i8042 buffer size. This is used for flushing
* the i8042 buffers. 32 should be more than enough.
*/
#define I8042_BUFFER_SIZE 32
#endif /* _I8042_H */
/*
* $Id: parkbd.c,v 1.10 2002/03/13 10:09:20 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* Parallel port to Keyboard port adapter 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/parport.h>
#include <linux/init.h>
#include <linux/serio.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver");
MODULE_LICENSE("GPL");
MODULE_PARM(parkbd, "1i");
MODULE_PARM(parkbd_mode, "1i");
#define PARKBD_CLOCK 0x01 /* Strobe & Ack */
#define PARKBD_DATA 0x02 /* AutoFd & Busy */
static int parkbd = 0;
static int parkbd_mode = SERIO_8042;
static int parkbd_buffer = 0;
static int parkbd_counter = 0;
static int parkbd_last = 0;
static int parkbd_writing = 0;
static unsigned long parkbd_start = 0;
static struct pardevice *parkbd_dev;
static char parkbd_name[] = "PARKBD AT/XT keyboard adapter";
static char parkbd_phys[32];
static int parkbd_readlines(void)
{
return (parport_read_status(parkbd_dev->port) >> 6) ^ 2;
}
static void parkbd_writelines(int data)
{
parport_write_control(parkbd_dev->port, (~data & 3) | 0x10);
}
static int parkbd_write(struct serio *port, unsigned char c)
{
unsigned char p;
if (!parkbd_mode) return -1;
p = c ^ (c >> 4);
p = p ^ (p >> 2);
p = p ^ (p >> 1);
parkbd_counter = 0;
parkbd_writing = 1;
parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600;
parkbd_writelines(2);
return 0;
}
static int parkbd_open(struct serio *port)
{
return 0;
}
static void parkbd_close(struct serio *port)
{
}
static struct serio parkbd_port =
{
write: parkbd_write,
open: parkbd_open,
close: parkbd_close,
name: parkbd_name,
phys: parkbd_phys,
};
static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
if (parkbd_writing) {
if (parkbd_counter && ((parkbd_counter == 11) || time_after(jiffies, parkbd_last + HZ/100))) {
parkbd_counter = 0;
parkbd_buffer = 0;
parkbd_writing = 0;
parkbd_writelines(3);
return;
}
parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2);
if (parkbd_counter == 11) {
parkbd_counter = 0;
parkbd_buffer = 0;
parkbd_writing = 0;
parkbd_writelines(3);
}
} else {
if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) {
parkbd_counter = 0;
parkbd_buffer = 0;
}
parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
if (parkbd_counter == parkbd_mode + 10) {
if (parkbd_port.dev)
parkbd_port.dev->interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
}
}
parkbd_last = jiffies;
}
static int parkbd_getport(void)
{
struct parport *pp;
if (parkbd < 0) {
printk(KERN_ERR "parkbd: no port specified\n");
return -ENODEV;
}
for (pp = parport_enumerate(); pp != NULL && (parkbd > 0); pp = pp->next) parkbd--;
if (pp == NULL) {
printk(KERN_ERR "parkbd: no such parport\n");
return -ENODEV;
}
parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL);
if (!parkbd_dev)
return -ENODEV;
if (parport_claim(parkbd_dev)) {
parport_unregister_device(parkbd_dev);
return -EBUSY;
}
parkbd_start = jiffies;
return 0;
}
int __init parkbd_init(void)
{
if (parkbd_getport()) return -1;
parkbd_writelines(3);
parkbd_port.type = parkbd_mode;
sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name);
serio_register_port(&parkbd_port);
printk(KERN_INFO "serio: PARKBD %s adapter on %s\n",
parkbd_mode ? "AT" : "XT", parkbd_dev->port->name);
return 0;
}
void __exit parkbd_exit(void)
{
parport_release(parkbd_dev);
serio_unregister_port(&parkbd_port);
parport_unregister_device(parkbd_dev);
}
module_init(parkbd_init);
module_exit(parkbd_exit);
/*
* $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
* unknown author
*/
/*
* Acorn RiscPC PS/2 keyboard controller 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/init.h>
#include <linux/serio.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/iomd.h>
#include <asm/system.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
MODULE_LICENSE("GPL");
static inline void rpckbd_write(unsigned char val)
{
while(!(inb(IOMD_KCTRL) & (1 << 7)));
outb(val, IOMD_KARTTX);
}
static struct serio rpckbd_port =
{
type: SERIO_8042,
write: rpckbd_write,
name: "RiscPC PS/2 kbd port",
phys: "rpckbd/serio0",
};
static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
{
kbd_pt_regs = regs;
while (inb(IOMD_KCTRL) & (1 << 5))
if (rpckbd_port.dev)
rpckbd_port.dev->interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0);
}
static void rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
{
}
static int __init rpckbd_init(void)
{
unsigned long flags;
/* Reset the keyboard state machine. */
outb(0, IOMD_KCTRL);
outb(8, IOMD_KCTRL);
save_flags_cli(flags);
if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", NULL) != 0) {
printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ!\n")
return -EBUSY;
}
if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", NULL) != 0) {
printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ!\n")
free_irq(IRQ_KEYBOARDRX, NULL);
return -EBUSY;
}
disable_irq(IRQ_KEYBOARDTX);
(void)IOMD_KARTRX;
restore_flags(flags);
register_serio_port(&rpckbd_port);
printk(KERN_INFO "serio: RiscPC PS/2 kbd port irq %d %d\n", IRQ_KEYBOARDRX, IRQ_KEYBOARDTX);
return 0;
}
static void __exit rpckbd_exit(void)
{
free_irq(IRQ_KEYBOARDRX, NULL);
free_irq(IRQ_KEYBOARDTX, NULL);
unregister_serio_port(&rpckbd_port);
}
module_init(rpckbd_init);
module_exit(rpckbd_exit);
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