diff options
-rw-r--r-- | drivers/char/watchdog/Kconfig | 8 | ||||
-rw-r--r-- | drivers/char/watchdog/shwdt.c | 52 |
2 files changed, 59 insertions, 1 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index fff89c2d88fd..f114d7b5bb2a 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
@@ -510,6 +510,14 @@ config SH_WDT | |||
510 | To compile this driver as a module, choose M here: the | 510 | To compile this driver as a module, choose M here: the |
511 | module will be called shwdt. | 511 | module will be called shwdt. |
512 | 512 | ||
513 | config SH_WDT_MMAP | ||
514 | bool "Allow mmap of SH WDT" | ||
515 | default n | ||
516 | depends on SH_WDT | ||
517 | help | ||
518 | If you say Y here, user applications will be able to mmap the | ||
519 | WDT/CPG registers. | ||
520 | # | ||
513 | # SPARC64 Architecture | 521 | # SPARC64 Architecture |
514 | 522 | ||
515 | config WATCHDOG_CP1XXX | 523 | config WATCHDOG_CP1XXX |
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c index 7c39f39effdf..e5b8c64f1d65 100644 --- a/drivers/char/watchdog/shwdt.c +++ b/drivers/char/watchdog/shwdt.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/notifier.h> | 27 | #include <linux/notifier.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | 30 | #include <linux/mm.h> | |
31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
33 | #include <asm/watchdog.h> | 33 | #include <asm/watchdog.h> |
@@ -258,6 +258,55 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf, | |||
258 | } | 258 | } |
259 | 259 | ||
260 | /** | 260 | /** |
261 | * sh_wdt_mmap - map WDT/CPG registers into userspace | ||
262 | * @file: file structure for the device | ||
263 | * @vma: VMA to map the registers into | ||
264 | * | ||
265 | * A simple mmap() implementation for the corner cases where the counter | ||
266 | * needs to be mapped in userspace directly. Due to the relatively small | ||
267 | * size of the area, neighbouring registers not necessarily tied to the | ||
268 | * CPG will also be accessible through the register page, so this remains | ||
269 | * configurable for users that really know what they're doing. | ||
270 | * | ||
271 | * Additionaly, the register page maps in the CPG register base relative | ||
272 | * to the nearest page-aligned boundary, which requires that userspace do | ||
273 | * the appropriate CPU subtype math for calculating the page offset for | ||
274 | * the counter value. | ||
275 | */ | ||
276 | static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) | ||
277 | { | ||
278 | int ret = -ENOSYS; | ||
279 | |||
280 | #ifdef CONFIG_SH_WDT_MMAP | ||
281 | unsigned long addr; | ||
282 | |||
283 | /* Only support the simple cases where we map in a register page. */ | ||
284 | if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff) | ||
285 | return -EINVAL; | ||
286 | |||
287 | /* | ||
288 | * Pick WTCNT as the start, it's usually the first register after the | ||
289 | * FRQCR, and neither one are generally page-aligned out of the box. | ||
290 | */ | ||
291 | addr = WTCNT & ~(PAGE_SIZE - 1); | ||
292 | |||
293 | vma->vm_flags |= VM_IO; | ||
294 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
295 | |||
296 | if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, | ||
297 | PAGE_SIZE, vma->vm_page_prot)) { | ||
298 | printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", | ||
299 | __FUNCTION__); | ||
300 | return -EAGAIN; | ||
301 | } | ||
302 | |||
303 | ret = 0; | ||
304 | #endif | ||
305 | |||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | /** | ||
261 | * sh_wdt_ioctl - Query Device | 310 | * sh_wdt_ioctl - Query Device |
262 | * @inode: inode of device | 311 | * @inode: inode of device |
263 | * @file: file handle of device | 312 | * @file: file handle of device |
@@ -342,6 +391,7 @@ static const struct file_operations sh_wdt_fops = { | |||
342 | .ioctl = sh_wdt_ioctl, | 391 | .ioctl = sh_wdt_ioctl, |
343 | .open = sh_wdt_open, | 392 | .open = sh_wdt_open, |
344 | .release = sh_wdt_close, | 393 | .release = sh_wdt_close, |
394 | .mmap = sh_wdt_mmap, | ||
345 | }; | 395 | }; |
346 | 396 | ||
347 | static struct watchdog_info sh_wdt_info = { | 397 | static struct watchdog_info sh_wdt_info = { |