LCOV - code coverage report
Current view: top level - drivers/rtc - rtc-sysfs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 79 0.0 %
Date: 2014-02-18 Functions: 0 12 0.0 %
Branches: 0 48 0.0 %

           Branch data     Line data    Source code
       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                 :            : 
      27                 :            : static ssize_t
      28                 :          0 : name_show(struct device *dev, struct device_attribute *attr, char *buf)
      29                 :            : {
      30                 :          0 :         return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
      31                 :            : }
      32                 :            : static DEVICE_ATTR_RO(name);
      33                 :            : 
      34                 :            : static ssize_t
      35                 :          0 : date_show(struct device *dev, struct device_attribute *attr, char *buf)
      36                 :            : {
      37                 :            :         ssize_t retval;
      38                 :            :         struct rtc_time tm;
      39                 :            : 
      40                 :          0 :         retval = rtc_read_time(to_rtc_device(dev), &tm);
      41         [ #  # ]:          0 :         if (retval == 0) {
      42                 :          0 :                 retval = sprintf(buf, "%04d-%02d-%02d\n",
      43                 :          0 :                         tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
      44                 :            :         }
      45                 :            : 
      46                 :          0 :         return retval;
      47                 :            : }
      48                 :            : static DEVICE_ATTR_RO(date);
      49                 :            : 
      50                 :            : static ssize_t
      51                 :          0 : time_show(struct device *dev, struct device_attribute *attr, char *buf)
      52                 :            : {
      53                 :            :         ssize_t retval;
      54                 :            :         struct rtc_time tm;
      55                 :            : 
      56                 :          0 :         retval = rtc_read_time(to_rtc_device(dev), &tm);
      57         [ #  # ]:          0 :         if (retval == 0) {
      58                 :          0 :                 retval = sprintf(buf, "%02d:%02d:%02d\n",
      59                 :            :                         tm.tm_hour, tm.tm_min, tm.tm_sec);
      60                 :            :         }
      61                 :            : 
      62                 :          0 :         return retval;
      63                 :            : }
      64                 :            : static DEVICE_ATTR_RO(time);
      65                 :            : 
      66                 :            : static ssize_t
      67                 :          0 : since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf)
      68                 :            : {
      69                 :            :         ssize_t retval;
      70                 :            :         struct rtc_time tm;
      71                 :            : 
      72                 :          0 :         retval = rtc_read_time(to_rtc_device(dev), &tm);
      73         [ #  # ]:          0 :         if (retval == 0) {
      74                 :            :                 unsigned long time;
      75                 :          0 :                 rtc_tm_to_time(&tm, &time);
      76                 :          0 :                 retval = sprintf(buf, "%lu\n", time);
      77                 :            :         }
      78                 :            : 
      79                 :          0 :         return retval;
      80                 :            : }
      81                 :            : static DEVICE_ATTR_RO(since_epoch);
      82                 :            : 
      83                 :            : static ssize_t
      84                 :          0 : max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
      85                 :            : {
      86                 :          0 :         return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
      87                 :            : }
      88                 :            : 
      89                 :            : static ssize_t
      90                 :          0 : max_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                 :          0 :         unsigned long val = simple_strtoul(buf, NULL, 0);
      95                 :            : 
      96         [ #  # ]:          0 :         if (val >= 4096 || val == 0)
      97                 :            :                 return -EINVAL;
      98                 :            : 
      99                 :          0 :         rtc->max_user_freq = (int)val;
     100                 :            : 
     101                 :          0 :         return n;
     102                 :            : }
     103                 :            : static 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                 :            :  */
     111                 :            : static ssize_t
     112                 :          0 : hctosys_show(struct device *dev, struct device_attribute *attr, char *buf)
     113                 :            : {
     114                 :            : #ifdef CONFIG_RTC_HCTOSYS_DEVICE
     115 [ #  # ][ #  # ]:          0 :         if (rtc_hctosys_ret == 0 &&
     116                 :          0 :                         strcmp(dev_name(&to_rtc_device(dev)->dev),
     117                 :            :                                 CONFIG_RTC_HCTOSYS_DEVICE) == 0)
     118                 :          0 :                 return sprintf(buf, "1\n");
     119                 :            :         else
     120                 :            : #endif
     121                 :          0 :                 return sprintf(buf, "0\n");
     122                 :            : }
     123                 :            : static DEVICE_ATTR_RO(hctosys);
     124                 :            : 
     125                 :            : static 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                 :            : };
     134                 :            : ATTRIBUTE_GROUPS(rtc);
     135                 :            : 
     136                 :            : static ssize_t
     137                 :          0 : 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                 :          0 :         retval = rtc_read_alarm(to_rtc_device(dev), &alm);
     153 [ #  # ][ #  # ]:          0 :         if (retval == 0 && alm.enabled) {
     154                 :          0 :                 rtc_tm_to_time(&alm.time, &alarm);
     155                 :          0 :                 retval = sprintf(buf, "%lu\n", alarm);
     156                 :            :         }
     157                 :            : 
     158                 :          0 :         return retval;
     159                 :            : }
     160                 :            : 
     161                 :            : static ssize_t
     162                 :          0 : 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                 :          0 :         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                 :          0 :         retval = rtc_read_time(rtc, &alm.time);
     177         [ #  # ]:          0 :         if (retval < 0)
     178                 :            :                 return retval;
     179                 :          0 :         rtc_tm_to_time(&alm.time, &now);
     180                 :            : 
     181                 :            :         buf_ptr = (char *)buf;
     182         [ #  # ]:          0 :         if (*buf_ptr == '+') {
     183                 :          0 :                 buf_ptr++;
     184         [ #  # ]:          0 :                 if (*buf_ptr == '=') {
     185                 :          0 :                         buf_ptr++;
     186                 :          0 :                         push = 1;
     187                 :            :                 } else
     188                 :            :                         adjust = 1;
     189                 :            :         }
     190                 :          0 :         alarm = simple_strtoul(buf_ptr, NULL, 0);
     191         [ #  # ]:          0 :         if (adjust) {
     192                 :          0 :                 alarm += now;
     193                 :            :         }
     194 [ #  # ][ #  # ]:          0 :         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                 :          0 :                 retval = rtc_read_alarm(rtc, &alm);
     200         [ #  # ]:          0 :                 if (retval < 0)
     201                 :            :                         return retval;
     202         [ #  # ]:          0 :                 if (alm.enabled) {
     203         [ #  # ]:          0 :                         if (push) {
     204                 :          0 :                                 rtc_tm_to_time(&alm.time, &push);
     205                 :          0 :                                 alarm += push;
     206                 :            :                         } else
     207                 :            :                                 return -EBUSY;
     208         [ #  # ]:          0 :                 } else if (push)
     209                 :            :                         return -EINVAL;
     210                 :          0 :                 alm.enabled = 1;
     211                 :            :         } else {
     212                 :          0 :                 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                 :          0 :                 alarm = now + 300;
     218                 :            :         }
     219                 :          0 :         rtc_time_to_tm(alarm, &alm.time);
     220                 :            : 
     221                 :          0 :         retval = rtc_set_alarm(rtc, &alm);
     222         [ #  # ]:          0 :         return (retval < 0) ? retval : n;
     223                 :            : }
     224                 :            : static 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                 :            :  */
     233                 :            : static inline int rtc_does_wakealarm(struct rtc_device *rtc)
     234                 :            : {
     235 [ #  # ][ #  # ]:          0 :         if (!device_can_wakeup(rtc->dev.parent))
     236                 :            :                 return 0;
     237                 :          0 :         return rtc->ops->set_alarm != NULL;
     238                 :            : }
     239                 :            : 
     240                 :            : 
     241                 :          0 : void rtc_sysfs_add_device(struct rtc_device *rtc)
     242                 :            : {
     243                 :            :         int err;
     244                 :            : 
     245                 :            :         /* not all RTCs support both alarms and wakeup */
     246         [ #  # ]:          0 :         if (!rtc_does_wakealarm(rtc))
     247                 :          0 :                 return;
     248                 :            : 
     249                 :          0 :         err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
     250         [ #  # ]:          0 :         if (err)
     251                 :          0 :                 dev_err(rtc->dev.parent,
     252                 :            :                         "failed to create alarm attribute, %d\n", err);
     253                 :            : }
     254                 :            : 
     255                 :          0 : void rtc_sysfs_del_device(struct rtc_device *rtc)
     256                 :            : {
     257                 :            :         /* REVISIT did we add it successfully? */
     258         [ #  # ]:          0 :         if (rtc_does_wakealarm(rtc))
     259                 :          0 :                 device_remove_file(&rtc->dev, &dev_attr_wakealarm);
     260                 :          0 : }
     261                 :            : 
     262                 :          0 : void __init rtc_sysfs_init(struct class *rtc_class)
     263                 :            : {
     264                 :          0 :         rtc_class->dev_groups = rtc_groups;
     265                 :          0 : }

Generated by: LCOV version 1.9