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 + -
显示快捷键?