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