当I2C总线上的四个设备(MAX3107 UART芯片)之一接收到字符时,它会生成中断。所有四个MAX3107芯片的中断线是共享的(开漏下拉),并且该线连接到3180的GPIO引脚,该引脚配置为电平中断。当3017之一生成中断时,将运行一个处理程序,该处理程序执行以下处理(粗略):
spin_lock_irqsave();
disable_irq_nosync(irqno);
irq_enabled = 0;
irq_received = 1;
spin_unlock_irqrestore()
set_queued_work(); // Queue up work for all four devices for every interrupt
// because at this point we don't know which of the four
// 3107's generated the interrupt
return IRQ_HANDLED;
请注意,我发现有些令人不安的是,在离开上述代码之前,并没有重新启用中断。相反,驱动程序是这样编写的,即通过底半部工作队列任务重新启用中断(使用“enable_irq(LPC_IRQ_LINE)”函数调用)。由于工作队列任务不在中断上下文中运行,我认为它们可能会休眠,这对于中断处理程序来说可能是一个坏主意。
上述方法的原理如下: 1. 如果四个MAX3107串口芯片中的一个接收到字符并生成中断(例如),则中断处理程序需要确定实际引起中断的四个I2C设备中的哪一个。但是,显然不能在上半部分中断处理程序的上下文中读取I2C设备,因为I2C读取可能会休眠,这被认为不适合作为中断处理程序的上半部分。 2. 采用的方法来解决上述问题(即哪个设备引起了中断)是禁用中断并退出上半部分处理程序,之后非中断上下文代码可以查询I2C总线上的每个设备以确定哪个接收到了字符(因此生成了中断)。 3. 一旦底半部分处理程序确定了哪个设备引发了中断,底半部分代码将禁用该芯片上的中断,以便它不会重新触发LPC3180的中断线。在这样做后,它读取串行数据并退出。
主要问题似乎是在中断处理程序的顶半部分没有一种方法可以查询四个MAX3107串行通信芯片。如果顶半部分仅在返回之前重新启用中断,这将导致同一芯片再次生成中断,我认为会出现这样的情况:顶半部分禁用了中断,安排底半部分工作队列并禁用中断,但等到底半部分代码到达引起中断的芯片时,又出现了另一个中断,如此往复。
任何有关处理此驱动程序的建议都将不胜感激。我真的不喜欢在驱动程序的顶半部分允许禁用中断,但在退出顶半部分驱动程序之前未重新启用它的想法。这不太安全。
谢谢,
吉姆
附注:在阅读中,我发现线程中断是应对上述需求的一种方式(至少这是我根据网站文章 http://lwn.net/Articles/302043/ 的解释得出的)。我不确定Phytec提供的2.6.10内核是否包含线程中断功能。我打算在接下来的几天里研究一下。