Linux 2.3.7pre1
[davej-history.git] / drivers / char / pc110pad.c
blob0c00dcfa5be9e7d232dbdede8ced9e9385419e92
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@redhat.com> - 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@redhat.com> - 2.1 commit
16 * 0.4 1997-11-09 Alan Cox <alan@redhat.com> - Single Unix VFS API changes
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/signal.h>
22 #include <linux/errno.h>
23 #include <linux/mm.h>
24 #include <linux/miscdevice.h>
25 #include <linux/ptrace.h>
26 #include <linux/poll.h>
27 #include <linux/ioport.h>
28 #include <linux/interrupt.h>
30 #include <asm/signal.h>
31 #include <asm/io.h>
32 #include <asm/irq.h>
33 #include <asm/uaccess.h>
35 #include "pc110pad.h"
38 static struct pc110pad_params default_params = {
39 PC110PAD_PS2, /* read mode */
40 50 MS, /* bounce interval */
41 200 MS, /* tap interval */
42 10, /* IRQ */
43 0x15E0, /* I/O port */
47 static struct pc110pad_params current_params;
50 /* driver/filesystem interface management */
51 static wait_queue_head_t queue;
52 static struct fasync_struct *asyncptr;
53 static int active=0; /* number of concurrent open()s */
57 * Utility to reset a timer to go off some time in the future.
60 static void set_timer_callback(struct timer_list *timer, int ticks)
62 del_timer(timer);
63 timer->expires = jiffies+ticks;
64 add_timer(timer);
69 * Take care of letting any waiting processes know that
70 * now would be a good time to do a read(). Called
71 * whenever a state transition occurs, real or synthetic.
74 static void wake_readers(void)
76 wake_up_interruptible(&queue);
77 if(asyncptr)
78 kill_fasync(asyncptr, SIGIO);
82 /*****************************************************************************/
84 * Deal with the messy business of synthesizing button tap and drag
85 * events.
87 * Exports:
88 * notify_pad_up_down()
89 * Must be called whenever debounced pad up/down state changes.
90 * button_pending
91 * Flag is set whenever read_button() has new values
92 * to return.
93 * read_button()
94 * Obtains the current synthetic mouse button state.
98 * These keep track of up/down transitions needed to generate the
99 * synthetic mouse button events. While recent_transition is set,
100 * up/down events cause transition_count to increment. tap_timer
101 * turns off the recent_transition flag and may cause some synthetic
102 * up/down mouse events to be created by incrementing synthesize_tap.
105 static int button_pending=0;
106 static int recent_transition=0;
107 static int transition_count=0;
108 static int synthesize_tap=0;
109 static void tap_timeout(unsigned long data);
110 static struct timer_list tap_timer = { NULL, NULL, 0, 0, tap_timeout };
114 * This callback goes off a short time after an up/down transition;
115 * before it goes off, transitions will be considered part of a
116 * single PS/2 event and counted in transition_count. Once the
117 * timeout occurs the recent_transition flag is cleared and
118 * any synthetic mouse up/down events are generated.
121 static void tap_timeout(unsigned long data)
123 if(!recent_transition)
125 printk("pc110pad: tap_timeout but no recent transition!\n");
127 if( transition_count==2 || transition_count==4 || transition_count==6 )
129 synthesize_tap+=transition_count;
130 button_pending = 1;
131 wake_readers();
133 recent_transition=0;
138 * Called by the raw pad read routines when a (debounced) up/down
139 * transition is detected.
142 void notify_pad_up_down(void)
144 if(recent_transition)
146 transition_count++;
148 else
150 transition_count=1;
151 recent_transition=1;
153 set_timer_callback(&tap_timer, current_params.tap_interval);
155 /* changes to transition_count can cause reported button to change */
156 button_pending = 1;
157 wake_readers();
161 static void read_button(int *b)
163 if(synthesize_tap)
165 *b=--synthesize_tap & 1;
167 else
169 *b=(!recent_transition && transition_count==3); /* drag */
171 button_pending=(synthesize_tap>0);
175 /*****************************************************************************/
177 * Read pad absolute co-ordinates and debounced up/down state.
179 * Exports:
180 * pad_irq()
181 * Function to be called whenever the pad signals
182 * that it has new data available.
183 * read_raw_pad()
184 * Returns the most current pad state.
185 * xy_pending
186 * Flag is set whenever read_raw_pad() has new values
187 * to return.
188 * Imports:
189 * wake_readers()
190 * Called when movement occurs.
191 * notify_pad_up_down()
192 * Called when debounced up/down status changes.
196 * These are up/down state and absolute co-ords read directly from pad
199 static int raw_data[3];
200 static int raw_data_count=0;
201 static int raw_x=0, raw_y=0; /* most recent absolute co-ords read */
202 static int raw_down=0; /* raw up/down state */
203 static int debounced_down=0; /* up/down state after debounce processing */
204 static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
205 /* set just after an up/down transition */
206 static int xy_pending=0; /* set if new data have not yet been read */
209 * Timer goes off a short while after an up/down transition and copies
210 * the value of raw_down to debounced_down.
213 static void bounce_timeout(unsigned long data);
214 static struct timer_list bounce_timer = { NULL, NULL, 0, 0, bounce_timeout };
217 static void bounce_timeout(unsigned long data)
220 * No further up/down transitions happened within the
221 * bounce period, so treat this as a genuine transition.
223 switch(bounce)
225 case NO_BOUNCE:
228 * Strange; the timer callback should only go off if
229 * we were expecting to do bounce processing!
231 printk("pc110pad, bounce_timeout: bounce flag not set!\n");
232 break;
234 case JUST_GONE_UP:
237 * The last up we spotted really was an up, so set
238 * debounced state the same as raw state.
240 bounce=NO_BOUNCE;
241 if(debounced_down==raw_down)
243 printk("pc110pad, bounce_timeout: raw already debounced!\n");
245 debounced_down=raw_down;
247 notify_pad_up_down();
248 break;
250 case JUST_GONE_DOWN:
253 * We don't debounce down events, but we still time
254 * out soon after one occurs so we can avoid the (x,y)
255 * skittering that sometimes happens.
257 bounce=NO_BOUNCE;
258 break;
265 * Callback when pad's irq goes off; copies values in to raw_* globals;
266 * initiates debounce processing.
268 static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
271 /* Obtain byte from pad and prime for next byte */
273 int value=inb_p(current_params.io);
274 int handshake=inb_p(current_params.io+2);
275 outb_p(handshake | 1, current_params.io+2);
276 outb_p(handshake &~1, current_params.io+2);
277 inb_p(0x64);
279 raw_data[raw_data_count++]=value;
282 if(raw_data_count==3)
284 int new_down=raw_data[0]&0x01;
285 int new_x=raw_data[1];
286 int new_y=raw_data[2];
287 if(raw_data[0]&0x10) new_x+=128;
288 if(raw_data[0]&0x80) new_x+=256;
289 if(raw_data[0]&0x08) new_y+=128;
291 if( (raw_x!=new_x) || (raw_y!=new_y) )
293 raw_x=new_x;
294 raw_y=new_y;
295 xy_pending=1;
298 if(new_down != raw_down)
300 /* Down state has changed. raw_down always holds
301 * the most recently observed state.
303 raw_down=new_down;
305 /* Forget any earlier bounce processing */
306 if(bounce)
308 del_timer(&bounce_timer);
309 bounce=NO_BOUNCE;
312 if(new_down)
314 if(debounced_down)
316 /* pad gone down, but we were reporting
317 * it down anyway because we suspected
318 * (correctly) that the last up was just
319 * a bounce
322 else
324 bounce=JUST_GONE_DOWN;
325 set_timer_callback(&bounce_timer,
326 current_params.bounce_interval);
327 /* start new stroke/tap */
328 debounced_down=new_down;
329 notify_pad_up_down();
332 else /* just gone up */
334 if(recent_transition)
336 /* early bounces are probably part of
337 * a multi-tap gesture, so process
338 * immediately
340 debounced_down=new_down;
341 notify_pad_up_down();
343 else
345 /* don't trust it yet */
346 bounce=JUST_GONE_UP;
347 set_timer_callback(&bounce_timer,
348 current_params.bounce_interval);
352 wake_readers();
353 raw_data_count=0;
358 static void read_raw_pad(int *down, int *debounced, int *x, int *y)
360 disable_irq(current_params.irq);
362 *down=raw_down;
363 *debounced=debounced_down;
364 *x=raw_x;
365 *y=raw_y;
366 xy_pending = 0;
368 enable_irq(current_params.irq);
371 /*****************************************************************************/
373 * Filesystem interface
377 * Read returns byte triples, so we need to keep track of
378 * how much of a triple has been read. This is shared across
379 * all processes which have this device open---not that anything
380 * will make much sense in that case.
382 static int read_bytes[3];
383 static int read_byte_count=0;
387 static void sample_raw(int d[3])
389 d[0]=raw_data[0];
390 d[1]=raw_data[1];
391 d[2]=raw_data[2];
395 static void sample_rare(int d[3])
397 int thisd, thisdd, thisx, thisy;
399 read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
401 d[0]=(thisd?0x80:0)
402 | (thisx/256)<<4
403 | (thisdd?0x08:0)
404 | (thisy/256)
406 d[1]=thisx%256;
407 d[2]=thisy%256;
411 static void sample_debug(int d[3])
413 int thisd, thisdd, thisx, thisy;
414 int b;
415 cli();
416 read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
417 d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
418 d[1]=(recent_transition?0x80:0)+transition_count;
419 read_button(&b);
420 d[2]=(synthesize_tap<<4) | (b?0x01:0);
421 sti();
425 static void sample_ps2(int d[3])
427 static int lastx, lasty, lastd;
429 int thisd, thisdd, thisx, thisy;
430 int dx, dy, b;
433 * Obtain the current mouse parameters and limit as appropriate for
434 * the return data format. Interrupts are only disabled while
435 * obtaining the parameters, NOT during the puts_fs_byte() calls,
436 * so paging in put_user() does not affect mouse tracking.
438 read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
439 read_button(&b);
441 /* Now compare with previous readings. Note that we use the
442 * raw down flag rather than the debounced one.
444 if( (thisd && !lastd) /* new stroke */
445 || (bounce!=NO_BOUNCE) )
447 dx=0;
448 dy=0;
450 else
452 dx = (thisx-lastx);
453 dy = -(thisy-lasty);
455 lastx=thisx;
456 lasty=thisy;
457 lastd=thisd;
460 d[0]= ((dy<0)?0x20:0)
461 | ((dx<0)?0x10:0)
462 | 0x08
463 | (b? 0x01:0x00)
466 d[0]= ((dy<0)?0x20:0)
467 | ((dx<0)?0x10:0)
468 | (b? 0x00:0x08)
470 d[1]=dx;
471 d[2]=dy;
476 static int fasync_pad(int fd, struct file *filp, int on)
478 int retval;
480 retval = fasync_helper(fd, filp, on, &asyncptr);
481 if (retval < 0)
482 return retval;
483 return 0;
488 * close access to the pad
490 static int close_pad(struct inode * inode, struct file * file)
492 fasync_pad(-1, file, 0);
493 if (--active)
494 return 0;
495 outb(0x30, current_params.io+2); /* switch off digitiser */
496 MOD_DEC_USE_COUNT;
497 return 0;
502 * open access to the pad
504 static int open_pad(struct inode * inode, struct file * file)
506 if (active++)
507 return 0;
508 MOD_INC_USE_COUNT;
510 cli();
511 outb(0x30, current_params.io+2); /* switch off digitiser */
512 pad_irq(0,0,0); /* read to flush any pending bytes */
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 outb(0x38, current_params.io+2); /* switch on digitiser */
516 current_params = default_params;
517 raw_data_count=0; /* re-sync input byte counter */
518 read_byte_count=0; /* re-sync output byte counter */
519 button_pending=0;
520 recent_transition=0;
521 transition_count=0;
522 synthesize_tap=0;
523 del_timer(&bounce_timer);
524 del_timer(&tap_timer);
525 sti();
527 return 0;
532 * writes are disallowed
534 static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos)
536 return -EINVAL;
540 void new_sample(int d[3])
542 switch(current_params.mode)
544 case PC110PAD_RAW: sample_raw(d); break;
545 case PC110PAD_RARE: sample_rare(d); break;
546 case PC110PAD_DEBUG: sample_debug(d); break;
547 case PC110PAD_PS2: sample_ps2(d); break;
553 * Read pad data. Currently never blocks.
555 static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos)
557 int r;
559 for(r=0; r<count; r++)
561 if(!read_byte_count)
562 new_sample(read_bytes);
563 if(put_user(read_bytes[read_byte_count], buffer+r))
564 return -EFAULT;
565 read_byte_count = (read_byte_count+1)%3;
567 return r;
572 * select for pad input
575 static unsigned int pad_poll(struct file *file, poll_table * wait)
577 poll_wait(file, &queue, wait);
578 if(button_pending || xy_pending)
579 return POLLIN | POLLRDNORM;
580 return 0;
584 static int pad_ioctl(struct inode *inode, struct file * file,
585 unsigned int cmd, unsigned long arg)
587 struct pc110pad_params new;
589 if (!inode)
590 return -EINVAL;
592 switch (cmd) {
593 case PC110PADIOCGETP:
594 new = current_params;
595 if(copy_to_user((void *)arg, &new, sizeof(new)))
596 return -EFAULT;
597 return 0;
599 case PC110PADIOCSETP:
600 if(copy_from_user(&new, (void *)arg, sizeof(new)))
601 return -EFAULT;
603 if( (new.mode<PC110PAD_RAW)
604 || (new.mode>PC110PAD_PS2)
605 || (new.bounce_interval<0)
606 || (new.tap_interval<0)
608 return -EINVAL;
610 current_params.mode = new.mode;
611 current_params.bounce_interval = new.bounce_interval;
612 current_params.tap_interval = new.tap_interval;
613 return 0;
615 return -ENOIOCTLCMD;
619 static struct file_operations pad_fops = {
620 NULL, /* pad_seek */
621 read_pad,
622 write_pad,
623 NULL, /* pad_readdir */
624 pad_poll,
625 pad_ioctl,
626 NULL, /* pad_mmap */
627 open_pad,
628 NULL, /* flush */
629 close_pad,
630 NULL, /* fsync */
631 fasync_pad,
632 NULL, /* check_media_change */
633 NULL, /* revalidate */
634 NULL /* lock */
638 static struct miscdevice pc110_pad = {
639 PC110PAD_MINOR, "pc110 pad", &pad_fops
643 int pc110pad_init(void)
645 current_params = default_params;
647 if(request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0))
649 printk("pc110pad: Unable to get IRQ.\n");
650 return -EBUSY;
652 if(check_region(current_params.io, 4))
654 printk("pc110pad: I/O area in use.\n");
655 free_irq(current_params.irq,0);
656 return -EBUSY;
658 request_region(current_params.io, 4, "pc110pad");
659 init_waitqueue_head(&queue);
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