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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Advantech Single Board Computer WDT driver for Linux 2.4.x
3
 *
4
 *      (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
5
 *
6
 *      Based on acquirewdt.c which is based on wdt.c.
7
 *      Original copyright messages:
8
 *
9
 *      (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
10
 *                              http://www.redhat.com
11
 *
12
 *      This program is free software; you can redistribute it and/or
13
 *      modify it under the terms of the GNU General Public License
14
 *      as published by the Free Software Foundation; either version
15
 *      2 of the License, or (at your option) any later version.
16
 *
17
 *      Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
18
 *      warranty for any of this software. This material is provided
19
 *      "AS-IS" and at no charge.
20
 *
21
 *      (c) Copyright 1995    Alan Cox <alan@redhat.com>
22
 *
23
 *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
24
 *          Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
25
 */
26
 
27
#include <linux/config.h>
28
#include <linux/module.h>
29
#include <linux/types.h>
30
#include <linux/errno.h>
31
#include <linux/kernel.h>
32
#include <linux/miscdevice.h>
33
#include <linux/watchdog.h>
34
#include <linux/ioport.h>
35
#include <linux/fcntl.h>
36
#include <asm/io.h>
37
#include <asm/uaccess.h>
38
#include <asm/system.h>
39
#include <linux/notifier.h>
40
#include <linux/reboot.h>
41
#include <linux/init.h>
42
 
43
static unsigned long advwdt_is_open;
44
static char adv_expect_close;
45
 
46
/*
47
 *      You must set these - there is no sane way to probe for this board.
48
 *
49
 *      To enable or restart, write the timeout value in seconds (1 to 63)
50
 *      to I/O port wdt_start.  To disable, read I/O port wdt_stop.
51
 *      Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
52
 *      check your manual (at least the PCA-6159 seems to be different -
53
 *      the manual says wdt_stop is 0x43, not 0x443).
54
 *      (0x43 is also a write-only control register for the 8254 timer!)
55
 */
56
 
57
static int wdt_stop = 0x443;
58
static int wdt_start = 0x443;
59
 
60
static int wd_margin = 60; /* 60 sec default timeout */
61
 
62
#ifdef CONFIG_WATCHDOG_NOWAYOUT
63
static int nowayout = 1;
64
#else
65
static int nowayout = 0;
66
#endif
67
 
68
MODULE_PARM(nowayout,"i");
69
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
70
 
71
/*
72
 *      Kernel methods.
73
 */
74
 
75
#ifndef MODULE
76
 
77
static int __init adv_setup(char *str)
78
{
79
        int ints[4];
80
 
81
        str = get_options(str, ARRAY_SIZE(ints), ints);
82
 
83
        if(ints[0] > 0){
84
                wdt_stop = ints[1];
85
                if(ints[0] > 1)
86
                        wdt_start = ints[2];
87
        }
88
 
89
        return 1;
90
}
91
 
92
__setup("advwdt=", adv_setup);
93
 
94
#endif /* !MODULE */
95
 
96
MODULE_PARM(wdt_stop, "i");
97
MODULE_PARM_DESC(wdt_stop, "Advantech WDT 'stop' io port (default 0x443)");
98
MODULE_PARM(wdt_start, "i");
99
MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
100
 
101
static void
102
advwdt_ping(void)
103
{
104
        /* Write a watchdog value */
105
        outb_p(wd_margin, wdt_start);
106
}
107
 
108
static void
109
advwdt_disable(void)
110
{
111
        inb_p(wdt_stop);
112
}
113
 
114
static ssize_t
115
advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
116
{
117
        /*  Can't seek (pwrite) on this device  */
118
        if (ppos != &file->f_pos)
119
                return -ESPIPE;
120
 
121
        if (count) {
122
                if (!nowayout) {
123
                        size_t i;
124
 
125
                        adv_expect_close = 0;
126
 
127
                        for (i = 0; i != count; i++) {
128
                                char c;
129
                                if(get_user(c, buf+i))
130
                                        return -EFAULT;
131
                                if (c == 'V')
132
                                        adv_expect_close = 42;
133
                        }
134
                }
135
                        advwdt_ping();
136
        }
137
        return count;
138
}
139
 
140
static int
141
advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
142
          unsigned long arg)
143
{
144
        int new_margin;
145
        static struct watchdog_info ident = {
146
                options:                WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
147
                firmware_version:       0,
148
                identity:               "Advantech WDT"
149
        };
150
 
151
        switch (cmd) {
152
        case WDIOC_GETSUPPORT:
153
          if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
154
            return -EFAULT;
155
          break;
156
 
157
        case WDIOC_GETSTATUS:
158
        case WDIOC_GETBOOTSTATUS:
159
          return put_user(0, (int *)arg);
160
 
161
        case WDIOC_KEEPALIVE:
162
          advwdt_ping();
163
          break;
164
 
165
        case WDIOC_SETTIMEOUT:
166
          if (get_user(new_margin, (int *)arg))
167
                  return -EFAULT;
168
          if ((new_margin < 1) || (new_margin > 63))
169
                  return -EINVAL;
170
          wd_margin = new_margin;
171
          advwdt_ping();
172
          /* Fall */
173
 
174
        case WDIOC_GETTIMEOUT:
175
          return put_user(wd_margin, (int *)arg);
176
 
177
        case WDIOC_SETOPTIONS:
178
        {
179
          int options, retval = -EINVAL;
180
 
181
          if (get_user(options, (int *)arg))
182
            return -EFAULT;
183
 
184
          if (options & WDIOS_DISABLECARD) {
185
            advwdt_disable();
186
            retval = 0;
187
          }
188
 
189
          if (options & WDIOS_ENABLECARD) {
190
            advwdt_ping();
191
            retval = 0;
192
          }
193
 
194
          return retval;
195
        }
196
 
197
        default:
198
          return -ENOTTY;
199
        }
200
        return 0;
201
}
202
 
203
static int
204
advwdt_open(struct inode *inode, struct file *file)
205
{
206
        if (test_and_set_bit(0, &advwdt_is_open))
207
                return -EBUSY;
208
        /*
209
         *      Activate
210
         */
211
 
212
        advwdt_ping();
213
        return 0;
214
}
215
 
216
static int
217
advwdt_close(struct inode *inode, struct file *file)
218
{
219
        if (adv_expect_close == 42) {
220
                advwdt_disable();
221
        } else {
222
                printk(KERN_CRIT "advancetechwdt: Unexpected close, not stopping watchdog!\n");
223
                advwdt_ping();
224
        }
225
        clear_bit(0, &advwdt_is_open);
226
        adv_expect_close = 0;
227
        return 0;
228
}
229
 
230
/*
231
 *      Notifier for system down
232
 */
233
 
234
static int
235
advwdt_notify_sys(struct notifier_block *this, unsigned long code,
236
        void *unused)
237
{
238
        if (code == SYS_DOWN || code == SYS_HALT) {
239
                /* Turn the WDT off */
240
                advwdt_disable();
241
        }
242
        return NOTIFY_DONE;
243
}
244
 
245
/*
246
 *      Kernel Interfaces
247
 */
248
 
249
static struct file_operations advwdt_fops = {
250
        owner:          THIS_MODULE,
251
        llseek:         no_llseek,
252
        write:          advwdt_write,
253
        ioctl:          advwdt_ioctl,
254
        open:           advwdt_open,
255
        release:        advwdt_close,
256
};
257
 
258
static struct miscdevice advwdt_miscdev = {
259
        minor:          WATCHDOG_MINOR,
260
        name:           "watchdog",
261
        fops:           &advwdt_fops,
262
};
263
 
264
/*
265
 *      The WDT needs to learn about soft shutdowns in order to
266
 *      turn the timebomb registers off.
267
 */
268
 
269
static struct notifier_block advwdt_notifier = {
270
        advwdt_notify_sys,
271
        NULL,
272
 
273
};
274
 
275
static int __init
276
advwdt_init(void)
277
{
278
        printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
279
 
280
        misc_register(&advwdt_miscdev);
281
        if(wdt_stop != wdt_start)
282
                request_region(wdt_stop, 1, "Advantech WDT");
283
        request_region(wdt_start, 1, "Advantech WDT");
284
        register_reboot_notifier(&advwdt_notifier);
285
        return 0;
286
}
287
 
288
static void __exit
289
advwdt_exit(void)
290
{
291
        misc_deregister(&advwdt_miscdev);
292
        unregister_reboot_notifier(&advwdt_notifier);
293
        if(wdt_stop != wdt_start)
294
                release_region(wdt_stop,1);
295
        release_region(wdt_start,1);
296
}
297
 
298
module_init(advwdt_init);
299
module_exit(advwdt_exit);
300
 
301
MODULE_LICENSE("GPL");
302
MODULE_AUTHOR("Marek Michalkiewicz <marekm@linux.org.pl>");
303
MODULE_DESCRIPTION("Advantech Single Board Computer WDT driver");
304
EXPORT_NO_SYMBOLS;
305
 
306
/* end of advantechwdt.c */
307
 

powered by: WebSVN 2.1.0

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