Linux中断处理

目录

一、什么是中断

二、中断处理原理

三、中断接口

3.1 中断申请

3.2 中断释放

3.3 中断处理函数原型

四、按键驱动


一、什么是中断

一种硬件上的通知机制,用来通知CPU发生了某种需要立即处理的事件

分为:

1. 内部中断  CPU执行程序的过程中,发生的一些硬件出错、运算出错事件(如分母为0、溢出等等),不可屏蔽

2. 外部中断  外设发生某种情况,通过一个引脚的高、低电平变化来通知CPU (如外设产生了数据、某种处理完毕等等)

二、中断处理原理

(向量中断:在一块内存中每个地址对应一个中断.arm中异常是向量形式的。中断是非向量形式的中断是7种异常的一种

非向量中断:只有一个中断接口,在中断处理程序中有很多分处理函数,比如exynos4412)

(哪种中断好像和硬件有关)

任何一种中断产生,CPU都会暂停当前执行的程序,跳转到内存固定位置执行一段程序,该程序被称为总的中断服务程序,在该程序中区分中断源,然后进一步调用该中断源对应的处理函数。

中断源对应的处理函数被称为分中断处理程序,一般每一个分中断处理程序对应一个外设产生的中断

写驱动时,如果外设有中断,则需要编写一个函数(分中断处理程序)来处理这种中断

三、中断接口

3.1 中断申请

```c

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)

/*

参数:

    irq:所申请的中断号

    handler:该中断号对应的中断处理函数

    flags:中断触发方式或处理方式

        触发方式:IRQF_TRIGGER_NONE      //无触发

                 IRQF_TRIGGER_RISING    //上升沿触发

                 IRQF_TRIGGER_FALLING  //下降沿触发

                IRQF_TRIGGER_HIGH   //高电平触发

                IRQF_TRIGGER_LOW        //低电平触发

        处理方式:

               IRQF_DISABLED        //用于快速中断,处理中屏蔽所有中断

                IRQF_SHARED       //共享中断

        name:中断名 /proc/interrupts

        dev:传递给中断例程的参数,共享中断时用于区分那个设备,一般为对应设备的结构体地址,无共享中断时写NULL

返回值:成功:0 失败:错误码

*/

```

3.2 中断释放

```c

void free_irq(unsigned int irq, void *dev_id);

/*

功能:释放中断号

参数:

    irq:设备号

    dev_id:共享中断时用于区分那个设备一般强转成设备号,无共享中断时写NULL

*/

```

3.3 中断处理函数原型

```c

typedef irqreturn_t (*irq_handler_t)(int, void *);

/*

参数:

    int:中断号

    void*:对应的申请中断时的dev_id

返回值:

    typedef enum irqreturn irqreturn_t; //中断返回值类型

    enum irqreturn {

        IRQ_NONE    = (0 << 0),

        IRQ_HANDLED = (1 << 0),

        IRQ_WAKE_THREAD = (1 << 1),

    };

    返回IRQ_HANDLED表示处理完了,返回IRQ_NONE在共享中断表示不处理

*/

```

四、按键驱动

按键原理图:

interrupts中第一个数据是 上面紫色框一致的25是第1个24是第0个所以是1,3是11所以上升沿也触发下降沿也触发。

exynos4412-fs4412.dts中增加节点

```

mykey2_node {

    compatible = "mykey2,key2";

    key2-gpio = <&gpx1 1 0>;

    interrupt-parent = <&gpx1>;

    interrupts = <1 3>;

};

```

申请中断做好要在初始化函数左后做,不然可以会导致有些东西没准备好

由于是按键所以要设置防抖,异常上下文是不能msleep的这里延时使用mdelay

 

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#include "fs4412_key.h"


int major = 11;
int minor = 0;
int fs4412key2_num  = 1;

struct fs4412key2_dev
{
	struct cdev mydev;

	int gpio;
	int irqno;

	struct keyvalue data;
	int newflag;
	spinlock_t lock;

	wait_queue_head_t rq;
};

struct fs4412key2_dev *pgmydev = NULL;

int fs4412key2_open(struct inode *pnode,struct file *pfile)
{
	pfile->private_data =(void *) (container_of(pnode->i_cdev,struct fs4412key2_dev,mydev));
	return 0;
}

int fs4412key2_close(struct inode *pnode,struct file *pfile)
{

	return 0;
}

ssize_t fs4412key2_read(struct file *pfile,char __user *puser,size_t count,loff_t *p_pos)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)pfile->private_data;
	int size = 0;
	int ret = 0;

	if(count < sizeof(struct keyvalue))
	{
		printk("expect read size is invalid\n");
		return -1;
	}

	spin_lock(&pmydev->lock);
	if(!pmydev->newflag)
	{
		if(pfile->f_flags & O_NONBLOCK)
		{//非阻塞
			spin_unlock(&pmydev->lock);
			printk("O_NONBLOCK No Data Read\n");
			return -1;
		}
		else
		{//阻塞
			spin_unlock(&pmydev->lock);
			ret = wait_event_interruptible(pmydev->rq,pmydev->newflag == 1);
			if(ret)
			{
				printk("Wake up by signal\n");
				return -ERESTARTSYS;
			}
			spin_lock(&pmydev->lock);
		}
	}

	if(count > sizeof(struct keyvalue))
	{
		size = sizeof(struct keyvalue);
	}
	else
	{
		size = count;
	}

	ret = copy_to_user(puser,&pmydev->data,size);
	if(ret)
	{
		spin_unlock(&pmydev->lock);
		printk("copy_to_user failed\n");
		return -1;
	}

	pmydev->newflag = 0;

	spin_unlock(&pmydev->lock);

	return size;
}

unsigned int fs4412key2_poll(struct file *pfile,poll_table *ptb)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)pfile->private_data;
	unsigned int mask = 0;

	poll_wait(pfile,&pmydev->rq,ptb);

	spin_lock(&pmydev->lock);
	if(pmydev->newflag)
	{
		mask |= POLLIN | POLLRDNORM;
	}
	spin_unlock(&pmydev->lock);

	return mask;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = fs4412key2_open,
	.release = fs4412key2_close,
	.read = fs4412key2_read,
	.poll = fs4412key2_poll,
};

irqreturn_t key2_irq_handle(int no,void *arg)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;
	int status1 = 0;
	int status2 = 0;
	int status = 0;

	status1 = gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2 = gpio_get_value(pmydev->gpio);

	if(status1 != status2)
	{
		return IRQ_NONE;
	}

	status = status1;

	spin_lock(&pmydev->lock);
	if(status == pmydev->data.status)
	{
		spin_unlock(&pmydev->lock);
		return IRQ_NONE;
	}

	pmydev->data.code = KEY2;
	pmydev->data.status = status;
	pmydev->newflag = 1;

	spin_unlock(&pmydev->lock);
	wake_up(&pmydev->rq);

	return IRQ_HANDLED;
}

int __init fs4412key2_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);

	struct device_node *pnode = NULL;

	pnode = of_find_node_by_path("/mykey2_node");
	if(NULL == pnode)
	{
		printk("find node failed\n");
		return -1;
	}


	pgmydev = (struct fs4412key2_dev *)kmalloc(sizeof(struct fs4412key2_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmallc for struct fs4412key2_dev failed\n");
		return -1;
	}

	pgmydev->gpio = of_get_named_gpio(pnode,"key2-gpio",0);

	pgmydev->irqno = irq_of_parse_and_map(pnode,0);

	ret = register_chrdev_region(devno,fs4412key2_num,"fs4412key2");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,fs4412key2_num,"fs4412key2");
		if(ret)
		{
			kfree(pgmydev);
			pgmydev = NULL;
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);
	}

	cdev_init(&pgmydev->mydev,&myops);

	pgmydev->mydev.owner = THIS_MODULE;
	cdev_add(&pgmydev->mydev,devno,fs4412key2_num);


	init_waitqueue_head(&pgmydev->rq);

	spin_lock_init(&pgmydev->lock);
	
	ret = request_irq(pgmydev->irqno,key2_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key2",pgmydev);
	if(ret)
	{
		printk("request_irq failed\n");
		cdev_del(&pgmydev->mydev);
		kfree(pgmydev);
		pgmydev = NULL;
		unregister_chrdev_region(devno,fs4412key2_num);
		return -1;
	}
	return 0;
}

void __exit fs4412key2_exit(void)
{
	dev_t devno = MKDEV(major,minor);

	free_irq(pgmydev->irqno,pgmydev);

	cdev_del(&pgmydev->mydev);

	unregister_chrdev_region(devno,fs4412key2_num);

	kfree(pgmydev);
	pgmydev = NULL;
}


MODULE_LICENSE("GPL");

module_init(fs4412key2_init);
module_exit(fs4412key2_exit);

 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <stdio.h>

#include "fs4412_key.h"

int main(int argc,char *argv[])
{
	int fd = -1;
	struct keyvalue keydata = {0};
	int ret = 0;

	if(argc < 2)
	{
		printf("The argument is too few\n");
		return 1;
	}

	fd = open(argv[1],O_RDONLY);
	if(fd < 0)
	{
		printf("open %s failed\n",argv[1]);
		return 3;
	}

	while((ret = read(fd,&keydata,sizeof(keydata))) == sizeof(keydata))
	{
		if(keydata.status == KEY_DOWN)
		{
			printf("Key2 is down!\n");
		}
		else
		{
			printf("Key2 is up!\n");
		}
	}

	close(fd);
	fd = -1;
	return 0;
}

根据key2的驱动改写key3

 

 

 

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#include "fs4412_key.h"


int major = 11;
int minor = 0;
int fs4412key3_num  = 1;

struct fs4412key3_dev
{
	struct cdev mydev;

	int gpio;
	int irqno;

	struct keyvalue data;
	int newflag;
	spinlock_t lock;

	wait_queue_head_t rq;
};

struct fs4412key3_dev *pgmydev = NULL;

int fs4412key3_open(struct inode *pnode,struct file *pfile)
{
	pfile->private_data =(void *) (container_of(pnode->i_cdev,struct fs4412key3_dev,mydev));
	return 0;
}

int fs4412key3_close(struct inode *pnode,struct file *pfile)
{

	return 0;
}

ssize_t fs4412key3_read(struct file *pfile,char __user *puser,size_t count,loff_t *p_pos)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)pfile->private_data;
	int size = 0;
	int ret = 0;

	if(count < sizeof(struct keyvalue))
	{
		printk("expect read size is invalid\n");
		return -1;
	}

	spin_lock(&pmydev->lock);
	if(!pmydev->newflag)
	{
		if(pfile->f_flags & O_NONBLOCK)
		{//非阻塞
			spin_unlock(&pmydev->lock);
			printk("O_NONBLOCK No Data Read\n");
			return -1;
		}
		else
		{//阻塞
			spin_unlock(&pmydev->lock);
			ret = wait_event_interruptible(pmydev->rq,pmydev->newflag == 1);
			if(ret)
			{
				printk("Wake up by signal\n");
				return -ERESTARTSYS;
			}
			spin_lock(&pmydev->lock);
		}
	}

	if(count > sizeof(struct keyvalue))
	{
		size = sizeof(struct keyvalue);
	}
	else
	{
		size = count;
	}

	ret = copy_to_user(puser,&pmydev->data,size);
	if(ret)
	{
		spin_unlock(&pmydev->lock);
		printk("copy_to_user failed\n");
		return -1;
	}

	pmydev->newflag = 0;

	spin_unlock(&pmydev->lock);

	return size;
}

unsigned int fs4412key3_poll(struct file *pfile,poll_table *ptb)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)pfile->private_data;
	unsigned int mask = 0;

	poll_wait(pfile,&pmydev->rq,ptb);

	spin_lock(&pmydev->lock);
	if(pmydev->newflag)
	{
		mask |= POLLIN | POLLRDNORM;
	}
	spin_unlock(&pmydev->lock);

	return mask;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = fs4412key3_open,
	.release = fs4412key3_close,
	.read = fs4412key3_read,
	.poll = fs4412key3_poll,
};

irqreturn_t key3_irq_handle(int no,void *arg)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)arg;
	int status1 = 0;
	int status2 = 0;
	int status = 0;

	status1 = gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2 = gpio_get_value(pmydev->gpio);

	if(status1 != status2)
	{
		return IRQ_NONE;
	}

	status = status1;

	spin_lock(&pmydev->lock);
	if(status == pmydev->data.status)
	{
		spin_unlock(&pmydev->lock);
		return IRQ_NONE;
	}

	pmydev->data.code = KEY3;
	pmydev->data.status = status;
	pmydev->newflag = 1;

	spin_unlock(&pmydev->lock);
	wake_up(&pmydev->rq);

	return IRQ_HANDLED;
}

int __init fs4412key3_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);

	struct device_node *pnode = NULL;

	pnode = of_find_node_by_path("/mykey3_node");
	if(NULL == pnode)
	{
		printk("find node failed\n");
		return -1;
	}


	pgmydev = (struct fs4412key3_dev *)kmalloc(sizeof(struct fs4412key3_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmallc for struct fs4412key3_dev failed\n");
		return -1;
	}

	pgmydev->gpio = of_get_named_gpio(pnode,"key3-gpio",0);

	pgmydev->irqno = irq_of_parse_and_map(pnode,0);

	ret = register_chrdev_region(devno,fs4412key3_num,"fs4412key3");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,fs4412key3_num,"fs4412key3");
		if(ret)
		{
			kfree(pgmydev);
			pgmydev = NULL;
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);
	}

	cdev_init(&pgmydev->mydev,&myops);

	pgmydev->mydev.owner = THIS_MODULE;
	cdev_add(&pgmydev->mydev,devno,fs4412key3_num);


	init_waitqueue_head(&pgmydev->rq);

	spin_lock_init(&pgmydev->lock);
	
	ret = request_irq(pgmydev->irqno,key3_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key3",pgmydev);
	if(ret)
	{
		printk("request_irq failed\n");
		cdev_del(&pgmydev->mydev);
		kfree(pgmydev);
		pgmydev = NULL;
		unregister_chrdev_region(devno,fs4412key3_num);
		return -1;
	}
	return 0;
}

void __exit fs4412key3_exit(void)
{
	dev_t devno = MKDEV(major,minor);

	free_irq(pgmydev->irqno,pgmydev);

	cdev_del(&pgmydev->mydev);

	unregister_chrdev_region(devno,fs4412key3_num);

	kfree(pgmydev);
	pgmydev = NULL;
}


MODULE_LICENSE("GPL");

module_init(fs4412key3_init);
module_exit(fs4412key3_exit);

 

#ifndef FS4412_KEY_H
#define FS4412_KEY_H

enum KEYCODE
{
	KEY2 = 1002,
	KEY3 = 1003,
	KEY4,
};

enum KEY_STATUS
{
	KEY_DOWN = 0,
	KEY_UP,
};

struct keyvalue
{
	int code;//which KEY
	int status;
};

#endif

测试代码修改一下打印就行。 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇努力学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值