Chinaunix首页 | 论坛 | 博客
  • 博客访问: 434511
  • 博文数量: 99
  • 博客积分: 65
  • 博客等级: 民兵
  • 技术积分: 1012
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-20 16:30
个人简介

linux kernel 工程师

文章分类

全部博文(99)

文章存档

2018年(5)

2017年(12)

2016年(27)

2015年(10)

2014年(43)

2012年(2)

我的朋友

分类: LINUX

2014-02-08 15:14:36

注册中断的函数是request_irq,实际上这个函数会调用request_threaded_irq,但由于
调用request_threaded_irq(irq, handler, NULL, flags, name, dev);时,参数3,也就是thread_fn为NULL,
调用request_irq注册的isr不会被线程化。


request_threaded_irq(unsigned int irq, irq_handler_t handler,
       irq_handler_t thread_fn,
       unsigned long flags, const char *name, void *dev);

static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
     const char *name, void *dev)
{
 return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

-----------------------------------------------------------------------------
下面介绍下request_threaded_irq

线程化的中断服务程序,包括两部分
 handler, 在中断环境下执行的程序
thread_fn 在线程环境下执行的程序, 如果为NULL,就不会为当前注册的中断产生一个专门的内核线程

/**
 * request_threaded_irq - allocate an interrupt line
 * @irq: Interrupt line to allocate
 * @handler: Function to be called when the IRQ occurs.
 *    Primary handler for threaded interrupts
 *    If NULL and thread_fn != NULL the default
 *    primary handler is installed
 * @thread_fn: Function called from the irq handler thread
 *      If NULL, no irq thread is created
 * @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.
 *
 * If you want to set up a threaded irq handler for your device
 * then you need to supply @handler and @thread_fn. @handler is
 * still called in hard interrupt context and has to check
 * whether the interrupt originates from the device. If yes it
 * needs to disable the interrupt on the device and return
 * IRQ_WAKE_THREAD which will wake up the handler thread and run
 * @thread_fn. This split handler design is necessary to support
 * shared interrupts.
 *
 * 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_TRIGGER_*  Specify active edge(s) or level
 *
 */

/*
关于IRQF_ONESHOT, 直到线程函数执行完毕才会开启该中断
 IRQF_ONESHOT:Interrupt is not reenabled after the hardirq handler finished.
    Used by threaded interrupts which need to keep the irq line disabled until
the threaded handler has been run. */
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
    irq_handler_t thread_fn, unsigned long irqflags,
    const char *devname, void *dev_id)
{
 struct irqaction *action;
 struct irq_desc *desc;
 int retval;

 /*
  * 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).
  */
 /* 如果是共享中断,dev_id不能为NULL,否则在free_irq时,没有devid作为参照,无法释放 */
 if ((irqflags & IRQF_SHARED) && !dev_id)
  return -EINVAL;

 desc = irq_to_desc(irq);
 if (!desc)
  return -EINVAL;

 if (!irq_settings_can_request(desc) ||
     WARN_ON(irq_settings_is_per_cpu_devid(desc)))
  return -EINVAL;

 if (!handler) {
  if (!thread_fn)
   return -EINVAL;
  handler = irq_default_primary_handler;
 }

 /* 分配一个action, handler,thread_fn赋给action
 action->handler,
 action->thread_fn  */
 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); /* 安装这个action */
 chip_bus_sync_unlock(desc);

 if (retval)
  kfree(action);

#ifdef CONFIG_DEBUG_SHIRQ_FIXME
 if (!retval && (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;
}

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

Chris_Dou2019-10-04 16:32:50

你好,我在ubuntu上开发一个中断响应时间测试程序,想注册一个中断,但是使用#include <linux/interrupt.h>等头文件的时候提示不存在这些头文件,我查寻之后发现这些头文件都在usr/src/linux-headers-4.4.0-21/include/linux 中,我该怎么做才能调用这些头文件呢??
请大神赐教!!