在中断中,分为中断上文和下文(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
//注销设备节点
//注销类
//注销设备号
}