Import 2.1.118
[davej-history.git] / drivers / sbus / char / sunmouse.c
blob3a6d672fbf577ee3d0796021383482a6da80e5d1
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:
7 * Johan Myreen.
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
25 * Byte 2) Delta-x
26 * Byte 3) Delta-y
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.
39 * */
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>
49 #include <linux/mm.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
57 * mouse.
59 #define STREAM_SIZE 2048
60 #define EV_SIZE (STREAM_SIZE/sizeof (Firm_event))
61 #define BUTTON_LEFT 4
62 #define BUTTON_MIDDLE 2
63 #define BUTTON_RIGHT 1
65 struct sun_mouse {
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 */
72 int present;
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 */
80 unsigned int head;
81 unsigned int tail;
82 union {
83 char stream [STREAM_SIZE];
84 Firm_event ev [0];
85 } queue;
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);
95 #undef SMOUSE_DEBUG
97 static void
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;
108 static int
109 queue_empty (void)
111 return sunmouse.head == sunmouse.tail;
114 static Firm_event *
115 get_from_queue (void)
117 Firm_event *result;
119 result = &sunmouse.queue.ev [sunmouse.tail];
120 sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
121 return result;
124 static void
125 push_char (char c)
127 int next = (sunmouse.head + 1) % STREAM_SIZE;
129 if (next != sunmouse.tail){
130 #ifdef SMOUSE_DEBUG
131 printk("P<%02x>\n", (unsigned char)c);
132 #endif
133 sunmouse.queue.stream [sunmouse.head] = c;
134 sunmouse.head = next;
136 sunmouse.ready = 1;
137 if (sunmouse.fasync)
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)
153 mouse_baud = 4800;
154 else
155 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;
164 static int ctr = 0;
166 if(wait_for_synchron) {
167 if((c < 0x80) || (c > 0x87))
168 mouse_bogon_bytes++;
169 else {
170 ctr = 0;
171 wait_for_synchron = 0;
173 } else {
174 ctr++;
175 if(ctr >= 4) {
176 ctr = 0;
177 wait_for_synchron = 1;
178 if(mouse_baud_changing == 1) {
179 printk(KERN_DEBUG "sunmouse: Successfully adjusted to %d baud.\n",
180 mouse_baud);
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.
195 void
196 sun_mouse_inbyte(unsigned char byte)
198 signed char mvalue;
199 int d;
200 Firm_event ev;
202 add_mouse_randomness (byte);
203 if(!sunmouse.active)
204 return;
206 mouse_baud_detection(byte);
208 if (!gen_events){
209 push_char (byte);
210 return;
213 /* If the mouse sends us a byte from 0x80 to 0x87
214 * we are starting at byte zero in the transaction
215 * protocol.
217 if(byte >= 0x80 && byte <= 0x87)
218 sunmouse.byte = 0;
220 mvalue = (signed char) byte;
221 switch(sunmouse.byte) {
222 case 0:
223 /* Button state */
224 sunmouse.button_state = (~byte) & 0x7;
225 #ifdef SMOUSE_DEBUG
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"));
230 #endif
231 sunmouse.byte++;
232 return;
233 case 1:
234 /* Delta-x 1 */
235 #ifdef SMOUSE_DEBUG
236 printk("DX1<%d>", mvalue);
237 #endif
238 sunmouse.delta_x = mvalue;
239 sunmouse.byte++;
240 return;
241 case 2:
242 /* Delta-y 1 */
243 #ifdef SMOUSE_DEBUG
244 printk("DY1<%d>", mvalue);
245 #endif
246 sunmouse.delta_y = mvalue;
247 sunmouse.byte++;
248 return;
249 case 3:
250 /* Delta-x 2 */
251 #ifdef SMOUSE_DEBUG
252 printk("DX2<%d>", mvalue);
253 #endif
254 sunmouse.delta_x += mvalue;
255 sunmouse.byte++;
256 return;
257 case 4:
258 /* Last byte, Delta-y 2 */
259 #ifdef SMOUSE_DEBUG
260 printk("DY2<%d>", mvalue);
261 #endif
262 sunmouse.delta_y += mvalue;
263 sunmouse.byte = 69; /* Some ridiculous value */
264 break;
265 case 69:
266 /* Until we get the (0x80 -> 0x87) value we aren't
267 * in the middle of a real transaction, so just
268 * return.
270 return;
271 default:
272 printk("sunmouse: bogon transaction state\n");
273 sunmouse.byte = 69; /* What could cause this? */
274 return;
276 d = bstate ^ pstate;
277 pstate = bstate;
278 if (d){
279 if (d & BUTTON_LEFT){
280 ev.id = MS_LEFT;
281 ev.value = bstate & BUTTON_LEFT;
283 if (d & BUTTON_RIGHT){
284 ev.id = MS_RIGHT;
285 ev.value = bstate & BUTTON_RIGHT;
287 if (d & BUTTON_MIDDLE){
288 ev.id = MS_MIDDLE;
289 ev.value = bstate & BUTTON_MIDDLE;
291 ev.time = xtime;
292 ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
293 push_event (&ev);
295 if (sunmouse.delta_x){
296 ev.id = LOC_X_DELTA;
297 ev.time = xtime;
298 ev.value = sunmouse.delta_x;
299 push_event (&ev);
300 sunmouse.delta_x = 0;
302 if (sunmouse.delta_y){
303 ev.id = LOC_Y_DELTA;
304 ev.time = xtime;
305 ev.value = sunmouse.delta_y;
306 push_event (&ev);
309 /* We just completed a transaction, wake up whoever is awaiting
310 * this event.
312 sunmouse.ready = 1;
313 if (sunmouse.fasync)
314 kill_fasync (sunmouse.fasync, SIGIO);
315 wake_up_interruptible(&sunmouse.proc_list);
316 return;
319 static int
320 sun_mouse_open(struct inode * inode, struct file * file)
322 if(sunmouse.active++)
323 return 0;
324 if(!sunmouse.present)
325 return -EINVAL;
326 sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
327 sunmouse.button_state = 0x80;
328 sunmouse.vuid_mode = VUID_NATIVE;
329 return 0;
332 static int sun_mouse_fasync (struct file *filp, int on)
334 int retval;
336 retval = fasync_helper (filp, on, &sunmouse.fasync);
337 if (retval < 0)
338 return retval;
339 return 0;
342 static int
343 sun_mouse_close(struct inode *inode, struct file *file)
345 sun_mouse_fasync (file, 0);
346 if (--sunmouse.active)
347 return 0;
348 sunmouse.ready = 0;
349 return 0;
352 static ssize_t
353 sun_mouse_write(struct file *file, const char *buffer,
354 size_t count, loff_t *ppos)
356 return -EINVAL; /* foo on you */
359 static ssize_t
360 sun_mouse_read(struct file *file, char *buffer,
361 size_t count, loff_t *ppos)
363 struct wait_queue wait = { current, NULL };
365 if (queue_empty ()){
366 if (file->f_flags & O_NONBLOCK)
367 return -EWOULDBLOCK;
368 add_wait_queue (&sunmouse.proc_list, &wait);
369 while (queue_empty () && !signal_pending(current)) {
370 current->state = TASK_INTERRUPTIBLE;
371 schedule ();
373 current->state = TASK_RUNNING;
374 remove_wait_queue (&sunmouse.proc_list, &wait);
376 if (gen_events){
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),
386 -EFAULT);
387 p += sizeof(Firm_event)-sizeof(struct timeval);
388 __put_user_ret(q->time.tv_sec, (u32 *)p, -EFAULT);
389 p += sizeof(u32);
390 __put_user_ret(q->time.tv_usec, (u32 *)p, -EFAULT);
391 p += sizeof(u32);
392 } else
393 #endif
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;
402 return p-buffer;
403 } else {
404 int c;
406 for (c = count; !queue_empty() && c; c--){
407 put_user_ret(sunmouse.queue.stream[sunmouse.tail], buffer, -EFAULT);
408 buffer++;
409 sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
411 sunmouse.ready = !queue_empty();
412 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
413 return count-c;
415 /* Only called if nothing was sent */
416 if (signal_pending(current))
417 return -ERESTARTSYS;
418 return 0;
421 static unsigned int sun_mouse_poll(struct file *file, poll_table *wait)
423 poll_wait(file, &sunmouse.proc_list, wait);
424 if(sunmouse.ready)
425 return POLLIN | POLLRDNORM;
426 return 0;
429 sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
431 int i;
433 switch (cmd){
434 /* VUIDGFORMAT - Get input device byte stream format */
435 case _IOR('v', 2, int):
436 put_user_ret(sunmouse.vuid_mode, (int *) arg, -EFAULT);
437 break;
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){
443 int value;
445 get_user_ret(value, (int *)arg, -EFAULT);
446 sunmouse.vuid_mode = value;
447 sunmouse.head = sunmouse.tail = 0;
448 } else
449 return -EINVAL;
450 break;
452 case 0x8024540b:
453 case 0x40245408:
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 */
457 break;
459 default:
460 #ifdef DEBUG
461 printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
462 #endif
463 return -1;
465 return 0;
468 struct file_operations sun_mouse_fops = {
469 NULL,
470 sun_mouse_read,
471 sun_mouse_write,
472 NULL,
473 sun_mouse_poll,
474 sun_mouse_ioctl,
475 NULL,
476 sun_mouse_open,
477 NULL, /* flush */
478 sun_mouse_close,
479 NULL,
480 sun_mouse_fasync,
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)
490 return -ENODEV;
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;
499 sunmouse.byte = 69;
500 return 0;
503 void
504 sun_mouse_zsinit(void)
506 sunmouse.present = 1;