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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      IB700 Single Board Computer WDT driver for Linux 2.4.x
3
 *
4
 *      (c) Copyright 2001 Charles Howes <chowes@vsol.net>
5
 *
6
 *      Based on advantechwdt.c which is based on acquirewdt.c which
7
 *       is based on wdt.c.
8
 *
9
 *      (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
10
 *
11
 *      Based on acquirewdt.c which is based on wdt.c.
12
 *      Original copyright messages:
13
 *
14
 *      (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
15
 *                              http://www.redhat.com
16
 *
17
 *      This program is free software; you can redistribute it and/or
18
 *      modify it under the terms of the GNU General Public License
19
 *      as published by the Free Software Foundation; either version
20
 *      2 of the License, or (at your option) any later version.
21
 *
22
 *      Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
23
 *      warranty for any of this software. This material is provided
24
 *      "AS-IS" and at no charge.
25
 *
26
 *      (c) Copyright 1995    Alan Cox <alan@redhat.com>
27
 *
28
 */
29
 
30
#include <linux/config.h>
31
#include <linux/module.h>
32
#include <linux/version.h>
33
#include <linux/types.h>
34
#include <linux/errno.h>
35
#include <linux/kernel.h>
36
#include <linux/sched.h>
37
#include <linux/miscdevice.h>
38
#include <linux/watchdog.h>
39
#include <linux/slab.h>
40
#include <linux/ioport.h>
41
#include <linux/fcntl.h>
42
#include <asm/io.h>
43
#include <asm/uaccess.h>
44
#include <asm/system.h>
45
#include <linux/notifier.h>
46
#include <linux/reboot.h>
47
#include <linux/init.h>
48
#include <linux/spinlock.h>
49
#include <linux/smp_lock.h>
50
 
51
static int ibwdt_is_open;
52
static spinlock_t ibwdt_lock;
53
static int expect_close = 0;
54
 
55
/*
56
 *
57
 * Watchdog Timer Configuration
58
 *
59
 * The function of the watchdog timer is to reset the system
60
 * automatically and is defined at I/O port 0443H.  To enable the
61
 * watchdog timer and allow the system to reset, write I/O port 0443H.
62
 * To disable the timer, write I/O port 0441H for the system to stop the
63
 * watchdog function.  The timer has a tolerance of 20% for its
64
 * intervals.
65
 *
66
 * The following describes how the timer should be programmed.
67
 *
68
 * Enabling Watchdog:
69
 * MOV AX,000FH (Choose the values from 0 to F)
70
 * MOV DX,0443H
71
 * OUT DX,AX
72
 *
73
 * Disabling Watchdog:
74
 * MOV AX,000FH (Any value is fine.)
75
 * MOV DX,0441H
76
 * OUT DX,AX
77
 *
78
 * Watchdog timer control table:
79
 * Level   Value  Time/sec | Level Value Time/sec
80
 *   1       F       0     |   9     7      16
81
 *   2       E       2     |   10    6      18
82
 *   3       D       4     |   11    5      20
83
 *   4       C       6     |   12    4      22
84
 *   5       B       8     |   13    3      24
85
 *   6       A       10    |   14    2      26
86
 *   7       9       12    |   15    1      28
87
 *   8       8       14    |   16    0      30
88
 *
89
 */
90
 
91
static int wd_times[] = {
92
        30,     /* 0x0 */
93
        28,     /* 0x1 */
94
        26,     /* 0x2 */
95
        24,     /* 0x3 */
96
        22,     /* 0x4 */
97
        20,     /* 0x5 */
98
        18,     /* 0x6 */
99
        16,     /* 0x7 */
100
        14,     /* 0x8 */
101
        12,     /* 0x9 */
102
        10,     /* 0xA */
103
        8,      /* 0xB */
104
        6,      /* 0xC */
105
        4,      /* 0xD */
106
        2,      /* 0xE */
107
        0,       /* 0xF */
108
};
109
 
110
#define WDT_STOP 0x441
111
#define WDT_START 0x443
112
 
113
/* Default timeout */
114
#define WD_TIMO 0               /* 30 seconds +/- 20%, from table */
115
 
116
static int wd_margin = WD_TIMO;
117
 
118
#ifdef CONFIG_WATCHDOG_NOWAYOUT
119
static int nowayout = 1;
120
#else
121
static int nowayout = 0;
122
#endif
123
 
124
MODULE_PARM(nowayout,"i");
125
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
126
 
127
 
128
/*
129
 *      Kernel methods.
130
 */
131
 
132
static void
133
ibwdt_ping(void)
134
{
135
        /* Write a watchdog value */
136
        outb_p(wd_times[wd_margin], WDT_START);
137
}
138
 
139
static ssize_t
140
ibwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
141
{
142
        /*  Can't seek (pwrite) on this device  */
143
        if (ppos != &file->f_pos)
144
                return -ESPIPE;
145
 
146
        if (count) {
147
                if (!nowayout) {
148
                        size_t i;
149
 
150
                        /* In case it was set long ago */
151
                        expect_close = 0;
152
 
153
                        for (i = 0; i != count; i++) {
154
                                char c;
155
                                if (get_user(c, buf + i))
156
                                        return -EFAULT;
157
                                if (c == 'V')
158
                                        expect_close = 1;
159
                        }
160
                }
161
                ibwdt_ping();
162
                return 1;
163
        }
164
        return 0;
165
}
166
 
167
static ssize_t
168
ibwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos)
169
{
170
        return -EINVAL;
171
}
172
 
173
static int
174
ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
175
          unsigned long arg)
176
{
177
        int i, new_margin;
178
 
179
        static struct watchdog_info ident = {
180
                WDIOF_KEEPALIVEPING |
181
                WDIOF_SETTIMEOUT |
182
                WDIOF_MAGICCLOSE,
183
                1, "IB700 WDT"
184
        };
185
 
186
        switch (cmd) {
187
        case WDIOC_GETSUPPORT:
188
          if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
189
            return -EFAULT;
190
          break;
191
 
192
        case WDIOC_GETSTATUS:
193
          if (copy_to_user((int *)arg, &ibwdt_is_open,  sizeof(int)))
194
            return -EFAULT;
195
          break;
196
 
197
        case WDIOC_KEEPALIVE:
198
          ibwdt_ping();
199
          break;
200
 
201
        case WDIOC_SETTIMEOUT:
202
          if (get_user(new_margin, (int *)arg))
203
                  return -EFAULT;
204
          if ((new_margin < 0) || (new_margin > 30))
205
                  return -EINVAL;
206
          for (i = 0x0F; i > -1; i--)
207
                  if (wd_times[i] > new_margin)
208
                          break;
209
          wd_margin = i;
210
          ibwdt_ping();
211
          /* Fall */
212
 
213
        case WDIOC_GETTIMEOUT:
214
          return put_user(wd_times[wd_margin], (int *)arg);
215
          break;
216
 
217
        default:
218
          return -ENOTTY;
219
        }
220
        return 0;
221
}
222
 
223
static int
224
ibwdt_open(struct inode *inode, struct file *file)
225
{
226
        switch (MINOR(inode->i_rdev)) {
227
                case WATCHDOG_MINOR:
228
                        spin_lock(&ibwdt_lock);
229
                        if (ibwdt_is_open) {
230
                                spin_unlock(&ibwdt_lock);
231
                                return -EBUSY;
232
                        }
233
                        /*
234
                         *      Activate
235
                         */
236
 
237
                        ibwdt_is_open = 1;
238
                        ibwdt_ping();
239
                        spin_unlock(&ibwdt_lock);
240
                        return 0;
241
                default:
242
                        return -ENODEV;
243
        }
244
}
245
 
246
static int
247
ibwdt_close(struct inode *inode, struct file *file)
248
{
249
        lock_kernel();
250
        if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
251
                spin_lock(&ibwdt_lock);
252
                if (expect_close) {
253
                        outb_p(wd_times[wd_margin], WDT_STOP);
254
                } else {
255
                        printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
256
                }
257
                ibwdt_is_open = 0;
258
                spin_unlock(&ibwdt_lock);
259
        }
260
        unlock_kernel();
261
        return 0;
262
}
263
 
264
/*
265
 *      Notifier for system down
266
 */
267
 
268
static int
269
ibwdt_notify_sys(struct notifier_block *this, unsigned long code,
270
        void *unused)
271
{
272
        if (code == SYS_DOWN || code == SYS_HALT) {
273
                /* Turn the WDT off */
274
                outb_p(wd_times[wd_margin], WDT_STOP);
275
        }
276
        return NOTIFY_DONE;
277
}
278
 
279
/*
280
 *      Kernel Interfaces
281
 */
282
 
283
static struct file_operations ibwdt_fops = {
284
        owner:          THIS_MODULE,
285
        read:           ibwdt_read,
286
        write:          ibwdt_write,
287
        ioctl:          ibwdt_ioctl,
288
        open:           ibwdt_open,
289
        release:        ibwdt_close,
290
};
291
 
292
static struct miscdevice ibwdt_miscdev = {
293
        WATCHDOG_MINOR,
294
        "watchdog",
295
        &ibwdt_fops
296
};
297
 
298
/*
299
 *      The WDT needs to learn about soft shutdowns in order to
300
 *      turn the timebomb registers off.
301
 */
302
 
303
static struct notifier_block ibwdt_notifier = {
304
        ibwdt_notify_sys,
305
        NULL,
306
 
307
};
308
 
309
static int __init
310
ibwdt_init(void)
311
{
312
        printk("WDT driver for IB700 single board computer initialising.\n");
313
 
314
        spin_lock_init(&ibwdt_lock);
315
        misc_register(&ibwdt_miscdev);
316
#if WDT_START != WDT_STOP
317
        request_region(WDT_STOP, 1, "IB700 WDT");
318
#endif
319
        request_region(WDT_START, 1, "IB700 WDT");
320
        register_reboot_notifier(&ibwdt_notifier);
321
        return 0;
322
}
323
 
324
static void __exit
325
ibwdt_exit(void)
326
{
327
        misc_deregister(&ibwdt_miscdev);
328
        unregister_reboot_notifier(&ibwdt_notifier);
329
#if WDT_START != WDT_STOP
330
        release_region(WDT_STOP,1);
331
#endif
332
        release_region(WDT_START,1);
333
}
334
 
335
module_init(ibwdt_init);
336
module_exit(ibwdt_exit);
337
 
338
MODULE_AUTHOR("Charles Howes <chowes@vsol.net>");
339
MODULE_DESCRIPTION("IB700 SBC watchdog driver");
340
MODULE_LICENSE("GPL");
341
 
342
/* end of ib700wdt.c */

powered by: WebSVN 2.1.0

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