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)
6 * The characters input can be '1', '2', '4' or '8'
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>
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>
30 #include <asm/uaccess.h>
32 #define BUTTON_MAJOR 62
33 int button_major
= BUTTON_MAJOR
;
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
45 char buf
[BUTTON_BUF_SIZE
];
49 wait_queue_head_t rxq
;
50 struct semaphore mutex
;
54 static void button_handle_event(void *dev_id
)
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;
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
;
77 /* wake up any waiting reader */
78 if (waitqueue_active(&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
;
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
);
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",
115 printk("pio_button: unable to register interrupt %d\n", PIO_BUTTON_IRQ
);
118 outl(-1, &pio
->np_piointerruptmask
);
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
;
134 if (dev
->started
!=1) {
139 /* init buffon info */
143 init_waitqueue_head(&dev
->rxq
);
144 init_MUTEX(&dev
->mutex
);
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
;
161 if (dev
->started
!= 0) {
167 /*disable this interrupts */
168 outl(0, &pio
->np_piointerruptmask
);
169 free_irq(PIO_BUTTON_IRQ
, (void*)(dev
));
176 button_ioctl(struct inode
*inode
, struct file
*filp
,
177 unsigned int command
, unsigned long arg
)
182 static ssize_t
button_read(struct file
*filp
, char *buf
,
183 size_t count
, loff_t
* ppos
)
186 struct button_dev
*dev
= (struct button_dev
*)filp
->private_data
;
190 if (filp
->f_flags
& O_NONBLOCK
)
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))
197 finish_wait(&dev
->rxq
, &wait
);
199 if (signal_pending(current
) && (dev
->count
== 0))
203 if (down_interruptible(&dev
->mutex
))
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
;
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
);
226 mask
|= POLLIN
| POLLRDNORM
; /* readable */
230 static struct file_operations button_fops
= {
233 .release
= button_release
,
234 .ioctl
= button_ioctl
,
236 .owner
= THIS_MODULE
,
240 static int __init
button_init(void)
245 if (!(request_mem_region((unsigned long)PIO_BUTTON_BASE
, PIO_BUTTON_SIZE
, "pio_button")))
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");
255 printk(KERN_NOTICE
"Can't get major %d for PIO buttons", button_major
);
258 i
= cdev_add(&_button_dev
.cdev
, devno
, 1);
260 printk(KERN_NOTICE
"Error %d adding PIO buttons", i
);
264 unregister_chrdev_region(devno
, 1);
266 release_mem_region((unsigned long)PIO_BUTTON_BASE
, PIO_BUTTON_SIZE
);
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");