嵌入式LINUX驱动学习之7中断相关(三)底半部机制之work_struct

嵌入式LINUX驱动学习之7中断相关(三)底半部机制之work_struct


work_struct工作在进程上下文,允许进行休眠操作

一、头文件、函数及说明

struct work_struct {
    
    
        atomic_long_t data;
        struct list_head entry; // 内核维护的工作队列列表
        work_func_t func;  //延迟处理函数 
#ifdef CONFIG_LOCKDEP
        struct lockdep_map lockdep_map;
#endif
};
/*用于初始化工作队列*/
#define INIT_WORK(_work, _func)                                 \
        do {                                                    \
                __INIT_WORK((_work), (_func), 0);               \
        } while (0)
/*
    _work : 结构体对象;
    _func : 延迟处理函数;
*/
//配套函数:chedule_work()
extern int schedule_work(struct work_struct *work);

二、代码举例

#include <linux/init.h>
#include <linux/module.h>
#include <cfg_type.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
/*定义按键信息*/
struct btn_src {
    
    
    char *name ;
    int gpio;
};
struct btn_src btn_info[] = {
    
    
    {
    
    
        .name = "BTN1",
        .gpio = PAD_GPIO_A + 28
    },
    {
    
    
        .name = "BTN2",
        .gpio = PAD_GPIO_B + 30
    },
    {
    
    
        .name = "BTN3",
        .gpio = PAD_GPIO_B + 31
    },
    {
    
    
        .name = "BTN4",
        .gpio = PAD_GPIO_B + 9
    }
};
/*定义LED灯信息*/
struct led_src{
    
    
    char *name;
    int gpio;
};
struct led_src led_info[] = {
    
    
    {
    
    
        .name = "LED1",
        .gpio = PAD_GPIO_B + 26
    },
    {
    
    
        .name = "LED2",
        .gpio = PAD_GPIO_C + 11
    },
    {
    
    
        .name = "LED3",
        .gpio = PAD_GPIO_C + 7
    },
    {
    
    
        .name = "LED4",
        .gpio = PAD_GPIO_B + 12
    }
};
struct led_src *g_led_state;//定义全局变量保存LED灯中断触发后的状态
/*基于工作队列机制,实现的延迟处理函数*/
static void work_func (struct work_struct *wrok){
    
    
    ssleep(1);//进程休眠1秒后继续执行
    printk("%s, %s状态为%s \n",__func__,\
            g_led_state ->name,\
            gpio_get_value(g_led_state -> gpio) ? "关":"开");
}
struct work_struct work_s;//定义工作队列对象
/*中断处理函数*/
static irqreturn_t func_irq(int irq,void * argv){
    
    
    schedule_work(&work_s);//登记work_s对象基于工作队列,即底半部,可以延后执行。
    g_led_state = (struct led_src *) argv;
    //设置对应GPIO的电平,如果之前是高电平,现在就为低电平 ,如果之前为低电平,现在就为高电平。
    gpio_set_value(g_led_state -> gpio,1-gpio_get_value(g_led_state -> gpio));
    return IRQ_HANDLED;
}

static int work_btn_led_init(void){
    
    
    int i = 0;
    for(; i < ARRAY_SIZE(btn_info);i++){
    
    
        gpio_request(btn_info[i].gpio,btn_info[i].name);
        gpio_direction_input(btn_info[i].gpio);
        request_irq(gpio_to_irq(btn_info[i].gpio),func_irq,\
                    IRQF_TRIGGER_LOW,btn_info[i].name,&led_info[i]);
        gpio_request(led_info[i].gpio,led_info[i].name);
        gpio_direction_output(led_info[i].gpio,1);
    }
    INIT_WORK(&work_s,work_func);//初始化工作队列对象和对应的延迟处理函数

    return 0;
}
static void work_btn_led_exit(void){
    
    
    int i = 0;
    for(; i< ARRAY_SIZE(btn_info);i++){
    
    
        free_irq(gpio_to_irq(btn_info[i].gpio),&led_info[i]);
        gpio_free(btn_info[i].gpio);
        gpio_set_value(led_info[i].gpio,1);
        gpio_free(led_info[i].gpio);
    }

}
module_init(work_btn_led_init);
module_exit(work_btn_led_exit);
MODULE_LICENSE("GPL");

猜你喜欢

转载自blog.csdn.net/weixin_47273317/article/details/107941845