MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / char / keypad.c
blob2fe98dafd92de6797965d0703ef9366734b658e5
1 /*
2 * This is IVTC ODM project to use Moxa CPU for keypad device driver.
3 * It is from misc interface. So the device node major number is 10.
4 * The device node minor number is following:
5 * keypad: 103
6 *
7 * There devices are mapping system memory is following:
8 * keypad: 0x04004000 write for out, read for in
10 * History:
11 * Date Aurhor Comment
12 * 12-05-2005 Victor Yu. Create it.
14 #include <linux/config.h>
15 #include <asm/arch/moxa.h>
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/types.h>
19 #include <linux/miscdevice.h>
20 #include <linux/fcntl.h>
21 #include <linux/init.h>
22 #include <linux/poll.h>
23 #include <linux/proc_fs.h>
24 #include <linux/spinlock.h>
25 #include <linux/delay.h>
26 #include <linux/rtc.h>
27 #include <linux/timer.h>
28 #include <linux/ioport.h>
30 #include <asm/io.h>
31 #include <asm/uaccess.h>
32 #include <asm/system.h>
34 #define KEYPAD_OUT_ADDR 0x84008000
35 #define KEYPAD_IN_ADDR 0x84008000
36 #define KEYPAD_RAW_NO 4
37 #define KEYPAD_COL_NO 6
39 #define MOXA_KEYPAD_MINOR 103
41 static spinlock_t keypad_lock= SPIN_LOCK_UNLOCKED;
44 // keypad file operation function call
46 #define IOCTL_KEYPAD_HAS_PRESS 1
47 #define IOCTL_KEYPAD_GET_KEY 2
48 #define IOCTL_KEYPAD_PRESS_TWICE 3
50 #define KEYPAD_BUFFER_LENGTH 32
51 #define KEYPAD_BUFFER_MASK (KEYPAD_BUFFER_LENGTH-1)
52 #define KEYPAD_POLL_TIME (HZ/5)
54 static int keypad_wptr=0, keypad_rptr=0;
55 static unsigned int keypad_buffer[KEYPAD_BUFFER_LENGTH];
56 static unsigned int keypadold;
57 static struct timer_list keypadtimer;
58 static int keypadtimer_on=0;
59 static int keypad_opened=0;
61 static unsigned int keypad_scan(void)
63 unsigned int ret=0, v;
64 int raw, col;
67 for ( col=0; col<KEYPAD_COL_NO;) {
68 outw((1<<col), KEYPAD_OUT_ADDR);
69 col++ ;
70 v = inw(KEYPAD_IN_ADDR) & 0x0f;
71 ret |= (v << (col*4));
73 return ret;
76 static int press_twice = 0 ;
77 static void keypad_poll(unsigned long ingore)
79 unsigned int v, v1;
81 spin_lock(&keypad_lock);
82 del_timer(&keypadtimer);
83 keypadtimer_on = 0;
84 if ( keypad_opened <= 0 ) {
85 spin_unlock(&keypad_lock);
86 return;
88 v = keypad_scan();
89 v1 = v ^ keypadold;
90 keypadold = v;
91 if ( v && v1 && (keypad_wptr+1) != keypad_rptr ) {
92 int index ;
93 unsigned char bits = 0 ;
95 for(index=0;index<24;index++)
97 if(v&(1<<index))
98 bits++ ;
99 if(bits>1)
101 press_twice = 1 ;
102 break ;
105 keypad_buffer[keypad_wptr++] = v;
106 keypad_wptr &= KEYPAD_BUFFER_MASK;
110 keypadtimer.function = keypad_poll;
111 keypadtimer.expires = jiffies + KEYPAD_POLL_TIME;
112 keypadtimer_on = 1;
113 add_timer(&keypadtimer);
114 spin_unlock(&keypad_lock);
117 static int keypad_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
119 int v;
121 switch ( cmd ) {
122 case IOCTL_KEYPAD_PRESS_TWICE :
123 if ( copy_to_user((void *)arg, &press_twice, sizeof(int)) )
124 return -EFAULT;
125 break ;
126 case IOCTL_KEYPAD_HAS_PRESS :
127 spin_lock(&keypad_lock);
128 #if 1
129 v = (keypad_wptr - keypad_rptr) & KEYPAD_BUFFER_MASK;
130 #else
131 if ( keypad_wptr == keypad_rptr )
132 v = 0;
133 else
134 v = 1;
135 #endif
136 spin_unlock(&keypad_lock);
137 if ( copy_to_user((void *)arg, &v, sizeof(int)) )
138 return -EFAULT;
139 break;
140 case IOCTL_KEYPAD_GET_KEY :
141 spin_lock(&keypad_lock);
142 if ( keypad_wptr == keypad_rptr )
143 v = -1;
144 else {
145 v = keypad_buffer[keypad_rptr++];
146 keypad_rptr &= KEYPAD_BUFFER_MASK;
148 spin_unlock(&keypad_lock);
149 if ( copy_to_user((void *)arg, &v, sizeof(int)) )
150 return -EFAULT;
151 press_twice = 0 ;
152 break;
153 default:
154 return -EINVAL;
156 return 0;
159 static int keypad_open(struct inode *inode, struct file *file)
161 if ( MINOR(inode->i_rdev) != MOXA_KEYPAD_MINOR )
162 return -ENODEV;
163 spin_lock(&keypad_lock);
164 if ( keypad_opened == 0 ) {
165 keypad_wptr = keypad_rptr = 0;
166 keypadold = keypad_scan();
167 keypadtimer.function = keypad_poll;
168 keypadtimer.expires = jiffies + KEYPAD_POLL_TIME;
169 keypadtimer_on = 1;
170 add_timer(&keypadtimer);
172 keypad_opened++;
173 spin_unlock(&keypad_lock);
174 return 0;
177 static int keypad_release(struct inode *inode, struct file *file)
179 spin_lock(&keypad_lock);
180 if ( keypad_opened > 0 ) {
181 keypad_opened--;
182 if ( keypad_opened == 0 ) {
183 if ( keypadtimer_on ) {
184 del_timer(&keypadtimer);
185 keypadtimer_on = 0;
187 keypad_wptr = keypad_rptr = 0;
190 spin_unlock(&keypad_lock);
191 return 0;
194 static struct file_operations keypad_fops = {
195 owner:THIS_MODULE,
196 llseek:NULL,
197 ioctl:keypad_ioctl,
198 open:keypad_open,
199 release:keypad_release,
201 static struct miscdevice keypad_dev = {
202 MOXA_KEYPAD_MINOR,
203 "keypad",
204 &keypad_fops
207 static void __exit ivtc_keypad_exit(void)
209 spin_lock(&keypad_lock);
210 if ( keypadtimer_on ) {
211 del_timer(&keypadtimer);
212 keypadtimer_on = 0;
214 spin_unlock(&keypad_lock);
215 misc_deregister(&keypad_dev);
218 static int __init ivtc_keypad_init(void)
220 printk("Moxa CPU misc: Register Keypad misc ver1.0 ");
221 if ( misc_register(&keypad_dev) ) {
222 printk("fail !\n");
223 return -ENOMEM;
225 init_timer(&keypadtimer);
226 printk("OK.\n");
228 return 0;
231 module_init(ivtc_keypad_init);
232 module_exit(ivtc_keypad_exit);
234 MODULE_AUTHOR("Victor Yu");
235 MODULE_LICENSE("GPL");