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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [watchdog/] [wafer5823wdt.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *      ICP Wafer 5823 Single Board Computer WDT driver
3
 *      http://www.icpamerica.com/wafer_5823.php
4
 *      May also work on other similar models
5
 *
6
 *      (c) Copyright 2002 Justin Cormack <justin@street-vision.com>
7
 *
8
 *      Release 0.02
9
 *
10
 *      Based on advantechwdt.c which is based on wdt.c.
11
 *      Original copyright messages:
12
 *
13
 *      (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
14
 *                              http://www.redhat.com
15
 *
16
 *      This program is free software; you can redistribute it and/or
17
 *      modify it under the terms of the GNU General Public License
18
 *      as published by the Free Software Foundation; either version
19
 *      2 of the License, or (at your option) any later version.
20
 *
21
 *      Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
22
 *      warranty for any of this software. This material is provided
23
 *      "AS-IS" and at no charge.
24
 *
25
 *      (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
26
 *
27
 */
28
 
29
#include <linux/module.h>
30
#include <linux/moduleparam.h>
31
#include <linux/miscdevice.h>
32
#include <linux/watchdog.h>
33
#include <linux/fs.h>
34
#include <linux/ioport.h>
35
#include <linux/notifier.h>
36
#include <linux/reboot.h>
37
#include <linux/init.h>
38
#include <linux/spinlock.h>
39
#include <asm/io.h>
40
#include <asm/uaccess.h>
41
 
42
#define WATCHDOG_NAME "Wafer 5823 WDT"
43
#define PFX WATCHDOG_NAME ": "
44
#define WD_TIMO 60                      /* 60 sec default timeout */
45
 
46
static unsigned long wafwdt_is_open;
47
static char expect_close;
48
static DEFINE_SPINLOCK(wafwdt_lock);
49
 
50
/*
51
 *      You must set these - there is no sane way to probe for this board.
52
 *
53
 *      To enable, write the timeout value in seconds (1 to 255) to I/O
54
 *      port WDT_START, then read the port to start the watchdog. To pat
55
 *      the dog, read port WDT_STOP to stop the timer, then read WDT_START
56
 *      to restart it again.
57
 */
58
 
59
static int wdt_stop = 0x843;
60
static int wdt_start = 0x443;
61
 
62
static int timeout = WD_TIMO;  /* in seconds */
63
module_param(timeout, int, 0);
64
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WD_TIMO) ".");
65
 
66
static int nowayout = WATCHDOG_NOWAYOUT;
67
module_param(nowayout, int, 0);
68
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
69
 
70
static void wafwdt_ping(void)
71
{
72
        /* pat watchdog */
73
        spin_lock(&wafwdt_lock);
74
        inb_p(wdt_stop);
75
        inb_p(wdt_start);
76
        spin_unlock(&wafwdt_lock);
77
}
78
 
79
static void wafwdt_start(void)
80
{
81
        /* start up watchdog */
82
        outb_p(timeout, wdt_start);
83
        inb_p(wdt_start);
84
}
85
 
86
static void
87
wafwdt_stop(void)
88
{
89
        /* stop watchdog */
90
        inb_p(wdt_stop);
91
}
92
 
93
static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
94
{
95
        /* See if we got the magic character 'V' and reload the timer */
96
        if (count) {
97
                if (!nowayout) {
98
                        size_t i;
99
 
100
                        /* In case it was set long ago */
101
                        expect_close = 0;
102
 
103
                        /* scan to see whether or not we got the magic character */
104
                        for (i = 0; i != count; i++) {
105
                                char c;
106
                                if (get_user(c, buf + i))
107
                                        return -EFAULT;
108
                                if (c == 'V')
109
                                        expect_close = 42;
110
                        }
111
                }
112
                /* Well, anyhow someone wrote to us, we should return that favour */
113
                wafwdt_ping();
114
        }
115
        return count;
116
}
117
 
118
static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
119
             unsigned long arg)
120
{
121
        int new_timeout;
122
        void __user *argp = (void __user *)arg;
123
        int __user *p = argp;
124
        static struct watchdog_info ident = {
125
                .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
126
                .firmware_version = 1,
127
                .identity = "Wafer 5823 WDT",
128
        };
129
 
130
        switch (cmd) {
131
        case WDIOC_GETSUPPORT:
132
                if (copy_to_user(argp, &ident, sizeof (ident)))
133
                        return -EFAULT;
134
                break;
135
 
136
        case WDIOC_GETSTATUS:
137
        case WDIOC_GETBOOTSTATUS:
138
                return put_user(0, p);
139
 
140
        case WDIOC_KEEPALIVE:
141
                wafwdt_ping();
142
                break;
143
 
144
        case WDIOC_SETTIMEOUT:
145
                if (get_user(new_timeout, p))
146
                        return -EFAULT;
147
                if ((new_timeout < 1) || (new_timeout > 255))
148
                        return -EINVAL;
149
                timeout = new_timeout;
150
                wafwdt_stop();
151
                wafwdt_start();
152
                /* Fall */
153
        case WDIOC_GETTIMEOUT:
154
                return put_user(timeout, p);
155
 
156
        case WDIOC_SETOPTIONS:
157
        {
158
                int options, retval = -EINVAL;
159
 
160
                if (get_user(options, p))
161
                        return -EFAULT;
162
 
163
                if (options & WDIOS_DISABLECARD) {
164
                        wafwdt_start();
165
                        retval = 0;
166
                }
167
 
168
                if (options & WDIOS_ENABLECARD) {
169
                        wafwdt_stop();
170
                        retval = 0;
171
                }
172
 
173
                return retval;
174
        }
175
 
176
        default:
177
                return -ENOTTY;
178
        }
179
        return 0;
180
}
181
 
182
static int wafwdt_open(struct inode *inode, struct file *file)
183
{
184
        if (test_and_set_bit(0, &wafwdt_is_open))
185
                return -EBUSY;
186
 
187
        /*
188
         *      Activate
189
         */
190
        wafwdt_start();
191
        return nonseekable_open(inode, file);
192
}
193
 
194
static int
195
wafwdt_close(struct inode *inode, struct file *file)
196
{
197
        if (expect_close == 42) {
198
                wafwdt_stop();
199
        } else {
200
                printk(KERN_CRIT PFX "WDT device closed unexpectedly.  WDT will not stop!\n");
201
                wafwdt_ping();
202
        }
203
        clear_bit(0, &wafwdt_is_open);
204
        expect_close = 0;
205
        return 0;
206
}
207
 
208
/*
209
 *      Notifier for system down
210
 */
211
 
212
static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
213
{
214
        if (code == SYS_DOWN || code == SYS_HALT) {
215
                /* Turn the WDT off */
216
                wafwdt_stop();
217
        }
218
        return NOTIFY_DONE;
219
}
220
 
221
/*
222
 *      Kernel Interfaces
223
 */
224
 
225
static const struct file_operations wafwdt_fops = {
226
        .owner          = THIS_MODULE,
227
        .llseek         = no_llseek,
228
        .write          = wafwdt_write,
229
        .ioctl          = wafwdt_ioctl,
230
        .open           = wafwdt_open,
231
        .release        = wafwdt_close,
232
};
233
 
234
static struct miscdevice wafwdt_miscdev = {
235
        .minor  = WATCHDOG_MINOR,
236
        .name   = "watchdog",
237
        .fops   = &wafwdt_fops,
238
};
239
 
240
/*
241
 *      The WDT needs to learn about soft shutdowns in order to
242
 *      turn the timebomb registers off.
243
 */
244
 
245
static struct notifier_block wafwdt_notifier = {
246
        .notifier_call = wafwdt_notify_sys,
247
};
248
 
249
static int __init wafwdt_init(void)
250
{
251
        int ret;
252
 
253
        printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n");
254
 
255
        if (timeout < 1 || timeout > 255) {
256
                timeout = WD_TIMO;
257
                printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n",
258
                        timeout);
259
        }
260
 
261
        if (wdt_stop != wdt_start) {
262
                if(!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
263
                        printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
264
                        wdt_stop);
265
                        ret = -EIO;
266
                        goto error;
267
                }
268
        }
269
 
270
        if(!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
271
                printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
272
                        wdt_start);
273
                ret = -EIO;
274
                goto error2;
275
        }
276
 
277
        ret = register_reboot_notifier(&wafwdt_notifier);
278
        if (ret != 0) {
279
                printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
280
                        ret);
281
                goto error3;
282
        }
283
 
284
        ret = misc_register(&wafwdt_miscdev);
285
        if (ret != 0) {
286
                printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
287
                        WATCHDOG_MINOR, ret);
288
                goto error4;
289
        }
290
 
291
        printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
292
                timeout, nowayout);
293
 
294
        return ret;
295
error4:
296
        unregister_reboot_notifier(&wafwdt_notifier);
297
error3:
298
        release_region(wdt_start, 1);
299
error2:
300
        if (wdt_stop != wdt_start)
301
                release_region(wdt_stop, 1);
302
error:
303
        return ret;
304
}
305
 
306
static void __exit wafwdt_exit(void)
307
{
308
        misc_deregister(&wafwdt_miscdev);
309
        unregister_reboot_notifier(&wafwdt_notifier);
310
        if(wdt_stop != wdt_start)
311
                release_region(wdt_stop, 1);
312
        release_region(wdt_start, 1);
313
}
314
 
315
module_init(wafwdt_init);
316
module_exit(wafwdt_exit);
317
 
318
MODULE_AUTHOR("Justin Cormack");
319
MODULE_DESCRIPTION("ICP Wafer 5823 Single Board Computer WDT driver");
320
MODULE_LICENSE("GPL");
321
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
322
 
323
/* end of wafer5823wdt.c */

powered by: WebSVN 2.1.0

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