• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2020 Unisoc Communications Inc.
4  *
5  * This file is a implementation for rtc set read,covert to tm functions
6  */
7 
8 #include <stdbool.h>
9 #include <limits.h>
10 #define TST_NO_DEFAULT_MAIN
11 #include "tst_test.h"
12 #include "tst_rtctime.h"
13 
14 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
15 
16 static const unsigned char rtc_days_in_month[] = {
17 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
18 };
19 
is_leap_year(unsigned int year)20 static inline bool is_leap_year(unsigned int year)
21 {
22 	return (!(year % 4) && (year % 100)) || !(year % 400);
23 }
24 
tst_mktime(const unsigned int year0,const unsigned int mon0,const unsigned int day,const unsigned int hour,const unsigned int min,const unsigned int sec)25 static long long tst_mktime(const unsigned int year0, const unsigned int mon0,
26 		const unsigned int day, const unsigned int hour,
27 		const unsigned int min, const unsigned int sec)
28 {
29 	unsigned int mon = mon0, year = year0;
30 
31 	/* 1..12 -> 11,12,1..10 */
32 	mon -= 2;
33 	if (0 >= (int) (mon)) {
34 		mon += 12;	/* Puts Feb last since it has leap day */
35 		year -= 1;
36 	}
37 
38 	return ((((long long)
39 		(year/4 - year/100 + year/400 + 367*mon/12 + day) +
40 		year*365 - 719499
41 		)*24 + hour /* now have hours - midnight tomorrow handled here */
42 		)*60 + min /* now have minutes */
43 		)*60 + sec; /* finally seconds */
44 }
45 
46 /*
47  * The number of days in the month.
48  */
rtc_month_days(unsigned int month,unsigned int year)49 static int rtc_month_days(unsigned int month, unsigned int year)
50 {
51 	return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
52 }
53 
54 /*
55  * tst_rtc_time_to_tm - Converts time_t to rtc_time.
56  * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
57  */
tst_rtc_time_to_tm(long long time,struct rtc_time * tm)58 void tst_rtc_time_to_tm(long long time, struct rtc_time *tm)
59 {
60 	unsigned int month, year, secs;
61 	int days;
62 
63 	/* time must be positive */
64 	days = time / 86400;
65 	secs = time % 86400;
66 
67 	/* day of the week, 1970-01-01 was a Thursday */
68 	tm->tm_wday = (days + 4) % 7;
69 
70 	year = 1970 + days / 365;
71 	days -= (year - 1970) * 365
72 		+ LEAPS_THRU_END_OF(year - 1)
73 		- LEAPS_THRU_END_OF(1970 - 1);
74 	while (days < 0) {
75 		year -= 1;
76 		days += 365 + is_leap_year(year);
77 	}
78 	tm->tm_year = year - 1900;
79 	tm->tm_yday = days + 1;
80 
81 	for (month = 0; month < 11; month++) {
82 		int newdays;
83 
84 		newdays = days - rtc_month_days(month, year);
85 		if (newdays < 0)
86 			break;
87 		days = newdays;
88 	}
89 	tm->tm_mon = month;
90 	tm->tm_mday = days + 1;
91 
92 	tm->tm_hour = secs / 3600;
93 	secs -= tm->tm_hour * 3600;
94 	tm->tm_min = secs / 60;
95 	tm->tm_sec = secs - tm->tm_min * 60;
96 
97 	tm->tm_isdst = 0;
98 }
99 
100 /*
101  * tst_rtc_tm_to_time - Converts rtc_time to time_t.
102  * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
103  */
tst_rtc_tm_to_time(struct rtc_time * tm)104 long long tst_rtc_tm_to_time(struct rtc_time *tm)
105 {
106 	return tst_mktime(((unsigned int)tm->tm_year + 1900), tm->tm_mon + 1,
107 			tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
108 }
109 
tst_rtc_ioctl(const char * rtc_dev,unsigned long request,struct rtc_time * rtc_tm)110 int tst_rtc_ioctl(const char *rtc_dev, unsigned long request,
111                   struct rtc_time *rtc_tm)
112 {
113 	int ret;
114 	int rtc_fd = -1;
115 
116 	rtc_fd = SAFE_OPEN(rtc_dev, O_RDONLY);
117 
118 	ret = ioctl(rtc_fd, request, rtc_tm);
119 
120 	if (ret != 0)
121 		return -1;
122 
123 	if (rtc_fd > 0)
124 		SAFE_CLOSE(rtc_fd);
125 
126 	return 0;
127 }
128