diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/rtc/interface.c | 4 | ||||
-rw-r--r-- | drivers/rtc/rtc-dev.c | 42 | ||||
-rw-r--r-- | drivers/rtc/rtc-omap.c | 28 |
3 files changed, 43 insertions, 31 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index b5cc5f82436..ad66c6ecf36 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -125,6 +125,10 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; + err = rtc_valid_tm(&alarm->time); + if (err != 0) + return err; + err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return -EBUSY; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 671b14ec28b..f4e5f0040ff 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -277,12 +277,48 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, alarm.enabled = 0; alarm.pending = 0; - alarm.time.tm_mday = -1; - alarm.time.tm_mon = -1; - alarm.time.tm_year = -1; alarm.time.tm_wday = -1; alarm.time.tm_yday = -1; alarm.time.tm_isdst = -1; + + /* RTC_ALM_SET alarms may be up to 24 hours in the future. + * Rather than expecting every RTC to implement "don't care" + * for day/month/year fields, just force the alarm to have + * the right values for those fields. + * + * RTC_WKALM_SET should be used instead. Not only does it + * eliminate the need for a separate RTC_AIE_ON call, it + * doesn't have the "alarm 23:59:59 in the future" race. + * + * NOTE: some legacy code may have used invalid fields as + * wildcards, exposing hardware "periodic alarm" capabilities. + * Not supported here. + */ + { + unsigned long now, then; + + err = rtc_read_time(rtc, &tm); + if (err < 0) + return err; + rtc_tm_to_time(&tm, &now); + + alarm.time.tm_mday = tm.tm_mday; + alarm.time.tm_mon = tm.tm_mon; + alarm.time.tm_year = tm.tm_year; + err = rtc_valid_tm(&alarm.time); + if (err < 0) + return err; + rtc_tm_to_time(&alarm.time, &then); + + /* alarm may need to wrap into tomorrow */ + if (then < now) { + rtc_time_to_tm(now + 24 * 60 * 60, &tm); + alarm.time.tm_mday = tm.tm_mday; + alarm.time.tm_mon = tm.tm_mon; + alarm.time.tm_year = tm.tm_year; + } + } + err = rtc_set_alarm(rtc, &alarm); break; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index e6c7b0149f2..60a8a4bb8bd 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -289,34 +289,6 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { u8 reg; - /* Much userspace code uses RTC_ALM_SET, thus "don't care" for - * day/month/year specifies alarms up to 24 hours in the future. - * So we need to handle that ... but let's ignore the "don't care" - * values for hours/minutes/seconds. - */ - if (alm->time.tm_mday <= 0 - && alm->time.tm_mon < 0 - && alm->time.tm_year < 0) { - struct rtc_time tm; - unsigned long now, then; - - omap_rtc_read_time(dev, &tm); - rtc_tm_to_time(&tm, &now); - - alm->time.tm_mday = tm.tm_mday; - alm->time.tm_mon = tm.tm_mon; - alm->time.tm_year = tm.tm_year; - rtc_tm_to_time(&alm->time, &then); - - /* sometimes the alarm wraps into tomorrow */ - if (then < now) { - rtc_time_to_tm(now + 24 * 60 * 60, &tm); - alm->time.tm_mday = tm.tm_mday; - alm->time.tm_mon = tm.tm_mon; - alm->time.tm_year = tm.tm_year; - } - } - if (tm2bcd(&alm->time) < 0) return -EINVAL; |