Linux学习:中断下半部

来源:互联网 发布:按键精灵编程语言 编辑:程序博客网 时间:2024/06/05 12:44

为什么使用中断下半部?

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


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

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


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

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

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

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

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


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

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\n", __FUNCTION__);}// 中断处理程序,多个按键可以根据 irqno 区分  irqreturn_t key_irq_handler(int irqno, void *dev_id)  {      int ret;        printk("------------%s-------------\n", __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\n", 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\n", __FUNCTION__);}// 中断处理程序,多个按键可以根据 irqno 区分  irqreturn_t key_irq_handler(int irqno, void *dev_id)  {      int ret;        printk("------------%s-------------\n", __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\n", 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);      ... ...  }

原创粉丝点击