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