diff options
author | Alessandro Zummo <a.zummo@towertech.it> | 2006-03-27 04:16:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-27 11:44:51 -0500 |
commit | 728a294787b780130d8eb237518d4cac0afe760c (patch) | |
tree | fd9b4b87dc963397bb3e4e8ed003b565353eef29 | |
parent | c5c3e19225217536d90515c494e55e642a21e4fa (diff) |
[PATCH] RTC subsystem: proc interface
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>
-rw-r--r-- | drivers/rtc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-proc.c | 162 |
3 files changed, 174 insertions, 1 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 824499920485..200fb06b788a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -51,6 +51,17 @@ config RTC_INTF_SYSFS | |||
51 | This driver can also be built as a module. If so, the module | 51 | This driver can also be built as a module. If so, the module |
52 | will be called rtc-sysfs. | 52 | will be called rtc-sysfs. |
53 | 53 | ||
54 | config RTC_INTF_PROC | ||
55 | tristate "proc" | ||
56 | depends on RTC_CLASS && PROC_FS | ||
57 | default RTC_CLASS | ||
58 | help | ||
59 | Say yes here if you want to use your RTC using the proc | ||
60 | interface, /proc/driver/rtc . | ||
61 | |||
62 | This driver can also be built as a module. If so, the module | ||
63 | will be called rtc-proc. | ||
64 | |||
54 | comment "RTC drivers" | 65 | comment "RTC drivers" |
55 | depends on RTC_CLASS | 66 | depends on RTC_CLASS |
56 | 67 | ||
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c44363355c2b..137aef0e29ab 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -8,4 +8,4 @@ obj-$(CONFIG_RTC_CLASS) += rtc-core.o | |||
8 | rtc-core-y := class.o interface.o | 8 | rtc-core-y := class.o interface.o |
9 | 9 | ||
10 | obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o | 10 | obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o |
11 | 11 | 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 index 000000000000..90b8a97a0919 --- /dev/null +++ b/drivers/rtc/rtc-proc.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * RTC subsystem, proc interface | ||
3 | * | ||
4 | * Copyright (C) 2005-06 Tower Technologies | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * based on arch/arm/common/rtctime.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/rtc.h> | ||
16 | #include <linux/proc_fs.h> | ||
17 | #include <linux/seq_file.h> | ||
18 | |||
19 | static struct class_device *rtc_dev = NULL; | ||
20 | static DEFINE_MUTEX(rtc_lock); | ||
21 | |||
22 | static int rtc_proc_show(struct seq_file *seq, void *offset) | ||
23 | { | ||
24 | int err; | ||
25 | struct class_device *class_dev = seq->private; | ||
26 | struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops; | ||
27 | struct rtc_wkalrm alrm; | ||
28 | struct rtc_time tm; | ||
29 | |||
30 | err = rtc_read_time(class_dev, &tm); | ||
31 | if (err == 0) { | ||
32 | seq_printf(seq, | ||
33 | "rtc_time\t: %02d:%02d:%02d\n" | ||
34 | "rtc_date\t: %04d-%02d-%02d\n", | ||
35 | tm.tm_hour, tm.tm_min, tm.tm_sec, | ||
36 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | ||
37 | } | ||
38 | |||
39 | err = rtc_read_alarm(class_dev, &alrm); | ||
40 | if (err == 0) { | ||
41 | seq_printf(seq, "alrm_time\t: "); | ||
42 | if ((unsigned int)alrm.time.tm_hour <= 24) | ||
43 | seq_printf(seq, "%02d:", alrm.time.tm_hour); | ||
44 | else | ||
45 | seq_printf(seq, "**:"); | ||
46 | if ((unsigned int)alrm.time.tm_min <= 59) | ||
47 | seq_printf(seq, "%02d:", alrm.time.tm_min); | ||
48 | else | ||
49 | seq_printf(seq, "**:"); | ||
50 | if ((unsigned int)alrm.time.tm_sec <= 59) | ||
51 | seq_printf(seq, "%02d\n", alrm.time.tm_sec); | ||
52 | else | ||
53 | seq_printf(seq, "**\n"); | ||
54 | |||
55 | seq_printf(seq, "alrm_date\t: "); | ||
56 | if ((unsigned int)alrm.time.tm_year <= 200) | ||
57 | seq_printf(seq, "%04d-", alrm.time.tm_year + 1900); | ||
58 | else | ||
59 | seq_printf(seq, "****-"); | ||
60 | if ((unsigned int)alrm.time.tm_mon <= 11) | ||
61 | seq_printf(seq, "%02d-", alrm.time.tm_mon + 1); | ||
62 | else | ||
63 | seq_printf(seq, "**-"); | ||
64 | if ((unsigned int)alrm.time.tm_mday <= 31) | ||
65 | seq_printf(seq, "%02d\n", alrm.time.tm_mday); | ||
66 | else | ||
67 | seq_printf(seq, "**\n"); | ||
68 | seq_printf(seq, "alrm_wakeup\t: %s\n", | ||
69 | alrm.enabled ? "yes" : "no"); | ||
70 | seq_printf(seq, "alrm_pending\t: %s\n", | ||
71 | alrm.pending ? "yes" : "no"); | ||
72 | } | ||
73 | |||
74 | if (ops->proc) | ||
75 | ops->proc(class_dev->dev, seq); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int rtc_proc_open(struct inode *inode, struct file *file) | ||
81 | { | ||
82 | struct class_device *class_dev = PDE(inode)->data; | ||
83 | |||
84 | if (!try_module_get(THIS_MODULE)) | ||
85 | return -ENODEV; | ||
86 | |||
87 | return single_open(file, rtc_proc_show, class_dev); | ||
88 | } | ||
89 | |||
90 | static int rtc_proc_release(struct inode *inode, struct file *file) | ||
91 | { | ||
92 | int res = single_release(inode, file); | ||
93 | module_put(THIS_MODULE); | ||
94 | return res; | ||
95 | } | ||
96 | |||
97 | static struct file_operations rtc_proc_fops = { | ||
98 | .open = rtc_proc_open, | ||
99 | .read = seq_read, | ||
100 | .llseek = seq_lseek, | ||
101 | .release = rtc_proc_release, | ||
102 | }; | ||
103 | |||
104 | static int rtc_proc_add_device(struct class_device *class_dev, | ||
105 | struct class_interface *class_intf) | ||
106 | { | ||
107 | mutex_lock(&rtc_lock); | ||
108 | if (rtc_dev == NULL) { | ||
109 | struct proc_dir_entry *ent; | ||
110 | |||
111 | rtc_dev = class_dev; | ||
112 | |||
113 | ent = create_proc_entry("driver/rtc", 0, NULL); | ||
114 | if (ent) { | ||
115 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
116 | |||
117 | ent->proc_fops = &rtc_proc_fops; | ||
118 | ent->owner = rtc->owner; | ||
119 | ent->data = class_dev; | ||
120 | |||
121 | dev_info(class_dev->dev, "rtc intf: proc\n"); | ||
122 | } | ||
123 | else | ||
124 | rtc_dev = NULL; | ||
125 | } | ||
126 | mutex_unlock(&rtc_lock); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void rtc_proc_remove_device(struct class_device *class_dev, | ||
132 | struct class_interface *class_intf) | ||
133 | { | ||
134 | mutex_lock(&rtc_lock); | ||
135 | if (rtc_dev == class_dev) { | ||
136 | remove_proc_entry("driver/rtc", NULL); | ||
137 | rtc_dev = NULL; | ||
138 | } | ||
139 | mutex_unlock(&rtc_lock); | ||
140 | } | ||
141 | |||
142 | static struct class_interface rtc_proc_interface = { | ||
143 | .add = &rtc_proc_add_device, | ||
144 | .remove = &rtc_proc_remove_device, | ||
145 | }; | ||
146 | |||
147 | static int __init rtc_proc_init(void) | ||
148 | { | ||
149 | return rtc_interface_register(&rtc_proc_interface); | ||
150 | } | ||
151 | |||
152 | static void __exit rtc_proc_exit(void) | ||
153 | { | ||
154 | class_interface_unregister(&rtc_proc_interface); | ||
155 | } | ||
156 | |||
157 | module_init(rtc_proc_init); | ||
158 | module_exit(rtc_proc_exit); | ||
159 | |||
160 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
161 | MODULE_DESCRIPTION("RTC class proc interface"); | ||
162 | MODULE_LICENSE("GPL"); | ||