1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * RTC subsystem, sysfs interface |
4 | * |
5 | * Copyright (C) 2005 Tower Technologies |
6 | * Author: Alessandro Zummo <a.zummo@towertech.it> |
7 | */ |
8 | |
9 | #include <linux/kstrtox.h> |
10 | #include <linux/module.h> |
11 | #include <linux/rtc.h> |
12 | |
13 | #include "rtc-core.h" |
14 | |
15 | /* device attributes */ |
16 | |
17 | /* |
18 | * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's |
19 | * ideally UTC. However, PCs that also boot to MS-Windows normally use |
20 | * the local time and change to match daylight savings time. That affects |
21 | * attributes including date, time, since_epoch, and wakealarm. |
22 | */ |
23 | |
24 | static ssize_t |
25 | name_show(struct device *dev, struct device_attribute *attr, char *buf) |
26 | { |
27 | return sprintf(buf, fmt: "%s %s\n" , dev_driver_string(dev: dev->parent), |
28 | dev_name(dev: dev->parent)); |
29 | } |
30 | static DEVICE_ATTR_RO(name); |
31 | |
32 | static ssize_t |
33 | date_show(struct device *dev, struct device_attribute *attr, char *buf) |
34 | { |
35 | ssize_t retval; |
36 | struct rtc_time tm; |
37 | |
38 | retval = rtc_read_time(to_rtc_device(dev), tm: &tm); |
39 | if (retval) |
40 | return retval; |
41 | |
42 | return sprintf(buf, fmt: "%ptRd\n" , &tm); |
43 | } |
44 | static DEVICE_ATTR_RO(date); |
45 | |
46 | static ssize_t |
47 | time_show(struct device *dev, struct device_attribute *attr, char *buf) |
48 | { |
49 | ssize_t retval; |
50 | struct rtc_time tm; |
51 | |
52 | retval = rtc_read_time(to_rtc_device(dev), tm: &tm); |
53 | if (retval) |
54 | return retval; |
55 | |
56 | return sprintf(buf, fmt: "%ptRt\n" , &tm); |
57 | } |
58 | static DEVICE_ATTR_RO(time); |
59 | |
60 | static ssize_t |
61 | since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) |
62 | { |
63 | ssize_t retval; |
64 | struct rtc_time tm; |
65 | |
66 | retval = rtc_read_time(to_rtc_device(dev), tm: &tm); |
67 | if (retval == 0) { |
68 | time64_t time; |
69 | |
70 | time = rtc_tm_to_time64(tm: &tm); |
71 | retval = sprintf(buf, fmt: "%lld\n" , time); |
72 | } |
73 | |
74 | return retval; |
75 | } |
76 | static DEVICE_ATTR_RO(since_epoch); |
77 | |
78 | static ssize_t |
79 | max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) |
80 | { |
81 | return sprintf(buf, fmt: "%d\n" , to_rtc_device(dev)->max_user_freq); |
82 | } |
83 | |
84 | static ssize_t |
85 | max_user_freq_store(struct device *dev, struct device_attribute *attr, |
86 | const char *buf, size_t n) |
87 | { |
88 | struct rtc_device *rtc = to_rtc_device(dev); |
89 | unsigned long val; |
90 | int err; |
91 | |
92 | err = kstrtoul(s: buf, base: 0, res: &val); |
93 | if (err) |
94 | return err; |
95 | |
96 | if (val >= 4096 || val == 0) |
97 | return -EINVAL; |
98 | |
99 | rtc->max_user_freq = (int)val; |
100 | |
101 | return n; |
102 | } |
103 | static DEVICE_ATTR_RW(max_user_freq); |
104 | |
105 | /** |
106 | * hctosys_show - indicate if the given RTC set the system time |
107 | * @dev: The device that the attribute belongs to. |
108 | * @attr: The attribute being read. |
109 | * @buf: The result buffer. |
110 | * |
111 | * buf is "1" if the system clock was set by this RTC at the last |
112 | * boot or resume event. |
113 | */ |
114 | static ssize_t |
115 | hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) |
116 | { |
117 | #ifdef CONFIG_RTC_HCTOSYS_DEVICE |
118 | if (rtc_hctosys_ret == 0 && |
119 | strcmp(dev_name(dev: &to_rtc_device(dev)->dev), |
120 | CONFIG_RTC_HCTOSYS_DEVICE) == 0) |
121 | return sprintf(buf, fmt: "1\n" ); |
122 | #endif |
123 | return sprintf(buf, fmt: "0\n" ); |
124 | } |
125 | static DEVICE_ATTR_RO(hctosys); |
126 | |
127 | static ssize_t |
128 | wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) |
129 | { |
130 | ssize_t retval; |
131 | time64_t alarm; |
132 | struct rtc_wkalrm alm; |
133 | |
134 | /* Don't show disabled alarms. For uniformity, RTC alarms are |
135 | * conceptually one-shot, even though some common RTCs (on PCs) |
136 | * don't actually work that way. |
137 | * |
138 | * NOTE: RTC implementations where the alarm doesn't match an |
139 | * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC |
140 | * alarms after they trigger, to ensure one-shot semantics. |
141 | */ |
142 | retval = rtc_read_alarm(to_rtc_device(dev), alrm: &alm); |
143 | if (retval == 0 && alm.enabled) { |
144 | alarm = rtc_tm_to_time64(tm: &alm.time); |
145 | retval = sprintf(buf, fmt: "%lld\n" , alarm); |
146 | } |
147 | |
148 | return retval; |
149 | } |
150 | |
151 | static ssize_t |
152 | wakealarm_store(struct device *dev, struct device_attribute *attr, |
153 | const char *buf, size_t n) |
154 | { |
155 | ssize_t retval; |
156 | time64_t now, alarm; |
157 | time64_t push = 0; |
158 | struct rtc_wkalrm alm; |
159 | struct rtc_device *rtc = to_rtc_device(dev); |
160 | const char *buf_ptr; |
161 | int adjust = 0; |
162 | |
163 | /* Only request alarms that trigger in the future. Disable them |
164 | * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. |
165 | */ |
166 | retval = rtc_read_time(rtc, tm: &alm.time); |
167 | if (retval < 0) |
168 | return retval; |
169 | now = rtc_tm_to_time64(tm: &alm.time); |
170 | |
171 | buf_ptr = buf; |
172 | if (*buf_ptr == '+') { |
173 | buf_ptr++; |
174 | if (*buf_ptr == '=') { |
175 | buf_ptr++; |
176 | push = 1; |
177 | } else { |
178 | adjust = 1; |
179 | } |
180 | } |
181 | retval = kstrtos64(s: buf_ptr, base: 0, res: &alarm); |
182 | if (retval) |
183 | return retval; |
184 | if (adjust) |
185 | alarm += now; |
186 | if (alarm > now || push) { |
187 | /* Avoid accidentally clobbering active alarms; we can't |
188 | * entirely prevent that here, without even the minimal |
189 | * locking from the /dev/rtcN api. |
190 | */ |
191 | retval = rtc_read_alarm(rtc, alrm: &alm); |
192 | if (retval < 0) |
193 | return retval; |
194 | if (alm.enabled) { |
195 | if (push) { |
196 | push = rtc_tm_to_time64(tm: &alm.time); |
197 | alarm += push; |
198 | } else |
199 | return -EBUSY; |
200 | } else if (push) |
201 | return -EINVAL; |
202 | alm.enabled = 1; |
203 | } else { |
204 | alm.enabled = 0; |
205 | |
206 | /* Provide a valid future alarm time. Linux isn't EFI, |
207 | * this time won't be ignored when disabling the alarm. |
208 | */ |
209 | alarm = now + 300; |
210 | } |
211 | rtc_time64_to_tm(time: alarm, tm: &alm.time); |
212 | |
213 | retval = rtc_set_alarm(rtc, alrm: &alm); |
214 | return (retval < 0) ? retval : n; |
215 | } |
216 | static DEVICE_ATTR_RW(wakealarm); |
217 | |
218 | static ssize_t |
219 | offset_show(struct device *dev, struct device_attribute *attr, char *buf) |
220 | { |
221 | ssize_t retval; |
222 | long offset; |
223 | |
224 | retval = rtc_read_offset(to_rtc_device(dev), offset: &offset); |
225 | if (retval == 0) |
226 | retval = sprintf(buf, fmt: "%ld\n" , offset); |
227 | |
228 | return retval; |
229 | } |
230 | |
231 | static ssize_t |
232 | offset_store(struct device *dev, struct device_attribute *attr, |
233 | const char *buf, size_t n) |
234 | { |
235 | ssize_t retval; |
236 | long offset; |
237 | |
238 | retval = kstrtol(s: buf, base: 10, res: &offset); |
239 | if (retval == 0) |
240 | retval = rtc_set_offset(to_rtc_device(dev), offset); |
241 | |
242 | return (retval < 0) ? retval : n; |
243 | } |
244 | static DEVICE_ATTR_RW(offset); |
245 | |
246 | static ssize_t |
247 | range_show(struct device *dev, struct device_attribute *attr, char *buf) |
248 | { |
249 | return sprintf(buf, fmt: "[%lld,%llu]\n" , to_rtc_device(dev)->range_min, |
250 | to_rtc_device(dev)->range_max); |
251 | } |
252 | static DEVICE_ATTR_RO(range); |
253 | |
254 | static struct attribute *rtc_attrs[] = { |
255 | &dev_attr_name.attr, |
256 | &dev_attr_date.attr, |
257 | &dev_attr_time.attr, |
258 | &dev_attr_since_epoch.attr, |
259 | &dev_attr_max_user_freq.attr, |
260 | &dev_attr_hctosys.attr, |
261 | &dev_attr_wakealarm.attr, |
262 | &dev_attr_offset.attr, |
263 | &dev_attr_range.attr, |
264 | NULL, |
265 | }; |
266 | |
267 | /* The reason to trigger an alarm with no process watching it (via sysfs) |
268 | * is its side effect: waking from a system state like suspend-to-RAM or |
269 | * suspend-to-disk. So: no attribute unless that side effect is possible. |
270 | * (Userspace may disable that mechanism later.) |
271 | */ |
272 | static bool rtc_does_wakealarm(struct rtc_device *rtc) |
273 | { |
274 | if (!device_can_wakeup(dev: rtc->dev.parent)) |
275 | return false; |
276 | |
277 | return !!test_bit(RTC_FEATURE_ALARM, rtc->features); |
278 | } |
279 | |
280 | static umode_t rtc_attr_is_visible(struct kobject *kobj, |
281 | struct attribute *attr, int n) |
282 | { |
283 | struct device *dev = kobj_to_dev(kobj); |
284 | struct rtc_device *rtc = to_rtc_device(dev); |
285 | umode_t mode = attr->mode; |
286 | |
287 | if (attr == &dev_attr_wakealarm.attr) { |
288 | if (!rtc_does_wakealarm(rtc)) |
289 | mode = 0; |
290 | } else if (attr == &dev_attr_offset.attr) { |
291 | if (!rtc->ops->set_offset) |
292 | mode = 0; |
293 | } else if (attr == &dev_attr_range.attr) { |
294 | if (!(rtc->range_max - rtc->range_min)) |
295 | mode = 0; |
296 | } |
297 | |
298 | return mode; |
299 | } |
300 | |
301 | static struct attribute_group rtc_attr_group = { |
302 | .is_visible = rtc_attr_is_visible, |
303 | .attrs = rtc_attrs, |
304 | }; |
305 | |
306 | static const struct attribute_group *rtc_attr_groups[] = { |
307 | &rtc_attr_group, |
308 | NULL |
309 | }; |
310 | |
311 | const struct attribute_group **rtc_get_dev_attribute_groups(void) |
312 | { |
313 | return rtc_attr_groups; |
314 | } |
315 | |
316 | int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) |
317 | { |
318 | size_t old_cnt = 0, add_cnt = 0, new_cnt; |
319 | const struct attribute_group **groups, **old; |
320 | |
321 | if (!grps) |
322 | return -EINVAL; |
323 | |
324 | groups = rtc->dev.groups; |
325 | if (groups) |
326 | for (; *groups; groups++) |
327 | old_cnt++; |
328 | |
329 | for (groups = grps; *groups; groups++) |
330 | add_cnt++; |
331 | |
332 | new_cnt = old_cnt + add_cnt + 1; |
333 | groups = devm_kcalloc(dev: &rtc->dev, n: new_cnt, size: sizeof(*groups), GFP_KERNEL); |
334 | if (!groups) |
335 | return -ENOMEM; |
336 | memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups)); |
337 | memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups)); |
338 | groups[old_cnt + add_cnt] = NULL; |
339 | |
340 | old = rtc->dev.groups; |
341 | rtc->dev.groups = groups; |
342 | if (old && old != rtc_attr_groups) |
343 | devm_kfree(dev: &rtc->dev, p: old); |
344 | |
345 | return 0; |
346 | } |
347 | EXPORT_SYMBOL(rtc_add_groups); |
348 | |
349 | int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) |
350 | { |
351 | const struct attribute_group *groups[] = { grp, NULL }; |
352 | |
353 | return rtc_add_groups(rtc, groups); |
354 | } |
355 | EXPORT_SYMBOL(rtc_add_group); |
356 | |