Ok24403看门狗驱动代码详细分析Word下载.docx
《Ok24403看门狗驱动代码详细分析Word下载.docx》由会员分享,可在线阅读,更多相关《Ok24403看门狗驱动代码详细分析Word下载.docx(18页珍藏版)》请在冰豆网上搜索。
![Ok24403看门狗驱动代码详细分析Word下载.docx](https://file1.bdocx.com/fileroot1/2023-1/24/480e68d9-c238-4fd2-981e-8bb3ed2018b1/480e68d9-c238-4fd2-981e-8bb3ed2018b11.gif)
linux/miscdevice.h>
linux/watchdog.h>
linux/fs.h>
linux/init.h>
linux/platform_device.h>
linux/interrupt.h>
linux/clk.h>
linux/uaccess.h>
linux/io.h>
mach/map.h>
#undefS3C_VA_WATCHDOG
#defineS3C_VA_WATCHDOG(0)
asm/plat-s3c/regs-watchdog.h>
#definePFX"
s3c2410-wdt:
"
#defineCONFIG_S3C2410_WATCHDOG_ATBOOT(0)
#defineCONFIG_S3C2410_WATCHDOG_DEFAULT_TIME(15)
staticintnowayout=WATCHDOG_NOWAYOUT;
staticinttmr_margin=CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
staticinttmr_atboot=CONFIG_S3C2410_WATCHDOG_ATBOOT;
staticintsoft_noboot;
staticintdebug;
module_param(tmr_margin,int,0);
module_param(tmr_atboot,int,0);
module_param(nowayout,int,0);
module_param(soft_noboot,int,0);
module_param(debug,int,0);
MODULE_PARM_DESC(tmr_margin,"
Watchdogtmr_margininseconds.default="
__MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME)"
)"
);
MODULE_PARM_DESC(tmr_atboot,
"
Watchdogisstartedatboottimeifsetto1,default="
__MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
MODULE_PARM_DESC(nowayout,"
Watchdogcannotbestoppedoncestarted(default="
__MODULE_STRING(WATCHDOG_NOWAYOUT)"
MODULE_PARM_DESC(soft_noboot,"
Watchdogaction,setto1toignorereboots,0toreboot(defaultdependsonONLY_TESTING)"
MODULE_PARM_DESC(debug,"
Watchdogdebug,setto>
1fordebug,(default0)"
typedefenumclose_state{
CLOSE_STATE_NOT,
CLOSE_STATE_ALLOW=0x4021
}close_state_t;
staticunsignedlongopen_lock;
staticstructdevice*wdt_dev;
/*platformdeviceattachedto*/
staticstructresource*wdt_mem;
staticstructresource*wdt_irq;
staticstructclk*wdt_clock;
staticvoid__iomem*wdt_base;
staticunsignedintwdt_count;
staticclose_state_tallow_close;
staticDEFINE_SPINLOCK(wdt_lock);
/*watchdogcontrolroutines*/
#defineDBG(msg...)do{\
if(debug)\
printk(KERN_INFOmsg);
\
}while(0)
/*functions*/
staticvoids3c2410wdt_keepalive(void)//喂狗,即将计数值赋给WTCNT寄存器
{
spin_lock(&
wdt_lock);
writel(wdt_count,wdt_base+S3C2410_WTCNT);
spin_unlock(&
}
staticvoid__s3c2410wdt_stop(void)
unsignedlongwtcon;
wtcon=readl(wdt_base+S3C2410_WTCON);
wtcon&
=~(S3C2410_WTCON_ENABLE|S3C2410_WTCON_RSTEN);
writel(wtcon,wdt_base+S3C2410_WTCON);
//将WTCON寄存器的位[5]和位[0]清零,不输出复位信号,停止看门狗
staticvoids3c2410wdt_stop(void)//关看门狗
__s3c2410wdt_stop();
staticvoids3c2410wdt_start(void)
//关看门狗
wtcon|=S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV128;
/*#defineS3C2410_WTCON_ENABLE(1<
<
5)
#defineS3C2410_WTCON_DIV128(3<
3)
开启看门狗,设置分频系数为128(这里并没有将其写入控制寄存器,只是设置值而已)
if(soft_noboot){
wtcon|=S3C2410_WTCON_INTEN;
//#defineS3C2410_WTCON_INTEN(1<
2)使能看门狗中断
wtcon&
=~S3C2410_WTCON_RSTEN;
//#defineS3C2410_WTCON_RSTEN(0x01),不输出复位信号
}else{
=~S3C2410_WTCON_INTEN;
//禁止看门狗中断
wtcon|=S3C2410_WTCON_RSTEN;
//允许输出复位信号
}
DBG("
%s:
wdt_count=0x%08x,wtcon=%08lx\n"
__func__,wdt_count,wtcon);
writel(wdt_count,wdt_base+S3C2410_WTDAT);
//写入计数值
//写WTCON寄存器,前面的设置会生效
staticints3c2410wdt_set_heartbeat(inttimeout)
unsignedintfreq=clk_get_rate(wdt_clock);
//获得时钟,这里的时钟应该是系统初始化时设置好了的。
就是pclk的值
unsignedintcount;
unsignedintdivisor=1;
if(timeout<
1)
return-EINVAL;
freq/=128;
//这个地方有点不明白了,在前面没有设置WTCON寄存器的[4:
3]位,怎么就直接采用了128分频呢?
难道也是系统初始化时的设置?
count=timeout*freq;
//将看门时间timeout(秒)乘以freq,根据count的值确定是否需要设置看门狗的预分配项。
count=%d,timeout=%d,freq=%d\n"
__func__,count,timeout,freq);
/*ifthecountisbiggerthanthewatchdogregister,
thenworkoutwhatweneedtodo(andif)wecan
actuallymakethisvalue
*/
if(count>
=0x10000){
for(divisor=1;
divisor<
=0x100;
divisor++){
if((count/divisor)<
0x10000)
break;
}
//因为WTDAT寄存器为16位,因此当计数值count>
=0x10000时必须采用与分频项,经过这个循环后,divisor的值即为与分频因子。
if((count/divisor)>
dev_err(wdt_dev,"
timeout%dtoobig\n"
timeout);
return-EINVAL;
//如果count/divisor)>
=0x10000,则说明看门狗时间设得太大了,将会退出。
tmr_margin=timeout;
timeout=%d,divisor=%d,count=%d(%08x)\n"
__func__,timeout,divisor,count,count/divisor);
count/=divisor;
//得到采用预分频后看门狗的计数脉冲数
wdt_count=count;
/*updatethepre-scaler*/
=~S3C2410_WTCON_PRESCALE_MASK;
wtcon|=S3C2410_WTCON_PRESCALE(divisor-1);
//计算看门狗预分配因子
writel(count,wdt_base+S3C2410_WTDAT);
//设置看门狗计数脉冲数
//设置看门狗预分频因子
return0;
/*
*/dev/watchdoghandling
staticints3c2410wdt_open(structinode*inode,structfile*file)
if(test_and_set_bit(0,&
open_lock))//上锁,因此同时只有一个进程打开看门狗设备文件,该函数的功能为:
设置&
open_lock的位0为1,返回原来位0的值。
return-EBUSY;
if(nowayout)
__module_get(THIS_MODULE);
allow_close=CLOSE_STATE_NOT;
//这个状态用来干什么的呢?
/*startthetimer*/
s3c2410wdt_start();
//启动看门狗
returnnonseekable_open(inode,file);
staticints3c2410wdt_release(structinode*inode,structfile*file)
/*
*Shutoffthetimer.
*Lockitinifit'
samoduleandwesetnowayout
if(allow_close==CLOSE_STATE_ALLOW)
s3c2410wdt_stop();
else{
dev_err(wdt_dev,"
Unexpectedclose,notstoppingwatchdog\n"
s3c2410wdt_keepalive();
}
clear_bit(0,&
open_lock);
//释放锁
staticssize_ts3c2410wdt_write(structfile*file,constchar__user*data,
size_tlen,loff_t*ppos)
*Refreshthetimer.
if(len){
if(!
nowayout){
size_ti;
/*Incaseitwassetlongago*/
allow_close=CLOSE_STATE_NOT;
for(i=0;
i!
=len;
i++){
charc;
if(get_user(c,data+i))//用户空间到内核空间
return-EFAULT;
if(c=='
V'
)//如果写入了V,允许关闭
allow_close=CLOSE_STATE_ALLOW;
}
returnlen;
#defineOPTIONSWDIOF_SETTIMEOUT|WDIOF_KEEPALIVEPING|WDIOF_MAGICCLOSE
staticconststructwatchdog_infos3c2410_wdt_ident={
.options=OPTIONS,
.firmware_version=0,
.identity="
S3C2410Watchdog"
};
staticlongs3c2410wdt_ioctl(structfile*file,unsignedintcmd,
unsignedlongarg)
void__user*argp=(void__user*)arg;
int__user*p=argp;
intnew_margin;
switch(cmd){
caseWDIOC_GETSUPPORT:
returncopy_to_user(argp,&
s3c2410_wdt_ident,
sizeof(s3c2410_wdt_ident))?
-EFAULT:
0;
caseWDIOC_GETSTATUS:
caseWDIOC_GETBOOTSTATUS:
returnput_user(0,p);
caseWDIOC_KEEPALIVE:
return0;
caseWDIOC_SETTIMEOUT:
if(get_user(new_margin,p))
return-EFAULT;
if(s3c2410wdt_set_heartbeat(new_margin))
returnput_user(tmr_margin,p);
caseWDIOC_GETTIMEOUT:
default:
return-ENOTTY;
/*kernelinterface*/
staticconststructfile_operationss3c2410wdt_fops={
.owner=THIS_MODULE,
.llseek=no_llseek,
.write=s3c2410wdt_write,
.unlocked_ioctl=s3c2410wdt_ioctl,
.open=s3c2410wdt_open,
.release=s3c2410wdt_release,
staticstructmiscdevices3c2410wdt_miscdev={
.minor=WATCHDOG_MINOR,
.name="
watchdog"
.fops=&
s3c2410wdt_fops,
/*interrupthandlercode*/
staticirqreturn_ts3c2410wdt_irq(intirqno,void*param)
dev_info(wdt_dev,"
watchdogtimerexpired(irq)\n"
s3c2410wdt_keepalive();
//喂狗
returnIRQ_HANDLED;
/*deviceinterface*/
staticints3c2410wdt_probe(structplatform_device*pdev)
/*入口参数
structplatform_devices3c_device_wdt={
s3c2410-wdt"
.id=-1,
.num_resources=ARRAY_SIZE(s3c_wdt_resource),
.resource=s3c_wdt_resource,
#defineARRAY_SIZE(x)(sizeof(x)/sizeof((x)[0]))
说明:
num_resources:
设备占用的资源数量
staticstructresources3c_wdt_resource[]={
[0]={
.start=S3C24XX_PA_WATCHDOG,
S3C24XX_PA_WATCHDOG等于(0x53000000)
WTCON寄存器的物理地址即为0x53000000
.end=S3C24XX_PA_WATCHDOG+S3C24XX_SZ_WATCHDOG-1,
S3C24XX_SZ_WATCHDOG等于0x00100000
.flags=IORESOURCE_MEM,
该标志用来资源的类型
},
[1]={
.start=IRQ_WDT,
.end=IRQ_WDT,
#defineIRQ_WDT17/*0x00020000*/
.flags=IORESOURCE_IRQ,
structresource*res;
structdevice*dev;
unsignedintwtcon;
intstarted=0;
intret;
intsize;