rtc-sysfs.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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 ssize_t
  62. rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr,
  63. char *buf)
  64. {
  65. return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
  66. }
  67. static ssize_t
  68. rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
  69. const char *buf, size_t n)
  70. {
  71. struct rtc_device *rtc = to_rtc_device(dev);
  72. unsigned long val = simple_strtoul(buf, NULL, 0);
  73. if (val >= 4096 || val == 0)
  74. return -EINVAL;
  75. rtc->max_user_freq = (int)val;
  76. return n;
  77. }
  78. static struct device_attribute rtc_attrs[] = {
  79. __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
  80. __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
  81. __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
  82. __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
  83. __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
  84. rtc_sysfs_set_max_user_freq),
  85. { },
  86. };
  87. static ssize_t
  88. rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
  89. char *buf)
  90. {
  91. ssize_t retval;
  92. unsigned long alarm;
  93. struct rtc_wkalrm alm;
  94. /* Don't show disabled alarms; but the RTC could leave the
  95. * alarm enabled after it's already triggered. Alarms are
  96. * conceptually one-shot, even though some common hardware
  97. * (PCs) doesn't actually work that way.
  98. *
  99. * REVISIT maybe we should require RTC implementations to
  100. * disable the RTC alarm after it triggers, for uniformity.
  101. */
  102. retval = rtc_read_alarm(to_rtc_device(dev), &alm);
  103. if (retval == 0 && alm.enabled) {
  104. rtc_tm_to_time(&alm.time, &alarm);
  105. retval = sprintf(buf, "%lu\n", alarm);
  106. }
  107. return retval;
  108. }
  109. static ssize_t
  110. rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
  111. const char *buf, size_t n)
  112. {
  113. ssize_t retval;
  114. unsigned long now, alarm;
  115. struct rtc_wkalrm alm;
  116. struct rtc_device *rtc = to_rtc_device(dev);
  117. /* Only request alarms that trigger in the future. Disable them
  118. * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
  119. */
  120. retval = rtc_read_time(rtc, &alm.time);
  121. if (retval < 0)
  122. return retval;
  123. rtc_tm_to_time(&alm.time, &now);
  124. alarm = simple_strtoul(buf, NULL, 0);
  125. if (alarm > now) {
  126. /* Avoid accidentally clobbering active alarms; we can't
  127. * entirely prevent that here, without even the minimal
  128. * locking from the /dev/rtcN api.
  129. */
  130. retval = rtc_read_alarm(rtc, &alm);
  131. if (retval < 0)
  132. return retval;
  133. if (alm.enabled)
  134. return -EBUSY;
  135. alm.enabled = 1;
  136. } else {
  137. alm.enabled = 0;
  138. /* Provide a valid future alarm time. Linux isn't EFI,
  139. * this time won't be ignored when disabling the alarm.
  140. */
  141. alarm = now + 300;
  142. }
  143. rtc_time_to_tm(alarm, &alm.time);
  144. retval = rtc_set_alarm(rtc, &alm);
  145. return (retval < 0) ? retval : n;
  146. }
  147. static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
  148. rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
  149. /* The reason to trigger an alarm with no process watching it (via sysfs)
  150. * is its side effect: waking from a system state like suspend-to-RAM or
  151. * suspend-to-disk. So: no attribute unless that side effect is possible.
  152. * (Userspace may disable that mechanism later.)
  153. */
  154. static inline int rtc_does_wakealarm(struct rtc_device *rtc)
  155. {
  156. if (!device_can_wakeup(rtc->dev.parent))
  157. return 0;
  158. return rtc->ops->set_alarm != NULL;
  159. }
  160. void rtc_sysfs_add_device(struct rtc_device *rtc)
  161. {
  162. int err;
  163. /* not all RTCs support both alarms and wakeup */
  164. if (!rtc_does_wakealarm(rtc))
  165. return;
  166. err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
  167. if (err)
  168. dev_err(rtc->dev.parent,
  169. "failed to create alarm attribute, %d\n", err);
  170. }
  171. void rtc_sysfs_del_device(struct rtc_device *rtc)
  172. {
  173. /* REVISIT did we add it successfully? */
  174. if (rtc_does_wakealarm(rtc))
  175. device_remove_file(&rtc->dev, &dev_attr_wakealarm);
  176. }
  177. void __init rtc_sysfs_init(struct class *rtc_class)
  178. {
  179. rtc_class->dev_attrs = rtc_attrs;
  180. }