Chinaunix首页 | 论坛 | 博客
  • 博客访问: 208138
  • 博文数量: 33
  • 博客积分: 1241
  • 博客等级: 中尉
  • 技术积分: 330
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-20 16:34
个人简介

..

文章分类

全部博文(33)

文章存档

2012年(1)

2011年(8)

2010年(8)

2009年(4)

2007年(12)

我的朋友

分类: LINUX

2010-07-22 18:51:07

这篇文章有部分是从下面文章中copy的.
http://blog.chinaunix.net/u3/104447/showart_2251021.html

i use 2.6.29 kernel, he use 2.6.32.
function: request_irq change to request_threaded_irq

interrupt handle:
Linux内核将所有的中断统一编号,使用一个irq_desc结构数组来描述这些中断;每个数组项对应一个中断,也可能是一组中断,它们共用相同的中断号,里面记录了中断的名称、中断状态、中断标记(比如中断类型、是否共享中断等),并提供了中断的低层硬件访问函数(清除、屏蔽、使能中断),提供了这个中断的处理函数入口,通过它可以调用用户注册的中断处理函数。

arch/mips/wintegra/wds3/wds3-int.c : plat_irq_dispatch
arch/mips/include/asm/irq.h:do_IRQ
include/linux/irq.h:generic_handle_irq
include/linux/irq.h:generic_handle_irq_desc 
      (call: desc->handle_irq or __do_IRQ)

其中:
handle_irq会使用chip成员中的函数来设置硬件,比如清除中断、禁止中断、重新使能中断等. handle_irq逐个调用用户在aciton链表中注册的处理函数.

中断体系结构的初始化就是构造这些数据结构,比如irq_desc数组项中的handle_irq、chip等成员;用户注册中断时就是构造action链表;用户卸载中断时就是从action链表中去除不需要的项。

---------------------------------
中断处理体系结构的初始化
1>arch/mips/kernel/irq.c : init_IRQ (这个函数是)
void __init init_IRQ(void)
{
    int i;

    for (i = 0; i < NR_IRQS; i++)
        set_irq_noprobe(i);   //初始化irq_desc结构数组中每一项的中断状态

    arch_init_irq();//调用架构相关的中断初始化函数
}
2>arch/mips/wintegra/wds3/wds3-int.c : arch_init_irq
3>arch/mips/wintegra/wds3/wds3-int.c : winpath3_pic_init
winpath3_pic_init()
{
  for (i = WINPATH_IRQ_BASE; i < (WINPATH_IRQ_BASE+IV_WINPATH_MAX+1); i++)
       set_irq_chip_and_handler(i, &winpath3_pic, handle_level_irq);
}


--------- 一些函数的说明 -----------
set_irq_handler(irqno, handle_level_irq); //电平触发
set_irq_handler(irqno, handle_edge_irq);  //边沿
set_irq_flags(irqno, IRQF_VALID);  //valid表示中断有效, 可以使用
------------------------------------


用户驱动程序通过request_irq函数向内核注册中断处理函数,request_irq函数根据中断号找到irq_desc数组项,然后在它的action链表添加一个表项.
原先的内核中requset_irq函数在kernel/irq/manage.c中定义,而现在2.6.32版本中,进行了改变,在2.6.32内核中我们可以看到找不到了request_irq函数的实现,而是用request_threaded_irq()函数给替换了。我们可以在inclue/linux/interrupt.h中找到这个函数的原型。


=========================

setup_irq函数完成如下3个主要功能
(1)将新建的irqaction结构链入irq_desc[irq]结构的action链表中,这有两种可能。
如果action链表为空,则直接链入,否则先判断新建的irqaction结构和链表中的irqaction结构所表示的中断类型是否一致,即是否都声明为"可共享的"(IRQF_SHARED)、是否都使用相同的触发方式,如果一致,则将新建的irqation结构链入
(2)设置irq_desc[irq]结构中chip成员的还没设置的指针,让它们指向一些默认函数
chip成员在init_IRQ函数初始化中断体系结构的时候已经设置了,这里只是设置其中还没设置的指针这通过irq_chip_set_defaults函数来完成,它在kernel/irq/chip.c中定义

如果irq_desc[irq]结构中status成员没有被指明IRQ_NOAUTOEN(表示注册中断时不要使用中断),还要调用 chip->startup或chip->enable来启动中断,所谓启动中断通常就是使用中断。一般情况下,只有那些“可以自动使能的” 中断对应的irq_desc[irq].status才会被指明为IRQ_NOAUTOEN,所以,无论哪种情况,执行request_irq注册中断之后,这个中断就已经被使能了。
总结一下request_irq函数注册
(1)irq_des[irq]结构中的action链表中已经链入了用户注册的中断处理函数
(2)中断的触发方式已经被设好
(3)中断已经被使能

arch/mips/kernel/genex.S : handle_int

handle_int函数由
arch/mips/kernel/traps.c:trap_init
arch/mips/kernel/traps.c: set_except_vector //这里注册
set_except_vector函数中exception_handlers[n] = handler. 在这个数组中保存异常入口地址.


中断的处理流程可以总结如下:
 (1)中断向量调用总入口函数asm_do_IRQ,传入根据中断号irq
(2)asm_do_IRQ 函数根据中断号irq调用irq_desc[irq].handle_irq,它是这个中断的处理函数入口,对于电平触发的中断,这个入口函数通常为 handle_level_irq,对于边沿触发的中断,这个入口通常为handle_edge_irq
(3)入口函数首先清除中断,入口函数是handle_level_irq时还要屏蔽中断
(4)逐个调用用户在irq_desc[irq].aciton链表中注册的中断处理函数
(5) 入口函数是handle_level_irq时还要重新开启中断
    卸载中断处理函数这通过free_irq函数来实现,它与request_irq一样,也是在kernel/irq/mangage.c中定义:                                           
   它需要用到两个参数:irq和dev_id,它们与通过request_irq注册中断函数时使用的参数一样,使用中断号irq定位action链表,再使用dev_id在action链表中找到要卸载的表项。同一个中断的不同中断处理函数必须使用不同的dev_id来区分,在注册共享中断时参数 dev_id必惟一。free_irq函数的处理过程与request_irq函数相反
(1)根据中断号irq,dev_id从action链表中找到表项,将它移除
(2)如果它是惟一的表项,还要调用IRQ_DESC[IRQ].CHIP->SHUTDOWN 或IRQ_DESC[IRQ].CHIP->DISABLW来关闭中断

阅读(2429) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~