blob: 057ca30bc6ffa9a5998a79de3685a8f6d4f82176 [file] [log] [blame]
/*
* 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");
EXPORT_NO_SYMBOLS;