嵌入式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");