ARM based Linux中断(四)

下面介绍三对管理中断的函数,这些函数都是对第2节中提到的内核中的数据结构进行操作。第一对:request_irq和free_irq一般用于动态注册irq_action结构到内核,在设备驱动中使用;第二对:setup_irq和remove_irq用于静态的注册irq_action,一般用于启动之处的函数的注册和移除;第三对:__setup_irq和__free_irq仅用于内核中断核心代码,一般内核开发人员不能使用。

1.1      rquest_irq

reques_irq的实现是与平台无关的代码,其原型在所有的体系结构上都是相同的,因为这对编写平台无关的驱动来说是一个先决条件。request_irq的调用流程如下:

request_irq

       request_threaded_irq

              __setup_irq

intrequest_threaded_irq(unsigned int irq, irq_handler_t handler,

                      irq_handler_t thread_fn, unsigned longirqflags,

                      const char *devname, void *dev_id)

{

       struct irqaction *action;

       struct irq_desc *desc;

       int retval;

      

       if ((irqflags & IRQF_SHARED)&& !dev_id)

              return -EINVAL;

 

       desc =irq_to_desc(irq);

       if (!desc)

              return -EINVAL;

 

       if (!irq_settings_can_request(desc))

              return -EINVAL;

 

       if (!handler) {

              if (!thread_fn)

                     return -EINVAL;

              handler =irq_default_primary_handler;

       }

 

       action =kzalloc(sizeof(struct irqaction), GFP_KERNEL);

       if (!action)

              return -ENOMEM;

 

       action->handler = handler;

       action->thread_fn = thread_fn;

       action->flags = irqflags;

       action->name = devname;

       action->dev_id = dev_id;

 

       chip_bus_lock(desc);

       retval =__setup_irq(irq, desc, action);

       chip_bus_sync_unlock(desc);

 

       if (retval)

              kfree(action);

       …… …….

       return retval;

}

request_threaded_irq主要生成一个新的irqaction实例,然后用函数参数填充内容。然后将后续的工作交给__setup_irq来完成。

1.2      __setup_irq

static int

__setup_irq(unsignedint irq, struct irq_desc *desc, struct irqaction *new)

{

       if (new->flags & IRQF_SAMPLE_RANDOM) {       

              rand_initialize_irq(irq);

       }

 

       nested = irq_settings_is_nested_thread(desc);

       if (nested) {

              if (!new->thread_fn)

                     return -EINVAL;

      

              new->handler =irq_nested_primary_handler;

       } else {

              if (irq_settings_can_thread(desc))

                     irq_setup_forced_threading(new);

       }

 

       if(new->thread_fn && !nested) {

              struct task_struct *t;

 

              t = kthread_create(irq_thread,new, "irq/%d-%s", irq,

                               new->name);

              if (IS_ERR(t))

                     return PTR_ERR(t);

             

              get_task_struct(t);

              new->thread = t;

       }

 

       if (!alloc_cpumask_var(&mask,GFP_KERNEL)) {

              ret = -ENOMEM;

              goto out_thread;

       }

 

       /*

        *The following block of code has to be executed atomically

        */

       raw_spin_lock_irqsave(&desc->lock,flags);

       old_ptr = &desc->action;

       old = *old_ptr;

       if (old) {

              /* add new interrupt at end of irq queue */

              do {

                     thread_mask |=old->thread_mask;

                     old_ptr =&old->next;

                     old = *old_ptr;

              } while (old);

              shared = 1;

       }

 

       …… ……

 

       register_irq_proc(irq,desc);

       new->dir = NULL;

       register_handler_proc(irq,new);

       free_cpumask_var(mask);

       …… ……

       return 0;

}

该函数主要完成以下工作:

(1)       如果设置了IRQF_SAMPLE_RANDOM,则该中断将对内核熵池有所贡献。

 

1.3      setup_irq

intsetup_irq(unsigned int irq, struct irqaction *act)

{

       int retval;

       struct irq_desc *desc = irq_to_desc(irq);

 

       chip_bus_lock(desc);

       retval = __setup_irq(irq, desc, act);

       chip_bus_sync_unlock(desc);

 

       return retval;

}

该函数用来在启动之处,静态的注册action到系统中。

1.4      __free_irq

static structirqaction *__free_irq(unsigned int irq, void *dev_id)

{

       struct irq_desc*desc = irq_to_desc(irq);

       struct irqaction *action, **action_ptr;

       unsigned long flags;

 

       WARN(in_interrupt(), "Trying to freeIRQ %d from IRQ context!\n", irq);

 

       if (!desc)

              return NULL;

 

       raw_spin_lock_irqsave(&desc->lock,flags);

 

       /*

        *There can be multiple actions per IRQ descriptor, find the right

        *one based on the dev_id:

        */

       action_ptr =&desc->action;

       for (;;) {

              action = *action_ptr;

 

              if (!action) {

                     WARN(1, "Trying tofree already-free IRQ %d\n", irq);

                     raw_spin_unlock_irqrestore(&desc->lock,flags);

 

                     return NULL;

              }

 

              if (action->dev_id == dev_id)

                     break;

              action_ptr = &action->next;

       }

 

       /* Found it - now remove it from the listof entries: */

       *action_ptr = action->next;

       …… ……

return action;

}

 

该函数主要完成的工作是,根据irq和dev_id找到对应的irqaction结构,从irq_desc的action链表中删除该结构,然后返回该结构的指针。

1.5      free_irq

voidfree_irq(unsigned int irq, void *dev_id)

{

       struct irq_desc *desc = irq_to_desc(irq);

 

       if (!desc)

              return;

 

#ifdefCONFIG_SMP

       if (WARN_ON(desc->affinity_notify))

              desc->affinity_notify = NULL;

#endif

 

       chip_bus_lock(desc);

       kfree(__free_irq(irq, dev_id));

       chip_bus_sync_unlock(desc);

}

该函数的功能是调用__free_irq找到irq对应的irq_desc结构,然后释放对应的irq_action结构。但要注意的是该函数不能在中断上下文中使用,以为kfree可能导致睡眠。

1.6      remove_irq

voidremove_irq(unsigned int irq, struct irqaction *act)

{

       __free_irq(irq, act->dev_id);

}

remove_irq函数主要调用__free_irq移除中断。和free_irq不同的地方是没有释放irq_action的内存空间,因此该函数只能用来移除在启动之初的时候使用setup_irq静态setup的中断。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值