📄 linux设备驱动程序学习(11)-中断处理 - linux设备驱动程序 - tekkaman ninja.htm
字号:
<TABLE
style="BORDER-COLLAPSE: collapse; WORD-WRAP: break-word"
cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD width="100%">
<DIV id=art style="MARGIN: 15px" width="100%">
<P align=center><FONT color=#0000ff
size=4><STRONG>Linux设备驱动程序学习(11)-中断处理</STRONG></FONT>
</P>
<P>可以让设备在产生某个事件时通知处理器的方法就是中断。一个“中断”仅是一个信号,当硬件需要获得处理器对它的关注时,就可以发送这个信号。<FONT
color=#ff0000> Linux
处理中断的方式非常类似在用户空间处理信号的方式。</FONT>
大多数情况下,一个驱动只需要为它的设备的中断注册一个处理例程,并当中断到来时进行正确的处理。本质上来讲,中断处理例程和其他的代码并行运行。因此,它们不可避免地引起并发问题,并竞争数据结构和硬件。
透彻地理解并发控制技术对中断来讲非常重要。
<HR id=null>
<P></P>
<P><FONT color=#0000ff
size=4><STRONG>安装中断处理例程</STRONG></FONT></P>
<P>内核维护了一个中断信号线的注册表,类似于 I/O
端口的注册表。模块在使用中断前要先请求一个中断通道(或者
IRQ中断请求),并在使用后释放它。所用的函数声明在 <FONT
color=#0000ff><linux/interrupt.h></FONT>
(在此文件中并未真正包含,是通过它include的文件间接包含的,函数在/kernel/irq/Manage.h中),中断注册和释放的函数接口如下:
<TABLE style="BORDER-COLLAPSE: collapse"
borderColor=#999999 cellSpacing=0 cellPadding=0
width="95%" bgColor=#f1f1f1 border=1>
<TBODY>
<TR>
<TD>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
style="COLOR: #000000"><FONT face=新宋体><SPAN
style="COLOR: #0000ff">int</SPAN>
request_irq<SPAN
style="COLOR: #0000cc">(</SPAN><SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">int</SPAN> irq<SPAN
style="COLOR: #0000cc">,</SPAN><BR> irqreturn_t
<SPAN style="COLOR: #0000cc">(</SPAN><SPAN
style="COLOR: #0000cc">*</SPAN>handler<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">(</SPAN><SPAN
style="COLOR: #0000ff">int</SPAN><SPAN
style="COLOR: #0000cc">,</SPAN> <SPAN
style="COLOR: #0000ff">void</SPAN> <SPAN
style="COLOR: #0000cc">*</SPAN><SPAN
style="COLOR: #0000cc">,</SPAN> <SPAN
style="COLOR: #0000ff">struct</SPAN> pt_regs
<SPAN style="COLOR: #0000cc">*</SPAN><SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">,</SPAN><BR> <SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">long</SPAN> flags<SPAN
style="COLOR: #0000cc">,</SPAN></FONT></SPAN></CODE></P>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
style="COLOR: #000000"><SPAN
style="COLOR: #0000cc"></SPAN><FONT
face=新宋体> <SPAN
style="COLOR: #0000ff">const</SPAN> <SPAN
style="COLOR: #0000ff">char</SPAN> <SPAN
style="COLOR: #0000cc">*</SPAN>dev_name<SPAN
style="COLOR: #0000cc">,</SPAN><BR> <SPAN
style="COLOR: #0000ff">void</SPAN> <SPAN
style="COLOR: #0000cc">*</SPAN>dev_id<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN><BR><BR><SPAN
style="COLOR: #0000ff">void</SPAN> free_irq<SPAN
style="COLOR: #0000cc">(</SPAN><SPAN
style="COLOR: #0000ff">unsigned</SPAN> <SPAN
style="COLOR: #0000ff">int</SPAN> irq<SPAN
style="COLOR: #0000cc">,</SPAN> <SPAN
style="COLOR: #0000ff">void</SPAN> <SPAN
style="COLOR: #0000cc">*</SPAN>dev_id<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P><PRE class=programlisting><FONT color=#0000ff>request_irq</FONT> 的返回值: 0 指示成功,或返回一个负的错误码,如 -EBUSY 表示另一个驱动已经占用了你所请求的中断线。</PRE>
<P>函数的参数如下:</P>
<DIV class=variablelist>
<DL>
<DT><SPAN class=term><SPAN><FONT
color=#0000ff>unsigned int irq</FONT>
:</SPAN></SPAN>请求的中断号
<DT><SPAN class=term><SPAN><FONT
color=#0000ff>irqreturn_t
(*handler)</FONT></SPAN></SPAN> :安装的处理函数指针。
<DT><SPAN class=term><SPAN><FONT
color=#0000ff>unsigned long flags</FONT>
</SPAN></SPAN>:一个与中断管理相关的位掩码选项。
<DT><SPAN class=term><SPAN><FONT
color=#0000ff>const char *dev_name</FONT>
:</SPAN></SPAN>传递给 request_irq 的字符串,用来在
/proc/interrupts 来显示中断的拥有者。
<DT><SPAN class=term><SPAN><FONT
color=#0000ff>void *dev_id</FONT>
</SPAN></SPAN>:用于共享中断信号线的指针。它是唯一的标识,在中断线空闲时可以使用它,驱动程序也可以用它来指向自己的私有数据区(来标识哪个设备产生中断)。若中断没有被共享,dev_id
可以设置为 NULL,但推荐用它指向设备的数据结构。
<DT>
<DT><FONT color=#0000ff><STRONG>flags
中可以设置的位如下:</STRONG></FONT></DT></DL></DIV>
<DIV class=variablelist>
<DL>
<DT><SPAN class=term><SPAN><FONT
color=#0000ff>SA_INTERRUPT</FONT>
:</SPAN></SPAN>快速中断标志。快速中断处理例程运行在当前处理器禁止中断的状态下。
<DT><SPAN class=term><SPAN><FONT
color=#0000ff>SA_SHIRQ</FONT> </SPAN></SPAN>:
在设备间共享中断标志。
<DT><SPAN class=term><SPAN><FONT
color=#0000ff>SA_SAMPLE_RANDOM</FONT>
:该</SPAN></SPAN>位表示产生的中断能对 /dev/random 和
/dev/urandom 使用的熵池(entropy pool)有贡献。
读取这些设备会返回真正的随机数,从而有助于应用程序软件选择用于加密的安全密钥。
若设备以真正随机的周期产生中断,就应当设置这个标志。若设备中断是可预测的,这个标志不值得设置。可能被攻击者影响的设备不应当设置这个标志。更多信息看
drivers/char/random.c 的注释。</DT></DL></DIV>
<P>中断处理例程可在驱动初始化时或在设备第一次打开时安装。推荐在设备第一次打开、硬件被告知产生中断前时申请中断,因为可以共享有限的中断资源。这样调用
free_irq
的位置是设备最后一次被关闭、硬件被告知不用再中断处理器之后。但这种方式的缺点是必须为每个设备维护一个打开计数。</P>
<P> 以下是中断申请的示例(并口):
<TABLE style="BORDER-COLLAPSE: collapse"
borderColor=#999999 cellSpacing=0 cellPadding=0
width="95%" bgColor=#f1f1f1 border=1>
<TBODY>
<TR>
<TD>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
style="COLOR: #000000"><FONT face=新宋体><SPAN
style="COLOR: #0000ff">if</SPAN> <SPAN
style="COLOR: #0000cc">(</SPAN>short_irq <SPAN
style="COLOR: #0000cc">></SPAN><SPAN
style="COLOR: #0000cc">=</SPAN> 0<SPAN
style="COLOR: #0000cc">)</SPAN><BR><SPAN
style="COLOR: #0000cc">{</SPAN><BR> result
<SPAN style="COLOR: #0000cc">=</SPAN>
request_irq<SPAN
style="COLOR: #0000cc">(</SPAN>short_irq<SPAN
style="COLOR: #0000cc">,</SPAN>
short_interrupt<SPAN
style="COLOR: #0000cc">,</SPAN><BR> SA_INTERRUPT<SPAN
style="COLOR: #0000cc">,</SPAN> <SPAN
style="COLOR: #ff00ff">"short"</SPAN><SPAN
style="COLOR: #0000cc">,</SPAN> <SPAN
style="COLOR: #ff0000">NULL</SPAN><SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN><BR> <SPAN
style="COLOR: #0000ff">if</SPAN> <SPAN
style="COLOR: #0000cc">(</SPAN>result<SPAN
style="COLOR: #0000cc">)</SPAN> <SPAN
style="COLOR: #0000cc">{</SPAN><BR> printk<SPAN
style="COLOR: #0000cc">(</SPAN>KERN_INFO <SPAN
style="COLOR: #ff00ff">"short: can't get
assigned irq %i\n"</SPAN><SPAN
style="COLOR: #0000cc">,</SPAN><BR> short_irq<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN><BR><BR> short_irq
<SPAN style="COLOR: #0000cc">=</SPAN> <SPAN
style="COLOR: #0000cc">-</SPAN>1<SPAN
style="COLOR: #0000cc">;</SPAN><BR> <SPAN
style="COLOR: #0000cc">}</SPAN> <SPAN
style="COLOR: #0000ff">else</SPAN> <SPAN
style="COLOR: #0000cc">{</SPAN> <SPAN
style="COLOR: #ff9900">/*打开中断硬件的中断能力*/</SPAN><BR> outb<SPAN
style="COLOR: #0000cc">(</SPAN>0x10<SPAN
style="COLOR: #0000cc">,</SPAN>short_base<SPAN
style="COLOR: #0000cc">+</SPAN>2<SPAN
style="COLOR: #0000cc">)</SPAN><SPAN
style="COLOR: #0000cc">;</SPAN><BR> <SPAN
style="COLOR: #0000cc">}</SPAN><BR><SPAN
style="COLOR: #0000cc">}</SPAN></FONT></SPAN></CODE></P></TD></TR></TBODY></TABLE></P>
<DIV>
<P>i386 和 x86_64 体系定义了一个函数来查询一个中断线是否可用:
<TABLE style="BORDER-COLLAPSE: collapse"
borderColor=#999999 cellSpacing=0 cellPadding=0
width="95%" bgColor=#f1f1f1 border=1>
<TBODY>
<TR>
<TD>
<P
style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -