Commit 42ec7868 authored by Vojtech Pavlik's avatar Vojtech Pavlik

Remove mouse drivers no longer needed, because these mice are

now handled by the input subsystem.
parent a49e82a5
......@@ -633,37 +633,6 @@ CONFIG_BUSMOUSE
The module will be called busmouse.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_MOUSE
This is for machines with a mouse which is neither a serial nor a
bus mouse. Examples are PS/2 mice (such as the track balls on some
laptops) and some digitizer pads. Most people have a regular serial
MouseSystem or Microsoft mouse (made by Logitech) that plugs into a
COM port (rectangular with 9 or 25 pins). These people say N here.
If you have something else, read the Busmouse-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>. This HOWTO contains
information about all non-serial mice, not just bus mice.
If you have a laptop, you either have to check the documentation or
experiment a bit to find out whether the trackball is a serial mouse
or not; it's best to say Y here for you.
Note that the answer to this question won't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about non-serial mice. If unsure, say Y.
CONFIG_LOGIBUSMOUSE
Logitech mouse connected to a proprietary interface card. It's
generally a round connector with 9 pins. Note that the newer mice
made by Logitech don't use the Logitech protocol anymore; for those,
you don't need this option. You want to read the Busmouse-HOWTO,
available from <http://www.linuxdoc.org/docs.html#howto>.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called busmouse.o. If you are unsure, say N and read the
HOWTO nevertheless: it will tell you what you have.
CONFIG_PSMOUSE
The PS/2 mouse connects to a special mouse port that looks much like
the keyboard port (small circular connector with 6 pins). This way,
......@@ -683,64 +652,6 @@ CONFIG_PSMOUSE
<ftp://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
CONFIG_82C710_MOUSE
This is a certain kind of PS/2 mouse used on the TI Travelmate. If
you are unsure, try first to say N here and come back if the mouse
doesn't work. Read the Busmouse-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.
CONFIG_PC110_PAD
This drives the digitizer pad on the IBM PC110 palmtop. It can turn
the digitizer pad into a PS/2 mouse emulation with tap gestures or
into an absolute pad.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called pc110pad.o.
CONFIG_MS_BUSMOUSE
These animals (also called Inport mice) are connected to an
expansion board using a round connector with 9 pins. If this is what
you have, say Y and read the Busmouse-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.
If you are unsure, say N and read the HOWTO nevertheless: it will
tell you what you have. Also be aware that several vendors talk
about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so
count the pins on the connector.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called msbusmouse.o.
CONFIG_ADBMOUSE
Say Y here if you have this type of bus mouse (4 pin connector) as
is common on Macintoshes. You may want to read the Busmouse-HOWTO,
available from <http://www.linuxdoc.org/docs.html#howto>.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called adbmouse.o.
CONFIG_ATIXL_BUSMOUSE
This is a rare type of busmouse that is connected to the back of an
ATI video card. Say Y if you have one of those. Note however that
most mice by ATI are actually Microsoft busmice; you should say Y to
"Microsoft busmouse support" above if you have one of those. Read
the Busmouse-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called atixlmouse.o.
If you are unsure, say N and read the HOWTO nevertheless: it will
tell you what you have.
CONFIG_QIC02_TAPE
If you have a non-SCSI tape drive like that, say Y. Or, if you want
to compile this driver as a module ( = code which can be inserted in
......
......@@ -114,22 +114,7 @@ source drivers/i2c/Config.in
mainmenu_option next_comment
comment 'Mice'
tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
if [ "$CONFIG_BUSMOUSE" != "n" ]; then
dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then
dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
fi
fi
tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
if [ "$CONFIG_MOUSE" != "n" ]; then
bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
tristate ' C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
tristate ' PC110 digitizer pad support' CONFIG_PC110_PAD
fi
endmenu
bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
......
......@@ -155,8 +155,6 @@ obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o
obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_BUSMOUSE) += busmouse.o
......@@ -164,12 +162,7 @@ obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
obj-$(CONFIG_SONYPI) += sonypi.o
obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o
obj-$(CONFIG_82C710_MOUSE) += qpmouse.o
obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o
obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
obj-$(CONFIG_ADBMOUSE) += adbmouse.o
obj-$(CONFIG_PC110_PAD) += pc110pad.o
obj-$(CONFIG_RTC) += rtc.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
ifeq ($(CONFIG_PPC),)
......@@ -235,4 +228,4 @@ $(obj)/defkeymap.c $(obj)/qtronixmap.c: $(obj)/%.c: $(src)/%.map
sed -e 's/^static *//' $@.tmp > $@
rm $@.tmp
endif
\ No newline at end of file
endif
/*
* Macintosh ADB Mouse driver for Linux
*
* 27 Oct 1997 Michael Schmitz
* logitech fixes by anthony tong
* further hacking by Paul Mackerras
*
* Apple mouse protocol according to:
*
* Device code shamelessly stolen from:
*/
/*
* Atari Mouse Driver for Linux
* by Robert de Vries (robert@and.nl) 19Jul93
*
* 16 Nov 1994 Andreas Schwab
* Compatibility with busmouse
* Support for three button mouse (shamelessly stolen from MiNT)
* third button wired to one of the joystick directions on joystick 1
*
* 1996/02/11 Andreas Schwab
* Module support
* Allow multiple open's
*
* Converted to use new generic busmouse code. 11 July 1998
* Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/adb_mouse.h>
#ifdef __powerpc__
#include <asm/processor.h>
#endif
#if defined(__mc68000__) || defined(MODULE)
#include <asm/setup.h>
#endif
#include "busmouse.h"
static int msedev;
static unsigned char adb_mouse_buttons[16];
extern void (*adb_mouse_interrupt_hook)(unsigned char *, int);
extern int adb_emulate_buttons;
extern int adb_button2_keycode;
extern int adb_button3_keycode;
/*
* XXX: need to figure out what ADB mouse packets mean ...
* This is the stuff stolen from the Atari driver ...
*/
static void adb_mouse_interrupt(unsigned char *buf, int nb)
{
int buttons, id;
char dx, dy;
/*
Handler 1 -- 100cpi original Apple mouse protocol.
Handler 2 -- 200cpi original Apple mouse protocol.
For Apple's standard one-button mouse protocol the data array will
contain the following values:
BITS COMMENTS
data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
data[1] = bxxx xxxx First button and x-axis motion.
data[2] = byyy yyyy Second button and y-axis motion.
Handler 4 -- Apple Extended mouse protocol.
For Apple's 3-button mouse protocol the data array will contain the
following values:
BITS COMMENTS
data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
data[1] = bxxx xxxx Left button and x-axis motion.
data[2] = byyy yyyy Second button and y-axis motion.
data[3] = byyy bxxx Third button and fourth button.
Y is additiona. high bits of y-axis motion.
X is additional high bits of x-axis motion.
'buttons' here means 'button down' states!
Button 1 (left) : bit 2, busmouse button 3
Button 2 (right) : bit 0, busmouse button 1
Button 3 (middle): bit 1, busmouse button 2
*/
/* x/y and buttons swapped */
id = (buf[0] >> 4) & 0xf;
buttons = adb_mouse_buttons[id];
/* button 1 (left, bit 2) */
buttons = (buttons & 3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
/* button 2 (middle) */
buttons = (buttons & 5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
/* button 3 (right) present?
* on a logitech mouseman, the right and mid buttons sometimes behave
* strangely until they both have been pressed after booting. */
/* data valid only if extended mouse format ! */
if (nb >= 4)
buttons = (buttons & 6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
adb_mouse_buttons[id] = buttons;
/* a button is down if it is down on any mouse */
for (id = 0; id < 16; ++id)
buttons &= adb_mouse_buttons[id];
dx = ((buf[2] & 0x7f) < 64 ? (buf[2] & 0x7f) : (buf[2] & 0x7f) - 128);
dy = ((buf[1] & 0x7f) < 64 ? (buf[1] & 0x7f) : (buf[1] & 0x7f) - 128);
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
if (console_loglevel >= 8)
printk(" %X %X %X dx %d dy %d \n",
buf[1], buf[2], buf[3], dx, dy);
}
static int release_mouse(struct inode *inode, struct file *file)
{
adb_mouse_interrupt_hook = NULL;
/*
* FIXME?: adb_mouse_interrupt_hook may still be executing
* on another CPU.
*/
return 0;
}
static int open_mouse(struct inode *inode, struct file *file)
{
adb_mouse_interrupt_hook = adb_mouse_interrupt;
return 0;
}
static struct busmouse adb_mouse =
{
ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7
};
static int __init adb_mouse_init(void)
{
#ifdef __powerpc__
if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac))
return -ENODEV;
#endif
#ifdef __mc68000__
if (!MACH_IS_MAC)
return -ENODEV;
#endif
/* all buttons up */
memset(adb_mouse_buttons, 7, sizeof(adb_mouse_buttons));
msedev = register_busmouse(&adb_mouse);
if (msedev < 0)
printk(KERN_WARNING "Unable to register ADB mouse driver.\n");
else
printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
return msedev < 0 ? msedev : 0;
}
#ifndef MODULE
/*
* XXX this function is misnamed.
* It is called if the kernel is booted with the adb_buttons=xxx
* option, which is about using ADB keyboard buttons to emulate
* mouse buttons. -- paulus
*/
static int __init adb_mouse_setup(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] >= 1) {
adb_emulate_buttons = ints[1];
if (ints[0] >= 2)
adb_button2_keycode = ints[2];
if (ints[0] >= 3)
adb_button3_keycode = ints[3];
}
return 1;
}
__setup("adb_buttons=", adb_mouse_setup);
#endif /* !MODULE */
static void __exit adb_mouse_cleanup(void)
{
unregister_busmouse(msedev);
}
module_init(adb_mouse_init);
module_exit(adb_mouse_cleanup);
MODULE_LICENSE("GPL");
/*
* Amiga Mouse Driver for Linux 68k by Michael Rausch
* based upon:
*
* Logitech Bus Mouse Driver for Linux
* by James Banks
*
* Mods by Matthew Dillon
* calls verify_area()
* tracks better when X is busy or paging
*
* Heavily modified by David Giller
* changed from queue- to counter- driven
* hacked out a (probably incorrect) mouse_poll
*
* Modified again by Nathan Laredo to interface with
* 0.96c-pl1 IRQ handling changes (13JUL92)
* didn't bother touching poll code.
*
* Modified the poll() code blindly to conform to the VFS
* requirements. 92.07.14 - Linus. Somebody should test it out.
*
* Modified by Johan Myreen to make room for other mice (9AUG92)
* removed assignment chr_fops[10] = &mouse_fops; see mouse.c
* renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
* renamed this file mouse.c => busmouse.c
*
* Modified for use in the 1.3 kernels by Jes Sorensen.
*
* Moved the isr-allocation to the mouse_{open,close} calls, as there
* is no reason to service the mouse in the vertical blank isr if
* the mouse is not in use. Jes Sorensen
*
* Converted to use new generic busmouse code. 5 Apr 1998
* Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/logibusmouse.h>
#include <asm/setup.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
#include "busmouse.h"
#if AMIGA_OLD_INT
#define AMI_MSE_INT_ON() mouseint_allowed = 1
#define AMI_MSE_INT_OFF() mouseint_allowed = 0
static int mouseint_allowed;
#endif
static int msedev;
static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
static int lastx=0, lasty=0;
int dx, dy;
int nx, ny;
unsigned char buttons;
unsigned short joy0dat, potgor;
#if AMIGA_OLD_INT
if(!mouseint_allowed)
return;
AMI_MSE_INT_OFF();
#endif
/*
* This routine assumes, just like Kickstart, that the mouse
* has not moved more than 127 ticks since last VBL.
*/
joy0dat = custom.joy0dat;
nx = joy0dat & 0xff;
ny = joy0dat >> 8;
dx = nx - lastx;
if (dx < - 127)
dx = (256 + nx) - lastx;
if (dx > 127)
dx = (nx - 256) - lastx;
dy = ny - lasty;
if (dy < - 127)
dy = (256 + ny) - lasty;
if (dy > 127)
dy = (ny - 256) - lasty;
lastx = nx;
lasty = ny;
#if 0
dx = -lastdx;
dx += (lastdx = joy0dat & 0xff);
if (dx < -127)
dx = -255-dx; /* underrun */
else
if (dx > 127)
dx = 255-dx; /* overflow */
dy = -lastdy;
dy += (lastdy = joy0dat >> 8);
if (dy < -127)
dy = -255-dy;
else
if (dy > 127)
dy = 255-dy;
#endif
potgor = custom.potgor;
buttons = (ciaa.pra & 0x40 ? 4 : 0) | /* left button; note that the bits are low-active, as are the expected results -> double negation */
#if 1
(potgor & 0x0100 ? 2 : 0) | /* middle button; emulation goes here */
#endif
(potgor & 0x0400 ? 1 : 0); /* right button */
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
#if AMIGA_OLD_INT
AMI_MSE_INT_ON();
#endif
}
/*
* close access to the mouse
*/
static int release_mouse(struct inode * inode, struct file * file)
{
free_irq(IRQ_AMIGA_VERTB, mouse_interrupt);
#if AMIGA_OLD_INT
AMI_MSE_INT_OFF();
#endif
return 0;
}
/*
* open access to the mouse, currently only one open is
* allowed.
*/
static int open_mouse(struct inode * inode, struct file * file)
{
/*
* use VBL to poll mouse deltas
*/
if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0,
"Amiga mouse", mouse_interrupt)) {
printk(KERN_INFO "Installing Amiga mouse failed.\n");
return -EIO;
}
#if AMIGA_OLD_INT
AMI_MSE_INT_ON();
#endif
return 0;
}
static struct busmouse amigamouse = {
AMIGAMOUSE_MINOR, "amigamouse", THIS_MODULE, open_mouse, release_mouse, 7
};
static int __init amiga_mouse_init(void)
{
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
return -ENODEV;
if (!request_mem_region(CUSTOM_PHYSADDR+10, 2, "amigamouse [Denise]"))
return -EBUSY;
custom.joytest = 0; /* reset counters */
#if AMIGA_OLD_INT
AMI_MSE_INT_OFF();
#endif
msedev = register_busmouse(&amigamouse);
if (msedev < 0)
printk(KERN_WARNING "Unable to install Amiga mouse driver.\n");
else
printk(KERN_INFO "Amiga mouse installed.\n");
return msedev < 0 ? msedev : 0;
}
static void __exit amiga_mouse_exit(void)
{
unregister_busmouse(msedev);
release_mem_region(CUSTOM_PHYSADDR+10, 2);
}
module_init(amiga_mouse_init);
module_exit(amiga_mouse_exit);
MODULE_LICENSE("GPL");
/*
* ATI XL Bus Mouse Driver for Linux
* by Bob Harris (rth@sparta.com)
*
* Uses VFS interface for linux 0.98 (01OCT92)
*
* Modified by Chris Colohan (colohan@eecg.toronto.edu)
* Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*
* Converted to use new generic busmouse code. 5 Apr 1998
* Russell King <rmk@arm.uk.linux.org>
*
* version 0.3a
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "busmouse.h"
#define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */
#define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */
/* ATI XL Inport Busmouse Definitions */
#define ATIXL_MSE_DATA_PORT 0x23d
#define ATIXL_MSE_SIGNATURE_PORT 0x23e
#define ATIXL_MSE_CONTROL_PORT 0x23c
#define ATIXL_MSE_READ_BUTTONS 0x00
#define ATIXL_MSE_READ_X 0x01
#define ATIXL_MSE_READ_Y 0x02
/* Some nice ATI XL macros */
/* Select IR7, HOLD UPDATES (INT ENABLED), save X,Y */
#define ATIXL_MSE_DISABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
outb( (0x20 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
/* Select IR7, Enable updates (INT ENABLED) */
#define ATIXL_MSE_ENABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
outb( (0xdf & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
/* Select IR7 - Mode Register, NO INTERRUPTS */
#define ATIXL_MSE_INT_OFF() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
outb( (0xe7 & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
/* Select IR7 - Mode Register, DATA INTERRUPTS ENABLED */
#define ATIXL_MSE_INT_ON() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \
outb( (0x08 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); }
/* Same general mouse structure */
static int msedev;
static void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
char dx, dy, buttons;
ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */
outb(ATIXL_MSE_READ_X, ATIXL_MSE_CONTROL_PORT); /* Select IR1 - X movement */
dx = inb( ATIXL_MSE_DATA_PORT);
outb(ATIXL_MSE_READ_Y, ATIXL_MSE_CONTROL_PORT); /* Select IR2 - Y movement */
dy = inb( ATIXL_MSE_DATA_PORT);
outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */
buttons = inb( ATIXL_MSE_DATA_PORT);
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
ATIXL_MSE_ENABLE_UPDATE();
}
static int release_mouse(struct inode * inode, struct file * file)
{
ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
free_irq(ATIXL_MOUSE_IRQ, NULL);
return 0;
}
static int open_mouse(struct inode * inode, struct file * file)
{
if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL))
return -EBUSY;
ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
return 0;
}
static struct busmouse atixlmouse = {
ATIXL_BUSMOUSE, "atixl", THIS_MODULE, open_mouse, release_mouse, 0
};
static int __init atixl_busmouse_init(void)
{
unsigned char a,b,c;
/*
* We must request the resource and claim it atomically
* nowdays. We can throw it away on error. Otherwise we
* may race another module load of the same I/O
*/
if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse"))
return -EIO;
a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */
b = inb( ATIXL_MSE_SIGNATURE_PORT );
c = inb( ATIXL_MSE_SIGNATURE_PORT );
if (( a != b ) && ( a == c ))
printk(KERN_INFO "\nATI Inport ");
else
{
release_region(ATIXL_MSE_DATA_PORT,3);
return -EIO;
}
outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */
outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */
outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
msedev = register_busmouse(&atixlmouse);
if (msedev < 0)
{
printk("Bus mouse initialisation error.\n");
release_region(ATIXL_MSE_DATA_PORT,3); /* Was missing */
}
else
printk("Bus mouse detected and installed.\n");
return msedev < 0 ? msedev : 0;
}
static void __exit atixl_cleanup (void)
{
release_region(ATIXL_MSE_DATA_PORT, 3);
unregister_busmouse(msedev);
}
module_init(atixl_busmouse_init);
module_exit(atixl_cleanup);
MODULE_LICENSE("GPL");
/*
* Logitech Bus Mouse Driver for Linux
* by James Banks
*
* Mods by Matthew Dillon
* calls verify_area()
* tracks better when X is busy or paging
*
* Heavily modified by David Giller
* changed from queue- to counter- driven
* hacked out a (probably incorrect) mouse_select
*
* Modified again by Nathan Laredo to interface with
* 0.96c-pl1 IRQ handling changes (13JUL92)
* didn't bother touching select code.
*
* Modified the select() code blindly to conform to the VFS
* requirements. 92.07.14 - Linus. Somebody should test it out.
*
* Modified by Johan Myreen to make room for other mice (9AUG92)
* removed assignment chr_fops[10] = &mouse_fops; see mouse.c
* renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
* renamed this file mouse.c => busmouse.c
*
* Minor addition by Cliff Matthews
* added fasync support
*
* Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*
* Replaced dumb busy loop with udelay() 16 Nov 95
* Nathan Laredo <laredo@gnu.ai.mit.edu>
*
* Track I/O ports with request_region(). 12 Dec 95 Philip Blundell
*
* Converted to use new generic busmouse code. 5 Apr 1998
* Russell King <rmk@arm.uk.linux.org>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/logibusmouse.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "busmouse.h"
static int msedev;
static int mouse_irq = MOUSE_IRQ;
MODULE_PARM(mouse_irq, "i");
#ifndef MODULE
static int __init bmouse_setup(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0)
mouse_irq=ints[1];
return 1;
}
__setup("logi_busmouse=", bmouse_setup);
#endif /* !MODULE */
static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
char dx, dy;
unsigned char buttons;
outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
dx = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
dy = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
buttons = inb(MSE_DATA_PORT);
dy |= (buttons & 0xf) << 4;
buttons = ((buttons >> 5) & 0x07);
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
MSE_INT_ON();
}
/*
* close access to the mouse
*/
static int close_mouse(struct inode * inode, struct file * file)
{
MSE_INT_OFF();
free_irq(mouse_irq, NULL);
return 0;
}
/*
* open access to the mouse
*/
static int open_mouse(struct inode * inode, struct file * file)
{
if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL))
return -EBUSY;
MSE_INT_ON();
return 0;
}
static struct busmouse busmouse = {
LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7
};
static int __init logi_busmouse_init(void)
{
if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse"))
return -EIO;
outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
udelay(100L); /* wait for reply from mouse */
if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
return -EIO;
}
outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
MSE_INT_OFF();
msedev = register_busmouse(&busmouse);
if (msedev < 0) {
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
printk(KERN_WARNING "Unable to register busmouse driver.\n");
}
else
printk(KERN_INFO "Logitech busmouse installed.\n");
return msedev < 0 ? msedev : 0;
}
static void __exit logi_busmouse_cleanup (void)
{
unregister_busmouse(msedev);
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
}
module_init(logi_busmouse_init);
module_exit(logi_busmouse_cleanup);
MODULE_LICENSE("GPL");
/*
* Microsoft busmouse driver based on Logitech driver (see busmouse.c)
*
* Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92)
*
* Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net)
* 8/28/92
*
* Microsoft Bus Mouse support folded into 0.97pl4 code
* by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
* Changes: Logitech and Microsoft support in the same kernel.
* Defined new constants in busmouse.h for MS mice.
* Added int mse_busmouse_type to distinguish busmouse types
* Added a couple of new functions to handle differences in using
* MS vs. Logitech (where the int variable wasn't appropriate).
*
* Modified by Peter Cervasio (address above) (26SEP92)
* Changes: Included code to (properly?) detect when a Microsoft mouse is
* really attached to the machine. Don't know what this does to
* Logitech bus mice, but all it does is read ports.
*
* Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de)
* Changes: Better interrupt-handler (like in busmouse.c).
* Some changes to reduce code-size.
* Changed detection code to use inb_p() instead of doing empty
* loops to delay i/o.
*
* Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*
* Converted to use new generic busmouse code. 5 Apr 1998
* Russell King <rmk@arm.uk.linux.org>
*
* version 0.3b
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/logibusmouse.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "busmouse.h"
static int msedev;
static int mouse_irq = MOUSE_IRQ;
MODULE_PARM(mouse_irq, "i");
#ifndef MODULE
static int __init msmouse_setup(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0)
mouse_irq=ints[1];
return 1;
}
__setup("msmouse=",msmouse_setup);
#endif /* !MODULE */
static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
char dx, dy;
unsigned char buttons;
outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT);
outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT);
dx = inb(MS_MSE_DATA_PORT);
outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT);
dy = inb(MS_MSE_DATA_PORT);
outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT);
buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07;
outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
/* why did the original have:
* if (dx != 0 || dy != 0 || buttons != mouse.buttons ||
* ((~buttons) & 0x07))
* ^^^^^^^^^^^^^^^^^^^ this?
*/
busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
}
static int release_mouse(struct inode * inode, struct file * file)
{
MS_MSE_INT_OFF();
free_irq(mouse_irq, NULL);
return 0;
}
static int open_mouse(struct inode * inode, struct file * file)
{
if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL))
return -EBUSY;
outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
MS_MSE_INT_ON();
return 0;
}
static struct busmouse msbusmouse = {
MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0
};
static int __init ms_bus_mouse_init(void)
{
int present = 0;
int mse_byte, i;
if (check_region(MS_MSE_CONTROL_PORT, 0x04))
return -ENODEV;
if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
mse_byte = inb_p(MS_MSE_SIGNATURE_PORT);
for (i = 0; i < 4; i++) {
if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte)
present = 1;
else
present = 0;
} else
present = 0;
}
}
if (present == 0)
return -EIO;
if (!request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse"))
return -EIO;
MS_MSE_INT_OFF();
msedev = register_busmouse(&msbusmouse);
if (msedev < 0) {
printk(KERN_WARNING "Unable to register msbusmouse driver.\n");
release_region(MS_MSE_CONTROL_PORT, 0x04);
}
else
printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
return msedev < 0 ? msedev : 0;
}
static void __exit ms_bus_mouse_exit(void)
{
unregister_busmouse(msedev);
release_region(MS_MSE_CONTROL_PORT, 0x04);
}
module_init(ms_bus_mouse_init)
module_exit(ms_bus_mouse_exit)
MODULE_LICENSE("GPL");
/*
* Linux driver for the PC110 pad
*/
/**
* DOC: PC110 Digitizer Hardware
*
* The pad provides triples of data. The first byte has
* 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
* The second byte is bits 0-6 X
* The third is bits 0-6 Y
*
* This is read internally and used to synthesize a stream of
* triples in the form expected from a PS/2 device. Specialist
* applications can choose to obtain the pad data in other formats
* including a debugging mode.
*
* It would be good to add a joystick driver mode to this pad so
* that doom and other game playing are better. One possible approach
* would be to deactive the mouse mode while the joystick port is opened.
*/
/*
* History
*
* 0.0 1997-05-16 Alan Cox <alan@redhat.com> - Pad reader
* 0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
* 0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
* 0.3 1997-06-27 Alan Cox <alan@redhat.com> - 2.1 commit
* 0.4 1997-11-09 Alan Cox <alan@redhat.com> - Single Unix VFS API changes
* 0.5 2000-02-10 Alan Cox <alan@redhat.com> - 2.3.x cleanup, documentation
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/ptrace.h>
#include <linux/poll.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/semaphore.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include "pc110pad.h"
static struct pc110pad_params default_params = {
mode: PC110PAD_PS2,
bounce_interval: 50 MS,
tap_interval: 200 MS,
irq: 10,
io: 0x15E0,
};
static struct pc110pad_params current_params;
/* driver/filesystem interface management */
static wait_queue_head_t queue;
static struct fasync_struct *asyncptr;
static int active_count = 0; /* number of concurrent open()s */
static spinlock_t pc110_lock = SPIN_LOCK_UNLOCKED;
/* this lock should be held when referencing active_count */
static struct semaphore reader_lock;
/**
* wake_readers:
*
* Take care of letting any waiting processes know that
* now would be a good time to do a read(). Called
* whenever a state transition occurs, real or synthetic. Also
* issue any SIGIO's to programs that use SIGIO on mice (eg
* Executor)
*/
static void wake_readers(void)
{
wake_up_interruptible(&queue);
kill_fasync(&asyncptr, SIGIO, POLL_IN);
}
/*****************************************************************************/
/*
* Deal with the messy business of synthesizing button tap and drag
* events.
*
* Exports:
* notify_pad_up_down()
* Must be called whenever debounced pad up/down state changes.
* button_pending
* Flag is set whenever read_button() has new values
* to return.
* read_button()
* Obtains the current synthetic mouse button state.
*/
/*
* These keep track of up/down transitions needed to generate the
* synthetic mouse button events. While recent_transition is set,
* up/down events cause transition_count to increment. tap_timer
* turns off the recent_transition flag and may cause some synthetic
* up/down mouse events to be created by incrementing synthesize_tap.
*/
static int button_pending;
static int recent_transition;
static int transition_count;
static int synthesize_tap;
static void tap_timeout(unsigned long data);
static struct timer_list tap_timer = { function: tap_timeout };
/**
* tap_timeout:
* @data: Unused
*
* This callback goes off a short time after an up/down transition;
* before it goes off, transitions will be considered part of a
* single PS/2 event and counted in transition_count. Once the
* timeout occurs the recent_transition flag is cleared and
* any synthetic mouse up/down events are generated.
*/
static void tap_timeout(unsigned long data)
{
if(!recent_transition)
{
printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!\n");
}
if( transition_count==2 || transition_count==4 || transition_count==6 )
{
synthesize_tap+=transition_count;
button_pending = 1;
wake_readers();
}
recent_transition=0;
}
/**
* notify_pad_up_down:
*
* Called by the raw pad read routines when a (debounced) up/down
* transition is detected.
*/
void notify_pad_up_down(void)
{
if(recent_transition)
{
transition_count++;
}
else
{
transition_count=1;
recent_transition=1;
}
mod_timer(&tap_timer, jiffies + current_params.tap_interval);
/* changes to transition_count can cause reported button to change */
button_pending = 1;
wake_readers();
}
/**
* read_button:
* @b: pointer to the button status.
*
* The actual button state depends on what we are seeing. We have to check
* for the tap gesture and also for dragging.
*/
static void read_button(int *b)
{
if(synthesize_tap)
{
*b=--synthesize_tap & 1;
}
else
{
*b=(!recent_transition && transition_count==3); /* drag */
}
button_pending=(synthesize_tap>0);
}
/*****************************************************************************/
/*
* Read pad absolute co-ordinates and debounced up/down state.
*
* Exports:
* pad_irq()
* Function to be called whenever the pad signals
* that it has new data available.
* read_raw_pad()
* Returns the most current pad state.
* xy_pending
* Flag is set whenever read_raw_pad() has new values
* to return.
* Imports:
* wake_readers()
* Called when movement occurs.
* notify_pad_up_down()
* Called when debounced up/down status changes.
*/
/*
* These are up/down state and absolute co-ords read directly from pad
*/
static int raw_data[3];
static int raw_data_count;
static int raw_x, raw_y; /* most recent absolute co-ords read */
static int raw_down; /* raw up/down state */
static int debounced_down; /* up/down state after debounce processing */
static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
/* set just after an up/down transition */
static int xy_pending; /* set if new data have not yet been read */
/*
* Timer goes off a short while after an up/down transition and copies
* the value of raw_down to debounced_down.
*/
static void bounce_timeout(unsigned long data);
static struct timer_list bounce_timer = { function: bounce_timeout };
/**
* bounce_timeout:
* @data: Unused
*
* No further up/down transitions happened within the
* bounce period, so treat this as a genuine transition.
*/
static void bounce_timeout(unsigned long data)
{
switch(bounce)
{
case NO_BOUNCE:
{
/*
* Strange; the timer callback should only go off if
* we were expecting to do bounce processing!
*/
printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n");
break;
}
case JUST_GONE_UP:
{
/*
* The last up we spotted really was an up, so set
* debounced state the same as raw state.
*/
bounce=NO_BOUNCE;
if(debounced_down==raw_down)
{
printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n");
}
debounced_down=raw_down;
notify_pad_up_down();
break;
}
case JUST_GONE_DOWN:
{
/*
* We don't debounce down events, but we still time
* out soon after one occurs so we can avoid the (x,y)
* skittering that sometimes happens.
*/
bounce=NO_BOUNCE;
break;
}
}
}
/**
* pad_irq:
* @irq: Interrupt number
* @ptr: Unused
* @regs: Unused
*
* Callback when pad's irq goes off; copies values in to raw_* globals;
* initiates debounce processing. This isn't SMP safe however there are
* no SMP machines with a PC110 touchpad on them.
*/
static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
{
/* Obtain byte from pad and prime for next byte */
{
int value=inb_p(current_params.io);
int handshake=inb_p(current_params.io+2);
outb_p(handshake | 1, current_params.io+2);
outb_p(handshake &~1, current_params.io+2);
inb_p(0x64);
raw_data[raw_data_count++]=value;
}
if(raw_data_count==3)
{
int new_down=raw_data[0]&0x01;
int new_x=raw_data[1];
int new_y=raw_data[2];
if(raw_data[0]&0x10) new_x+=128;
if(raw_data[0]&0x80) new_x+=256;
if(raw_data[0]&0x08) new_y+=128;
if( (raw_x!=new_x) || (raw_y!=new_y) )
{
raw_x=new_x;
raw_y=new_y;
xy_pending=1;
}
if(new_down != raw_down)
{
/* Down state has changed. raw_down always holds
* the most recently observed state.
*/
raw_down=new_down;
/* Forget any earlier bounce processing */
if(bounce)
{
del_timer(&bounce_timer);
bounce=NO_BOUNCE;
}
if(new_down)
{
if(debounced_down)
{
/* pad gone down, but we were reporting
* it down anyway because we suspected
* (correctly) that the last up was just
* a bounce
*/
}
else
{
bounce=JUST_GONE_DOWN;
mod_timer(&bounce_timer,
jiffies+current_params.bounce_interval);
/* start new stroke/tap */
debounced_down=new_down;
notify_pad_up_down();
}
}
else /* just gone up */
{
if(recent_transition)
{
/* early bounces are probably part of
* a multi-tap gesture, so process
* immediately
*/
debounced_down=new_down;
notify_pad_up_down();
}
else
{
/* don't trust it yet */
bounce=JUST_GONE_UP;
mod_timer(&bounce_timer,
jiffies+current_params.bounce_interval);
}
}
}
wake_readers();
raw_data_count=0;
}
}
/**
* read_raw_pad:
* @down: set if the pen is down
* @debounced: set if the debounced pen position is down
* @x: X position
* @y: Y position
*
* Retrieve the data saved by the interrupt handler and indicate we
* have no more pending XY to do.
*
* FIXME: We should switch to a spinlock for this.
*/
static void read_raw_pad(int *down, int *debounced, int *x, int *y)
{
disable_irq(current_params.irq);
{
*down=raw_down;
*debounced=debounced_down;
*x=raw_x;
*y=raw_y;
xy_pending = 0;
}
enable_irq(current_params.irq);
}
/*****************************************************************************/
/*
* Filesystem interface
*/
/*
* Read returns byte triples, so we need to keep track of
* how much of a triple has been read. This is shared across
* all processes which have this device open---not that anything
* will make much sense in that case.
*/
static int read_bytes[3];
static int read_byte_count;
/**
* sample_raw:
* @d: sample buffer
*
* Retrieve a triple of sample data.
*/
static void sample_raw(int d[3])
{
d[0]=raw_data[0];
d[1]=raw_data[1];
d[2]=raw_data[2];
}
/**
* sample_rare:
* @d: sample buffer
*
* Retrieve a triple of sample data and sanitize it. We do the needed
* scaling and masking to get the current status.
*/
static void sample_rare(int d[3])
{
int thisd, thisdd, thisx, thisy;
read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
d[0]=(thisd?0x80:0)
| (thisx/256)<<4
| (thisdd?0x08:0)
| (thisy/256)
;
d[1]=thisx%256;
d[2]=thisy%256;
}
/**
* sample_debug:
* @d: sample buffer
*
* Retrieve a triple of sample data and mix it up with the state
* information in the gesture parser. Not useful for normal users but
* handy when debugging
*/
static void sample_debug(int d[3])
{
int thisd, thisdd, thisx, thisy;
int b;
unsigned long flags;
spin_lock_irqsave(&pc110_lock, flags);
read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
d[1]=(recent_transition?0x80:0)+transition_count;
read_button(&b);
d[2]=(synthesize_tap<<4) | (b?0x01:0);
spin_unlock_irqrestore(&pc110_lock, flags);
}
/**
* sample_ps2:
* @d: sample buffer
*
* Retrieve a triple of sample data and turn the debounced tap and
* stroke information into what appears to be a PS/2 mouse. This means
* the PC110 pad needs no funny application side support.
*/
static void sample_ps2(int d[3])
{
static int lastx, lasty, lastd;
int thisd, thisdd, thisx, thisy;
int dx, dy, b;
/*
* Obtain the current mouse parameters and limit as appropriate for
* the return data format. Interrupts are only disabled while
* obtaining the parameters, NOT during the puts_fs_byte() calls,
* so paging in put_user() does not affect mouse tracking.
*/
read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
read_button(&b);
/* Now compare with previous readings. Note that we use the
* raw down flag rather than the debounced one.
*/
if( (thisd && !lastd) /* new stroke */
|| (bounce!=NO_BOUNCE) )
{
dx=0;
dy=0;
}
else
{
dx = (thisx-lastx);
dy = -(thisy-lasty);
}
lastx=thisx;
lasty=thisy;
lastd=thisd;
/*
d[0]= ((dy<0)?0x20:0)
| ((dx<0)?0x10:0)
| 0x08
| (b? 0x01:0x00)
;
*/
d[0]= ((dy<0)?0x20:0)
| ((dx<0)?0x10:0)
| (b? 0x00:0x08)
;
d[1]=dx;
d[2]=dy;
}
/**
* fasync_pad:
* @fd: file number for the file
* @filp: file handle
* @on: 1 to add, 0 to remove a notifier
*
* Update the queue of asynchronous event notifiers. We can use the
* same helper the mice do and that does almost everything we need.
*/
static int fasync_pad(int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &asyncptr);
if (retval < 0)
return retval;
return 0;
}
/**
* close_pad:
* @inode: inode of pad
* @file: file handle to pad
*
* Close access to the pad. We turn the pad power off if this is the
* last user of the pad. I've not actually measured the power draw but
* the DOS driver is careful to do this so we follow suit.
*/
static int close_pad(struct inode * inode, struct file * file)
{
unsigned long flags;
fasync_pad(-1, file, 0);
spin_lock_irqsave(&pc110_lock, flags);
if (!--active_count)
outb(0x30, current_params.io+2); /* switch off digitiser */
spin_unlock_irqrestore(&pc110_lock, flags);
return 0;
}
/**
* open_pad:
* @inode: inode of pad
* @file: file handle to pad
*
* Open access to the pad. We turn the pad off first (we turned it off
* on close but if this is the first open after a crash the state is
* indeterminate). The device has a small fifo so we empty that before
* we kick it back into action.
*/
static int open_pad(struct inode * inode, struct file * file)
{
unsigned long flags;
spin_lock_irqsave(&pc110_lock, flags);
if (active_count++)
{
spin_unlock_irqrestore(&pc110_lock, flags);
return 0;
}
outb(0x30, current_params.io+2); /* switch off digitiser */
pad_irq(0,0,0); /* read to flush any pending bytes */
pad_irq(0,0,0); /* read to flush any pending bytes */
pad_irq(0,0,0); /* read to flush any pending bytes */
outb(0x38, current_params.io+2); /* switch on digitiser */
current_params = default_params;
raw_data_count=0; /* re-sync input byte counter */
read_byte_count=0; /* re-sync output byte counter */
button_pending=0;
recent_transition=0;
transition_count=0;
synthesize_tap=0;
del_timer(&bounce_timer);
del_timer(&tap_timer);
spin_unlock_irqrestore(&pc110_lock, flags);
return 0;
}
/**
* write_pad:
* @file: File handle to the pad
* @buffer: Unused
* @count: Unused
* @ppos: Unused
*
* Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone
* seems happy with this and not faking the write modes.
*/
static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos)
{
return -EINVAL;
}
/*
* new_sample:
* @d: sample buffer
*
* Fetch a new sample according the current mouse mode the pad is
* using.
*/
void new_sample(int d[3])
{
switch(current_params.mode)
{
case PC110PAD_RAW: sample_raw(d); break;
case PC110PAD_RARE: sample_rare(d); break;
case PC110PAD_DEBUG: sample_debug(d); break;
case PC110PAD_PS2: sample_ps2(d); break;
}
}
/**
* read_pad:
* @file: File handle to pad
* @buffer: Target for the mouse data
* @count: Buffer length
* @ppos: Offset (unused)
*
* Read data from the pad. We use the reader_lock to avoid mess when there are
* two readers. This shouldnt be happening anyway but we play safe.
*/
static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
int r;
down(&reader_lock);
for(r=0; r<count; r++)
{
if(!read_byte_count)
new_sample(read_bytes);
if(put_user(read_bytes[read_byte_count], buffer+r))
{
r = -EFAULT;
break;
}
read_byte_count = (read_byte_count+1)%3;
}
up(&reader_lock);
return r;
}
/**
* pad_poll:
* @file: File of the pad device
* @wait: Poll table
*
* The pad is ready to read if there is a button or any position change
* pending in the queue. The reading and interrupt routines maintain the
* required state for us and do needed wakeups.
*/
static unsigned int pad_poll(struct file *file, poll_table * wait)
{
poll_wait(file, &queue, wait);
if(button_pending || xy_pending)
return POLLIN | POLLRDNORM;
return 0;
}
/**
* pad_ioctl;
* @inode: Inode of the pad
* @file: File handle to the pad
* @cmd: Ioctl command
* @arg: Argument pointer
*
* The PC110 pad supports two ioctls both of which use the pc110pad_params
* structure. GETP queries the current pad status. SETP changes the pad
* configuration. Changing configuration during normal mouse operations
* may give momentarily odd results as things like tap gesture state
* may be lost.
*/
static int pad_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct pc110pad_params new;
if (!inode)
return -EINVAL;
switch (cmd) {
case PC110PADIOCGETP:
new = current_params;
if(copy_to_user((void *)arg, &new, sizeof(new)))
return -EFAULT;
return 0;
case PC110PADIOCSETP:
if(copy_from_user(&new, (void *)arg, sizeof(new)))
return -EFAULT;
if( (new.mode<PC110PAD_RAW)
|| (new.mode>PC110PAD_PS2)
|| (new.bounce_interval<0)
|| (new.tap_interval<0)
)
return -EINVAL;
current_params.mode = new.mode;
current_params.bounce_interval = new.bounce_interval;
current_params.tap_interval = new.tap_interval;
return 0;
}
return -ENOTTY;
}
static struct file_operations pad_fops = {
owner: THIS_MODULE,
read: read_pad,
write: write_pad,
poll: pad_poll,
ioctl: pad_ioctl,
open: open_pad,
release: close_pad,
fasync: fasync_pad,
};
static struct miscdevice pc110_pad = {
minor: PC110PAD_MINOR,
name: "pc110 pad",
fops: &pad_fops,
};
/**
* pc110pad_init_driver:
*
* We configure the pad with the default parameters (that is PS/2
* emulation mode. We then claim the needed I/O and interrupt resources.
* Finally as a matter of paranoia we turn the pad off until we are
* asked to open it by an application.
*/
static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.\n";
static int __init pc110pad_init_driver(void)
{
init_MUTEX(&reader_lock);
current_params = default_params;
if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) {
printk(KERN_ERR "pc110pad: Unable to get IRQ.\n");
return -EBUSY;
}
if (!request_region(current_params.io, 4, "pc110pad")) {
printk(KERN_ERR "pc110pad: I/O area in use.\n");
free_irq(current_params.irq,0);
return -EBUSY;
}
init_waitqueue_head(&queue);
printk(banner, current_params.io, current_params.irq);
misc_register(&pc110_pad);
outb(0x30, current_params.io+2); /* switch off digitiser */
return 0;
}
/*
* pc110pad_exit_driver:
*
* Free the resources we acquired when the module was loaded. We also
* turn the pad off to be sure we don't leave it using power.
*/
static void __exit pc110pad_exit_driver(void)
{
outb(0x30, current_params.io+2); /* switch off digitiser */
if (current_params.irq)
free_irq(current_params.irq, 0);
current_params.irq = 0;
release_region(current_params.io, 4);
misc_deregister(&pc110_pad);
}
module_init(pc110pad_init_driver);
module_exit(pc110pad_exit_driver);
MODULE_AUTHOR("Alan Cox, Robin O'Leary");
MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop");
MODULE_LICENSE("GPL");
#ifndef _PC110PAD_H
#define _PC110PAD_H
#include <linux/ioctl.h>
enum pc110pad_mode {
PC110PAD_RAW, /* bytes as they come out of the hardware */
PC110PAD_RARE, /* debounced up/down and absolute x,y */
PC110PAD_DEBUG, /* up/down, debounced, transitions, button */
PC110PAD_PS2, /* ps2 relative (default) */
};
struct pc110pad_params {
enum pc110pad_mode mode;
int bounce_interval;
int tap_interval;
int irq;
int io;
};
#define MS *HZ/1000
/* Appears as device major=10 (MISC), minor=PC110_PAD */
#define PC110PAD_IOCTL_TYPE 0x9a
#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
#endif /* _PC110PAD_H */
/*
* linux/drivers/char/qpmouse.c
*
* Driver for a 82C710 C&T mouse interface chip.
*
* Based on the PS/2 driver by Johan Myreen.
*
* Corrections in device setup for some laptop mice & trackballs.
* 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
*
* Modified by Johan Myreen (jem@iki.fi) 04Aug93
* to include support for QuickPort mouse.
*
* Changed references to "QuickPort" with "82C710" since "QuickPort"
* is not what this driver is all about -- QuickPort is just a
* connector type, and this driver is for the mouse port on the Chips
* & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi
*
* Added support for SIGIO. 28Jul95 jem@iki.fi
*
* Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com
*
* Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/semaphore.h>
#include <linux/pc_keyb.h> /* mouse enable command.. */
/*
* We use the same minor number as the PS/2 mouse for (bad) historical
* reasons..
*/
#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */
#define QP_BUF_SIZE 2048
struct qp_queue {
unsigned long head;
unsigned long tail;
wait_queue_head_t proc_list;
struct fasync_struct *fasync;
unsigned char buf[QP_BUF_SIZE];
};
static struct qp_queue *queue;
static unsigned int get_from_queue(void)
{
unsigned int result;
unsigned long flags;
save_flags(flags);
cli();
result = queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (QP_BUF_SIZE-1);
restore_flags(flags);
return result;
}
static inline int queue_empty(void)
{
return queue->head == queue->tail;
}
static int fasync_qp(int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &queue->fasync);
if (retval < 0)
return retval;
return 0;
}
/*
* 82C710 Interface
*/
#define QP_DATA 0x310 /* Data Port I/O Address */
#define QP_STATUS 0x311 /* Status Port I/O Address */
#define QP_DEV_IDLE 0x01 /* Device Idle */
#define QP_RX_FULL 0x02 /* Device Char received */
#define QP_TX_IDLE 0x04 /* Device XMIT Idle */
#define QP_RESET 0x08 /* Device Reset */
#define QP_INTS_ON 0x10 /* Device Interrupt On */
#define QP_ERROR_FLAG 0x20 /* Device Error */
#define QP_CLEAR 0x40 /* Device Clear */
#define QP_ENABLE 0x80 /* Device Enable */
#define QP_IRQ 12
static int qp_present;
static int qp_count;
static spinlock_t qp_count_lock = SPIN_LOCK_UNLOCKED;
static int qp_data = QP_DATA;
static int qp_status = QP_STATUS;
static int poll_qp_status(void);
static int probe_qp(void);
/*
* Interrupt handler for the 82C710 mouse port. A character
* is waiting in the 82C710.
*/
static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
{
int head = queue->head;
int maxhead = (queue->tail-1) & (QP_BUF_SIZE-1);
add_mouse_randomness(queue->buf[head] = inb(qp_data));
if (head != maxhead) {
head++;
head &= QP_BUF_SIZE-1;
}
queue->head = head;
kill_fasync(&queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
static int release_qp(struct inode * inode, struct file * file)
{
unsigned char status;
fasync_qp(-1, file, 0);
spin_lock( &qp_count_lock );
if (!--qp_count) {
if (!poll_qp_status())
printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
status = inb_p(qp_status);
outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
if (!poll_qp_status())
printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
free_irq(QP_IRQ, NULL);
}
spin_unlock( &qp_count_lock );
return 0;
}
/*
* Install interrupt handler.
* Enable the device, enable interrupts.
*/
static int open_qp(struct inode * inode, struct file * file)
{
unsigned char status;
if (!qp_present)
return -EINVAL;
spin_lock( &qp_count_lock );
if (qp_count++)
{
spin_unlock( &qp_count_lock );
return 0;
}
spin_unlock( &qp_count_lock );
if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) {
qp_count--;
return -EBUSY;
}
status = inb_p(qp_status);
status |= (QP_ENABLE|QP_RESET);
outb_p(status, qp_status);
status &= ~(QP_RESET);
outb_p(status, qp_status);
queue->head = queue->tail = 0; /* Flush input queue */
status |= QP_INTS_ON;
outb_p(status, qp_status); /* Enable interrupts */
while (!poll_qp_status()) {
printk(KERN_ERR "Error: Mouse device busy in open_qp()\n");
qp_count--;
status &= ~(QP_ENABLE|QP_INTS_ON);
outb_p(status, qp_status);
free_irq(QP_IRQ, NULL);
return -EBUSY;
}
outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */
return 0;
}
/*
* Write to the 82C710 mouse device.
*/
static ssize_t write_qp(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
ssize_t i = count;
while (i--) {
char c;
if (!poll_qp_status())
return -EIO;
get_user(c, buffer++);
outb_p(c, qp_data);
}
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
return count;
}
static unsigned int poll_qp(struct file *file, poll_table * wait)
{
poll_wait(file, &queue->proc_list, wait);
if (!queue_empty())
return POLLIN | POLLRDNORM;
return 0;
}
/*
* Wait for device to send output char and flush any input char.
*/
#define MAX_RETRIES (60)
static int poll_qp_status(void)
{
int retries=0;
while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
!= (QP_DEV_IDLE|QP_TX_IDLE)
&& retries < MAX_RETRIES) {
if (inb_p(qp_status)&(QP_RX_FULL))
inb_p(qp_data);
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((5*HZ + 99) / 100);
retries++;
}
return !(retries==MAX_RETRIES);
}
/*
* Put bytes from input queue to buffer.
*/
static ssize_t read_qp(struct file * file, char * buffer,
size_t count, loff_t *ppos)
{
DECLARE_WAITQUEUE(wait, current);
ssize_t i = count;
unsigned char c;
if (queue_empty()) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
add_wait_queue(&queue->proc_list, &wait);
repeat:
set_current_state(TASK_INTERRUPTIBLE);
if (queue_empty() && !signal_pending(current)) {
schedule();
goto repeat;
}
current->state = TASK_RUNNING;
remove_wait_queue(&queue->proc_list, &wait);
}
while (i > 0 && !queue_empty()) {
c = get_from_queue();
put_user(c, buffer++);
i--;
}
if (count-i) {
file->f_dentry->d_inode->i_atime = CURRENT_TIME;
return count-i;
}
if (signal_pending(current))
return -ERESTARTSYS;
return 0;
}
struct file_operations qp_fops = {
owner: THIS_MODULE,
read: read_qp,
write: write_qp,
poll: poll_qp,
open: open_qp,
release: release_qp,
fasync: fasync_qp,
};
/*
* Initialize driver.
*/
static struct miscdevice qp_mouse = {
minor: PSMOUSE_MINOR,
name: "QPmouse",
fops: &qp_fops,
};
/*
* Function to read register in 82C710.
*/
static inline unsigned char read_710(unsigned char index)
{
outb_p(index, 0x390); /* Write index */
return inb_p(0x391); /* Read the data */
}
/*
* See if we can find a 82C710 device. Read mouse address.
*/
static int __init probe_qp(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 */
if (read_710(0x0f) != 0xe4) /* Config address found? */
return 0; /* No: no 82C710 here */
qp_data = read_710(0x0d)*4; /* Get mouse I/O address */
qp_status = qp_data+1;
outb_p(0x0f, 0x390);
outb_p(0x0f, 0x391); /* Close config mode */
return 1;
}
static char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n";
static char msg_nomem[] __initdata = KERN_ERR "qpmouse: no queue memory.\n";
static int __init qpmouse_init_driver(void)
{
if (!probe_qp())
return -EIO;
printk(msg_banner);
/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
if (queue == NULL) {
printk(msg_nomem);
return -ENOMEM;
}
qp_present = 1;
misc_register(&qp_mouse);
memset(queue, 0, sizeof(*queue));
queue->head = queue->tail = 0;
init_waitqueue_head(&queue->proc_list);
return 0;
}
static void __exit qpmouse_exit_driver(void)
{
misc_deregister(&qp_mouse);
kfree(queue);
}
module_init(qpmouse_init_driver);
module_exit(qpmouse_exit_driver);
MODULE_LICENSE("GPL");
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