linux内核中断之看门狗

  一:内核中断

  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 }

 

posted @ 2015-09-12 14:59  zhangwju  阅读(1116)  评论(0编辑  收藏  举报