免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 873 | 回复: 0
打印 上一主题 下一主题

Uclinux中断追踪 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-03-17 10:45 |只看该作者 |倒序浏览
最近在做uclinux设备驱动实验时,涉及到I2c总线的驱动。程序主要采取中断方试读写I2c数据。而uclinux中中断主要采用函数 request_irqrequest_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
   unsigned long irq_flags, const char * devname, void *dev_id)
申请获得中断号并注册中断函数。那么这个函数时到底如何管理中断的呢,它又是怎样管理ARM下的中断资源呢。本文将带你追踪如下:
首先,这个函数的源定义如下:
request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
   unsigned long irq_flags, const char * devname, void *dev_id)
{
unsigned long retval;
struct irqaction *action;
if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
     (irq_flags & SA_SHIRQ && !dev_id))
  return -EINVAL;
action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);   
if (!action)
  return -ENOMEM;
action->handler = handler;
action->flags = irq_flags;
action->mask = 0;
action->name = devname;
action->next = NULL;      
action->dev_id = dev_id;
retval = setup_arm_irq(irq, action);
if (retval)
  kfree(action);
return retval;
}
程序首先检查所要申请中断号是否越界,中断处理函数是否有效,并对中断标志和设备名称是否为空做出判断。注意还有irq_desc[irq].valid,关于这一项的意义,后面将给出解释。
接着,向内核申请一个irqaction结构,并且填充这个结构。最后调用函数setup_arm_irq()。
下面先来解释一下irqaction结构,其完整定义如下:
struct irqaction {
        void (*handler)(int, void *, struct pt_regs *);  //中断处理函数
        unsigned long flags;                             //中断管理有关的位掩码
        unsigned long mask;
        const char *name;                             //中断拥有者名称
        void *dev_id;                                  //用于共享的中断信号线
        struct irqaction *next;                         //构成链表
};
irqaction结构包含中断申请者的所有信息,而request_irq函数填充一个中断申请者结构,然后通过函数setup_arm_irq向系统申请中断。在解释函数setup_arm_irq之前先来解释一下irqdesc结构
struct irqdesc {
        unsigned int     nomask   : 1;          /* IRQ does not mask in IRQ   */   
        unsigned int     enabled  : 1;          /* IRQ is currently enabled   */      
        unsigned int     triggered: 1;          /* IRQ has occurred           */      
        unsigned int     probing  : 1;          /* IRQ in use for a probe     */      
        unsigned int     probe_ok : 1;          /* IRQ can be used for probe  */        
        unsigned int     valid    : 1;          /* IRQ claimable              */        
        unsigned int     noautoenable : 1;      /* don't automatically enable IRQ */
        unsigned int     unused   :25;
        void (*mask_ack)(unsigned int irq);     /* Mask and acknowledge IRQ   */      
        void (*mask)(unsigned int irq);         /* Mask IRQ                   */        
        void (*unmask)(unsigned int irq);       /* Unmask IRQ                 */        
        struct irqaction *action;
        /*
         * IRQ lock detection
         */
        unsigned int     lck_cnt;
        unsigned int     lck_pc;
        unsigned int     lck_jif;
};
irqdesc包含了中断的基本信息,并且还包含了一个中段申请者的指针。程序在初始化时定义了一个全局的irqdesc数组
irqdesc irq_desc[];
下面来看函数
int setup_arm_irq(int irq, struct irqaction * new)
{
int shared = 0;         //判断中断是否被共享
struct irqaction *old, **p;
unsigned long flags;
struct irqdesc *desc;
/*
  * Some drivers like serial.c use request_irq() heavily,
  * so we have to be careful not to interfere with a
  * running system.
  */
if (new->flags & SA_SAMPLE_RANDOM) {
  /*
   * This function might sleep, we want to call it first,
   * outside of the atomic block.
   * Yes, this might clear the entropy pool if the wrong
   * driver is attempted to be loaded, without actually
   * installing a new handler, but is this really a problem,
   * only the sysadmin is able to do this.
   */
         rand_initialize_irq(irq);
}
/*
  * The following block of code has to be executed atomically
  */
desc = irq_desc + irq;   //desc就是irq_desc[irq]
spin_lock_irqsave(&irq_controller_lock, flags);
p = &desc->action;
if ((old = *p) != NULL) {     
  /* Can't share interrupts unless both agree to */
  if (!(old->flags & new->flags & SA_SHIRQ)) {
   spin_unlock_irqrestore(&irq_controller_lock, flags);
   return -EBUSY;
  }
  /* add new interrupt at end of irq queue */
  do {
   p = &old->next;
   old = *p;
  } while (old);
  shared = 1;
}
*p = new;
if (!shared) {
  desc->probing = 0;
  desc->running = 0;
  desc->pending = 0;
  desc->disable_depth = 1;
  if (!desc->noautoenable) {
   desc->disable_depth = 0;
   desc->unmask(irq);
  }
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
return 0;
}
以上函数其本功能时根据irq中断号,来申请irq_desc[irq]这个中断结构,如果这个结构没被其他的设备占用,则申请成功,并且填充这个结构。这个结构是系统中断管理最重的结构。最后内核是如何利用这个结构来进行中断函数调用呢,我将继续追踪


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/15800/showart_86704.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP