diff options
author | Wim Van Sebroeck <wim@iguana.be> | 2011-07-22 14:57:55 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2011-07-28 04:01:09 -0400 |
commit | 234445b4e4542f3e0f216459245ab369a18adcf2 (patch) | |
tree | ed670bb2aa3eae41f00e5217fb786eaa9fbe6cb3 /drivers/watchdog/watchdog_dev.c | |
parent | c2dc00e494cc476551b9beeb883910391ff59737 (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>
Diffstat (limited to 'drivers/watchdog/watchdog_dev.c')
-rw-r--r-- | drivers/watchdog/watchdog_dev.c | 79 |
1 files changed, 72 insertions, 7 deletions
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 | ||
59 | static int watchdog_ping(struct watchdog_device *wddev) | 60 | static 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 | |||
80 | static 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 | |||
103 | static 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 | } |