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

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2016-09-27 18:17:35

/**
 * 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中定义
 asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_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();
 set_irq_regs(old_regs);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
irq.h中定义
static inline void generic_handle_irq(unsigned int irq)
{
 
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();//
 即为 s3c24xx_init_irq
//////////////////////////////////////////////////////////////////以下为注释
//set_up.c 中有setup_arch()中有init_arch_irq=mdesc->init_irq;对于S3C2410,S3C2440开发板,mach_smdk2410.c中有
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch* to SMDK2410 */
 .phys_io = S3C2410_PA_UART,
 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 .boot_params = S3C2410_SDRAM_PA + 0x100,
 .map_io  = smdk2410_map_io,
 .init_irq = s3c24xx_init_irq,
 .init_machine = smdk2410_init,
 .timer  = &s3c24xx_timer,
MACHINE_END
//////////////////////////////////////////////////////////////////////以上为注释

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* s3c24xx_init_irq
 *
 * Initialise S3C2410 IRQ system
*/
void __init s3c24xx_init_irq(void)
{
 unsigned long pend;
 unsigned long last;
 int irqno;
 int i;
 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
 /* first, clear all interrupts pending... */
 last = 0;
 for (i = 0; i < 4; i++) {
  pend = __raw_readl(S3C24XX_EINTPEND);
  if (pend == 0 || pend == last)
   break;
  __raw_writel(pend, S3C24XX_EINTPEND);
  printk("irq: clearing pending ext status %08x\n", (int)pend);
  last = pend;
 }
 last = 0;
 for (i = 0; i < 4; i++) {
  pend = __raw_readl(S3C2410_INTPND);
  if (pend == 0 || pend == last)
   break;
  __raw_writel(pend, S3C2410_SRCPND);
  __raw_writel(pend, S3C2410_INTPND);
  printk("irq: clearing pending status %08x\n", (int)pend);
  last = pend;
 }
 last = 0;
 for (i = 0; i < 4; i++) {
  pend = __raw_readl(S3C2410_SUBSRCPND);
  if (pend == 0 || pend == last)
   break;
  printk("irq: clearing subpending status %08x\n", (int)pend);
  __raw_writel(pend, S3C2410_SUBSRCPND);
  last = pend;
 }
 /* register the main interrupts */
 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
 for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
  /* set all the s3c2410 internal irqs */
  switch (irqno) {
   /* deal with the special IRQs (cascaded) */
  case IRQ_EINT4t7:
  case IRQ_EINT8t23:
  case IRQ_UART0:
  case IRQ_UART1:
  case IRQ_UART2:
  case IRQ_ADCPARENT:
   set_irq_chip(irqno, &s3c_irq_level_chip);
   set_irq_handler(irqno, handle_level_irq);
   break;
  case IRQ_RESERVED6:
  case IRQ_RESERVED24:
   /* no IRQ here */
   break;
  default:
   //irqdbf("registering irq %d (s3c irq)\n", irqno);
   set_irq_chip(irqno, &s3c_irq_chip);
   set_irq_handler(irqno, handle_edge_irq);
   set_irq_flags(irqno, IRQF_VALID);
  }
 }
 /* setup the cascade irq handlers */
 set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
 set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
 /* external interrupts */
 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
  irqdbf("registering irq %d (ext int)\n", irqno);
  set_irq_chip(irqno, &s3c_irq_eint0t4);
  set_irq_handler(irqno, handle_edge_irq);
  set_irq_flags(irqno, IRQF_VALID);
 }
 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
  irqdbf("registering irq %d (extended s3c irq)\n", irqno);
  set_irq_chip(irqno, &s3c_irqext_chip);        //以后就就可以通过irq_desc[irqno].chip结构中的函数指针设置这些外部中断的触发方式了
  set_irq_handler(irqno, handle_edge_irq);//设置中断入口函数,handle_edge_irq函数会调用用户注册的具体处理函数
  set_irq_flags(irqno, IRQF_VALID); //设置中断标志,表示可以使用

 }
 /* register the uart interrupts */
 irqdbf("s3c2410: registering external interrupts\n");
 for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
  irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
  set_irq_chip(irqno, &s3c_irq_uart0);
  set_irq_handler(irqno, handle_level_irq);
  set_irq_flags(irqno, IRQF_VALID);
 }
 for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
  irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
  set_irq_chip(irqno, &s3c_irq_uart1);
  set_irq_handler(irqno, handle_level_irq);
  set_irq_flags(irqno, IRQF_VALID);
 }
 for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
  irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
  set_irq_chip(irqno, &s3c_irq_uart2);
  set_irq_handler(irqno, handle_level_irq);
  set_irq_flags(irqno, IRQF_VALID);
 }
 for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
  irqdbf("registering irq %d (s3c adc irq)\n", irqno);
  set_irq_chip(irqno, &s3c_irq_adc);
  set_irq_handler(irqno, handle_edge_irq);
  set_irq_flags(irqno, IRQF_VALID);
 }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
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;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
arch/arm/plat-s3c24xx中irq.c中
static void 
s3c_irq_demux_extint8(unsigned int irq,
        struct irq_desc *desc)
{
 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
 eintpnd &= ~eintmsk;
 eintpnd &= ~0xff; /* ignore lower irqs */
 /* we may as well handle all the pending IRQs here */
 while (eintpnd) {
  irq = __ffs(eintpnd);
  eintpnd &= ~(1<
  irq += (IRQ_EINT4 - 4);
  generic_handle_irq(irq);
 }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
用户注册中断处理函数 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
 * @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;
 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);
  local_irq_restore(flags);
  enable_irq(irq);
 }
#endif
 return retval;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
manage.c中 

/*
 * 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:这个标志表明多个中断处理程序可以共享一个中断号。
图片 

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