aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWim Van Sebroeck <wim@iguana.be>2011-07-22 14:57:55 -0400
committerWim Van Sebroeck <wim@iguana.be>2011-07-28 04:01:09 -0400
commit234445b4e4542f3e0f216459245ab369a18adcf2 (patch)
treeed670bb2aa3eae41f00e5217fb786eaa9fbe6cb3
parentc2dc00e494cc476551b9beeb883910391ff59737 (diff)
watchdog: WatchDog Timer Driver Core - Add WDIOC_SETOPTIONS ioctl
This part add's the WDIOC_SETOPTIONS ioctl functionality to the WatchDog Timer Driver Core framework. Signed-off-by: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Wim Van Sebroeck <wim@iguana.be> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Wolfram Sang <w.sang@pengutronix.de>
-rw-r--r--Documentation/watchdog/watchdog-kernel-api.txt9
-rw-r--r--drivers/watchdog/watchdog_dev.c79
-rw-r--r--include/linux/watchdog.h1
3 files changed, 80 insertions, 9 deletions
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index abbcf2ce8f62..429f81bf0cf7 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -56,8 +56,9 @@ It contains following fields:
56 This data should only be accessed via the watchdog_set_drvadata and 56 This data should only be accessed via the watchdog_set_drvadata and
57 watchdog_get_drvdata routines. 57 watchdog_get_drvdata routines.
58* status: this field contains a number of status bits that give extra 58* status: this field contains a number of status bits that give extra
59 information about the status of the device (Like: is the device opened via 59 information about the status of the device (Like: is the watchdog timer
60 the /dev/watchdog interface or not, ...). 60 running/active, is the device opened via the /dev/watchdog interface or not,
61 ...).
61 62
62The list of watchdog operations is defined as: 63The list of watchdog operations is defined as:
63 64
@@ -109,6 +110,10 @@ they are supported. These optional routines/operations are:
109 110
110The status bits should (preferably) be set with the set_bit and clear_bit alike 111The status bits should (preferably) be set with the set_bit and clear_bit alike
111bit-operations. The status bits that are defined are: 112bit-operations. The status bits that are defined are:
113* WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
114 is active or not. When the watchdog is active after booting, then you should
115 set this status bit (Note: when you register the watchdog timer device with
116 this bit set, then opening /dev/watchdog will skip the start operation)
112* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device 117* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device
113 was opened via /dev/watchdog. 118 was opened via /dev/watchdog.
114 (This bit should only be used by the WatchDog Timer Driver Core). 119 (This bit should only be used by the WatchDog Timer Driver Core).
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 2fb4cecd50d8..9f5550e16ab5 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -54,14 +54,64 @@ static struct watchdog_device *wdd;
54 * If the watchdog has no own ping operation then it needs to be 54 * If the watchdog has no own ping operation then it needs to be
55 * restarted via the start operation. This wrapper function does 55 * restarted via the start operation. This wrapper function does
56 * exactly that. 56 * exactly that.
57 * We only ping when the watchdog device is running.
57 */ 58 */
58 59
59static int watchdog_ping(struct watchdog_device *wddev) 60static int watchdog_ping(struct watchdog_device *wddev)
60{ 61{
61 if (wddev->ops->ping) 62 if (test_bit(WDOG_ACTIVE, &wdd->status)) {
62 return wddev->ops->ping(wddev); /* ping the watchdog */ 63 if (wddev->ops->ping)
63 else 64 return wddev->ops->ping(wddev); /* ping the watchdog */
64 return wddev->ops->start(wddev); /* restart the watchdog */ 65 else
66 return wddev->ops->start(wddev); /* restart watchdog */
67 }
68 return 0;
69}
70
71/*
72 * watchdog_start: wrapper to start the watchdog.
73 * @wddev: the watchdog device to start
74 *
75 * Start the watchdog if it is not active and mark it active.
76 * This function returns zero on success or a negative errno code for
77 * failure.
78 */
79
80static int watchdog_start(struct watchdog_device *wddev)
81{
82 int err;
83
84 if (!test_bit(WDOG_ACTIVE, &wdd->status)) {
85 err = wddev->ops->start(wddev);
86 if (err < 0)
87 return err;
88
89 set_bit(WDOG_ACTIVE, &wdd->status);
90 }
91 return 0;
92}
93
94/*
95 * watchdog_stop: wrapper to stop the watchdog.
96 * @wddev: the watchdog device to stop
97 *
98 * Stop the watchdog if it is still active and unmark it active.
99 * This function returns zero on success or a negative errno code for
100 * failure.
101 */
102
103static int watchdog_stop(struct watchdog_device *wddev)
104{
105 int err;
106
107 if (test_bit(WDOG_ACTIVE, &wdd->status)) {
108 err = wddev->ops->stop(wddev);
109 if (err < 0)
110 return err;
111
112 clear_bit(WDOG_ACTIVE, &wdd->status);
113 }
114 return 0;
65} 115}
66 116
67/* 117/*
@@ -110,6 +160,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
110 void __user *argp = (void __user *)arg; 160 void __user *argp = (void __user *)arg;
111 int __user *p = argp; 161 int __user *p = argp;
112 unsigned int val; 162 unsigned int val;
163 int err;
113 164
114 switch (cmd) { 165 switch (cmd) {
115 case WDIOC_GETSUPPORT: 166 case WDIOC_GETSUPPORT:
@@ -120,6 +171,20 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
120 return put_user(val, p); 171 return put_user(val, p);
121 case WDIOC_GETBOOTSTATUS: 172 case WDIOC_GETBOOTSTATUS:
122 return put_user(wdd->bootstatus, p); 173 return put_user(wdd->bootstatus, p);
174 case WDIOC_SETOPTIONS:
175 if (get_user(val, p))
176 return -EFAULT;
177 if (val & WDIOS_DISABLECARD) {
178 err = watchdog_stop(wdd);
179 if (err < 0)
180 return err;
181 }
182 if (val & WDIOS_ENABLECARD) {
183 err = watchdog_start(wdd);
184 if (err < 0)
185 return err;
186 }
187 return 0;
123 case WDIOC_KEEPALIVE: 188 case WDIOC_KEEPALIVE:
124 if (!(wdd->info->options & WDIOF_KEEPALIVEPING)) 189 if (!(wdd->info->options & WDIOF_KEEPALIVEPING))
125 return -EOPNOTSUPP; 190 return -EOPNOTSUPP;
@@ -155,7 +220,7 @@ static int watchdog_open(struct inode *inode, struct file *file)
155 if (!try_module_get(wdd->ops->owner)) 220 if (!try_module_get(wdd->ops->owner))
156 goto out; 221 goto out;
157 222
158 err = wdd->ops->start(wdd); 223 err = watchdog_start(wdd);
159 if (err < 0) 224 if (err < 0)
160 goto out_mod; 225 goto out_mod;
161 226
@@ -181,8 +246,8 @@ static int watchdog_release(struct inode *inode, struct file *file)
181{ 246{
182 int err; 247 int err;
183 248
184 err = wdd->ops->stop(wdd); 249 err = watchdog_stop(wdd);
185 if (err != 0) { 250 if (err < 0) {
186 pr_crit("%s: watchdog did not stop!\n", wdd->info->identity); 251 pr_crit("%s: watchdog did not stop!\n", wdd->info->identity);
187 watchdog_ping(wdd); 252 watchdog_ping(wdd);
188 } 253 }
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 29ff80807dd4..db46fe89563e 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -106,6 +106,7 @@ struct watchdog_device {
106 void *driver_data; 106 void *driver_data;
107 unsigned long status; 107 unsigned long status;
108/* Bit numbers for status flags */ 108/* Bit numbers for status flags */
109#define WDOG_ACTIVE 0 /* Is the watchdog running/active */
109#define WDOG_DEV_OPEN 1 /* Opened via /dev/watchdog ? */ 110#define WDOG_DEV_OPEN 1 /* Opened via /dev/watchdog ? */
110}; 111};
111 112