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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *      Acquire Single Board Computer Watchdog Timer driver
3
 *
4
 *      Based on wdt.c. Original copyright messages:
5
 *
6
 *      (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
7
 *                              http://www.redhat.com
8
 *
9
 *      This program is free software; you can redistribute it and/or
10
 *      modify it under the terms of the GNU General Public License
11
 *      as published by the Free Software Foundation; either version
12
 *      2 of the License, or (at your option) any later version.
13
 *
14
 *      Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
15
 *      warranty for any of this software. This material is provided
16
 *      "AS-IS" and at no charge.
17
 *
18
 *      (c) Copyright 1995    Alan Cox <alan@redhat.com>
19
 *
20
 *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
21
 *          Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
22
 *          Can't add timeout - driver doesn't allow changing value
23
 */
24
 
25
/*
26
 *      Theory of Operation:
27
 *              The Watch-Dog Timer is provided to ensure that standalone
28
 *              Systems can always recover from catastrophic conditions that
29
 *              caused the CPU to crash. This condition may have occured by
30
 *              external EMI or a software bug. When the CPU stops working
31
 *              correctly, hardware on the board will either perform a hardware
32
 *              reset (cold boot) or a non-maskable interrupt (NMI) to bring the
33
 *              system back to a known state.
34
 *
35
 *              The Watch-Dog Timer is controlled by two I/O Ports.
36
 *                443 hex       - Read  - Enable or refresh the Watch-Dog Timer
37
 *                043 hex       - Read  - Disable the Watch-Dog Timer
38
 *
39
 *              To enable the Watch-Dog Timer, a read from I/O port 443h must
40
 *              be performed. This will enable and activate the countdown timer
41
 *              which will eventually time out and either reset the CPU or cause
42
 *              an NMI depending on the setting of a jumper. To ensure that this
43
 *              reset condition does not occur, the Watch-Dog Timer must be
44
 *              periodically refreshed by reading the same I/O port 443h.
45
 *              The Watch-Dog Timer is disabled by reading I/O port 043h.
46
 *
47
 *              The Watch-Dog Timer Time-Out Period is set via jumpers.
48
 *              It can be 1, 2, 10, 20, 110 or 220 seconds.
49
 */
50
 
51
/*
52
 *      Includes, defines, variables, module parameters, ...
53
 */
54
 
55
/* Includes */
56
#include <linux/module.h>               /* For module specific items */
57
#include <linux/moduleparam.h>          /* For new moduleparam's */
58
#include <linux/types.h>                /* For standard types (like size_t) */
59
#include <linux/errno.h>                /* For the -ENODEV/... values */
60
#include <linux/kernel.h>               /* For printk/panic/... */
61
#include <linux/miscdevice.h>           /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
62
#include <linux/watchdog.h>             /* For the watchdog specific items */
63
#include <linux/fs.h>                   /* For file operations */
64
#include <linux/ioport.h>               /* For io-port access */
65
#include <linux/platform_device.h>      /* For platform_driver framework */
66
#include <linux/init.h>                 /* For __init/__exit/... */
67
 
68
#include <asm/uaccess.h>                /* For copy_to_user/put_user/... */
69
#include <asm/io.h>                     /* For inb/outb/... */
70
 
71
/* Module information */
72
#define DRV_NAME "acquirewdt"
73
#define PFX DRV_NAME ": "
74
#define WATCHDOG_NAME "Acquire WDT"
75
#define WATCHDOG_HEARTBEAT 0    /* There is no way to see what the correct time-out period is */
76
 
77
/* internal variables */
78
static struct platform_device *acq_platform_device;     /* the watchdog platform device */
79
static unsigned long acq_is_open;
80
static char expect_close;
81
 
82
/* module parameters */
83
static int wdt_stop = 0x43;     /* You must set this - there is no sane way to probe for this board. */
84
module_param(wdt_stop, int, 0);
85
MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)");
86
 
87
static int wdt_start = 0x443;   /* You must set this - there is no sane way to probe for this board. */
88
module_param(wdt_start, int, 0);
89
MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
90
 
91
static int nowayout = WATCHDOG_NOWAYOUT;
92
module_param(nowayout, int, 0);
93
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
94
 
95
/*
96
 *      Watchdog Operations
97
 */
98
 
99
static void acq_keepalive(void)
100
{
101
        /* Write a watchdog value */
102
        inb_p(wdt_start);
103
}
104
 
105
static void acq_stop(void)
106
{
107
        /* Turn the card off */
108
        inb_p(wdt_stop);
109
}
110
 
111
/*
112
 *      /dev/watchdog handling
113
 */
114
 
115
static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
116
{
117
        /* See if we got the magic character 'V' and reload the timer */
118
        if(count) {
119
                if (!nowayout) {
120
                        size_t i;
121
 
122
                        /* note: just in case someone wrote the magic character
123
                         * five months ago... */
124
                        expect_close = 0;
125
 
126
                        /* scan to see whether or not we got the magic character */
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
                                        expect_close = 42;
133
                        }
134
                }
135
 
136
                /* Well, anyhow someone wrote to us, we should return that favour */
137
                acq_keepalive();
138
        }
139
        return count;
140
}
141
 
142
static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
143
        unsigned long arg)
144
{
145
        int options, retval = -EINVAL;
146
        void __user *argp = (void __user *)arg;
147
        int __user *p = argp;
148
        static struct watchdog_info ident =
149
        {
150
                .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
151
                .firmware_version = 1,
152
                .identity = WATCHDOG_NAME,
153
        };
154
 
155
        switch(cmd)
156
        {
157
        case WDIOC_GETSUPPORT:
158
          return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
159
 
160
        case WDIOC_GETSTATUS:
161
        case WDIOC_GETBOOTSTATUS:
162
          return put_user(0, p);
163
 
164
        case WDIOC_KEEPALIVE:
165
          acq_keepalive();
166
          return 0;
167
 
168
        case WDIOC_GETTIMEOUT:
169
          return put_user(WATCHDOG_HEARTBEAT, p);
170
 
171
        case WDIOC_SETOPTIONS:
172
        {
173
            if (get_user(options, p))
174
              return -EFAULT;
175
 
176
            if (options & WDIOS_DISABLECARD)
177
            {
178
              acq_stop();
179
              retval = 0;
180
            }
181
 
182
            if (options & WDIOS_ENABLECARD)
183
            {
184
              acq_keepalive();
185
              retval = 0;
186
            }
187
 
188
            return retval;
189
        }
190
 
191
        default:
192
          return -ENOTTY;
193
        }
194
}
195
 
196
static int acq_open(struct inode *inode, struct file *file)
197
{
198
        if (test_and_set_bit(0, &acq_is_open))
199
                return -EBUSY;
200
 
201
        if (nowayout)
202
                __module_get(THIS_MODULE);
203
 
204
        /* Activate */
205
        acq_keepalive();
206
        return nonseekable_open(inode, file);
207
}
208
 
209
static int acq_close(struct inode *inode, struct file *file)
210
{
211
        if (expect_close == 42) {
212
                acq_stop();
213
        } else {
214
                printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
215
                acq_keepalive();
216
        }
217
        clear_bit(0, &acq_is_open);
218
        expect_close = 0;
219
        return 0;
220
}
221
 
222
/*
223
 *      Kernel Interfaces
224
 */
225
 
226
static const struct file_operations acq_fops = {
227
        .owner          = THIS_MODULE,
228
        .llseek         = no_llseek,
229
        .write          = acq_write,
230
        .ioctl          = acq_ioctl,
231
        .open           = acq_open,
232
        .release        = acq_close,
233
};
234
 
235
static struct miscdevice acq_miscdev = {
236
        .minor  = WATCHDOG_MINOR,
237
        .name   = "watchdog",
238
        .fops   = &acq_fops,
239
};
240
 
241
/*
242
 *      Init & exit routines
243
 */
244
 
245
static int __devinit acq_probe(struct platform_device *dev)
246
{
247
        int ret;
248
 
249
        if (wdt_stop != wdt_start) {
250
                if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
251
                        printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
252
                                wdt_stop);
253
                        ret = -EIO;
254
                        goto out;
255
                }
256
        }
257
 
258
        if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
259
                printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
260
                        wdt_start);
261
                ret = -EIO;
262
                goto unreg_stop;
263
        }
264
 
265
        ret = misc_register(&acq_miscdev);
266
        if (ret != 0) {
267
                printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
268
                        WATCHDOG_MINOR, ret);
269
                goto unreg_regions;
270
        }
271
 
272
        printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
273
                nowayout);
274
 
275
        return 0;
276
 
277
unreg_regions:
278
        release_region(wdt_start, 1);
279
unreg_stop:
280
        if (wdt_stop != wdt_start)
281
                release_region(wdt_stop, 1);
282
out:
283
        return ret;
284
}
285
 
286
static int __devexit acq_remove(struct platform_device *dev)
287
{
288
        misc_deregister(&acq_miscdev);
289
        release_region(wdt_start,1);
290
        if(wdt_stop != wdt_start)
291
                release_region(wdt_stop,1);
292
 
293
        return 0;
294
}
295
 
296
static void acq_shutdown(struct platform_device *dev)
297
{
298
        /* Turn the WDT off if we have a soft shutdown */
299
        acq_stop();
300
}
301
 
302
static struct platform_driver acquirewdt_driver = {
303
        .probe          = acq_probe,
304
        .remove         = __devexit_p(acq_remove),
305
        .shutdown       = acq_shutdown,
306
        .driver         = {
307
                .owner  = THIS_MODULE,
308
                .name   = DRV_NAME,
309
        },
310
};
311
 
312
static int __init acq_init(void)
313
{
314
        int err;
315
 
316
        printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n");
317
 
318
        err = platform_driver_register(&acquirewdt_driver);
319
        if (err)
320
                return err;
321
 
322
        acq_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
323
        if (IS_ERR(acq_platform_device)) {
324
                err = PTR_ERR(acq_platform_device);
325
                goto unreg_platform_driver;
326
        }
327
 
328
        return 0;
329
 
330
unreg_platform_driver:
331
        platform_driver_unregister(&acquirewdt_driver);
332
        return err;
333
}
334
 
335
static void __exit acq_exit(void)
336
{
337
        platform_device_unregister(acq_platform_device);
338
        platform_driver_unregister(&acquirewdt_driver);
339
        printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
340
}
341
 
342
module_init(acq_init);
343
module_exit(acq_exit);
344
 
345
MODULE_AUTHOR("David Woodhouse");
346
MODULE_DESCRIPTION("Acquire Inc. Single Board Computer Watchdog Timer driver");
347
MODULE_LICENSE("GPL");
348
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);

powered by: WebSVN 2.1.0

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