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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *      Advantech Single Board Computer WDT driver
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
 *      16-Oct-2002 Rob Radez <rob@osinvestor.com>
27
 *          Clean up ioctls, clean up init + exit, add expect close support,
28
 *          add wdt_start and wdt_stop as parameters.
29
 */
30
 
31
#include <linux/module.h>
32
#include <linux/moduleparam.h>
33
#include <linux/types.h>
34
#include <linux/miscdevice.h>
35
#include <linux/watchdog.h>
36
#include <linux/fs.h>
37
#include <linux/ioport.h>
38
#include <linux/platform_device.h>
39
#include <linux/init.h>
40
 
41
#include <asm/io.h>
42
#include <asm/uaccess.h>
43
#include <asm/system.h>
44
 
45
#define DRV_NAME "advantechwdt"
46
#define PFX DRV_NAME ": "
47
#define WATCHDOG_NAME "Advantech WDT"
48
#define WATCHDOG_TIMEOUT 60             /* 60 sec default timeout */
49
 
50
static struct platform_device *advwdt_platform_device;  /* the watchdog platform device */
51
static unsigned long advwdt_is_open;
52
static char adv_expect_close;
53
 
54
/*
55
 *      You must set these - there is no sane way to probe for this board.
56
 *
57
 *      To enable or restart, write the timeout value in seconds (1 to 63)
58
 *      to I/O port wdt_start.  To disable, read I/O port wdt_stop.
59
 *      Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
60
 *      check your manual (at least the PCA-6159 seems to be different -
61
 *      the manual says wdt_stop is 0x43, not 0x443).
62
 *      (0x43 is also a write-only control register for the 8254 timer!)
63
 */
64
 
65
static int wdt_stop = 0x443;
66
module_param(wdt_stop, int, 0);
67
MODULE_PARM_DESC(wdt_stop, "Advantech WDT 'stop' io port (default 0x443)");
68
 
69
static int wdt_start = 0x443;
70
module_param(wdt_start, int, 0);
71
MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
72
 
73
static int timeout = WATCHDOG_TIMEOUT;  /* in seconds */
74
module_param(timeout, int, 0);
75
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
76
 
77
static int nowayout = WATCHDOG_NOWAYOUT;
78
module_param(nowayout, int, 0);
79
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
80
 
81
/*
82
 *      Watchdog Operations
83
 */
84
 
85
static void
86
advwdt_ping(void)
87
{
88
        /* Write a watchdog value */
89
        outb_p(timeout, wdt_start);
90
}
91
 
92
static void
93
advwdt_disable(void)
94
{
95
        inb_p(wdt_stop);
96
}
97
 
98
static int
99
advwdt_set_heartbeat(int t)
100
{
101
        if ((t < 1) || (t > 63))
102
                return -EINVAL;
103
 
104
        timeout = t;
105
        return 0;
106
}
107
 
108
/*
109
 *      /dev/watchdog handling
110
 */
111
 
112
static ssize_t
113
advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
114
{
115
        if (count) {
116
                if (!nowayout) {
117
                        size_t i;
118
 
119
                        adv_expect_close = 0;
120
 
121
                        for (i = 0; i != count; i++) {
122
                                char c;
123
                                if (get_user(c, buf+i))
124
                                        return -EFAULT;
125
                                if (c == 'V')
126
                                        adv_expect_close = 42;
127
                        }
128
                }
129
                advwdt_ping();
130
        }
131
        return count;
132
}
133
 
134
static int
135
advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
136
          unsigned long arg)
137
{
138
        int new_timeout;
139
        void __user *argp = (void __user *)arg;
140
        int __user *p = argp;
141
        static struct watchdog_info ident = {
142
                .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
143
                .firmware_version = 1,
144
                .identity = WATCHDOG_NAME,
145
        };
146
 
147
        switch (cmd) {
148
        case WDIOC_GETSUPPORT:
149
          if (copy_to_user(argp, &ident, sizeof(ident)))
150
            return -EFAULT;
151
          break;
152
 
153
        case WDIOC_GETSTATUS:
154
        case WDIOC_GETBOOTSTATUS:
155
          return put_user(0, p);
156
 
157
        case WDIOC_KEEPALIVE:
158
          advwdt_ping();
159
          break;
160
 
161
        case WDIOC_SETTIMEOUT:
162
          if (get_user(new_timeout, p))
163
                  return -EFAULT;
164
          if (advwdt_set_heartbeat(new_timeout))
165
                  return -EINVAL;
166
          advwdt_ping();
167
          /* Fall */
168
 
169
        case WDIOC_GETTIMEOUT:
170
          return put_user(timeout, p);
171
 
172
        case WDIOC_SETOPTIONS:
173
        {
174
          int options, retval = -EINVAL;
175
 
176
          if (get_user(options, p))
177
            return -EFAULT;
178
 
179
          if (options & WDIOS_DISABLECARD) {
180
            advwdt_disable();
181
            retval = 0;
182
          }
183
 
184
          if (options & WDIOS_ENABLECARD) {
185
            advwdt_ping();
186
            retval = 0;
187
          }
188
 
189
          return retval;
190
        }
191
 
192
        default:
193
          return -ENOTTY;
194
        }
195
        return 0;
196
}
197
 
198
static int
199
advwdt_open(struct inode *inode, struct file *file)
200
{
201
        if (test_and_set_bit(0, &advwdt_is_open))
202
                return -EBUSY;
203
        /*
204
         *      Activate
205
         */
206
 
207
        advwdt_ping();
208
        return nonseekable_open(inode, file);
209
}
210
 
211
static int
212
advwdt_close(struct inode *inode, struct file *file)
213
{
214
        if (adv_expect_close == 42) {
215
                advwdt_disable();
216
        } else {
217
                printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
218
                advwdt_ping();
219
        }
220
        clear_bit(0, &advwdt_is_open);
221
        adv_expect_close = 0;
222
        return 0;
223
}
224
 
225
/*
226
 *      Kernel Interfaces
227
 */
228
 
229
static const struct file_operations advwdt_fops = {
230
        .owner          = THIS_MODULE,
231
        .llseek         = no_llseek,
232
        .write          = advwdt_write,
233
        .ioctl          = advwdt_ioctl,
234
        .open           = advwdt_open,
235
        .release        = advwdt_close,
236
};
237
 
238
static struct miscdevice advwdt_miscdev = {
239
        .minor  = WATCHDOG_MINOR,
240
        .name   = "watchdog",
241
        .fops   = &advwdt_fops,
242
};
243
 
244
/*
245
 *      Init & exit routines
246
 */
247
 
248
static int __devinit
249
advwdt_probe(struct platform_device *dev)
250
{
251
        int ret;
252
 
253
        if (wdt_stop != wdt_start) {
254
                if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
255
                        printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
256
                                wdt_stop);
257
                        ret = -EIO;
258
                        goto out;
259
                }
260
        }
261
 
262
        if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
263
                printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
264
                        wdt_start);
265
                ret = -EIO;
266
                goto unreg_stop;
267
        }
268
 
269
        /* Check that the heartbeat value is within it's range ; if not reset to the default */
270
        if (advwdt_set_heartbeat(timeout)) {
271
                advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
272
                printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
273
                        timeout);
274
        }
275
 
276
        ret = misc_register(&advwdt_miscdev);
277
        if (ret != 0) {
278
                printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
279
                        WATCHDOG_MINOR, ret);
280
                goto unreg_regions;
281
        }
282
 
283
        printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
284
                timeout, nowayout);
285
 
286
out:
287
        return ret;
288
unreg_regions:
289
        release_region(wdt_start, 1);
290
unreg_stop:
291
        if (wdt_stop != wdt_start)
292
                release_region(wdt_stop, 1);
293
        goto out;
294
}
295
 
296
static int __devexit
297
advwdt_remove(struct platform_device *dev)
298
{
299
        misc_deregister(&advwdt_miscdev);
300
        release_region(wdt_start,1);
301
        if(wdt_stop != wdt_start)
302
                release_region(wdt_stop,1);
303
 
304
        return 0;
305
}
306
 
307
static void
308
advwdt_shutdown(struct platform_device *dev)
309
{
310
        /* Turn the WDT off if we have a soft shutdown */
311
        advwdt_disable();
312
}
313
 
314
static struct platform_driver advwdt_driver = {
315
        .probe          = advwdt_probe,
316
        .remove         = __devexit_p(advwdt_remove),
317
        .shutdown       = advwdt_shutdown,
318
        .driver         = {
319
                .owner  = THIS_MODULE,
320
                .name   = DRV_NAME,
321
        },
322
};
323
 
324
static int __init
325
advwdt_init(void)
326
{
327
        int err;
328
 
329
        printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
330
 
331
        err = platform_driver_register(&advwdt_driver);
332
        if (err)
333
                return err;
334
 
335
        advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
336
        if (IS_ERR(advwdt_platform_device)) {
337
                err = PTR_ERR(advwdt_platform_device);
338
                goto unreg_platform_driver;
339
        }
340
 
341
        return 0;
342
 
343
unreg_platform_driver:
344
        platform_driver_unregister(&advwdt_driver);
345
        return err;
346
}
347
 
348
static void __exit
349
advwdt_exit(void)
350
{
351
        platform_device_unregister(advwdt_platform_device);
352
        platform_driver_unregister(&advwdt_driver);
353
        printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
354
}
355
 
356
module_init(advwdt_init);
357
module_exit(advwdt_exit);
358
 
359
MODULE_LICENSE("GPL");
360
MODULE_AUTHOR("Marek Michalkiewicz <marekm@linux.org.pl>");
361
MODULE_DESCRIPTION("Advantech Single Board Computer WDT driver");
362
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.