一:内核中断
linux内核中的看门狗中断跟之前的裸板的中断差不多,在编写驱动之前,需要线把内核自带的watch dog模块裁剪掉,要不然会出现错误;在Device Drivers /Watchdog Timer Support /S3C2410 Watchdo
在内核中,我们处理一个中断,必须先注册一个中断号,注册中断的函数是:
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 }