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

Configure Feed

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

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