-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 55875 b: refs/heads/master c: 04bf3b4 h: refs/heads/master i: 55873: bbcbd8e 55871: d182041 v: v3
- Loading branch information
Florian Fainelli
authored and
Wim Van Sebroeck
committed
May 6, 2007
1 parent
861c1dd
commit a40be6f
Showing
4 changed files
with
247 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 62be074147fe2e24359d76a33938df7bccea1e6a | ||
refs/heads/master: 04bf3b4f5fc033adf921f2e57d034ddbebef5fe7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
/* | ||
* Driver for the MTX-1 Watchdog. | ||
* | ||
* (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved. | ||
* http://www.4g-systems.biz | ||
* | ||
* (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the License, or (at your option) any later version. | ||
* | ||
* Neither Michael Stickel nor 4G Systems admit liability nor provide | ||
* warranty for any of this software. This material is provided | ||
* "AS-IS" and at no charge. | ||
* | ||
* (c) Copyright 2005 4G Systems <info@4g-systems.biz> | ||
* | ||
* Release 0.01. | ||
* Author: Michael Stickel michael.stickel@4g-systems.biz | ||
* | ||
* Release 0.02. | ||
* Author: Florian Fainelli florian@openwrt.org | ||
* use the Linux watchdog/timer APIs | ||
* | ||
* The Watchdog is configured to reset the MTX-1 | ||
* if it is not triggered for 100 seconds. | ||
* It should not be triggered more often than 1.6 seconds. | ||
* | ||
* A timer triggers the watchdog every 5 seconds, until | ||
* it is opened for the first time. After the first open | ||
* it MUST be triggered every 2..95 seconds. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/moduleparam.h> | ||
#include <linux/types.h> | ||
#include <linux/errno.h> | ||
#include <linux/miscdevice.h> | ||
#include <linux/fs.h> | ||
#include <linux/init.h> | ||
#include <linux/ioport.h> | ||
#include <linux/timer.h> | ||
#include <linux/completion.h> | ||
#include <linux/jiffies.h> | ||
#include <linux/watchdog.h> | ||
#include <asm/io.h> | ||
#include <asm/uaccess.h> | ||
|
||
#include <asm/mach-au1x00/au1000.h> | ||
|
||
#define MTX1_WDT_INTERVAL (5 * HZ) | ||
|
||
static int ticks = 100 * HZ; | ||
|
||
static struct { | ||
struct completion stop; | ||
volatile int running; | ||
struct timer_list timer; | ||
volatile int queue; | ||
int default_ticks; | ||
unsigned long inuse; | ||
} mtx1_wdt_device; | ||
|
||
static void mtx1_wdt_trigger(unsigned long unused) | ||
{ | ||
u32 tmp; | ||
|
||
if (mtx1_wdt_device.running) | ||
ticks--; | ||
/* | ||
* toggle GPIO2_15 | ||
*/ | ||
tmp = au_readl(GPIO2_DIR); | ||
tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15)); | ||
au_writel (tmp, GPIO2_DIR); | ||
|
||
if (mtx1_wdt_device.queue && ticks) | ||
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); | ||
else { | ||
complete(&mtx1_wdt_device.stop); | ||
} | ||
} | ||
|
||
static void mtx1_wdt_reset(void) | ||
{ | ||
ticks = mtx1_wdt_device.default_ticks; | ||
} | ||
|
||
|
||
static void mtx1_wdt_start(void) | ||
{ | ||
if (!mtx1_wdt_device.queue) { | ||
mtx1_wdt_device.queue = 1; | ||
au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR); | ||
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); | ||
} | ||
mtx1_wdt_device.running++; | ||
} | ||
|
||
static int mtx1_wdt_stop(void) | ||
{ | ||
if (mtx1_wdt_device.queue) { | ||
mtx1_wdt_device.queue = 0; | ||
au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR); | ||
} | ||
|
||
ticks = mtx1_wdt_device.default_ticks; | ||
|
||
return 0; | ||
} | ||
|
||
/* Filesystem functions */ | ||
|
||
static int mtx1_wdt_open(struct inode *inode, struct file *file) | ||
{ | ||
if (test_and_set_bit(0, &mtx1_wdt_device.inuse)) | ||
return -EBUSY; | ||
|
||
return nonseekable_open(inode, file); | ||
} | ||
|
||
|
||
static int mtx1_wdt_release(struct inode *inode, struct file *file) | ||
{ | ||
clear_bit(0, &mtx1_wdt_device.inuse); | ||
return 0; | ||
} | ||
|
||
static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
{ | ||
void __user *argp = (void __user *)arg; | ||
unsigned int value; | ||
static struct watchdog_info ident = | ||
{ | ||
.options = WDIOF_CARDRESET, | ||
.identity = "MTX-1 WDT", | ||
}; | ||
|
||
switch(cmd) { | ||
case WDIOC_KEEPALIVE: | ||
mtx1_wdt_reset(); | ||
break; | ||
case WDIOC_GETSTATUS: | ||
if ( copy_to_user(argp, &value, sizeof(int)) ) | ||
return -EFAULT; | ||
break; | ||
case WDIOC_GETSUPPORT: | ||
if ( copy_to_user(argp, &ident, sizeof(ident)) ) | ||
return -EFAULT; | ||
break; | ||
case WDIOC_SETOPTIONS: | ||
if ( copy_from_user(&value, argp, sizeof(int)) ) | ||
return -EFAULT; | ||
switch(value) { | ||
case WDIOS_ENABLECARD: | ||
mtx1_wdt_start(); | ||
break; | ||
case WDIOS_DISABLECARD: | ||
return mtx1_wdt_stop(); | ||
default: | ||
return -EINVAL; | ||
} | ||
break; | ||
default: | ||
return -ENOTTY; | ||
} | ||
return 0; | ||
} | ||
|
||
|
||
static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) | ||
{ | ||
if (!count) | ||
return -EIO; | ||
|
||
mtx1_wdt_reset(); | ||
return count; | ||
} | ||
|
||
static struct file_operations mtx1_wdt_fops = { | ||
.owner = THIS_MODULE, | ||
.llseek = no_llseek, | ||
.ioctl = mtx1_wdt_ioctl, | ||
.open = mtx1_wdt_open, | ||
.write = mtx1_wdt_write, | ||
.release = mtx1_wdt_release | ||
}; | ||
|
||
|
||
static struct miscdevice mtx1_wdt_misc = { | ||
.minor = WATCHDOG_MINOR, | ||
.name = "watchdog", | ||
.fops = &mtx1_wdt_fops | ||
}; | ||
|
||
|
||
static int __init mtx1_wdt_init(void) | ||
{ | ||
int ret; | ||
|
||
if ((ret = misc_register(&mtx1_wdt_misc)) < 0) { | ||
printk(KERN_ERR " mtx-1_wdt : failed to register\n"); | ||
return ret; | ||
} | ||
|
||
init_completion(&mtx1_wdt_device.stop); | ||
mtx1_wdt_device.queue = 0; | ||
|
||
clear_bit(0, &mtx1_wdt_device.inuse); | ||
|
||
setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L); | ||
|
||
mtx1_wdt_device.default_ticks = ticks; | ||
|
||
mtx1_wdt_start(); | ||
|
||
printk(KERN_INFO "MTX-1 Watchdog driver\n"); | ||
|
||
return 0; | ||
} | ||
|
||
static void __exit mtx1_wdt_exit(void) | ||
{ | ||
if (mtx1_wdt_device.queue) { | ||
mtx1_wdt_device.queue = 0; | ||
wait_for_completion(&mtx1_wdt_device.stop); | ||
} | ||
misc_deregister(&mtx1_wdt_misc); | ||
} | ||
|
||
module_init(mtx1_wdt_init); | ||
module_exit(mtx1_wdt_exit); | ||
|
||
MODULE_AUTHOR("Michael Stickel, Florian Fainelli"); | ||
MODULE_DESCRIPTION("Driver for the MTX-1 watchdog"); | ||
MODULE_LICENSE("GPL"); |