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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [watchdog/] [wdt977.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *      Wdt977  0.04:   A Watchdog Device for Netwinder W83977AF chip
3
 *
4
 *      (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
5
 *
6
 *                      -----------------------
7
 *
8
 *      This program is free software; you can redistribute it and/or
9
 *      modify it under the terms of the GNU General Public License
10
 *      as published by the Free Software Foundation; either version
11
 *      2 of the License, or (at your option) any later version.
12
 *
13
 *                      -----------------------
14
 *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
15
 *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
16
 *      19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface
17
 *      06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts
18
 *                                  from minutes to seconds.
19
 *      07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
20
 *                                    nwwatchdog_init.
21
 *      25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks
22
 *                                  remove limitiation to be used on Netwinders only
23
 */
24
 
25
#include <linux/module.h>
26
#include <linux/moduleparam.h>
27
#include <linux/types.h>
28
#include <linux/kernel.h>
29
#include <linux/fs.h>
30
#include <linux/miscdevice.h>
31
#include <linux/init.h>
32
#include <linux/ioport.h>
33
#include <linux/watchdog.h>
34
#include <linux/notifier.h>
35
#include <linux/reboot.h>
36
 
37
#include <asm/io.h>
38
#include <asm/system.h>
39
#include <asm/mach-types.h>
40
#include <asm/uaccess.h>
41
 
42
#define WATCHDOG_VERSION  "0.04"
43
#define WATCHDOG_NAME     "Wdt977"
44
#define PFX WATCHDOG_NAME ": "
45
#define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
46
 
47
#define IO_INDEX_PORT   0x370           /* on some systems it can be 0x3F0 */
48
#define IO_DATA_PORT    (IO_INDEX_PORT+1)
49
 
50
#define UNLOCK_DATA     0x87
51
#define LOCK_DATA       0xAA
52
#define DEVICE_REGISTER 0x07
53
 
54
 
55
#define DEFAULT_TIMEOUT 60                      /* default timeout in seconds */
56
 
57
static  int timeout = DEFAULT_TIMEOUT;
58
static  int timeoutM;                           /* timeout in minutes */
59
static  unsigned long timer_alive;
60
static  int testmode;
61
static  char expect_close;
62
static  DEFINE_SPINLOCK(spinlock);
63
 
64
module_param(timeout, int, 0);
65
MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
66
module_param(testmode, int, 0);
67
MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
68
 
69
static int nowayout = WATCHDOG_NOWAYOUT;
70
module_param(nowayout, int, 0);
71
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
72
 
73
/*
74
 * Start the watchdog
75
 */
76
 
77
static int wdt977_start(void)
78
{
79
        unsigned long flags;
80
 
81
        spin_lock_irqsave(&spinlock, flags);
82
 
83
        /* unlock the SuperIO chip */
84
        outb_p(UNLOCK_DATA, IO_INDEX_PORT);
85
        outb_p(UNLOCK_DATA, IO_INDEX_PORT);
86
 
87
        /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
88
         * F2 has the timeout in minutes
89
         * F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
90
         *   at timeout, and to reset timer on kbd/mouse activity (not impl.)
91
         * F4 is used to just clear the TIMEOUT'ed state (bit 0)
92
         */
93
        outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
94
        outb_p(0x08, IO_DATA_PORT);
95
        outb_p(0xF2, IO_INDEX_PORT);
96
        outb_p(timeoutM, IO_DATA_PORT);
97
        outb_p(0xF3, IO_INDEX_PORT);
98
        outb_p(0x00, IO_DATA_PORT);     /* another setting is 0E for kbd/mouse/LED */
99
        outb_p(0xF4, IO_INDEX_PORT);
100
        outb_p(0x00, IO_DATA_PORT);
101
 
102
        /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
103
        /* in test mode watch the bit 1 on F4 to indicate "triggered" */
104
        if (!testmode)
105
        {
106
                outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
107
                outb_p(0x07, IO_DATA_PORT);
108
                outb_p(0xE6, IO_INDEX_PORT);
109
                outb_p(0x08, IO_DATA_PORT);
110
        }
111
 
112
        /* lock the SuperIO chip */
113
        outb_p(LOCK_DATA, IO_INDEX_PORT);
114
 
115
        spin_unlock_irqrestore(&spinlock, flags);
116
        printk(KERN_INFO PFX "activated.\n");
117
 
118
        return 0;
119
}
120
 
121
/*
122
 * Stop the watchdog
123
 */
124
 
125
static int wdt977_stop(void)
126
{
127
        unsigned long flags;
128
        spin_lock_irqsave(&spinlock, flags);
129
 
130
        /* unlock the SuperIO chip */
131
        outb_p(UNLOCK_DATA, IO_INDEX_PORT);
132
        outb_p(UNLOCK_DATA, IO_INDEX_PORT);
133
 
134
        /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
135
        * F3 is reset to its default state
136
        * F4 can clear the TIMEOUT'ed state (bit 0) - back to default
137
        * We can not use GP17 as a PowerLed, as we use its usage as a RedLed
138
        */
139
        outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
140
        outb_p(0x08, IO_DATA_PORT);
141
        outb_p(0xF2, IO_INDEX_PORT);
142
        outb_p(0xFF, IO_DATA_PORT);
143
        outb_p(0xF3, IO_INDEX_PORT);
144
        outb_p(0x00, IO_DATA_PORT);
145
        outb_p(0xF4, IO_INDEX_PORT);
146
        outb_p(0x00, IO_DATA_PORT);
147
        outb_p(0xF2, IO_INDEX_PORT);
148
        outb_p(0x00, IO_DATA_PORT);
149
 
150
        /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
151
        outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
152
        outb_p(0x07, IO_DATA_PORT);
153
        outb_p(0xE6, IO_INDEX_PORT);
154
        outb_p(0x08, IO_DATA_PORT);
155
 
156
        /* lock the SuperIO chip */
157
        outb_p(LOCK_DATA, IO_INDEX_PORT);
158
 
159
        spin_unlock_irqrestore(&spinlock, flags);
160
        printk(KERN_INFO PFX "shutdown.\n");
161
 
162
        return 0;
163
}
164
 
165
/*
166
 * Send a keepalive ping to the watchdog
167
 * This is done by simply re-writing the timeout to reg. 0xF2
168
 */
169
 
170
static int wdt977_keepalive(void)
171
{
172
        unsigned long flags;
173
        spin_lock_irqsave(&spinlock, flags);
174
 
175
        /* unlock the SuperIO chip */
176
        outb_p(UNLOCK_DATA, IO_INDEX_PORT);
177
        outb_p(UNLOCK_DATA, IO_INDEX_PORT);
178
 
179
        /* select device Aux2 (device=8) and kicks watchdog reg F2 */
180
        /* F2 has the timeout in minutes */
181
        outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
182
        outb_p(0x08, IO_DATA_PORT);
183
        outb_p(0xF2, IO_INDEX_PORT);
184
        outb_p(timeoutM, IO_DATA_PORT);
185
 
186
        /* lock the SuperIO chip */
187
        outb_p(LOCK_DATA, IO_INDEX_PORT);
188
        spin_unlock_irqrestore(&spinlock, flags);
189
 
190
        return 0;
191
}
192
 
193
/*
194
 * Set the watchdog timeout value
195
 */
196
 
197
static int wdt977_set_timeout(int t)
198
{
199
        int tmrval;
200
 
201
        /* convert seconds to minutes, rounding up */
202
        tmrval = (t + 59) / 60;
203
 
204
        if (machine_is_netwinder()) {
205
                /* we have a hw bug somewhere, so each 977 minute is actually only 30sec
206
                 *  this limits the max timeout to half of device max of 255 minutes...
207
                 */
208
                tmrval += tmrval;
209
        }
210
 
211
        if ((tmrval < 1) || (tmrval > 255))
212
                return -EINVAL;
213
 
214
        /* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */
215
        timeout = t;
216
        timeoutM = tmrval;
217
        return 0;
218
}
219
 
220
/*
221
 * Get the watchdog status
222
 */
223
 
224
static int wdt977_get_status(int *status)
225
{
226
        int new_status;
227
        unsigned long flags;
228
 
229
        spin_lock_irqsave(&spinlock, flags);
230
 
231
        /* unlock the SuperIO chip */
232
        outb_p(UNLOCK_DATA, IO_INDEX_PORT);
233
        outb_p(UNLOCK_DATA, IO_INDEX_PORT);
234
 
235
        /* select device Aux2 (device=8) and read watchdog reg F4 */
236
        outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
237
        outb_p(0x08, IO_DATA_PORT);
238
        outb_p(0xF4, IO_INDEX_PORT);
239
        new_status = inb_p(IO_DATA_PORT);
240
 
241
        /* lock the SuperIO chip */
242
        outb_p(LOCK_DATA, IO_INDEX_PORT);
243
 
244
        spin_unlock_irqrestore(&spinlock, flags);
245
 
246
        *status=0;
247
        if (new_status & 1)
248
                *status |= WDIOF_CARDRESET;
249
 
250
        return 0;
251
}
252
 
253
 
254
/*
255
 *      /dev/watchdog handling
256
 */
257
 
258
static int wdt977_open(struct inode *inode, struct file *file)
259
{
260
        /* If the watchdog is alive we don't need to start it again */
261
        if( test_and_set_bit(0,&timer_alive) )
262
                return -EBUSY;
263
 
264
        if (nowayout)
265
                __module_get(THIS_MODULE);
266
 
267
        wdt977_start();
268
        return nonseekable_open(inode, file);
269
}
270
 
271
static int wdt977_release(struct inode *inode, struct file *file)
272
{
273
        /*
274
         *      Shut off the timer.
275
         *      Lock it in if it's a module and we set nowayout
276
         */
277
        if (expect_close == 42)
278
        {
279
                wdt977_stop();
280
                clear_bit(0,&timer_alive);
281
        } else {
282
                wdt977_keepalive();
283
                printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
284
        }
285
        expect_close = 0;
286
        return 0;
287
}
288
 
289
 
290
/*
291
 *      wdt977_write:
292
 *      @file: file handle to the watchdog
293
 *      @buf: buffer to write (unused as data does not matter here
294
 *      @count: count of bytes
295
 *      @ppos: pointer to the position to write. No seeks allowed
296
 *
297
 *      A write to a watchdog device is defined as a keepalive signal. Any
298
 *      write of data will do, as we we don't define content meaning.
299
 */
300
 
301
static ssize_t wdt977_write(struct file *file, const char __user *buf,
302
                            size_t count, loff_t *ppos)
303
{
304
        if (count)
305
        {
306
                if (!nowayout)
307
                {
308
                        size_t i;
309
 
310
                        /* In case it was set long ago */
311
                        expect_close = 0;
312
 
313
                        for (i = 0; i != count; i++)
314
                        {
315
                                char c;
316
                                if (get_user(c, buf + i))
317
                                        return -EFAULT;
318
                                if (c == 'V')
319
                                        expect_close = 42;
320
                        }
321
                }
322
 
323
                /* someone wrote to us, we should restart timer */
324
                wdt977_keepalive();
325
        }
326
        return count;
327
}
328
 
329
/*
330
 *      wdt977_ioctl:
331
 *      @inode: inode of the device
332
 *      @file: file handle to the device
333
 *      @cmd: watchdog command
334
 *      @arg: argument pointer
335
 *
336
 *      The watchdog API defines a common set of functions for all watchdogs
337
 *      according to their available features.
338
 */
339
 
340
static struct watchdog_info ident = {
341
        .options =              WDIOF_SETTIMEOUT |
342
                                WDIOF_MAGICCLOSE |
343
                                WDIOF_KEEPALIVEPING,
344
        .firmware_version =     1,
345
        .identity =             WATCHDOG_NAME,
346
};
347
 
348
static int wdt977_ioctl(struct inode *inode, struct file *file,
349
        unsigned int cmd, unsigned long arg)
350
{
351
        int status;
352
        int new_options, retval = -EINVAL;
353
        int new_timeout;
354
        union {
355
                struct watchdog_info __user *ident;
356
                int __user *i;
357
        } uarg;
358
 
359
        uarg.i = (int __user *)arg;
360
 
361
        switch(cmd)
362
        {
363
        default:
364
                return -ENOTTY;
365
 
366
        case WDIOC_GETSUPPORT:
367
                return copy_to_user(uarg.ident, &ident,
368
                        sizeof(ident)) ? -EFAULT : 0;
369
 
370
        case WDIOC_GETSTATUS:
371
                wdt977_get_status(&status);
372
                return put_user(status, uarg.i);
373
 
374
        case WDIOC_GETBOOTSTATUS:
375
                return put_user(0, uarg.i);
376
 
377
        case WDIOC_KEEPALIVE:
378
                wdt977_keepalive();
379
                return 0;
380
 
381
        case WDIOC_SETOPTIONS:
382
                if (get_user (new_options, uarg.i))
383
                        return -EFAULT;
384
 
385
                if (new_options & WDIOS_DISABLECARD) {
386
                        wdt977_stop();
387
                        retval = 0;
388
                }
389
 
390
                if (new_options & WDIOS_ENABLECARD) {
391
                        wdt977_start();
392
                        retval = 0;
393
                }
394
 
395
                return retval;
396
 
397
        case WDIOC_SETTIMEOUT:
398
                if (get_user(new_timeout, uarg.i))
399
                        return -EFAULT;
400
 
401
                if (wdt977_set_timeout(new_timeout))
402
                    return -EINVAL;
403
 
404
                wdt977_keepalive();
405
                /* Fall */
406
 
407
        case WDIOC_GETTIMEOUT:
408
                return put_user(timeout, uarg.i);
409
 
410
        }
411
}
412
 
413
static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
414
        void *unused)
415
{
416
        if(code==SYS_DOWN || code==SYS_HALT)
417
                wdt977_stop();
418
        return NOTIFY_DONE;
419
}
420
 
421
static const struct file_operations wdt977_fops=
422
{
423
        .owner          = THIS_MODULE,
424
        .llseek         = no_llseek,
425
        .write          = wdt977_write,
426
        .ioctl          = wdt977_ioctl,
427
        .open           = wdt977_open,
428
        .release        = wdt977_release,
429
};
430
 
431
static struct miscdevice wdt977_miscdev=
432
{
433
        .minor          = WATCHDOG_MINOR,
434
        .name           = "watchdog",
435
        .fops           = &wdt977_fops,
436
};
437
 
438
static struct notifier_block wdt977_notifier = {
439
        .notifier_call = wdt977_notify_sys,
440
};
441
 
442
static int __init wd977_init(void)
443
{
444
        int rc;
445
 
446
        //if (!machine_is_netwinder())
447
        //      return -ENODEV;
448
 
449
        printk(KERN_INFO PFX DRIVER_VERSION);
450
 
451
        /* Check that the timeout value is within it's range ; if not reset to the default */
452
        if (wdt977_set_timeout(timeout))
453
        {
454
                wdt977_set_timeout(DEFAULT_TIMEOUT);
455
                printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
456
                        DEFAULT_TIMEOUT);
457
        }
458
 
459
        /* on Netwinder the IOports are already reserved by
460
         * arch/arm/mach-footbridge/netwinder-hw.c
461
         */
462
        if (!machine_is_netwinder())
463
        {
464
                if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
465
                {
466
                        printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
467
                                IO_INDEX_PORT);
468
                        rc = -EIO;
469
                        goto err_out;
470
                }
471
        }
472
 
473
        rc = misc_register(&wdt977_miscdev);
474
        if (rc)
475
        {
476
                printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
477
                        wdt977_miscdev.minor, rc);
478
                goto err_out_region;
479
        }
480
 
481
        rc = register_reboot_notifier(&wdt977_notifier);
482
        if (rc)
483
        {
484
                printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
485
                        rc);
486
                goto err_out_miscdev;
487
        }
488
 
489
        printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
490
                timeout, nowayout, testmode);
491
 
492
        return 0;
493
 
494
err_out_miscdev:
495
        misc_deregister(&wdt977_miscdev);
496
err_out_region:
497
        if (!machine_is_netwinder())
498
                release_region(IO_INDEX_PORT,2);
499
err_out:
500
        return rc;
501
}
502
 
503
static void __exit wd977_exit(void)
504
{
505
        wdt977_stop();
506
        misc_deregister(&wdt977_miscdev);
507
        unregister_reboot_notifier(&wdt977_notifier);
508
        release_region(IO_INDEX_PORT,2);
509
}
510
 
511
module_init(wd977_init);
512
module_exit(wd977_exit);
513
 
514
MODULE_AUTHOR("Woody Suwalski <woodys@xandros.com>");
515
MODULE_DESCRIPTION("W83977AF Watchdog driver");
516
MODULE_LICENSE("GPL");
517
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.