一:内核中断

  linux内核中的看门狗中断跟之前的裸板的中断差不多,在编写驱动之前,需要线把内核自带的watch dog模块裁剪掉,要不然会出现错误;在Device Drivers /Watchdog Timer Support /S3C2410 Watchdo

linux内核中断之看门狗_linux

在内核中,我们处理一个中断,必须先注册一个中断号,注册中断的函数是:


132 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
133 const char *name, void *dev)
134 {
135 return request_threaded_irq(irq, handler, NULL, flags, name, dev);
136 }


  irq是要申请的硬件中断号

  handler 是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev参数将被传递给它。

  flags 是中断处理的属性,若 设置了IRQF_DISABLED ,则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程 序不屏蔽;若设置了IRQF_SHARED ,则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM,表示对系统熵有贡献,对系统获取随机数有好处。

  name设置中断名称通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。

  dev在中断共享时会用到,一般设置为这个设备的设备结构体或者为NULL

  request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。

  在开发板上通过cat /proc/interrupts查看中断有没有注册成功:

  下面代码实现是按键(key1)控制dog,dog控制灯,按键第一次按下灯闪,再次按下灯灭



  1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/io.h>
4 #include <linux/irq.h>
5 #include <linux/interrupt.h>
6 #include <linux/clk.h>
7 #include <linux/gpio.h>
8
9 MODULE_LICENSE("GPL");
10 MODULE_AUTHOR("bunfly");
11
12 irqreturn_t do_irq(int irq, void *data);
13 void led_on();
14 void led_off();
15 void wt_on();
16 void wt_off();
17
18 unsigned long gpio_virt;
19 unsigned long *gpm4con, *gpm4dat;
20 unsigned long wt_virt;
21 unsigned long *wtcon, *wtdat, *wtcnt, *wtclrint;
22 struct clk *wtclk;
23 int et_irq = 0;
24
25 int bunfly_init()
26 {
27 int ret = 0;
28 et_irq = gpio_to_irq(EXYNOS4_GPX3(2));//EXINT()获取外部中断号
29 ret = request_irq(et_irq, do_irq, IRQ_TYPE_EDGE_FALLING, "key 1", 2222);//注册按键中断
30 if(ret < 0) { //中断号 //处理函数
31 printk("request_irq error\n");
32 return 1;
33 }
34
35 wtclk = clk_get(NULL, "watchdog");//设置时钟频率
36 clk_enable(wtclk);
37 ret = request_irq(IRQ_WDT, do_irq, IRQF_SHARED, "wangcai", 2222);//注册watchdog中断
38 if(ret < 0) {
39 printk("request_irq\n");
40 return 1;
41 }
42 gpio_virt = ioremap(0x11000000, SZ_4K);//led的物理地址到虚拟地址
43 gpm4con = gpio_virt + 0x02e0;
44 gpm4dat = gpio_virt + 0x02e4;
45
46 wt_virt = ioremap(0x10060000, SZ_4K);//dog的物理地址到虚拟地址
47 wtcon = wt_virt + 0x00;
48 wtdat = wt_virt + 0x04;
49 wtcnt = wt_virt + 0x08;
50 wtclrint = wt_virt + 0x0c;
51
52
53 return 0;
54 }
55
56 void bunfly_exit()
57 {
58 printk("this is bunfly_exit\n");
59 }
60
61 module_init(bunfly_init);
62 module_exit(bunfly_exit);
63
64 irqreturn_t do_irq(int irq, void *data)
65 {
66 if(irq == et_irq) {//判断是否为按键中断
67 static int flags = 1;
68 printk("key 1 down\n");
69 if(flags) {
70 wt_on();
71 flags = 0;
72 }
73 else {
74 wt_off();
75 led_off();
76 flags = 1;
77 }
78 }
79 if(irq == IRQ_WDT) {//判断是否为狗中断
80 *wtclrint = 0;//清中断
81 static int flags = 1;
82 if(flags) {
83 led_on();
84 flags = 0;
85 }
86 else {
87 led_off();
88 flags = 1;
89 }
90 }
91
92 return IRQ_HANDLED;//处理完成
93 }
94
95 void led_on()
96 {
97 *gpm4con &= ~0xffff;
98 *gpm4con |= 0x1111;
99 *gpm4dat = 0x0;
100 }
101
102 void led_off()
103 {
104 *gpm4con &= ~0xffff;
105 *gpm4con |= 0x1111;
106 *gpm4dat = 0xf;
107
108 }
109
110 void wt_on()
111 {
112 *wtdat = 0x8000;
113 *wtcnt = 0x8000;
114 *wtcon = (1 << 2) | (0 << 3) | (1 << 5) | (168 << 8);
115 }
116
117 void wt_off()
118 {
119 *wtcon = 0;
120 }