2 * USB HID boot protocol mouse support based on MS BusMouse driver, psaux
3 * driver, and Linus's skeleton USB mouse driver. Fixed up a lot by Linus.
7 * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it
8 * correctly. Events are added together, not queued, to keep the rodent sober.
10 * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events.
11 * This is wrong: when an application (like X or gpm) reads the mouse device,
12 * it wants to find out the mouse's current position, not its recent history.
13 * The button thing turned out to be UHCI not flipping data toggle, so half the
14 * packets were thrown out.
16 * version 0.01: Switched over to busmouse protocol, and changed the minor
17 * number to 32 (same as uusbd's hidbp driver). Buttons work more sanely now,
18 * but it still doesn't generate button events unless you move the mouse.
20 * version 0.0: Driver emulates a PS/2 mouse, stealing /dev/psaux (sorry, I
21 * know that's not very nice). Moving in the X and Y axes works. Buttons don't
22 * work right yet: X sees a lot of MotionNotify/ButtonPress/ButtonRelease
23 * combos when you hold down a button and drag the mouse around. Probably has
24 * some additional bugs on an SMP machine.
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
29 #include <linux/signal.h>
30 #include <linux/errno.h>
31 #include <linux/miscdevice.h>
32 #include <linux/random.h>
33 #include <linux/poll.h>
34 #include <linux/init.h>
35 #include <linux/malloc.h>
37 #include <asm/spinlock.h>
41 #define USB_MOUSE_MINOR 32
44 unsigned char buttons
; /* current button state */
45 long dx
; /* dx, dy, dz are change since last read */
48 int present
; /* this mouse is plugged in */
49 int active
; /* someone is has this mouse's device open */
50 int ready
; /* the mouse has changed state since the last read */
51 wait_queue_head_t wait
; /* for polling */
52 struct fasync_struct
*fasync
;
53 /* later, add a list here to support multiple mice */
54 /* but we will also need a list of file pointers to identify it */
57 static struct mouse_state static_mouse_state
= {
60 __WAIT_QUEUE_HEAD_INITIALIZER(static_mouse_state
.wait
),
63 spinlock_t usb_mouse_lock
= SPIN_LOCK_UNLOCKED
;
65 static int mouse_irq(int state
, void *__buffer
, void *dev_id
)
67 signed char *data
= __buffer
;
68 /* finding the mouse is easy when there's only one */
69 struct mouse_state
*mouse
= &static_mouse_state
;
71 /* if a mouse moves with no one listening, do we care? no */
75 /* if the USB mouse sends an interrupt, then something noteworthy
77 mouse
->buttons
= data
[0] & 0x07;
78 mouse
->dx
+= data
[1]; /* data[] is signed, so this works */
79 mouse
->dy
-= data
[2]; /* y-axis is reversed */
83 add_mouse_randomness((mouse
->buttons
<< 24) + (mouse
->dz
<< 16 ) +
84 (mouse
->dy
<< 8) + mouse
->dx
);
86 wake_up_interruptible(&mouse
->wait
);
88 kill_fasync(mouse
->fasync
, SIGIO
);
93 static int fasync_mouse(int fd
, struct file
*filp
, int on
)
96 struct mouse_state
*mouse
= &static_mouse_state
;
98 retval
= fasync_helper(fd
, filp
, on
, &mouse
->fasync
);
104 static int release_mouse(struct inode
* inode
, struct file
* file
)
106 struct mouse_state
*mouse
= &static_mouse_state
;
108 fasync_mouse(-1, file
, 0);
114 static int open_mouse(struct inode
* inode
, struct file
* file
)
116 struct mouse_state
*mouse
= &static_mouse_state
;
123 mouse
->buttons
= mouse
->dx
= mouse
->dy
= mouse
->dz
= 0;
127 static ssize_t
write_mouse(struct file
* file
,
128 const char * buffer
, size_t count
, loff_t
*ppos
)
134 * Look like a PS/2 mouse, please..
136 * The PS/2 protocol is fairly strange, but
137 * oh, well, it's at least common..
139 static ssize_t
read_mouse(struct file
* file
, char * buffer
, size_t count
, loff_t
*ppos
)
142 static int state
= 0;
143 struct mouse_state
*mouse
= &static_mouse_state
;
148 case 0: { /* buttons and sign */
149 int buttons
= mouse
->buttons
;
155 put_user(buttons
, buffer
);
165 put_user(dx
, buffer
);
175 put_user(dy
, buffer
);
186 static unsigned int mouse_poll(struct file
*file
, poll_table
* wait
)
188 struct mouse_state
*mouse
= &static_mouse_state
;
190 poll_wait(file
, &mouse
->wait
, wait
);
192 return POLLIN
| POLLRDNORM
;
196 struct file_operations usb_mouse_fops
= {
197 NULL
, /* mouse_seek */
200 NULL
, /* mouse_readdir */
201 mouse_poll
, /* mouse_poll */
202 NULL
, /* mouse_ioctl */
203 NULL
, /* mouse_mmap */
211 static struct miscdevice usb_mouse
= {
212 USB_MOUSE_MINOR
, "USB mouse", &usb_mouse_fops
215 static int mouse_probe(struct usb_device
*dev
)
217 struct usb_interface_descriptor
*interface
;
218 struct usb_endpoint_descriptor
*endpoint
;
219 struct mouse_state
*mouse
= &static_mouse_state
;
221 /* We don't handle multi-config mice */
222 if (dev
->descriptor
.bNumConfigurations
!= 1)
225 /* We don't handle multi-interface mice */
226 if (dev
->config
[0].bNumInterfaces
!= 1)
229 /* Is it a mouse interface? */
230 interface
= &dev
->config
[0].interface
[0];
231 if (interface
->bInterfaceClass
!= 3)
233 if (interface
->bInterfaceSubClass
!= 1)
235 if (interface
->bInterfaceProtocol
!= 2)
238 /* Multiple endpoints? What kind of mutant ninja-mouse is this? */
239 if (interface
->bNumEndpoints
!= 1)
242 endpoint
= &interface
->endpoint
[0];
244 /* Output endpoint? Curiousier and curiousier.. */
245 if (!(endpoint
->bEndpointAddress
& 0x80))
248 /* If it's not an interrupt endpoint, we'd better punt! */
249 if ((endpoint
->bmAttributes
& 3) != 3)
252 printk("USB mouse found\n");
254 usb_set_configuration(dev
, dev
->config
[0].bConfigurationValue
);
256 usb_request_irq(dev
, usb_rcvctrlpipe(dev
, endpoint
->bEndpointAddress
), mouse_irq
, endpoint
->bInterval
, NULL
);
262 static void mouse_disconnect(struct usb_device
*dev
)
264 struct mouse_state
*mouse
= &static_mouse_state
;
266 /* this might need work */
270 static struct usb_driver mouse_driver
= {
277 int usb_mouse_init(void)
279 struct mouse_state
*mouse
= &static_mouse_state
;
281 misc_register(&usb_mouse
);
283 mouse
->present
= mouse
->active
= 0;
285 mouse
->fasync
= NULL
;
287 usb_register(&mouse_driver
);
288 printk(KERN_INFO
"USB HID boot protocol mouse registered.\n");
292 void usb_mouse_cleanup(void)
294 /* this, too, probably needs work */
295 usb_deregister(&mouse_driver
);
296 misc_deregister(&usb_mouse
);