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); ... ... }
- Linux学习:中断下半部
- 个人学习笔记--linux中断下半部之软中断
- Linux内核中断学习
- linux中断学习
- Linux的中断学习
- Linux 中断学习之一
- Linux 中断学习及中断内核编程
- 中断 Linux 中断学习之前言篇
- Linux 中断学习之小试牛刀篇
- Linux 中断学习之小试牛刀篇
- Linux kernel 学习之中断
- Linux 中断学习之小试牛刀篇
- linux 中断学习之小试牛刀篇
- Linux中断处理学习笔记
- linux中断机制学习整理
- Linux 中断学习之小试牛刀篇
- linux kernel学习(2) - 中断
- Linux 中断学习之小试牛刀篇
- freemarker总结
- Ionic跨平台项目(十)从Ionic2升级到Ionic3
- 用VBA刷新ODBC连接表,也就是SQL SERVER表
- 创意吃鱼法
- python的re模块的函数(module-level functions)
- Linux学习:中断下半部
- 实现NEW_ARRAY/DELETE_ARRAY宏,模拟new[]/delete[]申请和释放数组
- Android的init过程详解(一)
- A3C经典源码
- 请记得为按钮规定 type 属性
- sendto 返回-1,errno为22,invalid argument的解决办法,mark一下
- Banner实现
- angularjs验证
- SQL Server 2008 R2 清空数据库中ldf日志文件