看門狗(watchdog )分硬件看門狗和軟件看門狗。硬件看門狗是利用一個定時器 電路,其定時輸出鏈接到電路的復位端,程序在必定時間範圍內對定時器清零 (俗稱 「喂狗」),若是程序出現故障,不在定時週期內復位看門狗,就使得看門狗定時器溢出產生復位信號 並重啓系統。軟件看門狗原理上同樣,只是將硬件電路上的定時器用處理器的內部定 時器代替。html
1 看門狗的三個寄存器node
1.1 watchdog原理app
S3C2410內部集成了watchdog,提供3 個寄存器對watchdog 進行操做,這3 個寄存器分別爲WTCON (watchdog 控制寄存器)、WTDAT (watchdog 數據寄存器)和WTCNT(watchdog 記數寄存器) S3c2440的看門狗的原理框圖以下:函數
能夠看到,看門狗定時器的頻率由PCLK提供,其預分頻器最大取值爲255+1;另外,經過MUX,能夠進一步下降頻率。定時器採用遞減模式,一旦到0,則能夠觸發看門狗中斷以及RESET復位信號。 看門狗定時器的頻率的計算公式以下:ui
t_watchdog = 1/[PCLK/(Prescaler value + 1)/Division_factor]
1.2 開啓S3C2410 的看門狗 spa
void enable watchdog () { rWTCON = WTCON DIV64 | WTCON RSTEN;//64分頻、開啓復位信號 rWTDAT = 0x8000;//計數目標 rWTCON |= WTCON ENABLE;//開啓看門狗 }
1.3 S3C2410 的看門狗 「喂狗」orm
void feed dog () { rWTCNT=0x8000; }
1.4 看門狗的使用例程 htm
void main () { init system (); ... enable watchdog ();//啓動看門狗 ... while (1) { ... feed dog (); //喂狗 } }
2 watchdog中的數據結blog
有一類設備被稱爲 「平臺設備」,一般 SoC 系統中集成的獨立的外設單元都被看成平臺設備處理內存
2.1 platform_device 結構體
struct platform device { const char * name;//設備名 u32 id; struct device dev; u32 num resources;//設備所使用各種資源數量 struct resource * resource;//資源 };
2.2 S3C2410 中的平臺設備
struct platform device *s3c24xx uart devs[]; struct platform device s3c device usb; //USB 控制器 struct platform device s3c device lcd; //LCD 控制器 struct platform device s3c device wdt; //看門狗 2 struct platform device s3c device i2c; //I C 控制器 struct platform device s3c device iis; //IIS struct platform device s3c device rtc; //實時鐘 ... /*SMDK2410開發板使用的平臺設備*/ static struct platform device *smdk2410 devices[] initdata = { &s3c device usb, //USB &s3c device lcd, //LCD &s3c device wdt, //看門狗 &s3c device i2c, //I C &s3c device iis, //IIS };
2.3 S3C2410 看門狗的platform_device 結構體
struct platform device s3c device wdt = { .name = "s3c2410-wdt", //設備名 .id = - 1, . num resources = ARRAY SIZE (s3c wdt resource), //資源數量 .resource = s3c wdt resource, //看門狗所使用資源 };
2.4 int platform_add_devices()函數
int platform add devices(struct platform device **devs, int num) { int i, ret = 0; for (i = 0; i < num; i++) { ret = platform device register(devs[i]);/*註冊平臺設備*/ if (ret) /*註冊失敗*/ { while (--i >= 0) platform device unregister(devs[i]);/*註銷已經註冊的平臺設備 */ break; } } return ret; }
2.5 platform_driver 結構體
struct platform driver { int (*probe)(struct platform device *);//探測 int (*remove)(struct platform device *);//移除 void (*shutdown)(struct platform device *);//關閉 int (*suspend)(struct platform device *, pm message t state);// 掛起 int (*resume)(struct platform device *);//恢復 struct device driver driver; };
2.6 S3C2410 看門狗的platform_driver 結構體
static struct platform driver s3c2410wdt driver = { .probe = s3c2410wdt probe,//S3C2410看門狗探測 .remove = s3c2410wdt remove,// S3C2410看門狗移除 .shutdown = s3c2410wdt shutdown,//S3C2410看門狗關閉 .suspend = s3c2410wdt suspend,//S3C2410看門狗掛起 .resume = s3c2410wdt resume, //S3C2410看門狗恢復 .driver = { .owner = THIS MODULE, .name = "s3c2410-wdt",//設備名 }, };
2.7 S3C2410 看門狗所用資源
static struct resource s3c wdt resource[] = { [0] = { .start = S3C24XX PA WATCHDOG, //看門狗I/O 內存開始位置 .end = S3C24XX PA WATCHDOG + S3C24XX SZ WATCHDOG - 1, //看門狗I/O 內存結束位置 .flags = IORESOURCE MEM, //I/O 內存資源 } , [1] = { .start = IRQ WDT, //看門狗開始IRQ 號 .end = IRQ WDT, //看門狗結束IRQ 號 .flags = IORESOURCE IRQ, //IRQ 資源 } };
2.8 S3C2410 看門狗驅動的miscdevice 結構體
static struct miscdevice s3c2410wdt miscdev = { .minor = WATCHDOG MINOR,//次設備號 .name = "watchdog", .fops = &s3c2410wdt fops,//文件操做結構體 };
2.9 S3C2410 看門狗驅動的文件操做結構體
static struct file operations s3c2410wdt fops = { .owner = THIS MODULE, .llseek = no llseek, //seek .write = s3c2410wdt write, //寫函數 .ioctl = s3c2410wdt ioctl, //ioctl 函數 .open = s3c2410wdt open, //打開函數 .release = s3c2410wdt release,//釋放函數 };
3 加載和卸載函數
驅動模塊的加載和卸載函數分別 用 platform_driver_register() 和 platform_driver_ unregister()註冊和註銷platform_driver
3.1 S3C2410 看門狗驅動
static int __init watchdog__init (void) { printk (banner); return platform driver register(&s3c2410wdt driver);// 注 冊platform driver } static void exit watchdog exit (void) { platform driver unregister (&s3c2410wdt driver);// 注 銷 platform driver }
4 探測和移除函數
4.1 探測函數
static int s3c2410wdt probe (struct platform device *pdev) { struct resource *res; int started = 0; int ret; int size; DBG ("%s: probe=%p\n", _ _FUNCTION_ _, pdev); /* 得到看門狗的內存區域 */ res = platform get resource (pdev, IORESOURCE MEM, 0); if (res == NULL) { printk(KERN INFO PFX "failed to get memory region resouce\n"); return - ENOENT; } size = (res->end - res->start) + 1; //申請I/O 內存 wdt mem = request mem region (res->start, size, pdev->name); if (wdt mem == NULL) { printk(KERN INFO PFX "failed to get memory region\n"); return - ENOENT; } wdt base = ioremap (res->start, size); //設備內存->虛擬地址 if (wdt base == 0) { printk(KERN INFO PFX "failed to ioremap () region\n"); return - EINVAL; } DBG ("probe: mapped wdt base=%p\n", wdt base); /* 得到看門狗的中斷 */ res = platform get resource (pdev, IORESOURCE IRQ, 0); if (res == NULL) { printk(KERN INFO PFX "failed to get irq resource\n"); return - ENOENT; } //申請中斷 ret = request irq (res->start, s3c2410wdt irq, 0, pdev->name, pdev); if (ret != 0) { printk(KERN INFO PFX "failed to install irq (%d)\n", ret); return ret; } wdt clock = clk get (&pdev->dev, "watchdog"); //得到看門狗時鐘源 if (wdt clock == NULL) { printk(KERN INFO PFX "failed to find watchdog clock source\n"); return - ENOENT; } clk enable (wdt clock); /* 看看是否能設置定時器的超時時間爲指望的值,若是不能,使用缺省值 */ if (s3c2410wdt set heartbeat (tmr margin)) { started = s3c2410wdt set heartbeat ( CONFIG S3C2410 WATCHDOG DEFAULT TIME); if (started == 0) { printk (KERN INFO PFX "tmr margin value out of range, default %d used\n",CONFIG S3C2410 WATCHDOG DEFAULT TIME); } else { printk (KERN INFO PFX "default timer value is out of range, cannot start\n"); } } //註冊miscdevice ret = misc register(&s3c2410wdt miscdev); if (ret) { printk(KERN ERR PFX "cannot registermiscdev on minor=%d (%d)\n", WATCHDOG MINOR, ret); return ret; } if (tmr atboot && started == 0) { printk(KERN INFO PFX "Starting Watchdog Timer\n"); s3c2410wdt start (); } return 0; }
4.2 探測函數
static int s3c2410wdt remove (struct platform device *dev) { if (wdt mem != NULL) { release resource (wdt mem); //釋放資源 kfree (wdt mem);//釋放內存 wdt mem = NULL; } //釋放中斷 if (wdt irq != NULL) { free irq (wdt irq->start, dev); wdt irq = NULL; } //禁止時鐘源 if (wdt clock != NULL) { clk disable (wdt clock); clk put (wdt clock); wdt clock = NULL; } misc deregister(&s3c2410wdt miscdev);//註銷miscdevice return 0; }
5 掛起和恢復函數
5.1 掛起函數
static int s3c2410wdt suspend (struct platform device *dev, pm message t state) { /* 保存看門狗狀態,中止它 */ wtcon save = readl (wdt base + S3C2410 WTCON); wtdat save = readl (wdt base + S3C2410 WTDAT); s3c2410wdt stop (); return 0; }
5.2 恢復函數
static int s3c2410wdt resume (struct platform device *dev) { /* 恢復看門狗狀態 */ writel (wtdat save, wdt base + S3C2410 WTDAT); writel (wtdat save, wdt base + S3C2410 WTCNT); writel (wtcon save, wdt base + S3C2410 WTCON); printk (KERN INFO PFX "watchdog %sabled\n", (wtcon save &S3C2410 WTCON ENABLE)? "en" : "dis"); return 0; }
6 打開和釋放函數
6.1 打開函數
static int s3c2410wdt open (struct inode *inode, struct file *file) { if (down trylock (&open lock)) //得到打開鎖 return - EBUSY; if (nowayout) { module get (THIS MODULE); } else { allow close = CLOSE STATE ALLOW; } /* 啓動看門狗 */ s3c2410wdt start (); return nonseekable open (inode, file); }
6.2 釋放函數
static int s3c2410wdt release (struct inode *inode,struct file *file) { /* 中止看門狗 */ if (allow close == CLOSE STATE ALLOW) { s3c2410wdt stop (); } else { printk (KERN CRIT PFX "Unexpected close, not stopping watchdog!\n"); s3c2410wdt keepalive (); } allow close = CLOSE STATE NOT; up (&open lock); //釋放打開鎖 return 0; }
7 啓停watchdog函數和寫函數
7.1 啓停看門狗函數
/*中止看門狗*/ static int s3c2410wdt stop (void) { unsigned long wtcon; wtcon = readl(wdt base + S3C2410 WTCON); //中止看門狗,禁止復位 wtcon &= ~ (S3C2410 WTCON ENABLE | S3C2410 WTCON RSTEN); writel (wtcon, wdt base + S3C2410 WTCON); return 0; } /*開啓看門狗*/ static int s3c2410wdt start (void) { unsigned long wtcon; s3c2410wdt stop (); wtcon = readl(wdt base + S3C2410 WTCON); //使能看門狗,128 分頻 wtcon |= S3C2410 WTCON ENABLE | S3C2410 WTCON DIV128; if (soft noboot) { wtcon |= S3C2410 WTCON INTEN; //使能中斷 wtcon &= ~S3C2410 WTCON RSTEN; //禁止復位 } else { wtcon &= ~S3C2410 WTCON INTEN; //禁止中斷 wtcon |= S3C2410 WTCON RSTEN; //使能復位 } DBG ("%s: wdt count=0x%08x, wtcon=%08lx\n", FUNCTION , wdt count, wtcon); writel (wdt count, wdt base + S3C2410 WTDAT); writel (wdt count, wdt base + S3C2410 WTCNT); writel (wtcon, wdt base + S3C2410 WTCON); return 0; }
7.2 寫函數
static ssize t s3c2410wdt write (struct file *file, const char user *data, size t len, loff t *ppos) { /* 刷新看門狗 */ if (len) { if (!nowayout) { size t i; allow close = CLOSE STATE NOT; for (i = 0; i != len; i++) { char c; if (get user(c, data + i))//用戶空間->內核空間 return - EFAULT; if (c == 'V ') //若是寫入了'V ' ,容許關閉 allow close = CLOSE STATE ALLOW; } } s3c2410wdt keepalive (); } return len; }
版權全部,轉載請註明轉載地址:http://www.cnblogs.com/lihuidashen/p/4501953.html