linux内核中设备中断

linux内核中设备中断

1、获取软件中断号

1.1 rc = of_irq_parse_one(dev, index, &oirq);解析dts中device node对中断的配置

platform_get_irq(struct platform_device *dev, unsigned int num)
--->of_irq_get(dev, index)
--->--->of_irq_parse_one(device, index, out_irq):解析解析dts中device node对中断的配置
		{
			p = of_irq_find_parent(device);
             out_irq->np = p;
             out_irq->args_count = intsize;
             for (i = 0; i < intsize; i++) {
                res = of_property_read_u32_index(device, "interrupts",
                                 (index * intsize) + i,
                                 out_irq->args + i);
            }
		}

例如

以下是dts文件中i2c节点关于中断的定义, 这里主要看软解是如何解析中断的
 i2c0: i2c@5a800000 
 {
     interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
     interrupt-parent = <&gic>;
 };
 
 解析的目的是初始化struct of_phandle_args结构体,该结构体定义如下:
 struct of_phandle_args 
 {
     struct device_node *np;
     int args_count;
     uint32_t args[MAX_PHANDLE_ARGS];
 };
 
 解析的结果为:
 out_irq->np = interrupt-parent = gic node
 out_irq->args[0] = GIC_SPI;
 out_irq->args[1] = 硬件中断号 = 220
 out_irq->args[2] = 中断触发类型 = IRQ_TYPE_LEVEL_HIGH

1.2 domain = irq_find_host(oirq.np);找到interrupt controller对应的irq domain,对于i2c来说,其对应的中断控制器为gic。

通过匹配irq_domain_list中的fwnode参数来找当前终端控制器对应的domain, 那么domain又是在什么时候加入irq_domain_list中的呢

irq_find_matching_fwspec(){
	list_for_each_entry(h, &irq_domain_list, link) {
        rc = ((fwnode != NULL) && (h->fwnode == fwnode) &&
       		 ((bus_token == DOMAIN_BUS_ANY) ||
        		(h->bus_token == bus_token)));

		if (rc) {
			found = h;
			break;
		}
	}
}

1.3 找到gic终端控制器对应的domain之后,进行map, 将硬件中断号转化为软件中断号

irq_create_of_mapping(struct of_phandle_args *irq_data)
1、将of_phandle_args转化为struct irq_fwspec
of_phandle_args_to_fwspec(irq_data->np, irq_data->args, irq_data->args_count, &fwspec)
{
    fwspec->fwnode = np ? &np->fwnode : NULL;
    fwspec->param_count = count;
    for (i = 0; i < count; i++)
    	fwspec->param[i] = args[i];
}
2、irq_create_fwspec_mapping
先找到终端控制器对应的domain
 domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
 
 解析结构体struct irq_fwspec, 获取hwirq和type
 irq_domain_translate(domain, fwspec, &hwirq, &type)
 若hwirq已经被映射
 hwirq还未被映射,建立映射,virq = irq_domain_alloc_irqs

2、为获得的中断号分配中断处理函数

devm_request_irq
	devm_request_threaded_irq
		request_threaded_irq
1. 将虚拟的irq转化为desc, desc = irq_to_desc(irq); 
2. 如果handler和thread_fn都不存在,直接return;如果只是handler不存在,使用default handler直接唤醒thread
3. 为action分配内存,然后初始化action
4. 注册irqaction  __setup_irq(irq, desc, action);

参考:https://blog.csdn.net/pandy_gao/article/details/79309712

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux内核驱动的定时器是一种常见的机制,可以在指定的时间间隔内触发中断。它的主要作用是进行定时操作,如周期性地刷新屏幕、进行数据采集等。下面是一个简单的Linux内核驱动定时器中断的代码示例: ``` #include <linux/timer.h> #include <linux/init.h> #include <linux/module.h> struct timer_list my_timer; void my_timer_callback(unsigned long data) { printk(KERN_INFO "my_timer_callback called (%ld).\n", jiffies); } static int __init timer_init(void) { int ret; printk(KERN_INFO "timer_init() called\n"); // 设置定时器 setup_timer(&my_timer, my_timer_callback, 0); ret = mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000)); // 定时1秒 if (ret) printk(KERN_ERR "Error in mod_timer\n"); return 0; } static void __exit timer_exit(void) { int ret; ret = del_timer(&my_timer); if (ret) printk(KERN_ERR "The timer is still in use...\n"); printk(KERN_INFO "timer_exit() called\n"); } module_init(timer_init); module_exit(timer_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Linux Timer Driver"); ``` 在上面的示例,我们定义了一个名为`my_timer`的定时器,并将其设置为1秒钟后触发中断。当定时器到期时,它会调用`my_timer_callback()`函数来处理中断。这个函数会输出一条信息,表明它已被调用。 上述示例只是一个简单的示例,实际上在Linux内核驱动使用定时器有许多不同的方法和实现方式。如果你需要更深入地了解Linux内核驱动定时器中断代码,你可以查阅相关的文档或书籍,例如《Linux设备驱动开发详解》等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值