diff options
author | Scott Wood <scottwood@freescale.com> | 2006-12-10 02:19:00 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-10 09:55:40 -0800 |
commit | 884b4aaaa242a2db8c8252796f0118164a680ab5 (patch) | |
tree | eea898cb8df58cace0a04025b5efdb8b2a2fd3d2 /drivers/rtc | |
parent | 9080d0ae0fd16628d688ce7d03d02ccf7011c6f0 (diff) |
[PATCH] rtc: Add rtc_merge_alarm()
Add rtc_merge_alarm(), which can be used by rtc drivers to turn a partially
specified alarm expiry (i.e. most significant fields set to -1, as with the
RTC_ALM_SET ioctl()) into a fully specified expiry.
If the most significant specified field is earlier than the current time, the
least significant unspecified field is incremented.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Acked-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-lib.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index ba795a4db1e9..7bbc26a34bd2 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -117,4 +117,85 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) } EXPORT_SYMBOL(rtc_tm_to_time); + +/* Merge the valid (i.e. non-negative) fields of alarm into the current + * time. If the valid alarm fields are earlier than the equivalent + * fields in the time, carry one into the least significant invalid + * field, so that the alarm expiry is in the future. It assumes that the + * least significant invalid field is more significant than the most + * significant valid field, and that the seconds field is valid. + * + * This is used by alarms that take relative (rather than absolute) + * times, and/or have a simple binary second counter instead of + * day/hour/minute/sec registers. + */ +void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm) +{ + int *alarmp = &alarm->tm_sec; + int *timep = &now->tm_sec; + int carry_into, i; + + /* Ignore everything past the 6th element (tm_year). */ + for (i = 5; i > 0; i--) { + if (alarmp[i] < 0) + alarmp[i] = timep[i]; + else + break; + } + + /* No carry needed if all fields are valid. */ + if (i == 5) + return; + + for (carry_into = i + 1; i >= 0; i--) { + if (alarmp[i] < timep[i]) + break; + + if (alarmp[i] > timep[i]) + return; + } + + switch (carry_into) { + case 1: + alarm->tm_min++; + + if (alarm->tm_min < 60) + return; + + alarm->tm_min = 0; + /* fall-through */ + + case 2: + alarm->tm_hour++; + + if (alarm->tm_hour < 60) + return; + + alarm->tm_hour = 0; + /* fall-through */ + + case 3: + alarm->tm_mday++; + + if (alarm->tm_mday <= rtc_days_in_month[alarm->tm_mon]) + return; + + alarm->tm_mday = 1; + /* fall-through */ + + case 4: + alarm->tm_mon++; + + if (alarm->tm_mon <= 12) + return; + + alarm->tm_mon = 1; + /* fall-through */ + + case 5: + alarm->tm_year++; + } +} +EXPORT_SYMBOL(rtc_merge_alarm); + MODULE_LICENSE("GPL"); |