linux按键中断驱动程序——S3C2440

驱动程序
#include<linux/module.h>
#include<linux/init.h>
#include<linux/types.h>
#include<linux/kdev_t.h>
#include<linux/kernel.h>      //可以使用ptintk函数
#include<linux/fs.h>
#include<linux/interrupt.h>   //与中断相关的头文件
#include<linux/cdev.h>		   //字符设备的注册
#include<linux/err.h>           //出错检查函数
#include<linux/slab.h>         //与内存分配相关
#include<linux/sched.h>        //与中断相关的头文件
#include<asm/io.h>             //操作IO端口
#include<linux/wait.h>         //等待队列 
#include<asm/uaccess.h>         //用户和内核空间数据的拷贝
#include<asm/arch/regs-gpio.h>  //I/O口的寄存器地址及使用方式(输入、输出、中断或其他)
#include<asm/arch/regs-irq.h>   //与中断相关的寄存器
#include<asm/arch-s3c2410/irqs.h>//与平台相关的中断号的定义
#include<linux/delay.h>          //时间延迟函数

#define key_major 234         //定义主设备号
#define key_minor 0           //定义次设备号
#define DEVICE_NAME "key_interrupt"
//static struct cdev * key_cdev;
//static dev_t dev_num;
static volatile int key_flags=0;        //作为等待队列的标志
DECLARE_WAIT_QUEUE_HEAD(queue);         //初始化等待队列
static volatile int key_value[]={1,2,3,4};  //按键值
static volatile int key_press=0;            //记录那个键被按下了
static dev_t dev_num;                       //设备号的dev_t表示
static struct cdev *key_cdev;

struct key_irq_description{
	unsigned int irq;
	unsigned long flags;
	const char *dev_name;
};

struct key_irq_description key_irq[]={
	{IRQ_EINT0,SA_INTERRUPT,"key"},
	{IRQ_EINT2,SA_INTERRUPT,"key"},
	{IRQ_EINT3,SA_INTERRUPT,"key"},
	{IRQ_EINT4,SA_INTERRUPT,"key"},
};
/*中断处理函数*/
static irqreturn_t key_interrupt(int irq, void *dev_id,struct pt_regs *regs)
{
	__raw_writel(__raw_readl(S3C2410_SRCPND)&0xffffffda,S3C2410_SRCPND);//clear srcpnd 0 2 3 4(这个很重要)
	mdelay(1);
	key_press= *(int *) dev_id;                  //把按键值付给key_press
	key_flags=1;                                 //等待队列标志置一 
	wake_up_interruptible(&queue);               //唤醒等待队列
        return IRQ_HANDLED;  
}
/*在这里只申请中断,可以节省中断资源*/
static int key_open(struct inode *inode, struct file *filp)
{
        printk("now in key_open\n");
	int ret;
	int i;
	for(i=0;i<sizeof(key_irq)/sizeof(key_irq[0]);i++){
	ret=request_irq(key_irq[i].irq,key_interrupt,key_irq[i].flags,key_irq[i].dev_name,(void *)&key_value[i]);//申请中断
	printk("please irq\n");
	if(ret) break;
	}
	if(ret){
		printk("now at free_irq\n");
		i--;
		for(;i>=0;i--){
			free_irq(key_irq[i].irq,(void *)&key_value[i]);
			return -EBUSY;
		}
	}
        return 0;
}

/*不使用相关资源时释放中断*/
static int key_close(struct inode *inode, struct file *filp)
{
	int i;
	for(i=0;i<sizeof(key_irq)/sizeof(key_irq[0]);i++){
		free_irq(key_irq[i].irq,(void *)&key_value[i]);
	}
	return 0;
}

/*完成数据从内核空间到用户控件的拷贝*/
static ssize_t key_read(struct file *filp, char __user *buf, size_t count , loff_t * offp)
{
	unsigned long err;
	wait_event_interruptible(queue,key_flags);                 //开启等待队列
	key_flags=0;                                               //当key_flags=1时可释放等待队列
	err=copy_to_user(buf,(const void *)&key_press,count);      //注意表示方法
	key_press=0;
	return err?-EFAULT:0;
}

static struct file_operations key_fops={
	.owner    = THIS_MODULE,
	.read     = key_read,
	.open     = key_open,
	.release = key_close,
};

/*填充cdev结构*/
static void key_cdev_setup(void)
{
	int err;
	cdev_init(key_cdev,&key_fops);                               //初始化已分配到的结构
	key_cdev->owner=THIS_MODULE;                                 //设置所有者字段
	key_cdev->ops=&key_fops;
	err=cdev_add(key_cdev,dev_num,1);                            //告诉内核该结构的信息
	if(IS_ERR(&err)){                                            //检查返回的指针是否是一个错误编码
		printk(KERN_NOTICE "Error %d adding key_interrupt",err);
	}
}

/*初始化相关寄存器*/
static void initbutton(void)
{
	__raw_writel((__raw_readl(S3C2410_GPFCON)&(~((3<<8)|(3<<6)|(3<<4)|(3<<0))))|((2<<8)|(2<<6)|(2<<4)|(2<<0)),S3C2410_GPFCON) ;  //GPF2,0,3,4 set EINT
    __raw_writel((__raw_readl(S3C2410_EXTINT0)&(~(7|(7<<8)|(7<<12)|(7<<16)))),S3C2410_EXTINT0);
    __raw_writel((__raw_readl(S3C2410_EXTINT0)|(0|(0<<8)|(0<<12)|(0<<16))),S3C2410_EXTINT0);   //set eint0,2,3,4 falling edge int
    __raw_writel((__raw_readl(S3C2410_EINTPEND)|((1<<4))),S3C2410_EINTPEND);                   //clear eint 4
    __raw_writel((__raw_readl(S3C2410_EINTMASK)&(~((1<<4)))),S3C2410_EINTMASK);                //enable eint 4

}
/*模块初始化函数,分配设备编号,初始化寄存器,为cdev结构分配内存并初始化cdev结构*/
static int __init key_init(void)        
{
	int ret;
	initbutton();                                 //初始化相关寄存器
	if(key_major){                                
	   dev_num=MKDEV(key_major,key_minor);
	   ret=register_chrdev_region(dev_num,1,DEVICE_NAME);    //静态分配设备编号
	}
	else{
		ret=alloc_chrdev_region(&dev_num,key_minor,1,DEVICE_NAME);    //动态分配设备编号
	}
	if(ret<0){
		printk(KERN_WARNING "key: can't get key_major %d\n",key_major);
		return ret;
	}
	key_cdev=kmalloc(sizeof(struct cdev),GFP_KERNEL);                     //为cdev结构分配内存
	if(!key_cdev){
		printk("can't get this RAM\n");
		ret=-ENOMEM;
	}
	memset(key_cdev,0,sizeof(struct cdev));                               //cdev结构内存区清零
	key_cdev_setup();                                                     //注册设备结构cdev
	return 0;
}

/*模块退出函数,内部函数执行顺序要与模块初始化的顺序相反*/
static void __exit key_exit(void)
{
	cdev_del(key_cdev);                          //删除cdev结构
	kfree(key_cdev);                             //释放分配的内存
	unregister_chrdev_region(dev_num,1);         //释放设备编号
}
module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("lizhibin");  
MODULE_DESCRIPTION("key and interrupt");




测试程序
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <sys/ioctl.h>  
   
int main(int argc,char **argv)  
{  
    int i;  
    int ret;  
    int fd;  
    char press_cnt;  
    printf("Hi I am come in\n");
    sleep(5);
    printf("5 seconds after\n");  
    fd=open("/dev/key_interrupt",0);
    printf("key_interrupt by open\n");  
    if(fd<0)  {  
        printf("Can't open /dev/interrupt \n");  
        return -1;  
    }  
 
    while(1) {  
        printf("come in while(1)\n");
        ret = read(fd,&press_cnt,sizeof(press_cnt));  
        if(ret<0)  {  
            printf("read err !\n");  
            continue;  
        }  
            if(press_cnt)  
                printf("Key%d has been pressed  \n",press_cnt);  
 
      
    }          
      
}

编译之后下载到开发板,使用insmod加载驱动程序、mknod创建设备节点、运行测试程序之后按下按键时就可以DNW上看到结果了,呵呵。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值