smsc37b787_wdt.c

来自「linux 内核源代码」· C语言 代码 · 共 626 行 · 第 1/2 页

C
626
字号
/* *	SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x * *      Based on acquirewdt.c by Alan Cox <alan@redhat.com> *       and some other existing drivers * *	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 authors do 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. * *	(C) Copyright 2003-2006  Sven Anders <anders@anduras.de> * *  History: *	2003 - Created version 1.0 for Linux 2.4.x. *	2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE *             features. Released version 1.1 * *  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 /dev/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. * * Create device with: *  mknod /dev/watchdog c 10 130 * * For an example userspace keep-alive daemon, see: *   Documentation/watchdog/watchdog.txt */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/types.h>#include <linux/miscdevice.h>#include <linux/watchdog.h>#include <linux/delay.h>#include <linux/fs.h>#include <linux/ioport.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/init.h>#include <linux/spinlock.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>/* enable support for minutes as units? *//* (does not always work correctly, so disabled by default!) */#define SMSC_SUPPORT_MINUTES#undef SMSC_SUPPORT_MINUTES#define MAX_TIMEOUT     255#define UNIT_SECOND     0#define UNIT_MINUTE     1#define MODNAME		"smsc37b787_wdt: "#define VERSION         "1.1"#define IOPORT          0x3F0#define IOPORT_SIZE     2#define IODEV_NO        8static int unit = UNIT_SECOND;  /* timer's unit */static int timeout = 60;        /* timeout value: default is 60 "units" */static unsigned long timer_enabled = 0;   /* is the timer enabled? */static char expect_close;       /* is the close expected? */static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */static int nowayout = WATCHDOG_NOWAYOUT;/* -- Low level function ----------------------------------------*//* unlock the IO chip */static inline void open_io_config(void){        outb(0x55, IOPORT);	mdelay(1);        outb(0x55, IOPORT);}/* lock the IO chip */static inline void close_io_config(void){        outb(0xAA, IOPORT);}/* select the IO device */static inline void select_io_device(unsigned char devno){        outb(0x07, IOPORT);        outb(devno, IOPORT+1);}/* write to the control register */static inline void write_io_cr(unsigned char reg, unsigned char data){        outb(reg, IOPORT);        outb(data, IOPORT+1);}/* read from the control register */static inline char read_io_cr(unsigned char reg){        outb(reg, IOPORT);        return inb(IOPORT+1);}/* -- Medium level functions ------------------------------------*/static inline void gpio_bit12(unsigned char reg){	// -- General Purpose I/O Bit 1.2 --	// Bit 0,   In/Out: 0 = Output, 1 = Input	// Bit 1,   Polarity: 0 = No Invert, 1 = Invert	// Bit 2,   Group Enable Intr.: 0 = Disable, 1 = Enable	// Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,	//                           11 = Either Edge Triggered Intr. 2        // Bit 5/6  (Reserved)	// Bit 7,   Output Type: 0 = Push Pull Bit, 1 = Open Drain        write_io_cr(0xE2, reg);}static inline void gpio_bit13(unsigned char reg){	// -- General Purpose I/O Bit 1.3 --	// Bit 0,  In/Out: 0 = Output, 1 = Input	// Bit 1,  Polarity: 0 = No Invert, 1 = Invert	// Bit 2,  Group Enable Intr.: 0 = Disable, 1 = Enable	// Bit 3,  Function select: 0 = GPI/O, 1 = LED        // Bit 4-6 (Reserved)	// Bit 7,  Output Type: 0 = Push Pull Bit, 1 = Open Drain        write_io_cr(0xE3, reg);}static inline void wdt_timer_units(unsigned char new_units){	// -- Watchdog timer units --	// Bit 0-6 (Reserved)	// Bit 7,  WDT Time-out Value Units Select	//         (0 = Minutes, 1 = Seconds)        write_io_cr(0xF1, new_units);}static inline void wdt_timeout_value(unsigned char new_timeout){	// -- Watchdog Timer Time-out Value --	// Bit 0-7 Binary coded units (0=Disabled, 1..255)        write_io_cr(0xF2, new_timeout);}static inline void wdt_timer_conf(unsigned char conf){	// -- Watchdog timer configuration --	// Bit 0   Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O	// Bit 1   Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.	// Bit 2   Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr.        // Bit 3   Reset the timer        //         (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled)	// Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled,	//            0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15)        write_io_cr(0xF3, conf);}static inline void wdt_timer_ctrl(unsigned char reg){	// -- Watchdog timer control --	// Bit 0   Status Bit: 0 = Timer counting, 1 = Timeout occured	// Bit 1   Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz	// Bit 2   Force Timeout: 1 = Forces WD timeout event (self-cleaning)	// Bit 3   P20 Force Timeout enabled:	//          0 = P20 activity does not generate the WD timeout event	//          1 = P20 Allows rising edge of P20, from the keyboard	//              controller, to force the WD timeout event.	// Bit 4   (Reserved)	// -- Soft power management --	// Bit 5   Stop Counter: 1 = Stop software power down counter	//            set via register 0xB8, (self-cleaning)	//            (Upon read: 0 = Counter running, 1 = Counter stopped)	// Bit 6   Restart Counter: 1 = Restart software power down counter	//            set via register 0xB8, (self-cleaning)	// Bit 7   SPOFF: 1 = Force software power down (self-cleaning)        write_io_cr(0xF4, reg);}/* -- Higher level functions ------------------------------------*//* initialize watchdog */static void wb_smsc_wdt_initialize(void){        unsigned char old;	spin_lock(&io_lock);        open_io_config();        select_io_device(IODEV_NO);	// enable the watchdog	gpio_bit13(0x08);  // Select pin 80 = LED not GPIO	gpio_bit12(0x0A);  // Set pin 79 = WDT not GPIO/Output/Polarity=Invert	// disable the timeout        wdt_timeout_value(0);	// reset control register        wdt_timer_ctrl(0x00);	// reset configuration register	wdt_timer_conf(0x00);	// read old (timer units) register        old = read_io_cr(0xF1) & 0x7F;        if (unit == UNIT_SECOND) old |= 0x80; // set to seconds	// set the watchdog timer units        wdt_timer_units(old);        close_io_config();	spin_unlock(&io_lock);}/* shutdown the watchdog */static void wb_smsc_wdt_shutdown(void){	spin_lock(&io_lock);        open_io_config();        select_io_device(IODEV_NO);	// disable the watchdog        gpio_bit13(0x09);        gpio_bit12(0x09);	// reset watchdog config register	wdt_timer_conf(0x00);	// reset watchdog control register        wdt_timer_ctrl(0x00);	// disable timeout        wdt_timeout_value(0x00);        close_io_config();	spin_unlock(&io_lock);}/* set timeout => enable watchdog */static void wb_smsc_wdt_set_timeout(unsigned char new_timeout){	spin_lock(&io_lock);        open_io_config();        select_io_device(IODEV_NO);	// set Power LED to blink, if we enable the timeout        wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);	// set timeout value        wdt_timeout_value(new_timeout);        close_io_config();	spin_unlock(&io_lock);}/* get timeout */static unsigned char wb_smsc_wdt_get_timeout(void){        unsigned char set_timeout;	spin_lock(&io_lock);        open_io_config();        select_io_device(IODEV_NO);        set_timeout = read_io_cr(0xF2);        close_io_config();	spin_unlock(&io_lock);        return set_timeout;}/* disable watchdog */static void wb_smsc_wdt_disable(void){        // set the timeout to 0 to disable the watchdog        wb_smsc_wdt_set_timeout(0);}/* enable watchdog by setting the current timeout */static void wb_smsc_wdt_enable(void){        // set the current timeout...

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?