diff options
author | nyan <nyan@FreeBSD.org> | 2008-04-13 06:18:34 +0000 |
---|---|---|
committer | nyan <nyan@FreeBSD.org> | 2008-04-13 06:18:34 +0000 |
commit | 2eacd7b476600b3e66f2802706ee6d4b7c1a8fcd (patch) | |
tree | 5b8190c37a43fce75714365930aa1ef016d5a2a1 /sys/pc98/cbus | |
parent | c75b6e5deaa6b6d7d248ad0d6bc10617367b80dd (diff) | |
download | FreeBSD-src-2eacd7b476600b3e66f2802706ee6d4b7c1a8fcd.zip FreeBSD-src-2eacd7b476600b3e66f2802706ee6d4b7c1a8fcd.tar.gz |
MFi386: RTC related cleanups.
- Use generic RTC handling code.
- Make clock_if.m and subr_rtc.c standard.
- Nuke MD inittodr(), resettodr() functions.
- Add new "pcrtc" device driver.
- Add hints for "pcrtc" driver.
Diffstat (limited to 'sys/pc98/cbus')
-rw-r--r-- | sys/pc98/cbus/clock.c | 355 | ||||
-rw-r--r-- | sys/pc98/cbus/pcrtc.c | 355 |
2 files changed, 428 insertions, 282 deletions
diff --git a/sys/pc98/cbus/clock.c b/sys/pc98/cbus/clock.c index 05d34c5..81f61b9 100644 --- a/sys/pc98/cbus/clock.c +++ b/sys/pc98/cbus/clock.c @@ -119,10 +119,6 @@ static int using_lapic_timer; #define ACQUIRE_PENDING 3 static u_char timer1_state; -static void rtc_serialcombit(int); -static void rtc_serialcom(int); -static int rtc_inb(void); -static void rtc_outb(int); static unsigned i8254_get_timecount(struct timecounter *tc); static unsigned i8254_simple_get_timecount(struct timecounter *tc); @@ -400,137 +396,6 @@ startrtclock() init_TSC(); } -static void -rtc_serialcombit(int i) -{ - outb(IO_RTC, ((i&0x01)<<5)|0x07); - DELAY(1); - outb(IO_RTC, ((i&0x01)<<5)|0x17); - DELAY(1); - outb(IO_RTC, ((i&0x01)<<5)|0x07); - DELAY(1); -} - -static void -rtc_serialcom(int i) -{ - rtc_serialcombit(i&0x01); - rtc_serialcombit((i&0x02)>>1); - rtc_serialcombit((i&0x04)>>2); - rtc_serialcombit((i&0x08)>>3); - outb(IO_RTC, 0x07); - DELAY(1); - outb(IO_RTC, 0x0f); - DELAY(1); - outb(IO_RTC, 0x07); - DELAY(1); -} - -static void -rtc_outb(int val) -{ - int s; - int sa = 0; - - for (s=0;s<8;s++) { - sa = ((val >> s) & 0x01) ? 0x27 : 0x07; - outb(IO_RTC, sa); /* set DI & CLK 0 */ - DELAY(1); - outb(IO_RTC, sa | 0x10); /* CLK 1 */ - DELAY(1); - } - outb(IO_RTC, sa & 0xef); /* CLK 0 */ -} - -static int -rtc_inb(void) -{ - int s; - int sa = 0; - - for (s=0;s<8;s++) { - sa |= ((inb(0x33) & 0x01) << s); - outb(IO_RTC, 0x17); /* CLK 1 */ - DELAY(1); - outb(IO_RTC, 0x07); /* CLK 0 */ - DELAY(2); - } - return sa; -} - -/* - * Initialize the time of day register, based on the time base which is, e.g. - * from a filesystem. - */ -void -inittodr(time_t base) -{ - struct timespec ts; - struct clocktime ct; - int i; - - if (base) { - ts.tv_sec = base; - ts.tv_nsec = 0; - tc_setclock(&ts); - } - - rtc_serialcom(0x03); /* Time Read */ - rtc_serialcom(0x01); /* Register shift command. */ - DELAY(20); - - ct.nsec = 0; - ct.sec = bcd2bin(rtc_inb() & 0xff); /* sec */ - ct.min = bcd2bin(rtc_inb() & 0xff); /* min */ - ct.hour = bcd2bin(rtc_inb() & 0xff); /* hour */ - ct.day = bcd2bin(rtc_inb() & 0xff); /* date */ - i = rtc_inb(); - ct.dow = i & 0x0f; /* dow */ - ct.mon = (i >> 4) & 0x0f; /* month */ - ct.year = bcd2bin(rtc_inb() & 0xff) + 1900; /* year */ - if (ct.year < 1995) - ct.year += 100; - /* 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); - - rtc_serialcom(0x01); /* Register shift command. */ - - rtc_outb(bin2bcd(ct.sec)); /* Write back Seconds */ - rtc_outb(bin2bcd(ct.min)); /* Write back Minutes */ - rtc_outb(bin2bcd(ct.hour)); /* Write back Hours */ - - rtc_outb(bin2bcd(ct.day)); /* Write back Day */ - rtc_outb((ct.mon << 4) | ct.dow); /* Write back Month and DOW */ - rtc_outb(bin2bcd(ct.year % 100)); /* Write back Year */ - - rtc_serialcom(0x02); /* Time set & Counter hold command. */ - rtc_serialcom(0x00); /* Register hold command. */ -} - - /* * Start both clocks running. */ @@ -619,7 +484,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; @@ -632,11 +498,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 } }; @@ -645,7 +510,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); } @@ -662,8 +528,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 } }; @@ -676,4 +542,211 @@ static driver_t attimer_driver = { static devclass_t attimer_devclass; DRIVER_MODULE(attimer, isa, 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> + +static void rtc_serialcombit(int); +static void rtc_serialcom(int); +static int rtc_inb(void); +static void rtc_outb(int); + +static void +rtc_serialcombit(int i) +{ + outb(IO_RTC, ((i&0x01)<<5)|0x07); + DELAY(1); + outb(IO_RTC, ((i&0x01)<<5)|0x17); + DELAY(1); + outb(IO_RTC, ((i&0x01)<<5)|0x07); + DELAY(1); +} + +static void +rtc_serialcom(int i) +{ + rtc_serialcombit(i&0x01); + rtc_serialcombit((i&0x02)>>1); + rtc_serialcombit((i&0x04)>>2); + rtc_serialcombit((i&0x08)>>3); + outb(IO_RTC, 0x07); + DELAY(1); + outb(IO_RTC, 0x0f); + DELAY(1); + outb(IO_RTC, 0x07); + DELAY(1); +} + +static void +rtc_outb(int val) +{ + int s; + int sa = 0; + + for (s=0;s<8;s++) { + sa = ((val >> s) & 0x01) ? 0x27 : 0x07; + outb(IO_RTC, sa); /* set DI & CLK 0 */ + DELAY(1); + outb(IO_RTC, sa | 0x10); /* CLK 1 */ + DELAY(1); + } + outb(IO_RTC, sa & 0xef); /* CLK 0 */ +} + +static int +rtc_inb(void) +{ + int s; + int sa = 0; + + for (s=0;s<8;s++) { + sa |= ((inb(0x33) & 0x01) << s); + outb(IO_RTC, 0x17); /* CLK 1 */ + DELAY(1); + outb(IO_RTC, 0x07); /* CLK 0 */ + DELAY(2); + } + return sa; +} + +struct pcrtc_softc { + int port_rid1, port_rid2; + struct resource *port_res1, *port_res2; +}; + +/* + * Attach to the ISA PnP descriptors for the timer and realtime clock. + */ +static struct isa_pnp_id pcrtc_ids[] = { + { 0x000bd041 /* PNP0B00 */, "AT realtime clock" }, + { 0 } +}; + +static int +pcrtc_probe(device_t dev) +{ + int result; + + device_set_desc(dev, "PC Real Time Clock"); + result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcrtc_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 +pcrtc_attach(device_t dev) +{ + struct pcrtc_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); + sc->port_rid1 = 0; + bus_set_resource(dev, SYS_RES_IOPORT, sc->port_rid1, IO_RTC, 1); + if (!(sc->port_res1 = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->port_rid1, IO_RTC, IO_RTC, 1, RF_ACTIVE))) + device_printf(dev, "Warning: Couldn't map I/O.\n"); + sc->port_rid2 = 1; + bus_set_resource(dev, SYS_RES_IOPORT, sc->port_rid2, 0x33, 1); + if (!(sc->port_res2 = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->port_rid2, 0x33, 0x33, 1, RF_ACTIVE))) + device_printf(dev, "Warning: Couldn't map I/O.\n"); + + clock_register(dev, 1000000); + return(0); +} + +static int +pcrtc_settime(device_t dev __unused, struct timespec *ts) +{ + struct clocktime ct; + + clock_ts_to_ct(ts, &ct); + + rtc_serialcom(0x01); /* Register shift command. */ + + rtc_outb(bin2bcd(ct.sec)); /* Write back Seconds */ + rtc_outb(bin2bcd(ct.min)); /* Write back Minutes */ + rtc_outb(bin2bcd(ct.hour)); /* Write back Hours */ + + rtc_outb(bin2bcd(ct.day)); /* Write back Day */ + rtc_outb((ct.mon << 4) | ct.dow); /* Write back Month and DOW */ + rtc_outb(bin2bcd(ct.year % 100)); /* Write back Year */ + + rtc_serialcom(0x02); /* Time set & Counter hold command. */ + rtc_serialcom(0x00); /* Register hold command. */ + + return (0); +} + +static int +pcrtc_gettime(device_t dev, struct timespec *ts) +{ + struct clocktime ct; + int i; + + rtc_serialcom(0x03); /* Time Read */ + rtc_serialcom(0x01); /* Register shift command. */ + DELAY(20); + + ct.nsec = 0; + ct.sec = bcd2bin(rtc_inb() & 0xff); /* sec */ + ct.min = bcd2bin(rtc_inb() & 0xff); /* min */ + ct.hour = bcd2bin(rtc_inb() & 0xff); /* hour */ + ct.day = bcd2bin(rtc_inb() & 0xff); /* date */ + i = rtc_inb(); + ct.dow = i & 0x0f; /* dow */ + ct.mon = (i >> 4) & 0x0f; /* month */ + ct.year = bcd2bin(rtc_inb() & 0xff) + 1900; /* year */ + if (ct.year < 1995) + ct.year += 100; + + /* 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 pcrtc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pcrtc_probe), + DEVMETHOD(device_attach, pcrtc_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, pcrtc_gettime), + DEVMETHOD(clock_settime, pcrtc_settime), + + { 0, 0 } +}; + +static driver_t pcrtc_driver = { + "pcrtc", + pcrtc_methods, + sizeof(struct pcrtc_softc), +}; + +static devclass_t pcrtc_devclass; + +DRIVER_MODULE(pcrtc, isa, pcrtc_driver, pcrtc_devclass, 0, 0); + #endif /* DEV_ISA */ diff --git a/sys/pc98/cbus/pcrtc.c b/sys/pc98/cbus/pcrtc.c index 05d34c5..81f61b9 100644 --- a/sys/pc98/cbus/pcrtc.c +++ b/sys/pc98/cbus/pcrtc.c @@ -119,10 +119,6 @@ static int using_lapic_timer; #define ACQUIRE_PENDING 3 static u_char timer1_state; -static void rtc_serialcombit(int); -static void rtc_serialcom(int); -static int rtc_inb(void); -static void rtc_outb(int); static unsigned i8254_get_timecount(struct timecounter *tc); static unsigned i8254_simple_get_timecount(struct timecounter *tc); @@ -400,137 +396,6 @@ startrtclock() init_TSC(); } -static void -rtc_serialcombit(int i) -{ - outb(IO_RTC, ((i&0x01)<<5)|0x07); - DELAY(1); - outb(IO_RTC, ((i&0x01)<<5)|0x17); - DELAY(1); - outb(IO_RTC, ((i&0x01)<<5)|0x07); - DELAY(1); -} - -static void -rtc_serialcom(int i) -{ - rtc_serialcombit(i&0x01); - rtc_serialcombit((i&0x02)>>1); - rtc_serialcombit((i&0x04)>>2); - rtc_serialcombit((i&0x08)>>3); - outb(IO_RTC, 0x07); - DELAY(1); - outb(IO_RTC, 0x0f); - DELAY(1); - outb(IO_RTC, 0x07); - DELAY(1); -} - -static void -rtc_outb(int val) -{ - int s; - int sa = 0; - - for (s=0;s<8;s++) { - sa = ((val >> s) & 0x01) ? 0x27 : 0x07; - outb(IO_RTC, sa); /* set DI & CLK 0 */ - DELAY(1); - outb(IO_RTC, sa | 0x10); /* CLK 1 */ - DELAY(1); - } - outb(IO_RTC, sa & 0xef); /* CLK 0 */ -} - -static int -rtc_inb(void) -{ - int s; - int sa = 0; - - for (s=0;s<8;s++) { - sa |= ((inb(0x33) & 0x01) << s); - outb(IO_RTC, 0x17); /* CLK 1 */ - DELAY(1); - outb(IO_RTC, 0x07); /* CLK 0 */ - DELAY(2); - } - return sa; -} - -/* - * Initialize the time of day register, based on the time base which is, e.g. - * from a filesystem. - */ -void -inittodr(time_t base) -{ - struct timespec ts; - struct clocktime ct; - int i; - - if (base) { - ts.tv_sec = base; - ts.tv_nsec = 0; - tc_setclock(&ts); - } - - rtc_serialcom(0x03); /* Time Read */ - rtc_serialcom(0x01); /* Register shift command. */ - DELAY(20); - - ct.nsec = 0; - ct.sec = bcd2bin(rtc_inb() & 0xff); /* sec */ - ct.min = bcd2bin(rtc_inb() & 0xff); /* min */ - ct.hour = bcd2bin(rtc_inb() & 0xff); /* hour */ - ct.day = bcd2bin(rtc_inb() & 0xff); /* date */ - i = rtc_inb(); - ct.dow = i & 0x0f; /* dow */ - ct.mon = (i >> 4) & 0x0f; /* month */ - ct.year = bcd2bin(rtc_inb() & 0xff) + 1900; /* year */ - if (ct.year < 1995) - ct.year += 100; - /* 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); - - rtc_serialcom(0x01); /* Register shift command. */ - - rtc_outb(bin2bcd(ct.sec)); /* Write back Seconds */ - rtc_outb(bin2bcd(ct.min)); /* Write back Minutes */ - rtc_outb(bin2bcd(ct.hour)); /* Write back Hours */ - - rtc_outb(bin2bcd(ct.day)); /* Write back Day */ - rtc_outb((ct.mon << 4) | ct.dow); /* Write back Month and DOW */ - rtc_outb(bin2bcd(ct.year % 100)); /* Write back Year */ - - rtc_serialcom(0x02); /* Time set & Counter hold command. */ - rtc_serialcom(0x00); /* Register hold command. */ -} - - /* * Start both clocks running. */ @@ -619,7 +484,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; @@ -632,11 +498,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 } }; @@ -645,7 +510,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); } @@ -662,8 +528,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 } }; @@ -676,4 +542,211 @@ static driver_t attimer_driver = { static devclass_t attimer_devclass; DRIVER_MODULE(attimer, isa, 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> + +static void rtc_serialcombit(int); +static void rtc_serialcom(int); +static int rtc_inb(void); +static void rtc_outb(int); + +static void +rtc_serialcombit(int i) +{ + outb(IO_RTC, ((i&0x01)<<5)|0x07); + DELAY(1); + outb(IO_RTC, ((i&0x01)<<5)|0x17); + DELAY(1); + outb(IO_RTC, ((i&0x01)<<5)|0x07); + DELAY(1); +} + +static void +rtc_serialcom(int i) +{ + rtc_serialcombit(i&0x01); + rtc_serialcombit((i&0x02)>>1); + rtc_serialcombit((i&0x04)>>2); + rtc_serialcombit((i&0x08)>>3); + outb(IO_RTC, 0x07); + DELAY(1); + outb(IO_RTC, 0x0f); + DELAY(1); + outb(IO_RTC, 0x07); + DELAY(1); +} + +static void +rtc_outb(int val) +{ + int s; + int sa = 0; + + for (s=0;s<8;s++) { + sa = ((val >> s) & 0x01) ? 0x27 : 0x07; + outb(IO_RTC, sa); /* set DI & CLK 0 */ + DELAY(1); + outb(IO_RTC, sa | 0x10); /* CLK 1 */ + DELAY(1); + } + outb(IO_RTC, sa & 0xef); /* CLK 0 */ +} + +static int +rtc_inb(void) +{ + int s; + int sa = 0; + + for (s=0;s<8;s++) { + sa |= ((inb(0x33) & 0x01) << s); + outb(IO_RTC, 0x17); /* CLK 1 */ + DELAY(1); + outb(IO_RTC, 0x07); /* CLK 0 */ + DELAY(2); + } + return sa; +} + +struct pcrtc_softc { + int port_rid1, port_rid2; + struct resource *port_res1, *port_res2; +}; + +/* + * Attach to the ISA PnP descriptors for the timer and realtime clock. + */ +static struct isa_pnp_id pcrtc_ids[] = { + { 0x000bd041 /* PNP0B00 */, "AT realtime clock" }, + { 0 } +}; + +static int +pcrtc_probe(device_t dev) +{ + int result; + + device_set_desc(dev, "PC Real Time Clock"); + result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcrtc_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 +pcrtc_attach(device_t dev) +{ + struct pcrtc_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); + sc->port_rid1 = 0; + bus_set_resource(dev, SYS_RES_IOPORT, sc->port_rid1, IO_RTC, 1); + if (!(sc->port_res1 = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->port_rid1, IO_RTC, IO_RTC, 1, RF_ACTIVE))) + device_printf(dev, "Warning: Couldn't map I/O.\n"); + sc->port_rid2 = 1; + bus_set_resource(dev, SYS_RES_IOPORT, sc->port_rid2, 0x33, 1); + if (!(sc->port_res2 = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->port_rid2, 0x33, 0x33, 1, RF_ACTIVE))) + device_printf(dev, "Warning: Couldn't map I/O.\n"); + + clock_register(dev, 1000000); + return(0); +} + +static int +pcrtc_settime(device_t dev __unused, struct timespec *ts) +{ + struct clocktime ct; + + clock_ts_to_ct(ts, &ct); + + rtc_serialcom(0x01); /* Register shift command. */ + + rtc_outb(bin2bcd(ct.sec)); /* Write back Seconds */ + rtc_outb(bin2bcd(ct.min)); /* Write back Minutes */ + rtc_outb(bin2bcd(ct.hour)); /* Write back Hours */ + + rtc_outb(bin2bcd(ct.day)); /* Write back Day */ + rtc_outb((ct.mon << 4) | ct.dow); /* Write back Month and DOW */ + rtc_outb(bin2bcd(ct.year % 100)); /* Write back Year */ + + rtc_serialcom(0x02); /* Time set & Counter hold command. */ + rtc_serialcom(0x00); /* Register hold command. */ + + return (0); +} + +static int +pcrtc_gettime(device_t dev, struct timespec *ts) +{ + struct clocktime ct; + int i; + + rtc_serialcom(0x03); /* Time Read */ + rtc_serialcom(0x01); /* Register shift command. */ + DELAY(20); + + ct.nsec = 0; + ct.sec = bcd2bin(rtc_inb() & 0xff); /* sec */ + ct.min = bcd2bin(rtc_inb() & 0xff); /* min */ + ct.hour = bcd2bin(rtc_inb() & 0xff); /* hour */ + ct.day = bcd2bin(rtc_inb() & 0xff); /* date */ + i = rtc_inb(); + ct.dow = i & 0x0f; /* dow */ + ct.mon = (i >> 4) & 0x0f; /* month */ + ct.year = bcd2bin(rtc_inb() & 0xff) + 1900; /* year */ + if (ct.year < 1995) + ct.year += 100; + + /* 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 pcrtc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pcrtc_probe), + DEVMETHOD(device_attach, pcrtc_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, pcrtc_gettime), + DEVMETHOD(clock_settime, pcrtc_settime), + + { 0, 0 } +}; + +static driver_t pcrtc_driver = { + "pcrtc", + pcrtc_methods, + sizeof(struct pcrtc_softc), +}; + +static devclass_t pcrtc_devclass; + +DRIVER_MODULE(pcrtc, isa, pcrtc_driver, pcrtc_devclass, 0, 0); + #endif /* DEV_ISA */ |