一:内核中断
linux内核中的看门狗中断跟之前的裸板的中断差不多,在编写驱动之前,需要线把内核自带的watch dog模块裁剪掉,要不然会出现错误;在Device Drivers /Watchdog Timer Support /S3C2410 Watchdo
在内核中,我们处理一个中断,必须先注册一个中断号,注册中断的函数是:
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev)
{
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}
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控制灯,按键第一次按下灯闪,再次按下灯灭
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/gpio.h> MODULE_LICENSE("GPL");
MODULE_AUTHOR("bunfly"); irqreturn_t do_irq(int irq, void *data);
void led_on();
void led_off();
void wt_on();
void wt_off(); unsigned long gpio_virt;
unsigned long *gpm4con, *gpm4dat;
unsigned long wt_virt;
unsigned long *wtcon, *wtdat, *wtcnt, *wtclrint;
struct clk *wtclk;
int et_irq = ; int bunfly_init()
{
int ret = ;
et_irq = gpio_to_irq(EXYNOS4_GPX3());//EXINT()获取外部中断号
ret = request_irq(et_irq, do_irq, IRQ_TYPE_EDGE_FALLING, "key 1", );//注册按键中断
if(ret < ) { //中断号 //处理函数
printk("request_irq error\n");
return ;
} wtclk = clk_get(NULL, "watchdog");//设置时钟频率
clk_enable(wtclk);
ret = request_irq(IRQ_WDT, do_irq, IRQF_SHARED, "wangcai", );//注册watchdog中断
if(ret < ) {
printk("request_irq\n");
return ;
}
gpio_virt = ioremap(0x11000000, SZ_4K);//led的物理地址到虚拟地址
gpm4con = gpio_virt + 0x02e0;
gpm4dat = gpio_virt + 0x02e4; wt_virt = ioremap(0x10060000, SZ_4K);//dog的物理地址到虚拟地址
wtcon = wt_virt + 0x00;
wtdat = wt_virt + 0x04;
wtcnt = wt_virt + 0x08;
wtclrint = wt_virt + 0x0c; return ;
} void bunfly_exit()
{
printk("this is bunfly_exit\n");
} module_init(bunfly_init);
module_exit(bunfly_exit); irqreturn_t do_irq(int irq, void *data)
{
if(irq == et_irq) {//判断是否为按键中断
static int flags = ;
printk("key 1 down\n");
if(flags) {
wt_on();
flags = ;
}
else {
wt_off();
led_off();
flags = ;
}
}
if(irq == IRQ_WDT) {//判断是否为狗中断
*wtclrint = ;//清中断
static int flags = ;
if(flags) {
led_on();
flags = ;
}
else {
led_off();
flags = ;
}
} return IRQ_HANDLED;//处理完成
} void led_on()
{
*gpm4con &= ~0xffff;
*gpm4con |= 0x1111;
*gpm4dat = 0x0;
} void led_off()
{
*gpm4con &= ~0xffff;
*gpm4con |= 0x1111;
*gpm4dat = 0xf; } void wt_on()
{
*wtdat = 0x8000;
*wtcnt = 0x8000;
*wtcon = ( << ) | ( << ) | ( << ) | ( << );
} void wt_off()
{
*wtcon = ;
}