- <pre name="code" class="html">驱动程序</pre><pre name="code" class="html">#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");</pre><br>
- <pre></pre>
- <pre name="code" class="plain"></pre><pre name="code" class="plain"></pre><pre name="code" class="plain">测试程序</pre><pre name="code" class="plain"><pre name="code" class="plain">#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);
- }
- }</pre><br>
- 编译之后下载到开发板,使用insmod加载驱动程序、mknod创建设备节点、运行测试程序之后按下按键时就可以DNW上看到结果了,呵呵。
- <pre></pre>
- <pre></pre>
- </pre>
inux按键中断驱动程序——S3C2440
最新推荐文章于 2024-01-04 14:43:31 发布