Skip to content

Commit c8e0022

Browse files
cfriedtcarlescufi
authored andcommitted
drivers: rtc: mc146818: fix y2k bug
That's correct. We are still fixing the Y2K bug in 2023 \o/ * write century to RAM register 0x32 * ensure year register is in [0,99] (inclusive) Aside from that, there were a few other errors in the driver. * translate epoch-centric RTC API year to begin at 1900 * fix off-by-one error with month limit * fix off-by-one error with wday * fix off-by-one-hundred error with year limit * adjust timeptr values in rtc_mc146818_validate_time() * adjust timeptr values in rtc_mc146818_validate_alarm() With the above, the testsuite passes! Signed-off-by: Christopher Friedt <[email protected]>
1 parent 6c9a360 commit c8e0022

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

drivers/rtc/rtc_mc146818.c

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
#define RTC_MONTH 0x08
3535
#define RTC_YEAR 0x09
3636

37+
/* Y2K Bugfix */
38+
#define RTC_CENTURY 0x32
39+
3740
/* Alarm time indices in RTC RAM */
3841
#define RTC_ALARM_SEC 0x01
3942
#define RTC_ALARM_MIN 0x03
@@ -106,10 +109,10 @@
106109
#define MIN_WDAY 1
107110
#define MAX_MDAY 31
108111
#define MIN_MDAY 1
109-
#define MAX_MON 11
110-
#define MIN_MON 0
112+
#define MAX_MON 12
113+
#define MIN_MON 1
111114
#define MIN_YEAR_DIFF 0 /* YEAR - 1900 */
112-
#define MAX_YEAR_DIFF 199 /* YEAR - 1900 */
115+
#define MAX_YEAR_DIFF 99 /* YEAR - 1999 */
113116

114117
struct rtc_mc146818_data {
115118
struct k_spinlock lock;
@@ -149,16 +152,16 @@ static bool rtc_mc146818_validate_time(const struct rtc_time *timeptr)
149152
if (timeptr->tm_hour < MIN_HOUR || timeptr->tm_hour > MAX_HOUR) {
150153
return false;
151154
}
152-
if (timeptr->tm_wday < MIN_WDAY || timeptr->tm_wday > MAX_WDAY) {
155+
if (timeptr->tm_wday + 1 < MIN_WDAY || timeptr->tm_wday + 1 > MAX_WDAY) {
153156
return false;
154157
}
155158
if (timeptr->tm_mday < MIN_MDAY || timeptr->tm_mday > MAX_MDAY) {
156159
return false;
157160
}
158-
if (timeptr->tm_mon < MIN_MON || timeptr->tm_mon > MAX_MON) {
161+
if (timeptr->tm_mon + 1 < MIN_MON || timeptr->tm_mon + 1 > MAX_MON) {
159162
return false;
160163
}
161-
if (timeptr->tm_year < MIN_YEAR_DIFF || timeptr->tm_year > MAX_YEAR_DIFF) {
164+
if (timeptr->tm_year - 70 < MIN_YEAR_DIFF || timeptr->tm_year - 70 > MAX_YEAR_DIFF) {
162165
return false;
163166
}
164167
return true;
@@ -168,6 +171,8 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time
168171
{
169172
struct rtc_mc146818_data * const dev_data = dev->data;
170173
uint8_t value;
174+
int year;
175+
int cent;
171176
int ret;
172177

173178
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
@@ -186,22 +191,27 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time
186191
value = rtc_read(RTC_DATA);
187192
rtc_write(RTC_DATA, value | RTC_UCI_BIT);
188193

194+
year = (1970 + timeptr->tm_year) % 100;
195+
cent = (1970 + timeptr->tm_year) / 100;
196+
189197
if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) {
190198
rtc_write(RTC_SEC, (uint8_t)bin2bcd(timeptr->tm_sec));
191199
rtc_write(RTC_MIN, (uint8_t)bin2bcd(timeptr->tm_min));
192200
rtc_write(RTC_HOUR, (uint8_t)bin2bcd(timeptr->tm_hour));
193201
rtc_write(RTC_WDAY, (uint8_t)bin2bcd(timeptr->tm_wday));
194202
rtc_write(RTC_MDAY, (uint8_t)bin2bcd(timeptr->tm_mday));
195203
rtc_write(RTC_MONTH, (uint8_t)bin2bcd(timeptr->tm_mon + 1));
196-
rtc_write(RTC_YEAR, (uint8_t)bin2bcd(timeptr->tm_year));
204+
rtc_write(RTC_YEAR, (uint8_t)bin2bcd(year));
205+
rtc_write(RTC_CENTURY, (uint8_t)bin2bcd(cent));
197206
} else {
198207
rtc_write(RTC_SEC, (uint8_t)timeptr->tm_sec);
199208
rtc_write(RTC_MIN, (uint8_t)timeptr->tm_min);
200209
rtc_write(RTC_HOUR, (uint8_t)timeptr->tm_hour);
201210
rtc_write(RTC_WDAY, (uint8_t)timeptr->tm_wday);
202211
rtc_write(RTC_MDAY, (uint8_t)timeptr->tm_mday);
203212
rtc_write(RTC_MONTH, (uint8_t)timeptr->tm_mon + 1);
204-
rtc_write(RTC_YEAR, (uint8_t)timeptr->tm_year);
213+
rtc_write(RTC_YEAR, year);
214+
rtc_write(RTC_CENTURY, cent);
205215
}
206216

207217
if (timeptr->tm_isdst == 1) {
@@ -221,6 +231,8 @@ static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *tim
221231
{
222232
struct rtc_mc146818_data * const dev_data = dev->data;
223233
int ret;
234+
uint8_t cent;
235+
uint8_t year;
224236
uint8_t value;
225237

226238
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
@@ -239,16 +251,18 @@ static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *tim
239251
while (rtc_read(RTC_UIP) & RTC_UIP_BIT) {
240252
continue;
241253
}
242-
timeptr->tm_year = rtc_read(RTC_YEAR);
254+
cent = rtc_read(RTC_CENTURY);
255+
year = rtc_read(RTC_YEAR);
243256
timeptr->tm_mon = rtc_read(RTC_MONTH) - 1;
244257
timeptr->tm_mday = rtc_read(RTC_MDAY);
245-
timeptr->tm_wday = rtc_read(RTC_WDAY);
258+
timeptr->tm_wday = rtc_read(RTC_WDAY) - 1;
246259
timeptr->tm_hour = rtc_read(RTC_HOUR);
247260
timeptr->tm_min = rtc_read(RTC_MIN);
248261
timeptr->tm_sec = rtc_read(RTC_SEC);
249262

250263
if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) {
251-
timeptr->tm_year = bcd2bin(timeptr->tm_year);
264+
year = bcd2bin(year);
265+
cent = bcd2bin(cent);
252266
timeptr->tm_mon = bcd2bin(timeptr->tm_mon);
253267
timeptr->tm_mday = bcd2bin(timeptr->tm_mday);
254268
timeptr->tm_wday = bcd2bin(timeptr->tm_wday);
@@ -257,6 +271,8 @@ static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *tim
257271
timeptr->tm_sec = bcd2bin(timeptr->tm_sec);
258272
}
259273

274+
timeptr->tm_year = 100 * (int)cent + year - 1970;
275+
260276
timeptr->tm_nsec = 0;
261277
timeptr->tm_yday = 0;
262278
value = rtc_read(RTC_DATA);
@@ -296,7 +312,7 @@ static bool rtc_mc146818_validate_alarm(const struct rtc_time *timeptr, uint32_t
296312
}
297313

298314
if ((mask & RTC_ALARM_TIME_MASK_MONTH) &&
299-
(timeptr->tm_mon < MIN_WDAY || timeptr->tm_mon > MAX_WDAY)) {
315+
(timeptr->tm_mon + 1 < MIN_WDAY || timeptr->tm_mon + 1 > MAX_WDAY)) {
300316
return false;
301317
}
302318

@@ -306,7 +322,7 @@ static bool rtc_mc146818_validate_alarm(const struct rtc_time *timeptr, uint32_t
306322
}
307323

308324
if ((mask & RTC_ALARM_TIME_MASK_YEAR) &&
309-
(timeptr->tm_year < MIN_YEAR_DIFF || timeptr->tm_year > MAX_YEAR_DIFF)) {
325+
(timeptr->tm_year - 70 < MIN_YEAR_DIFF || timeptr->tm_year - 70 > MAX_YEAR_DIFF)) {
310326
return false;
311327
}
312328

0 commit comments

Comments
 (0)