diff --git a/rtc_linux.c b/rtc_linux.c index 11e2baa..4de11b0 100644 --- a/rtc_linux.c +++ b/rtc_linux.c @@ -497,8 +497,8 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate) /* ================================================== */ -static int -switch_interrupts(int on_off) +int +RTC_Linux_SwitchInterrupt(int fd, int on_off) { if (ioctl(fd, on_off ? RTC_UIE_ON : RTC_UIE_OFF, 0) < 0) { LOG(LOGS_ERR, "Could not %s RTC interrupt : %s", @@ -529,7 +529,7 @@ RTC_Linux_Initialise(void) } /* Make sure the RTC supports interrupts */ - if (!switch_interrupts(1) || !switch_interrupts(0)) { + if (!RTC_Linux_SwitchInterrupt(fd, 1) || !RTC_Linux_SwitchInterrupt(fd, 0)) { close(fd); return 0; } @@ -578,7 +578,7 @@ RTC_Linux_Finalise(void) /* Remove input file handler */ if (fd >= 0) { SCH_RemoveFileHandler(fd); - switch_interrupts(0); + RTC_Linux_SwitchInterrupt(fd, 0); close(fd); /* Save the RTC data */ @@ -599,7 +599,7 @@ static void measurement_timeout(void *any) { timeout_id = 0; - switch_interrupts(1); + RTC_Linux_SwitchInterrupt(fd, 1); } /* ================================================== */ @@ -760,15 +760,11 @@ process_reading(time_t rtc_time, struct timespec *system_time) /* ================================================== */ -static void -read_from_device(int fd_, int event, void *any) +int +RTC_Linux_CheckInterrupt(int fd) { int status; unsigned long data; - struct timespec sys_time; - struct rtc_time rtc_raw; - time_t rtc_t; - int error = 0; status = read(fd, &data, sizeof(data)); @@ -776,56 +772,68 @@ read_from_device(int fd_, int event, void *any) /* This looks like a bad error : the file descriptor was indicating it was * ready to read but we couldn't read anything. Give up. */ LOG(LOGS_ERR, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno)); - SCH_RemoveFileHandler(fd); - switch_interrupts(0); /* Likely to raise error too, but just to be sure... */ - close(fd); - fd = -1; - return; - } + return -1; + } if (skip_interrupts > 0) { /* Wait for the next interrupt, this one may be bogus */ skip_interrupts--; + return 0; + } + + /* Update interrupt detected? */ + return (data & RTC_UF) == RTC_UF; +} + +static void +read_from_device(int fd_, int event, void *any) +{ + int status; + struct timespec sys_time; + struct rtc_time rtc_raw; + time_t rtc_t; + int error = 0; + + status = RTC_Linux_CheckInterrupt(fd); + if (status < 0) { + SCH_RemoveFileHandler(fd); + RTC_Linux_SwitchInterrupt(fd, 0); /* Likely to raise error too, but just to be sure... */ + close(fd); + fd = -1; + return; + } else if (status == 0) { return; } - if ((data & RTC_UF) == RTC_UF) { - /* Update interrupt detected */ - - /* Read RTC time, sandwiched between two polls of the system clock - so we can bound any error. */ + SCH_GetLastEventTime(&sys_time, NULL, NULL); - SCH_GetLastEventTime(&sys_time, NULL, NULL); + status = ioctl(fd, RTC_RD_TIME, &rtc_raw); + if (status < 0) { + LOG(LOGS_ERR, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno)); + error = 1; + goto turn_off_interrupt; + } - status = ioctl(fd, RTC_RD_TIME, &rtc_raw); - if (status < 0) { - LOG(LOGS_ERR, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno)); - error = 1; - goto turn_off_interrupt; - } + /* Convert RTC time into a struct timespec */ + rtc_t = t_from_rtc(&rtc_raw, rtc_on_utc); - /* Convert RTC time into a struct timespec */ - rtc_t = t_from_rtc(&rtc_raw, rtc_on_utc); + if (rtc_t == (time_t)(-1)) { + error = 1; + goto turn_off_interrupt; + } - if (rtc_t == (time_t)(-1)) { - error = 1; - goto turn_off_interrupt; - } - - process_reading(rtc_t, &sys_time); - - if (n_samples < 4) { - measurement_period = LOWEST_MEASUREMENT_PERIOD; - } else if (n_samples < 6) { - measurement_period = LOWEST_MEASUREMENT_PERIOD << 1; - } else if (n_samples < 10) { - measurement_period = LOWEST_MEASUREMENT_PERIOD << 2; - } else if (n_samples < 14) { - measurement_period = LOWEST_MEASUREMENT_PERIOD << 3; - } else { - measurement_period = LOWEST_MEASUREMENT_PERIOD << 4; - } + process_reading(rtc_t, &sys_time); + if (n_samples < 4) { + measurement_period = LOWEST_MEASUREMENT_PERIOD; + } else if (n_samples < 6) { + measurement_period = LOWEST_MEASUREMENT_PERIOD << 1; + } else if (n_samples < 10) { + measurement_period = LOWEST_MEASUREMENT_PERIOD << 2; + } else if (n_samples < 14) { + measurement_period = LOWEST_MEASUREMENT_PERIOD << 3; + } else { + measurement_period = LOWEST_MEASUREMENT_PERIOD << 4; } turn_off_interrupt: @@ -837,7 +845,7 @@ turn_off_interrupt: operating_mode = OM_NORMAL; (after_init_hook)(after_init_hook_arg); - switch_interrupts(0); + RTC_Linux_SwitchInterrupt(fd, 0); timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL); } @@ -849,7 +857,7 @@ turn_off_interrupt: DEBUG_LOG("Could not complete after trim relock due to errors"); operating_mode = OM_NORMAL; - switch_interrupts(0); + RTC_Linux_SwitchInterrupt(fd, 0); timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL); } @@ -857,7 +865,7 @@ turn_off_interrupt: break; case OM_NORMAL: - switch_interrupts(0); + RTC_Linux_SwitchInterrupt(fd, 0); timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL); @@ -879,7 +887,7 @@ RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything) operating_mode = OM_INITIAL; timeout_id = 0; - switch_interrupts(1); + RTC_Linux_SwitchInterrupt(fd, 1); } /* ================================================== */ @@ -1058,7 +1066,7 @@ RTC_Linux_Trim(void) /* And start rapid sampling, interrupts on now */ SCH_RemoveTimeout(timeout_id); timeout_id = 0; - switch_interrupts(1); + RTC_Linux_SwitchInterrupt(fd, 1); } return 1; diff --git a/rtc_linux.h b/rtc_linux.h index fa33ef1..1f67ba8 100644 --- a/rtc_linux.h +++ b/rtc_linux.h @@ -42,4 +42,7 @@ extern int RTC_Linux_Trim(void); extern void RTC_Linux_CycleLogFile(void); +extern int RTC_Linux_SwitchInterrupt(int fd, int on_off); +extern int RTC_Linux_CheckInterrupt(int fd); + #endif /* _GOT_RTC_LINUX_H */