前言

这次实验就没办法使用定时器来忽悠了。在开发板上配按键和设备树。按键是上升沿和下降沿双向触发的。测试效果一级棒。

Linux实现底半部的机制主要有tasklet、工作队列、软中断和线程化irq。本次介绍最后一个线程化irq。

一 threaded_irq

在内核中,除了可以通过request_irq()、devm_request_irq()申请中断以外,还可以通过request_threaded_irq()和devm_request_threaded_irq()申请。这两个函数的原型为:

typedef irqreturn_t (*irq_handler_t)(int, void *);
int request_threaded_irq(unsigned int irq, irq_handler_t handler,irq_handler_t thread_fn,unsigned long flags, const char *name, void *dev);
int devm_request_threaded_irq(struct device *dev, unsigned int irq,irq_handler_t handler, irq_handler_t thread_fn,unsigned long irqflags, const char *devname,void *dev_id);

由此可见,它们比request_irq()、devm_request_irq()多了一个参数thread_fn。用这两个API申请中断的时候,内核会为相应的中断号分配一个对应的内核线程。注意这个线程只针对这个中断号,如果其他中断也通过request_threaded_irq()申请,自然会得到新的内核线程。

参数handler对应的函数执行于中断上下文,thread_fn参数对应的函数则执行于内核线程。如果handler结束的时候,返回值是IRQ_WAKE_THREAD,内核会调度对应线程执行thread_fn对应的函数。

request_threaded_irq()和devm_request_threaded_irq()支持在irqflags中设置IRQF_ONESHOT标记,这样内核会自动帮助我们在中断上下文中屏蔽对应的中断号,而在内核调度thread_fn执行后,重新使能该中断号。对于我们无法在上半部清除中断的情况,IRQF_ONESHOT特别有用,避免了中断服务程序一退出,中断就洪泛的情况。

handler参数可以设置为NULL,这种情况下,内核会用默认的irq_default_primary_handler()代替handler,并会使用IRQF_ONESHOT标记。irq_default_primary_handler()定义为:

释放函数:free_irq,

参数irq就是request_threaded_irq的参数irq,参数dev_id也是request_threaded_irq的最后一个参数的值,这两个也必须保持一致。例如irq是共享中断等待情况。

/*** free_irq - free an interrupt allocated with request_irq*    @irq: Interrupt line to free*  @dev_id: Device identity to free** Remove an interrupt handler. The handler is removed and if the* interrupt line is no longer in use by any driver it is disabled.*   On a shared IRQ the caller must ensure the interrupt is disabled*   on the card it drives before calling this function. The function*   does not return until any executing interrupts for this IRQ*    have completed.**   This function must not be called from interrupt context.*/
void free_irq(unsigned int irq, void *dev_id)
{struct irq_desc *desc = irq_to_desc(irq);if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))return;#ifdef CONFIG_SMPif (WARN_ON(desc->affinity_notify))desc->affinity_notify = NULL;
#endifchip_bus_lock(desc);kfree(__free_irq(irq, dev_id));chip_bus_sync_unlock(desc);
}

二 测试代码

设备树:

/ {mykey {#address-cells = <1>;#size-cells = <1>;compatible = "mykey";pinctrl-names = "default";pinctrl-0 = <&pinctrl_wskey>;mykey-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>;interrupt-parent = <&gpio1>;interrupts = <18 IRQ_TYPE_EDGE_BOTH>;status = "okay";};
};&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_hog_1>;imx6ul-evk {... ...pinctrl_mykey: mykeygrp {fsl,pins = <MX6UL_PAD_UART1_CTS_B__GPIO1_IO18       0xF080  /* KEY0 */>;};... ...
};

驱动源码:csi_threadirq.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/mutex.h>#define DEBUG_tq(format, ...)                                                                     \printk ("%s,line=%d:" format "\n", __func__, __LINE__, ##__VA_ARGS__)struct cstq_dev_{int count;int irq;
};
struct cstq_dev_ global_cstq_dev;
irqreturn_t cstq_irq_handler_t(int irq, void *dev)
{struct cstq_dev_ *cstq_dev = (struct cstq_dev_ *)dev;cstq_dev->count++;DEBUG_tq("cstq_dev->count = %d,irq=%d",cstq_dev->count,irq);if(cstq_dev->count%2 == 0){return IRQ_WAKE_THREAD;}return  IRQ_HANDLED;
}
irqreturn_t cstq_irq_thread_fn_t(int irq, void *dev)
{struct cstq_dev_ *cstq_dev = (struct cstq_dev_ *)dev;DEBUG_tq("cstq_dev->count = %d",cstq_dev->count);return IRQ_HANDLED;
}static int  cstq_platform_probe(struct platform_device *pdev){struct cstq_dev_ *cstq_dev = &global_cstq_dev;int ret = 0;cstq_dev->count = 0;cstq_dev->irq = platform_get_irq(pdev, 0);if (cstq_dev->irq  < 0) {if (cstq_dev->irq  != -EPROBE_DEFER){dev_err(&pdev->dev, "cannot get irq\n");}DEBUG_tq("platform_get_irq error cstq_dev->irq = %d\n",cstq_dev->irq);return cstq_dev->irq;}DEBUG_tq("cstq_dev->irq = %d\n",cstq_dev->irq);ret = request_threaded_irq(cstq_dev->irq,cstq_irq_handler_t,cstq_irq_thread_fn_t,IRQF_ONESHOT,"cstq_irq",cstq_dev);if (ret < 0) {dev_err(&pdev->dev, "Failed to request IRQ!\n");return ret;}DEBUG_tq("init ok");    return 0;
}
static int cstq_platform_remove(struct platform_device *platform_device){struct cstq_dev_ *cstq_dev = &global_cstq_dev;DEBUG_tq("cstq_dev->count = %d",cstq_dev->count);free_irq(cstq_dev->irq,cstq_dev);DEBUG_tq("exit ok");        return 0;
}static const struct of_device_id cstq_of_match[]={{.compatible = "mykey"},{}
};MODULE_DEVICE_TABLE(of, cstq_of_match);static struct platform_device_id cstq_driver_ids[] = {{.name  = "mykey",},{ },
};
MODULE_DEVICE_TABLE(platform, cstq_driver_ids);static struct platform_driver cstq_driver={.driver = {.name = "mykey",.of_match_table = cstq_of_match,},.probe = cstq_platform_probe,.remove = cstq_platform_remove, .id_table   = cstq_driver_ids,
};
module_platform_driver(cstq_driver);MODULE_LICENSE("GPL");

Makefile

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
KERN_DIR = /home/lkmao/imx/linux/linux-imxFILE_NAME=csi_threadirq
obj-m += $(FILE_NAME).oall:make -C $(KERN_DIR) M=$(shell pwd) modules
.PHONY:clean
clean:make -C $(KERN_DIR) M=$(shell pwd) clean

测试结果:

按下按键,cstq_irq_handler_t输出单数,抬起按键,cstq_irq_thread_fn_t输出双数。

也就是说,在cstq_irq_handler_t中返回IRQ_WAKE_THREAD,cstq_irq_thread_fn_t随后会被调用,返回IRQ_HANDLED,随后不会调用cstq_irq_thread_fn_t。

从cstq_irq_handler_t的参数irq值可知,该值就是platform_get_irq返回的终端号。

insmod csi_threadirq.ko
[ 5442.631954] cstq_platform_probe,line=48:cstq_dev->irq = 45
[ 5442.631954]
[ 5442.642162] cstq_platform_probe,line=59:init ok
root@hehe:~# [ 5453.252698] cstq_irq_handler_t,line=22:cstq_dev->count = 1,irq=45
[ 5453.557714] cstq_irq_handler_t,line=22:cstq_dev->count = 2,irq=45
[ 5453.563863] cstq_irq_thread_fn_t,line=31:cstq_dev->count = 2
[ 5454.485278] cstq_irq_handler_t,line=22:cstq_dev->count = 3,irq=45
[ 5454.731228] cstq_irq_handler_t,line=22:cstq_dev->count = 4,irq=45
[ 5454.737371] cstq_irq_thread_fn_t,line=31:cstq_dev->count = 4
[ 5455.263111] cstq_irq_handler_t,line=22:cstq_dev->count = 5,irq=45
[ 5455.462694] cstq_irq_handler_t,line=22:cstq_dev->count = 6,irq=45
[ 5455.468831] cstq_irq_thread_fn_t,line=31:cstq_dev->count = 6
... ...

结束

linux内核中断实践5:threaded_irq相关推荐

  1. linux内核中断实践2:tasklet

    前言 本次实验例程中断使用定时器替代使用的,实验结果确实没啥问题.如果使用硬件中断的话需要配置设备树,然后从设备树获取irq号,然后就是使用request_irq函数.剩下的就都一样了. Linux实 ...

  2. Linux内核中断系统处理机制-详细分析

    原文地址::https://blog.csdn.net/weixin_42092278/article/details/81989449 相关文章 1.Linux中断管理 (1)Linux中断管理机制 ...

  3. 《linux内核中断》之 法外狂徒张三删库跑路

    法外狂徒张三删库跑路 真实案例:在今年2月份,国内一个程序员删库的消息传遍it界.他的几行代码,直接让上市公司微盟的市值一天蒸发超10亿,300百万用户直接受到影响.网上是谣言四起,可谓是最牛逼的删库 ...

  4. linux内核看门狗关闭方法,linux内核中断之看门狗

    一:内核中断 linux内核中的看门狗中断跟之前的裸板的中断差不多,在编写驱动之前,需要线把内核自带的watch dog模块裁剪掉,要不然会出现错误:在Device Drivers /Watchdog ...

  5. linux内核中断详解

    linux内核中断详解 1.中断的硬件触发流程 外设:如果外设有操作或者有数据可用,那么就会产生一个电信号,这个电信号发送给中断控制器. 中断控制器:中断控制器接收到外设发来的电信号以后,进行进一步的 ...

  6. Linux 内核中断体系 初探

    还是要先理解整个中断的体系,首先要理解对中断的含义 如果这是涉及到的软件的调试的话,没有接触过硬件的同学会对,gdb的调试中的中断有一定的认知 但是,这两个中断指的意思是不相同的,gdb的调试中的中断 ...

  7. 初步了解Linux内核中断初始化

    在linux内核中,用struct irq_chip结构体描述一个可编程中断控制器,它的整个结构和调度器中的调度类类似,里面定义了中断控制器的一些操作: 在中断处理中所涉及的几个重要的数据结构:中断描 ...

  8. linux 内核中断与时钟的冲突 问题 del_timer,Linux内核开发之中断与时钟(三)

    晚上7点10分.. "小涛哥,这章不是叫Linux设备驱动程序之中断与时钟,前边你讲了中断,还给了我很多模版,我都看懂了,这次是不是要开始讲时钟了.." "真聪明,越来越 ...

  9. Linux 内核中断内幕【转】

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/ 本文对中断系统进行了全面的分析与探讨,主要包括中断控制器.中断分类 ...

最新文章

  1. 一致性直线提取--Coherent Line Drawing
  2. DBCP使用BasicdataSource连接(两种单例模式-----饿汉和懒汉模式)
  3. DevExpress控件安装和初次使用图解
  4. 自定义eclipse启动画面
  5. 关于vue.js的部分总结
  6. aop简介-aop相关概念
  7. powershell 查看系统设备\device status
  8. golang flag包(命令行参数解析)
  9. ZJOI2007 棋盘制作
  10. matlab怎么画二维热力图_Tableau画日历热力图
  11. C++基础教程之日期和时间
  12. NSURLSession实现文件上传
  13. 深入理解viewport及相关属性的关系
  14. java 中uuid生成算法_UUID生成算法,UUID还是snowflake
  15. 记录点滴——2020年终总结
  16. java 二叉树转数组_java二叉树怎么转成数组?java怎么实现二叉树?
  17. 2021-2025年中国休闲凉鞋行业市场供需与战略研究报告
  18. 阿里云添加邮箱解析 实现邮件收发
  19. 如何利用CRM来维护客户关系?
  20. 追赶的腾讯云 | 深网

热门文章

  1. ug支持linux系统吗,UG12.02-linux,感兴趣的可以下载
  2. python学习入门(一)
  3. 8个成语接龙首尾相连_四字成语接龙连接8个
  4. 【Java】session.getAttribute出现[classes/:na]报错如何解决
  5. (20200410已解决)ValueError: Cannot convert non-finite values (NA or inf) to integer
  6. IPHONE苹果手机短信短消息备份导出,格式分析,数据库sqlite
  7. agv系统介绍_AGV物流系统工作流程及模块介绍
  8. arctanx麦克劳林公式推导过程_三角函数的求导过程
  9. 紫光同创国产FPGA学习之Fabric Configuration
  10. 北航计算机组成原理课程设计-2020秋 【系列完结】Verilog或ISE高级特性与自动化测试