`
xiaoer_1982
  • 浏览: 1821655 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

三读内核中断处理(5):中断系统提供的API

阅读更多

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

本文适用于

ADSP-BF561

优视BF561EVB开发板

uclinux-2008r1.5-rc3(smp patch)

Visual DSP++ 5.0(update 5)

欢迎转载,但请保留作者信息

中断系统提供的API大都在kernel/irq/manage.c中。

1.1 synchronize_irq

这个函数用于在两个核间进行中断的同步:

/**

* synchronize_irq - wait for pending IRQ handlers (on other CPUs)

* @irq: interrupt number to wait for

*

* This function waits for any pending IRQ handlers for this interrupt

* to complete before returning. If you use this function while

* holding a resource the IRQ handler may need you will deadlock.

*

* This function may be called - with care - from IRQ context.

*/

void synchronize_irq(unsigned int irq)

{

struct irq_desc *desc = irq_desc + irq;

if (irq >= NR_IRQS)

return;

while (desc->status & IRQ_INPROGRESS)

cpu_relax();

}

这个函数仅用于使用SMP的情况。由于每一个核都可以同等地处理每一个外部中断,因此有时候需要进行同步,从代码可以看出,它就是简单地等待一个中断处理完成。

1.2 disable_irq_nosync

这个函数用于关闭指定中断:

/**

* disable_irq_nosync - disable an irq without waiting

* @irq: Interrupt to disable

*

* Disable the selected interrupt line. Disables and Enables are

* nested.

* Unlike disable_irq(), this function does not ensure existing

* instances of the IRQ handler have completed before returning.

*

* This function may be called from IRQ context.

*/

void disable_irq_nosync(unsigned int irq)

{

struct irq_desc *desc = irq_desc + irq;

unsigned long flags;

if (irq >= NR_IRQS)

return;

spin_lock_irqsave(&desc->lock, flags);

if (!desc->depth++) {

desc->status |= IRQ_DISABLED;

desc->chip->disable(irq);

}

spin_unlock_irqrestore(&desc->lock, flags);

}

可以看出,这个函数直接调用irq_chip的成员disable这一回调函数,野蛮的关闭硬件中断!

1.3 disable_irq

这个函数将关闭硬件中断并等待(可能有的)中断处理完成。

/**

* disable_irq - disable an irq and wait for completion

* @irq: Interrupt to disable

*

* Disable the selected interrupt line. Enables and Disables are

* nested.

* This function waits for any pending IRQ handlers for this interrupt

* to complete before returning. If you use this function while

* holding a resource the IRQ handler may need you will deadlock.

*

* This function may be called - with care - from IRQ context.

*/

void disable_irq(unsigned int irq)

{

struct irq_desc *desc = irq_desc + irq;

if (irq >= NR_IRQS)

return;

disable_irq_nosync(irq);

if (desc->action)

synchronize_irq(irq);

}

1.4 enable_irq

这个函数用于启用一个指定的中断。

/**

* enable_irq - enable handling of an irq

* @irq: Interrupt to enable

*

* Undoes the effect of one call to disable_irq(). If this

* matches the last disable, processing of interrupts on this

* IRQ line is re-enabled.

*

* This function may be called from IRQ context.

*/

void enable_irq(unsigned int irq)

{

struct irq_desc *desc = irq_desc + irq;

unsigned long flags;

if (irq >= NR_IRQS)

return;

spin_lock_irqsave(&desc->lock, flags);

switch (desc->depth) {

case 0:

printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);

WARN_ON(1);

break;

case 1: {

unsigned int status = desc->status & ~IRQ_DISABLED;

/* Prevent probing on this irq: */

desc->status = status | IRQ_NOPROBE;

check_irq_resend(desc, irq);

/* fall-through */

}

default:

desc->depth--;

}

spin_unlock_irqrestore(&desc->lock, flags);

}

在系统初始化完成的时候,每个irq_desc->depth值都将初始化为1。因而这个函数将直接执行check_irq_resend启用中断。

1.5 free_irq

这个函数用于释放中断:

/**

* free_irq - free an interrupt

* @irq: Interrupt line to free

* @dev_id: Device identity to free

*

* Remove an interrupt handler. The handler is removed and if the

* interrupt line is no longer in use by any driver it is disabled.

* On a shared IRQ the caller must ensure the interrupt is disabled

* on the card it drives before calling this function. The function

* does not return until any executing interrupts for this IRQ

* have completed.

*

* This function must not be called from interrupt context.

*/

void free_irq(unsigned int irq, void *dev_id)

{

struct irq_desc *desc;

struct irqaction **p;

unsigned long flags;

irqreturn_t (*handler)(int, void *) = NULL;

WARN_ON(in_interrupt());

if (irq >= NR_IRQS)

return;

desc = irq_desc + irq;

spin_lock_irqsave(&desc->lock, flags);

p = &desc->action;

for (;;) {

struct irqaction *action = *p;

if (action) {

struct irqaction **pp = p;

p = &action->next;

if (action->dev_id != dev_id)

continue;

/* Found it - now remove it from the list of entries */

*pp = action->next;

/* Currently used only by UML, might disappear one day.*/

#ifdef CONFIG_IRQ_RELEASE_METHOD

if (desc->chip->release)

desc->chip->release(irq, dev_id);

#endif

if (!desc->action) {

desc->status |= IRQ_DISABLED;

if (desc->chip->shutdown)

desc->chip->shutdown(irq);

else

desc->chip->disable(irq);

}

spin_unlock_irqrestore(&desc->lock, flags);

unregister_handler_proc(irq, action);

/* Make sure it's not being used on another CPU */

synchronize_irq(irq);

if (action->flags & IRQF_SHARED)

handler = action->handler;

kfree(action);

return;

}

printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);

spin_unlock_irqrestore(&desc->lock, flags);

return;

}

#ifdef CONFIG_DEBUG_SHIRQ

if (handler) {

/*

* It's a shared IRQ -- the driver ought to be prepared for it

* to happen even now it's being freed, so let's make sure....

* We do this after actually deregistering it, to make sure that

* a 'real' IRQ doesn't run in parallel with our fake

*/

handler(irq, dev_id);

}

#endif

}

1.6 request_irq

这个函数用以自己指定一个中断的处理函数。

/**

* request_irq - allocate an interrupt line

* @irq: Interrupt line to allocate

* @handler: Function to be called when the IRQ occurs

* @irqflags: Interrupt type flags

* @devname: An ascii name for the claiming device

* @dev_id: A cookie passed back to the handler function

*

* This call allocates interrupt resources and enables the

* interrupt line and IRQ handling. From the point this

* call is made your handler function may be invoked. Since

* your handler function must clear any interrupt the board

* raises, you must take care both to initialise your hardware

* and to set up the interrupt handler in the right order.

*

* Dev_id must be globally unique. Normally the address of the

* device data structure is used as the cookie. Since the handler

* receives this value it makes sense to use it.

*

* If your interrupt is shared you must pass a non NULL dev_id

* as this is required when freeing the interrupt.

*

* Flags:

*

* IRQF_SHARED Interrupt is shared

* IRQF_DISABLED Disable local interrupts while processing

* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy

*

*/

int request_irq(unsigned int irq, irq_handler_t handler,

unsigned long irqflags, const char *devname, void *dev_id)

{

struct irqaction *action;

int retval;

#ifdef CONFIG_LOCKDEP

/*

* Lockdep wants atomic interrupt handlers:

*/

irqflags |= IRQF_DISABLED;

#endif

/*

* 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;

if (irq >= NR_IRQS)

return -EINVAL;

if (irq_desc[irq].status & IRQ_NOREQUEST)

return -EINVAL;

if (!handler)

return -EINVAL;

action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);

if (!action)

return -ENOMEM;

action->handler = handler;

action->flags = irqflags;

cpus_clear(action->mask);

action->name = devname;

action->next = NULL;

action->dev_id = dev_id;

select_smp_affinity(irq);

#ifdef CONFIG_DEBUG_SHIRQ

if (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 do this before actually registering it, to make sure that

* a 'real' IRQ doesn't run in parallel with our fake

*/

if (irqflags & IRQF_DISABLED) {

unsigned long flags;

local_irq_save(flags);

handler(irq, dev_id);

local_irq_restore(flags);

} else

handler(irq, dev_id);

}

#endif

retval = setup_irq(irq, action);

if (retval)

kfree(action);

return retval;

}

这里直接用kmalloc来分配irqaction其实挺浪费空间的。当然由于中断个数有限,其浪费的空间数量也有限,呵呵。

分享到:
评论

相关推荐

    LINUX内核API完全参考手册.pdf+源代码.part1

    《Linux内核API完全参考手册》中分析的内核API模块包括:内核模块机制API、进程管理内核API、进程调度内核API、中断机制内核API、内存管理内核API、内核定时机制API、内核同步机制API、文件系统内核API和设备驱动及...

    LINUX内核API完全参考手册

    《Linux内核API完全参考手册》中分析的内核API模块包括:内核模块机制API、进程管理内核API、进程调度内核API、中断机制内核API、内存管理内核API、内核定时机制API、内核同步机制API、文件系统内核API和设备驱动及...

    深入分析Linux内核源码

    3.4.1中断和异常处理的硬件处理 3.4.2 Linux对异常和中断的处理 3.4.3 与堆栈有关的常量、数据结构及宏 3.4.4 中断处理程序的执行 3.4.5 从中断返回 3.5中断的后半部分处理机制 3.5.1 为什么把中断分为两部分...

    操作系统内核.zip

    随机性指:操作系统的运行是在一个随机的环境中,一个设备可能在任何时间向处理机发出中断请求,系统无法知道运行着的程序会在什么时候做什么事情。 4、虚拟 (virtual)是指通过技术将一个物理实体变成若干个逻辑上...

    操作系统大作业:假文件系统.zip

    随机性指:操作系统的运行是在一个随机的环境中,一个设备可能在任何时间向处理机发出中断请求,系统无法知道运行着的程序会在什么时候做什么事情。 4、虚拟 (virtual)是指通过技术将一个物理实体变成若干个逻辑上...

    深入分析Linux内核源码.chm

    1 Linux 2.4内核API 2.1 驱动程序的基本函数 2.2 双向循环链表的操作 2.3 基本C库函数 2.4 Linux内存管理中Slab缓冲区 2.5 Linux中的VFS 2.6 Linux的连网 2.7 网络设备支持 2.8 模块支持 2.9 硬件接口 2.10 块设备 ...

    深入剖析Linux中断机制

    【摘要】本文详解了 Linux 内核的中断实现机制。首先介绍了中断的一些基本概念,然后分 析了面向对象的 Linux 中断的组织形式、三种主要数据结构及其之间的关系。随后介绍了 Linux 处理异常和中断的基本流程, 在此...

    寒江独钓-Windows内核安全编程(高清完整版).part5

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    Windows 内核情景分析--采用开源代码ReactOS (上册) part01

    9.6 中断处理 817 9.7 一个过滤设备驱动模块的示例 828 9.8 设备驱动模块的装载 830 9.9 磁盘的设备驱动堆叠 858 9.9.1 类驱动disk.sys 860 9.10 磁盘的Miniport驱动模块 887 9.11 命名管道与Mailslot 896 ...

    寒江独钓-Windows内核安全编程(高清完整版).part4

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    Windows内核安全与驱动开发光盘源码

    第1章 内核上机指导 2 1.1 下载和使用WDK 2 1.1.1 下载并安装WDK 2 1.1.2 编写第一个C文件 4 1.1.3 编译一个工程 5 1.2 安装与运行 6 1.2.1 下载一个安装工具 6 1.2.2 运行与查看输出信息 7 1.2.3 在虚拟机...

    寒江独钓-Windows内核安全编程(高清完整版).part1

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    实验五Linux系统调用的编程技术

    libc 提供的 API 可能直接提供一些用户态的服务,并不需要通过系统调用与内核打交道,比如一些数学函数等,但涉及与内核空间进行交互的 API 内部会封装系统调用。一个 API 可能只对应一个系统调用,也可能内部由多个...

    寒江独钓-Windows内核安全编程(高清完整版).part3

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    寒江独钓-Windows内核安全编程(高清完整版).part7

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    《深入分析Linux内核源代码》

    第三章 中断机制 第四章 进程描述 第五章 进程调度与切换 第六章 Linux 内存管理 第七章 进程间通信 第八章 虚拟文件系统 第九章 Ext2 文件系统 第十章 模块机制 第十一章 设备驱动程序 第十二章 网络 第十三章 ...

    寒江独钓-Windows内核安全编程(高清完整版).part6

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    Linux内核源代码分析视频课-视频教程网盘链接提取码下载.txt

    本课程从理解计算机硬件的核心工作机制(存储程序计算机和函数调用堆栈)和用户态程序如何通过系统调用陷入内核(中断异常)入手,通过上下两个方向双向夹击的策略,并利用实际可运行程序的反汇编代码从实践的角度...

    Windows内核安全驱动开发(随书光盘)

    第1章 内核上机指导 2 1.1 下载和使用WDK 2 1.1.1 下载并安装WDK 2 1.1.2 编写第一个C文件 4 1.1.3 编译一个工程 5 1.2 安装与运行 6 1.2.1 下载一个安装工具 6 1.2.2 运行与查看输出信息 7 1.2.3 在虚拟机...

Global site tag (gtag.js) - Google Analytics