1、linux核心子產品喂狗方法:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/mach/arch.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
struct timer_list epc_watchdog;
void epc_feed_wdt(void)
{
gpio_direction_output(65, 0);
ndelay(2);
gpio_direction_output(65, 1);
}
EXPORT_SYMBOL(epc_feed_wdt);
static void epc_watchdog_timeout(unsigned long arg)
{
//printk("timer out!\n");
epc_feed_wdt();
mod_timer(&epc_watchdog, jiffies + 1*HZ/4);
}
static int epc_timer_init(void)
{
epc_feed_wdt();
printk("wdt feed timer start!!\n");
init_timer(&epc_watchdog);
epc_watchdog.function = &epc_watchdog_timeout;
epc_watchdog.expires = jiffies + 1*HZ/4;
add_timer(&epc_watchdog);
epc_feed_wdt();
return 0;
}
//static void epc_timer_exit(void)
//{
// printk(KERN_ALERT "Goodbye, cruel world\n");
//}
subsys_initcall(epc_timer_init);
//module_init(epc_timer_init);
//module_exit(epc_timer_exit);
MODULE_LICENSE("Dual BSD/GPL");
2、應用層喂狗方法:
M335x-T/A3352-T工控主機闆有一個可程式設計看門狗(/dev/watchdog),可用于監測應用程式的運作狀況。看門狗有如下特點:
(1)預設逾時時間為19秒,逾時時間可設定(1~60秒);
(2)先向看門狗發送一個字元“V”後,可關閉看門狗。
設定看門狗時間
看門狗預設逾時時間為19秒,使用者可以将逾時時間設定為需要的值,通過ioctl實作,具體指令為:WDIOC_SETTIMEOUT,需要一個參數,即逾時時間。使用示例:
int timeout = 10;
ioctl(wdt_fd, WDIOC_SETTIMEOUT, &timeout);
擷取逾時時間
通過ioctl以及WDIOC_GETTIMEOUT指令,可以獲得看門狗的逾時時間。使用示例:
timeout = 0;
ioctl(wdt_fd, WDIOC_GETTIMEOUT, &timeout);
printf("The timeout is %d seconds\n", timeout);
喂狗操作
看門狗被打開後,必須在逾時時間内進行喂狗,最簡單的喂狗辦法就是向看門狗寫一個字元(特殊字元除外)。
關閉看門狗
需先寫入“V”,然後使用close關閉看門狗。使用示例:
write(wdt_fd, "V", 1);
close(wdt_fd);
範例
程式清單1 是一個非常簡單的範例。打開看門狗後,将看門狗逾時設定為10秒鐘,然後在逾時時間内周期性喂狗。運作該程式,系統不會複位。如果調整喂狗周期大于10秒,程式将會引起系統複位。
程式清單1 看門狗用法簡單範例
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/watchdog.h>
#define WDT "/dev/watchdog"
int main(void)
{
int wdt_fd = -1;
int timeout;
wdt_fd = open(WDT, O_WRONLY);
if (wdt_fd == -1) {
printf("fail to open "WDT "!\n");
}
printf(WDT " is opened!\n");
timeout = 10;
ioctl(wdt_fd, WDIOC_SETTIMEOUT, &timeout);
ioctl(wdt_fd, WDIOC_GETTIMEOUT, &timeout);
printf("The timeout was is %d seconds\n", timeout);
#if 1 // 循環喂狗
while(1) {
write(wdt_fd, "\0", 1);
sleep(9); // 喂狗時間為9秒,小于設定的10秒;如果喂// 狗時間大于逾時時間,将會發生看門狗複位
}
#else // 關閉看門狗
write(wdt_fd, "V", 1);
close(wdt_fd);
printf( WDT " is closeed!\n");
#endif
return 0;
}
3、驅動程式代碼:
/*
* omap_wdt.c
*
* Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
*
* Author: MontaVista Software, Inc.
* <[email protected]> or <[email protected]>
*
* 2003 (c) MontaVista Software, Inc. This file is licensed under the
* terms of the GNU General Public License version 2. This program is
* licensed "as is" without any warranty of any kind, whether express
* or implied.
*
* History:
*
* 20030527: George G. Davis <[email protected]>
* Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c
* (c) Copyright 2000 Oleg Drokin <[email protected]>
* Based on SoftDog driver by Alan Cox <[email protected]>
*
* Copyright (c) 2004 Texas Instruments.
* 1. Modified to support OMAP1610 32-KHz watchdog timer
* 2. Ported to 2.6 kernel
*
* Copyright (c) 2005 David Brownell
* Use the driver model and standard identifiers; handle bigger timeouts.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/moduleparam.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <mach/hardware.h>
#include <plat/prcm.h>
#include "omap_wdt.h"
static struct platform_device *omap_wdt_dev;
static unsigned timer_margin;
module_param(timer_margin, uint, 0);
MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
static unsigned int wdt_trgr_pattern = 0x1234;
static spinlock_t wdt_lock;
struct omap_wdt_dev {
void __iomem *base; /* physical */
struct device *dev;
int omap_wdt_users;
struct resource *mem;
struct miscdevice omap_wdt_miscdev;
};
static void omap_wdt_ping(struct omap_wdt_dev *wdev)
{
void __iomem *base = wdev->base;
/* wait for posted write to complete */
while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
cpu_relax();
wdt_trgr_pattern = ~wdt_trgr_pattern;
__raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
/* wait for posted write to complete */
while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
cpu_relax();
/* reloaded WCRR from WLDR */
}
static void omap_wdt_enable(struct omap_wdt_dev *wdev)
{
void __iomem *base = wdev->base;
/* Sequence to enable the watchdog */
__raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
cpu_relax();
__raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
cpu_relax();
}
static void omap_wdt_disable(struct omap_wdt_dev *wdev)
{
void __iomem *base = wdev->base;
/* sequence required to disable watchdog */
__raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
cpu_relax();
__raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
cpu_relax();
}
static void omap_wdt_adjust_timeout(unsigned new_timeout)
{
if (new_timeout < TIMER_MARGIN_MIN)
new_timeout = TIMER_MARGIN_DEFAULT;
if (new_timeout > TIMER_MARGIN_MAX)
new_timeout = TIMER_MARGIN_MAX;
timer_margin = new_timeout;
}
static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
{
u32 pre_margin = GET_WLDR_VAL(timer_margin);
void __iomem *base = wdev->base;
/* just count up at 32 KHz */
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
__raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
}
/*
* Allow only one task to hold it open
*/
static int omap_wdt_open(struct inode *inode, struct file *file)
{
struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
void __iomem *base = wdev->base;
if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
return -EBUSY;
pm_runtime_get_sync(wdev->dev);
/* initialize prescaler */
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
__raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
file->private_data = (void *) wdev;
omap_wdt_set_timeout(wdev);
omap_wdt_ping(wdev); /* trigger loading of new timeout value */
omap_wdt_enable(wdev);
return nonseekable_open(inode, file);
}
static int omap_wdt_release(struct inode *inode, struct file *file)
{
struct omap_wdt_dev *wdev = file->private_data;
/*
* Shut off the timer unless NOWAYOUT is defined.
*/
#ifndef CONFIG_WATCHDOG_NOWAYOUT
omap_wdt_disable(wdev);
pm_runtime_put_sync(wdev->dev);
#else
printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
#endif
wdev->omap_wdt_users = 0;
return 0;
}
static ssize_t omap_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
struct omap_wdt_dev *wdev = file->private_data;
/* Refresh LOAD_TIME. */
if (len) {
spin_lock(&wdt_lock);
omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
}
return len;
}
static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct omap_wdt_dev *wdev;
int new_margin;
static const struct watchdog_info ident = {
.identity = "OMAP Watchdog",
.options = WDIOF_SETTIMEOUT,
.firmware_version = 0,
};
wdev = file->private_data;
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(ident));
case WDIOC_GETSTATUS:
return put_user(0, (int __user *)arg);
case WDIOC_GETBOOTSTATUS:
if (cpu_is_omap16xx())
return put_user(__raw_readw(ARM_SYSST),
(int __user *)arg);
if (cpu_is_omap24xx())
return put_user(omap_prcm_get_reset_sources(),
(int __user *)arg);
case WDIOC_KEEPALIVE:
spin_lock(&wdt_lock);
omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, (int __user *)arg))
return -EFAULT;
omap_wdt_adjust_timeout(new_margin);
spin_lock(&wdt_lock);
omap_wdt_disable(wdev);
omap_wdt_set_timeout(wdev);
omap_wdt_enable(wdev);
omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timer_margin, (int __user *)arg);
default:
return -ENOTTY;
}
}
static const struct file_operations omap_wdt_fops = {
.owner = THIS_MODULE,
.write = omap_wdt_write,
.unlocked_ioctl = omap_wdt_ioctl,
.open = omap_wdt_open,
.release = omap_wdt_release,
.llseek = no_llseek,
};
static int __devinit omap_wdt_probe(struct platform_device *pdev)
{
struct resource *res, *mem;
struct omap_wdt_dev *wdev;
int ret;
/* reserve static register mappings */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENOENT;
goto err_get_resource;
}
if (omap_wdt_dev) {
ret = -EBUSY;
goto err_busy;
}
mem = request_mem_region(res->start, resource_size(res), pdev->name);
if (!mem) {
ret = -EBUSY;
goto err_busy;
}
wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
if (!wdev) {
ret = -ENOMEM;
goto err_kzalloc;
}
wdev->omap_wdt_users = 0;
wdev->mem = mem;
wdev->dev = &pdev->dev;
wdev->base = ioremap(res->start, resource_size(res));
if (!wdev->base) {
ret = -ENOMEM;
goto err_ioremap;
}
platform_set_drvdata(pdev, wdev);
pm_runtime_enable(wdev->dev);
pm_runtime_get_sync(wdev->dev);
omap_wdt_disable(wdev);
omap_wdt_adjust_timeout(timer_margin);
wdev->omap_wdt_miscdev.parent = &pdev->dev;
wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
wdev->omap_wdt_miscdev.name = "watchdog";
wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
ret = misc_register(&(wdev->omap_wdt_miscdev));
if (ret)
goto err_misc;
pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
__raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
timer_margin);
pm_runtime_put_sync(wdev->dev);
omap_wdt_dev = pdev;
return 0;
err_misc:
platform_set_drvdata(pdev, NULL);
iounmap(wdev->base);
err_ioremap:
wdev->base = NULL;
kfree(wdev);
err_kzalloc:
release_mem_region(res->start, resource_size(res));
err_busy:
err_get_resource:
return ret;
}
static void omap_wdt_shutdown(struct platform_device *pdev)
{
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
if (wdev->omap_wdt_users) {
omap_wdt_disable(wdev);
pm_runtime_put_sync(wdev->dev);
}
}
static int __devexit omap_wdt_remove(struct platform_device *pdev)
{
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
misc_deregister(&(wdev->omap_wdt_miscdev));
release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
iounmap(wdev->base);
kfree(wdev);
omap_wdt_dev = NULL;
return 0;
}
#ifdef CONFIG_PM
/* REVISIT ... not clear this is the best way to handle system suspend; and
* it's very inappropriate for selective device suspend (e.g. suspending this
* through sysfs rather than by stopping the watchdog daemon). Also, this
* may not play well enough with NOWAYOUT...
*/
static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
if (wdev->omap_wdt_users) {
omap_wdt_disable(wdev);
pm_runtime_put_sync(wdev->dev);
}
return 0;
}
static int omap_wdt_resume(struct platform_device *pdev)
{
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
if (wdev->omap_wdt_users) {
pm_runtime_get_sync(wdev->dev);
omap_wdt_enable(wdev);
omap_wdt_ping(wdev);
}
return 0;
}
#else
#define omap_wdt_suspend NULL
#define omap_wdt_resume NULL
#endif
static struct platform_driver omap_wdt_driver = {
.probe = omap_wdt_probe,
.remove = __devexit_p(omap_wdt_remove),
.shutdown = omap_wdt_shutdown,
.suspend = omap_wdt_suspend,
.resume = omap_wdt_resume,
.driver = {
.owner = THIS_MODULE,
.name = "omap_wdt",
},
};
static int __init omap_wdt_init(void)
{
spin_lock_init(&wdt_lock);
return platform_driver_register(&omap_wdt_driver);
}
static void __exit omap_wdt_exit(void)
{
platform_driver_unregister(&omap_wdt_driver);
}
module_init(omap_wdt_init);
module_exit(omap_wdt_exit);
MODULE_AUTHOR("George G. Davis");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform:omap_wdt");