From f118420be83c3ce7888fe1d42db84af495da9edb Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 27 Sep 2006 17:53:59 +0900 Subject: [PATCH 1/1] watchdog: Add a simple mmap() stub for shwdt. In some applications people have expressed a need for an mmap() method, so we implement a simple stub for this that maps back a page with the counter in it. Signed-off-by: Paul Mundt --- drivers/char/watchdog/Kconfig | 8 ++++++ drivers/char/watchdog/shwdt.c | 52 ++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index fff89c2d88f..f114d7b5bb2 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -510,6 +510,14 @@ config SH_WDT To compile this driver as a module, choose M here: the module will be called shwdt. +config SH_WDT_MMAP + bool "Allow mmap of SH WDT" + default n + depends on SH_WDT + help + If you say Y here, user applications will be able to mmap the + WDT/CPG registers. +# # SPARC64 Architecture config WATCHDOG_CP1XXX diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c index 7c39f39effd..e5b8c64f1d6 100644 --- a/drivers/char/watchdog/shwdt.c +++ b/drivers/char/watchdog/shwdt.c @@ -27,7 +27,7 @@ #include #include #include - +#include #include #include #include @@ -257,6 +257,55 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf, return count; } +/** + * sh_wdt_mmap - map WDT/CPG registers into userspace + * @file: file structure for the device + * @vma: VMA to map the registers into + * + * A simple mmap() implementation for the corner cases where the counter + * needs to be mapped in userspace directly. Due to the relatively small + * size of the area, neighbouring registers not necessarily tied to the + * CPG will also be accessible through the register page, so this remains + * configurable for users that really know what they're doing. + * + * Additionaly, the register page maps in the CPG register base relative + * to the nearest page-aligned boundary, which requires that userspace do + * the appropriate CPU subtype math for calculating the page offset for + * the counter value. + */ +static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) +{ + int ret = -ENOSYS; + +#ifdef CONFIG_SH_WDT_MMAP + unsigned long addr; + + /* Only support the simple cases where we map in a register page. */ + if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff) + return -EINVAL; + + /* + * Pick WTCNT as the start, it's usually the first register after the + * FRQCR, and neither one are generally page-aligned out of the box. + */ + addr = WTCNT & ~(PAGE_SIZE - 1); + + vma->vm_flags |= VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot)) { + printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", + __FUNCTION__); + return -EAGAIN; + } + + ret = 0; +#endif + + return ret; +} + /** * sh_wdt_ioctl - Query Device * @inode: inode of device @@ -342,6 +391,7 @@ static const struct file_operations sh_wdt_fops = { .ioctl = sh_wdt_ioctl, .open = sh_wdt_open, .release = sh_wdt_close, + .mmap = sh_wdt_mmap, }; static struct watchdog_info sh_wdt_info = { -- 2.39.2