Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / drivers / char / scan_keyb.c
1 /*
2  *      $Id: scan_keyb.c,v 1.2 2000/07/04 06:24:42 yaegashi Exp $ 
3  *      Copyright (C) 2000 YAEGASHI Takeshi
4  *      Generic scan keyboard driver
5  */
6
7 #include <linux/spinlock.h>
8 #include <linux/sched.h>
9 #include <linux/interrupt.h>
10 #include <linux/tty.h>
11 #include <linux/mm.h>
12 #include <linux/signal.h>
13 #include <linux/init.h>
14 #include <linux/kbd_ll.h>
15 #include <linux/delay.h>
16 #include <linux/random.h>
17 #include <linux/poll.h>
18 #include <linux/miscdevice.h>
19 #include <linux/slab.h>
20 #include <linux/kbd_kern.h>
21 #include <linux/timer.h>
22
23 #define SCANHZ  (HZ/20)
24
25 struct scan_keyboard {
26         struct scan_keyboard *next;
27         int (*scan)(unsigned char *buffer);
28         const unsigned char *table;
29         unsigned char *s0, *s1;
30         int length;
31 };
32
33 static int scan_jiffies=0;
34 static struct scan_keyboard *keyboards=NULL;
35 struct timer_list scan_timer;
36
37 static void check_kbd(const unsigned char *table,
38                       unsigned char *new, unsigned char *old, int length)
39 {
40         int need_tasklet_schedule=0;
41         unsigned int xor, bit;
42         
43         while(length-->0) {
44                 if((xor=*new^*old)==0) {
45                         table+=8;
46                 }
47                 else {
48                         for(bit=0x01; bit<0x100; bit<<=1) {
49                                 if(xor&bit) {
50                                         handle_scancode(*table, !(*new&bit));
51                                         need_tasklet_schedule=1;
52 #if 0
53                                         printk("0x%x %s\n", *table, (*new&bit)?"released":"pressed");
54 #endif
55                                 }
56                                 table++;
57                         }
58                 }
59                 new++; old++;
60         }
61
62         if(need_tasklet_schedule)
63                 tasklet_schedule(&keyboard_tasklet);
64 }
65
66
67 static void scan_kbd(unsigned long dummy)
68 {
69         struct scan_keyboard *kbd;
70
71         scan_jiffies++;
72
73         for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) {
74                 if(scan_jiffies&1) {
75                         if(!kbd->scan(kbd->s0))
76                                 check_kbd(kbd->table,
77                                           kbd->s0, kbd->s1, kbd->length);
78                         else
79                                 memcpy(kbd->s0, kbd->s1, kbd->length);
80                 }
81                 else {
82                         if(!kbd->scan(kbd->s1))
83                                 check_kbd(kbd->table,
84                                           kbd->s1, kbd->s0, kbd->length);
85                         else
86                                 memcpy(kbd->s1, kbd->s0, kbd->length);
87                 }
88                 
89         }
90
91         init_timer(&scan_timer);
92         scan_timer.expires = jiffies + SCANHZ;
93         scan_timer.data = 0;
94         scan_timer.function = scan_kbd;
95         add_timer(&scan_timer);
96 }
97
98
99 int register_scan_keyboard(int (*scan)(unsigned char *buffer),
100                            const unsigned char *table,
101                            int length)
102 {
103         struct scan_keyboard *kbd;
104
105         kbd = kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL);
106         if (kbd == NULL)
107                 goto error_out;
108
109         kbd->scan=scan;
110         kbd->table=table;
111         kbd->length=length;
112
113         kbd->s0 = kmalloc(length, GFP_KERNEL);
114         if (kbd->s0 == NULL)
115                 goto error_free_kbd;
116
117         kbd->s1 = kmalloc(length, GFP_KERNEL);
118         if (kbd->s1 == NULL)
119                 goto error_free_s0;
120
121         memset(kbd->s0, -1, kbd->length);
122         memset(kbd->s1, -1, kbd->length);
123         
124         kbd->next=keyboards;
125         keyboards=kbd;
126
127         return 0;
128
129  error_free_s0:
130         kfree(kbd->s0);
131
132  error_free_kbd:
133         kfree(kbd);
134
135  error_out:
136         return -ENOMEM;
137 }
138                               
139                               
140 void __init scan_kbd_init(void)
141 {
142         init_timer(&scan_timer);
143         scan_timer.expires = jiffies + SCANHZ;
144         scan_timer.data = 0;
145         scan_timer.function = scan_kbd;
146         add_timer(&scan_timer);
147
148         printk(KERN_INFO "Generic scan keyboard driver initialized\n");
149 }