字符设备驱动第十三课----上半部与底半部机制

概念

优先级: 硬件中断->软件中断->内核->用户线程
# 概念
优先级: 硬件中断->软件中断->内核->用户线程
理想中的中断函数应该精简,耗时最短;但现实中的事物偏偏是复杂耗时的。
这样复杂耗时的操作我们想不用中断能不能实现,但我们又无法预知他什么时候到来,所以还是必须用中断。
中庸之道,在上面两种方案中糅合折中,就得出了“上半部分”与“下半部分”的概念。
中断嘛,还是要用滴,只不过现在我们只把他当“引子”,告诉说:“有个这样的中断产生了,'工作队列'你去处理下,我先撤啦!”。这就是“上半部分”
剩余的复杂耗时的工作就在“工作队列”中去做。这就属于“下半部分”

下半部分:

耗时,不太紧急,但又要优先于普通进程的部分

软中断

Tasklet

工作队列

定义:
<include/linux/workqueue.h>

struct work_struct {
    atomic_long_t data;       //
    struct list_head entry;   //队头
    work_func_t func;         //回调函数
#ifdef CONFIG_LOCKDEP
    struct lockdep_map lockdep_map;
#endif
};
typedef void (*work_func_t)(struct work_struct *work);
初始化
/*
* 功能:初始化工作队列,将回电函数加到工作队列中
* 输入参数:struct work_struct *work:工作队列
*          int onstack:             回调函数指针
* 返回值:none
*/
void __init_work(struct work_struct *work, int onstack);
调度函数
/*
* 功能:调度工作队列,实质并不是去调回调函数,而是标记他为运行态(即唤醒它)。
* 故几篇快速多次按键,任务函数也不一定调很多次,只是在它休眠时调用该调度函数会唤醒他
* 输入参数:struct work_struct *work:工作队列
* 返回值:boll
*/
bool schedule_work(struct work_struct *work)

上半部分

紧急,不耗时的任务,优先级最高的。

硬件中断

# 工程实例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>

#include <linux/interrupt.h>
#include <linux/gpio.h>

#include <linux/workqueue.h>

#include <linux/delay.h>

static int irq;
static int gpio;
static struct work_struct ws;//定义一个工作队列

static irqreturn_t handler_t(int irq, void *dev)//自定义的中断服务函数
{
    printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);
    schedule_work(&ws);  //调度,使工作队列中的任务变为可运行态,就是改变一个标志位的事,标志一下马上返回
                         //,并不是要等工作队列中的任务运行完才返回

    return IRQ_HANDLED;
}

void work_func(struct work_struct *work)//自定义的工作队列的回调函数
{
    printk(KERN_INFO "%s : %s : %d - entry.\n", __FILE__, __func__, __LINE__);
    ssleep(3);
    printk(KERN_INFO "%s : %s : %d - leave.\n", __FILE__, __func__, __LINE__);
}

static int __init demo_init(void)
{
    struct device_node *np = NULL;
    int ret;

    printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);

    INIT_WORK(&ws, work_func);//初始化工作队列,绑定回调函数

    np = of_find_node_by_name(NULL, "key");//从设备树中找到key这个设备
    if(NULL == np){
        return -EINVAL;
    }

    gpio = of_get_named_gpio(np, "key-intr", 0);//从np这个设备中找出属性名为key-intr的第0项gpio引脚
    if(gpio_is_valid(gpio)){
        ret = gpio_request_one(gpio, GPIOF_IN, "key-intr");//将引脚复用功能设为外部中断
        if(ret){
            printk(KERN_INFO "%s : %s : %d - gpio_request_one fail.\n", 
                __FILE__, __func__, __LINE__);
            return ret;
        }

        irq = gpio_to_irq(gpio);//为gpio引脚申请一个软中断号
        if(0 > irq){
            printk(KERN_INFO "%s : %s : %d - gpio_to_irq fail.\n", 
                __FILE__, __func__, __LINE__);
            return irq;
        }

        ret = request_irq(irq, handler_t, IRQF_TRIGGER_RISING, "demo", NULL);//绑定回调函数并将软中断号注册进内核
        if(ret){
            printk(KERN_INFO "%s : %s : %d - request_irq fail.\n", 
                __FILE__, __func__, __LINE__);
            return ret;
        }
    }else{
        printk(KERN_INFO "%s : %s : %d - of_get_named_gpio fail.\n", 
            __FILE__, __func__, __LINE__);
        return gpio;
    }

    return 0;
}

static void __exit demo_exit(void)
{
    printk(KERN_INFO "%s : %s : %d - ok.\n", __FILE__, __func__, __LINE__);
    free_irq(irq, NULL);//释放中断号
    gpio_free(gpio);//释放gpio,即引脚复用功能还原
}

module_init(demo_init);
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Farsight");
MODULE_DESCRIPTION("Demo for kernel module");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xxgui1992

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值