Move i386 to generic RTC handling code.
Make clock_if.m and subr_rtc.c standard on i386 Add hints for "atrtc" driver, for non-PnP, non-ACPI systems. NB: Make sure to install GENERIC.hints into /boot/device.hints in these! Nuke MD inittodr(), resettodr() functions. Don't attach to PHP0B00 in the "attimer" dummy driver any more, and remove comments that no longer apply for that reason. Add new "atrtc" device driver, which handles IBM PC AT Real Time Clock compatible devices using subr_rtc and clock_if. This driver is not entirely clean: other code still fondles the hardware to get a statclock interrupt on non-ACPI timer systems. Wrap some overly long lines. After it has settled in -current, this will be ported to amd64. Technically this is MFC'able, but I fail to see a good reason.
This commit is contained in:
parent
cee09d51d4
commit
2fcca203d7
@ -445,8 +445,10 @@ i4b/layer1/itjc/i4b_itjc_l1fsm.c optional itjc
|
||||
#
|
||||
isa/syscons_isa.c optional sc
|
||||
isa/vga_isa.c optional vga
|
||||
kern/clock_if.m standard
|
||||
kern/imgact_aout.c optional compat_aout
|
||||
kern/imgact_gzip.c optional gzip
|
||||
kern/subr_rtc.c standard
|
||||
libkern/divdi3.c standard
|
||||
libkern/ffsl.c standard
|
||||
libkern/flsl.c standard
|
||||
|
@ -74,3 +74,6 @@ hint.le.0.disabled="1"
|
||||
hint.le.0.port="0x280"
|
||||
hint.le.0.irq="10"
|
||||
hint.le.0.drq="0"
|
||||
hint.atrtc.0.at="isa"
|
||||
hint.atrtc.0.port="0x70"
|
||||
hint.atrtc.0.irq="8"
|
||||
|
@ -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;
|
||||
|
||||
@ -521,98 +519,6 @@ startrtclock()
|
||||
init_TSC();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -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 */
|
||||
|
271
sys/isa/atrtc.c
271
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;
|
||||
|
||||
@ -521,98 +519,6 @@ startrtclock()
|
||||
init_TSC();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user