您的位置:首页 > 运维架构 > Linux

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

2011-10-31 20:32 417 查看
驱动程序
#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上看到结果了,呵呵。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c linux struct module file 测试