免费注册 查看新帖 |

Chinaunix

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

精通内核头文件的高手请救命! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-17 16:51 |只看该作者 |倒序浏览
我下载了内核2.6.31.4,解压缩后用source insight导入入了整个工程,也同步了项目。

然后我搜:request_irq 的定义,发现如下结果:

./include/linux/interrupt.h

#ifdef CONFIG_GENERIC_HARDIRQS

extern int __must_check 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);
}
extern void exit_irq_thread(void);

#else

extern int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);

/*
* Special function to avoid ifdeffery in kernel/irq/devres.c which
* gets magically built by GENERIC_HARDIRQS=n architectures (sparc,
* m68k). I really love these $@%#!* obvious Makefile references:
* ../../../kernel/irq/devres.o
*/
static inline int __must_check request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long flags, const char *name, void *dev)
{
        return request_irq(irq, handler, flags, name, dev);
}
static inline void exit_irq_thread(void) { }

#endif

可见,如果定义了 CONFIG_GENERIC_HARDIRQS, 这段程序的 request_irq 要调  request_threaded_irq ,于是我又搜  request_threaded_irq 的定义 ,于是在:

./kernel/irq/manage.c 中找到:

/**
* 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
* @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 ist
* 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_DISABLED Disable local interrupts while processing
* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
* IRQF_TRIGGER_*  Specify active edge(s) or level
*
*/
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;
/*
  * handle_IRQ_event() always ignores IRQF_DISABLED except for
  * the _first_ irqaction (sigh).  That can cause oopsing, but
  * the behavior is classified as "will not fix" so we need to
  * start nudging drivers away from using that idiom.
  */
if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) == (IRQF_SHARED|IRQF_DISABLED)) {
  pr_warning(
    "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",
   irq, devname);
}
#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)
  return -EINVAL;
if (desc->status & IRQ_NOREQUEST)
  return -EINVAL;
if (!handler)
  return -EINVAL;
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;
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;
}
EXPORT_SYMBOL(request_threaded_irq);

我很奇怪的是,./include/linux/interrupt.h 的头文件中并没有包含 ./kernel/irq/manage.c ,这是怎么回事,那么这个 request_threaded_irq 是那个 request_irq
调用的吗 ?

除此两处之外,整个内核再也找不到 request_irq 或 request_threaded_irq 的定义了。

不是说各自的平台有各自的 request_irq 吗,为什么我找不到?

如果没有定义 CONFIG_GENERIC_HARDIRQS,那么执行的流程如何去找 request_irq 呢?

要命的问题是:./include/linux/interrupt.h 并没有对应的 ./include/linux/interrupt.c 而其中的 函数原型却在 ./kernel/irq/manage.c 中,这是个什么原理?

内核里是用相同的名字,一个头文件对应一个.c文件吗?

急盼解答!!!版主,高手,务必伸出援手啊!!!

论坛徽章:
0
2 [报告]
发表于 2009-10-17 22:09 |只看该作者
手上没源代码,猜测是汇编实现的,在S文件找找看。

论坛徽章:
0
3 [报告]
发表于 2009-10-17 22:39 |只看该作者
.s文件里没有,找过了!

论坛徽章:
0
4 [报告]
发表于 2009-10-17 22:41 |只看该作者
关键问题是:./include/linux/interrupt.h 并没有对应的 ./include/linux/interrupt.c 而其中的 函数原型却在 ./kernel/irq/manage.c 中,这是个什么原理?

论坛徽章:
0
5 [报告]
发表于 2009-10-17 23:58 |只看该作者
request_irq 不是依赖硬件的。只有一个

论坛徽章:
0
6 [报告]
发表于 2009-10-19 09:56 |只看该作者
原帖由 风之湍 于 2009-10-17 22:41 发表
关键问题是:./include/linux/interrupt.h 并没有对应的 ./include/linux/interrupt.c 而其中的 函数原型却在 ./kernel/irq/manage.c 中,这是个什么原理?


没有谁规定,有一个interrupt.h,必须要有一个interrupt.c来实现interrupt.h里declare的函数。
头文件只是用来声明用的,实现可以在任何一个.c文件中,只要最后在链接的时候,你把那个包含实现的.o文件包括进来进行了,当然你要保证在链接的时候,所有的.o文件中只有一份实现。

如果define了CONFIG_GENERIC_HARDIRQS,那么request_irq就会调用request_threaded_irq(),这个函数的实现在kernel/irq/manage.c中,并且在compile kernel的时候kernel/irq下的文件会被编译进kernel(see kernel/Makefile里有这样一句obj-$(CONFIG_GENERIC_HARDIRQS) += irq/)

如果没有define CONFIG_GENERIC_HARDIRQS,那么这个architecture (sparc, m68k...注释里有)需要提供request_irq的实现。
kernel/irq下的文件并不会被编译进kernel,但是因为kernel其他的地方会调用request_threaded_irq这个函数,所以就在interrupt.h里定义了这个函数。


所以只要保证整个kernel里只有一份request_threaded_irq和request_irq的实现就行了。

论坛徽章:
0
7 [报告]
发表于 2009-10-19 10:21 |只看该作者
感谢楼上的精彩解答!我获益很多!

论坛徽章:
0
8 [报告]
发表于 2014-04-11 16:28 |只看该作者
果断mark一下。回复 6# eexplorer


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP