linux/drivers/watchdog/sbc_fitpc2_wdt.c
<<
>>
Prefs
   1/*
   2 * Watchdog driver for SBC-FITPC2 board
   3 *
   4 * Author: Denis Turischev <denis@compulab.co.il>
   5 *
   6 * Adapted from the IXP2000 watchdog driver by Deepak Saxena.
   7 *
   8 * This file is licensed under  the terms of the GNU General Public
   9 * License version 2. This program is licensed "as is" without any
  10 * warranty of any kind, whether express or implied.
  11 */
  12
  13#define pr_fmt(fmt) KBUILD_MODNAME " WATCHDOG: " fmt
  14
  15#include <linux/module.h>
  16#include <linux/types.h>
  17#include <linux/miscdevice.h>
  18#include <linux/watchdog.h>
  19#include <linux/ioport.h>
  20#include <linux/delay.h>
  21#include <linux/fs.h>
  22#include <linux/init.h>
  23#include <linux/moduleparam.h>
  24#include <linux/dmi.h>
  25#include <linux/io.h>
  26#include <linux/uaccess.h>
  27
  28
  29static bool nowayout = WATCHDOG_NOWAYOUT;
  30static unsigned int margin = 60;        /* (secs) Default is 1 minute */
  31static unsigned long wdt_status;
  32static DEFINE_MUTEX(wdt_lock);
  33
  34#define WDT_IN_USE              0
  35#define WDT_OK_TO_CLOSE         1
  36
  37#define COMMAND_PORT            0x4c
  38#define DATA_PORT               0x48
  39
  40#define IFACE_ON_COMMAND        1
  41#define REBOOT_COMMAND          2
  42
  43#define WATCHDOG_NAME           "SBC-FITPC2 Watchdog"
  44
  45static void wdt_send_data(unsigned char command, unsigned char data)
  46{
  47        outb(data, DATA_PORT);
  48        msleep(200);
  49        outb(command, COMMAND_PORT);
  50        msleep(100);
  51}
  52
  53static void wdt_enable(void)
  54{
  55        mutex_lock(&wdt_lock);
  56        wdt_send_data(IFACE_ON_COMMAND, 1);
  57        wdt_send_data(REBOOT_COMMAND, margin);
  58        mutex_unlock(&wdt_lock);
  59}
  60
  61static void wdt_disable(void)
  62{
  63        mutex_lock(&wdt_lock);
  64        wdt_send_data(IFACE_ON_COMMAND, 0);
  65        wdt_send_data(REBOOT_COMMAND, 0);
  66        mutex_unlock(&wdt_lock);
  67}
  68
  69static int fitpc2_wdt_open(struct inode *inode, struct file *file)
  70{
  71        if (test_and_set_bit(WDT_IN_USE, &wdt_status))
  72                return -EBUSY;
  73
  74        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  75
  76        wdt_enable();
  77
  78        return nonseekable_open(inode, file);
  79}
  80
  81static ssize_t fitpc2_wdt_write(struct file *file, const char *data,
  82                                                size_t len, loff_t *ppos)
  83{
  84        size_t i;
  85
  86        if (!len)
  87                return 0;
  88
  89        if (nowayout) {
  90                len = 0;
  91                goto out;
  92        }
  93
  94        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  95
  96        for (i = 0; i != len; i++) {
  97                char c;
  98
  99                if (get_user(c, data + i))
 100                        return -EFAULT;
 101
 102                if (c == 'V')
 103                        set_bit(WDT_OK_TO_CLOSE, &wdt_status);
 104        }
 105
 106out:
 107        wdt_enable();
 108
 109        return len;
 110}
 111
 112
 113static const struct watchdog_info ident = {
 114        .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
 115                                WDIOF_KEEPALIVEPING,
 116        .identity       = WATCHDOG_NAME,
 117};
 118
 119
 120static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd,
 121                                                        unsigned long arg)
 122{
 123        int ret = -ENOTTY;
 124        int time;
 125
 126        switch (cmd) {
 127        case WDIOC_GETSUPPORT:
 128                ret = copy_to_user((struct watchdog_info *)arg, &ident,
 129                                   sizeof(ident)) ? -EFAULT : 0;
 130                break;
 131
 132        case WDIOC_GETSTATUS:
 133                ret = put_user(0, (int *)arg);
 134                break;
 135
 136        case WDIOC_GETBOOTSTATUS:
 137                ret = put_user(0, (int *)arg);
 138                break;
 139
 140        case WDIOC_KEEPALIVE:
 141                wdt_enable();
 142                ret = 0;
 143                break;
 144
 145        case WDIOC_SETTIMEOUT:
 146                ret = get_user(time, (int *)arg);
 147                if (ret)
 148                        break;
 149
 150                if (time < 31 || time > 255) {
 151                        ret = -EINVAL;
 152                        break;
 153                }
 154
 155                margin = time;
 156                wdt_enable();
 157                /* Fall through */
 158
 159        case WDIOC_GETTIMEOUT:
 160                ret = put_user(margin, (int *)arg);
 161                break;
 162        }
 163
 164        return ret;
 165}
 166
 167static int fitpc2_wdt_release(struct inode *inode, struct file *file)
 168{
 169        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
 170                wdt_disable();
 171                pr_info("Device disabled\n");
 172        } else {
 173                pr_warn("Device closed unexpectedly - timer will not stop\n");
 174                wdt_enable();
 175        }
 176
 177        clear_bit(WDT_IN_USE, &wdt_status);
 178        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 179
 180        return 0;
 181}
 182
 183
 184static const struct file_operations fitpc2_wdt_fops = {
 185        .owner          = THIS_MODULE,
 186        .llseek         = no_llseek,
 187        .write          = fitpc2_wdt_write,
 188        .unlocked_ioctl = fitpc2_wdt_ioctl,
 189        .open           = fitpc2_wdt_open,
 190        .i2471class="line" name="L187" class="line" n57" class="line" n180en" class="sref">len1 = 0;1out1;19ref="drivers/watchdog/sbc_fitpc2_wdt.c#L182" id="L1ss="line"1 name="L92">  92    1    }19ref="driversdog/sbc_fitpc2_wdt.c#L"L17">  17>ret =   17/a>static const struct  "+code=release" class="srerL17"> f">file_operations   91319ref="drivers/watchdog/sbc_fitminowdt.c#L185" id="minow class="line" name="L187"> 187wdt_status<1/a>);19ref="drivers/watchdog/sbc_fitstat . 173         7" classn(  91519ref="drivers/watchdog/sbc_fit"+code=file_operatiosref">fiass="line" nf">clear_bit(fss="line" name="L187" class="line" n57" class="l_llseek" de=i" class="sref">i1++) {19ref="drivers/watchdog/sbc_fitpc2_wdt.c#L117" id="L117 c1;1  91819a href="drivers/watchdog/sbc_fi__ namde=file_operati__ nam/a>static const struct   61static void iEFAULT;
 164        return  101<2a>
 164        return 'V')
wdt_status 187 DMI_BOARD.WDT_OK_TO_CLOSE, & 104      2 }
 105<2a>
 brd_stat .(  61static void out:
 164        return wdt_enable2);
 108<2a>
 171         %s foun="+code=pr_info"ref="+code=get_usbrd_stat .WDT_OK_TO_CLOSE, &len;
 110}
 s="sref">outb(WDT_OK_TO_CLOSE, & 111<2a>
 171         I/O address 0x%04x alreadyerr use"+code=pr_info"ref="+code=get_uss="sref">outb(command,  112<2a>
 164        return ident 2 {
WDIOF_SETTIMEOUTWDIOF_KEEPALIVEPING,
 " class="sref">outb(WDT_OK_TO_CLOSE, &WATCHDOG_NAME,
 171         I/O address 0x%04x alreadyerr use"+code=pr_info"ref="+code=get_us" class="sref">outb(data,  117 151  O                IOlass="line" name="L164"> 164        return  118<2a>
 164        return  119<2a>
cmd,
arg)
 150      mc#L155" id="L155" class="line" ntime" class="sref">time < 31 ||  122{
 171         ass="l mu"+cbeerr range="L1-e" c seef=ds, you time < 31 || ENOTTY;
(REBOOT_COMMAND, time;
 151                        ret = - 125<2a>
(ret = -cmd2 {
WDIOC_GETSUPPORT:
ident,
clear_bit( "+code=release" class="srerL17"> f">fND" class="sref">REBOOT_COMMAND, EFAULT :20;
time < 31 ||  120                bre2k;
 171         canef">regist_w rL17">  ol minow=%= (erw=%=)"+code=pr_info"rs="sref">time < 31 ||  131<2a>
 187REBOOT_COMMAND, WDIOC_GETSTATUS:
(ret = -arg 124                bre2k;
 135<2a>
WDIOC_GETBOOTSTATUS:
arg(        case  128                bre2k;
i247sregioa href="+code=opre>i247sregioa"line" name="L178"> " class="sref">outb(REBOOT_COMMAND,  139<2a>
        case WDIOC_KEEPALIVE:
i247sregioa href="+code=opre>i247sregioa"line" name="L178"> s="sref">outb(REBOOT_COMMAND, wdt_enable2);
ret =20;
 164        return  123                bre2k;
 144<2a>
WDIOC_SETTIMEOUT:
static const struct   61static void argtime < 31 || ret)
clear_bit( "+code=release" class="srerL17"> f">fND" class="sref">REBOOT_COMMAND, i247sregioa href="+code=opre>i247sregioa"line" name="L178"> " class="sref">outb(REBOOT_COMMAND,  149<2a>
i247sregioa href="+code=opre>i247sregioa"line" name="L178"> s="sref">outb(REBOOT_COMMAND, time > 2552 {
EINVAL;
 ct REBOOT_COMMAND,  12"> 153              2 }
 ct REBOOT_COMMAND,  154<2a>
time;
 171         Denis TurL17h>  namedenis@compulab.co.ilntimn("Device closed unexpectedly 2nable" cl2ss="sref">wdt_enable2);
 171         WATCHDOG_N W" classn("Device closed unexpectedly 2nef="+cod2">/* Fall through */
 158<2a>
 "sref">ret = wdt_send_data(WDIOC_GETTIMEOUT:
 "sref">ret =  171         W" class ass="l "l seef=ds (default 60s)n("Device closed unexpectedly 2ef="+code2arg" class="sref">arg 121                bre2k;
 pc2_wdt.c#L89" id="L89" class="lineref="+code=get_usboode=unlocked_ioctboodlinere>wdt_send_data( 162      2 }
 pc2_wdt.c#L89" id="L89" class="linerefe="L171"> 171         W" class canef">be>pr_wped once>prartedn("Device closed unexpectedly 2eL143"> 12"line" name="L163"> 163<2a>
ret;
 171         GPLn("Device closed unexpectedly 2e="+code=2line" name="L165"> 165}
 tity" claMINOR"Device closed unexpectedly 2eable" cl2"line" name="L166"> 166<2a>
file)



The ori="lal LXR software by thchdog/sbc_fhttp://sourceforge.net/projects/lxwd>LXR dt.cunass="li, this +codric#L1al tchdioa by dog/sbc_fmailto:lxw@"srux.no">lxw@"srux.no="li.
lxw."srux.no kinr_wahost_d by dog/sbc_fhttp://www.redpill-"srpro.no">Redpill Lsrpro AS="li, provider of Lsrux/ef="ulta> and o84"> 184< ser 17< since>1995.