Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rtc-sysfs.c
Go to the documentation of this file.
1 /*
2  * RTC subsystem, sysfs interface
3  *
4  * Copyright (C) 2005 Tower Technologies
5  * Author: Alessandro Zummo <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10 */
11 
12 #include <linux/module.h>
13 #include <linux/rtc.h>
14 
15 #include "rtc-core.h"
16 
17 
18 /* device attributes */
19 
20 /*
21  * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's
22  * ideally UTC. However, PCs that also boot to MS-Windows normally use
23  * the local time and change to match daylight savings time. That affects
24  * attributes including date, time, since_epoch, and wakealarm.
25  */
26 
27 static ssize_t
28 rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
29  char *buf)
30 {
31  return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
32 }
33 
34 static ssize_t
35 rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
36  char *buf)
37 {
39  struct rtc_time tm;
40 
41  retval = rtc_read_time(to_rtc_device(dev), &tm);
42  if (retval == 0) {
43  retval = sprintf(buf, "%04d-%02d-%02d\n",
44  tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
45  }
46 
47  return retval;
48 }
49 
50 static ssize_t
51 rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
52  char *buf)
53 {
55  struct rtc_time tm;
56 
57  retval = rtc_read_time(to_rtc_device(dev), &tm);
58  if (retval == 0) {
59  retval = sprintf(buf, "%02d:%02d:%02d\n",
61  }
62 
63  return retval;
64 }
65 
66 static ssize_t
67 rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
68  char *buf)
69 {
71  struct rtc_time tm;
72 
73  retval = rtc_read_time(to_rtc_device(dev), &tm);
74  if (retval == 0) {
75  unsigned long time;
76  rtc_tm_to_time(&tm, &time);
77  retval = sprintf(buf, "%lu\n", time);
78  }
79 
80  return retval;
81 }
82 
83 static ssize_t
84 rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr,
85  char *buf)
86 {
87  return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
88 }
89 
90 static ssize_t
91 rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
92  const char *buf, size_t n)
93 {
94  struct rtc_device *rtc = to_rtc_device(dev);
95  unsigned long val = simple_strtoul(buf, NULL, 0);
96 
97  if (val >= 4096 || val == 0)
98  return -EINVAL;
99 
100  rtc->max_user_freq = (int)val;
101 
102  return n;
103 }
104 
111 static ssize_t
112 rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
113  char *buf)
114 {
115 #ifdef CONFIG_RTC_HCTOSYS_DEVICE
116  if (rtc_hctosys_ret == 0 &&
117  strcmp(dev_name(&to_rtc_device(dev)->dev),
118  CONFIG_RTC_HCTOSYS_DEVICE) == 0)
119  return sprintf(buf, "1\n");
120  else
121 #endif
122  return sprintf(buf, "0\n");
123 }
124 
125 static struct device_attribute rtc_attrs[] = {
126  __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
127  __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
128  __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
129  __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
130  __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
131  rtc_sysfs_set_max_user_freq),
132  __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
133  { },
134 };
135 
136 static ssize_t
137 rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
138  char *buf)
139 {
140  ssize_t retval;
141  unsigned long alarm;
142  struct rtc_wkalrm alm;
143 
144  /* Don't show disabled alarms. For uniformity, RTC alarms are
145  * conceptually one-shot, even though some common RTCs (on PCs)
146  * don't actually work that way.
147  *
148  * NOTE: RTC implementations where the alarm doesn't match an
149  * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC
150  * alarms after they trigger, to ensure one-shot semantics.
151  */
152  retval = rtc_read_alarm(to_rtc_device(dev), &alm);
153  if (retval == 0 && alm.enabled) {
154  rtc_tm_to_time(&alm.time, &alarm);
155  retval = sprintf(buf, "%lu\n", alarm);
156  }
157 
158  return retval;
159 }
160 
161 static ssize_t
162 rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
163  const char *buf, size_t n)
164 {
165  ssize_t retval;
166  unsigned long now, alarm;
167  struct rtc_wkalrm alm;
168  struct rtc_device *rtc = to_rtc_device(dev);
169  char *buf_ptr;
170  int adjust = 0;
171 
172  /* Only request alarms that trigger in the future. Disable them
173  * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
174  */
175  retval = rtc_read_time(rtc, &alm.time);
176  if (retval < 0)
177  return retval;
178  rtc_tm_to_time(&alm.time, &now);
179 
180  buf_ptr = (char *)buf;
181  if (*buf_ptr == '+') {
182  buf_ptr++;
183  adjust = 1;
184  }
185  alarm = simple_strtoul(buf_ptr, NULL, 0);
186  if (adjust) {
187  alarm += now;
188  }
189  if (alarm > now) {
190  /* Avoid accidentally clobbering active alarms; we can't
191  * entirely prevent that here, without even the minimal
192  * locking from the /dev/rtcN api.
193  */
194  retval = rtc_read_alarm(rtc, &alm);
195  if (retval < 0)
196  return retval;
197  if (alm.enabled)
198  return -EBUSY;
199 
200  alm.enabled = 1;
201  } else {
202  alm.enabled = 0;
203 
204  /* Provide a valid future alarm time. Linux isn't EFI,
205  * this time won't be ignored when disabling the alarm.
206  */
207  alarm = now + 300;
208  }
209  rtc_time_to_tm(alarm, &alm.time);
210 
211  retval = rtc_set_alarm(rtc, &alm);
212  return (retval < 0) ? retval : n;
213 }
214 static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
215  rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
216 
217 
218 /* The reason to trigger an alarm with no process watching it (via sysfs)
219  * is its side effect: waking from a system state like suspend-to-RAM or
220  * suspend-to-disk. So: no attribute unless that side effect is possible.
221  * (Userspace may disable that mechanism later.)
222  */
223 static inline int rtc_does_wakealarm(struct rtc_device *rtc)
224 {
225  if (!device_can_wakeup(rtc->dev.parent))
226  return 0;
227  return rtc->ops->set_alarm != NULL;
228 }
229 
230 
232 {
233  int err;
234 
235  /* not all RTCs support both alarms and wakeup */
236  if (!rtc_does_wakealarm(rtc))
237  return;
238 
239  err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
240  if (err)
241  dev_err(rtc->dev.parent,
242  "failed to create alarm attribute, %d\n", err);
243 }
244 
246 {
247  /* REVISIT did we add it successfully? */
248  if (rtc_does_wakealarm(rtc))
249  device_remove_file(&rtc->dev, &dev_attr_wakealarm);
250 }
251 
252 void __init rtc_sysfs_init(struct class *rtc_class)
253 {
254  rtc_class->dev_attrs = rtc_attrs;
255 }