aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/rtc.txt7
-rw-r--r--drivers/rtc/interface.c4
-rw-r--r--drivers/rtc/rtc-dev.c42
-rw-r--r--drivers/rtc/rtc-omap.c28
4 files changed, 45 insertions, 36 deletions
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt
index 1ef6bb88cd00..7c701b88d6d5 100644
--- a/Documentation/rtc.txt
+++ b/Documentation/rtc.txt
@@ -147,7 +147,7 @@ RTC class framework, but can't be supported by the older driver.
147 147
148 * RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ ... when the RTC 148 * RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ ... when the RTC
149 is connected to an IRQ line, it can often issue an alarm IRQ up to 149 is connected to an IRQ line, it can often issue an alarm IRQ up to
150 24 hours in the future. 150 24 hours in the future. (Use RTC_WKALM_* by preference.)
151 151
152 * RTC_WKALM_SET, RTC_WKALM_RD ... RTCs that can issue alarms beyond 152 * RTC_WKALM_SET, RTC_WKALM_RD ... RTCs that can issue alarms beyond
153 the next 24 hours use a slightly more powerful API, which supports 153 the next 24 hours use a slightly more powerful API, which supports
@@ -175,10 +175,7 @@ driver returns ENOIOCTLCMD. Some common examples:
175 called with appropriate values. 175 called with appropriate values.
176 176
177 * RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: the 177 * RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: the
178 set_alarm/read_alarm functions will be called. To differentiate 178 set_alarm/read_alarm functions will be called.
179 between the ALM and WKALM, check the larger fields of the rtc_wkalrm
180 struct (like tm_year). These will be set to -1 when using ALM and
181 will be set to proper values when using WKALM.
182 179
183 * RTC_IRQP_SET, RTC_IRQP_READ: the irq_set_freq function will be called 180 * RTC_IRQP_SET, RTC_IRQP_READ: the irq_set_freq function will be called
184 to set the frequency while the framework will handle the read for you 181 to set the frequency while the framework will handle the read for you
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index b5cc5f82436d..ad66c6ecf365 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)
125{ 125{
126 int err; 126 int err;
127 127
128 err = rtc_valid_tm(&alarm->time);
129 if (err != 0)
130 return err;
131
128 err = mutex_lock_interruptible(&rtc->ops_lock); 132 err = mutex_lock_interruptible(&rtc->ops_lock);
129 if (err) 133 if (err)
130 return -EBUSY; 134 return -EBUSY;
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 671b14ec28bb..f4e5f0040ff7 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,
277 277
278 alarm.enabled = 0; 278 alarm.enabled = 0;
279 alarm.pending = 0; 279 alarm.pending = 0;
280 alarm.time.tm_mday = -1;
281 alarm.time.tm_mon = -1;
282 alarm.time.tm_year = -1;
283 alarm.time.tm_wday = -1; 280 alarm.time.tm_wday = -1;
284 alarm.time.tm_yday = -1; 281 alarm.time.tm_yday = -1;
285 alarm.time.tm_isdst = -1; 282 alarm.time.tm_isdst = -1;
283
284 /* RTC_ALM_SET alarms may be up to 24 hours in the future.
285 * Rather than expecting every RTC to implement "don't care"
286 * for day/month/year fields, just force the alarm to have
287 * the right values for those fields.
288 *
289 * RTC_WKALM_SET should be used instead. Not only does it
290 * eliminate the need for a separate RTC_AIE_ON call, it
291 * doesn't have the "alarm 23:59:59 in the future" race.
292 *
293 * NOTE: some legacy code may have used invalid fields as
294 * wildcards, exposing hardware "periodic alarm" capabilities.
295 * Not supported here.
296 */
297 {
298 unsigned long now, then;
299
300 err = rtc_read_time(rtc, &tm);
301 if (err < 0)
302 return err;
303 rtc_tm_to_time(&tm, &now);
304
305 alarm.time.tm_mday = tm.tm_mday;
306 alarm.time.tm_mon = tm.tm_mon;
307 alarm.time.tm_year = tm.tm_year;
308 err = rtc_valid_tm(&alarm.time);
309 if (err < 0)
310 return err;
311 rtc_tm_to_time(&alarm.time, &then);
312
313 /* alarm may need to wrap into tomorrow */
314 if (then < now) {
315 rtc_time_to_tm(now + 24 * 60 * 60, &tm);
316 alarm.time.tm_mday = tm.tm_mday;
317 alarm.time.tm_mon = tm.tm_mon;
318 alarm.time.tm_year = tm.tm_year;
319 }
320 }
321
286 err = rtc_set_alarm(rtc, &alarm); 322 err = rtc_set_alarm(rtc, &alarm);
287 break; 323 break;
288 324
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index e6c7b0149f27..60a8a4bb8bd2 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)
289{ 289{
290 u8 reg; 290 u8 reg;
291 291
292 /* Much userspace code uses RTC_ALM_SET, thus "don't care" for
293 * day/month/year specifies alarms up to 24 hours in the future.
294 * So we need to handle that ... but let's ignore the "don't care"
295 * values for hours/minutes/seconds.
296 */
297 if (alm->time.tm_mday <= 0
298 && alm->time.tm_mon < 0
299 && alm->time.tm_year < 0) {
300 struct rtc_time tm;
301 unsigned long now, then;
302
303 omap_rtc_read_time(dev, &tm);
304 rtc_tm_to_time(&tm, &now);
305
306 alm->time.tm_mday = tm.tm_mday;
307 alm->time.tm_mon = tm.tm_mon;
308 alm->time.tm_year = tm.tm_year;
309 rtc_tm_to_time(&alm->time, &then);
310
311 /* sometimes the alarm wraps into tomorrow */
312 if (then < now) {
313 rtc_time_to_tm(now + 24 * 60 * 60, &tm);
314 alm->time.tm_mday = tm.tm_mday;
315 alm->time.tm_mon = tm.tm_mon;
316 alm->time.tm_year = tm.tm_year;
317 }
318 }
319
320 if (tm2bcd(&alm->time) < 0) 292 if (tm2bcd(&alm->time) < 0)
321 return -EINVAL; 293 return -EINVAL;
322 294