OSDN Git Service

Change VERSION to 2.4.36.9
[linux-kernel-docs/linux-2.4.36.git] / drivers / char / mpc8xx_wdt.c
1 /*
2  * mpc8xx_wdt.c - MPC8xx watchdog userspace interface
3  *
4  * Copyright (C) 2002 Florian Schirmer <jolt@tuxbox.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21
22 #include <linux/config.h>
23 #include <linux/init.h>
24 #include <linux/kernel.h>
25 #include <linux/miscdevice.h>
26 #include <linux/module.h>
27 #include <linux/watchdog.h>
28 #include <asm/8xx_immap.h>
29 #include <asm/uaccess.h>
30
31 extern int m8xx_wdt_get_timeout(void);
32 extern void m8xx_wdt_reset(void);
33
34 static struct semaphore wdt_sem;
35 static int wdt_status;
36
37 static struct watchdog_info ident = {
38         .identity = "MPC8xx watchdog",
39         .options = WDIOF_KEEPALIVEPING,
40 };
41
42 static void
43 mpc8xx_wdt_handler_disable(void)
44 {
45         volatile immap_t *imap = (volatile immap_t *) IMAP_ADDR;
46
47         imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
48
49         printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
50 }
51
52 static void
53 mpc8xx_wdt_handler_enable(void)
54 {
55         volatile immap_t *imap = (volatile immap_t *) IMAP_ADDR;
56
57         imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
58
59         printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
60 }
61
62 static int
63 mpc8xx_wdt_open(struct inode *inode, struct file *file)
64 {
65         switch (MINOR(inode->i_rdev)) {
66         case WATCHDOG_MINOR:
67                 if (down_trylock(&wdt_sem))
68                         return -EBUSY;
69
70                 m8xx_wdt_reset();
71                 mpc8xx_wdt_handler_disable();
72                 break;
73
74         default:
75                 return -ENODEV;
76         }
77
78         return 0;
79 }
80
81 static int
82 mpc8xx_wdt_release(struct inode *inode, struct file *file)
83 {
84         m8xx_wdt_reset();
85
86 #if !defined(CONFIG_WATCHDOG_NOWAYOUT)
87         mpc8xx_wdt_handler_enable();
88 #endif
89
90         up(&wdt_sem);
91
92         return 0;
93 }
94
95 static ssize_t
96 mpc8xx_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos)
97 {
98         /* Can't seek (pwrite) on this device */
99         if (ppos != &file->f_pos)
100                 return -ESPIPE;
101
102         if (!len)
103                 return 0;
104
105         m8xx_wdt_reset();
106
107         return 1;
108 }
109
110 static int
111 mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
112                  unsigned int cmd, unsigned long arg)
113 {
114         switch (cmd) {
115         case WDIOC_GETSUPPORT:
116                 if (copy_to_user((void *) arg, &ident, sizeof (ident)))
117                         return -EFAULT;
118                 break;
119
120         case WDIOC_GETSTATUS:
121         case WDIOC_GETBOOTSTATUS:
122                 if (put_user(wdt_status, (int *) arg))
123                         return -EFAULT;
124                 wdt_status &= ~WDIOF_KEEPALIVEPING;
125                 break;
126
127         case WDIOC_KEEPALIVE:
128                 m8xx_wdt_reset();
129                 wdt_status |= WDIOF_KEEPALIVEPING;
130                 break;
131
132         case WDIOC_GETTIMEOUT:
133                 {
134                         int timeout = m8xx_wdt_get_timeout();
135                         if (put_user(timeout, (int *) arg))
136                                 return -EFAULT;
137                         break;
138                 }
139
140         default:
141                 return -ENOTTY;
142         }
143
144         return 0;
145 }
146
147 static struct file_operations mpc8xx_wdt_fops = {
148         .owner = THIS_MODULE,
149         .write = mpc8xx_wdt_write,
150         .ioctl = mpc8xx_wdt_ioctl,
151         .open = mpc8xx_wdt_open,
152         .release = mpc8xx_wdt_release,
153 };
154
155 static struct miscdevice mpc8xx_wdt_miscdev = {
156         .minor = WATCHDOG_MINOR,
157         .name = "watchdog",
158         .fops = &mpc8xx_wdt_fops,
159 };
160
161 static int __init
162 mpc8xx_wdt_init(void)
163 {
164         int ret;
165
166         sema_init(&wdt_sem, 1);
167
168         if ((ret = misc_register(&mpc8xx_wdt_miscdev))) {
169                 printk(KERN_WARNING
170                        "mpc8xx_wdt: could not register userspace interface\n");
171                 return ret;
172         }
173
174         return 0;
175 }
176
177 static void __exit
178 mpc8xx_wdt_exit(void)
179 {
180         misc_deregister(&mpc8xx_wdt_miscdev);
181
182         m8xx_wdt_reset();
183         mpc8xx_wdt_handler_enable();
184 }
185
186 module_init(mpc8xx_wdt_init);
187 module_exit(mpc8xx_wdt_exit);
188
189 MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
190 MODULE_DESCRIPTION("MPC8xx watchdog driver");
191 MODULE_LICENSE("GPL");