diff options
Diffstat (limited to 'sys/isa/atrtc.c')
-rw-r--r-- | sys/isa/atrtc.c | 271 |
1 files changed, 168 insertions, 103 deletions
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c index 09a9dc4..6573b37 100644 --- a/sys/isa/atrtc.c +++ b/sys/isa/atrtc.c @@ -206,7 +206,6 @@ timer_spkr_setfreq(int freq) mtx_unlock_spin(&clock_lock); } - /* * This routine receives statistical clock interrupts from the RTC. * As explained above, these occur at 128 interrupts per second. @@ -396,8 +395,7 @@ DELAY(int n) */ int -rtcin(reg) - int reg; +rtcin(int reg) { u_char val; @@ -522,98 +520,6 @@ startrtclock() } /* - * Initialize the time of day register, based on the time base which is, e.g. - * from a filesystem. - */ -void -inittodr(time_t base) -{ - int s; - struct timespec ts; - struct clocktime ct; - - if (base) { - s = splclock(); - ts.tv_sec = base; - ts.tv_nsec = 0; - tc_setclock(&ts); - splx(s); - } - - /* Look if we have a RTC present and the time is valid */ - if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) { - printf("Invalid time in clock: check and reset the date!\n"); - return; - } - - /* wait for time update to complete */ - /* If RTCSA_TUP is zero, we have at least 244us before next update */ - s = splhigh(); - while (rtcin(RTC_STATUSA) & RTCSA_TUP) { - splx(s); - s = splhigh(); - } - ct.nsec = 0; - ct.sec = readrtc(RTC_SEC); - ct.min = readrtc(RTC_MIN); - ct.hour = readrtc(RTC_HRS); - ct.day = readrtc(RTC_DAY); - ct.dow = readrtc(RTC_WDAY) - 1; - ct.mon = readrtc(RTC_MONTH); - ct.year = readrtc(RTC_YEAR); -#ifdef USE_RTC_CENTURY - ct.year += readrtc(RTC_CENTURY) * 100; -#else - ct.year += 2000; -#endif - /* Set dow = -1 because some clocks don't set it correctly. */ - ct.dow = -1; - if (clock_ct_to_ts(&ct, &ts)) { - printf("Invalid time in clock: check and reset the date!\n"); - return; - } - ts.tv_sec += utc_offset(); - tc_setclock(&ts); -} - -/* - * Write system time back to RTC - */ -void -resettodr() -{ - struct timespec ts; - struct clocktime ct; - - if (disable_rtc_set) - return; - - getnanotime(&ts); - ts.tv_sec -= utc_offset(); - clock_ts_to_ct(&ts, &ct); - - /* Disable RTC updates and interrupts. */ - writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); - - writertc(RTC_SEC, bin2bcd(ct.sec)); /* Write back Seconds */ - writertc(RTC_MIN, bin2bcd(ct.min)); /* Write back Minutes */ - writertc(RTC_HRS, bin2bcd(ct.hour)); /* Write back Hours */ - - writertc(RTC_WDAY, ct.dow + 1); /* Write back Weekday */ - writertc(RTC_DAY, bin2bcd(ct.day)); /* Write back Day */ - writertc(RTC_MONTH, bin2bcd(ct.mon)); /* Write back Month */ - writertc(RTC_YEAR, bin2bcd(ct.year % 100)); /* Write back Year */ -#ifdef USE_RTC_CENTURY - writertc(RTC_CENTURY, bin2bcd(ct.year / 100)); /* ... and Century */ -#endif - - /* Reenable RTC updates and interrupts. */ - writertc(RTC_STATUSB, rtc_statusb); - rtcin(RTC_INTR); -} - - -/* * Start both clocks running. */ void @@ -657,7 +563,8 @@ cpu_initclocks() if (!statclock_disable && !using_lapic_timer) { diag = rtcin(RTC_DIAG); if (diag != 0) - printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); + printf("RTC BIOS diagnostic error %b\n", + diag, RTCDG_BITS); /* Setting stathz to nonzero early helps avoid races. */ stathz = RTC_NOPROFRATE; @@ -665,7 +572,8 @@ cpu_initclocks() /* Enable periodic interrupts from the RTC. */ rtc_statusb |= RTCSB_PINTR; - intr_add_handler("rtc", 8, (driver_filter_t *)rtcintr, NULL, NULL, + intr_add_handler("rtc", 8, + (driver_filter_t *)rtcintr, NULL, NULL, INTR_TYPE_CLK, NULL); writertc(RTC_STATUSB, rtc_statusb); @@ -742,7 +650,8 @@ i8254_get_timecount(struct timecounter *tc) count = i8254_max_count - ((high << 8) | low); if (count < i8254_lastcount || (!i8254_ticked && (clkintr_pending || - ((count < 20 || (!(eflags & PSL_I) && count < i8254_max_count / 2u)) && + ((count < 20 || (!(eflags & PSL_I) && + count < i8254_max_count / 2u)) && i8254_pending != NULL && i8254_pending(i8254_intsrc))))) { i8254_ticked = 1; i8254_offset += i8254_max_count; @@ -755,11 +664,10 @@ i8254_get_timecount(struct timecounter *tc) #ifdef DEV_ISA /* - * Attach to the ISA PnP descriptors for the timer and realtime clock. + * Attach to the ISA PnP descriptors for the timer */ static struct isa_pnp_id attimer_ids[] = { { 0x0001d041 /* PNP0100 */, "AT timer" }, - { 0x000bd041 /* PNP0B00 */, "AT realtime clock" }, { 0 } }; @@ -768,7 +676,8 @@ attimer_probe(device_t dev) { int result; - if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids)) <= 0) + result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids); + if (result <= 0) device_quiet(dev); return(result); } @@ -785,8 +694,8 @@ static device_method_t attimer_methods[] = { DEVMETHOD(device_attach, attimer_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX stop statclock? */ - DEVMETHOD(device_resume, bus_generic_resume), /* XXX restart statclock? */ + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), { 0, 0 } }; @@ -802,3 +711,159 @@ DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0); DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0); #endif /* DEV_ISA */ + +#ifdef DEV_ISA + +/********************************************************************** + * RTC driver for subr_rtc + */ + +#include "clock_if.h" + +#include <sys/rman.h> + +struct atrtc_softc { + int port_rid, intr_rid; + struct resource *port_res; + struct resource *intr_res; +}; + +/* + * Attach to the ISA PnP descriptors for the timer and realtime clock. + */ +static struct isa_pnp_id atrtc_ids[] = { + { 0x000bd041 /* PNP0B00 */, "AT realtime clock" }, + { 0 } +}; + +static int +atrtc_probe(device_t dev) +{ + int result; + + device_set_desc(dev, "AT Real Time Clock"); + result = ISA_PNP_PROBE(device_get_parent(dev), dev, atrtc_ids); + /* ENXIO if wrong PnP-ID, ENOENT ifno PnP-ID, zero if good PnP-iD */ + if (result != ENOENT) + return(result); + /* All PC's have an RTC, and we're hosed without it, so... */ + return (BUS_PROBE_LOW_PRIORITY); +} + +static int +atrtc_attach(device_t dev) +{ + struct atrtc_softc *sc; + + /* + * Not that we need them or anything, but grab our resources + * so they show up, correctly attributed, in the big picture. + */ + + sc = device_get_softc(dev); + if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->port_rid, IO_RTC, IO_RTC + 1, 2, RF_ACTIVE))) + device_printf(dev,"Warning: Couldn't map I/O.\n"); + if (!(sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ, + &sc->intr_rid, 8, 8, 1, RF_ACTIVE))) + device_printf(dev,"Warning: Couldn't map Interrupt.\n"); + clock_register(dev, 1000000); + return(0); +} + + +static int +atrtc_settime(device_t dev __unused, struct timespec *ts) +{ + struct clocktime ct; + + clock_ts_to_ct(ts, &ct); + + /* Disable RTC updates and interrupts. */ + writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); + + writertc(RTC_SEC, bin2bcd(ct.sec)); /* Write back Seconds */ + writertc(RTC_MIN, bin2bcd(ct.min)); /* Write back Minutes */ + writertc(RTC_HRS, bin2bcd(ct.hour)); /* Write back Hours */ + + writertc(RTC_WDAY, ct.dow + 1); /* Write back Weekday */ + writertc(RTC_DAY, bin2bcd(ct.day)); /* Write back Day */ + writertc(RTC_MONTH, bin2bcd(ct.mon)); /* Write back Month */ + writertc(RTC_YEAR, bin2bcd(ct.year % 100)); /* Write back Year */ +#ifdef USE_RTC_CENTURY + writertc(RTC_CENTURY, bin2bcd(ct.year / 100)); /* ... and Century */ +#endif + + /* Reenable RTC updates and interrupts. */ + writertc(RTC_STATUSB, rtc_statusb); + rtcin(RTC_INTR); + return (0); +} + +static int +atrtc_gettime(device_t dev, struct timespec *ts) +{ + struct clocktime ct; + int s; + + /* Look if we have a RTC present and the time is valid */ + if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) { + device_printf(dev, "WARNING: Battery failure indication\n"); + return (EINVAL); + } + + /* wait for time update to complete */ + /* If RTCSA_TUP is zero, we have at least 244us before next update */ + s = splhigh(); + while (rtcin(RTC_STATUSA) & RTCSA_TUP) { + splx(s); + s = splhigh(); + } + ct.nsec = 0; + ct.sec = readrtc(RTC_SEC); + ct.min = readrtc(RTC_MIN); + ct.hour = readrtc(RTC_HRS); + ct.day = readrtc(RTC_DAY); + ct.dow = readrtc(RTC_WDAY) - 1; + ct.mon = readrtc(RTC_MONTH); + ct.year = readrtc(RTC_YEAR); +#ifdef USE_RTC_CENTURY + ct.year += readrtc(RTC_CENTURY) * 100; +#else + ct.year += 2000; +#endif + /* Set dow = -1 because some clocks don't set it correctly. */ + ct.dow = -1; + return (clock_ct_to_ts(&ct, ts)); +} + +static device_method_t atrtc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, atrtc_probe), + DEVMETHOD(device_attach, atrtc_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + /* XXX stop statclock? */ + DEVMETHOD(device_resume, bus_generic_resume), + /* XXX restart statclock? */ + + /* clock interface */ + DEVMETHOD(clock_gettime, atrtc_gettime), + DEVMETHOD(clock_settime, atrtc_settime), + + { 0, 0 } +}; + +static driver_t atrtc_driver = { + "atrtc", + atrtc_methods, + sizeof(struct atrtc_softc), +}; + +static devclass_t atrtc_devclass; + +DRIVER_MODULE(atrtc, isa, atrtc_driver, atrtc_devclass, 0, 0); +DRIVER_MODULE(atrtc, acpi, atrtc_driver, atrtc_devclass, 0, 0); + +#endif /* DEV_ISA */ |