Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.15-rc7 307 lines 7.3 kB view raw
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 %s\n", dev_driver_string(dev->parent), 31 dev_name(dev->parent)); 32} 33static DEVICE_ATTR_RO(name); 34 35static ssize_t 36date_show(struct device *dev, struct device_attribute *attr, char *buf) 37{ 38 ssize_t retval; 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} 49static DEVICE_ATTR_RO(date); 50 51static ssize_t 52time_show(struct device *dev, struct device_attribute *attr, char *buf) 53{ 54 ssize_t retval; 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", 60 tm.tm_hour, tm.tm_min, tm.tm_sec); 61 } 62 63 return retval; 64} 65static DEVICE_ATTR_RO(time); 66 67static ssize_t 68since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) 69{ 70 ssize_t retval; 71 struct rtc_time tm; 72 73 retval = rtc_read_time(to_rtc_device(dev), &tm); 74 if (retval == 0) { 75 time64_t time; 76 77 time = rtc_tm_to_time64(&tm); 78 retval = sprintf(buf, "%lld\n", time); 79 } 80 81 return retval; 82} 83static DEVICE_ATTR_RO(since_epoch); 84 85static ssize_t 86max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) 87{ 88 return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); 89} 90 91static ssize_t 92max_user_freq_store(struct device *dev, struct device_attribute *attr, 93 const char *buf, size_t n) 94{ 95 struct rtc_device *rtc = to_rtc_device(dev); 96 unsigned long val; 97 int err; 98 99 err = kstrtoul(buf, 0, &val); 100 if (err) 101 return err; 102 103 if (val >= 4096 || val == 0) 104 return -EINVAL; 105 106 rtc->max_user_freq = (int)val; 107 108 return n; 109} 110static DEVICE_ATTR_RW(max_user_freq); 111 112/** 113 * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time 114 * 115 * Returns 1 if the system clock was set by this RTC at the last 116 * boot or resume event. 117 */ 118static ssize_t 119hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) 120{ 121#ifdef CONFIG_RTC_HCTOSYS_DEVICE 122 if (rtc_hctosys_ret == 0 && 123 strcmp(dev_name(&to_rtc_device(dev)->dev), 124 CONFIG_RTC_HCTOSYS_DEVICE) == 0) 125 return sprintf(buf, "1\n"); 126 else 127#endif 128 return sprintf(buf, "0\n"); 129} 130static DEVICE_ATTR_RO(hctosys); 131 132static ssize_t 133wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) 134{ 135 ssize_t retval; 136 time64_t alarm; 137 struct rtc_wkalrm alm; 138 139 /* Don't show disabled alarms. For uniformity, RTC alarms are 140 * conceptually one-shot, even though some common RTCs (on PCs) 141 * don't actually work that way. 142 * 143 * NOTE: RTC implementations where the alarm doesn't match an 144 * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC 145 * alarms after they trigger, to ensure one-shot semantics. 146 */ 147 retval = rtc_read_alarm(to_rtc_device(dev), &alm); 148 if (retval == 0 && alm.enabled) { 149 alarm = rtc_tm_to_time64(&alm.time); 150 retval = sprintf(buf, "%lld\n", alarm); 151 } 152 153 return retval; 154} 155 156static ssize_t 157wakealarm_store(struct device *dev, struct device_attribute *attr, 158 const char *buf, size_t n) 159{ 160 ssize_t retval; 161 time64_t now, alarm; 162 time64_t push = 0; 163 struct rtc_wkalrm alm; 164 struct rtc_device *rtc = to_rtc_device(dev); 165 const char *buf_ptr; 166 int adjust = 0; 167 168 /* Only request alarms that trigger in the future. Disable them 169 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. 170 */ 171 retval = rtc_read_time(rtc, &alm.time); 172 if (retval < 0) 173 return retval; 174 now = rtc_tm_to_time64(&alm.time); 175 176 buf_ptr = buf; 177 if (*buf_ptr == '+') { 178 buf_ptr++; 179 if (*buf_ptr == '=') { 180 buf_ptr++; 181 push = 1; 182 } else 183 adjust = 1; 184 } 185 retval = kstrtos64(buf_ptr, 0, &alarm); 186 if (retval) 187 return retval; 188 if (adjust) { 189 alarm += now; 190 } 191 if (alarm > now || push) { 192 /* Avoid accidentally clobbering active alarms; we can't 193 * entirely prevent that here, without even the minimal 194 * locking from the /dev/rtcN api. 195 */ 196 retval = rtc_read_alarm(rtc, &alm); 197 if (retval < 0) 198 return retval; 199 if (alm.enabled) { 200 if (push) { 201 push = rtc_tm_to_time64(&alm.time); 202 alarm += push; 203 } else 204 return -EBUSY; 205 } else if (push) 206 return -EINVAL; 207 alm.enabled = 1; 208 } else { 209 alm.enabled = 0; 210 211 /* Provide a valid future alarm time. Linux isn't EFI, 212 * this time won't be ignored when disabling the alarm. 213 */ 214 alarm = now + 300; 215 } 216 rtc_time64_to_tm(alarm, &alm.time); 217 218 retval = rtc_set_alarm(rtc, &alm); 219 return (retval < 0) ? retval : n; 220} 221static DEVICE_ATTR_RW(wakealarm); 222 223static ssize_t 224offset_show(struct device *dev, struct device_attribute *attr, char *buf) 225{ 226 ssize_t retval; 227 long offset; 228 229 retval = rtc_read_offset(to_rtc_device(dev), &offset); 230 if (retval == 0) 231 retval = sprintf(buf, "%ld\n", offset); 232 233 return retval; 234} 235 236static ssize_t 237offset_store(struct device *dev, struct device_attribute *attr, 238 const char *buf, size_t n) 239{ 240 ssize_t retval; 241 long offset; 242 243 retval = kstrtol(buf, 10, &offset); 244 if (retval == 0) 245 retval = rtc_set_offset(to_rtc_device(dev), offset); 246 247 return (retval < 0) ? retval : n; 248} 249static DEVICE_ATTR_RW(offset); 250 251static struct attribute *rtc_attrs[] = { 252 &dev_attr_name.attr, 253 &dev_attr_date.attr, 254 &dev_attr_time.attr, 255 &dev_attr_since_epoch.attr, 256 &dev_attr_max_user_freq.attr, 257 &dev_attr_hctosys.attr, 258 &dev_attr_wakealarm.attr, 259 &dev_attr_offset.attr, 260 NULL, 261}; 262 263/* The reason to trigger an alarm with no process watching it (via sysfs) 264 * is its side effect: waking from a system state like suspend-to-RAM or 265 * suspend-to-disk. So: no attribute unless that side effect is possible. 266 * (Userspace may disable that mechanism later.) 267 */ 268static bool rtc_does_wakealarm(struct rtc_device *rtc) 269{ 270 if (!device_can_wakeup(rtc->dev.parent)) 271 return false; 272 273 return rtc->ops->set_alarm != NULL; 274} 275 276static umode_t rtc_attr_is_visible(struct kobject *kobj, 277 struct attribute *attr, int n) 278{ 279 struct device *dev = container_of(kobj, struct device, kobj); 280 struct rtc_device *rtc = to_rtc_device(dev); 281 umode_t mode = attr->mode; 282 283 if (attr == &dev_attr_wakealarm.attr) { 284 if (!rtc_does_wakealarm(rtc)) 285 mode = 0; 286 } else if (attr == &dev_attr_offset.attr) { 287 if (!rtc->ops->set_offset) 288 mode = 0; 289 } 290 291 return mode; 292} 293 294static struct attribute_group rtc_attr_group = { 295 .is_visible = rtc_attr_is_visible, 296 .attrs = rtc_attrs, 297}; 298 299static const struct attribute_group *rtc_attr_groups[] = { 300 &rtc_attr_group, 301 NULL 302}; 303 304const struct attribute_group **rtc_get_dev_attribute_groups(void) 305{ 306 return rtc_attr_groups; 307}