1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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/spinlock.h>
52#include <linux/smp_lock.h>
53#include <linux/init.h>
54#include <asm/uaccess.h>
55#include <asm/system.h>
56#include <asm/vuid_event.h>
57#include <linux/random.h>
58
59
60
61#define STREAM_SIZE 2048
62#define EV_SIZE (STREAM_SIZE/sizeof (Firm_event))
63#define BUTTON_LEFT 4
64#define BUTTON_MIDDLE 2
65#define BUTTON_RIGHT 1
66
67struct sun_mouse {
68 unsigned char transaction[5];
69 unsigned char byte;
70 unsigned char button_state;
71 unsigned char prev_state;
72 int delta_x;
73 int delta_y;
74 int active;
75 int vuid_mode;
76 wait_queue_head_t proc_list;
77 struct fasync_struct *fasync;
78
79
80 spinlock_t lock;
81 unsigned int head;
82 unsigned int tail;
83 union {
84 char stream [STREAM_SIZE];
85 Firm_event ev [EV_SIZE];
86 } queue;
87};
88
89static struct sun_mouse sunmouse;
90#define gen_events (sunmouse.vuid_mode != VUID_NATIVE)
91#define bstate sunmouse.button_state
92#define pstate sunmouse.prev_state
93
94extern void mouse_put_char(char ch);
95
96#undef SMOUSE_DEBUG
97
98static int
99push_event (Firm_event *ev)
100{
101 unsigned long flags;
102 int next, ret;
103
104 spin_lock_irqsave(&sunmouse.lock, flags);
105
106 next = (sunmouse.head + 1) % EV_SIZE;
107 ret = 0;
108 if (next != sunmouse.tail) {
109 sunmouse.queue.ev [sunmouse.head] = *ev;
110 sunmouse.head = next;
111 ret = 1;
112 }
113
114 spin_unlock_irqrestore(&sunmouse.lock, flags);
115
116 return ret;
117}
118
119static int
120queue_empty (void)
121{
122 return sunmouse.head == sunmouse.tail;
123}
124
125
126static void get_from_queue (Firm_event *p)
127{
128 *p = sunmouse.queue.ev [sunmouse.tail];
129 sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE;
130}
131
132static void
133push_char (char c)
134{
135 unsigned long flags;
136 int next;
137
138 spin_lock_irqsave(&sunmouse.lock, flags);
139
140 next = (sunmouse.head + 1) % STREAM_SIZE;
141 if (next != sunmouse.tail) {
142#ifdef SMOUSE_DEBUG
143 printk("P<%02x>\n", (unsigned char)c);
144#endif
145 sunmouse.queue.stream [sunmouse.head] = c;
146 sunmouse.head = next;
147 }
148
149 spin_unlock_irqrestore(&sunmouse.lock, flags);
150
151 kill_fasync (&sunmouse.fasync, SIGIO, POLL_IN);
152 wake_up_interruptible (&sunmouse.proc_list);
153}
154
155
156static int mouse_baud = 4800;
157
158
159void sun_mouse_change_baud(void)
160{
161 extern void rs_change_mouse_baud(int newbaud);
162
163 if(mouse_baud == 1200)
164 mouse_baud = 2400;
165 else if(mouse_baud == 2400)
166 mouse_baud = 4800;
167 else if(mouse_baud == 4800)
168 mouse_baud = 9600;
169 else
170 mouse_baud = 1200;
171
172 rs_change_mouse_baud(mouse_baud);
173}
174
175
176
177
178
179
180
181
182int mouse_baud_detection(unsigned char c, int is_break)
183{
184 static int mouse_got_break = 0;
185 static int ctr = 0;
186
187 if (is_break) {
188
189
190
191
192 if (mouse_got_break && ctr < 8)
193 return 1;
194
195
196 sun_mouse_change_baud();
197 ctr = 0;
198 mouse_got_break = 1;
199 return 1;
200 }
201 if (mouse_got_break) {
202 ctr++;
203 if (c == 0x87) {
204 printk(KERN_INFO "sunmouse: Successfully "
205 "adjusted to %d baud.\n", mouse_baud);
206 mouse_got_break = 0;
207 }
208 return 1;
209 }
210
211 return 0;
212}
213
214
215
216
217
218
219#define CLIP(__X) (((__X) > 127) ? 127 : (((__X) < -127) ? -127 : (__X)))
220
221
222
223
224void
225sun_mouse_inbyte(unsigned char byte, int is_break)
226{
227 signed char mvalue;
228 int d, pushed = 0;
229 Firm_event ev;
230
231 add_mouse_randomness (byte);
232#if 0
233 {
234 static int xxx = 0;
235 printk("mouse(%02x:%d) ",
236 byte, is_break);
237 if (byte == 0x87) {
238 xxx = 0;
239 printk("\n");
240 }
241 }
242#endif
243 if (mouse_baud_detection(byte, is_break))
244 return;
245
246 if(!sunmouse.active)
247 return;
248
249
250 if (sunmouse.byte == 69) {
251 if (byte != 0x87)
252 return;
253
254
255 sunmouse.byte = 0;
256 }
257#if 0
258
259
260
261
262 if((byte & ~0x0f) == 0x80)
263 sunmouse.byte = 0;
264#endif
265
266 mvalue = (signed char) byte;
267 switch(sunmouse.byte) {
268 case 0:
269
270
271
272
273
274
275
276 if ((byte & 0xf0) != 0x80)
277 return;
278
279
280 sunmouse.button_state = (~byte) & 0x7;
281#ifdef SMOUSE_DEBUG
282 printk("B<Left %s, Middle %s, Right %s>",
283 ((sunmouse.button_state & 0x4) ? "DOWN" : "UP"),
284 ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"),
285 ((sunmouse.button_state & 0x1) ? "DOWN" : "UP"));
286#endif
287
288 if (byte & 0x8) {
289 sunmouse.byte += 2;
290 sunmouse.delta_y = 0;
291 sunmouse.delta_x = 0;
292 }
293 sunmouse.byte++;
294 return;
295 case 1:
296
297#ifdef SMOUSE_DEBUG
298 printk("DX1<%d>", mvalue);
299#endif
300 sunmouse.delta_x = mvalue;
301 sunmouse.byte++;
302 return;
303 case 2:
304
305#ifdef SMOUSE_DEBUG
306 printk("DY1<%d>", mvalue);
307#endif
308 sunmouse.delta_y = mvalue;
309 sunmouse.byte++;
310 return;
311 case 3:
312
313#ifdef SMOUSE_DEBUG
314 printk("DX2<%d>", mvalue);
315#endif
316 sunmouse.delta_x += mvalue;
317 sunmouse.delta_x = CLIP(sunmouse.delta_x);
318 sunmouse.byte++;
319 return;
320 case 4:
321
322#ifdef SMOUSE_DEBUG
323 printk("DY2<%d>", mvalue);
324#endif
325 sunmouse.delta_y += mvalue;
326 sunmouse.delta_y = CLIP(sunmouse.delta_y);
327 sunmouse.byte = 0;
328 break;
329 case 69:
330
331
332
333
334 return;
335 default:
336 printk("sunmouse: bogon transaction state\n");
337 sunmouse.byte = 69;
338 return;
339 };
340
341 if (!gen_events) {
342 push_char (~sunmouse.button_state & 0x87);
343 push_char (sunmouse.delta_x);
344 push_char (sunmouse.delta_y);
345 return;
346 }
347
348 d = bstate ^ pstate;
349 pstate = bstate;
350 if (d) {
351 if (d & BUTTON_LEFT) {
352 ev.id = MS_LEFT;
353 ev.value = bstate & BUTTON_LEFT;
354 }
355 if (d & BUTTON_RIGHT) {
356 ev.id = MS_RIGHT;
357 ev.value = bstate & BUTTON_RIGHT;
358 }
359 if (d & BUTTON_MIDDLE) {
360 ev.id = MS_MIDDLE;
361 ev.value = bstate & BUTTON_MIDDLE;
362 }
363 ev.time = xtime;
364 ev.value = ev.value ? VKEY_DOWN : VKEY_UP;
365 pushed += push_event (&ev);
366 }
367 if (sunmouse.delta_x) {
368 ev.id = LOC_X_DELTA;
369 ev.time = xtime;
370 ev.value = sunmouse.delta_x;
371 pushed += push_event (&ev);
372 sunmouse.delta_x = 0;
373 }
374 if (sunmouse.delta_y) {
375 ev.id = LOC_Y_DELTA;
376 ev.time = xtime;
377 ev.value = sunmouse.delta_y;
378 pushed += push_event (&ev);
379 }
380
381 if (pushed != 0) {
382
383
384
385 kill_fasync (&sunmouse.fasync, SIGIO, POLL_IN);
386 wake_up_interruptible(&sunmouse.proc_list);
387 }
388 return;
389}
390
391static int
392sun_mouse_open(struct inode * inode, struct file * file)
393{
394 spin_lock_irq(&sunmouse.lock);
395 if (sunmouse.active++)
396 goto out;
397 sunmouse.delta_x = sunmouse.delta_y = 0;
398 sunmouse.button_state = 0x80;
399 sunmouse.vuid_mode = VUID_NATIVE;
400out:
401 spin_unlock_irq(&sunmouse.lock);
402 return 0;
403}
404
405static int sun_mouse_fasync (int fd, struct file *filp, int on)
406{
407 int retval;
408
409 retval = fasync_helper (fd, filp, on, &sunmouse.fasync);
410 if (retval < 0)
411 return retval;
412 return 0;
413}
414
415static int
416sun_mouse_close(struct inode *inode, struct file *file)
417{
418 sun_mouse_fasync (-1, file, 0);
419
420 spin_lock_irq(&sunmouse.lock);
421 sunmouse.active--;
422 spin_unlock_irq(&sunmouse.lock);
423
424 return 0;
425}
426
427static ssize_t
428sun_mouse_write(struct file *file, const char *buffer,
429 size_t count, loff_t *ppos)
430{
431 return -EINVAL;
432}
433
434static ssize_t
435sun_mouse_read(struct file *file, char *buffer,
436 size_t count, loff_t *ppos)
437{
438 DECLARE_WAITQUEUE(wait, current);
439 unsigned long flags;
440
441 if (queue_empty ()) {
442 if (file->f_flags & O_NONBLOCK)
443 return -EWOULDBLOCK;
444 add_wait_queue (&sunmouse.proc_list, &wait);
445repeat:
446 set_current_state(TASK_INTERRUPTIBLE);
447 if (queue_empty() && !signal_pending(current)) {
448 schedule();
449 goto repeat;
450 }
451 current->state = TASK_RUNNING;
452 remove_wait_queue (&sunmouse.proc_list, &wait);
453 }
454 if (gen_events) {
455 char *p = buffer, *end = buffer+count;
456
457 spin_lock_irqsave(&sunmouse.lock, flags);
458 while (p < end && !queue_empty ()){
459 Firm_event this_event;
460
461 get_from_queue(&this_event);
462 spin_unlock_irqrestore(&sunmouse.lock, flags);
463
464#ifdef CONFIG_SPARC32_COMPAT
465 if (current->thread.flags & SPARC_FLAG_32BIT) {
466 if ((end - p) <
467 ((sizeof(Firm_event) - sizeof(struct timeval) +
468 (sizeof(u32) * 2))))
469 break;
470 if (copy_to_user((Firm_event *)p, &this_event,
471 sizeof(Firm_event)-sizeof(struct timeval)))
472 return -EFAULT;
473 p += sizeof(Firm_event)-sizeof(struct timeval);
474 if (__put_user(this_event.time.tv_sec, (u32 *)p))
475 return -EFAULT;
476 p += sizeof(u32);
477 if (__put_user(this_event.time.tv_usec, (u32 *)p))
478 return -EFAULT;
479 p += sizeof(u32);
480 } else
481#endif
482 {
483 if ((end - p) < sizeof(Firm_event))
484 break;
485 if (copy_to_user((Firm_event *)p, &this_event,
486 sizeof(Firm_event)))
487 return -EFAULT;
488 p += sizeof (Firm_event);
489 }
490 spin_lock_irqsave(&sunmouse.lock, flags);
491 }
492 spin_unlock_irqrestore(&sunmouse.lock, flags);
493 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
494 return p-buffer;
495 } else {
496 int c, limit = 3;
497
498 if (count < limit)
499 limit = count;
500 for (c = 0; c < limit; c++) {
501 unsigned char val;
502 int empty = 0;
503
504 spin_lock_irqsave(&sunmouse.lock, flags);
505 if (queue_empty()) {
506 empty = 1;
507 val = 0;
508 } else {
509 val = sunmouse.queue.stream[sunmouse.tail];
510 sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
511 }
512 spin_unlock_irqrestore(&sunmouse.lock, flags);
513
514 if (empty)
515 break;
516
517 put_user(val, buffer);
518 buffer++;
519 }
520 while (c < count) {
521 if (c >= 5)
522 break;
523 put_user(0, buffer);
524 buffer++;
525 c++;
526 }
527 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
528 return c;
529 }
530
531 if (signal_pending(current))
532 return -ERESTARTSYS;
533 return 0;
534}
535
536static unsigned int sun_mouse_poll(struct file *file, poll_table *wait)
537{
538 poll_wait(file, &sunmouse.proc_list, wait);
539 if(!queue_empty())
540 return POLLIN | POLLRDNORM;
541 return 0;
542}
543int
544sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
545{
546 int i;
547
548 switch (cmd){
549
550 case _IOR('v', 2, int):
551 if (put_user(sunmouse.vuid_mode, (int *) arg))
552 return -EFAULT;
553 break;
554
555
556 case _IOW('v', 1, int):
557 if (get_user(i, (int *) arg))
558 return -EFAULT;
559 if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
560 int value;
561
562 if (get_user(value, (int *)arg))
563 return -EFAULT;
564
565 spin_lock_irq(&sunmouse.lock);
566 sunmouse.vuid_mode = value;
567 sunmouse.head = sunmouse.tail = 0;
568 spin_unlock_irq(&sunmouse.lock);
569 } else
570 return -EINVAL;
571 break;
572
573 case 0x8024540b:
574 case 0x40245408:
575
576
577
578 return -ENOTTY;
579
580 default:
581#ifdef DEBUG
582 printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
583#endif
584 return -EINVAL;
585 }
586 return 0;
587}
588
589struct file_operations sun_mouse_fops = {
590 read: sun_mouse_read,
591 write: sun_mouse_write,
592 poll: sun_mouse_poll,
593 ioctl: sun_mouse_ioctl,
594 open: sun_mouse_open,
595 release: sun_mouse_close,
596 fasync: sun_mouse_fasync,
597};
598
599static struct miscdevice sun_mouse_mouse = {
600 SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
601};
602
603void sun_mouse_zsinit(void)
604{
605 printk("Sun Mouse-Systems mouse driver version 1.00\n");
606
607 sunmouse.active = 0;
608 misc_register (&sun_mouse_mouse);
609 sunmouse.delta_x = sunmouse.delta_y = 0;
610 sunmouse.button_state = 0x80;
611 init_waitqueue_head(&sunmouse.proc_list);
612 spin_lock_init(&sunmouse.lock);
613 sunmouse.byte = 69;
614}
615