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 / altera_pio_button.c
blob28f1c0252526473502e96a6fa404044ed3928feb
1 /*
2 * linux/drivers/char/altera_pio_button.c
3 * A simple character driver that takes buttons on Nios Development
4 * Kit as an input device (major 62)
5 *
6 * The characters input can be '1', '2', '4' or '8'
7 *
8 * Copyright (C) 2004 Microtronix Datacom Ltd
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
15 * Written by Wentao Xu <wentao@microtronix.com>
18 #include <linux/init.h>
19 #include <linux/fs.h>
20 #include <linux/devfs_fs_kernel.h>
21 #include <linux/major.h>
22 #include <linux/module.h>
23 #include <linux/capability.h>
24 #include <linux/uio.h>
25 #include <linux/interrupt.h>
26 #include <linux/ioport.h>
27 #include <linux/cdev.h>
28 #include <linux/poll.h>
29 #include <asm/io.h>
30 #include <asm/uaccess.h>
32 #define BUTTON_MAJOR 62
33 int button_major = BUTTON_MAJOR;
34 int button_minor = 0;
36 #define PIO_BUTTON_BASE na_button_pio
37 #define PIO_BUTTON_IRQ na_button_pio_irq
38 #define PIO_BUTTON_SIZE sizeof(np_pio)
40 #define BUTTON_BUF_SIZE 100
41 struct button_dev {
42 int count;
43 int head;
44 int tail;
45 char buf[BUTTON_BUF_SIZE];
47 int started;
48 struct cdev cdev;
49 wait_queue_head_t rxq;
50 struct semaphore mutex;
51 } _button_dev;
54 static void button_handle_event(void *dev_id)
56 static int old = 0;
57 int status, key;
58 struct button_dev * dev=(struct button_dev*)dev_id;
59 np_pio* pio = (np_pio *)(PIO_BUTTON_BASE);
61 outl(0, &pio->np_pioedgecapture);
62 /* read input, check 4 buttons */
63 status = (~inl(&pio->np_piodata)) & 0xF;
64 key = status - old;
65 old = status;
67 if (key > 0) {
68 down(&dev->mutex);
69 /* we simply discard new inputs if buffer overflows */
70 if (dev->count < BUTTON_BUF_SIZE) {
71 dev->buf[dev->tail] = key + '0';
72 dev->tail = (dev->tail+1) % BUTTON_BUF_SIZE;
73 dev->count++;
75 up(&dev->mutex);
77 /* wake up any waiting reader */
78 if (waitqueue_active(&dev->rxq)) {
79 wake_up(&dev->rxq);
83 /* re-enable interrupts */
84 outl(-1, &pio->np_piointerruptmask);
87 static DECLARE_WORK(button_work, button_handle_event, (void*)&_button_dev);
88 static irqreturn_t pio_button_isr(int irq, void *dev_id, struct pt_regs *regs)
90 np_pio* pio = (np_pio *)PIO_BUTTON_BASE;
92 if (!pio)
93 return IRQ_NONE;
96 /* disable interrupt */
97 outl(0, &pio->np_pioedgecapture);
98 outl(0, &pio->np_piointerruptmask);
100 /* activate the bottom half */
101 schedule_work(&button_work);
103 return IRQ_HANDLED;
105 static int button_start(struct button_dev *dev)
107 np_pio *pio=(np_pio *)(PIO_BUTTON_BASE);
109 outl(0, &pio->np_pioedgecapture);
110 outl(0, &pio->np_piodirection);
112 /* register interrupt */
113 if (request_irq(PIO_BUTTON_IRQ, pio_button_isr, SA_INTERRUPT, "pio_button",
114 (void*)(dev))) {
115 printk("pio_button: unable to register interrupt %d\n", PIO_BUTTON_IRQ);
116 return -1;
118 outl(-1, &pio->np_piointerruptmask);
120 return 0;
123 * Open/close .
125 static int button_open(struct inode *inode, struct file *filp)
127 struct button_dev *dev;
129 dev = container_of(inode->i_cdev, struct button_dev, cdev);
130 filp->private_data = dev;
132 preempt_disable();
133 dev->started++;
134 if (dev->started!=1) {
135 preempt_enable();
136 return 0;
139 /* init buffon info */
140 dev->count=0;
141 dev->head=0;
142 dev->tail=0;
143 init_waitqueue_head(&dev->rxq);
144 init_MUTEX(&dev->mutex);
145 /* init buttons */
146 button_start(dev);
147 preempt_enable();
149 return 0;
154 static int button_release(struct inode *inode, struct file *filp)
156 np_pio *pio=(np_pio *)(PIO_BUTTON_BASE);
157 struct button_dev *dev = (struct button_dev*)filp->private_data;
159 preempt_disable();
160 dev->started--;
161 if (dev->started != 0) {
162 preempt_enable();
163 return 0;
165 preempt_enable();
167 /*disable this interrupts */
168 outl(0, &pio->np_piointerruptmask);
169 free_irq(PIO_BUTTON_IRQ, (void*)(dev));
170 return 0;
175 static int
176 button_ioctl(struct inode *inode, struct file *filp,
177 unsigned int command, unsigned long arg)
179 return -EINVAL;
182 static ssize_t button_read(struct file *filp, char *buf,
183 size_t count, loff_t * ppos)
185 int i, total;
186 struct button_dev *dev = (struct button_dev*)filp->private_data;
188 if (dev->count==0) {
189 DEFINE_WAIT(wait);
190 if (filp->f_flags & O_NONBLOCK)
191 return -EAGAIN;
193 while (!signal_pending(current) && (dev->count == 0)) {
194 prepare_to_wait(&dev->rxq, &wait, TASK_INTERRUPTIBLE);
195 if (!signal_pending(current) && (dev->count == 0))
196 schedule();
197 finish_wait(&dev->rxq, &wait);
199 if (signal_pending(current) && (dev->count == 0))
200 return -ERESTARTSYS;
203 if (down_interruptible(&dev->mutex))
204 return -ERESTARTSYS;
206 /* return data */
207 total = (count < dev->count) ? count : dev->count;
208 for (i=0; i < total; i++) {
209 put_user(dev->buf[dev->head], buf+i);
210 dev->head = (dev->head + 1) % BUTTON_BUF_SIZE;
211 dev->count--;
213 up(&dev->mutex);
215 return total;
218 static unsigned int button_poll(struct file *filp, poll_table *wait)
220 struct button_dev *dev = (struct button_dev*)filp->private_data;
221 unsigned int mask = 0;
223 poll_wait(filp, &dev->rxq, wait);
225 if (dev->count > 0)
226 mask |= POLLIN | POLLRDNORM; /* readable */
227 return mask;
230 static struct file_operations button_fops = {
231 .read = button_read,
232 .open = button_open,
233 .release= button_release,
234 .ioctl = button_ioctl,
235 .poll = button_poll,
236 .owner = THIS_MODULE,
240 static int __init button_init(void)
242 int i;
243 dev_t devno;
245 if (!(request_mem_region((unsigned long)PIO_BUTTON_BASE, PIO_BUTTON_SIZE, "pio_button")))
246 return -1;
248 devno = MKDEV(button_major, button_minor);
249 cdev_init(&_button_dev.cdev, &button_fops);
250 _button_dev.cdev.owner = THIS_MODULE;
251 _button_dev.started = 0;
253 i = register_chrdev_region(devno, 1, "pio_button");
254 if (i) {
255 printk(KERN_NOTICE "Can't get major %d for PIO buttons", button_major);
256 goto error1;
258 i = cdev_add(&_button_dev.cdev, devno, 1);
259 if (i) {
260 printk(KERN_NOTICE "Error %d adding PIO buttons", i);
261 goto error2;
263 error2:
264 unregister_chrdev_region(devno, 1);
265 error1:
266 release_mem_region((unsigned long)PIO_BUTTON_BASE, PIO_BUTTON_SIZE);
268 return i;
271 static void __exit button_exit(void)
273 cdev_del(&_button_dev.cdev);
274 unregister_chrdev_region(MKDEV(button_major, button_minor), 1);
275 release_mem_region((unsigned long)PIO_BUTTON_BASE, PIO_BUTTON_SIZE);
278 module_init(button_init);
279 module_exit(button_exit);
280 MODULE_LICENSE("GPL");