rtc-sysfs.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. #include <linux/module.h>
  12. #include <linux/rtc.h>
  13. #include "rtc-core.h"
  14. /* device attributes */
  15. static ssize_t
  16. rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
  17. char *buf)
  18. {
  19. return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
  20. }
  21. static ssize_t
  22. rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
  23. char *buf)
  24. {
  25. ssize_t retval;
  26. struct rtc_time tm;
  27. retval = rtc_read_time(to_rtc_device(dev), &tm);
  28. if (retval == 0) {
  29. retval = sprintf(buf, "%04d-%02d-%02d\n",
  30. tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
  31. }
  32. return retval;
  33. }
  34. static ssize_t
  35. rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
  36. char *buf)
  37. {
  38. ssize_t retval;
  39. struct rtc_time tm;
  40. retval = rtc_read_time(to_rtc_device(dev), &tm);
  41. if (retval == 0) {
  42. retval = sprintf(buf, "%02d:%02d:%02d\n",
  43. tm.tm_hour, tm.tm_min, tm.tm_sec);
  44. }
  45. return retval;
  46. }
  47. static ssize_t
  48. rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
  49. char *buf)
  50. {
  51. ssize_t retval;
  52. struct rtc_time tm;
  53. retval = rtc_read_time(to_rtc_device(dev), &tm);
  54. if (retval == 0) {
  55. unsigned long time;
  56. rtc_tm_to_time(&tm, &time);
  57. retval = sprintf(buf, "%lu\n", time);
  58. }
  59. return retval;
  60. }
  61. static struct device_attribute rtc_attrs[] = {
  62. __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
  63. __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
  64. __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
  65. __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
  66. { },
  67. };
  68. static ssize_t
  69. rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
  70. char *buf)
  71. {
  72. ssize_t retval;
  73. unsigned long alarm;
  74. struct rtc_wkalrm alm;
  75. /* Don't show disabled alarms; but the RTC could leave the
  76. * alarm enabled after it's already triggered. Alarms are
  77. * conceptually one-shot, even though some common hardware
  78. * (PCs) doesn't actually work that way.
  79. *
  80. * REVISIT maybe we should require RTC implementations to
  81. * disable the RTC alarm after it triggers, for uniformity.
  82. */
  83. retval = rtc_read_alarm(to_rtc_device(dev), &alm);
  84. if (retval == 0 && alm.enabled) {
  85. rtc_tm_to_time(&alm.time, &alarm);
  86. retval = sprintf(buf, "%lu\n", alarm);
  87. }
  88. return retval;
  89. }
  90. static ssize_t
  91. rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
  92. const char *buf, size_t n)
  93. {
  94. ssize_t retval;
  95. unsigned long now, alarm;
  96. struct rtc_wkalrm alm;
  97. struct rtc_device *rtc = to_rtc_device(dev);
  98. /* Only request alarms that trigger in the future. Disable them
  99. * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
  100. */
  101. retval = rtc_read_time(rtc, &alm.time);
  102. if (retval < 0)
  103. return retval;
  104. rtc_tm_to_time(&alm.time, &now);
  105. alarm = simple_strtoul(buf, NULL, 0);
  106. if (alarm > now) {
  107. /* Avoid accidentally clobbering active alarms; we can't
  108. * entirely prevent that here, without even the minimal
  109. * locking from the /dev/rtcN api.
  110. */
  111. retval = rtc_read_alarm(rtc, &alm);
  112. if (retval < 0)
  113. return retval;
  114. if (alm.enabled)
  115. return -EBUSY;
  116. alm.enabled = 1;
  117. } else {
  118. alm.enabled = 0;
  119. /* Provide a valid future alarm time. Linux isn't EFI,
  120. * this time won't be ignored when disabling the alarm.
  121. */
  122. alarm = now + 300;
  123. }
  124. rtc_time_to_tm(alarm, &alm.time);
  125. retval = rtc_set_alarm(rtc, &alm);
  126. return (retval < 0) ? retval : n;
  127. }
  128. static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
  129. rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
  130. /* The reason to trigger an alarm with no process watching it (via sysfs)
  131. * is its side effect: waking from a system state like suspend-to-RAM or
  132. * suspend-to-disk. So: no attribute unless that side effect is possible.
  133. * (Userspace may disable that mechanism later.)
  134. */
  135. static inline int rtc_does_wakealarm(struct rtc_device *rtc)
  136. {
  137. if (!device_can_wakeup(rtc->dev.parent))
  138. return 0;
  139. return rtc->ops->set_alarm != NULL;
  140. }
  141. void rtc_sysfs_add_device(struct rtc_device *rtc)
  142. {
  143. int err;
  144. /* not all RTCs support both alarms and wakeup */
  145. if (!rtc_does_wakealarm(rtc))
  146. return;
  147. err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
  148. if (err)
  149. dev_err(rtc->dev.parent, "failed to create "
  150. "alarm attribute, %d",
  151. err);
  152. }
  153. void rtc_sysfs_del_device(struct rtc_device *rtc)
  154. {
  155. /* REVISIT did we add it successfully? */
  156. if (rtc_does_wakealarm(rtc))
  157. device_remove_file(&rtc->dev, &dev_attr_wakealarm);
  158. }
  159. void __init rtc_sysfs_init(struct class *rtc_class)
  160. {
  161. rtc_class->dev_attrs = rtc_attrs;
  162. }