zoukankan      html  css  js  c++  java
  • Linux 中断下半部

    为什么使用中断下半部?

    中断执行的原则是要以最快的速度执行完,而且期间不能延时和休眠!


    可是现实中,中断中可能没办法很快的处理完需要做的事,或者必须用到延时和休眠,因此引入了中断下半部。

    中断中处理紧急事务,其余的交给中断下半部处理。


    怎样将代码合理有效的分配给中断和中断下半部?(以后发现新的再添加)

    与硬件有关的给中断处理程序(比如按键中断后判断电平),其余的给中断下半部;

    紧急事务给中断处理程序,相对不紧急的给中断下半部;

    不能被中断的给中断处理程序,剩余的给中断下半部;

    没有延时或休眠的给中断处理程序,有休眠或延时的给中断下半部(延时只能用工作队列);


    中断下半部有三种实现方法:软中断,小任务,工作队列

    1、软中断---softirq

    软中断一般用在内核级别的代码中,现在不讨论


    2、小任务---tasklet

    tasklet中不能延时或休眠


    struct tasklet_struct
    {
        struct tasklet_struct *next; 
        unsigned long state;             // tasklet 状态
        atomic_t count;                     // 锁计数器
        void (*func)(unsigned long);  // tasklet 处理函数
        unsigned long data;               // 传递给 tasklet 处理函数的参数
    };


    // 功能:初始化 tasklet

    // 参数1:被初始化的 tasklet

    // 参数2:中断下半部函数入口

    // 参数3:传递给中断下半部函数的参数

    static inline void tasklet_init(struct tasklet_struct *tasklet, void (*func)(unsigned long), unsigned long data);


    // 功能:启动下半部

    // 参数:tasklet

    static inline void tasklet_schedule(struct tasklet_struct *tasklet);


    // 功能:释放 tasklet

    // 参数: tasklet

    void tasklet_kill(struct tasklet_struct *t);


    struct key_event
    {
        int name;
        int value;
    };
    
    struct samsung
    {
        int major;
        struct class *cls;
        struct device *dev;
        struct key_event key;
        struct tasklet_struct tasklet;
    };
    
    static struct samsung *key_dev;
    
    void tasklet_key_irq(unsigned long data)
    {
        printk("___^_^___ %s
    ", __FUNCTION__);
    }
    
    // 中断处理程序,多个按键可以根据 irqno 区分  
    irqreturn_t key_irq_handler(int irqno, void *dev_id)  
    {  
        int ret;  
      
        printk("------------%s-------------
    ", __FUNCTION__);  
          
        ret = gpio_get_value(key_info[i].key_gpio);  
        ret ? (key_dev->key.value = 0) : (key_dev->key.value = 1);  
        printk("key = %d status = %d
    ", key_dev->key.name, key_dev->key.value);  
    
        tasklet_schedule(&key_dev->tasklet);
      
        // 返回值一定要是 IRQ_HANDLED  
        return IRQ_HANDLED;  
    }  
      
    static int __init key_drv_init(void)  
    {  
        ... ...  
        key_dev->irqno = IRQ_EINT(2);  
        ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "key_eint", NULL);
        tasklet_init(&key_dev->tasklet, tasklet_key_irq, 110);
        ... ...  
    }  
      
    static int __exit key_drv_exit(void)  
    {  
        ... ...  
        tasklet_kill(&key_dev->tasklet);
        free_irq(key_dev->irqno,NULL);  
        ... ...  
    } 

    3、工作队列---work queue

    work queue 中不能延时或休眠


    // 功能:初始化work

    // 参数1:被初始化的work

    // 参数2:中断下半部的入口函数

    INIT_WORK(_work, _func)


    // 功能:启动下半部

    // 参数:work

    int schedule_work(struct work_struct *work);


    // 功能:释放work

    // 参数:work

    bool cancel_work_sync(struct work_struct *work);


    struct key_event
    {
        int name;
        int value;
    };
    
    struct samsung
    {
        int major;
        struct class *cls;
        struct device *dev;
        struct key_event key;
        struct work_struct work;
    };
    
    static struct samsung *key_dev;
    
    void work_key_irq(struct work_struct *work)
    {
        printk("___^_^___ %s
    ", __FUNCTION__);
    }
    
    // 中断处理程序,多个按键可以根据 irqno 区分  
    irqreturn_t key_irq_handler(int irqno, void *dev_id)  
    {  
        int ret;  
      
        printk("------------%s-------------
    ", __FUNCTION__);  
          
        ret = gpio_get_value(key_info[i].key_gpio);  
        ret ? (key_dev->key.value = 0) : (key_dev->key.value = 1);  
        printk("key = %d status = %d
    ", key_dev->key.name, key_dev->key.value);  
    
        schedule_work(&key_dev->work);
      
        // 返回值一定要是 IRQ_HANDLED  
        return IRQ_HANDLED;  
    }  
    
    static int __init key_drv_init(void)  
    {  
        ... ...  
        key_dev->irqno = IRQ_EINT(2);  
        ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "key_eint", NULL);
        INIT_WORK(&key_dev->work, work_key_irq);
        ... ...  
    }  
      
    static int __exit key_drv_exit(void)  
    {  
        ... ...  
        cancel_work_sync(&key_dev->work);
        free_irq(key_dev->irqno,NULL);  
        ... ...  
    }
    
    
  • 相关阅读:
    以相同类型的一个对象初始化另一个对象
    java之StringBuilder类详解
    java之StringBuffer类详解
    jquery在线引用地址
    java之抽象类
    Oracle动态执行表不可访问
    libvirt-qemu-TLS加密虚拟机传输实例分析
    查看系统是虚拟机还是物理机
    WorkStation 虚拟机迁移到 ESXi
    Django入门------常见问题
  • 原文地址:https://www.cnblogs.com/lialong1st/p/7756672.html
Copyright © 2011-2022 走看看