底半部之工作队列和tasklet,内核定时器。

1、软中断机制
  不能以模块形式出现
  使用起来不够灵活
2、tasklet
  核心数据结构
      struct tasklet_struct
      {
          function
          data
          ....
      }  
  1)定义tasklet变量
  2)初始化tasklet变量
     DECLARE_TASKLET //定义并初始化tasklet变量
 
  3)使用tasklet变量登记底半部
 
  注意事项:
      tasklet登记的底半部函数也是运行中断上下文中的
      也就意味着在底半部函数中不能调用引起阻塞或者
      睡眠的函数
  如果底半部函数中 必须调用引起阻塞或者睡眠的函数
  可以考虑使用工作队列的方式登记底半部

3、工作队列
  核心数据结构
     struct work_struct
     {
        //保存底半部函数的地址
        work_func_t func;
        ...
     }
  步骤:
     1)定义work变量
        struct work_struct btn_work;
     2)初始化work变量
        INIT_WORK(&btn_work, btn_work_func)
        
        以上两个步骤可以使用
        DECLARE_WORK(btn_work, btn_work_func)
            
     3)使用work变量登记底半部
        schedule_work(&btn_work);
     4)flush或者cancel
        bool flush_work(struct work_struct *work)
        cancel_work_sync(struct work_struct *work)   
        
   
   tasklet和work登记底半部的对比
     1)通过工作队列去登记底半部
        底半部函数工作于进程上下文中 不受限制
     2)如果同时使用了tasklet和工作队列登记了底半部
        一定是taklet登记的底半部函数最先被执行到          
     详细对比  tasklet_work.png          
 
  如果希望底半部函数登记后隔10s再去执行 实现方式
 
  核心数据结构:
      struct delayed_work {
    struct work_struct work;
    struct timer_list timer;
      };
  使用步骤:
      1)定义delayed_work变量
         struct delayed_work btn_dwork;
      2) 初始化delayed_work变量
         INIT_DELAYED_WORK(&btn_dwork, func)
      3) 使用delayed_work登记底半部
         schedule_delayed_work(&btn_dwork, 延时时间)  
      4)当卸载模块时 对已经登记并未得到执行的
         底半部做处理?
         a)flush 阻塞到指定dwork被执行到才返回
           flush_delayed_work(struct delayed_work *dwork)
         b)cancel 取消约定
           cancel_delayed_work(struct delayed_work *work)
             
   1)连续两次登记底半部 几次有效?哪次有效?
      
      只有1次有效
      第一次有效
   2)登记底半部后 ,直接卸载模块 内核崩溃 为什么?
     
4、内核定时器
  软件意义上的定时器
 
  系统时钟中断:CPU会周期性 不停地收到系统时钟中断信号
                执行系统时钟中断处理函数
                timer_event_init()
                {
                   setup_irq(info->irqno, &timer_event_irqaction);
                }
                timer_event_irqaction.timer_event_handler()
                {
                    /*硬件相关的事*/
                    
                    /*硬件无关动作*/
                    tick_periodic()
                    {
                        更新墙上时间
                        jiffies++;
                        给当前正在执行的线程时间片做--操作
                        判断当前线程的时间片是否耗尽
                        一旦耗尽重新做任务调度
                        选出新的线程放入CPU中运行
                    }
                }
   HZ:决定了1s产生的系统时钟中断的次数
      当前系统中HZ=1000
   tick, 系统时钟滴答
         tick = 1/HZ;
   jiffies, 记录自开机以来产生的系统时钟中断次数      
            unsigned int 类型
            
            例如HZ=1000
            在某个时间点1读取jiffies 为10000
            在某个时间点2读取jiffies 为20000
   
   内核定时器(软件意义上的)
      struct timer_list
      {
          //超时时间
          unsigned long expires;
          //定时时间到后执行的动作
          void (*function)(unsigned long);
          //指定调用function时传递的参数值
          unsigned long data;
          ...
      }
   定时器的使用步骤:
      1)定义一个timer_list变量
         struct timer_list led_timer;
      2) 初始化timer_list变量
         init_timer(&led_timer)
         
         led_timer.function=xxx
         led_timer.expires = xxx
         led_timer.data = xxx
     3) 启动定时器  
        
        void add_timer(struct timer_list *timer)
        
        int mod_timer(struct timer_list *timer, unsigned long expires)
     4) 修改定时器超时时间
        int mod_timer(struct timer_list *timer, unsigned long expires)
     5)取消定时器
        int del_timer(struct timer_list *timer)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <mach/platform.h>
#include <linux/delay.h>

typedef struct btn_desc
{
    int irq;//中断号
    char *name;//名称
}btn_desc_t;

btn_desc_t buttons[]=
{
    {IRQ_GPIO_A_START+28, "up"},
    {IRQ_GPIO_B_START+30, "down"},
    {IRQ_GPIO_B_START+31, "left"},
    {IRQ_GPIO_B_START+9,  "right"},

};
/*1 定义变量*/
//struct tasklet_struct btn_tasklet;

int mydata = 0x100;

void btn_tasklet_func(unsigned long data)
{
    int *pdata = (int *)data;
    
    printk("<1>" "enter %s: do no emergent things ...\n",__func__);
    printk("<1>"  "mydata=%#x\n", *pdata);
    (*pdata)++;
    msleep(1);
}
DECLARE_TASKLET(btn_tasklet, btn_tasklet_func, (unsigned long)&mydata);
irqreturn_t btn_isr(int irq, void *dev)
{
    btn_desc_t *pdata = dev;
    printk("<1>" "enter %s: do emergent things ...\n",__func__);
    printk("<1>" "%s key is pressed!\n", pdata->name);

    /*登记底半部*/
    printk("<1>" "register bottom half\n");
    tasklet_schedule(&btn_tasklet);
    printk("<1>" "exit from top half\n");
    return IRQ_HANDLED;
}
int __init btn_drv_init(void)
{
    /*2 初始化变量*/
    //tasklet_init(&btn_tasklet, btn_tasklet_func, 
      //           (unsigned long)(&mydata));
    int ret = 0;
    int i =0;
    for(; i<ARRAY_SIZE(buttons); i++)
    {
        ret = request_irq(buttons[i].irq, btn_isr,
                          IRQF_TRIGGER_FALLING,
                          buttons[i].name, 
                          &(buttons[i]));
        if(ret)
        {
            printk("<1>"  "request_irq failed!\n");
            while(i)
            {
                i--;
                free_irq(buttons[i].irq, buttons+i);
            }
            return ret;
        }
    }
    return 0;
}
void __exit btn_drv_exit(void)
{
    int i = 0;
    for(i=0; i<ARRAY_SIZE(buttons); i++)
    {
        free_irq(buttons[i].irq, buttons+i);
    }
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);
MODULE_LICENSE("GPL");
#include <linux/init.h> 
#include <linux/module.h>

#include <linux/interrupt.h> #include <mach/platform.h> #include <linux/delay.h> typedef struct btn_desc { int irq;//中断号 char *name;//名称 }btn_desc_t; btn_desc_t buttons[]= { {IRQ_GPIO_A_START+28, "up"}, {IRQ_GPIO_B_START+30, "down"}, {IRQ_GPIO_B_START+31, "left"}, {IRQ_GPIO_B_START+9, "right"}, }; /*1 定义一个work变量*/ struct work_struct btn_work; irqreturn_t btn_isr(int irq, void *dev) { btn_desc_t *pdata = dev; printk("<1>" "enter %s: do emergent things ...\n",__func__); printk("<1>" "%s key is pressed!\n", pdata->name); /*登记底半部*/ printk("<1>" "register bottom half\n"); schedule_work(&btn_work); printk("<1>" "exit from top half\n"); return IRQ_HANDLED; } void btn_work_func(struct work_struct *work) { printk("<1>" "enter %s: do no emergent things....\n", __func__); } int __init btn_drv_init(void) { int ret = 0; int i =0; for(; i<ARRAY_SIZE(buttons); i++) { ret = request_irq(buttons[i].irq, btn_isr, IRQF_TRIGGER_FALLING, buttons[i].name, &(buttons[i])); if(ret) { printk("<1>" "request_irq failed!\n"); while(i) { i--; free_irq(buttons[i].irq, buttons+i); } return ret; } } /*2 初始化work变量*/ INIT_WORK(&btn_work, btn_work_func); return 0; } void __exit btn_drv_exit(void) { int i = 0; for(i=0; i<ARRAY_SIZE(buttons); i++) { free_irq(buttons[i].irq, buttons+i); } } module_init(btn_drv_init); module_exit(btn_drv_exit);
MODULE_LICENSE("GPL");
 

 

#include "../../global.h"

#include <linux/interrupt.h>
#include <mach/platform.h>
#include <linux/delay.h>

typedef struct btn_desc
{
    int irq;//中断号
    char *name;//名称
}btn_desc_t;

btn_desc_t buttons[]=
{
    {IRQ_GPIO_A_START+28, "up"},
    {IRQ_GPIO_B_START+30, "down"},
    {IRQ_GPIO_B_START+31, "left"},
    {IRQ_GPIO_B_START+9,  "right"},

};
/*1 定义一个work变量*/
struct work_struct btn_work;
struct delayed_work btn_dwork;

irqreturn_t btn_isr(int irq, void *dev)
{
    btn_desc_t *pdata = dev;
    printk("<1>" "enter %s: do emergent things ...\n",__func__);
    printk("<1>" "%s key is pressed!\n", pdata->name);

    /*登记底半部*/
    printk("<1>" "register bottom half\n");
    //schedule_work(&btn_work);
    schedule_delayed_work(&btn_dwork, 10*HZ);
    printk("<1>" "exit from top half\n");
    return IRQ_HANDLED;
}
void btn_work_func(struct work_struct *work)
{
    printk("<1>" "enter %s: do no emergent things....\n", __func__);
    msleep(1);
}
void btn_dwork_func(struct work_struct *work)
{
    printk("<1>" "enter %s: do no emergent things....\n", __func__);
}
int __init btn_drv_init(void)
{
    int ret = 0;
    int i =0;
    for(; i<ARRAY_SIZE(buttons); i++)
    {
        ret = request_irq(buttons[i].irq, btn_isr,
                          IRQF_TRIGGER_FALLING,
                          buttons[i].name, 
                          &(buttons[i]));
        if(ret)
        {
            printk("<1>"  "request_irq failed!\n");
            while(i)
            {
                i--;
                free_irq(buttons[i].irq, buttons+i);
            }
            return ret;
        }
    }
    /*2 初始化work变量*/
    INIT_WORK(&btn_work, btn_work_func);
    INIT_DELAYED_WORK(&btn_dwork,btn_dwork_func);
    return 0;
}
void __exit btn_drv_exit(void)
{
    int i = 0;
    for(i=0; i<ARRAY_SIZE(buttons); i++)
    {
        free_irq(buttons[i].irq, buttons+i);
    }
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);

 

#include "../../global.h"
#include <linux/gpio.h>
#include <mach/platform.h>

#define LED1    (PAD_GPIO_C+12)

/*定义timer变量*/
struct timer_list led_timer;

void led_timer_func(unsigned long data)
{
    gpio_set_value(LED1, data);
    
    led_timer.data = !data;
    mod_timer(&led_timer, jiffies+1*HZ);
}
int __init led_drv_init(void)
{
    /*申请GPIO管脚*/
    gpio_request(LED1, "led1");
    /*使用管脚*/
    gpio_direction_output(LED1, 0);
    /*初始化定时器*/
    init_timer(&led_timer);
    led_timer.function = led_timer_func;
    led_timer.expires = jiffies + 1*HZ;
    /*要设置为的管脚电平状态*/
    led_timer.data = 1;
    /*启动定时器*/
    add_timer(&led_timer);
    //mod_timer(&led_timer, led_timer.expires);
    return 0;
}
void __exit led_drv_exit(void)
{
    gpio_free(LED1);
}
module_init(led_drv_init);
module_exit(led_drv_exit);

 

 

posted @ 2019-11-14 17:47  刘大侠GG_B  阅读(507)  评论(0编辑  收藏  举报