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
;
60 MODULE_PARM(mouse_irq
, "i");
63 void __init
bmouse_setup(char *str
, int *ints
)
69 static void mouse_interrupt(int irq
, void *dev_id
, struct pt_regs
*regs
)
72 unsigned char buttons
;
74 outb(MSE_READ_X_LOW
, MSE_CONTROL_PORT
);
75 dx
= (inb(MSE_DATA_PORT
) & 0xf);
76 outb(MSE_READ_X_HIGH
, MSE_CONTROL_PORT
);
77 dx
|= (inb(MSE_DATA_PORT
) & 0xf) << 4;
78 outb(MSE_READ_Y_LOW
, MSE_CONTROL_PORT
);
79 dy
= (inb(MSE_DATA_PORT
) & 0xf);
80 outb(MSE_READ_Y_HIGH
, MSE_CONTROL_PORT
);
81 buttons
= inb(MSE_DATA_PORT
);
82 dy
|= (buttons
& 0xf) << 4;
83 buttons
= ((buttons
>> 5) & 0x07);
84 if (dx
!= 0 || dy
!= 0 || buttons
!= mouse
.buttons
) {
85 add_mouse_randomness((buttons
<< 16) + (dy
<< 8) + dx
);
86 mouse
.buttons
= buttons
;
90 wake_up_interruptible(&mouse
.wait
);
93 * keep dx/dy reasonable, but still able to track when X (or
94 * whatever) must page or is busy (i.e. long waits between
102 if (mouse
.dy
< -2048)
108 kill_fasync(mouse
.fasyncptr
, SIGIO
);
113 static int fasync_mouse(int fd
, struct file
*filp
, int on
)
117 retval
= fasync_helper(fd
, filp
, on
, &mouse
.fasyncptr
);
124 * close access to the mouse
127 static int close_mouse(struct inode
* inode
, struct file
* file
)
129 fasync_mouse(-1, file
, 0);
133 free_irq(mouse_irq
, NULL
);
139 * open access to the mouse
142 static int open_mouse(struct inode
* inode
, struct file
* file
)
148 if (request_irq(mouse_irq
, mouse_interrupt
, 0, "busmouse", NULL
)) {
155 mouse
.buttons
= 0x87;
162 * writes are disallowed
165 static ssize_t
write_mouse(struct file
* file
,
166 const char * buffer
, size_t count
, loff_t
*ppos
)
172 * read mouse data. Currently never blocks.
175 static ssize_t
read_mouse(struct file
* file
,
176 char * buffer
, size_t count
, loff_t
*ppos
)
181 unsigned char buttons
;
186 if ((r
= verify_area(VERIFY_WRITE
, buffer
, count
)))
192 * Obtain the current mouse parameters and limit as appropriate for
193 * the return data format. Interrupts are only disabled while
194 * obtaining the parameters, NOT during the puts_fs_byte() calls,
195 * so paging in put_user() does not effect mouse tracking.
198 /* save_flags(flags); cli(); */
199 disable_irq(mouse_irq
);
210 buttons
= mouse
.buttons
;
214 enable_irq(mouse_irq
);
215 /* restore_flags(flags); */
217 put_user(buttons
| 0x80, buffer
);
218 put_user((char)dx
, buffer
+ 1);
219 put_user((char)dy
, buffer
+ 2);
220 for (r
= 3; r
< count
; r
++)
221 put_user(0x00, buffer
+ r
);
226 * poll for mouse input
228 static unsigned int mouse_poll(struct file
*file
, poll_table
* wait
)
230 poll_wait(file
, &mouse
.wait
, wait
);
232 return POLLIN
| POLLRDNORM
;
236 struct file_operations bus_mouse_fops
= {
237 NULL
, /* mouse_seek */
240 NULL
, /* mouse_readdir */
241 mouse_poll
, /* mouse_poll */
242 NULL
, /* mouse_ioctl */
243 NULL
, /* mouse_mmap */
251 static struct miscdevice bus_mouse
= {
252 LOGITECH_BUSMOUSE
, "busmouse", &bus_mouse_fops
255 int __init
bus_mouse_init(void)
257 if (check_region(LOGIBM_BASE
, LOGIBM_EXTENT
)) {
262 outb(MSE_CONFIG_BYTE
, MSE_CONFIG_PORT
);
263 outb(MSE_SIGNATURE_BYTE
, MSE_SIGNATURE_PORT
);
264 udelay(100L); /* wait for reply from mouse */
265 if (inb(MSE_SIGNATURE_PORT
) != MSE_SIGNATURE_BYTE
) {
269 outb(MSE_DEFAULT_MODE
, MSE_CONFIG_PORT
);
272 request_region(LOGIBM_BASE
, LOGIBM_EXTENT
, "busmouse");
277 mouse
.buttons
= 0x87;
280 init_waitqueue_head(&mouse
.wait
);
281 printk(KERN_INFO
"Logitech bus mouse detected, using IRQ %d.\n",
283 misc_register(&bus_mouse
);
289 int init_module(void)
291 return bus_mouse_init();
294 void cleanup_module(void)
296 misc_deregister(&bus_mouse
);
297 release_region(LOGIBM_BASE
, LOGIBM_EXTENT
);