aboutsummaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/interface.c4
-rw-r--r--drivers/rtc/rtc-dev.c42
-rw-r--r--drivers/rtc/rtc-omap.c28
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;