aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-dev.c
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2007-05-08 03:34:07 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:19 -0400
commitf8245c26886c912627ebc49f714e4491261224c4 (patch)
tree132a34d1e482f96a5d4bba5f744658aea9a5fcc9 /drivers/rtc/rtc-dev.c
parent416ce32e704d778c283f2f86cadd836cd5d3696c (diff)
rtc: remove "RTC_ALM_SET mode" bugs
This fixes a common glitch in how RTC drivers handle two "set alarm" modes, by getting rid of the surprising/hidden one that was rarely implemented correctly (and which could expose nonportable hardware-specific behavior). The glitch comes from the /dev/rtcX logic implementing the legacy RTC_ALM_SET (limited to 24 hours, needing RTC_AIE_ON) ioctl on top of the RTC driver call providing access to the newer RTC_WKALM_SET (without those limitations) by initializing the day/month/year fields to be invalid ... that second mode. Now, since few RTC drivers check those fields, and most hardware misbehaves when faced with invalid date fields, many RTC drivers will set bogus alarm times on those RTC_ALM_SET code paths. (Several in-tree drivers have that issue, and I also noticed it with code reviews on several new RTC drivers.) This patch ensures that RTC drivers never see such invalid alarm fields, by moving some logic out of rtc-omap into the RTC_ALM_SET code and adding an explicit check (which will prevent the issue on other code paths). Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Cc: Scott Wood <scottwood@freescale.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-dev.c')
-rw-r--r--drivers/rtc/rtc-dev.c42
1 files changed, 39 insertions, 3 deletions
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