linux 中断之tasklet

Table of Contents

1、tasklet 初始化 

2、tasklet 处理函数

3、tasklet的登记调度

参考代码


1、tasklet 初始化 

#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

func    //处理函数(耗时,不紧急的事情)

data  //给处理函数传递的参数,一般传递的指针

2、tasklet 处理函数

//tasklet处理函数
static void btn_tasklet_func(unsigned long data)
{
    int *pdata = (int *)data;
    printk("%s: mydata = %#x\n", __func__, *pdata);
}

在某些场合,需要在底半部实现休眠的工作,那么使用tasklet就没法满足这个需求,因为tasklet工作在中断上下文中,不能引起休眠。所以这个时候需要使用工作队列来将复杂,耗时的工作退后执行。

3、tasklet的登记调度

tasklet_schedule(&mytasklet)

一旦完成登记,中断处理函数就可以立即返回,CPU就会在适当的时间去执行底半部tasklet的处理函数,完成耗时,不紧急的事情。tasklet还是工作在中断(只不过是另外的定时中断)(类似软中断)

参考代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

//定义按键硬件相关的数据结构
struct button_resource {
    int irq;    //中断号
    char *name; //中断名称
};

//初始化按键信息
static struct button_resource btn_info[] = {
    [0] = {
        .irq = IRQ_EINT(0),
        .name = "KEY_UP"
    },
    [1] = {
        .irq = IRQ_EINT(1),
        .name = "KEY_DOWN"
    }
};

static int mydata = 0x55;

//tasklet处理函数
static void btn_tasklet_func(unsigned long data)
{
    int *pdata = (int *)data;
    printk("%s: mydata = %#x\n", __func__, *pdata);
}

//分配工作和延时工作
static struct work_struct btn_work;
static struct delayed_work btn_dwork;

//分配初始化tasklet
//名称为btn_tasklet,处理函数btn_tasklet_func,传递的参数是mydata地址
static DECLARE_TASKLET(btn_tasklet, 
        btn_tasklet_func, (unsigned long)&mydata);

//中断处理函数就是顶半部
static irqreturn_t button_isr(int irq, void *dev_id)
{
    //1.登记底半部的tasklet
    //cpu会在适当的时候执行对应的处理函数
    tasklet_schedule(&btn_tasklet);     
    printk("%s\n", __func__);
    return IRQ_HANDLED; //处理完毕
}

static int btn_init(void)
{
    int i;

    printk("register irq!\n");

    for (i = 0; i < ARRAY_SIZE(btn_info); i++)
        request_irq(btn_info[i].irq, button_isr, 
                IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,
                btn_info[i].name, &btn_info[i]);
    
    return 0;
}

static void btn_exit(void)
{
    int i;

    printk("unregister irq!\n");

    //注意注册中断传递的参数和释放中断传递的参数一定要一致!
    for(i = 0; i < ARRAY_SIZE(btn_info); i++)
        free_irq(btn_info[i].irq, &btn_info[i]);
}
module_init(btn_init);
module_exit(btn_exit);
MODULE_LICENSE("GPL");
发布了137 篇原创文章 · 获赞 106 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/shenlong1356/article/details/103290067