Messages in this thread Patch in this message | | | Subject | [PATCH] new netcom watchdog driver for 2.4 | From | Justin Cormack <> | Date | 04 Sep 2003 18:04:44 +0100 |
| |
Here is a patch adding a watchdog driver for the Netcom SBCs http://www.netcomipc.com.tw/
I also moved softdog to the end of the section in Config.in like it says it should be.
It is against 2.4.22, but should apply or I will rediff it.
Justin Cormack
diff -urN linux-2.4.22-orig/drivers/char/Config.in linux-2.4.22/drivers/char/Config.in --- linux-2.4.22-orig/drivers/char/Config.in 2003-08-25 12:44:41.000000000 +0100 +++ linux-2.4.22/drivers/char/Config.in 2003-09-04 17:53:32.000000000 +0100 @@ -248,6 +248,7 @@ fi tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT dep_tristate ' AMD 766/768 TCO Timer/Watchdog' CONFIG_AMD7XX_TCO $CONFIG_EXPERIMENTAL + tristate ' Netcom SBC watchdog' CONFIG_NETCOM_WDT fi endmenu diff -urN linux-2.4.22-orig/drivers/char/Makefile linux-2.4.22/drivers/char/Makefile --- linux-2.4.22-orig/drivers/char/Makefile 2003-08-25 12:44:41.000000000 +0100 +++ linux-2.4.22/drivers/char/Makefile 2003-09-04 17:53:26.000000000 +0100 @@ -300,8 +300,9 @@ obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o -obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o +obj-$(CONFIG_NETCOM_WDT) += netcomwdt.o +obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o subdir-$(CONFIG_MWAVE) += mwave ifeq ($(CONFIG_MWAVE),y) diff -urN linux-2.4.22-orig/drivers/char/netcomwdt.c linux-2.4.22/drivers/char/netcomwdt.c --- linux-2.4.22-orig/drivers/char/netcomwdt.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.22/drivers/char/netcomwdt.c 2003-09-04 17:53:21.000000000 +0100 @@ -0,0 +1,246 @@ +/* + * Netcom Single Board Computer WDT driver for Linux 2.4.x + * Tested on Netcom NC-679, NC-671, should work on other models + * (all models I have checked documentation for have same driver) + * http://www.netcomipc.com.tw/ + * + * (c) Copyright 2003 Justin Cormack <justin@street-vision.com> + * + * To start watchdog write timeout in seconds to 0x443 + * To stop watchdog write any value to 0xk043 where k is 1..d + * (we use 0x1043 which seems to be fine) + * + * The documentation claims that the timeout values are 4s-1024s in + * 4s intervals. It even gives a nice table of these values. However + * this is clearly not the case on the boards I have tested. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/spinlock.h> + +static unsigned long ncwdt_is_open; +static spinlock_t ncwdt_lock; +static int expect_close = 0; + +/* + * You must set these - there is no sane way to probe for this board. + */ + +#define WDT_START 0x443 +#define WDT_STOP 0x1043 + +#define WD_TIMO 60 /* 1 minute */ +static int wd_margin = WD_TIMO; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static inline void ncwdt_start(void) +{ + /* start up watchdog */ + outb_p(wd_margin, WDT_START); +} + +static inline void ncwdt_stop(void) +{ + /* stop watchdog */ + outb_p(0, WDT_STOP); +} + + +static void ncwdt_ping(void) +{ + /* pat watchdog */ + spin_lock(&ncwdt_lock); + ncwdt_stop(); + ncwdt_start(); + spin_unlock(&ncwdt_lock); +} + +static ssize_t ncwdt_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + expect_close = 1; + } + } + ncwdt_ping(); + return 1; + } + return 0; +} + +static int ncwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_margin; + static struct watchdog_info ident = { + WDIOF_KEEPALIVEPING | + WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE, + 1, "Netcom WDT" + }; + int one=1; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user + ((struct watchdog_info *) arg, &ident, sizeof (ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *) arg, &one, sizeof (int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + ncwdt_ping(); + break; + + case WDIOC_SETTIMEOUT: + if (get_user(new_margin, (int *)arg)) + return -EFAULT; + if ((new_margin < 1) || (new_margin > 255)) + return -EINVAL; + wd_margin = new_margin; + ncwdt_ping(); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(wd_margin, (int *)arg); + + default: + return -ENOTTY; + } + return 0; +} + +static int ncwdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &ncwdt_is_open)) + return -EBUSY; + ncwdt_start(); + return 0; +} + +static int +ncwdt_close(struct inode *inode, struct file *file) +{ + clear_bit(0, &ncwdt_is_open); + if (expect_close) { + ncwdt_stop(); + } else { + printk(KERN_CRIT "WDT device closed unexpectedly. WDT will not stop!\n"); + } + return 0; +} + +/* + * Notifier for system down + */ + +static int ncwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the WDT off */ + ncwdt_stop(); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations ncwdt_fops = { + owner:THIS_MODULE, + write:ncwdt_write, + ioctl:ncwdt_ioctl, + open:ncwdt_open, + release:ncwdt_close, +}; + +static struct miscdevice ncwdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &ncwdt_fops +}; + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block ncwdt_notifier = { + ncwdt_notify_sys, + NULL, + 0 +}; + +static int __init ncwdt_init(void) +{ + printk(KERN_INFO "WDT driver for Netcom single board computers initialising.\n"); + + spin_lock_init(&ncwdt_lock); + if(!request_region(WDT_STOP, 1, "Netcom WDT")) + goto error; + if(!request_region(WDT_START, 1, "Netcom WDT")) + goto error2; + if(misc_register(&ncwdt_miscdev)<0) + goto error3; + register_reboot_notifier(&ncwdt_notifier); + return 0; +error3: + release_region(WDT_START, 1); +error2: + release_region(WDT_STOP, 1); +error: + return -ENODEV; +} + +static void __exit ncwdt_exit(void) +{ + misc_deregister(&ncwdt_miscdev); + unregister_reboot_notifier(&ncwdt_notifier); + release_region(WDT_STOP, 1); + release_region(WDT_START, 1); +} + +module_init(ncwdt_init); +module_exit(ncwdt_exit); + +MODULE_AUTHOR("Justin Cormack"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + +/* end of netcomwdt.c */
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |