[PATCH] RTC subsystem: proc interface
authorAlessandro Zummo <a.zummo@towertech.it>
Mon, 27 Mar 2006 09:16:40 +0000 (01:16 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 27 Mar 2006 16:44:51 +0000 (08:44 -0800)
Add the proc interface to the RTC subsystem.

The first RTC driver which registers with the class will be accessible by
/proc/driver/rtc .

This is required for compatibility with the standard RTC driver and to avoid
breaking any user space application which may erroneusly rely on this.

Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-proc.c [new file with mode: 0644]

index 8244999204859b3b476813ba5bdb6e8163019ab3..200fb06b788a24e7dffd2664402a1e792e906f26 100644 (file)
@@ -51,6 +51,17 @@ config RTC_INTF_SYSFS
          This driver can also be built as a module. If so, the module
          will be called rtc-sysfs.
 
+config RTC_INTF_PROC
+       tristate "proc"
+       depends on RTC_CLASS && PROC_FS
+       default RTC_CLASS
+       help
+         Say yes here if you want to use your RTC using the proc
+         interface, /proc/driver/rtc .
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-proc.
+
 comment "RTC drivers"
        depends on RTC_CLASS
 
index c44363355c2b5b4dc3a8adc672d0844ff2585c1f..137aef0e29ab14f17671293fb6c658373b0de8de 100644 (file)
@@ -8,4 +8,4 @@ obj-$(CONFIG_RTC_CLASS)         += rtc-core.o
 rtc-core-y                     := class.o interface.o
 
 obj-$(CONFIG_RTC_INTF_SYSFS)   += rtc-sysfs.o
-
+obj-$(CONFIG_RTC_INTF_PROC)    += rtc-proc.o
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
new file mode 100644 (file)
index 0000000..90b8a97
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * RTC subsystem, proc interface
+ *
+ * Copyright (C) 2005-06 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static struct class_device *rtc_dev = NULL;
+static DEFINE_MUTEX(rtc_lock);
+
+static int rtc_proc_show(struct seq_file *seq, void *offset)
+{
+       int err;
+       struct class_device *class_dev = seq->private;
+       struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
+       struct rtc_wkalrm alrm;
+       struct rtc_time tm;
+
+       err = rtc_read_time(class_dev, &tm);
+       if (err == 0) {
+               seq_printf(seq,
+                       "rtc_time\t: %02d:%02d:%02d\n"
+                       "rtc_date\t: %04d-%02d-%02d\n",
+                       tm.tm_hour, tm.tm_min, tm.tm_sec,
+                       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+       }
+
+       err = rtc_read_alarm(class_dev, &alrm);
+       if (err == 0) {
+               seq_printf(seq, "alrm_time\t: ");
+               if ((unsigned int)alrm.time.tm_hour <= 24)
+                       seq_printf(seq, "%02d:", alrm.time.tm_hour);
+               else
+                       seq_printf(seq, "**:");
+               if ((unsigned int)alrm.time.tm_min <= 59)
+                       seq_printf(seq, "%02d:", alrm.time.tm_min);
+               else
+                       seq_printf(seq, "**:");
+               if ((unsigned int)alrm.time.tm_sec <= 59)
+                       seq_printf(seq, "%02d\n", alrm.time.tm_sec);
+               else
+                       seq_printf(seq, "**\n");
+
+               seq_printf(seq, "alrm_date\t: ");
+               if ((unsigned int)alrm.time.tm_year <= 200)
+                       seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
+               else
+                       seq_printf(seq, "****-");
+               if ((unsigned int)alrm.time.tm_mon <= 11)
+                       seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
+               else
+                       seq_printf(seq, "**-");
+               if ((unsigned int)alrm.time.tm_mday <= 31)
+                       seq_printf(seq, "%02d\n", alrm.time.tm_mday);
+               else
+                       seq_printf(seq, "**\n");
+               seq_printf(seq, "alrm_wakeup\t: %s\n",
+                               alrm.enabled ? "yes" : "no");
+               seq_printf(seq, "alrm_pending\t: %s\n",
+                               alrm.pending ? "yes" : "no");
+       }
+
+       if (ops->proc)
+               ops->proc(class_dev->dev, seq);
+
+       return 0;
+}
+
+static int rtc_proc_open(struct inode *inode, struct file *file)
+{
+       struct class_device *class_dev = PDE(inode)->data;
+
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       return single_open(file, rtc_proc_show, class_dev);
+}
+
+static int rtc_proc_release(struct inode *inode, struct file *file)
+{
+       int res = single_release(inode, file);
+       module_put(THIS_MODULE);
+       return res;
+}
+
+static struct file_operations rtc_proc_fops = {
+       .open           = rtc_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = rtc_proc_release,
+};
+
+static int rtc_proc_add_device(struct class_device *class_dev,
+                                       struct class_interface *class_intf)
+{
+       mutex_lock(&rtc_lock);
+       if (rtc_dev == NULL) {
+               struct proc_dir_entry *ent;
+
+               rtc_dev = class_dev;
+
+               ent = create_proc_entry("driver/rtc", 0, NULL);
+               if (ent) {
+                       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+                       ent->proc_fops = &rtc_proc_fops;
+                       ent->owner = rtc->owner;
+                       ent->data = class_dev;
+
+                       dev_info(class_dev->dev, "rtc intf: proc\n");
+               }
+               else
+                       rtc_dev = NULL;
+       }
+       mutex_unlock(&rtc_lock);
+
+       return 0;
+}
+
+static void rtc_proc_remove_device(struct class_device *class_dev,
+                                       struct class_interface *class_intf)
+{
+       mutex_lock(&rtc_lock);
+       if (rtc_dev == class_dev) {
+               remove_proc_entry("driver/rtc", NULL);
+               rtc_dev = NULL;
+       }
+       mutex_unlock(&rtc_lock);
+}
+
+static struct class_interface rtc_proc_interface = {
+       .add = &rtc_proc_add_device,
+       .remove = &rtc_proc_remove_device,
+};
+
+static int __init rtc_proc_init(void)
+{
+       return rtc_interface_register(&rtc_proc_interface);
+}
+
+static void __exit rtc_proc_exit(void)
+{
+       class_interface_unregister(&rtc_proc_interface);
+}
+
+module_init(rtc_proc_init);
+module_exit(rtc_proc_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC class proc interface");
+MODULE_LICENSE("GPL");