1. 重要接口

LDD上说,“内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表。模块在使用中断前要先请求一个中断通道(或者中断请求IRQ),然后在使用后释放该通道。”

撇开系统如何遍历各个设备进行初始化,上面两句话说的实际上就是指两个接口函数:

externint __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, constchar*name, void*dev);
  externvoid free_irq(unsigned int, void*);

顾名思义,以上两个函数分别用于申请和释放IRQ。

而再一看,会发现其实request_irq是个“皮包”函数,它的定义是这样的:

static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
constchar*name, void*dev)
{
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

所以实际上起到申请IRQ作用的,正是这个request_threaded_irq函数。一查,它位于/kernel/irq/manage.c中。

2.追随request_threaded_irq

先贴上request_threaded_irq全文

int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long irqflags,
constchar*devname, void*dev_id)
{
struct irqaction *action;
struct irq_desc *desc;
int retval; /*
* Sanity-check: shared interrupts must pass in a real dev-ID,
* otherwise we'll have trouble later trying to figure out
* which interrupt is which (messes up the interrupt freeing
* logic etc).
*/
if ((irqflags & IRQF_SHARED) &&!dev_id)
return-EINVAL; desc = irq_to_desc(irq);
if (!desc)
return-EINVAL; if (desc->status & IRQ_NOREQUEST)
return-EINVAL; if (!handler) {
if (!thread_fn)
return-EINVAL;
handler = irq_default_primary_handler;
} action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return-ENOMEM; action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id; chip_bus_lock(irq, desc);
retval = __setup_irq(irq, desc, action);
chip_bus_sync_unlock(irq, desc); if (retval)
kfree(action); #ifdef CONFIG_DEBUG_SHIRQ
if (!retval && (irqflags & IRQF_SHARED)) {
/*
* It's a shared IRQ -- the driver ought to be prepared for it
* to happen immediately, so let's make sure....
* We disable the irq to make sure that a 'real' IRQ doesn't
* run in parallel with our fake.
*/
unsigned long flags; disable_irq(irq);
local_irq_save(flags); handler(irq, dev_id); local_irq_restore(flags);
enable_irq(irq);
}
#endif
return retval;
}

可以看到除去一些验证的语句,整个函数主要完成的任务是初始化了一个irqaction类型的struct和一个irq_desc类型的struct,接着对这两个struct进一步赋值和处理,便实现了IRQ申请。至此,我们有理由认为这两个struct是kernel管理IRQ的核心数据结构。因此不妨看看他们都是什么样的。

struct irq_desc {
unsigned int irq;
struct timer_rand_state *timer_rand_state;
unsigned int*kstat_irqs;
#ifdef CONFIG_INTR_REMAP
struct irq_2_iommu *irq_2_iommu;
#endif
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
struct msi_desc *msi_desc;
void*handler_data;
void*chip_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */ unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned long last_unhandled; /* Aging timer for unhandled count */
unsigned int irqs_unhandled;
raw_spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_var_t affinity;
conststruct cpumask *affinity_hint;
unsigned int node;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_t pending_mask;
#endif
#endif
atomic_t threads_active;
wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
constchar*name;
} ____cacheline_internodealigned_in_smp;

irq_desc实际是个用于构成数组的数据结构。这里irq就是我们熟悉的irq号,每个设备申请到一个IRQ,就需要填充一个irq_desc,并由kernel放入所维护的数组中进行管理。在这些需要填充的内容里,irq_chip和irqaction是两个比较有助于理解数据结构的struct。

struct irq_chip {
constchar*name;
unsigned int (*startup)(unsigned int irq);
void (*shutdown)(unsigned int irq);
void (*enable)(unsigned int irq);
void (*disable)(unsigned int irq); void (*ack)(unsigned int irq);
void (*mask)(unsigned int irq);
void (*mask_ack)(unsigned int irq);
void (*unmask)(unsigned int irq);
void (*eoi)(unsigned int irq); void (*end)(unsigned int irq);
int (*set_affinity)(unsigned int irq,
conststruct cpumask *dest);
int (*retrigger)(unsigned int irq);
int (*set_type)(unsigned int irq, unsigned int flow_type);
int (*set_wake)(unsigned int irq, unsigned int on); void (*bus_lock)(unsigned int irq);
void (*bus_sync_unlock)(unsigned int irq); /* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
void (*release)(unsigned int irq, void*dev_id);
#endif
/*
* For compatibility, ->typename is copied into ->name.
* Will disappear.
*/
constchar*typename;
};

这个struct里主要定义了硬件层面上一个系统对一个IRQ的管理接口。

struct irqaction {
irq_handler_t handler;
unsigned long flags;
constchar*name;
void*dev_id;
struct irqaction *next;
int irq;
struct proc_dir_entry *dir;
irq_handler_t thread_fn;
struct task_struct *thread;
unsigned long thread_flags;
};

这个struct中handler定义了中断处理函数, *next指向了下一个irqaction,也就是说irqaction是以链表的形式存在的。也就是说,每一个IRQ对应一个irq_desc,而irq_desc维护着irq_chip管理了硬件层面的中断使能,同时irq_desc也维护了一个irqaction链表。

根据所查的资料,实际上,系统在处理一个中断时,会根据中断号调用irq_desc数组中的handle_irq, handle_irq再使用chip控制硬件的使能,接着调用irqaction链表,逐个调用中断处理函数。

回过头来,request一个IRQ的过程实际上就是构造irqaction项,free的过程就是移除不需要的irqaction项。

http://www.cnblogs.com/garychen2272/archive/2011/02/25/1964176.html

[Fw]初探linux中断系统(1)的更多相关文章

  1. [Fw]初探linux中断系统(2)

    初探linux中断系统(2) 中断系统初始化的过程 用来初始化中断系统的函数位于arch/x86/kernel/irqinit.c,定义如下 void __init init_IRQ(void){ i ...

  2. linux中断系统那些事之----中断处理过程【转】

    转自:http://blog.csdn.net/xiaojsj111/article/details/14129661 以外部中断irq为例来说明,当外部硬件产生中断时,linux的处理过程.首先先说 ...

  3. linux中断子系统:中断号的映射与维护初始化mmap过程

    本文均属自己阅读源代码的点滴总结.转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:gzzaigcn2009@163.com 写在前沿: 好久好久没有静下心来整理一些东西了 ...

  4. Linux中断(interrupt)子系统之一:中断系统基本原理【转】

    转自:http://blog.csdn.net/droidphone/article/details/7445825 这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于AR ...

  5. Linux中断(interrupt)子系统之一:中断系统基本原理

    这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层.内核版本基于3.3.虽然内核的版本不断地提升,不 ...

  6. 裸板中中断异常处理,linux中断异常处理 ,linux系统中断处理的API,中断处理函数的要求,内核中登记底半部的方式

    1.linux系统中的中断处理  1.0裸板中中断异常是如何处理的?     以s5p6818+按键为例          1)按键中断的触发        中断源级配置            管脚功 ...

  7. [fw]LINUX中断描述符初始化

    LINUX中断描述符初始化 @CopyLeft by ICANTH,I Can do ANy THing that I CAN THink!~ Author: WenHui, WuHan Univer ...

  8. 初探Linux内核中的内存管理

    Linux内核设计与实现之内存管理的读书笔记 初探Linux内核管理 内核本身不像用户空间那样奢侈的使用内存; 内核不支持简单快捷的内存分配机制, 用户空间支持? 这种简单快捷的内存分配机制是什么呢? ...

  9. linux中断与异常

    看了<深入理解linux内核>的中断与异常,简单总结了下,如果有错误,望指正! 一 什么是中断和异常 异常又叫同步中断,是当指令执行时由cpu控制单元产生的,之所以称之为异常,是因为只有在 ...

随机推荐

  1. 攻防世界--dmd-50

    测试文件:https://adworld.xctf.org.cn/media/task/attachments/7ef7678559ea46cbb535c0b6835f2f4d 1.准备 获取信息 6 ...

  2. idea 创建 SSM + maven Java Web 项目流程

    idea 创建 SSM + maven Java Web 项目流程 一.idea 中选择File,New Project 新建项目 二.选择Maven,勾选上面的Create from archety ...

  3. 纯css实现星级评分效果

    效果 效果图如下,纯css实现超酷炫的星级评分动画效果 ​ 实现思路 5个类型为radio的input,label标签修改样式背景图为星星 label标签给每个星星鼠标停留时加注名字 点击星星有放大旋 ...

  4. JS-01 书写规范

    此部分内容整理自私教指导和自我体会:(持续更新...) 1.运算符左右两边留空格 (webstorm快捷键ctrl+alt+l): 2.判断值是否相等尽量用“===” 严格等于 : 3.编程中,可有可 ...

  5. linux100day(day5)--编程原理和shell脚本

    通过前面的学习,我们对于linux文件系统有了一定的了解,我们接下来会初步接触编程原理和尝试编写shell脚本来实现功能. day05--编程原理和shell脚本初步认识 编程原理 在早期编程中,因为 ...

  6. Zabbix学习笔记(yum源安装)

    Zabbix学习笔记(yum源安装) 链接:https://pan.baidu.com/s/19RXhumkB-ulpI4BGOa5b_A 提取码:115h 复制这段内容后打开百度网盘手机App,操作 ...

  7. zookeeper与kafka安装搭建

    1.2181:对cline端提供服务 2.3888:选举leader使用 3.2888:集群内机器通讯使用(Leader监听此端口)

  8. 记一个日志冲突——管中窥豹[java混乱的日志体系]

    D:\Java\jdk1.8.0_211\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Communit ...

  9. Java中的两种异常类型及其区别?

    Java中的两种异常类型是什么?他们有什么区别? Throwable包含了错误(Error)和异常(Excetion两类) Exception又包含了运行时异常(RuntimeException, 又 ...

  10. python写txt文件

    with open('data.txt','w') as f: #设置文件对象 w是重新写,原来的会被抹掉,a+是在原来的基础上写 str0=u"写文件\n" #写中文要在字符串签 ...