diff options
-rw-r--r-- | drivers/watchdog/mtx-1_wdt.c | 107 |
1 files changed, 52 insertions, 55 deletions
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index a8e67383784e..e0b8cdfa5e70 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the MTX-1 Watchdog. | 2 | * Driver for the MTX-1 Watchdog. |
3 | * | 3 | * |
4 | * (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved. | 4 | * (C) Copyright 2005 4G Systems <info@4g-systems.biz>, |
5 | * All Rights Reserved. | ||
5 | * http://www.4g-systems.biz | 6 | * http://www.4g-systems.biz |
6 | * | 7 | * |
7 | * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org> | 8 | * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org> |
@@ -46,12 +47,11 @@ | |||
46 | #include <linux/jiffies.h> | 47 | #include <linux/jiffies.h> |
47 | #include <linux/watchdog.h> | 48 | #include <linux/watchdog.h> |
48 | #include <linux/platform_device.h> | 49 | #include <linux/platform_device.h> |
49 | 50 | #include <linux/io.h> | |
50 | #include <asm/io.h> | 51 | #include <linux/uaccess.h> |
51 | #include <asm/uaccess.h> | 52 | #include <linux/gpio.h> |
52 | 53 | ||
53 | #include <asm/mach-au1x00/au1000.h> | 54 | #include <asm/mach-au1x00/au1000.h> |
54 | #include <asm/gpio.h> | ||
55 | 55 | ||
56 | #define MTX1_WDT_INTERVAL (5 * HZ) | 56 | #define MTX1_WDT_INTERVAL (5 * HZ) |
57 | 57 | ||
@@ -59,6 +59,7 @@ static int ticks = 100 * HZ; | |||
59 | 59 | ||
60 | static struct { | 60 | static struct { |
61 | struct completion stop; | 61 | struct completion stop; |
62 | spinlock_t lock; | ||
62 | int running; | 63 | int running; |
63 | struct timer_list timer; | 64 | struct timer_list timer; |
64 | int queue; | 65 | int queue; |
@@ -71,6 +72,7 @@ static void mtx1_wdt_trigger(unsigned long unused) | |||
71 | { | 72 | { |
72 | u32 tmp; | 73 | u32 tmp; |
73 | 74 | ||
75 | spin_lock(&mtx1_wdt_device.lock); | ||
74 | if (mtx1_wdt_device.running) | 76 | if (mtx1_wdt_device.running) |
75 | ticks--; | 77 | ticks--; |
76 | /* | 78 | /* |
@@ -79,13 +81,13 @@ static void mtx1_wdt_trigger(unsigned long unused) | |||
79 | tmp = au_readl(GPIO2_DIR); | 81 | tmp = au_readl(GPIO2_DIR); |
80 | tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) | | 82 | tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) | |
81 | ((~tmp) & (1 << mtx1_wdt_device.gpio)); | 83 | ((~tmp) & (1 << mtx1_wdt_device.gpio)); |
82 | au_writel (tmp, GPIO2_DIR); | 84 | au_writel(tmp, GPIO2_DIR); |
83 | 85 | ||
84 | if (mtx1_wdt_device.queue && ticks) | 86 | if (mtx1_wdt_device.queue && ticks) |
85 | mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); | 87 | mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); |
86 | else { | 88 | else |
87 | complete(&mtx1_wdt_device.stop); | 89 | complete(&mtx1_wdt_device.stop); |
88 | } | 90 | spin_unlock(&mtx1_wdt_device.lock); |
89 | } | 91 | } |
90 | 92 | ||
91 | static void mtx1_wdt_reset(void) | 93 | static void mtx1_wdt_reset(void) |
@@ -96,23 +98,25 @@ static void mtx1_wdt_reset(void) | |||
96 | 98 | ||
97 | static void mtx1_wdt_start(void) | 99 | static void mtx1_wdt_start(void) |
98 | { | 100 | { |
101 | spin_lock_irqsave(&mtx1_wdt_device.lock, flags); | ||
99 | if (!mtx1_wdt_device.queue) { | 102 | if (!mtx1_wdt_device.queue) { |
100 | mtx1_wdt_device.queue = 1; | 103 | mtx1_wdt_device.queue = 1; |
101 | gpio_set_value(mtx1_wdt_device.gpio, 1); | 104 | gpio_set_value(mtx1_wdt_device.gpio, 1); |
102 | mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); | 105 | mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); |
103 | } | 106 | } |
104 | mtx1_wdt_device.running++; | 107 | mtx1_wdt_device.running++; |
108 | spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags); | ||
105 | } | 109 | } |
106 | 110 | ||
107 | static int mtx1_wdt_stop(void) | 111 | static int mtx1_wdt_stop(void) |
108 | { | 112 | { |
113 | spin_lock_irqsave(&mtx1_wdt_device.lock, flags); | ||
109 | if (mtx1_wdt_device.queue) { | 114 | if (mtx1_wdt_device.queue) { |
110 | mtx1_wdt_device.queue = 0; | 115 | mtx1_wdt_device.queue = 0; |
111 | gpio_set_value(mtx1_wdt_device.gpio, 0); | 116 | gpio_set_value(mtx1_wdt_device.gpio, 0); |
112 | } | 117 | } |
113 | |||
114 | ticks = mtx1_wdt_device.default_ticks; | 118 | ticks = mtx1_wdt_device.default_ticks; |
115 | 119 | spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags); | |
116 | return 0; | 120 | return 0; |
117 | } | 121 | } |
118 | 122 | ||
@@ -122,7 +126,6 @@ static int mtx1_wdt_open(struct inode *inode, struct file *file) | |||
122 | { | 126 | { |
123 | if (test_and_set_bit(0, &mtx1_wdt_device.inuse)) | 127 | if (test_and_set_bit(0, &mtx1_wdt_device.inuse)) |
124 | return -EBUSY; | 128 | return -EBUSY; |
125 | |||
126 | return nonseekable_open(inode, file); | 129 | return nonseekable_open(inode, file); |
127 | } | 130 | } |
128 | 131 | ||
@@ -133,54 +136,51 @@ static int mtx1_wdt_release(struct inode *inode, struct file *file) | |||
133 | return 0; | 136 | return 0; |
134 | } | 137 | } |
135 | 138 | ||
136 | static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 139 | static long mtx1_wdt_ioctl(struct file *file, unsigned int cmd, |
140 | unsigned long arg) | ||
137 | { | 141 | { |
138 | void __user *argp = (void __user *)arg; | 142 | void __user *argp = (void __user *)arg; |
143 | int __user *p = (int __user *)argp; | ||
139 | unsigned int value; | 144 | unsigned int value; |
140 | static struct watchdog_info ident = | 145 | static const struct watchdog_info ident = { |
141 | { | ||
142 | .options = WDIOF_CARDRESET, | 146 | .options = WDIOF_CARDRESET, |
143 | .identity = "MTX-1 WDT", | 147 | .identity = "MTX-1 WDT", |
144 | }; | 148 | }; |
145 | 149 | ||
146 | switch(cmd) { | 150 | switch (cmd) { |
147 | case WDIOC_KEEPALIVE: | 151 | case WDIOC_KEEPALIVE: |
148 | mtx1_wdt_reset(); | 152 | mtx1_wdt_reset(); |
149 | break; | 153 | break; |
150 | case WDIOC_GETSTATUS: | 154 | case WDIOC_GETSTATUS: |
151 | case WDIOC_GETBOOTSTATUS: | 155 | case WDIOC_GETBOOTSTATUS: |
152 | if ( copy_to_user(argp, &value, sizeof(int)) ) | 156 | put_user(0, p); |
153 | return -EFAULT; | 157 | break; |
154 | break; | 158 | case WDIOC_GETSUPPORT: |
155 | case WDIOC_GETSUPPORT: | 159 | if (copy_to_user(argp, &ident, sizeof(ident))) |
156 | if ( copy_to_user(argp, &ident, sizeof(ident)) ) | 160 | return -EFAULT; |
157 | return -EFAULT; | 161 | break; |
158 | break; | 162 | case WDIOC_SETOPTIONS: |
159 | case WDIOC_SETOPTIONS: | 163 | if (get_user(value, p)) |
160 | if ( copy_from_user(&value, argp, sizeof(int)) ) | 164 | return -EFAULT; |
161 | return -EFAULT; | 165 | if (value & WDIOS_ENABLECARD) |
162 | switch(value) { | 166 | mtx1_wdt_start(); |
163 | case WDIOS_ENABLECARD: | 167 | else if (value & WDIOS_DISABLECARD) |
164 | mtx1_wdt_start(); | 168 | mtx1_wdt_stop(); |
165 | break; | 169 | else |
166 | case WDIOS_DISABLECARD: | 170 | return -EINVAL; |
167 | return mtx1_wdt_stop(); | 171 | return 0; |
168 | default: | 172 | default: |
169 | return -EINVAL; | 173 | return -ENOTTY; |
170 | } | ||
171 | break; | ||
172 | default: | ||
173 | return -ENOTTY; | ||
174 | } | 174 | } |
175 | return 0; | 175 | return 0; |
176 | } | 176 | } |
177 | 177 | ||
178 | 178 | ||
179 | static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) | 179 | static ssize_t mtx1_wdt_write(struct file *file, const char *buf, |
180 | size_t count, loff_t *ppos) | ||
180 | { | 181 | { |
181 | if (!count) | 182 | if (!count) |
182 | return -EIO; | 183 | return -EIO; |
183 | |||
184 | mtx1_wdt_reset(); | 184 | mtx1_wdt_reset(); |
185 | return count; | 185 | return count; |
186 | } | 186 | } |
@@ -188,7 +188,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, | |||
188 | static const struct file_operations mtx1_wdt_fops = { | 188 | static const struct file_operations mtx1_wdt_fops = { |
189 | .owner = THIS_MODULE, | 189 | .owner = THIS_MODULE, |
190 | .llseek = no_llseek, | 190 | .llseek = no_llseek, |
191 | .ioctl = mtx1_wdt_ioctl, | 191 | .unlocked_ioctl = mtx1_wdt_ioctl, |
192 | .open = mtx1_wdt_open, | 192 | .open = mtx1_wdt_open, |
193 | .write = mtx1_wdt_write, | 193 | .write = mtx1_wdt_write, |
194 | .release = mtx1_wdt_release | 194 | .release = mtx1_wdt_release |
@@ -208,29 +208,26 @@ static int mtx1_wdt_probe(struct platform_device *pdev) | |||
208 | 208 | ||
209 | mtx1_wdt_device.gpio = pdev->resource[0].start; | 209 | mtx1_wdt_device.gpio = pdev->resource[0].start; |
210 | 210 | ||
211 | if ((ret = misc_register(&mtx1_wdt_misc)) < 0) { | 211 | spin_lock_init(&mtx1_wdt_device.lock); |
212 | printk(KERN_ERR " mtx-1_wdt : failed to register\n"); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | init_completion(&mtx1_wdt_device.stop); | 212 | init_completion(&mtx1_wdt_device.stop); |
217 | mtx1_wdt_device.queue = 0; | 213 | mtx1_wdt_device.queue = 0; |
218 | |||
219 | clear_bit(0, &mtx1_wdt_device.inuse); | 214 | clear_bit(0, &mtx1_wdt_device.inuse); |
220 | |||
221 | setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L); | 215 | setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L); |
222 | |||
223 | mtx1_wdt_device.default_ticks = ticks; | 216 | mtx1_wdt_device.default_ticks = ticks; |
224 | 217 | ||
218 | ret = misc_register(&mtx1_wdt_misc); | ||
219 | if (ret < 0) { | ||
220 | printk(KERN_ERR " mtx-1_wdt : failed to register\n"); | ||
221 | return ret; | ||
222 | } | ||
225 | mtx1_wdt_start(); | 223 | mtx1_wdt_start(); |
226 | |||
227 | printk(KERN_INFO "MTX-1 Watchdog driver\n"); | 224 | printk(KERN_INFO "MTX-1 Watchdog driver\n"); |
228 | |||
229 | return 0; | 225 | return 0; |
230 | } | 226 | } |
231 | 227 | ||
232 | static int mtx1_wdt_remove(struct platform_device *pdev) | 228 | static int mtx1_wdt_remove(struct platform_device *pdev) |
233 | { | 229 | { |
230 | /* FIXME: do we need to lock this test ? */ | ||
234 | if (mtx1_wdt_device.queue) { | 231 | if (mtx1_wdt_device.queue) { |
235 | mtx1_wdt_device.queue = 0; | 232 | mtx1_wdt_device.queue = 0; |
236 | wait_for_completion(&mtx1_wdt_device.stop); | 233 | wait_for_completion(&mtx1_wdt_device.stop); |