diff options
-rw-r--r-- | Documentation/rtc.txt | 7 | ||||
-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 |
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 | ||