内核版本:linux-2.6.32.2
开发板:mini2440
参考韦东山的视频,编写代码,对于其源码稍有改动,以适合linux-2.6.32.2版本。代码如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <mach/io.h> #include <asm/io.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/device.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/irq.h> #define DEVICE_NAME "key_1" static struct class *leds_class; //static struct device *leds_class_devs; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */ static volatile int ev_press = 0; struct pin_desc{ unsigned int pin; unsigned int key_val; }; /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */ /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */ static unsigned char key_val; struct pin_desc pins_desc[3] = { {S3C2410_GPG(0), 0x01}, {S3C2410_GPG(3), 0x02}, {S3C2410_GPG(5), 0x03}, }; /* * 确定按键值 */ static unsigned char key_val; static irqreturn_t button_irq(int irq, void *dev_id) { struct pin_desc * pindesc = (struct pin_desc *)dev_id; unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); if (pinval) { /* 松开 */ key_val = 0x80 | pindesc->key_val; } else { /* 按下 */ key_val = pindesc->key_val; } ev_press = 1; /* 表示中断发生了 */ wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ return IRQ_RETVAL(IRQ_HANDLED); } static int mini2440_key_open(struct inode *inode, struct file *file) { /* * 配置中断。 */ request_irq(IRQ_EINT8, button_irq,IRQ_TYPE_EDGE_BOTH,"s1",&pins_desc[0]); request_irq(IRQ_EINT11,button_irq,IRQ_TYPE_EDGE_BOTH,"s2",&pins_desc[1]); request_irq(IRQ_EINT13,button_irq,IRQ_TYPE_EDGE_BOTH,"s3",&pins_desc[2]); return 0; } static ssize_t mini2440_key_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { if (size != 1) return -EINVAL; /* 如果没有按键动作, 休眠 */ wait_event_interruptible(button_waitq, ev_press); /* 如果有按键动作, 返回键值 */ copy_to_user(buf, &key_val, 1); ev_press = 0; return 1; } int mini2440_key_close(struct inode *inode, struct file *file) { free_irq(IRQ_EINT8, &pins_desc[0]); free_irq(IRQ_EINT11,&pins_desc[1]); free_irq(IRQ_EINT13,&pins_desc[2]); return 0; } static struct file_operations mini2440_key_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = mini2440_key_open, .read = mini2440_key_read, .release = mini2440_key_close, }; /* * 执行insmod命令时就会调用这个函数 */ int ret; static int mini2440_key_init(void) { ret = register_chrdev(0, DEVICE_NAME, &mini2440_key_fops); leds_class = class_create(THIS_MODULE,DEVICE_NAME); device_create(leds_class, NULL, MKDEV(ret, 0), NULL, "button"); /* /dev/button */ return 0; } /* * 执行rmmod命令时就会调用这个函数 */ static void mini2440_key_exit(void) { /* 卸载驱动程序 */ unregister_chrdev(ret, DEVICE_NAME); device_destroy(leds_class,MKDEV(ret, 0)); class_destroy(leds_class); } /* 这两行指定驱动程序的初始化函数和卸载函数 */ module_init(mini2440_key_init); module_exit(mini2440_key_exit); /* 描述驱动程序的一些信息,不是必须的 */ MODULE_LICENSE("GPL");
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> int main(int argc, char **argv) { int fd; unsigned char key_val; fd = open("/dev/button", O_RDWR); if (fd < 0) { printf("can't open!\n"); } while (1) { read(fd, &key_val, 1); printf("key_val = 0x%x\n", key_val); sleep(5); } return 0; }
查看cpu占有率:top
查看进程:ps
查看中断源:cat proc/interrupts
注意:实际测试中,键值返回很慢,有时按下的键值返回不了,暂时还不知道原因,mark下