linux/drivers/rtc/rtc-sysfs.c
<<
>>
Prefs
   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}
 306