<一> 中断处理流程例如以下:



1、发生中断时,CPU运行异常向量vector_irq的代码。

2、在vector_irq里面。终于会调用中断处理的总入口函数asm_do_IRQ。

3、asm_do_IRQ依据中断号调用irq_desc数组项中的handle_irq。

4、hadnle_irq会使用chip成员中的函数来设置硬件,比方清除中断、禁止中断、又一次使能中断等。

5、handle_irq逐个调用用户在action链表中注冊的处理函数。

      <二>安装中断处理例程

注冊/释放中断的函数:

int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs*), unsigned long flags,

const char *dev_name, void *dev_id);

void free_irq(unsigned int irq, void *dev_id);

unsigned int irq:申请的中断号

irqreturn_t (*handler)(int, void *, struct pt_regs*):安装的中断处理函数指针

unsigned long flags:中断管理有关的位掩码选项,中断的触发方式。如SA_INTERRUPT、SA_SHIRQ等

const char *dev_name:传递给request_irq的字符串。中断名字

void *dev_id:该指针仅仅用于共享的中断信号线。没有使用共享时,dev_id设置为NULL。

中断处理例程能够在驱动程序初始化时或设备第一次打开时安装。但考虑中断资源有限,调用request_irq的正确位置应该是在设备第一次打开、硬件被告知产生中断之前。调用free_irq的位置是最后一次关闭设备、硬件被告知不用再中断处理器之后。

    <三>实现中断处理例程

中断处理例程事实上也是一个C函数程序,但因为发生在中断时间内,所以它有下面特点:

1、处理例程不能向用户空间发送或者接收数据,由于它不是在不论什么进程的上下文中运行的。

2、处理例程不能做不论什么可能发生休眠的操作,比如调用wait_event,锁住一个信号量等。

3、处理例程不能调用schdule函数。

中断处理例程的功能就是将有关中断接收的信息反馈给设备,并依据正在服务的中断的不同含义对数据进行对应的读或写。它的一个典型任务就是:假设中断通知进程所等待的事件已经发生,比方新的数据到达,就会唤醒在该设备上休眠的进程。

不管是高速还是慢速处理例程,程序猿都应该编写运行时间尽可能短的处理例程。假设须要运行一个长时间的计算任务。最好的方法是使用tasklet或者工作队列在更安全的时间内调度计算任务。

中断处理例程irqreturn_t (*handler)(int, void *, struct pt_regs*)的參数及返回值:

int irq:中断号

void *dev_id:一种客户数据类型即驱动程序可用的私有数据,传递给request_irq函数的void *參数会在中断发生时作为參数被传回处理例程。通常,我们会为dev_id传递一个指向自己设备的数据结构指针。比如:

static irqreturn_t sample_interrupt(int irq, void *dev_id, struct pt_regs)
{
struct sample_dev *dev = dev_id;
……
}
/*与该处理例程相关联的典型open代码例如以下所看到的:*/
static void sample_open(struct inode *inode, struct file *filp)
{
struct sample_dev *dev = hwinfo + MINOR(inode->i_rdev);
request_irq(dev->irq, sample_interrupt, 0, "sample", (void *)dev);
……
return 0;
}

struct pt_reg *regs:非常少使用。

返回值有三种:IRQ_HANDLED。IRQ_NONE;IRQ_RETVAL(handled);

禁用和启用中断:

有时设备驱动程序必须在一个时间内堵塞中断的发生。

中断的禁用分为禁用单个中断和禁用全部中断。

禁用单个中断

#include <asm/irq.h>

void disable_irq(int irq);

void disable_irq_nosync(int irq);

void enable_irq(int irq);

禁用全部中断

#include <asm/irq.h>

void local_irq_save(unsigned long flags);

void local_irq_disable(void);

void local_irq_restore(unsigned long flags);

void local_irq_enable(void);

      <四>顶半部和底半部

中断处理的一个主要问题是如何在处理例程内完毕耗时的任务。对应一次设备中断须要完毕一定数量的工作。可是中断处理例程须要尽快结束而不能使终端堵塞的时间过长,这两个需求彼此冲突。

Linux通过将中断处理例程分成两部分来解决问题。

称为顶半部的部分。是实际响应中断的例程,也就是用request_irq注冊的中断例程;而所谓的底半部是一个被顶半部调度。并在稍后更安全的时间内运行的例程。顶半部处理例程和底半部处理例程之间最大的不同,就是当底半部处理例程运行时,全部的中断都是打开的——这就是所谓的更安全时间内运行。

典型的情况是顶半部保存设备的数据到一个设备特定的缓冲区并调度它的底半部。然后退出,这个操作是很快的。然后。底半部运行其它必要的工作。比如唤醒进程、启动另外的I/O操作等等。这样的方式同意在底半部工作期间,顶半部还能够继续为新的中断服务。

Linux内核有两种不同机制能够用来实现底半部处理:tasklet和工作队列。tasklet一般是底半部处理的优选机制,由于它很快,可是全部的tasklet代码必须是原子的。工作队列具有更高的延迟,但同意休眠。

tasklet:tasklet是一个能够由系统决定的安全时刻在软件中断上下文被调度执行的特殊函数。

使用宏DECLARE_TASKLET声明tasklet:DECLARE_TASKLET(name, function, data);当中的參数name是给tasklet起的名字,function是运行tasklet时调用的函数(它带有一个unsigned long型的參数而且返回void)。data是一个用来传递给tasklet函数的unsigned long类型的值。

函数tasklet_schedule用来调度一个tasklet执行。示比例如以下:

void example_do_tasklet(unsigned long)
{
……
}
DECLARE_TASKLET(example_tasklet, example_do_tasklet, 0); irqreturn_t example_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
……
tasklet_schedule(&example_tasklet);
……
}

工作队列:工作队列会在将来的某个时间、在某个特定的工作者进程上下文中调用一个函数。由于工作队列函数执行在进程上下文中。因此可在必要时休眠。

工作队列一般程序编写示比例如以下:

static struct work_struct example_workqueue;
INIT_WORK(&example_workqueue, (void (*)(void *))example_do_tasklet, NULL);
irqreturn_t example_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
……
schedule_work(&example_workqueue);
……
}

      <五>中断共享

安装共享的处理例程:就像普通非共享的中断一样,共享的中断也是通过request_irq安装的,但有两处不同:

1、请求中断时,必须指定flags參数中的SA_SHIRQ位。

2、dev_id參数必须是唯一的。

不论什么指定模块地址空间的指针都能够使用。但dev_id不能设置成NULL。

当请求一个共享中断时,假设满足以下条件之中的一个,那么request_irq就会成功:

1、中断信号线空暇

2、不论什么已经注冊了该中断信号线的处理例程也标识了IRQ是共享的。

使用共享处理例程的驱动程序须要小心一件事情:不能使用enable_irq和disable_irq。

LINUX设备驱动程序笔记(五)中断处理的更多相关文章

  1. LINUX设备驱动程序笔记(一)设备驱动程序简单介绍

    <一>:设备驱动程序的作用 从一个角度看,设备驱动程序的作用在于提供机制,而不是策略. 在编写驱动程序时,程序猿应该特别注意以下这个基本概念:编写訪问硬件的内核代码时,不要给用户强加不论什 ...

  2. LINUX设备驱动程序笔记(三)字符设备驱动程序

          <一>.主设备号和次设备号        对字符设备的訪问时通过文件系统内的设备名称进行的.那些设备名称简单称之为文件系统树的节点,它们通常位于/dev文件夹. 字符设备驱动程 ...

  3. Linux设备驱动程序 第三版 读书笔记(一)

    Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...

  4. 【转】linux设备驱动程序中的阻塞机制

    原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...

  5. linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

    原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...

  6. Linux设备驱动程序学习之分配内存

    内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...

  7. Linux设备驱动程序学习----2.内核模块与应用程序的对比

    内核模块与应用程序的对比 更多内容请参考Linux设备驱动程序学习----目录 1. 内核模块与应用程序的对比 内核模块和应用程序之间的不同之处: 大多数中小规模的应用程序是从头到尾执行单个任务,而模 ...

  8. Linux设备驱动程序学习----目录

    目录 设备驱动程序简介 1.设备驱动程序简介 构造和运行模块 2.内核模块和应用程序的对比 3.模块编译和装载 4.模块的内核符号表  5.模块初始化和关闭  6.模块参数  7.用户空间编写驱动程序 ...

  9. 教你写Linux设备驱动程序:一个简短的教程

    教你写Linux设备驱动程序:一个简短的教程 http://blog.chinaunix.net/uid-20799298-id-99675.html

随机推荐

  1. hihocoder#1046 K个串 可持久化线段树 + 堆

    首先考虑二分,然后发现不可行.... 注意到\(k\)十分小,尝试从这里突破 首先用扫描线来处理出以每个节点为右端点的区间的权值和,用可持久化线段树存下来 在所有的右端点相同的区间中,挑一个权值最大的 ...

  2. bzoj4641 基因改造 KMP / hash

    依稀记得,$NOIP$之前的我是如此的弱小.... 完全不会$KMP$的写法,只会暴力$hash$.... 大体思路为把一个串的哈希值拆成$26$个字母的位权 即$hash(S) = \sum\lim ...

  3. Shell中EOF内容转义

    1.在$符号前面加反斜杠,如: cat > test.sh <<EOF \$test EOF 如果不加,将转成实际的值. 2.给EOF加个双引号,如: cat > test.s ...

  4. 特殊字符\u2028导致的Javascript脚本异常

    这原本是个小错误,但排查花了不少时间,因此写下来和大家分享一下. 起因 通过Ajax动态从后台读取文章内容,并显示在页面上,加载到某篇文章的时候,报javascript语法错误,无法显示文章内容. A ...

  5. ParseFloat有超长的小数位数的解决

    描述一下sum=parseFloat(num1)+parseFloat(num2),这个个sum=113.32000000000002,最后用了个Math.round(sum* 100)/100,解决 ...

  6. TCP Socket的一些行为

    几个重要的结论: 1. read总是在接收缓冲区有数据时立即返回,而不是等到给定的read buffer填满时返回. 只有当receive buffer为空时,blocking模式才会等待,而nonb ...

  7. .Net高级技术——IDisposable

    IDisposable概述 GC(垃圾收集器)只能回收托管(Managed)内存资源,对于数据库连接.文件句柄.Socket连接等这些资源(非托管资源,UnManaged)就无能为例,必须程序员自己控 ...

  8. 使用Bootstrap 3开发响应式网站实践02,轮播

    本篇体验图片轮播.html部分为: <div class="carousel slide" id="myCarousel" > <!--Ind ...

  9. 咏南WEB框架群集

    咏南WEB框架群集 咏南WEB框架支持群集部署,支持负载均衡和自动故障转移. 咏南WEB群集部署在阿里云服务器上面. 在线测试:http://47.106.93.126:9999/

  10. Scheduled Jobs with Custom Clock Processes in Java with Quartz and RabbitMQ

    原文地址: https://devcenter.heroku.com/articles/scheduled-jobs-custom-clock-processes-java-quartz-rabbit ...