RTAI的用户空间编程(八)——中断

本文档为整理及示例代码展示,相关内容可见文档rtai_man_API官方说明第68-75页。

1. PIC(可编程中断控制器)管理函数

#include "rtai.h"
void rt_startup_irq(unsigned int irq);
//启动并初始化PIC确认中断请求irq

void rt_shutdown_irq(unsigned int irq);
//关闭PIC,不再确认中断请求irq

void rt_enable_irq(unsigned int irq);
//使能PIC中断请求irq

void rt_disable_irq(unsigned int irq);
//禁止PIC中断请求irq

void rt_mask_and_ack_irq(unsigned int irq);
//屏蔽(mask)中断请求,并承认,这样一旦CPU启用中断了,其他中断就能被确认,它们依赖于处理的PIC和编程方式。

void rt_unmask_irq (unsigned int irq);
//不屏蔽PIC中断请求irq,这样相关请求就能再次中断CPU,只要它还被承认

void rt_ack_irq (unsigned int irq);
//承认PIC中断请求irq,这样相关请求就能再次中断CPU,只要它没被屏蔽

以上函数允许您操纵手上的PIC,但是你必须清楚你在做什么。这种职责不适合本手册,你应该参考你的PIC数据表。

注意,linux具备相同的功能,但是只能用来处理它们自己的中断,只有以上函数能安全地在实时处理程序中使用。

再次声明,当你安装了一个实时处理程序时,在传递控制到你的中断处理程序前,RTAI要么已经调用了rt_mask_and_ack_irq,来处理水平触发中断(level triggered interrupts),要么已经调用了rt_ack_irq来处理边缘触发中断(edge triggered interrupts)。通常你应该只在适当的时候对水平触发中断调用rt_unmask_irq,对边缘触发中断什么都不做。在后一种情况下,一旦你使能了CPU级别的中断,应该尽快允许任何在相同的请求上的新中断。

通常某些上面的函数能做等效的事情。除了通过了解硬件没有正确处理方法时,你可以再一次手动操作一次。

而且你必须记住,当你安装一个实时处理程序时,相关的中断通常是禁止的,除非你超出(overtake)了那个linux已有的已经被它使能了的那个。记住如果已经正确处理了,中断也没有出现,有可能你只需rt_enable_irq你的irq。

返回:
无。在24.1.11rt_start_irq返回的不是void类型,而是unsigned long。

int rt_assign_irq_to_cpu (int irq, int cpu);
//强迫外部中断irq的分配转到CPUcpu
int rt_reset_irq_to_sym_mode (int irq);
//重置中断irq为对称(symmetric)中断管理,对称模式在所有CPU上分配IRQ。

返回:
如果系统上只有一个CPU,返回1
如果至少有两个,成功,返回0
如果cpu指向的是不存在的CPU,返回CPU的数目
其他失败,返回一个负值
负值定义如下:
EINVAL (irq 不是有效的IRQ数或者发现某些内部数据不一致。
(irq is not a valid IRQ number or some internal data inconsistency is found.)

注意:
- 这些功能只对多处理器系统有影响。
- 有了linux2.4.xx,这样的服务最终在原始内核本地可用
- 有了这样的linux版本,rt_reset_irq_to_sym_mode,重置原始linux交付模式,或者它们称之为的交付亲和力(deliver affinity)。警告:这样的名字主要是为了兼容性原因才保存的,对于这样一个内核,重置操作不一定意味着对称外部中断交付。

int rt_request_global_irq (unsigned int irq, void (*handler)(void));
//为IRQ级别的irq安装函数handlers实时中断服务程序,最后窃取到LINUX。随后handlers在中断数irq发生的时候被援用。安装的handler必须处理好他窃取的使用相同的irq数的linux handler,用rt_pend_linux_irq来适当激活

int rt_free_global_irq (unsigned int irq);
//卸载中断服务程序,如果之前已经被内核拥有,则为linux重新设置它

int request_RTirq (unsigned int irq, void (*handler)(void));
int free_RTirq (unsigned int irq);
//rtai.h里定义的宏,只有我们为2.0.35做的变体RT_linux以向后兼容支持它。他们完全等效于上面两个函数。

int rt_request_linux_irq (unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), char *linux_handler_id, void *dev_id);
//作为标准linux中断服务进程为IQO级别的irq安装函数处理程序,迫使linux和其他中断处理程序共享IRQ,就算它不希望这样。处理程序附加到任何已经存在的处理同样的irq的linux处理程序上,作为linux irq自己的处理程序运行。这样实时应用可以以自身的意愿监视linux中断处理程序。处理程序出现在/pro/interrupts.
//linux_handler_id 是/pro/interrupts的名称。参数dev_id是以与标准linux irq请求调用同样的方式传给中断处理程序的。

int rt_free_linux_irq (unsigned int irq, void *dev_id);
//

void rt_pend_linux_irq (unsigned int irq);
//给linux服务一个中断,附加一个linux中断irq用于linux IRQ模式处理,也就是,同时硬件中断完全启用。

示例代码

#include "rtai.h"
#include "rtai_srq.h"
int rt_request_srq (unsigned int label, void (*rtai_handler)(void),long long (*user_handler)(unsigned int whatever));
int rt_free_srq (unsigned int srq);
void rt_pend_linux_srq (unsigned int srq);

2. 内核模块(?)
This is the ways to write your ISR to prevent it from being preempted:

your_isr()
{
    disable_sched();

    //Your actual ISR code goes here....

    enable_sched();
}

在RTAI和Linux间共享IRQ

static struct pci_dev* plx;

static void PLX_linuxPostIrqHandler( int irq, void *dev_id,
                                 struct pt_regs *regs)
{
    rt_enable_irq(plx->irq);
}

static void PLX_irqHandler(void )
{
...
    /* Lock scheduling */
    rt_sched_lock();

    // Do the realtime irq handling if required

...
    /* The irq is not for me, give to linux */
    if (!myIrq)
    {
        rt_mask_and_ack_irq(plx->irq);
        rt_pend_linux_irq(plx->irq);
    }

    /* Unlock scheduling */
    rt_sched_unlock();
}


//init_module
...
/* Register irq handler */
rt_request_global_irq( plx->irq, PLX_irqHandler );
rt_request_linux_irq( plx->irq, PLX_linuxPostIrqHandler,
                            "LINUX_POST_IRQHANDLER", PLX_linuxPostIrqHandler );
    rt_startup_irq(plx->irq);
    rt_enable_irq( plx->irq );
..

//cleanup
...

rt_disable_irq( plx->irq );
rt_free_global_irq( plx->irq );
rt_free_linux_irq( plx->irq, PLX_linuxPostIrqHandler );

你可能感兴趣的:(Linux,RTAI)