2 * Logitech Bus Mouse Driver for Linux
5 * Mods by Matthew Dillon
7 * tracks better when X is busy or paging
9 * Heavily modified by David Giller
10 * changed from queue- to counter- driven
11 * hacked out a (probably incorrect) mouse_select
13 * Modified again by Nathan Laredo to interface with
14 * 0.96c-pl1 IRQ handling changes (13JUL92)
15 * didn't bother touching select code.
17 * Modified the select() code blindly to conform to the VFS
18 * requirements. 92.07.14 - Linus. Somebody should test it out.
20 * Modified by Johan Myreen to make room for other mice (9AUG92)
21 * removed assignment chr_fops[10] = &mouse_fops; see mouse.c
22 * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
23 * renamed this file mouse.c => busmouse.c
25 * Minor addition by Cliff Matthews
26 * added fasync support
28 * Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
30 * Replaced dumb busy loop with udelay() 16 Nov 95
31 * Nathan Laredo <laredo@gnu.ai.mit.edu>
33 * Track I/O ports with request_region(). 12 Dec 95 Philip Blundell
36 #include <linux/module.h>
38 #include <linux/kernel.h>
39 #include <linux/sched.h>
40 #include <linux/busmouse.h>
41 #include <linux/signal.h>
42 #include <linux/errno.h>
44 #include <linux/poll.h>
45 #include <linux/miscdevice.h>
46 #include <linux/random.h>
47 #include <linux/delay.h>
48 #include <linux/ioport.h>
49 #include <linux/init.h>
52 #include <asm/uaccess.h>
53 #include <asm/system.h>
56 static struct mouse_status mouse
;
57 static int mouse_irq
= MOUSE_IRQ
;
59 __initfunc(void bmouse_setup(char *str
, int *ints
))
65 static void mouse_interrupt(int irq
, void *dev_id
, struct pt_regs
*regs
)
68 unsigned char buttons
;
70 outb(MSE_READ_X_LOW
, MSE_CONTROL_PORT
);
71 dx
= (inb(MSE_DATA_PORT
) & 0xf);
72 outb(MSE_READ_X_HIGH
, MSE_CONTROL_PORT
);
73 dx
|= (inb(MSE_DATA_PORT
) & 0xf) << 4;
74 outb(MSE_READ_Y_LOW
, MSE_CONTROL_PORT
);
75 dy
= (inb(MSE_DATA_PORT
) & 0xf);
76 outb(MSE_READ_Y_HIGH
, MSE_CONTROL_PORT
);
77 buttons
= inb(MSE_DATA_PORT
);
78 dy
|= (buttons
& 0xf) << 4;
79 buttons
= ((buttons
>> 5) & 0x07);
80 if (dx
!= 0 || dy
!= 0 || buttons
!= mouse
.buttons
) {
81 add_mouse_randomness((buttons
<< 16) + (dy
<< 8) + dx
);
82 mouse
.buttons
= buttons
;
86 wake_up_interruptible(&mouse
.wait
);
89 * keep dx/dy reasonable, but still able to track when X (or
90 * whatever) must page or is busy (i.e. long waits between
104 kill_fasync(mouse
.fasyncptr
, SIGIO
);
109 static int fasync_mouse(struct file
*filp
, int on
)
113 retval
= fasync_helper(filp
, on
, &mouse
.fasyncptr
);
120 * close access to the mouse
123 static int close_mouse(struct inode
* inode
, struct file
* file
)
125 fasync_mouse(file
, 0);
129 free_irq(mouse_irq
, NULL
);
135 * open access to the mouse
138 static int open_mouse(struct inode
* inode
, struct file
* file
)
144 if (request_irq(mouse_irq
, mouse_interrupt
, 0, "busmouse", NULL
)) {
151 mouse
.buttons
= 0x87;
158 * writes are disallowed
161 static ssize_t
write_mouse(struct file
* file
,
162 const char * buffer
, size_t count
, loff_t
*ppos
)
168 * read mouse data. Currently never blocks.
171 static ssize_t
read_mouse(struct file
* file
,
172 char * buffer
, size_t count
, loff_t
*ppos
)
177 unsigned char buttons
;
182 if ((r
= verify_area(VERIFY_WRITE
, buffer
, count
)))
188 * Obtain the current mouse parameters and limit as appropriate for
189 * the return data format. Interrupts are only disabled while
190 * obtaining the parameters, NOT during the puts_fs_byte() calls,
191 * so paging in put_user() does not effect mouse tracking.
194 /* save_flags(flags); cli(); */
195 disable_irq(mouse_irq
);
206 buttons
= mouse
.buttons
;
210 enable_irq(mouse_irq
);
211 /* restore_flags(flags); */
213 put_user(buttons
| 0x80, buffer
);
214 put_user((char)dx
, buffer
+ 1);
215 put_user((char)dy
, buffer
+ 2);
216 for (r
= 3; r
< count
; r
++)
217 put_user(0x00, buffer
+ r
);
222 * poll for mouse input
224 static unsigned int mouse_poll(struct file
*file
, poll_table
* wait
)
226 poll_wait(&mouse
.wait
, wait
);
228 return POLLIN
| POLLRDNORM
;
232 struct file_operations bus_mouse_fops
= {
233 NULL
, /* mouse_seek */
236 NULL
, /* mouse_readdir */
237 mouse_poll
, /* mouse_poll */
238 NULL
, /* mouse_ioctl */
239 NULL
, /* mouse_mmap */
246 static struct miscdevice bus_mouse
= {
247 LOGITECH_BUSMOUSE
, "busmouse", &bus_mouse_fops
250 __initfunc(int bus_mouse_init(void))
252 if (check_region(LOGIBM_BASE
, LOGIBM_EXTENT
)) {
257 outb(MSE_CONFIG_BYTE
, MSE_CONFIG_PORT
);
258 outb(MSE_SIGNATURE_BYTE
, MSE_SIGNATURE_PORT
);
259 udelay(100L); /* wait for reply from mouse */
260 if (inb(MSE_SIGNATURE_PORT
) != MSE_SIGNATURE_BYTE
) {
264 outb(MSE_DEFAULT_MODE
, MSE_CONFIG_PORT
);
267 request_region(LOGIBM_BASE
, LOGIBM_EXTENT
, "busmouse");
272 mouse
.buttons
= 0x87;
276 printk(KERN_INFO
"Logitech bus mouse detected, using IRQ %d.\n",
278 misc_register(&bus_mouse
);
284 int init_module(void)
286 return bus_mouse_init();
289 void cleanup_module(void)
291 misc_deregister(&bus_mouse
);
292 release_region(LOGIBM_BASE
, LOGIBM_EXTENT
);