1/* 2 * RTC subsystem, sysfs interface 3 * 4 * Copyright (C) 2005 Tower Technologies 5 * Author: Alessandro Zummo <a.zummo@towertech.it> 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 27static ssize_t 28name_show(struct device *dev, struct device_attribute *attr, char *buf) 29{ 30 return sprintf(buf, "%s\n", to_rtc_device(dev)->name); 31} 32static DEVICE_ATTR_RO(name); 33 34static ssize_t 35date_show(struct device *dev, struct device_attribute *attr, char *buf) 36{ 37 ssize_t retval; 38 struct rtc_time tm; 39 40 retval = rtc_read_time(to_rtc_device(dev), &tm); 41 if (retval == 0) { 42 retval = sprintf(buf, "%04d-%02d-%02d\n", 43 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 44 } 45 46 return retval; 47} 48static DEVICE_ATTR_RO(date); 49 50static ssize_t 51time_show(struct device *dev, struct device_attribute *attr, char *buf) 52{ 53 ssize_t retval; 54 struct rtc_time tm; 55 56 retval = rtc_read_time(to_rtc_device(dev), &tm); 57 if (retval == 0) { 58 retval = sprintf(buf, "%02d:%02d:%02d\n", 59 tm.tm_hour, tm.tm_min, tm.tm_sec); 60 } 61 62 return retval; 63} 64static DEVICE_ATTR_RO(time); 65 66static ssize_t 67since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) 68{ 69 ssize_t retval; 70 struct rtc_time tm; 71 72 retval = rtc_read_time(to_rtc_device(dev), &tm); 73 if (retval == 0) { 74 unsigned long time; 75 rtc_tm_to_time(&tm, &time); 76 retval = sprintf(buf, "%lu\n", time); 77 } 78 79 return retval; 80} 81static DEVICE_ATTR_RO(since_epoch); 82 83static ssize_t 84max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) 85{ 86 return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); 87} 88 89static ssize_t 90max_user_freq_store(struct device *dev, struct device_attribute *attr, 91 const char *buf, size_t n) 92{ 93 struct rtc_device *rtc = to_rtc_device(dev); 94 unsigned long val = simple_strtoul(buf, NULL, 0); 95 96 if (val >= 4096 || val == 0) 97 return -EINVAL; 98 99 rtc->max_user_freq = (int)val; 100 101 return n; 102} 103static DEVICE_ATTR_RW(max_user_freq); 104 105/** 106 * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time 107 * 108 * Returns 1 if the system clock was set by this RTC at the last 109 * boot or resume event. 110 */ 111static ssize_t 112hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) 113{ 114#ifdef CONFIG_RTC_HCTOSYS_DEVICE 115 if (rtc_hctosys_ret == 0 && 116 strcmp(dev_name(&to_rtc_device(dev)->dev), 117 CONFIG_RTC_HCTOSYS_DEVICE) == 0) 118 return sprintf(buf, "1\n"); 119 else 120#endif 121 return sprintf(buf, "0\n"); 122} 123static DEVICE_ATTR_RO(hctosys); 124 125static struct attribute *rtc_attrs[] = { 126 &dev_attr_name.attr, 127 &dev_attr_date.attr, 128 &dev_attr_time.attr, 129 &dev_attr_since_epoch.attr, 130 &dev_attr_max_user_freq.attr, 131 &dev_attr_hctosys.attr, 132 NULL, 133}; 134ATTRIBUTE_GROUPS(rtc); 135 136static ssize_t 137rtc_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 161static ssize_t 162rtc_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 unsigned long push = 0; 168 struct rtc_wkalrm alm; 169 struct rtc_device *rtc = to_rtc_device(dev); 170 char *buf_ptr; 171 int adjust = 0; 172 173 /* Only request alarms that trigger in the future. Disable them 174 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. 175 */ 176 retval = rtc_read_time(rtc, &alm.time); 177 if (retval < 0) 178 return retval; 179 rtc_tm_to_time(&alm.time, &now); 180 181 buf_ptr = (char *)buf; 182 if (*buf_ptr == '+') { 183 buf_ptr++; 184 if (*buf_ptr == '=') { 185 buf_ptr++; 186 push = 1; 187 } else 188 adjust = 1; 189 } 190 alarm = simple_strtoul(buf_ptr, NULL, 0); 191 if (adjust) { 192 alarm += now; 193 } 194 if (alarm > now || push) { 195 /* Avoid accidentally clobbering active alarms; we can't 196 * entirely prevent that here, without even the minimal 197 * locking from the /dev/rtcN api. 198 */ 199 retval = rtc_read_alarm(rtc, &alm); 200 if (retval < 0) 201 return retval; 202 if (alm.enabled) { 203 if (push) { 204 rtc_tm_to_time(&alm.time, &push); 205 alarm += push; 206 } else 207 return -EBUSY; 208 } else if (push) 209 return -EINVAL; 210 alm.enabled = 1; 211 } else { 212 alm.enabled = 0; 213 214 /* Provide a valid future alarm time. Linux isn't EFI, 215 * this time won't be ignored when disabling the alarm. 216 */ 217 alarm = now + 300; 218 } 219 rtc_time_to_tm(alarm, &alm.time); 220 221 retval = rtc_set_alarm(rtc, &alm); 222 return (retval < 0) ? retval : n; 223} 224static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, 225 rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm); 226 227 228/* The reason to trigger an alarm with no process watching it (via sysfs) 229 * is its side effect: waking from a system state like suspend-to-RAM or 230 * suspend-to-disk. So: no attribute unless that side effect is possible. 231 * (Userspace may disable that mechanism later.) 232 */ 233static inline int rtc_does_wakealarm(struct rtc_device *rtc) 234{ 235 if (!device_can_wakeup(rtc->dev.parent)) 236 return 0; 237 return rtc->ops->set_alarm != NULL; 238} 239 240 241void rtc_sysfs_add_device(struct rtc_device *rtc) 242{ 243 int err; 244 245 /* not all RTCs support both alarms and wakeup */ 246 if (!rtc_does_wakealarm(rtc)) 247 return; 248 249 err = device_create_file(&rtc->dev, &dev_attr_wakealarm); 250 if (err) 251 dev_err(rtc->dev.parent, 252 "failed to create alarm attribute, %d\n", err); 253} 254 255void rtc_sysfs_del_device(struct rtc_device *rtc) 256{ 257 /* REVISIT did we add it successfully? */ 258 if (rtc_does_wakealarm(rtc)) 259 device_remove_file(&rtc->dev, &dev_attr_wakealarm); 260} 261 262void __init rtc_sysfs_init(struct class *rtc_class) 263{ 264 rtc_class->dev_groups = rtc_groups; 265} 266