📄 (ldd) ch09-中断处理(上)(转载).htm
字号:
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="http://joyfire.net/about.htm"><FONT
color=#ffffff>关于</FONT></A></DIV></TD>
<TD width="1%" height=4>
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="mailto:joyfire@sina.com"><FONT
color=#ffffff>联系</FONT></A></DIV></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE borderColor=#666666 cellPadding=2 width="90%" align=center border=2>
<TBODY>
<TR>
<TD bgColor=#000000>
<P align=center><A href="http://joyfire.net/lsdp/index.htm"><FONT
color=#ffffff size=2>目录页</FONT></A> | <A
href="http://joyfire.net/lsdp/10.htm"><FONT color=#ffffff
size=2>上一页</FONT></A> | <A href="http://joyfire.net/lsdp/12.htm"><FONT
color=#ffffff size=2>下一页</FONT></A></P>
<P align=center><FONT face=黑体 color=#ffffff size=6>(LDD) Ch09-中断处理(上)(转载)
</FONT></P><SPAN style="LINE-HEIGHT: 1; LETTER-SPACING: 0pt"><FONT
color=#ffffff size=3>
<P>发信人: Altmayer (alt), 信区: GNULinux<BR>标 题: (LDD) Ch09-中断处理(上)(转载)<BR>发信站: 饮水思源 (2001年12月13日08:57:25 星期四), 站内信件<BR> <BR>【 以下文字转载自 <FONT
color=#00ff00>UNIXpost </FONT>讨论区 】<BR>【 原文由<FONT
color=#00ff00> altmayer.bbs@bbs.nju.edu.cn,</FONT> 所发表 】<BR> <BR>【 以下文字转载自 <FONT
color=#00ff00>altmayer </FONT>的信箱 】<BR> <BR> <BR>第9章 中断处理<BR> <BR> <BR> 中断是硬件管理的最终资源。众所周知,设备利用中断来通知软件可以对它进行<BR>操作了。Linux为中断处理提供了很好的接口。事实上中断处理的接口如此之好,以至于<BR>编写和安装中断处理程序几乎和编写其它核心函数一样容易。但是由于中断处理程序和<BR>系统的其它部分是异步运行的,使用时要注意一些事项。<BR> <BR> <BR> <BR> 本章的示例代码使用并口来产生中断。因此,如果你想运行测试程序,你必须给<BR>你的电烙铁接上电源,即使在上一章的例子程序中你拒绝这样做。<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR> <BR> <BR> 我们用上一章的short模块来示范如何使用中断。这个模块的名字,short,实际<BR>上是指 short int(这是C语言,不是吗?),提醒我们它要对中断(interrupt)进行处理<BR>。<BR> <BR>准备并口<BR> 虽然我在第8章“硬件管理”的“使用并口”一节已经提到,并口很简单,但它<BR>也会触发中断。打印机就是利用这种能力来通知lp驱动程序它已准备好接收缓冲区中的<BR>下一个字符。<BR> <BR> <BR> <BR> 在指定接口这样做之前实际上并不会产生中断;并口标准规定设置2号端口的第4<BR>位(0x37a,0x27a或其它某个地址)时启动中断报告。short模块在初始化时调用outb设置<BR>该位。<BR> <BR> <BR> <BR> 启动中断报告之后,每当引脚10(所谓的"ACK"位)上的电平从低变高时,并口都<BR>会产生一个中断。强迫接口(没有把打印机连到端口上)产生中断的最简单方法是将并<BR>行插座的引脚9和引脚10相连。为此,你需要一个阳性的25针D型插座和一英寸的电缆线<BR></P></FONT><FONT
color=#ffffff size=3>
<P>行插座的引脚9和引脚10相连。为此,你需要一个阳性的25针D型插座和一英寸的电缆线<BR>。<BR> <BR> <BR> <BR> 引脚9是并行数据字节中最重要的一位。如果你往/dev/short0中写入二进制数据<BR>,就可以产生几个中断。然而,往端口中写入ASCII文本将不会产生中断,因为此时不会<BR>设置这个最重要的位。<BR> <BR> <BR> <BR> 如果你确实想“看看”产生的中断,那么,仅仅往硬件设备中写是不够的;还必<BR>须在系统中配置一个软件处理程序。目前,Linux-x86和Linux-Alpha只是简单的确认,<BR>忽略任何在预料之外的中断。<BR> <BR>安装中断处理程序<BR> 中断信号线是宝贵并且非常有限的资源,当只有15或16根中断信号线时尤其如此<BR>。内核维护了一个类似于I/O端口注册表的中断信号线的注册表。一个模块可以申请一个<BR>中断通道(或中断请求IRQ,即Interrupt ReQuest),并且,处理完以后还可以释放掉<BR>它。在<linux/sched.h>头文件中申明的下列函数实现了这个接口:<BR> <BR> <BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>int request_irq(unsigned int irq,<BR> <BR>void (*handler)(int, void*, struct pt_regs *),<BR> <BR>unsigned long flags,<BR> <BR>const char *device, void *dev_id);<BR> <BR>void free_irq(unsigned int irq, void *dev_id);<BR> <BR> <BR> <BR> 注意,1.2版定义了不同的原型。相关的移植问题可参见本章稍后的“IRQ处理程<BR>序的版本相关性”一节。<BR> <BR> <BR> <BR> 通常,申请中断的函数的返回值为0时表示成功,或者返回一个负的错误码。函<BR>数返回-EBUSY通知另一个设备驱动程序已经使用了要申请的中断信号线的情况并不常见<BR>。函数参数定义如下:<BR> <BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR> <BR>unsigned int irq<BR> <BR>该参数为中断号。有时从Linux中断号到硬件中断号的映射并不是一对一的。例如,在ar<BR>ch/alpha/kernel/irq.c文件中可以查看到Alpha上的映射。这里,传递给内核函数的参<BR>数是Linux中断号而不是硬件中断号。<BR> <BR> <BR> <BR>void (*handler)(int,void *,struct pt_regs *)<BR> <BR> 指向要安装的中断处理函数的指针。<BR> <BR> <BR> <BR>unsigned long flags<BR> <BR> 如你所想,这是一个与中断管理有关的各种选项的字节掩码。<BR> <BR> <BR> <BR>const char *device<BR></P></FONT><FONT
color=#ffffff size=3>
<P>const char *device<BR> <BR>传递给request_irq的字符串,在/proc/interrupts中用于显示中断的拥有者(参见下一<BR>节)。<BR> <BR> <BR> <BR>void *dev_id<BR> <BR>这个指针用于共享的中断信号线。它是一个唯一的标志符,更象一个ClientDate(C++中<BR>的this对象)。设备驱动程序可以自由地任意使用dev_id。除非强制使用中断共享,dev<BR>_id通常被置为NULL。在后面的“实现一个处理程序”一节中,我们将看到一个使用dev_<BR>id的实际例子。<BR> <BR> <BR> <BR>在flags中可以设置的位是:<BR> <BR> <BR> <BR>SA_INTERRUPT<BR> <BR>如果设置该位,就指示这是一个“快速”中断处理程序;如果清除这位,那么它就是一<BR></P></FONT><FONT
color=#ffffff size=3>
<P>如果设置该位,就指示这是一个“快速”中断处理程序;如果清除这位,那么它就是一<BR>个“慢速”中断处理程序。快速中断处理程序和慢速中断处理程序的概念在下面的“快<BR>速和慢速处理程序”一节中会谈到。<BR> <BR> <BR> <BR>SA_SHIRQ<BR> <BR> 该位表明中断可以在设备间共享。共享的概念在稍后的“中断共享”一节中介绍<BR>。<BR> <BR> <BR> <BR>SA_SAMPLE_RANDOM<BR> <BR>该位表明产生的中断对/dev/random和/dev/urandom设备要使用的熵池(entropy pool)有<BR>贡献。读这些设备返回真正的随机数,它们用来帮助应用软件选取用于加密的安全钥匙<BR>。这些随机数是从一个熵池中取得的,各种随机事件都会对系统的熵池(无序度)有贡献<BR>。如果你希望设备真正随机地产生中断,你应该置上这个标志。而如果你的中断是可预<BR>测的(例如,帧捕捉卡的垂直消隐),那就不值得设置这个标志位-它对系统的熵池没有<BR>任何贡献。更详尽的信息可参见drivers/char/random.c文件中的注释。<BR> <BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR> <BR> 中断处理程序可以在驱动程序初始化时或者在设备第一次打开时安装。虽然在in<BR>it_module函数中安装中断处理程序听起来是个好主意,但实际上并非如此。因为中断信<BR>号线数量有限,你不会想浪费它们的。你的计算机拥有的设备通常要比中断信号线多。<BR>如果一个设备模块在初始化就申请了一个中断,会阻碍其它驱动程序使用这个中断,即<BR>便这个设备根本不使用它占用的这个中断。而在打开设备时申请中断,则允许资源有限<BR>的共享。<BR> <BR> <BR> <BR> 例如,只要你不同时使用帧捕捉卡和调制解调器这两个设备,它们使用同一个中<BR>断就是可能的。用户经常在系统启动时装载某个特殊设备的模块,即使这个设备很少使<BR>用。数据采集卡可以和第二个串口使用同一个中断。尽管在进行数据采集时避免去连你<BR>的ISP并不是件难事,但在使用调制解调器前不得不先卸载一个模块太令人不愉快了。<BR> <BR> <BR> <BR> 调用request_irq的正确位置是在设备第一次打开,硬件被指示产生中断前的时<BR>候。而调用free_irq的位置是设备最后关闭,硬件被通知不要再中断处理器后的时候。<BR>该技术的缺点是你必须为每个设备维护一个记录其打开次数的计数器。而如果你在同一<BR>个模块中控制两个以上的设备,那么仅仅使用模块计数器那还不够。<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR> <BR> <BR> 尽管我已说了这么多,short却是在装载时申请中断信号线的。我这样做是为了<BR>使你在运行测试程序时不必运行其它进程来使设备保持打开的状态。因此,short会象真<BR>正的设备那样,在init_module中而不是short_open中申请中断。<BR> <BR> <BR> <BR> 下面这段代码要申请的中断是short_irq。对这个变量的赋值将在后面再给出,<BR>因为它与现在的讨论无关。short_base是使用的并口的I/O基地址;写接口的2号寄存器<BR>打开中断报告。<BR> <BR> <BR> <BR> if (short_irq >=0 ) {<BR> <BR> result=request_irq(short_irq, short_interrupt, SA_INTERRUPT,<BR>"short", NULL);<BR> <BR> if (result) {<BR> <BR> printk(KERN_INFO "short: can't get assigned irq %i\n",<BR></P></FONT><FONT color=#ffffff size=3>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -