2019独角兽企业重金招聘Python工程师标准>>>
由于OK6410的GPIO按键中断已经被飞凌自带的按键驱动注册,所以运行我们编写的按键驱动前要先去掉飞凌自带的按键驱动,方法:make menuconfig->Device Drivers->input device support->Key Boards->GPIO Buttons 去掉前面的*,即不选该项即可。
key.c
#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/gpio.h>#include <linux/types.h>#include <linux/cdev.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <linux/device.h>#include <linux/poll.h>#include <linux/semaphore.h>#include <linux/timer.h>#include <asm/irq.h>#include <asm/uaccess.h>//#include <mach/hardware.h>#include <mach/irqs.h>#define DEVICE_NAME "keyint"#define KEYNUM 6dev_t devid;//static DEFINE_SEMAPHORE(key_lock); //declare a mutex lock for keyint//定义一个信号量struct semaphore key_lock;static struct fasync_struct *key_async;static struct timer_list key_timer;struct key_irq_desc {int irq; //irq numunsigned long flags; //irq flags,identified the way of irq here,eq.edge,levelchar *name; //irq name};static struct key_irq_desc key_irqs[] = {//下降沿产生中断{IRQ_EINT(0), IRQF_TRIGGER_FALLING, "KEY1"},{IRQ_EINT(1), IRQF_TRIGGER_FALLING, "KEY2"},{IRQ_EINT(2), IRQF_TRIGGER_FALLING, "KEY3"},{IRQ_EINT(3), IRQF_TRIGGER_FALLING, "KEY4"},{IRQ_EINT(4), IRQF_TRIGGER_FALLING, "KEY5"},{IRQ_EINT(5), IRQF_TRIGGER_FALLING, "KEY6"},};/*define a waiting queue here*/static DECLARE_WAIT_QUEUE_HEAD(key_waitq);/*define a event flag ev_press*/static volatile int ev_press = 0;static volatile int press_cnt[KEYNUM] = {0,0,0,0,0,0};/*中断处理函数*/static irqreturn_t keys_interrupt(int irq, void *dev_id){volatile int *press_cnt = (volatile int *) dev_id;/*set the pressed key flag(must do here due to not be static value)*/*press_cnt = *press_cnt + 1;//延时10ms后执行定时器处理函数mod_timer(&key_timer,jiffies+HZ/100); //start timer after 10msreturn IRQ_RETVAL(IRQ_HANDLED);}//定时器处理函数static void key_timer_func(unsigned long data){ev_press = 1;//唤醒等待队列wake_up_interruptible(&key_waitq);kill_fasync(&key_async, SIGIO, POLL_IN);}static int key_fasync(int fd, struct file *filp, int on){printk("Function key_fasync\n");return fasync_helper(fd,filp,on,&key_async);}static unsigned key_poll(struct file *file, poll_table *wait){unsigned int mask=0;//指明要使用的等待队列poll_wait(file,&key_waitq,wait);//返回掩码if(ev_press)mask |= POLL_IN | POLLRDNORM;printk("poll wait\n");return mask;}static int key_open(struct inode *inode, struct file *file){int num;if(file->f_flags & O_NONBLOCK) {if(down_trylock(&key_lock)) return -EBUSY;}else {down(&key_lock);}//为每个按键注册中断处理程序for(num=0;num<KEYNUM;num++) {request_irq(key_irqs[num].irq, keys_interrupt, key_irqs[num].flags, key_irqs[num].name, (void *)&press_cnt[num]);}return 0;}static int key_close(struct inode *inode, struct file *file){int num;//释放中断号for(num=0;num<6;num++) {free_irq(key_irqs[num].irq, (void *)&press_cnt[num]);}up(&key_lock);printk("key_close free irqs\n");return 0;}static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){// unsigned int err;//判断是阻塞读还是非阻塞读if(filp->f_flags & O_NONBLOCK) {if(!ev_press) return -EAGAIN;}else {/*if ev_press==0,then sleep*//*阻塞,当有按键按下时(中断)被唤醒*/wait_event_interruptible(key_waitq,ev_press);}//阻塞结束,有键按下了ev_press = 0;//拷贝数据到用户空间copy_to_user(buff,(const void *)press_cnt,min(sizeof(press_cnt),count));memset((void *)press_cnt,0,sizeof(press_cnt));// printk("read and clean press_cnt\n");return 1;}static struct file_operations key_ops = {.owner = THIS_MODULE,.open = key_open,.release = key_close,.read = key_read,.poll = key_poll,.fasync = key_fasync,};static struct cdev *cdev_keyint;static struct class *keyint_class;//模块初始化函数static int __init s3c6410_keyint_init(void) {int val;/*timer initial */init_timer(&key_timer);key_timer.function = key_timer_func;add_timer(&key_timer);/*初始化信号量*/init_MUTEX(&key_lock);/*register device*/val = alloc_chrdev_region(&devid,0,1,DEVICE_NAME);if(val) {return -1;printk("register keyint error\n");}cdev_keyint = cdev_alloc();cdev_init(cdev_keyint, &key_ops);cdev_keyint->owner = THIS_MODULE;cdev_keyint->ops = &key_ops;val = cdev_add(cdev_keyint,devid,1);if(val) {return -1;printk("add device error\n");}keyint_class = class_create(THIS_MODULE,DEVICE_NAME);device_create(keyint_class,NULL,devid,NULL,"%s",DEVICE_NAME);printk("KEY initialezed ^_^\n");return 0;}static void __exit s3c6410_keyint_exit(void){cdev_del(cdev_keyint);device_destroy(keyint_class,devid);class_destroy(keyint_class);unregister_chrdev_region(devid,1);}module_init(s3c6410_keyint_init);module_exit(s3c6410_keyint_exit);MODULE_LICENSE("GPL");
Makefile
ifneq ($(KERNELRELEASE),)obj-m := key.o
elseKDIR := /forlinux/linux-3.0.1
all:make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
产生.ko文件进行安装模块和设备 insmod,这里不需要mknod因为函数里调用了class_create和device_create会自动创建设备节点。
测试代码
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>int main(int argc, char **argv){int fd;int val;int i;int key_value[6];fd = open("/dev/keybutton",0);if(fd<0) {printf("open devie error\n");return -1;}while(1) {val = read(fd,key_value, sizeof(key_value));if(val<0) {printf("read error\n");continue;}for(i=0;i<6;i++) {if(key_value[i])printf("KEY%d pressed\n",(i+1),key_value[i]);} }close(fd);return 0;}