Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 884b4aaa authored by Scott Wood's avatar Scott Wood Committed by Linus Torvalds
Browse files

[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: default avatarScott Wood <scottwood@freescale.com>
Acked-by: default avatarAlessandro Zummo <a.zummo@towertech.it>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9080d0ae
Loading
Loading
Loading
Loading
+81 −0
Original line number Diff line number Diff line
@@ -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");
+1 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year
extern int rtc_valid_tm(struct rtc_time *tm);
extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
extern void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm);

#include <linux/device.h>
#include <linux/seq_file.h>