内核函数asm_do_IRQ()中的irq与我在模块中请求的不同

我用cortex-A9开发板做了一些实验。 我用gpio_to_irq()来获得一个irq num,并且我请求了irq,并用它写了一个小的驱动程序,在syslog中是196。 我在asm_do_IRQ中添加了一些printks。 当我触发gpio中断时,驱动程序工作正常,但是asm_do_IRQ中的irq num是62,我不明白。 为什么irq号码与我要求的不一样? 司机如下:

#include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/gpio.h> #define GPIO_N 36 //gpio number int flag = 0; static irqreturn_t handler(int irq,void *dev_id) { printk("hello world hahahahahhahahah \n\n"); return 0; } static int __init gpio_test_init(void) { if(gpio_request_one(GPIO_N,GPIOF_DIR_IN,"some test")<0) { printk(KERN_ERR "Oops! BAD! BAD! BAD!\n\n"); return 0; } int irq,irq2; irq = OMAP_GPIO_IRQ(TEST_GPIO); printk("irq : %d \n",irq,irq2); // .................. // irq : 196 in dmesg //...................... set_irq_type(irq,IRQ_TYPE_EDGE_FALLING); enable_irq(gpio_to_irq(GPIO_N)); int err; // request the irq ... if((err = request_irq(irq,&handler,0,NULL,NULL))<0) { printk("err : %d\n",err); return 0; } printk("gpio test init success!\n"); flag = 1; return 0; } static void __exit gpio_test_exit(void) { int irq = gpio_to_irq(TEST_GPIO); if(flag == 1)free_irq(irq,NULL); gpio_free(TEST_GPIO); printk("gpio test exit byebye!\n"); } module_init(gpio_test_init); module_exit(gpio_test_exit); MODULE_LICENSE("GPL"); 

arch / arm / kernel / irq.c中的asm_do_IRQ

  asmlinkage void __exception_irq_entry asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); printk("the irq : %d\n",irq); //............... // I get 62 here //............... irq_enter(); /* * Some hardware gives randomly wrong interrupts. Rather * than crashing, do something sensible. */ if (unlikely(irq >= nr_irqs)) { if (printk_ratelimit()) printk(KERN_WARNING "Bad IRQ%u\n", irq); ack_bad_irq(irq); } else { generic_handle_irq(irq); } /* AT91 specific workaround */ irq_finish(irq); irq_exit(); set_irq_regs(old_regs); } 

Solutions Collecting From Web of "内核函数asm_do_IRQ()中的irq与我在模块中请求的不同"

这一观察可能是由于物理和虚拟IRQ号码之间的映射。 在您的驱动程序中看到的数字是虚拟IRQ号码,只有在使用通用Linux中断处理子系统时才有效。 asm_do_IRQ的中断号将是内核中断结构提供的物理中断号。

我相信OMAP处理器支持GPIO引脚上的中断。 通常实现的方式是为一组GPIO输入(比如32位)分配一条IRQ线。 当任何GPIO发生中断时,IRQ线路将被激活。 这可能是您的处理器上的数字62。 如果您查看处理器的手册,您应该看到IRQ 62对应于GPIO bank上的中断。

现在,linux的GPIO子系统将允许你为任何一个GPIO分配一个中断处理程序,为你提供从linux irq号码到物理irq号码的映射。 在你的情况下,linux irq数是196. GPIO子系统被配置为处理所有的GPIO中断(比如中断62),读GPIO寄存器以确定bank中的哪个GPIO位可以产生中断,然后调出你用request_irq分配的中断处理程序。

以下是GPIO中断的基本控制流程:

  1. GPIO bank中的中断发生变化。 IRQ 62被提出。
  2. asm_do_IRQ在IRQ 62上运行asm_do_IRQ子系统已经被注册以通过平台初始化代码来处理IRQ 62。
  3. GPIO子系统读取GPIO寄存器并确定GPIO位X已导致中断。 它计算从位X到linux虚拟IRQ号码的映射,在本例中为196。
  4. GPIO中断处理程序然后调用196的generic_handle_irq函数,调用你的中断处理程序。

虚拟IRQ号和物理IRQ号之间通常由平台定义静态映射 。 要看这个映射,

  • 在Linux-3.4之前的内核上启用CONFIG_VIRQ_DEBUG ,或者
  • 在新的内核上启用CONFIG_IRQ_DOMAIN_DEBUG

然后看看irq_domain_mapping debugfs文件。 例如在PowerPC上:

 # mount -t debugfs none /sys/kernel/debug # cat /sys/kernel/debug/irq_domain_mapping irq hwirq chip name chip data domain name 16 0x00009 IPIC 0xcf801c80 /soc8347@e0000000/pic@700 18 0x00012 IPIC 0xcf801c80 /soc8347@e0000000/pic@700 19 0x0000e IPIC 0xcf801c80 /soc8347@e0000000/pic@700 20 0x0000f IPIC 0xcf801c80 /soc8347@e0000000/pic@700 21 0x00010 IPIC 0xcf801c80 /soc8347@e0000000/pic@700 77 0x0004d IPIC 0xcf801c80 /soc8347@e0000000/pic@700