Import 2.1.118
[davej-history.git] / drivers / char / pc110pad.c
blobea6d706cb9c93ba86e8e4ccfb346388d668a3ee8
1 /*
2 * Linux driver for the PC110 pad
4 * The pad provides triples of data. The first byte has
5 * 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
6 * The second byte is bits 0-6 X
7 * The third is bits 0-6 Y
9 * This is read internally and used to synthesize a stream of
10 * triples in the form expected from a PS/2 device.
12 * 0.0 1997-05-16 Alan Cox <alan@cymru.net> - Pad reader
13 * 0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
14 * 0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
15 * 0.3 1997-06-27 Alan Cox <alan@cymru.net> - 2.1 commit
16 * 0.4 1997-11-09 Alan Cox <alan@cymru.net> - Single Unix VFS API changes
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/busmouse.h>
22 #include <linux/signal.h>
23 #include <linux/errno.h>
24 #include <linux/mm.h>
25 #include <linux/miscdevice.h>
26 #include <linux/ptrace.h>
27 #include <linux/poll.h>
28 #include <linux/ioport.h>
29 #include <linux/interrupt.h>
31 #include <asm/signal.h>
32 #include <asm/io.h>
33 #include <asm/irq.h>
34 #include <asm/uaccess.h>
36 #include "pc110pad.h"
39 static struct pc110pad_params default_params = {
40 PC110PAD_PS2, /* read mode */
41 50 MS, /* bounce interval */
42 200 MS, /* tap interval */
43 10, /* IRQ */
44 0x15E0, /* I/O port */
48 static struct pc110pad_params current_params;
51 /* driver/filesystem interface management */
52 static struct wait_queue *queue;
53 static struct fasync_struct *asyncptr;
54 static int active=0; /* number of concurrent open()s */
58 * Utility to reset a timer to go off some time in the future.
61 static void set_timer_callback(struct timer_list *timer, int ticks)
63 del_timer(timer);
64 timer->expires = jiffies+ticks;
65 add_timer(timer);
70 * Take care of letting any waiting processes know that
71 * now would be a good time to do a read(). Called
72 * whenever a state transition occurs, real or synthetic.
75 static void wake_readers(void)
77 wake_up_interruptible(&queue);
78 if(asyncptr)
79 kill_fasync(asyncptr, SIGIO);
83 /*****************************************************************************/
85 * Deal with the messy business of synthesizing button tap and drag
86 * events.
88 * Exports:
89 * notify_pad_up_down()
90 * Must be called whenever debounced pad up/down state changes.
91 * button_pending
92 * Flag is set whenever read_button() has new values
93 * to return.
94 * read_button()
95 * Obtains the current synthetic mouse button state.
99 * These keep track of up/down transitions needed to generate the
100 * synthetic mouse button events. While recent_transition is set,
101 * up/down events cause transition_count to increment. tap_timer
102 * turns off the recent_transition flag and may cause some synthetic
103 * up/down mouse events to be created by incrementing synthesize_tap.
106 static int button_pending=0;
107 static int recent_transition=0;
108 static int transition_count=0;
109 static int synthesize_tap=0;
110 static void tap_timeout(unsigned long data);
111 static struct timer_list tap_timer = { NULL, NULL, 0, 0, tap_timeout };
115 * This callback goes off a short time after an up/down transition;
116 * before it goes off, transitions will be considered part of a
117 * single PS/2 event and counted in transition_count. Once the
118 * timeout occurs the recent_transition flag is cleared and
119 * any synthetic mouse up/down events are generated.
122 static void tap_timeout(unsigned long data)
124 if(!recent_transition)
126 printk("pc110pad: tap_timeout but no recent transition!\n");
128 if( transition_count==2 || transition_count==4 || transition_count==6 )
130 synthesize_tap+=transition_count;
131 button_pending = 1;
132 wake_readers();
134 recent_transition=0;
139 * Called by the raw pad read routines when a (debounced) up/down
140 * transition is detected.
143 void notify_pad_up_down(void)
145 if(recent_transition)
147 transition_count++;
149 else
151 transition_count=1;
152 recent_transition=1;
154 set_timer_callback(&tap_timer, current_params.tap_interval);
156 /* changes to transition_count can cause reported button to change */
157 button_pending = 1;
158 wake_readers();
162 static void read_button(int *b)
164 if(synthesize_tap)
166 *b=--synthesize_tap & 1;
168 else
170 *b=(!recent_transition && transition_count==3); /* drag */
172 button_pending=(synthesize_tap>0);
176 /*****************************************************************************/
178 * Read pad absolute co-ordinates and debounced up/down state.
180 * Exports:
181 * pad_irq()
182 * Function to be called whenever the pad signals
183 * that it has new data available.
184 * read_raw_pad()
185 * Returns the most current pad state.
186 * xy_pending
187 * Flag is set whenever read_raw_pad() has new values
188 * to return.
189 * Imports:
190 * wake_readers()
191 * Called when movement occurs.
192 * notify_pad_up_down()
193 * Called when debounced up/down status changes.
197 * These are up/down state and absolute co-ords read directly from pad
200 static int raw_data[3];
201 static int raw_data_count=0;
202 static int raw_x=0, raw_y=0; /* most recent absolute co-ords read */
203 static int raw_down=0; /* raw up/down state */
204 static int debounced_down=0; /* up/down state after debounce processing */
205 static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
206 /* set just after an up/down transition */
207 static int xy_pending=0; /* set if new data have not yet been read */
210 * Timer goes off a short while after an up/down transition and copies
211 * the value of raw_down to debounced_down.
214 static void bounce_timeout(unsigned long data);
215 static struct timer_list bounce_timer = { NULL, NULL, 0, 0, bounce_timeout };
218 static void bounce_timeout(unsigned long data)
221 * No further up/down transitions happened within the
222 * bounce period, so treat this as a genuine transition.
224 switch(bounce)
226 case NO_BOUNCE:
229 * Strange; the timer callback should only go off if
230 * we were expecting to do bounce processing!
232 printk("pc110pad, bounce_timeout: bounce flag not set!\n");
233 break;
235 case JUST_GONE_UP:
238 * The last up we spotted really was an up, so set
239 * debounced state the same as raw state.
241 bounce=NO_BOUNCE;
242 if(debounced_down==raw_down)
244 printk("pc110pad, bounce_timeout: raw already debounced!\n");
246 debounced_down=raw_down;
248 notify_pad_up_down();
249 break;
251 case JUST_GONE_DOWN:
254 * We don't debounce down events, but we still time
255 * out soon after one occurs so we can avoid the (x,y)
256 * skittering that sometimes happens.
258 bounce=NO_BOUNCE;
259 break;
266 * Callback when pad's irq goes off; copies values in to raw_* globals;
267 * initiates debounce processing.
269 static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
272 /* Obtain byte from pad and prime for next byte */
274 int value=inb_p(current_params.io);
275 int handshake=inb_p(current_params.io+2);
276 outb_p(handshake | 1, current_params.io+2);
277 outb_p(handshake &~1, current_params.io+2);
278 inb_p(0x64);
280 raw_data[raw_data_count++]=value;
283 if(raw_data_count==3)
285 int new_down=raw_data[0]&0x01;
286 int new_x=raw_data[1];
287 int new_y=raw_data[2];
288 if(raw_data[0]&0x10) new_x+=128;
289 if(raw_data[0]&0x80) new_x+=256;
290 if(raw_data[0]&0x08) new_y+=128;
292 if( (raw_x!=new_x) || (raw_y!=new_y) )
294 raw_x=new_x;
295 raw_y=new_y;
296 xy_pending=1;
299 if(new_down != raw_down)
301 /* Down state has changed. raw_down always holds
302 * the most recently observed state.
304 raw_down=new_down;
306 /* Forget any earlier bounce processing */
307 if(bounce)
309 del_timer(&bounce_timer);
310 bounce=NO_BOUNCE;
313 if(new_down)
315 if(debounced_down)
317 /* pad gone down, but we were reporting
318 * it down anyway because we suspected
319 * (correctly) that the last up was just
320 * a bounce
323 else
325 bounce=JUST_GONE_DOWN;
326 set_timer_callback(&bounce_timer,
327 current_params.bounce_interval);
328 /* start new stroke/tap */
329 debounced_down=new_down;
330 notify_pad_up_down();
333 else /* just gone up */
335 if(recent_transition)
337 /* early bounces are probably part of
338 * a multi-tap gesture, so process
339 * immediately
341 debounced_down=new_down;
342 notify_pad_up_down();
344 else
346 /* don't trust it yet */
347 bounce=JUST_GONE_UP;
348 set_timer_callback(&bounce_timer,
349 current_params.bounce_interval);
353 wake_readers();
354 raw_data_count=0;
359 static void read_raw_pad(int *down, int *debounced, int *x, int *y)
361 disable_irq(current_params.irq);
363 *down=raw_down;
364 *debounced=debounced_down;
365 *x=raw_x;
366 *y=raw_y;
367 xy_pending = 0;
369 enable_irq(current_params.irq);
372 /*****************************************************************************/
374 * Filesystem interface
378 * Read returns byte triples, so we need to keep track of
379 * how much of a triple has been read. This is shared across
380 * all processes which have this device open---not that anything
381 * will make much sense in that case.
383 static int read_bytes[3];
384 static int read_byte_count=0;
388 static void sample_raw(int d[3])
390 d[0]=raw_data[0];
391 d[1]=raw_data[1];
392 d[2]=raw_data[2];
396 static void sample_rare(int d[3])
398 int thisd, thisdd, thisx, thisy;
400 read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
402 d[0]=(thisd?0x80:0)
403 | (thisx/256)<<4
404 | (thisdd?0x08:0)
405 | (thisy/256)
407 d[1]=thisx%256;
408 d[2]=thisy%256;
412 static void sample_debug(int d[3])
414 int thisd, thisdd, thisx, thisy;
415 int b;
416 cli();
417 read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
418 d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
419 d[1]=(recent_transition?0x80:0)+transition_count;
420 read_button(&b);
421 d[2]=(synthesize_tap<<4) | (b?0x01:0);
422 sti();
426 static void sample_ps2(int d[3])
428 static int lastx, lasty, lastd;
430 int thisd, thisdd, thisx, thisy;
431 int dx, dy, b;
434 * Obtain the current mouse parameters and limit as appropriate for
435 * the return data format. Interrupts are only disabled while
436 * obtaining the parameters, NOT during the puts_fs_byte() calls,
437 * so paging in put_user() does not affect mouse tracking.
439 read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
440 read_button(&b);
442 /* Now compare with previous readings. Note that we use the
443 * raw down flag rather than the debounced one.
445 if( (thisd && !lastd) /* new stroke */
446 || (bounce!=NO_BOUNCE) )
448 dx=0;
449 dy=0;
451 else
453 dx = (thisx-lastx);
454 dy = -(thisy-lasty);
456 lastx=thisx;
457 lasty=thisy;
458 lastd=thisd;
461 d[0]= ((dy<0)?0x20:0)
462 | ((dx<0)?0x10:0)
463 | 0x08
464 | (b? 0x01:0x00)
467 d[0]= ((dy<0)?0x20:0)
468 | ((dx<0)?0x10:0)
469 | (b? 0x00:0x08)
471 d[1]=dx;
472 d[2]=dy;
477 static int fasync_pad(int fd, struct file *filp, int on)
479 int retval;
481 retval = fasync_helper(fd, filp, on, &asyncptr);
482 if (retval < 0)
483 return retval;
484 return 0;
489 * close access to the pad
491 static int close_pad(struct inode * inode, struct file * file)
493 fasync_pad(-1, file, 0);
494 if (--active)
495 return 0;
496 outb(0x30, current_params.io+2); /* switch off digitiser */
497 MOD_DEC_USE_COUNT;
498 return 0;
503 * open access to the pad
505 static int open_pad(struct inode * inode, struct file * file)
507 if (active++)
508 return 0;
509 MOD_INC_USE_COUNT;
511 cli();
512 outb(0x30, current_params.io+2); /* switch off digitiser */
513 pad_irq(0,0,0); /* read to flush any pending bytes */
514 pad_irq(0,0,0); /* read to flush any pending bytes */
515 pad_irq(0,0,0); /* read to flush any pending bytes */
516 outb(0x38, current_params.io+2); /* switch on digitiser */
517 current_params = default_params;
518 raw_data_count=0; /* re-sync input byte counter */
519 read_byte_count=0; /* re-sync output byte counter */
520 button_pending=0;
521 recent_transition=0;
522 transition_count=0;
523 synthesize_tap=0;
524 del_timer(&bounce_timer);
525 del_timer(&tap_timer);
526 sti();
528 return 0;
533 * writes are disallowed
535 static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos)
537 return -EINVAL;
541 void new_sample(int d[3])
543 switch(current_params.mode)
545 case PC110PAD_RAW: sample_raw(d); break;
546 case PC110PAD_RARE: sample_rare(d); break;
547 case PC110PAD_DEBUG: sample_debug(d); break;
548 case PC110PAD_PS2: sample_ps2(d); break;
554 * Read pad data. Currently never blocks.
556 static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos)
558 int r;
560 for(r=0; r<count; r++)
562 if(!read_byte_count)
563 new_sample(read_bytes);
564 if(put_user(read_bytes[read_byte_count], buffer+r))
565 return -EFAULT;
566 read_byte_count = (read_byte_count+1)%3;
568 return r;
573 * select for pad input
576 static unsigned int pad_poll(struct file *file, poll_table * wait)
578 poll_wait(file, &queue, wait);
579 if(button_pending || xy_pending)
580 return POLLIN | POLLRDNORM;
581 return 0;
585 static int pad_ioctl(struct inode *inode, struct file * file,
586 unsigned int cmd, unsigned long arg)
588 struct pc110pad_params new;
590 if (!inode)
591 return -EINVAL;
593 switch (cmd) {
594 case PC110PADIOCGETP:
595 new = current_params;
596 if(copy_to_user((void *)arg, &new, sizeof(new)))
597 return -EFAULT;
598 return 0;
600 case PC110PADIOCSETP:
601 if(copy_from_user(&new, (void *)arg, sizeof(new)))
602 return -EFAULT;
604 if( (new.mode<PC110PAD_RAW)
605 || (new.mode>PC110PAD_PS2)
606 || (new.bounce_interval<0)
607 || (new.tap_interval<0)
609 return -EINVAL;
611 current_params.mode = new.mode;
612 current_params.bounce_interval = new.bounce_interval;
613 current_params.tap_interval = new.tap_interval;
614 return 0;
616 return -ENOIOCTLCMD;
620 static struct file_operations pad_fops = {
621 NULL, /* pad_seek */
622 read_pad,
623 write_pad,
624 NULL, /* pad_readdir */
625 pad_poll,
626 pad_ioctl,
627 NULL, /* pad_mmap */
628 open_pad,
629 NULL, /* flush */
630 close_pad,
631 NULL, /* fsync */
632 fasync_pad,
633 NULL, /* check_media_change */
634 NULL, /* revalidate */
635 NULL /* lock */
639 static struct miscdevice pc110_pad = {
640 PC110PAD_MINOR, "pc110 pad", &pad_fops
644 int pc110pad_init(void)
646 current_params = default_params;
648 if(request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0))
650 printk("pc110pad: Unable to get IRQ.\n");
651 return -EBUSY;
653 if(check_region(current_params.io, 4))
655 printk("pc110pad: I/O area in use.\n");
656 free_irq(current_params.irq,0);
657 return -EBUSY;
659 request_region(current_params.io, 4, "pc110pad");
660 printk("PC110 digitizer pad at 0x%X, irq %d.\n",
661 current_params.io,current_params.irq);
662 misc_register(&pc110_pad);
663 outb(0x30, current_params.io+2); /* switch off digitiser */
665 return 0;
668 #ifdef MODULE
670 static void pc110pad_unload(void)
672 outb(0x30, current_params.io+2); /* switch off digitiser */
673 if(current_params.irq)
674 free_irq(current_params.irq, 0);
675 current_params.irq=0;
676 release_region(current_params.io, 4);
677 misc_deregister(&pc110_pad);
682 int init_module(void)
684 return pc110pad_init();
687 void cleanup_module(void)
689 pc110pad_unload();
691 #endif