内核中断实现

1 篇文章 0 订阅
1 篇文章 0 订阅

内核中断实现

Linux中断处理子系统

1.根据中断号找到正确的中断处理代码
2.Linux定义 了名字为irq_desc的中断例程描述符表:(include/inux/irq.h)该表struct irgdesc结构组成
struct irq_desc irg_desc[NR_IROST];NR_ _IRQS表示中断源的数目
irg_desc结构体中的成员action指向该中断号对应的irgaction结构体链表
。irgaction结构体定义如下:

//include/linux/interrupt.h
struct irgaction {
irq_hander_t handler; /指向中断服务程序
unsigned long flags;//中断标志
unsigned long mask; //中断掩码
const char *name; //I/O设备名
void *dev_id;//设备标识
struct irgaction *next;//指向下一个描述符
int irq; //IRQ线
struct proc_dir_entry *dir; //指向IRQn相关的/proc/irg/n目录的描述符
}

全局中断控制:

全局中断控制包括启用和禁用中断(ARM)

 raw_local_irg_save(x) //用来禁用所有的中断(一般不使用)
 raw_local_irg_enable   //用来取消中断禁用

尽量不要对全局中断进行操作

static inline int atomic s1ub return(int i atomic↑*v)
{
	unsigned long flags;
	int val; 
	raw_local_irq_save(flags);
	val = v-> counter;
	v-> counter = val-= i;
	raw_local_irq_restore(flags);
	return val;
}

申请IRQ

1.中断处理程序注册的两个功能:注册中断号和注册中断
处理函数

typedef irgreturn_t (*irq_handler_t)(int, void *);
int request_irg(
			unsigned int irq,
			irq_handler_t handler,
			unsigned long flags,
			const char *name,
			void *dev_ id);

2.驱动程序可以选择在初始化的时候安装中断处理程序,也可以在用户打开设备时再安装
3.参数说明:
1)irq是要申请的中断号
2)handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev参数将被传递给它。
3) flags是中断标志位。若设置了IRQF_DISABLED,则表示中断处理程序被调用时屏蔽所有中断;若设置了IRQF_SHARED,则表示多个设备共享中断;
4) name设置中断名称,在cat /proc/interrupts中可以看到此名称(自定义)。
5)dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。

中断实现示例

内核部分:

在设备树文件中添加设备声明:vim linux-3.14/arch/arm/boot/dts/exynos4412-origen.dts
注意:需要在该文件中加入头文件否则无法识别IRQ_TYPE_EDGE_FALLING关键字

#include <dt-bindings\interrupt-controller\irq.h>
key{
	compatible = "superme,mykey";
	interrupt-parent = <&gpx1>;
	interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
};

参数说明:
compatible为设备匹配字,必须确保字符和驱动中注册字符完全一致
interrupt-parent为中断的父节点,需要查询芯片手册来查看所操作的硬件设备的分组,比如示例设备为按键2为gpx1_1,为第一组所以填写&gpx1,具体是否有该分组需要查看exynos4412-origen.dts所包含的头文件
interrupts第一个参数为分组的编号比如按键2为gpx1_1,则是gpx1组的1,
IRQ_TYPE_EDGE_FALLING意为下降沿触发,
IRQ_TYPE_EDGE_RISING意为上升沿触发,
IRQ_TYPE_LEVEL_HIGH意为高电平触发
IRQ_TYPE_LEVEL_LOW意为低电平触发
IRQ_TYPE_EDGE_BOTH意为上升和下降沿都触发

驱动部分:

//中断处理函数
irqreturn_t myfun(int irqno,void* dev_id)
{
	printk("this interrupt no is %d\n",irqno);
	return IRQ_HANDLED;
}
static int mykey_probe(struct platform_device* pdev)
{
	int ret = -1;
	/*************kernel****************/
	//1.reg
	no = MKDEV(MA,MI);
	ret = register_chrdev_region(no,num,name);
	if(ret<0)
		return ret;
	//2.init
	cdev_init(&mydev,&myops);
	//3.add
	cdev_add(&mydev,no,num);
	/*************hw   ****************/
	struct resource* irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);//获取中断信息
	int ret = request_irq(
		irqres->start,//中断起始地址
		myfun,//中断函数
		irqres->flags | IRQF_ DISABLED,
		"myirq",
		NULL);
	return 0;
}

static int mybee_remove(struct platform_device* pdev)
{
	//kernel
	cdev_del(&mydev);
	unregister_chrdev_region(devno,devNum);
	//hw
	free_irq(irqres->start,NULL);//释放中断
	return 0;
}

Linux中断半部机制

1.两个半部的理念:
解决既要中断执行快,又要做的事情多的矛盾。
2.下半部机制的实现:
1)软中断(同类型的中断可以同时执行)
2)Tasklet(同类型的中断不能同时执行)
定义一个处理函数
void my_tasklet_func(unsigned long);
定义一个tasklet结构my_tasklet,与my_tasklet_func(data)函数相联
DECLARE_TASKLET(my_tasklet, my_tasklet_func, data);
调度tasklet
tasklet_schedule(&my_tasklet);
3)工作队列(作为进程被调度)
定义一个工作队列
struct work_struct my_wq;
定义一个处理函数
void my_wq_func(unsigned long) ;
初始化工作队列并将其与处理函数绑定
INIT_WORK(&my_wq, my_wq_func);
调度工作队列执行
schedule_work(&my_wq);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值