diff -ruN linux.org/Documentation/Configure.help linux/Documentation/Configure.help --- linux.org/Documentation/Configure.help Fri Nov 2 17:39:05 2001 +++ linux/Documentation/Configure.help Thu Jan 3 00:17:14 2002 @@ -11399,6 +11399,52 @@ computer, say `Y' here to support its built-in watchdog timer feature. See the help for CONFIG_WATCHDOG for discussion. +WAFER 582x Watchdog Timer +CONFIG_582X_WDT + This is the driver for the hardware watchdog on the WAFER 582x Single + Board Computer produced by ICP Electronics. This watchdog watches your + kernel to make sure it doesn't freeze, and if it does, it reboots your + computer after a certain amount of time. You may also check an + userspace code using the /dev/watchdog special file. + See sources for more info. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called wafer582xwdt.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +WAFER 582x Watchdog Timer /proc support +CONFIG_582X_WDT_USE_PROC + This option active 10 userspace timers in the /proc/watchdog dir: + put a value greater than 0 to a file and you activate the watchdog, + put a 0 in the same file and you will stop the timer. + + You must say Y to "proc filesystem support" (CONFIG_PROC_FS) to + use this option. + +WAFER 5822 I/O Port Support +CONFIG_5822_IO + This is the driver for the I/O port on the WAFER 5822 Single Board + Computer produced by ICP Electronics. You can read the status of + input signals and set the status of output signals in the + /proc/io_port directory. + + This driver may works correctly also with WAFER 4823 and WAFER 4821 + cards if you set the register address in the BIOS at the 0x240 value. + + You must say Y to "proc filesystem support" (CONFIG_PROC_FS) to + use this part of the kernel. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called wafer582xio.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +WAFER 5822 I/O Port Register Address +CONFIG_5822_IO_ADDR + Set here the register address of the I/O port in your card. You can + find this walue in the BIOS. + SBC-60XX Watchdog Timer CONFIG_60XX_WDT This driver can be used with the watchdog timer found on some diff -ruN linux.org/arch/i386/config.in linux/arch/i386/config.in --- linux.org/arch/i386/config.in Fri Nov 2 17:39:05 2001 +++ linux/arch/i386/config.in Wed Jan 2 21:11:42 2002 @@ -120,6 +120,10 @@ bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi tristate 'Toshiba Laptop support' CONFIG_TOSHIBA +tristate ' WAFER 5822 I/O controller' CONFIG_5822_IO +if [ "$CONFIG_5822_IO" = "y" ]; then + hex ' Register address 240,260,280' CONFIG_5822_IO_ADDR 280 +fi endmenu diff -ruN linux.org/drivers/char/Config.in linux/drivers/char/Config.in --- linux.org/drivers/char/Config.in Fri Nov 2 17:39:06 2001 +++ linux/drivers/char/Config.in Wed Jan 2 20:57:04 2002 @@ -103,7 +103,11 @@ tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO - tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD + tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD + tristate ' WAFER 582x Watchdog Timer' CONFIG_582X_WDT + if [ "$CONFIG_582X_WDT" != "n" ]; then + bool ' /proc/watchdog directory support' CONFIG_582X_WDT_USE_PROC + fi tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' WDT ISA Watchdog timer' CONFIG_WDT diff -ruN linux.org/drivers/char/Makefile linux/drivers/char/Makefile --- linux.org/drivers/char/Makefile Fri Nov 2 17:39:06 2001 +++ linux/drivers/char/Makefile Wed Jan 2 21:14:59 2002 @@ -317,6 +317,14 @@ endif endif +ifeq ($(CONFIG_582X_WDT),y) +O_OBJS += wafer582xwdt.o +else + ifeq ($(CONFIG_582X_WDT),m) + M_OBJS += wafer582xwdt.o + endif +endif + ifeq ($(CONFIG_60XX_WDT),y) O_OBJS += sbc60xxwdt.o else @@ -708,6 +716,14 @@ else ifeq ($(CONFIG_TOSHIBA),m) M_OBJS += toshiba.o + endif +endif + +ifeq ($(CONFIG_5822_IO),y) +O_OBJS += wafer5822io.o +else + ifeq ($(CONFIG_5822_IO),m) + M_OBJS += wafer5822io.o endif endif diff -ruN linux.org/drivers/char/misc.c linux/drivers/char/misc.c --- linux.org/drivers/char/misc.c Fri Nov 2 17:39:06 2001 +++ linux/drivers/char/misc.c Thu Jan 3 02:03:21 2002 @@ -71,6 +71,7 @@ extern void wdt_init(void); extern void acq_init(void); extern void wdt60xx_init(void); +extern void wafer582xwdt_init(void); extern void sbc60xxwdt_init(void); extern void dtlk_init(void); extern void pcwatchdog_init(void); @@ -84,6 +85,7 @@ extern int pc110pad_init(void); extern int pmu_device_init(void); extern int tosh_init(void); +extern int wafer5822io_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) @@ -189,7 +191,7 @@ EXPORT_SYMBOL(misc_register); EXPORT_SYMBOL(misc_deregister); -static struct proc_dir_entry *proc_misc; +static struct proc_dir_entry *proc_misc; int __init misc_init(void) { @@ -241,6 +243,9 @@ #ifdef CONFIG_ADVANTECH_WDT advwdt_init(); #endif +#ifdef CONFIG_582X_WDT + wafer582xwdt_init(); +#endif #ifdef CONFIG_60XX_WDT sbc60xxwdt_init(); #endif @@ -288,6 +293,9 @@ #endif #ifdef CONFIG_TOSHIBA tosh_init(); +#endif +#ifdef CONFIG_5822_IO + wafer5822io_init(); #endif if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", diff -ruN linux.org/drivers/char/wafer5822io.c linux/drivers/char/wafer5822io.c --- linux.org/drivers/char/wafer5822io.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/wafer5822io.c Wed Jan 2 21:11:26 2002 @@ -0,0 +1,434 @@ +/* + * WAFER 5822 Single Board Computer I/O interface driver for Linux 2.2.x + * + * (C) Copyright 2001 Piergiorgio Ghezzo + * + * + * 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. + * + * The author does NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * + * HISTORY: + * + * 30/12/2001 [Initial revision] + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEBUG(x) if (debug) { x }; +#define MODULE_NAME "wafer5822io" + + + +/*** Module parameters *******************************************************/ + + +#ifdef CONFIG_5822_IO_ADDR + static int io_addr = CONFIG_5822_IO_ADDR; // I/O register (see BIOS value) +#else + static int io_addr = 0; +#endif +static int debug = 0; // Debug flag +static int start_out_down = 0; // Output signals disabled at start? +static int Status; // Status of output signals + +MODULE_AUTHOR("Piergiorgio Ghezzo "); +MODULE_DESCRIPTION("I/O driver for WAFER 5822 single board computer"); +MODULE_PARM(debug, "i"); +MODULE_PARM(io_addr, "i"); +MODULE_PARM(start_out_down, "i"); + + + +/*** /proc/watchdog handling *************************************************/ + + +int io_proc_open(struct inode *inode, struct file *file) +{ +MOD_INC_USE_COUNT; +return 0; +} + + +int io_proc_close(struct inode *inode, struct file *file) +{ +MOD_DEC_USE_COUNT; +return 0; +} + + +/* This function show register address and status of all ports */ +static ssize_t status_output(struct file *file, char *Buffer, size_t len, loff_t *offset) +{ +static int finished = 0; +char OutString [500]; +int Register; +int Ciclo; + + +/* We return 0 to indicate end of file, that we have + * no more information. Otherwise, processes will + * continue to read from us in an endless loop. + */ +if (finished) + { + finished = 0; + return 0; + } + + +/* We use put_user to copy the string from the kernel's + * memory segment to the memory segment of the process that called us. + */ +Register = inb_p(io_addr); +sprintf(OutString, "Register address: 0x%x\nInput: %d %d %d %d\nOutput: %d %d %d %d\n", + io_addr, + (Register & 1 ? 1 : 0), (Register & 2 ? 1 : 0), (Register & 4 ? 1 : 0), (Register & 8 ? 1 : 0), + (Status & 1 ? 1 : 0), (Status & 2 ? 1 : 0), (Status & 4 ? 1 : 0), (Status & 8 ? 1 : 0) + ); + +for (Ciclo=0; Ciclof_dentry->d_name.name; + +if (FileName[0] == 'i' && FileName[1] == 'n') + { + Register = inb_p(io_addr); + sprintf(OutString, "%d\n", (Register & (1<<(FileName[2]-48)) ? 1 : 0)); + } + else + if (FileName[0] == 'o' && FileName[1] == 'u' && FileName[2] == 't') + sprintf(OutString, "%d\n", (Status & (1<<(FileName[3]-48)) ? 1 : 0)); + else + strcpy (OutString, "Bad file name!"); + +for (Ciclo=0; Ciclo 2) + return Length; + +/* Read the first input char */ +get_user(Action, Buffer); +if (Action != '0' && Action != '1') + return Length; + + +/* Get the file name */ +FileName = (char *)file->f_dentry->d_name.name; + +if (FileName[0] != 'o' || FileName[1] != 'u' || FileName[2] != 't') + return Length; + + +if (Action == '1') + { + // Set the bit + Status |= 1<<(FileName[3]-48); + outb(~Status, io_addr); + } + else + { + // Clear the bit + Status &= ~(1<<(FileName[3]-48)); + outb(~Status, io_addr); + } + +return Length; +} + + +int io_proc_permission(struct inode *inode, int op) +{ +/* We allow everybody to read from our files, */ +/* but only root (uid 0) may write to them in the out files */ +if (op == 4 || (op == 2 && current->euid == 0 && (inode->i_mode & S_IWUSR) != 0)) + return 0; + +/* If it's anything else, access is denied */ +return -EACCES; +} + + +/* File operations for our proc files */ +static struct file_operations IO_FileOps_Proc_Status = + { + NULL, status_output, NULL, + NULL, NULL, NULL, NULL, + io_proc_open, NULL, io_proc_close, + }; + +static struct file_operations IO_FileOps_Proc_Files = + { + NULL, proc_output, proc_input, + NULL, NULL, NULL, NULL, + io_proc_open, NULL, io_proc_close, + }; + + +/* Inode operations for our proc files */ +static struct inode_operations IO_Inode_Proc_Status = + { + &IO_FileOps_Proc_Status, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + io_proc_permission + }; + +static struct inode_operations IO_Inode_Proc_Files = + { + &IO_FileOps_Proc_Files, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + io_proc_permission + }; + + +/* Directory entries */ +static struct proc_dir_entry IO_Proc_Dir = + { + 0, 7, "io_port", S_IFDIR | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_Status = + { + 0, 6, "status", S_IFREG | S_IRUGO, + 1, 0, 0, 0, &IO_Inode_Proc_Status, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_In0 = + { + 0, 3, "in0", S_IFREG | S_IRUGO, + 1, 0, 0, 0, &IO_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_In1 = + { + 0, 3, "in1", S_IFREG | S_IRUGO, + 1, 0, 0, 0, &IO_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_In2 = + { + 0, 3, "in2", S_IFREG | S_IRUGO, + 1, 0, 0, 0, &IO_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_In3 = + { + 0, 3, "in3", S_IFREG | S_IRUGO, + 1, 0, 0, 0, &IO_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_Out0 = + { + 0, 4, "out0", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &IO_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_Out1 = + { + 0, 4, "out1", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &IO_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_Out2 = + { + 0, 4, "out2", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &IO_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry IO_Proc_Out3 = + { + 0, 4, "out3", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &IO_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + + + +/*** Auto detection functions ************************************************/ + + +int SearchRegister(int Address) +{ +int Register = 0; + +request_region(Address, 1, "WAFER 5822 I/O"); +Register = inb(Address); +DEBUG ( printk(MODULE_NAME ": Register 0x%x value: %d\n", Address, Register); ) + + +if (Register < 0xFF) + { + printk(MODULE_NAME ": I/O register found at 0x%x\n", Address); + io_addr = Address; + return 0; + } + +release_region(Address, 1); +return 1; +} + + +int AutoDetect(void) +{ +if (SearchRegister(0x240)) + if (SearchRegister(0x260)) + if (SearchRegister(0x280)) + { + printk(MODULE_NAME ": I/O register not found. Check your BIOS!\n"); + return 1; + } + +return 0; +} + + + +/*** Module routines *********************************************************/ + + +#ifdef MODULE + +#define wafer5822io_init init_module + +void cleanup_module(void) +{ +proc_unregister(&IO_Proc_Dir, IO_Proc_Out3.low_ino); +proc_unregister(&IO_Proc_Dir, IO_Proc_Out2.low_ino); +proc_unregister(&IO_Proc_Dir, IO_Proc_Out1.low_ino); +proc_unregister(&IO_Proc_Dir, IO_Proc_Out0.low_ino); +proc_unregister(&IO_Proc_Dir, IO_Proc_In3.low_ino); +proc_unregister(&IO_Proc_Dir, IO_Proc_In2.low_ino); +proc_unregister(&IO_Proc_Dir, IO_Proc_In1.low_ino); +proc_unregister(&IO_Proc_Dir, IO_Proc_In0.low_ino); +proc_unregister(&IO_Proc_Dir, IO_Proc_Status.low_ino); +proc_unregister(&proc_root, IO_Proc_Dir.low_ino); + +release_region(io_addr, 1); +} + +#endif + + +#if defined(__init) +int __init wafer5822io_init(void) +#elif defined(__initfunc) +__initfunc(int wafer5822io_init(void)) +#else +int wafer5822io_init(void) +#endif +{ +int Register = 0; + +printk(MODULE_NAME ": I/O driver for WAFER 5822 single board computer initialising\n"); + +if (io_addr == 0) + { + if (AutoDetect()) + return 1; + } + else + { + if (SearchRegister(io_addr)) + { + printk(MODULE_NAME ": I/O register not found at 0x%x. Check your BIOS!\n", io_addr); + return 1; + } + } + + +proc_register(&proc_root, &IO_Proc_Dir); +proc_register(&IO_Proc_Dir, &IO_Proc_Status); +proc_register(&IO_Proc_Dir, &IO_Proc_In0); +proc_register(&IO_Proc_Dir, &IO_Proc_In1); +proc_register(&IO_Proc_Dir, &IO_Proc_In2); +proc_register(&IO_Proc_Dir, &IO_Proc_In3); +proc_register(&IO_Proc_Dir, &IO_Proc_Out0); +proc_register(&IO_Proc_Dir, &IO_Proc_Out1); +proc_register(&IO_Proc_Dir, &IO_Proc_Out2); +proc_register(&IO_Proc_Dir, &IO_Proc_Out3); + +outb((start_out_down ? 0x0F : 0), io_addr); +Status = (start_out_down ? 0 : 0x0F); + + +DEBUG ( Register = inb(io_addr); ) +DEBUG ( printk(MODULE_NAME ": Register 0x%x value: 0x%x\n", io_addr, Register); ) + +return 0; +} diff -ruN linux.org/drivers/char/wafer582xwdt.c linux/drivers/char/wafer582xwdt.c --- linux.org/drivers/char/wafer582xwdt.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/wafer582xwdt.c Sun Jan 6 09:05:58 2002 @@ -0,0 +1,671 @@ +/* + * WAFER 582x Single Board Computer Watchdog Timer driver for Linux 2.2.x + * + * (C) Copyright 2001 Piergiorgio Ghezzo + * + * Based on sbc60xxwdt.c by Jakob Oestergaard. + * Based on acquirewdt.c by Alan Cox. + * + * + * 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. + * + * The author does NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * + * HISTORY: + * + * 26/12/2001 [Initial revision] + * 27/12/2001 [Added /proc/watchdog support] + * + * + * --- Original text by Jakob Oestergaard -------------------------------- + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from the other Linux WDT + * drivers in several ways: + * *) The driver will ping the watchdog by itself, because this + * particular WDT has a very short timeout (one second) and it + * would be insane to count on any userspace daemon always + * getting scheduled within that time frame. + * *) This driver expects the userspace daemon to send a specific + * character code ('V') to /dev/watchdog before closing the + * /dev/watchdog file. If the userspace daemon closes the file + * without sending this special character, the driver will assume + * that the daemon (and userspace in general) died, and will + * stop pinging the WDT without disabling it first. This will + * cause a reboot. + * + * Why `V' ? Well, `V' is the character in ASCII for the value 86, + * and we all know that 86 is _the_ most random number in the universe. + * Therefore it is the letter that has the slightest chance of occurring + * by chance, when the system becomes corrupted. + * + * ----------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG(x) if (debug) { x }; +#define OUR_NAME "wafer582xwdt" +//#define CONFIG_582X_WDT_USE_PROC + + + +/*** Module parameters *******************************************************/ + + +static int debug = 0; // Debug flag +static int timeout = 7; // Watchdog timeout value (seconds) +static int ping = 5; // Module ping delay (seconds) +static int devtimeout = 10; // /dev/watchdog timeout value (seconds) +static int proctimeout[10] = // /prox/n timeout value (seconds) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static unsigned long next_heartbeat[11] = // 10 proc + 1 dev + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static int wdt_is_active = 0; +static int wdt_dev_is_open = 0; +static int wdt_expect_close = 0; + +MODULE_AUTHOR("Piergiorgio Ghezzo "); +MODULE_DESCRIPTION("WDT driver for 582x single board computer"); +MODULE_PARM(debug, "i"); +MODULE_PARM(timeout, "i"); +MODULE_PARM(ping, "i"); +MODULE_PARM(devtimeout, "i"); + + +/* You must set these - The driver cannot probe for the settings */ + +#define WDT_STOP 0x843 // watchdog start register +#define WDT_START 0x443 // watchdog stop register + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer = { 0, 0, 0, 0, wdt_timer_ping }; + + + +/*** Whack the dog routine ***************************************************/ + + +static void wdt_timer_ping(unsigned long data) +{ +char IsGood = 'Y'; +int Ciclo; + + +DEBUG ( printk(OUR_NAME ": jiffies=%ld - wdt_dev_is_open=%d - wdt_is_active=%d\n", jiffies, wdt_dev_is_open, wdt_is_active); ) + + +if (wdt_dev_is_open == 1 && time_after(jiffies, next_heartbeat[10])) + IsGood = 'N'; + +#ifdef CONFIG_582X_WDT_USE_PROC +for (Ciclo = 0; Ciclo < 10; Ciclo++) + if (proctimeout[Ciclo] != 0 && time_after(jiffies, next_heartbeat[Ciclo])) + IsGood = 'N'; +#endif + + +if (IsGood == 'Y') + { + /* Ping the WDT by reading from WDT_STOP and WDT_START */ + inb_p(WDT_STOP); + inb_p(WDT_START); + + /* Re-set the timer interval */ + timer.expires = jiffies + (ping * HZ); + add_timer(&timer); + + DEBUG ( printk(OUR_NAME ": Ping sent to the WDT\n"); ) + } + else + { + printk(OUR_NAME ": User heartbeat lost! Will not ping the watchdog\n"); + } +} + + +static void wdt_startup(void) +{ +/* Set the timeout */ +outb_p(timeout, WDT_START); + +/* Start the timer */ +timer.expires = jiffies + (ping * HZ); +add_timer(&timer); +printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ +/* Stop the timer */ +del_timer(&timer); +inb_p(WDT_STOP); +printk(OUR_NAME ": Watchdog timer is now disabled.\n"); +} + + + +/*** /dev/watchdog handling **************************************************/ + + +static ssize_t wdt_dev_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ +/* We can't seek */ +if (ppos != &file->f_pos) + return -ESPIPE; + +/* See if we got the magic character */ +if (count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for (ofs = 0; ofs != count; ofs++) + { + char c; + + if (get_user(c, buf+ofs)) + return -EFAULT; + + if (c == 'V') + { + DEBUG ( printk(OUR_NAME ": DEBUG: Received application data: special character\n"); ) + wdt_expect_close = 1; + } + else + DEBUG ( printk(OUR_NAME ": DEBUG: Received application data: other character\n"); ) + } + + /* Well, anyhow someone wrote to us, we should return that favour */ + next_heartbeat[10] = jiffies + (devtimeout * HZ); + } + +return 0; +} + + +static ssize_t wdt_dev_read(struct file * file, char * buf, size_t count, loff_t * ppos) +{ +/* No can do */ +return -EINVAL; +} + + +static int wdt_dev_open(struct inode * inode, struct file * file) +{ +switch (MINOR(inode->i_rdev)) + { + case WATCHDOG_MINOR: + + /* Just in case we're already talking to someone... */ + if (wdt_dev_is_open) + return -EBUSY; + + /* Good, fire up the show */ + MOD_INC_USE_COUNT; + + next_heartbeat[10] = jiffies + (devtimeout * HZ); + wdt_dev_is_open=1; + + if (wdt_is_active++ == 0) + wdt_startup(); + + return 0; + + default: + return -ENODEV; + } +} + + +static int wdt_dev_close(struct inode * inode, struct file * file) +{ +if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) + { + if (wdt_expect_close) + { + if (wdt_is_active-- == 1) + wdt_turnoff(); + } + else + { + del_timer(&timer); + printk(OUR_NAME ": device file closed unexpectedly. I reboot the system!\n"); + } + } + +wdt_dev_is_open=0; +MOD_DEC_USE_COUNT; + +return 0; +} + + +static struct file_operations wdt_dev_fops = + { + 0, wdt_dev_read, wdt_dev_write, + 0, 0, 0, 0, + wdt_dev_open, 0, wdt_dev_close + }; + +static struct miscdevice wdt_miscdev = + { + WATCHDOG_MINOR, + "watchdog", + &wdt_dev_fops + }; + + + +/*** /proc/watchdog handling *************************************************/ + + +#ifdef CONFIG_582X_WDT_USE_PROC + +int wdt_proc_open(struct inode *inode, struct file *file) +{ +MOD_INC_USE_COUNT; +return 0; +} + + +int wdt_wdt_proc_close(struct inode *inode, struct file *file) +{ +MOD_DEC_USE_COUNT; +return 0; +} + + +static ssize_t status_output(struct file *file, char *Buffer, size_t len, loff_t *offset) +{ +static int finished = 0; +char OutString[500]; +int Ciclo; + + +if (finished) + { + finished = 0; + return 0; + } + + +sprintf(OutString, "The watchdog is now %s.\n" + "WDT timeout: %d\n" + "Module ping: %d\n" + "/dev/watchdog timeout: %d - %s\n" + "/proc/watchdog/0 timeout: %d\n" + "/proc/watchdog/1 timeout: %d\n" + "/proc/watchdog/2 timeout: %d\n" + "/proc/watchdog/3 timeout: %d\n" + "/proc/watchdog/4 timeout: %d\n" + "/proc/watchdog/5 timeout: %d\n" + "/proc/watchdog/6 timeout: %d\n" + "/proc/watchdog/7 timeout: %d\n" + "/proc/watchdog/8 timeout: %d\n" + "/proc/watchdog/9 timeout: %d\n", + (wdt_is_active != 0 ? "enabled" : "disabled"), + timeout, ping, + devtimeout, (wdt_dev_is_open != 0 ? "enabled" : "disabled"), + proctimeout[0], proctimeout[1], proctimeout[2], + proctimeout[3], proctimeout[4], proctimeout[5], + proctimeout[6], proctimeout[7], proctimeout[8], + proctimeout[9]); + +for (Ciclo=0; Ciclof_dentry->d_name.name; + +/* Show out the timeout */ +sprintf(OutString, "%d\n", proctimeout[(*FileName)-48]); +for (Ciclo=0; Ciclo 4) + return Length; + +/* Get the file name */ +FileName = (char *)file->f_dentry->d_name.name; + + +/* Get the timeout value from the userspace buffer */ +for (Ciclo = 0; Ciclo < sizeof(Valore)-1 && Ciclo < Length; Ciclo++) + get_user (Valore[Ciclo], Buffer + Ciclo); +Valore[Ciclo] = '\0'; + + +NewTimeout = (int) simple_strtoul(Valore, NULL, 0); +OldTimeout = proctimeout[(*FileName)-48]; + +if (NewTimeout != 0) + { + next_heartbeat[(*FileName)-48] = jiffies + (NewTimeout * HZ); + + // Start a new check + if (OldTimeout == 0) + { + DEBUG ( printk(OUR_NAME ": Start a new proc check %c\n", *FileName); ) + if (wdt_is_active++ == 0) + wdt_startup(); + } + } + +// Stop an existing check +if (NewTimeout == 0 && OldTimeout != 0) + { + DEBUG ( printk(OUR_NAME ": Stop an existing proc check %c\n", *FileName); ) + if (wdt_is_active-- == 1) + wdt_turnoff(); + } + +proctimeout[(*FileName)-48] = NewTimeout; + +return Length; +} + + +int wdt_proc_permission(struct inode *inode, int op) +{ +/* We allow everybody to read from our files, */ +/* but only root (uid 0) may write to them in the out files */ +if (op == 4 || (op == 2 && current->euid == 0 && (inode->i_mode & S_IWUSR) != 0)) + return 0; + +/* If it's anything else, access is denied */ +return -EACCES; +} + + +/* File operations for our proc files */ +static struct file_operations WDT_FileOps_Proc_Status = + { + NULL, status_output, NULL, + NULL, NULL, NULL, NULL, + wdt_proc_open, NULL, wdt_wdt_proc_close, + }; + +static struct file_operations WDT_FileOps_Proc_Files = + { + NULL, proc_output, proc_input, + NULL, NULL, NULL, NULL, + wdt_proc_open, NULL, wdt_wdt_proc_close, + }; + + +/* Inode operations for our proc files */ +static struct inode_operations WDT_Inode_Proc_Status = + { + &WDT_FileOps_Proc_Status, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + wdt_proc_permission + }; + +static struct inode_operations WDT_Inode_Proc_Files = + { + &WDT_FileOps_Proc_Files, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + wdt_proc_permission + }; + + +/* Directory entries */ +static struct proc_dir_entry WDT_Proc_Dir = + { + 0, 8, "watchdog", S_IFDIR | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_Status = + { + 0, 6, "status", S_IFREG | S_IRUGO, + 1, 0, 0, 0, &WDT_Inode_Proc_Status, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File0 = + { + 0, 1, "0", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File1 = + { + 0, 1, "1", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File2 = + { + 0, 1, "2", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File3 = + { + 0, 1, "3", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File4 = + { + 0, 1, "4", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File5 = + { + 0, 1, "5", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File6 = + { + 0, 1, "6", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File7 = + { + 0, 1, "7", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File8 = + { + 0, 1, "8", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +static struct proc_dir_entry WDT_Proc_File9 = + { + 0, 1, "9", S_IFREG | S_IRUGO | S_IWUSR, + 1, 0, 0, 0, &WDT_Inode_Proc_Files, NULL, NULL, NULL, NULL, NULL + }; + +#endif + + + +/*** Notifier for system down ************************************************/ + + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ +if (code == SYS_DOWN || code == SYS_HALT) + wdt_turnoff(); + +return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier = { wdt_notify_sys, 0, 0 }; + + + +/*** Module routines *********************************************************/ + + +#ifdef MODULE + +#define wafer582xwdt_init init_module + +void cleanup_module(void) +{ +wdt_turnoff(); + +unregister_reboot_notifier(&wdt_notifier); + +#ifdef CONFIG_582X_WDT_USE_PROC +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File9.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File8.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File7.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File6.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File5.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File4.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File3.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File2.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File1.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_File0.low_ino); +proc_unregister(&WDT_Proc_Dir, WDT_Proc_Status.low_ino); +proc_unregister(&proc_root, WDT_Proc_Dir.low_ino); +#endif + +misc_deregister(&wdt_miscdev); + +release_region(WDT_STOP,1); +release_region(WDT_START,1); +} + +#endif + + +#if defined(__init) +int __init wafer582xwdt_init(void) +#elif defined(__initfunc) +__initfunc(int wafer582xwdt_init(void)) +#else +int wafer582xwdt_init(void) +#endif +{ +printk(OUR_NAME ": WDT driver for WAFER 582x single board computer initialising\n"); +printk(OUR_NAME ": WDT timeout: %ds - Module ping: %ds - /dev/watchdog timeout: %ds\n", timeout, ping, devtimeout); + + +request_region(WDT_STOP, 1, "WAFER 582x WDT"); +request_region(WDT_START, 1, "WAFER 582x WDT"); + +misc_register(&wdt_miscdev); + +#ifdef CONFIG_582X_WDT_USE_PROC +proc_register(&proc_root, &WDT_Proc_Dir); +proc_register(&WDT_Proc_Dir, &WDT_Proc_Status); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File0); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File1); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File2); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File3); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File4); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File5); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File6); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File7); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File8); +proc_register(&WDT_Proc_Dir, &WDT_Proc_File9); +#endif + +register_reboot_notifier(&wdt_notifier); + +return 0; +} +