1 /* sunmouse.c: Sun mouse driver for the Sparc
3 * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
4 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * Parts based on the psaux.c driver written by:
9 * Dec/19/95 Added SunOS mouse ioctls - miguel.
10 * Jan/5/96 Added VUID support, sigio support - miguel.
11 * Mar/5/96 Added proper mouse stream support - miguel.
12 * Sep/96 Allow more than one reader -miguel.
13 * Aug/97 Added PCI 8042 controller support -DaveM
16 /* The mouse is run off of one of the Zilog serial ports. On
17 * that port is the mouse and the keyboard, each gets a zs channel.
18 * The mouse itself is mouse-systems in nature. So the protocol is:
20 * Byte 1) Button state which is bit-encoded as
21 * 0x4 == left-button down, else up
22 * 0x2 == middle-button down, else up
23 * 0x1 == right-button down, else up
27 * Byte 4) Delta-x again
28 * Byte 5) Delta-y again
30 * One day this driver will have to support more than one mouse in the system.
32 * This driver has two modes of operation: the default VUID_NATIVE is
33 * set when the device is opened and allows the application to see the
34 * mouse character stream as we get it from the serial (for gpm for
35 * example). The second method, VUID_FIRM_EVENT will provide cooked
36 * events in Firm_event records as expected by SunOS/Solaris applications.
38 * FIXME: We need to support more than one mouse.
41 #include <linux/config.h>
42 #include <linux/kernel.h>
43 #include <linux/sched.h>
44 #include <linux/fcntl.h>
45 #include <linux/signal.h>
46 #include <linux/timer.h>
47 #include <linux/errno.h>
48 #include <linux/miscdevice.h>
50 #include <linux/poll.h>
51 #include <linux/init.h>
52 #include <asm/uaccess.h>
53 #include <asm/system.h>
54 #include <asm/vuid_event.h>
55 #include <linux/random.h>
56 /* The following keeps track of software state for the Sun
59 #define STREAM_SIZE 2048
60 #define EV_SIZE (STREAM_SIZE/sizeof (Firm_event))
62 #define BUTTON_MIDDLE 2
63 #define BUTTON_RIGHT 1
66 unsigned char transaction
[5]; /* Each protocol transaction */
67 unsigned char byte
; /* Counter, starts at 0 */
68 unsigned char button_state
; /* Current button state */
69 unsigned char prev_state
; /* Previous button state */
70 int delta_x
; /* Current delta-x */
71 int delta_y
; /* Current delta-y */
73 int ready
; /* set if there if data is available */
74 int active
; /* set if device is open */
75 int vuid_mode
; /* VUID_NATIVE or VUID_FIRM_EVENT */
76 struct wait_queue
*proc_list
;
77 struct fasync_struct
*fasync
;
79 /* The event/stream queue */
83 char stream
[STREAM_SIZE
];
88 static struct sun_mouse sunmouse
;
89 #define gen_events (sunmouse.vuid_mode != VUID_NATIVE)
90 #define bstate sunmouse.button_state
91 #define pstate sunmouse.prev_state
93 extern void mouse_put_char(char ch
);
98 push_event (Firm_event
*ev
)
100 int next
= (sunmouse
.head
+ 1) % EV_SIZE
;
102 if (next
!= sunmouse
.tail
){
103 sunmouse
.queue
.ev
[sunmouse
.head
] = *ev
;
104 sunmouse
.head
= next
;
111 return sunmouse
.head
== sunmouse
.tail
;
115 get_from_queue (void)
119 result
= &sunmouse
.queue
.ev
[sunmouse
.tail
];
120 sunmouse
.tail
= (sunmouse
.tail
+ 1) % EV_SIZE
;
127 int next
= (sunmouse
.head
+ 1) % STREAM_SIZE
;
129 if (next
!= sunmouse
.tail
){
131 printk("P<%02x>\n", (unsigned char)c
);
133 sunmouse
.queue
.stream
[sunmouse
.head
] = c
;
134 sunmouse
.head
= next
;
138 kill_fasync (sunmouse
.fasync
, SIGIO
);
139 wake_up_interruptible (&sunmouse
.proc_list
);
142 /* Auto baud rate "detection". ;-) */
143 static int mouse_bogon_bytes
= 0;
144 static int mouse_baud_changing
= 0; /* For reporting things to the user. */
145 static int mouse_baud
= 4800; /* Initial rate set by zilog driver. */
147 /* Change the baud rate after receiving too many "bogon bytes". */
148 void sun_mouse_change_baud(void)
150 extern void rs_change_mouse_baud(int newbaud
);
152 if(mouse_baud
== 1200)
157 rs_change_mouse_baud(mouse_baud
);
158 mouse_baud_changing
= 1;
161 void mouse_baud_detection(unsigned char c
)
163 static int wait_for_synchron
= 1;
166 if(wait_for_synchron
) {
167 if((c
< 0x80) || (c
> 0x87))
171 wait_for_synchron
= 0;
177 wait_for_synchron
= 1;
178 if(mouse_baud_changing
== 1) {
179 printk(KERN_DEBUG
"sunmouse: Successfully adjusted to %d baud.\n",
181 mouse_baud_changing
= 0;
185 if(mouse_bogon_bytes
> 12) {
186 sun_mouse_change_baud();
187 mouse_bogon_bytes
= 0;
188 wait_for_synchron
= 1;
192 /* The following is called from the zs driver when bytes are received on
193 * the Mouse zs8530 channel.
196 sun_mouse_inbyte(unsigned char byte
)
202 add_mouse_randomness (byte
);
206 mouse_baud_detection(byte
);
213 /* If the mouse sends us a byte from 0x80 to 0x87
214 * we are starting at byte zero in the transaction
217 if(byte
>= 0x80 && byte
<= 0x87)
220 mvalue
= (signed char) byte
;
221 switch(sunmouse
.byte
) {
224 sunmouse
.button_state
= (~byte
) & 0x7;
226 printk("B<Left %s, Middle %s, Right %s>",
227 ((sunmouse
.button_state
& 0x4) ? "DOWN" : "UP"),
228 ((sunmouse
.button_state
& 0x2) ? "DOWN" : "UP"),
229 ((sunmouse
.button_state
& 0x1) ? "DOWN" : "UP"));
236 printk("DX1<%d>", mvalue
);
238 sunmouse
.delta_x
= mvalue
;
244 printk("DY1<%d>", mvalue
);
246 sunmouse
.delta_y
= mvalue
;
252 printk("DX2<%d>", mvalue
);
254 sunmouse
.delta_x
+= mvalue
;
258 /* Last byte, Delta-y 2 */
260 printk("DY2<%d>", mvalue
);
262 sunmouse
.delta_y
+= mvalue
;
263 sunmouse
.byte
= 69; /* Some ridiculous value */
266 /* Until we get the (0x80 -> 0x87) value we aren't
267 * in the middle of a real transaction, so just
272 printk("sunmouse: bogon transaction state\n");
273 sunmouse
.byte
= 69; /* What could cause this? */
279 if (d
& BUTTON_LEFT
){
281 ev
.value
= bstate
& BUTTON_LEFT
;
283 if (d
& BUTTON_RIGHT
){
285 ev
.value
= bstate
& BUTTON_RIGHT
;
287 if (d
& BUTTON_MIDDLE
){
289 ev
.value
= bstate
& BUTTON_MIDDLE
;
292 ev
.value
= ev
.value
? VKEY_DOWN
: VKEY_UP
;
295 if (sunmouse
.delta_x
){
298 ev
.value
= sunmouse
.delta_x
;
300 sunmouse
.delta_x
= 0;
302 if (sunmouse
.delta_y
){
305 ev
.value
= sunmouse
.delta_y
;
309 /* We just completed a transaction, wake up whoever is awaiting
314 kill_fasync (sunmouse
.fasync
, SIGIO
);
315 wake_up_interruptible(&sunmouse
.proc_list
);
320 sun_mouse_open(struct inode
* inode
, struct file
* file
)
322 if(sunmouse
.active
++)
324 if(!sunmouse
.present
)
326 sunmouse
.ready
= sunmouse
.delta_x
= sunmouse
.delta_y
= 0;
327 sunmouse
.button_state
= 0x80;
328 sunmouse
.vuid_mode
= VUID_NATIVE
;
332 static int sun_mouse_fasync (struct file
*filp
, int on
)
336 retval
= fasync_helper (filp
, on
, &sunmouse
.fasync
);
343 sun_mouse_close(struct inode
*inode
, struct file
*file
)
345 sun_mouse_fasync (file
, 0);
346 if (--sunmouse
.active
)
353 sun_mouse_write(struct file
*file
, const char *buffer
,
354 size_t count
, loff_t
*ppos
)
356 return -EINVAL
; /* foo on you */
360 sun_mouse_read(struct file
*file
, char *buffer
,
361 size_t count
, loff_t
*ppos
)
363 struct wait_queue wait
= { current
, NULL
};
366 if (file
->f_flags
& O_NONBLOCK
)
368 add_wait_queue (&sunmouse
.proc_list
, &wait
);
369 while (queue_empty () && !signal_pending(current
)) {
370 current
->state
= TASK_INTERRUPTIBLE
;
373 current
->state
= TASK_RUNNING
;
374 remove_wait_queue (&sunmouse
.proc_list
, &wait
);
377 char *p
= buffer
, *end
= buffer
+count
;
379 while (p
< end
&& !queue_empty ()){
380 #ifdef CONFIG_SPARC32_COMPAT
381 if (current
->tss
.flags
& SPARC_FLAG_32BIT
) {
382 Firm_event
*q
= get_from_queue();
384 copy_to_user_ret((Firm_event
*)p
, q
,
385 sizeof(Firm_event
)-sizeof(struct timeval
),
387 p
+= sizeof(Firm_event
)-sizeof(struct timeval
);
388 __put_user_ret(q
->time
.tv_sec
, (u32
*)p
, -EFAULT
);
390 __put_user_ret(q
->time
.tv_usec
, (u32
*)p
, -EFAULT
);
395 copy_to_user_ret((Firm_event
*)p
, get_from_queue(),
396 sizeof(Firm_event
), -EFAULT
);
397 p
+= sizeof (Firm_event
);
400 sunmouse
.ready
= !queue_empty ();
401 file
->f_dentry
->d_inode
->i_atime
= CURRENT_TIME
;
406 for (c
= count
; !queue_empty() && c
; c
--){
407 put_user_ret(sunmouse
.queue
.stream
[sunmouse
.tail
], buffer
, -EFAULT
);
409 sunmouse
.tail
= (sunmouse
.tail
+ 1) % STREAM_SIZE
;
411 sunmouse
.ready
= !queue_empty();
412 file
->f_dentry
->d_inode
->i_atime
= CURRENT_TIME
;
415 /* Only called if nothing was sent */
416 if (signal_pending(current
))
421 static unsigned int sun_mouse_poll(struct file
*file
, poll_table
*wait
)
423 poll_wait(file
, &sunmouse
.proc_list
, wait
);
425 return POLLIN
| POLLRDNORM
;
429 sun_mouse_ioctl (struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
434 /* VUIDGFORMAT - Get input device byte stream format */
435 case _IOR('v', 2, int):
436 put_user_ret(sunmouse
.vuid_mode
, (int *) arg
, -EFAULT
);
439 /* VUIDSFORMAT - Set input device byte stream format*/
440 case _IOW('v', 1, int):
441 get_user_ret(i
, (int *) arg
, -EFAULT
);
442 if (i
== VUID_NATIVE
|| i
== VUID_FIRM_EVENT
){
445 get_user_ret(value
, (int *)arg
, -EFAULT
);
446 sunmouse
.vuid_mode
= value
;
447 sunmouse
.head
= sunmouse
.tail
= 0;
454 /* This is a buggy application doing termios on the mouse driver */
455 /* we ignore it. I keep this check here so that we will notice */
456 /* future mouse vuid ioctls */
461 printk ("[MOUSE-ioctl: %8.8x]\n", cmd
);
468 struct file_operations sun_mouse_fops
= {
483 static struct miscdevice sun_mouse_mouse
= {
484 SUN_MOUSE_MINOR
, "sunmouse", &sun_mouse_fops
487 __initfunc(int sun_mouse_init(void))
489 if (!sunmouse
.present
)
492 printk("Sun Mouse-Systems mouse driver version 1.00\n");
494 sunmouse
.ready
= sunmouse
.active
= 0;
495 misc_register (&sun_mouse_mouse
);
496 sunmouse
.delta_x
= sunmouse
.delta_y
= 0;
497 sunmouse
.button_state
= 0x80;
498 sunmouse
.proc_list
= NULL
;
504 sun_mouse_zsinit(void)
506 sunmouse
.present
= 1;