X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=drivers%2Frtc%2Frtc-sysfs.c;h=2531ce4c9db082d94cd3b1afba7ac7f4acf93f85;hb=4fb8af10d0fd09372d52966b76922b9e82bbc950;hp=1c2fa0cc9cbb27df9d0921fdde796ef4fbdefbfa;hpb=446ecbd925dc580c9972049c926c17aa8d967fe4;p=linux-2.6 diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 1c2fa0cc9c..2531ce4c9d 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -17,12 +17,23 @@ /* device attributes */ -static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf) +/* + * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's + * ideally UTC. However, PCs that also boot to MS-Windows normally use + * the local time and change to match daylight savings time. That affects + * attributes including date, time, since_epoch, and wakealarm. + */ + +static ssize_t +rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr, + char *buf) { return sprintf(buf, "%s\n", to_rtc_device(dev)->name); } -static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf) +static ssize_t +rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr, + char *buf) { ssize_t retval; struct rtc_time tm; @@ -36,7 +47,9 @@ static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf) return retval; } -static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf) +static ssize_t +rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr, + char *buf) { ssize_t retval; struct rtc_time tm; @@ -50,7 +63,9 @@ static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf) return retval; } -static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf) +static ssize_t +rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr, + char *buf) { ssize_t retval; struct rtc_time tm; @@ -65,28 +80,53 @@ static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf) return retval; } -static struct class_device_attribute rtc_attrs[] = { +static ssize_t +rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); +} + +static ssize_t +rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct rtc_device *rtc = to_rtc_device(dev); + unsigned long val = simple_strtoul(buf, NULL, 0); + + if (val >= 4096 || val == 0) + return -EINVAL; + + rtc->max_user_freq = (int)val; + + return n; +} + +static struct device_attribute rtc_attrs[] = { __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL), __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), + __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq, + rtc_sysfs_set_max_user_freq), { }, }; static ssize_t -rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf) +rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, + char *buf) { ssize_t retval; unsigned long alarm; struct rtc_wkalrm alm; - /* Don't show disabled alarms; but the RTC could leave the - * alarm enabled after it's already triggered. Alarms are - * conceptually one-shot, even though some common hardware - * (PCs) doesn't actually work that way. + /* Don't show disabled alarms. For uniformity, RTC alarms are + * conceptually one-shot, even though some common RTCs (on PCs) + * don't actually work that way. * - * REVISIT maybe we should require RTC implementations to - * disable the RTC alarm after it triggers, for uniformity. + * NOTE: RTC implementations where the alarm doesn't match an + * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC + * alarms after they trigger, to ensure one-shot semantics. */ retval = rtc_read_alarm(to_rtc_device(dev), &alm); if (retval == 0 && alm.enabled) { @@ -98,12 +138,15 @@ rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf) } static ssize_t -rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n) +rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) { ssize_t retval; unsigned long now, alarm; struct rtc_wkalrm alm; struct rtc_device *rtc = to_rtc_device(dev); + char *buf_ptr; + int adjust = 0; /* Only request alarms that trigger in the future. Disable them * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. @@ -113,7 +156,15 @@ rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n) return retval; rtc_tm_to_time(&alm.time, &now); - alarm = simple_strtoul(buf, NULL, 0); + buf_ptr = (char *)buf; + if (*buf_ptr == '+') { + buf_ptr++; + adjust = 1; + } + alarm = simple_strtoul(buf_ptr, NULL, 0); + if (adjust) { + alarm += now; + } if (alarm > now) { /* Avoid accidentally clobbering active alarms; we can't * entirely prevent that here, without even the minimal @@ -139,7 +190,7 @@ rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n) retval = rtc_set_alarm(rtc, &alm); return (retval < 0) ? retval : n; } -static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm); @@ -150,7 +201,7 @@ static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, */ static inline int rtc_does_wakealarm(struct rtc_device *rtc) { - if (!device_can_wakeup(rtc->class_dev.dev)) + if (!device_can_wakeup(rtc->dev.parent)) return 0; return rtc->ops->set_alarm != NULL; } @@ -164,23 +215,20 @@ void rtc_sysfs_add_device(struct rtc_device *rtc) if (!rtc_does_wakealarm(rtc)) return; - err = class_device_create_file(&rtc->class_dev, - &class_device_attr_wakealarm); + err = device_create_file(&rtc->dev, &dev_attr_wakealarm); if (err) - dev_err(rtc->class_dev.dev, "failed to create " - "alarm attribute, %d", - err); + dev_err(rtc->dev.parent, + "failed to create alarm attribute, %d\n", err); } void rtc_sysfs_del_device(struct rtc_device *rtc) { /* REVISIT did we add it successfully? */ if (rtc_does_wakealarm(rtc)) - class_device_remove_file(&rtc->class_dev, - &class_device_attr_wakealarm); + device_remove_file(&rtc->dev, &dev_attr_wakealarm); } void __init rtc_sysfs_init(struct class *rtc_class) { - rtc_class->class_dev_attrs = rtc_attrs; + rtc_class->dev_attrs = rtc_attrs; }