pc87413_wdt.c

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

C
634
字号
/* *      NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x * *      This code is based on wdt.c with original copyright. * *      (C) Copyright 2006 Sven Anders, <anders@anduras.de> *                     and Marcus Junker, <junker@anduras.de> * *      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 Sven Anders, Marcus Junker nor ANDURAS AG *      admit liability nor provide warranty for any of this software. *      This material is provided "AS-IS" and at no charge. * *      Release 1.1 */#include <linux/module.h>#include <linux/types.h>#include <linux/miscdevice.h>#include <linux/watchdog.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/notifier.h>#include <linux/fs.h>#include <linux/reboot.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/moduleparam.h>#include <linux/version.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>/* #define DEBUG 1 */#define DEFAULT_TIMEOUT     1            /* 1 minute */#define MAX_TIMEOUT         255#define VERSION             "1.1"#define MODNAME             "pc87413 WDT"#define PFX                 MODNAME ": "#define DPFX                MODNAME " - DEBUG: "#define WDT_INDEX_IO_PORT   (io+0)       /* I/O port base (index register) */#define WDT_DATA_IO_PORT    (WDT_INDEX_IO_PORT+1)#define SWC_LDN             0x04#define SIOCFG2             0x22         /* Serial IO register */#define WDCTL               0x10         /* Watchdog-Timer-Controll-Register */#define WDTO                0x11         /* Watchdog timeout register */#define WDCFG               0x12         /* Watchdog config register */static int io = 0x2E;		         /* Address used on Portwell Boards */static int timeout = DEFAULT_TIMEOUT;    /* timeout value */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 ----------------------------------------*//* Select pins for Watchdog output */static inline void pc87413_select_wdt_out (void){	unsigned int cr_data = 0;	/* Step 1: Select multiple pin,pin55,as WDT output */	outb_p(SIOCFG2, WDT_INDEX_IO_PORT);	cr_data = inb (WDT_DATA_IO_PORT);	cr_data |= 0x80; /* Set Bit7 to 1*/	outb_p(SIOCFG2, WDT_INDEX_IO_PORT);	outb_p(cr_data, WDT_DATA_IO_PORT);#ifdef DEBUG	printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:"	                      " Bit7 to 1: %d\n", cr_data);#endif}/* Enable SWC functions */static inline void pc87413_enable_swc(void){	unsigned int cr_data=0;	/* Step 2: Enable SWC functions */	outb_p(0x07, WDT_INDEX_IO_PORT);        /* Point SWC_LDN (LDN=4) */	outb_p(SWC_LDN, WDT_DATA_IO_PORT);	outb_p(0x30, WDT_INDEX_IO_PORT);        /* Read Index 0x30 First */	cr_data = inb(WDT_DATA_IO_PORT);	cr_data |= 0x01;                        /* Set Bit0 to 1 */	outb_p(0x30, WDT_INDEX_IO_PORT);	outb_p(cr_data, WDT_DATA_IO_PORT);      /* Index0x30_bit0P1 */#ifdef DEBUG	printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n");#endif}/* Read SWC I/O base address */static inline unsigned int pc87413_get_swc_base(void){	unsigned int  swc_base_addr = 0;	unsigned char addr_l, addr_h = 0;	/* Step 3: Read SWC I/O Base Address */	outb_p(0x60, WDT_INDEX_IO_PORT);        /* Read Index 0x60 */	addr_h = inb(WDT_DATA_IO_PORT);	outb_p(0x61, WDT_INDEX_IO_PORT);        /* Read Index 0x61 */	addr_l = inb(WDT_DATA_IO_PORT);	swc_base_addr = (addr_h << 8) + addr_l;#ifdef DEBUG	printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d,"	                      " res %d\n", addr_l, addr_h, swc_base_addr);#endif	return swc_base_addr;}/* Select Bank 3 of SWC */static inline void pc87413_swc_bank3(unsigned int swc_base_addr){	/* Step 4: Select Bank3 of SWC */	outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);#ifdef DEBUG	printk(KERN_INFO DPFX "Select Bank3 of SWC\n");#endif}/* Set watchdog timeout to x minutes */static inline void pc87413_programm_wdto(unsigned int swc_base_addr,					 char pc87413_time){	/* Step 5: Programm WDTO, Twd. */	outb_p(pc87413_time, swc_base_addr + WDTO);#ifdef DEBUG	printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time);#endif}/* Enable WDEN */static inline void pc87413_enable_wden(unsigned int swc_base_addr){	/* Step 6: Enable WDEN */	outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);#ifdef DEBUG	printk(KERN_INFO DPFX "Enable WDEN\n");#endif}/* Enable SW_WD_TREN */static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr){	/* Enable SW_WD_TREN */	outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);#ifdef DEBUG	printk(KERN_INFO DPFX "Enable SW_WD_TREN\n");#endif}/* Disable SW_WD_TREN */static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr){	/* Disable SW_WD_TREN */	outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);#ifdef DEBUG	printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n");#endif}/* Enable SW_WD_TRG */static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr){	/* Enable SW_WD_TRG */	outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);#ifdef DEBUG	printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n");#endif}/* Disable SW_WD_TRG */static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr){	/* Disable SW_WD_TRG */	outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);#ifdef DEBUG	printk(KERN_INFO DPFX "Disable SW_WD_TRG\n");#endif}/* -- Higher level functions ------------------------------------*//* Enable the watchdog */static void pc87413_enable(void){	unsigned int swc_base_addr;	spin_lock(&io_lock);	pc87413_select_wdt_out();	pc87413_enable_swc();	swc_base_addr = pc87413_get_swc_base();	pc87413_swc_bank3(swc_base_addr);	pc87413_programm_wdto(swc_base_addr, timeout);	pc87413_enable_wden(swc_base_addr);	pc87413_enable_sw_wd_tren(swc_base_addr);	pc87413_enable_sw_wd_trg(swc_base_addr);	spin_unlock(&io_lock);}/* Disable the watchdog */static void pc87413_disable(void){	unsigned int swc_base_addr;	spin_lock(&io_lock);	pc87413_select_wdt_out();	pc87413_enable_swc();	swc_base_addr = pc87413_get_swc_base();	pc87413_swc_bank3(swc_base_addr);	pc87413_disable_sw_wd_tren(swc_base_addr);	pc87413_disable_sw_wd_trg(swc_base_addr);	pc87413_programm_wdto(swc_base_addr, 0);	spin_unlock(&io_lock);}/* Refresh the watchdog */static void pc87413_refresh(void){	unsigned int swc_base_addr;	spin_lock(&io_lock);	pc87413_select_wdt_out();	pc87413_enable_swc();	swc_base_addr = pc87413_get_swc_base();	pc87413_swc_bank3(swc_base_addr);	pc87413_disable_sw_wd_tren(swc_base_addr);	pc87413_disable_sw_wd_trg(swc_base_addr);	pc87413_programm_wdto(swc_base_addr, timeout);	pc87413_enable_wden(swc_base_addr);	pc87413_enable_sw_wd_tren(swc_base_addr);	pc87413_enable_sw_wd_trg(swc_base_addr);	spin_unlock(&io_lock);}/* -- File operations -------------------------------------------*//** *	pc87413_open: *	@inode: inode of device *	@file: file handle to device * */static int pc87413_open(struct inode *inode, struct file *file){	/* /dev/watchdog can only be opened once */	if (test_and_set_bit(0, &timer_enabled))		return -EBUSY;	if (nowayout)		__module_get(THIS_MODULE);	/* Reload and activate timer */	pc87413_refresh();	printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to"

⌨️ 快捷键说明

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