Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1183419
  • 博文数量: 221
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2139
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(221)

文章存档

2024年(6)

2023年(8)

2022年(2)

2021年(2)

2020年(29)

2019年(11)

2018年(23)

2017年(41)

2016年(76)

2015年(23)

我的朋友
最近访客

分类: LINUX

2016-10-14 17:18:20

参考博文http://blog.chinaunix.net/uid-25845340-id-2983156.html
/**
 * struct irq_desc - interrupt descriptor
 * @irq:  interrupt number for this descriptor
 * @handle_irq:  highlevel irq-events handler [if NULL, __do_IRQ()]
 * @chip:  low level interrupt hardware access
 * @msi_desc:  MSI descriptor
 * @handler_data: per-IRQ data for the irq_chip methods
 * @chip_data:  platform-specific per-chip private data for the chip
 *   methods, to allow shared chip implementations
 * @action:  the irq action chain
 * @status:  status information
 * @depth:  disable-depth, for nested irq_disable() calls
 * @wake_depth:  enable depth, for multiple set_irq_wake() callers
 * @irq_count:  stats field to detect stalled irqs
 * @irqs_unhandled: stats field for spurious unhandled interrupts
 * @last_unhandled: aging timer for unhandled count
 * @lock:  locking for SMP
 * @affinity:  IRQ affinity on SMP
 * @cpu:  cpu index useful for balancing
 * @pending_mask: pending rebalanced interrupts
 * @dir:  /proc/irq/ procfs entry
 * @name:  flow handler name for /proc/interrupts output
 */

struct irq_desc {
 unsigned int  irq;
 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 int  irqs_unhandled;
 unsigned long  last_unhandled; /* Aging timer for unhandled count */
 spinlock_t  lock;
#ifdef CONFIG_SMP
 cpumask_t  affinity;
 unsigned int  cpu;
#endif
#ifdef CONFIG_GENERIC_PENDING_IRQ
 cpumask_t  pending_mask;
#endif
#ifdef CONFIG_PROC_FS
 struct proc_dir_entry *dir;
#endif
 const char  *name;
} ____cacheline_internodealigned_in_smp;


extern struct irq_desc irq_desc[NR_IRQS];
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
尤entry_armv.s 里面的中断底层汇编可知asm_do_IRQ函数式中断的C语言总入口函数。它在arch/arm/kernel/irq.c中定义

               /**

 * 我们暂且可以认为,绝大部分中断是从汇编跳到本函数处理的。当然,IPIlocal_timer不是。

 *                 irq:            产生中断的外部中断号。

 *                  regs:                  被中断打断的寄存器现场。

 */

 asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{


           /**

     * 将当前正在处理的中断现场保存到每CPU变量__irq_regs中去。

     * 这样做的目的,是为了在其他代码中,直接读取__irq_regs中的值,找到中断前的现场。

     * 而不用将regs参数层层传递下去。

     */

 

 struct pt_regs *old_regs = set_irq_regs(regs);
 irq_enter();
 /*
  * Some hardware gives randomly wrong interrupts.  Rather
  * than crashing, do something sensible.
  */
 if (irq >= NR_IRQS) //
中断号错误,超过最大中断号 
     handle_bad_irq(irq, &bad_irq_desc);
 else
  
generic_handle_irq(irq);//
/* 这里进行正常的中断处理 */
 /* AT91 specific workaround */
 irq_finish(irq);
 irq_exit();
//
恢复__irq_regsCPU变量的内容。
 set_irq_regs(old_regs);
}
////////////////
include/asm-generic/irq_regs.h

//这个函数就是记录中断现场
static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
{
    struct pt_regs *old_regs, **pp_regs = &__get_cpu_var(__irq_regs);

    old_regs = *pp_regs;
    *pp_regs = new_regs;
    return old_regs;
}
///////////////////////////////

               /**

     * 中断退出过程,主要处理以下内容:

     *              1、调试钩子,记录退出中断的事实。

     *              2、在任务的抢占计数字段中,递减中断计数

     *              3、处理软中断

     *              4、调用rcu模块的函数,表示已经退出中断。

     */



 
/*
 * Exit an interrupt context. Process softirqs if needed and possible:
 */
void irq_exit(void)
{
    account_system_vtime(current);
    trace_hardirq_exit();
    sub_preempt_count(IRQ_EXIT_OFFSET);
    if (!in_interrupt() && local_softirq_pending())
        invoke_softirq();

#ifdef CONFIG_NO_HZ
    /* Make sure that timer wheel updates are propagated */
    if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched())
        tick_nohz_stop_sched_tick(0);
    rcu_irq_exit();
#endif
    preempt_enable_no_resched();
}
/////////////////////////////////

               /**

     * 调用irq_enter表示进入中断处理过程。该函数进行如下处理:

     *              1rcu模块记录内部计数,表示当前退出了NOHZ状态。关于rcu,需要整整一本书来描述,请从下载<深入理解并行编程>了解更多内容。

     *              2、处理NOHZ事件。

     *              3、将当前任务的抢占计数中的硬中断计数加1.该计数表示当前中断嵌套层次。

     *              4、调试信息,表示当前已经进入中断的事实。

     */


/*
 * Enter an interrupt context.
 */
void irq_enter(void)
{
    int cpu = smp_processor_id();

    if (idle_cpu(cpu) && !in_interrupt()) {
        __irq_enter();
        tick_check_idle(cpu);
    } else
        __irq_enter();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void s3c_irq_demux_timer0(unsigned int irq, struct irq_desc *desc)
{
    s3c_irq_demux_timer(irq, IRQ_TIMER0);
}
//////////////////////////////////////////////////////////////


 
/* Timer interrupt handling */

static void s3c_irq_demux_timer(unsigned int base_irq, unsigned int sub_irq)
{
    generic_handle_irq(sub_irq);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
中定义
static inline void generic_handle_irq(unsigned int irq)
{
   // * 根据中断描述符中的信息,得到该中断ISR,并处理中断。


 generic_handle_irq_desc(irq, irq_to_desc(irq));

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
 * Architectures call this to let the generic IRQ layer
 * handle an interrupt. If the descriptor is attached to an
 * irqchip-style controller then we call the ->handle_irq() handler,
 * and it calls __do_IRQ() if it's attached to an irqtype-style controller.
 */

中定义
 
static inline void
generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
 desc->handle_irq(irq, desc);
#else
 if (likely(desc->handle_irq))
  desc->handle_irq(irq, desc);
 
 //此处调用s3c24xx_init_irq()中 set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8)的s3c_irq_demux_extint8()
 else
  __do_IRQ(irq);
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
handle.c
unsigned int __do_IRQ(unsigned int irq)
{
 struct irq_desc *desc = irq_to_desc(irq);
 struct irqaction *action;
 unsigned int status;
  spin_lock(&desc->lock);
 /*
  * REPLAY is when Linux resends an IRQ that was dropped earlier
  * WAITING is used by probe to mark irqs that are being tested
  */
 status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
 status |= IRQ_PENDING; /* we _want_ to handle it */
 /*
  * If the IRQ is disabled for whatever reason, we cannot
  * use the action we have.
  */
 action = NULL;
 if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
  action = desc->action;
  status &= ~IRQ_PENDING; /* we commit to handling */
  status |= IRQ_INPROGRESS; /* we are handling it */
 }
 desc->status = status;
 /*
  * If there is no IRQ handler or it was disabled, exit early.
  * Since we set PENDING, if another processor is handling
  * a different instance of this same irq, the other processor
  * will take care of it.
  */
 if (unlikely(!action))
  goto out;
 /*
  * Edge triggered interrupts need to remember
  * pending events.
  * This applies to any hw interrupts that allow a second
  * instance of the same irq to arrive while we are in do_IRQ
  * or in the handler. But the code here only handles the _second_
  * instance of the irq, not the third or fourth. So it is mostly
  * useful for irq hardware that does not mask cleanly in an
  * SMP environment.
  */
 for (;;) {
  irqreturn_t action_ret;
  spin_unlock(&desc->lock);
  action_ret = handle_IRQ_event(irq, action);//通过此函数逐个执行action链表中用户注册的中断处理函数
  if (!noirqdebug)
   note_interrupt(irq, desc, action_ret);
  spin_lock(&desc->lock);
  if (likely(!(desc->status & IRQ_PENDING)))
   break;
  desc->status &= ~IRQ_PENDING;
 }
 desc->status &= ~IRQ_INPROGRESS;
out:
 /*
  * The ->end() handler has to deal with interrupts which got
  * disabled while the handler was running.
  */
 desc->chip->end(irq);
 spin_unlock(&desc->lock);
 return 1;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
handle.c
/**
 * handle_IRQ_event - irq action chain handler
 * @irq: the interrupt number
 * @action: the interrupt action chain for this irq
 *
 * Handles the action chain of an irq event
 */
irqreturn_t
handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
 irqreturn_t ret, retval = IRQ_NONE;
 unsigned int status = 0;
 if (!(action->flags & IRQF_DISABLED))
  local_irq_enable_in_hardirq();
 do {
  ret =
action->handler(irq, action->dev_id);
  if (ret == IRQ_HANDLED)
   status |= action->flags;
  retval |= ret;
  action = action->next;
 } while (action);
 if (status & IRQF_SAMPLE_RANDOM)
  add_interrupt_randomness(irq);
 local_irq_disable();
 return retval;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/init/main.c asmlinkage void __init start_kernel(void) --->调用 arch/arm/kernel/irq.c     void __init init_IRQ(void)


void __init init_IRQ(void)
{
 int irq;
 for (irq = 0; irq < NR_IRQS; irq++)
 
 irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
#ifdef CONFIG_SMP
 bad_irq_desc.affinity = CPU_MASK_ALL;
 bad_irq_desc.cpu = smp_processor_id();
#endif
 init_arch_irq();//
 即为 s3c6410_init_irq
//////////////////////////////////////////////////////////////////以下为注释
//set_up.c 中有setup_arch()中有init_arch_irq=mdesc->init_irq;对于S3C2410,S3C2440开发板,中有
MACHINE_START(SMDK6410, "SMDK6410")
    /* Maintainer: Ben Dooks */
    .phys_io    = S3C_PA_UART & 0xfff00000,
    .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
    .boot_params    = S3C64XX_PA_SDRAM + 0x100,

    .init_irq    = s3c6410_init_irq,
    .map_io        = smdk6410_map_io,
    .init_machine    = smdk6410_machine_init,
    .timer        = &s3c64xx_timer,
MACHINE_END

//////////////////////////////////////////////////////////////////////以上为注释

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 
void __init s3c6410_init_irq(void)
{
    /* VIC0 is missing IRQ7, VIC1 is fully populated. */
    s3c64xx_init_irq(~0 & ~(1 << 7), ~0);
}
//////////////////////////////////////////////////////////////////////////////////////////////

void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
{
    int uart, irq;

    printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);

    /* initialise the pair of VICs */
    vic_init(S3C_VA_VIC0, S3C_VIC0_BASE, vic0_valid);
    vic_init(S3C_VA_VIC1, S3C_VIC1_BASE, vic1_valid);

    /* add the timer sub-irqs */

    set_irq_chained_handler(IRQ_TIMER0_VIC, s3c_irq_demux_timer0);
    set_irq_chained_handler(IRQ_TIMER1_VIC, s3c_irq_demux_timer1);
    set_irq_chained_handler(IRQ_TIMER2_VIC, s3c_irq_demux_timer2);
    set_irq_chained_handler(IRQ_TIMER3_VIC, s3c_irq_demux_timer3);
    set_irq_chained_handler(IRQ_TIMER4_VIC, s3c_irq_demux_timer4);

    for (irq = IRQ_TIMER0; irq <= IRQ_TIMER4; irq++) {
        set_irq_chip(irq, &s3c_irq_timer);
        set_irq_handler(irq, handle_level_irq);
        set_irq_flags(irq, IRQF_VALID);
    }

    for (uart = 0; uart < ARRAY_SIZE(uart_irqs); uart++)
        s3c64xx_uart_irq(&uart_irqs[uart]);
}
///////////////////////////////////



/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
 * are consecutive when looking up the interrupt in the demux routines.
 */
static struct uart_irq uart_irqs[] = {
    [0] = {
        .regs        = S3C_VA_UART0,
        .base_irq    = IRQ_S3CUART_BASE0,
        .parent_irq    = IRQ_UART0,
    },
    [1] = {
        .regs        = S3C_VA_UART1,
        .base_irq    = IRQ_S3CUART_BASE1,
        .parent_irq    = IRQ_UART1,
    },
    [2] = {
        .regs        = S3C_VA_UART2,
        .base_irq    = IRQ_S3CUART_BASE2,
        .parent_irq    = IRQ_UART2,
    },
    [3] = {
        .regs        = S3C_VA_UART3,
        .base_irq    = IRQ_S3CUART_BASE3,
        .parent_irq    = IRQ_UART3,
    },
};
//////////////////


 
static void __init s3c64xx_uart_irq(struct uart_irq *uirq)
{
    void *reg_base = uirq->regs;
    unsigned int irq;
    int offs;

    /* mask all interrupts at the start. */
    __raw_writel(0xf, reg_base + S3C64XX_UINTM);

    for (offs = 0; offs < 3; offs++) {
        irq = uirq->base_irq + offs;

        set_irq_chip(irq, &s3c_irq_uart);
        set_irq_chip_data(irq, uirq);
        set_irq_handler(irq, handle_level_irq);
        set_irq_flags(irq, IRQF_VALID);
    }

    set_irq_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
include/linux/irq.h中
static inline void
set_irq_chained_handler(unsigned int irq,
   irq_flow_handler_t handle)
{
 __set_irq_handler(irq, handle, 1, NULL);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
kernel/irq/chip.c
void  __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
    const char *name)
{
 
struct irq_desc *desc = irq_to_desc(irq);
 unsigned long flags;
 desc->handle_irq = handle;
 desc->name = name;
 if (handle != handle_bad_irq && is_chained) {
  desc->status &= ~IRQ_DISABLED;
  desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
  desc->depth = 0;
  desc->chip->startup(irq);
 }
 spin_unlock_irqrestore(&desc->lock, flags);
}
//////////////////////////////////////////////
static inline struct irq_desc *irq_to_desc(unsigned int irq)
{
 return (irq < nr_irqs) ? irq_desc + irq : NULL;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
irq.h中
static inline struct irq_desc
*irq_to_desc(unsigned int irq)
{
 return (irq < nr_irqs) ? irq_desc + irq : NULL;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
用户注册中断处理函数 manage.c
/**
 * 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 传递给request_irq的字符串,用来在/proc/interrupts中显示中断的拥有者
 * @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
 * IRQF_TRIGGER_*  Specify active edge(s) or level
 *
 */
在内核中用于申请中断的函数是request_irq(),函数原型在Kernel/irq/manage.c中定义:

int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)

irq是要申请的硬件中断号
handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。
irqflags是中断处理的属性,若 设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程 序不屏蔽;若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的 SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)
devname设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。
dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。

request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。

int request_irq(unsigned int irq, irq_handler_t handler,
  unsigned long irqflags, const char *devname, void *dev_id)

{
 struct irqaction *action;
 struct irq_desc *desc;
 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;
 desc = irq_to_desc(irq);          //根据中断号来获得关于中断资源的描述
 if (desc->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;
         ////__setup_irq函数,该函数才是真正的将中断注册
 retval = __setup_irq(irq, desc, action);
 if (retval)
  kfree(action);
#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 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);        //???为啥在这里立即调用了中断的handler函数(这是一个参数) 看看宏CONFIG_DEBUG_SHIRQ
  local_irq_restore(flags);
  enable_irq(irq);
 }
#endif
 return retval;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
manage.c中 

////__setup_irq函数,该函数才是真正的将中断注册 /*
 * Internal function to register an irqaction - typically used to
 * allocate special interrupts that are part of the architecture.
 */
static int
__setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
{
 struct irqaction *old, **p;
 const char *old_name = NULL;
 unsigned long flags;
 int shared = 0;
 int ret;

 /*
  * The following block of code has to be executed atomically
  */
 spin_lock_irqsave(&desc->lock, flags);
 p = &desc->action;
 old = *p;
 if (old) {
  /* add new interrupt at end of irq queue */ ????????????????????????????、
  do {
   p = &old->next;
   old = *p;
  } while (old);
  shared = 1;
 }
 if (!shared) {
  irq_chip_set_defaults(desc->chip);
  /* Setup the type (level, edge polarity) if configured: */
  if (new->flags & IRQF_TRIGGER_MASK) {
   ret = __irq_set_trigger(desc, irq, new->flags);
   if (ret) {
    spin_unlock_irqrestore(&desc->lock, flags);
    return ret;
   }
  } else
   compat_irq_chip_set_default_handler(desc);
  desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
      IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
  if (!(desc->status & IRQ_NOAUTOEN)) {
   desc->depth = 0;
   desc->status &= ~IRQ_DISABLED;
   desc->chip->startup(irq);
  } else
   /* Undo nested disables: */
   desc->depth = 1;
  /* Exclude IRQ from balancing if requested */
  if (new->flags & IRQF_NOBALANCING)
   desc->status |= IRQ_NO_BALANCING;
  /* Set default affinity mask once everything is setup */
  do_irq_select_affinity(irq, desc);
 } else if ((new->flags & IRQF_TRIGGER_MASK)
   && (new->flags & IRQF_TRIGGER_MASK)
    != (desc->status & IRQ_TYPE_SENSE_MASK)) {
  /* hope the handler works with the actual trigger mode... */
  pr_warning("IRQ %d uses trigger mode %d; requested %d\n",
    irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),
    (int)(new->flags & IRQF_TRIGGER_MASK));
 }
 *p = new;
 /* Reset broken irq detection when installing new handler */
 desc->irq_count = 0;
 desc->irqs_unhandled = 0;
 /*
  * Check whether we disabled the irq via the spurious handler
  * before. Reenable it and give it another chance.
  */
 if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
  desc->status &= ~IRQ_SPURIOUS_DISABLED;
  __enable_irq(desc, irq);
 }
 spin_unlock_irqrestore(&desc->lock, flags);
 new->irq = irq;
 register_irq_proc(irq, desc);
 new->dir = NULL;
 register_handler_proc(irq, new);
 return 0;
mismatch:
 spin_unlock_irqrestore(&desc->lock, flags);
 return -EBUSY;
/////////////////////////////////////////
arch/arm/kernel/setup.c      void __init setup_arch(char **cmdline_p)  调用

early_trap_init(void)
 
arch/arm/kernel/traps.c

void __init early_trap_init(void)
{

// include/linux/autoconf.h       #define CONFIG_VECTORS_BASE 0xffff0000
    unsigned long vectors = CONFIG_VECTORS_BASE;
    extern char __stubs_start[], __stubs_end[];
    extern char __vectors_start[], __vectors_end[];
    extern char __kuser_helper_start[], __kuser_helper_end[];
    int kuser_sz = __kuser_helper_end - __kuser_helper_start;

    /*
     * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
     * into the vector page, mapped at 0xffff0000, and ensure these
     * are visible to the instruction stream.
     */
//将_vectors_start到
__vectors_start之间的代码拷贝到0xffff0000

 
 
  memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
    memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
    memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

    /*
     * Copy signal return handlers into the vector page, and
     * set sigreturn to be a pointer to these.
     */
    memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
           sizeof(sigreturn_codes));

    flush_icache_range(vectors, vectors + PAGE_SIZE);
    modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}
 




中断共享
如果开发板上按键的中断已经被另外的驱动程序注册中断了,而我现在又想再注册一次这个中断,这就出现了一个中断号不止对应一个中断函数的情况。注意,这里与硬件上的共享中断不一样,这里是指,当一个中断信号来了,基于,一个中断的到来可以调用多个中断处理程序,与硬件无关。

SA_SHIRQ:这个标志表明多个中断处理程序可以共享一个中断号。
图片 

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