diff options
| author | Wim Van Sebroeck <wim@iguana.be> | 2007-06-20 17:36:43 -0400 |
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2007-07-05 01:34:14 -0400 |
| commit | 28401140a27b7ebc5a686dbfc345e3724d274738 (patch) | |
| tree | 95ee8280851944ca3c0089187ebe61da53bbfef9 | |
| parent | 726c9f611a4079b5265e7ede1d66ed455ac6343c (diff) | |
[WATCHDOG] at32ap700x_wdt.c - Add nowayout + MAGICCLOSE features
Add nowayout + MAGICCLOSE features.
Signed-off-by: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
Cc: Haavard Skinnemoen <hskinnemoen@atmel.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Cc: Andrew Morton <akpm@linux-foundation.org>
| -rw-r--r-- | drivers/char/watchdog/at32ap700x_wdt.c | 64 |
1 files changed, 53 insertions, 11 deletions
diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index 6e7c9588b1b9..fcd55c600b87 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c | |||
| @@ -30,6 +30,11 @@ MODULE_PARM_DESC(timeout, | |||
| 30 | "Timeout value. Limited to be 1 or 2 seconds. (default=" | 30 | "Timeout value. Limited to be 1 or 2 seconds. (default=" |
| 31 | __MODULE_STRING(TIMEOUT_DEFAULT) ")"); | 31 | __MODULE_STRING(TIMEOUT_DEFAULT) ")"); |
| 32 | 32 | ||
| 33 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
| 34 | module_param(nowayout, int, 0); | ||
| 35 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | ||
| 36 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 37 | |||
| 33 | /* Watchdog registers and write/read macro */ | 38 | /* Watchdog registers and write/read macro */ |
| 34 | #define WDT_CTRL 0x00 | 39 | #define WDT_CTRL 0x00 |
| 35 | #define WDT_CTRL_EN 0 | 40 | #define WDT_CTRL_EN 0 |
| @@ -54,6 +59,7 @@ struct wdt_at32ap700x { | |||
| 54 | }; | 59 | }; |
| 55 | 60 | ||
| 56 | static struct wdt_at32ap700x *wdt; | 61 | static struct wdt_at32ap700x *wdt; |
| 62 | static char expect_release; | ||
| 57 | 63 | ||
| 58 | /* | 64 | /* |
| 59 | * Disable the watchdog. | 65 | * Disable the watchdog. |
| @@ -102,15 +108,19 @@ static int at32_wdt_open(struct inode *inode, struct file *file) | |||
| 102 | } | 108 | } |
| 103 | 109 | ||
| 104 | /* | 110 | /* |
| 105 | * Close the watchdog device. If CONFIG_WATCHDOG_NOWAYOUT is _not_ defined then | 111 | * Close the watchdog device. |
| 106 | * the watchdog is also disabled. | ||
| 107 | */ | 112 | */ |
| 108 | static int at32_wdt_close(struct inode *inode, struct file *file) | 113 | static int at32_wdt_close(struct inode *inode, struct file *file) |
| 109 | { | 114 | { |
| 110 | #ifndef CONFIG_WATCHDOG_NOWAYOUT | 115 | if (expect_release == 42) { |
| 111 | at32_wdt_stop(); | 116 | at32_wdt_stop(); |
| 112 | #endif | 117 | } else { |
| 118 | dev_dbg(wdt->miscdev.parent, | ||
| 119 | "Unexpected close, not stopping watchdog!\n"); | ||
| 120 | at32_wdt_pat(); | ||
| 121 | } | ||
| 113 | clear_bit(1, &wdt->users); | 122 | clear_bit(1, &wdt->users); |
| 123 | expect_release = 0; | ||
| 114 | return 0; | 124 | return 0; |
| 115 | } | 125 | } |
| 116 | 126 | ||
| @@ -136,7 +146,9 @@ static int at32_wdt_settimeout(int time) | |||
| 136 | 146 | ||
| 137 | static struct watchdog_info at32_wdt_info = { | 147 | static struct watchdog_info at32_wdt_info = { |
| 138 | .identity = "at32ap700x watchdog", | 148 | .identity = "at32ap700x watchdog", |
| 139 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 149 | .options = WDIOF_SETTIMEOUT | |
| 150 | WDIOF_KEEPALIVEPING | | ||
| 151 | WDIOF_MAGICCLOSE, | ||
| 140 | }; | 152 | }; |
| 141 | 153 | ||
| 142 | /* | 154 | /* |
| @@ -191,10 +203,35 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, | |||
| 191 | return ret; | 203 | return ret; |
| 192 | } | 204 | } |
| 193 | 205 | ||
| 194 | static ssize_t at32_wdt_write(struct file *file, const char *data, size_t len, | 206 | static ssize_t at32_wdt_write(struct file *file, const char __user *data, |
| 195 | loff_t *ppos) | 207 | size_t len, loff_t *ppos) |
| 196 | { | 208 | { |
| 197 | at32_wdt_pat(); | 209 | /* See if we got the magic character 'V' and reload the timer */ |
| 210 | if (len) { | ||
| 211 | if (!nowayout) { | ||
| 212 | size_t i; | ||
| 213 | |||
| 214 | /* | ||
| 215 | * note: just in case someone wrote the magic | ||
| 216 | * character five months ago... | ||
| 217 | */ | ||
| 218 | expect_release = 0; | ||
| 219 | |||
| 220 | /* | ||
| 221 | * scan to see whether or not we got the magic | ||
| 222 | * character | ||
| 223 | */ | ||
| 224 | for (i = 0; i != len; i++) { | ||
| 225 | char c; | ||
| 226 | if (get_user(c, data+i)) | ||
| 227 | return -EFAULT; | ||
| 228 | if (c == 'V') | ||
| 229 | expect_release = 42; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | /* someone wrote to us, we should pat the watchdog */ | ||
| 233 | at32_wdt_pat(); | ||
| 234 | } | ||
| 198 | return len; | 235 | return len; |
| 199 | } | 236 | } |
| 200 | 237 | ||
| @@ -255,8 +292,9 @@ static int __init at32_wdt_probe(struct platform_device *pdev) | |||
| 255 | 292 | ||
| 256 | platform_set_drvdata(pdev, wdt); | 293 | platform_set_drvdata(pdev, wdt); |
| 257 | wdt->miscdev.parent = &pdev->dev; | 294 | wdt->miscdev.parent = &pdev->dev; |
| 258 | dev_info(&pdev->dev, "AT32AP700X WDT at 0x%p, timeout %d sec\n", | 295 | dev_info(&pdev->dev, |
| 259 | wdt->regs, wdt->timeout); | 296 | "AT32AP700X WDT at 0x%p, timeout %d sec (nowayout=%d)\n", |
| 297 | wdt->regs, wdt->timeout, nowayout); | ||
| 260 | 298 | ||
| 261 | return 0; | 299 | return 0; |
| 262 | 300 | ||
| @@ -271,6 +309,10 @@ err_free: | |||
| 271 | static int __exit at32_wdt_remove(struct platform_device *pdev) | 309 | static int __exit at32_wdt_remove(struct platform_device *pdev) |
| 272 | { | 310 | { |
| 273 | if (wdt && platform_get_drvdata(pdev) == wdt) { | 311 | if (wdt && platform_get_drvdata(pdev) == wdt) { |
| 312 | /* Stop the timer before we leave */ | ||
| 313 | if (!nowayout) | ||
| 314 | at32_wdt_stop(); | ||
| 315 | |||
| 274 | misc_deregister(&wdt->miscdev); | 316 | misc_deregister(&wdt->miscdev); |
| 275 | iounmap(wdt->regs); | 317 | iounmap(wdt->regs); |
| 276 | kfree(wdt); | 318 | kfree(wdt); |
