起先我以为dev_id的值是提供给kernel进行判断共享中断线上的哪一个设备产生了中断(即哪个irqaction产生中断),然后执行相应的中断处理函数(irqaction->handler)。实际上不是的,我们来看看《Linux Kernel Development – Second Edition》第六章中Shared Handlers这一节,其中有段总结性的文字如下:
When the kernel receives an interrupt, it invokes sequentially each registered handler on the line. Therefore, it is important that the handler be capable of distinguishing whether it generated a given interrupt. The handler must quickly exit if its associated device did not generate the interrupt. This requires the hardware device to have a status register (or similar mechanism) that the handler can check. Most hardware does indeed have such a feature.
我总结了一下,实际上dev_id作用主要有两点: 一.在中断处理程序释放时使用到dev_id When your driver unloads, you need to unregister your interrupt handler and potentially disable the interrupt line. To do this, call void free_irq(unsigned int irq, void *dev_id) …… The fifth parameter, dev_id, is used primarily for shared interrupt lines. When an interrupt handler is freed (discussed later), dev_id provides a unique cookie to allow the removal of only the desired interrupt handler from the interrupt line. Without this parameter, it would be impossible for the kernel to know which handler to remove on a given interrupt line.
下面我们来看一下free_irq的代码: void free_irq(unsigned int irq, void *dev_id) { struct irq_desc *desc; struct irqaction **p; unsigned long flags; WARN_ON(in_interrupt()); if (irq >= NR_IRQS) return; desc = irq_desc + irq; /* 获取该中断号对应的irq_desc */ spin_lock_irqsave(&desc->lock, flags); p = &desc->action; /* 找到该irq的irqaction链表 */ for (;;) { struct irqaction *action = *p; if (action) { struct irqaction **pp = p; p = &action->next; if (action->dev_id != dev_id) continue; /* 这两句进行循环判断,直到找到相应dev_id设备的irqaction */ /* Found it - now remove it from the list of entries */ *pp = action->next; /* 指向下一个irqaction */ /* Currently used only by UML, might disappear one day.*/ #ifdef CONFIG_IRQ_RELEASE_METHOD if (desc->chip->release) desc->chip->release(irq, dev_id); #endif if (!desc->action) { desc->status |= IRQ_DISABLED; if (desc->chip->shutdown) desc->chip->shutdown(irq); else desc->chip->disable(irq); } recalculate_desc_flags(desc); spin_unlock_irqrestore(&desc->lock, flags); unregister_handler_proc(irq, action); /* Make sure it's not being used on another CPU */ synchronize_irq(irq); kfree(action); /* 删除该设备(dev_id)的irqaction */ return; } printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq); spin_unlock_irqrestore(&desc->lock, flags); return; } }