在中断中,分为中断上文和下文(tasklet),在request_irq中注册的函数为中断函数,一般是中断上文,中断下文一般用于处理一些复杂耗时间的程序。
1.中断上下文
1.1 tasklet结构体
struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); unsigned long data; };
成员 | 描述 |
*next | tasklet链表中下一个tasklet |
state | tasklet 的状态 TASKLET_STATE_SCHED 已经被调度,将要运行 TASKLET_STATE_RUN 正在运行 |
count | tasklet的引用计数,如果它不为0,则tasklet被禁止,不允许执行;只有当它为0时,tasklet才被激活,并且在被设置为挂起(TASKLET_STATE_SCHED)状态时,该tasklet才能够被执行。 |
(*func)(unsigned long) | tasklet的处理函数 |
data | tasklet fun的参数 |
1.2 tasklet 初始化
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data);
参数 | 描述 |
*t | tasklet结构体指针 |
(*func)(unsigned long) | tasklet处理函数 |
data | tasklet参数 |
1.3 tasklet 调度
static inline void tasklet_schedule(struct tasklet_struct *t)
1.4 调用过程
1)定义tasklet结构体
2)初始化tasklet
3)编写tasklet function
4)调度tasklet
5)注销tasklet
1.5 伪代码
struct tasklet_struct key_task; void key_task_fun(unsigned long data) //tasklet function { printk("key tasklet fun is action!\n"); } irqreturn_t key_fun(int irq,void *args) //interrupt function { printk(KERN_ERR "test fun is action!!\n"); tasklet_schedule(&key_task); //开始调度tasklet return IRQ_HANDLED; } int led_probe(struct platform_device *pdev){ int ret; gpio_res = gpiod_get_index(&pdev->dev,"key",0,GPIOD_OUT_LOW); //获取名为key的gpio属性 ret = gpiod_direction_input(gpio_res); //将引脚设置为输入 irq = of_irq_get(pdev->dev.of_node, 0); //通过设备树结点获取中断信息 ret = request_irq(irq, key_fun, IRQF_TRIGGER_RISING, "key_interrupt", NULL); //申请中断号 tasklet_init(&key_task,key_task_fun, 0); //初始化tasklet //注册设备号 //创建class //生成设备节点 return 0; } static void charDev_exit(void) { //释放gpio tasklet_kill(&key_task); //注销tasklet //释放irq //注销设备节点 //注销类 //注销设备号 }