Linux 中断完整例程

Posted Li-Yongjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 中断完整例程相关的知识,希望对你有一定的参考价值。

interrupt.c

/* Linux 中断例程 */
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>

static int irq = 19; /* 这个值不是随便填的,得从设备树中查找 */
char *interface = "aaa";

static irqreturn_t myirq_handler(int irq, void *dev)

	printk("%d IRQ is working\\n", irq);
	return IRQ_NONE;


static int __init myirq_init(void)

	printk("the module is working!\\n");
	printk("the irq is ready for working!\\n");
	if (request_irq(irq, myirq_handler, IRQF_SHARED, interface, &irq)) 
		printk(KERN_ERR "%s interrrupt can't register %d IRQ \\n", interface, irq);
		return -EIO;
	
	printk("%s request %d IRQ\\n", interface, irq);
	return 0;


static void __exit myirq_exit(void)

	printk("the module is leaving!\\n");
	printk("the irq is bye bye!\\n");
	free_irq(irq, &irq);
	printk("%s interrupt free %d IRQ\\n", interface, irq);


module_init(myirq_init);
module_exit(myirq_exit);

MODULE_LICENSE("GPL");

Makefile

obj-m:=interrupt.o  
  
CURRENT_PATH:=$(shell pwd)  
VERSION_NUM:=$(shell uname -r)  
LINUX_PATH:=/usr/src/linux-headers-$(VERSION_NUM)  

all :  
	make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules  
clean:  
	make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean 

编译

$ make
make -C /usr/src/linux-headers-5.8.0-44-generic     M=/home/liyongjun/project/c/study/kernel/interrupt   modules  
make[1]: 进入目录“/usr/src/linux-headers-5.8.0-44-generic”
  CC [M]  /home/liyongjun/project/c/study/kernel/interrupt/interrupt.o
  MODPOST /home/liyongjun/project/c/study/kernel/interrupt/Module.symvers
  LD [M]  /home/liyongjun/project/c/study/kernel/interrupt/interrupt.ko
make[1]: 离开目录“/usr/src/linux-headers-5.8.0-44-generic”

在安装前,可以通过 tail -f /var/log/kern.log 持续打印内核 log

安装

$ sudo insmod interrupt.ko

内核 log

Mar  3 17:42:58 Box20 kernel: [  958.935881] the module is working!
Mar  3 17:42:58 Box20 kernel: [  958.935882] the irq is ready for working!
Mar  3 17:42:58 Box20 kernel: [  958.935886] aaa request 19 IRQ
Mar  3 17:42:59 Box20 kernel: [  959.833022] 19 IRQ is working
Mar  3 17:42:59 Box20 kernel: [  959.837598] 19 IRQ is working
Mar  3 17:42:59 Box20 kernel: [  959.837863] 19 IRQ is working
Mar  3 17:43:00 Box20 kernel: [  960.587580] 19 IRQ is working
Mar  3 17:43:00 Box20 kernel: [  960.967419] 19 IRQ is working
Mar  3 17:43:00 Box20 kernel: [  961.338492] 19 IRQ is working

卸载

$ sudo rmmod interrupt.ko

内核 log

Mar  3 17:43:03 Box20 kernel: [  964.455501] the module is leaving!
Mar  3 17:43:03 Box20 kernel: [  964.455502] the irq is bye bye!
Mar  3 17:43:03 Box20 kernel: [  964.455526] aaa interrupt free 19 IRQ

重点:如何确定中断号

方法一:从设备树中获取

cat linux-source-4.15.0/arch/arc/boot/dts/axs10x_mb.dtsi
...
uart@0x20000 
            compatible = "snps,dw-apb-uart";                                                                                                                      
            reg = <0x20000 0x100>;
            clock-frequency = <33333333>;
            interrupts = <17>;
            baud = <115200>;
            reg-shift = <2>;
            reg-io-width = <4>;
        ;

        uart@0x21000 
            compatible = "snps,dw-apb-uart";
            reg = <0x21000 0x100>;
            clock-frequency = <33333333>;
            interrupts = <18>;
            baud = <115200>;
            reg-shift = <2>;
            reg-io-width = <4>;
        ;

        /* UART muxed with USB data port (ttyS3) */
        uart@0x22000 
            compatible = "snps,dw-apb-uart";
            reg = <0x22000 0x100>;
            clock-frequency = <33333333>;
            interrupts = <19>;
            baud = <115200>;
            reg-shift = <2>;
            reg-io-width = <4>;
        ;

        i2c@0x1d000 
            compatible = "snps,designware-i2c";
            reg = <0x1d000 0x100>;
            clock-frequency = <400000>;
            clocks = <&i2cclk>;
            interrupts = <14>;
        ;

        i2s: i2s@1e000 
            compatible = "snps,designware-i2s";
            reg = <0x1e000 0x100>;
            clocks = <&i2sclk 0>;
            clock-names = "i2sclk";
            interrupts = <15>;
            #sound-dai-cells = <0>;
        ;
...

interrupts = <19> 这个值就是中断号,一般要开发哪款外设,就使用哪个设备对应的中断号。由于我这里没有特定的外设,这里只是作为一个演示,故采用 ttyS3 设备的中断号 19 作为例程演示。

方法二:cat /proc/interrupts

$ cat /proc/interrupts 
           CPU0       CPU1       CPU2       CPU3       
  0:         25          0          0          0   IO-APIC   2-edge      timer
  1:          0          0        948          0   IO-APIC   1-edge      i8042
  8:          0          0          0          0   IO-APIC   8-edge      rtc0
  9:          0          0          0          0   IO-APIC   9-fasteoi   acpi
 12:          0        602          0          0   IO-APIC  12-edge      i8042
 14:          0          0          0          0   IO-APIC  14-edge      ata_piix
 15:          0          0          0        505   IO-APIC  15-edge      ata_piix
 18:          0       2807        308          0   IO-APIC  18-fasteoi   vmwgfx
 19:          0          0          0       2165   IO-APIC  19-fasteoi   enp0s3, aaa
 20:          0       4153          0          0   IO-APIC  20-fasteoi   vboxguest
 21:      22444          0      18680          0   IO-APIC  21-fasteoi   ahci[0000:00:0d.0], snd_intel8x0
 22:         27          0          0          0   IO-APIC  22-fasteoi   ohci_hcd:usb1
NMI:          0          0          0          0   Non-maskable interrupts
LOC:      77025      75978     178758     103782   Local timer interrupts
SPU:          0          0          0          0   Spurious interrupts
PMI:          0          0          0          0   Performance monitoring interrupts
IWI:          0          0          0        186   IRQ work interrupts
RTR:          0          0          0          0   APIC ICR read retries
RES:      58469      59770      59610      56375   Rescheduling interrupts
CAL:      12253      12480       9561      13636   Function call interrupts
TLB:      11531      11931      13837      11497   TLB shootdowns
TRM:          0          0          0          0   Thermal event interrupts
THR:          0          0          0          0   Threshold APIC interrupts
DFR:          0          0          0          0   Deferred Error APIC interrupts
MCE:          0          0          0          0   Machine check exceptions
MCP:          2          2          2          2   Machine check polls
ERR:          0
MIS:         10
PIN:          0          0          0          0   Posted-interrupt notification event
NPI:          0          0          0          0   Nested posted-interrupt event
PIW:          0          0          0          0   Posted-interrupt wakeup event

最左侧就是中断号,找到你外设对应的中断号就可以使用了。
我使用 aaa 名称在 19 号中断上注册的服务也能从上面看到。

以上是关于Linux 中断完整例程的主要内容,如果未能解决你的问题,请参考以下文章

STM32F103基于标准库开发串口中断接收数据环形队列例程

linux UART驱动_应用程序例程

《Linux内核设计与实现》学习笔记——中断中断处理程序

Linux(内核剖析):22---中断之中断控制接口(禁止/激活/屏蔽中断)

Linux驱动实践:一起来梳理中断的前世今生(附代码)

Linux驱动实践:一起来梳理中断的前世今生(附代码)