File: /usr/src/linux/drivers/char/msbusmouse.c

1     /*
2      * Microsoft busmouse driver based on Logitech driver (see busmouse.c)
3      *
4      * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92)
5      *
6      * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net)
7      *    8/28/92
8      *
9      * Microsoft Bus Mouse support folded into 0.97pl4 code
10      *    by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
11      * Changes:  Logitech and Microsoft support in the same kernel.
12      *           Defined new constants in busmouse.h for MS mice.
13      *           Added int mse_busmouse_type to distinguish busmouse types
14      *           Added a couple of new functions to handle differences in using
15      *             MS vs. Logitech (where the int variable wasn't appropriate).
16      *
17      * Modified by Peter Cervasio (address above) (26SEP92)
18      * Changes:  Included code to (properly?) detect when a Microsoft mouse is
19      *           really attached to the machine.  Don't know what this does to
20      *           Logitech bus mice, but all it does is read ports.
21      *
22      * Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de)
23      * Changes:  Better interrupt-handler (like in busmouse.c).
24      *	     Some changes to reduce code-size.
25      *	     Changed detection code to use inb_p() instead of doing empty
26      *	     loops to delay i/o.
27      *
28      * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
29      *
30      * Converted to use new generic busmouse code.  5 Apr 1998
31      *   Russell King <rmk@arm.uk.linux.org>
32      *
33      * version 0.3b
34      */
35     
36     #include <linux/module.h>
37     
38     #include <linux/kernel.h>
39     #include <linux/ioport.h>
40     #include <linux/sched.h>
41     #include <linux/logibusmouse.h>
42     #include <linux/signal.h>
43     #include <linux/errno.h>
44     #include <linux/miscdevice.h>
45     #include <linux/random.h>
46     #include <linux/poll.h>
47     #include <linux/init.h>
48     
49     #include <asm/io.h>
50     #include <asm/uaccess.h>
51     #include <asm/system.h>
52     #include <asm/irq.h>
53     
54     #include "busmouse.h"
55     
56     static int msedev;
57     static int mouse_irq = MOUSE_IRQ;
58     
59     MODULE_PARM(mouse_irq, "i");
60     
61     #ifndef MODULE
62     
63     static int __init msmouse_setup(char *str)
64     {
65             int ints[4];
66     
67             str = get_options(str, ARRAY_SIZE(ints), ints);
68     
69     	if (ints[0] > 0)
70     		mouse_irq=ints[1];
71     
72     	return 1;
73     }
74     
75     __setup("msmouse=",msmouse_setup);
76     
77     #endif /* !MODULE */
78     
79     static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
80     {
81             char dx, dy;
82     	unsigned char buttons;
83     
84     	outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
85     	outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT);
86     
87     	outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT);
88     	dx = inb(MS_MSE_DATA_PORT);
89     
90     	outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT);
91     	dy = inb(MS_MSE_DATA_PORT);
92     
93     	outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT);
94     	buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07;
95     
96     	outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
97     	outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
98     
99     	/* why did the original have:
100     	 * if (dx != 0 || dy != 0 || buttons != mouse.buttons ||
101     	 *    ((~buttons) & 0x07))
102     	 *    ^^^^^^^^^^^^^^^^^^^ this?
103     	 */
104     	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
105     }
106     
107     static int release_mouse(struct inode * inode, struct file * file)
108     {
109     	MS_MSE_INT_OFF();
110     	free_irq(mouse_irq, NULL);
111     	return 0;
112     }
113     
114     static int open_mouse(struct inode * inode, struct file * file)
115     {
116     	if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL))
117     		return -EBUSY;
118     
119     	outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
120     	MS_MSE_INT_ON();	
121     	return 0;
122     }
123     
124     static struct busmouse msbusmouse = {
125     	MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0
126     };
127     
128     static int __init ms_bus_mouse_init(void)
129     {
130     	int present = 0;
131     	int mse_byte, i;
132     
133     	if (check_region(MS_MSE_CONTROL_PORT, 0x04))
134     		return -ENODEV;
135     
136     	if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
137     
138     		mse_byte = inb_p(MS_MSE_SIGNATURE_PORT);
139     
140     		for (i = 0; i < 4; i++) {
141     			if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
142     				if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte)
143     					present = 1;
144     				else
145     					present = 0;
146     			} else
147     				present = 0;
148     		}
149     	}
150     	if (present == 0)
151     		return -EIO;
152     	MS_MSE_INT_OFF();
153     	request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse");
154     	msedev = register_busmouse(&msbusmouse);
155     	if (msedev < 0)
156     		printk(KERN_WARNING "Unable to register msbusmouse driver.\n");
157     	else
158     		printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
159     	return msedev < 0 ? msedev : 0;
160     }
161     
162     static void __exit ms_bus_mouse_exit(void)
163     {
164     	unregister_busmouse(msedev);
165     	release_region(MS_MSE_CONTROL_PORT, 0x04);
166     }
167     
168     module_init(ms_bus_mouse_init)
169     module_exit(ms_bus_mouse_exit)
170     
171     MODULE_LICENSE("GPL");
172     EXPORT_NO_SYMBOLS;
173