void inittodr(time_t base) { struct clock_ymdhms dt; struct timespec ts; time_t rtc; if (!sh_clock.rtc_initialized) sh_clock.rtc_initialized = 1; sh_clock.rtc.get(sh_clock.rtc._cookie, base, &dt); rtc = clock_ymdhms_to_secs(&dt); #ifdef DEBUG printf("inittodr: %d/%d/%d/%d/%d/%d(%d)\n", dt.dt_year, dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec, dt.dt_wday); #endif if (!(sh_clock.flags & SH_CLOCK_NOINITTODR) && (rtc < base || dt.dt_year < MINYEAR || dt.dt_year > 2037 || dt.dt_mon < 1 || dt.dt_mon > 12 || dt.dt_wday > 6 || dt.dt_day < 1 || dt.dt_day > 31 || dt.dt_hour > 23 || dt.dt_min > 59 || dt.dt_sec > 59)) { /* * Believe the time in the file system for lack of * anything better, resetting the RTC. */ ts.tv_sec = base; ts.tv_nsec = 0; tc_setclock(&ts); printf("WARNING: preposterous clock chip time\n"); resettodr(); printf(" -- CHECK AND RESET THE DATE!\n"); return; } ts.tv_sec = rtc; ts.tv_nsec = 0; tc_setclock(&ts); return; }
/* * Reset the TODR based on the time value. */ void aurtc_set(struct device *dev, struct clocktime *ct) { struct clock_ymdhms ymdhms; time_t secs; ymdhms.dt_sec = ct->sec; ymdhms.dt_min = ct->min; ymdhms.dt_hour = ct->hour; ymdhms.dt_wday = ct->dow; ymdhms.dt_day = ct->day; ymdhms.dt_mon = ct->mon; ymdhms.dt_year = ct->year + PB1000_YEAR_OFFSET; secs = clock_ymdhms_to_secs(&ymdhms); *(u_int32_t *)MIPS_PHYS_TO_KSEG1(PC_BASE + PC_COUNTER_READ_0) = secs; }
void mkclock_isa_set(struct device *self, struct clocktime *ct) { struct mkclock_isa_softc *sc = (struct mkclock_isa_softc *)self; struct clock_ymdhms dt; struct timeval tv; dt.dt_year = ct->year + 1900; if (dt.dt_year < 1970) dt.dt_year += 100; dt.dt_mon = ct->mon; dt.dt_day = ct->day; dt.dt_wday = ct->dow; dt.dt_hour = ct->hour; dt.dt_min = ct->min; dt.dt_sec = ct->sec; tv.tv_sec = clock_ymdhms_to_secs(&dt); tv.tv_usec = 0; todr_settime(sc->sc_todr, &tv); }
/* * Return current RTC time. Note that due to waiting for the update cycle to * complete, this call may take some time. */ static uint64_t rtc_gettimeofday(void) { struct bmk_clock_ymdhms dt; interrupts_disable(); /* * If RTC_UIP is down, we have at least 244us to obtain a * consistent reading before an update can occur. */ while (rtc_read(RTC_STATUS_A) & RTC_UIP) continue; dt.dt_sec = bcdtobin(rtc_read(RTC_SEC)); dt.dt_min = bcdtobin(rtc_read(RTC_MIN)); dt.dt_hour = bcdtobin(rtc_read(RTC_HOUR)); dt.dt_day = bcdtobin(rtc_read(RTC_DAY)); dt.dt_mon = bcdtobin(rtc_read(RTC_MONTH)); dt.dt_year = bcdtobin(rtc_read(RTC_YEAR)) + 2000; interrupts_enable(); return clock_ymdhms_to_secs(&dt) * NSEC_PER_SEC; }
/* * Convert a NMEA 0183 formatted date string to seconds since the epoch. * The string must be of the form DDMMYY. * Return 0 on success, -1 if illegal characters are encountered. */ int nmea_date_to_nano(char *s, int64_t *nano) { struct clock_ymdhms ymd; time_t secs; char *p; int n; /* make sure the input contains only numbers and is six digits long */ for (n = 0, p = s; n < 6 && *p && *p >= '0' && *p <= '9'; n++, p++) ; if (n != 6 || (*p != '\0')) return (-1); ymd.dt_year = 2000 + (s[4] - '0') * 10 + (s[5] - '0'); ymd.dt_mon = (s[2] - '0') * 10 + (s[3] - '0'); ymd.dt_day = (s[0] - '0') * 10 + (s[1] - '0'); ymd.dt_hour = ymd.dt_min = ymd.dt_sec = 0; secs = clock_ymdhms_to_secs(&ymd); *nano = secs * 1000000000LL; return (0); }
static void todr_debug(const char *prefix, int rv, struct clock_ymdhms *dt, struct timeval *tvp) { struct timeval tv_val; struct clock_ymdhms dt_val; if (dt == NULL) { clock_secs_to_ymdhms(tvp->tv_sec, &dt_val); dt = &dt_val; } if (tvp == NULL) { tvp = &tv_val; tvp->tv_sec = clock_ymdhms_to_secs(dt); tvp->tv_usec = 0; } printf("%s: rv = %d\n", prefix, rv); printf("%s: rtc_offset = %d\n", prefix, rtc_offset); printf("%s: %4u/%02u/%02u %02u:%02u:%02u, (wday %d) (epoch %u.%06u)\n", prefix, (unsigned)dt->dt_year, dt->dt_mon, dt->dt_day, dt->dt_hour, dt->dt_min, dt->dt_sec, dt->dt_wday, (unsigned)tvp->tv_sec, (unsigned)tvp->tv_usec); }
/* * Set up the system's time, given a `reasonable' time value. */ void inittodr(time_t base) { bool badbase = false; bool waszero = (base == 0); bool goodtime = false; bool badrtc = false; int s; struct timespec ts; struct timeval tv; rnd_add_data(NULL, &base, sizeof(base), 0); if (base < 5 * SECS_PER_COMMON_YEAR) { struct clock_ymdhms basedate; /* * If base is 0, assume filesystem time is just unknown * instead of preposterous. Don't bark. */ if (base != 0) printf("WARNING: preposterous time in file system\n"); /* not going to use it anyway, if the chip is readable */ basedate.dt_year = 2010; basedate.dt_mon = 1; basedate.dt_day = 1; basedate.dt_hour = 12; basedate.dt_min = 0; basedate.dt_sec = 0; base = clock_ymdhms_to_secs(&basedate); badbase = true; } /* * Some ports need to be supplied base in order to fabricate a time_t. */ if (todr_handle) todr_handle->base_time = base; if ((todr_handle == NULL) || (todr_gettime(todr_handle, &tv) != 0) || (tv.tv_sec < (25 * SECS_PER_COMMON_YEAR))) { if (todr_handle != NULL) printf("WARNING: preposterous TOD clock time\n"); else printf("WARNING: no TOD clock present\n"); badrtc = true; } else { time_t deltat = tv.tv_sec - base; if (deltat < 0) deltat = -deltat; if (!badbase && deltat >= 2 * SECS_PER_DAY) { if (tv.tv_sec < base) { /* * The clock should never go backwards * relative to filesystem time. If it * does by more than the threshold, * believe the filesystem. */ printf("WARNING: clock lost %" PRId64 " days\n", deltat / SECS_PER_DAY); badrtc = true; } else { aprint_verbose("WARNING: clock gained %" PRId64 " days\n", deltat / SECS_PER_DAY); goodtime = true; } } else { goodtime = true; } rnd_add_data(NULL, &tv, sizeof(tv), 0); } /* if the rtc time is bad, use the filesystem time */ if (badrtc) { if (badbase) { printf("WARNING: using default initial time\n"); } else { printf("WARNING: using filesystem time\n"); } tv.tv_sec = base; tv.tv_usec = 0; } timeset = true; ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; s = splclock(); tc_setclock(&ts); splx(s); if (waszero || goodtime) return; printf("WARNING: CHECK AND RESET THE DATE!\n"); }