OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [scx200_wdt.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* linux/drivers/char/scx200_wdt.c
2
 
3
   National Semiconductor SCx200 Watchdog support
4
 
5
   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
6
 
7
   Som code taken from:
8
   National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
9
   (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
10
 
11
   This program is free software; you can redistribute it and/or
12
   modify it under the terms of the GNU General Public License as
13
   published by the Free Software Foundation; either version 2 of the
14
   License, or (at your option) any later version.
15
 
16
   The author(s) of this software shall not be held liable for damages
17
   of any nature resulting due to the use of this software. This
18
   software is provided AS-IS with no warranties. */
19
 
20
#include <linux/config.h>
21
#include <linux/module.h>
22
#include <linux/errno.h>
23
#include <linux/kernel.h>
24
#include <linux/init.h>
25
#include <linux/miscdevice.h>
26
#include <linux/watchdog.h>
27
#include <linux/notifier.h>
28
#include <linux/reboot.h>
29
#include <linux/pci.h>
30
#include <asm/uaccess.h>
31
#include <asm/io.h>
32
 
33
#include <linux/scx200.h>
34
 
35
#define NAME "scx200_wdt"
36
 
37
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
38
MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
39
MODULE_LICENSE("GPL");
40
 
41
#ifndef CONFIG_WATCHDOG_NOWAYOUT
42
#define CONFIG_WATCHDOG_NOWAYOUT 0
43
#endif
44
 
45
static int margin = 60;         /* in seconds */
46
MODULE_PARM(margin, "i");
47
MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
48
 
49
static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
50
MODULE_PARM(nowayout, "i");
51
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
52
 
53
static u16 wdto_restart;
54
static struct semaphore open_semaphore;
55
static unsigned expect_close;
56
 
57
/* Bits of the WDCNFG register */
58
#define W_ENABLE 0x00fa         /* Enable watchdog */
59
#define W_DISABLE 0x0000        /* Disable watchdog */
60
 
61
/* The scaling factor for the timer, this depends on the value of W_ENABLE */
62
#define W_SCALE (32768/1024)
63
 
64
static void scx200_wdt_ping(void)
65
{
66
        outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO);
67
}
68
 
69
static void scx200_wdt_update_margin(void)
70
{
71
        printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
72
        wdto_restart = margin * W_SCALE;
73
}
74
 
75
static void scx200_wdt_enable(void)
76
{
77
        printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
78
               wdto_restart);
79
 
80
        outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
81
        outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
82
        outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
83
 
84
        scx200_wdt_ping();
85
}
86
 
87
static void scx200_wdt_disable(void)
88
{
89
        printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
90
 
91
        outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
92
        outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
93
        outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
94
}
95
 
96
static int scx200_wdt_open(struct inode *inode, struct file *file)
97
{
98
        /* only allow one at a time */
99
        if (down_trylock(&open_semaphore))
100
                return -EBUSY;
101
        scx200_wdt_enable();
102
        expect_close = 0;
103
 
104
        return 0;
105
}
106
 
107
static int scx200_wdt_release(struct inode *inode, struct file *file)
108
{
109
        if (!expect_close) {
110
                printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
111
        } else if (!nowayout) {
112
                scx200_wdt_disable();
113
        }
114
        up(&open_semaphore);
115
 
116
        return 0;
117
}
118
 
119
static int scx200_wdt_notify_sys(struct notifier_block *this,
120
                                      unsigned long code, void *unused)
121
{
122
        if (code == SYS_HALT || code == SYS_POWER_OFF)
123
                if (!nowayout)
124
                        scx200_wdt_disable();
125
 
126
        return NOTIFY_DONE;
127
}
128
 
129
static struct notifier_block scx200_wdt_notifier =
130
{
131
        notifier_call: scx200_wdt_notify_sys
132
};
133
 
134
static ssize_t scx200_wdt_write(struct file *file, const char *data,
135
                                     size_t len, loff_t *ppos)
136
{
137
        if (ppos != &file->f_pos)
138
                return -ESPIPE;
139
 
140
        /* check for a magic close character */
141
        if (len)
142
        {
143
                size_t i;
144
 
145
                scx200_wdt_ping();
146
 
147
                expect_close = 0;
148
                for (i = 0; i < len; ++i) {
149
                        char c;
150
                        if (get_user(c, data+i))
151
                                return -EFAULT;
152
                        if (c == 'V')
153
                                expect_close = 1;
154
                }
155
 
156
                return len;
157
        }
158
 
159
        return 0;
160
}
161
 
162
static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
163
        unsigned int cmd, unsigned long arg)
164
{
165
        static struct watchdog_info ident = {
166
                .identity = "NatSemi SCx200 Watchdog",
167
                .firmware_version = 1,
168
                .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
169
        };
170
        int new_margin;
171
 
172
        switch (cmd) {
173
        default:
174
                return -ENOTTY;
175
        case WDIOC_GETSUPPORT:
176
                if(copy_to_user((struct watchdog_info *)arg, &ident,
177
                                sizeof(ident)))
178
                        return -EFAULT;
179
                return 0;
180
        case WDIOC_GETSTATUS:
181
        case WDIOC_GETBOOTSTATUS:
182
                if (put_user(0, (int *)arg))
183
                        return -EFAULT;
184
                return 0;
185
        case WDIOC_KEEPALIVE:
186
                scx200_wdt_ping();
187
                return 0;
188
        case WDIOC_SETTIMEOUT:
189
                if (get_user(new_margin, (int *)arg))
190
                        return -EFAULT;
191
                if (new_margin < 1)
192
                        return -EINVAL;
193
                margin = new_margin;
194
                scx200_wdt_update_margin();
195
                scx200_wdt_ping();
196
        case WDIOC_GETTIMEOUT:
197
                if (put_user(margin, (int *)arg))
198
                        return -EFAULT;
199
                return 0;
200
        }
201
}
202
 
203
static struct file_operations scx200_wdt_fops = {
204
        .owner   = THIS_MODULE,
205
        .write   = scx200_wdt_write,
206
        .ioctl   = scx200_wdt_ioctl,
207
        .open    = scx200_wdt_open,
208
        .release = scx200_wdt_release,
209
};
210
 
211
static struct miscdevice scx200_wdt_miscdev = {
212
        .minor = WATCHDOG_MINOR,
213
        .name  = NAME,
214
        .fops  = &scx200_wdt_fops,
215
};
216
 
217
static int __init scx200_wdt_init(void)
218
{
219
        int r;
220
 
221
        printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
222
 
223
        /* First check that this really is a NatSemi SCx200 CPU */
224
        if ((pci_find_device(PCI_VENDOR_ID_NS,
225
                             PCI_DEVICE_ID_NS_SCx200_BRIDGE,
226
                             NULL)) == NULL)
227
                return -ENODEV;
228
 
229
        /* More sanity checks, verify that the configuration block is there */
230
        if (!scx200_cb_probe(SCx200_CB_BASE)) {
231
                printk(KERN_WARNING NAME ": no configuration block found\n");
232
                return -ENODEV;
233
        }
234
 
235
        if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
236
                            SCx200_WDT_SIZE,
237
                            "NatSemi SCx200 Watchdog")) {
238
                printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
239
                return -EBUSY;
240
        }
241
 
242
        scx200_wdt_update_margin();
243
        scx200_wdt_disable();
244
 
245
        sema_init(&open_semaphore, 1);
246
 
247
        r = misc_register(&scx200_wdt_miscdev);
248
        if (r)
249
                return r;
250
 
251
        r = register_reboot_notifier(&scx200_wdt_notifier);
252
        if (r) {
253
                printk(KERN_ERR NAME ": unable to register reboot notifier");
254
                misc_deregister(&scx200_wdt_miscdev);
255
                return r;
256
        }
257
 
258
        return 0;
259
}
260
 
261
static void __exit scx200_wdt_cleanup(void)
262
{
263
        unregister_reboot_notifier(&scx200_wdt_notifier);
264
        misc_deregister(&scx200_wdt_miscdev);
265
        release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
266
                       SCx200_WDT_SIZE);
267
}
268
 
269
module_init(scx200_wdt_init);
270
module_exit(scx200_wdt_cleanup);
271
 
272
/*
273
    Local variables:
274
        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
275
        c-basic-offset: 8
276
    End:
277
*/

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.