#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/cdev.h>#include <linux/slab.h>#include <linux/fs.h>#include <linux/device.h>#include <linux/irq.h>#include <asm/uaccess.h>#include <linux/interrupt.h>#include <plat/gpio-cfg.h>#include <plat/gpio-fns.h>#include <mach/gpio-nrs.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/poll.h>#include <asm/signal.h>static dev_t dev;static struct cdev *my_cdev = NULL;static struct class *cdev_class = NULL;static struct device *cdev_class_device = NULL;static unsigned char key_val;static volatile int condition = 0;static DECLARE_WAIT_QUEUE_HEAD(wq);static struct fasync_struct *button_async_queue;struct key_desc{ int pin; char value;};static struct key_desc my_desc[4] = { { S3C2410_GPF(1), 0x01 }, { S3C2410_GPF(4), 0x02 }, { S3C2410_GPF(2), 0x03 }, { S3C2410_GPF(0), 0x04 },};MODULE_LICENSE("GPL");static irqreturn_t key_irq(int irq, void *dev_id){ struct key_desc *tmp = (struct key_desc *)dev_id; if(!s3c2410_gpio_getpin(tmp->pin)) { key_val = tmp->value; } else { key_val = 0x10|tmp->value; } condition = 1; wake_up_interruptible(&wq); kill_fasync(&button_async_queue, SIGIO, POLL_IN); return IRQ_HANDLED;}static int key_open(struct inode *inode, struct file *file){ request_irq(IRQ_EINT1 , key_irq, IRQ_TYPE_EDGE_BOTH, "K1", &my_desc[0]); request_irq(IRQ_EINT4 , key_irq, IRQ_TYPE_EDGE_BOTH, "K2", &my_desc[1]); request_irq(IRQ_EINT2 , key_irq, IRQ_TYPE_EDGE_BOTH, "K3", &my_desc[2]); request_irq(IRQ_EINT0 , key_irq, IRQ_TYPE_EDGE_BOTH, "K4", &my_desc[3]); return 0;}static ssize_t key_close(struct inode *inode, struct file *file){ free_irq(IRQ_EINT1, &my_desc[0]); free_irq(IRQ_EINT4, &my_desc[1]); free_irq(IRQ_EINT2, &my_desc[2]); free_irq(IRQ_EINT0, &my_desc[3]); return 0;}static ssize_t key_read(struct file *file, char __user *buf, size_t count, loff_t *offset){ if(count != 1) { return -EINVAL; } wait_event_interruptible(wq, condition); copy_to_user(buf, &key_val, 1); condition = 0; return 1;}static unsigned key_poll(struct file *file, poll_table *wait){ unsigned int mask = 0; poll_wait(file, &wq, wait); if(condition) mask |= POLLIN|POLLRDNORM; return mask;}static int key_fasync(int fd, struct file *filp, int on){ return fasync_helper(fd, filp, on, &button_async_queue);}static struct file_operations fops = { .owner = THIS_MODULE, .open = key_open, .release= key_close, .read = key_read, .poll = key_poll, .fasync = key_fasync,};static int key_drv_init(void){ int ret = 0; ret = alloc_chrdev_region(&dev, 0, 4, "mykey"); if(ret < 0) { printk("alloc_chrdev_region\n"); } my_cdev = cdev_alloc(); cdev_init(my_cdev, &fops); my_cdev->owner = THIS_MODULE; cdev_add(my_cdev, dev, 4); cdev_class = class_create(THIS_MODULE, "mykey"); cdev_class_device = device_create(cdev_class, NULL, dev, NULL, "keybutton"); return 0;}static void key_drv_exit(void){ device_destroy(cdev_class, dev); class_destroy(cdev_class); cdev_del(my_cdev); kzfree(my_cdev); unregister_chrdev_region(dev, 4); return ;}module_init(key_drv_init);module_exit(key_drv_exit);测试程序:#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <poll.h>#include <signal.h>int fd;void sig_func(int signo){ unsigned char key_val; read(fd, &key_val, 1); printf("key_val is 0x%x\n", key_val);}int main(int argc, char *argv[]){ int oflags; fd = open("/dev/keybutton", O_RDWR); signal(SIGIO, sig_func); fcntl(fd, F_SETOWN, getpid()); oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, oflags|FASYNC); while(1) { sleep(1); } return 0;}