|
Lines 42-62
Link Here
|
| 42 |
#include <sys/kernel.h> |
42 |
#include <sys/kernel.h> |
| 43 |
#include <sys/module.h> |
43 |
#include <sys/module.h> |
| 44 |
#include <sys/proc.h> |
44 |
#include <sys/proc.h> |
| 45 |
#include <sys/rman.h> |
|
|
| 46 |
#include <sys/timeet.h> |
45 |
#include <sys/timeet.h> |
| 47 |
|
46 |
|
| 48 |
#include <isa/rtc.h> |
47 |
#include <isa/rtc.h> |
|
|
48 |
#include <machine/intr_machdep.h> |
| 49 |
#include "clock_if.h" |
| 50 |
#include "atrtcvar.h" |
| 51 |
|
| 49 |
#ifdef DEV_ISA |
52 |
#ifdef DEV_ISA |
| 50 |
#include <isa/isareg.h> |
53 |
#include <isa/isareg.h> |
| 51 |
#include <isa/isavar.h> |
54 |
#include <isa/isavar.h> |
| 52 |
#endif |
55 |
#endif |
| 53 |
#include <machine/intr_machdep.h> |
|
|
| 54 |
#include "clock_if.h" |
| 55 |
|
56 |
|
| 56 |
#define RTC_LOCK do { if (!kdb_active) mtx_lock_spin(&clock_lock); } while (0) |
57 |
#define RTC_LOCK do { if (!kdb_active) mtx_lock_spin(&clock_lock); } while (0) |
| 57 |
#define RTC_UNLOCK do { if (!kdb_active) mtx_unlock_spin(&clock_lock); } while (0) |
58 |
#define RTC_UNLOCK do { if (!kdb_active) mtx_unlock_spin(&clock_lock); } while (0) |
| 58 |
|
59 |
|
| 59 |
int atrtcclock_disable = 0; |
60 |
#define IO_DELAY() (void)inb(0x84) |
|
|
61 |
#define IO_RTC_ADDR (IO_RTC + 0) |
| 62 |
#define IO_RTC_DATA (IO_RTC + 1) |
| 60 |
|
63 |
|
| 61 |
static int rtc_reg = -1; |
64 |
static int rtc_reg = -1; |
| 62 |
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; |
65 |
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; |
|
Lines 73-82
Link Here
|
| 73 |
|
76 |
|
| 74 |
RTC_LOCK; |
77 |
RTC_LOCK; |
| 75 |
if (rtc_reg != reg) { |
78 |
if (rtc_reg != reg) { |
| 76 |
inb(0x84); |
79 |
IO_DELAY(); |
| 77 |
outb(IO_RTC, reg); |
80 |
outb(IO_RTC, reg); |
| 78 |
rtc_reg = reg; |
81 |
rtc_reg = reg; |
| 79 |
inb(0x84); |
82 |
IO_DELAY(); |
| 80 |
} |
83 |
} |
| 81 |
val = inb(IO_RTC + 1); |
84 |
val = inb(IO_RTC + 1); |
| 82 |
RTC_UNLOCK; |
85 |
RTC_UNLOCK; |
|
Lines 89-101
Link Here
|
| 89 |
|
92 |
|
| 90 |
RTC_LOCK; |
93 |
RTC_LOCK; |
| 91 |
if (rtc_reg != reg) { |
94 |
if (rtc_reg != reg) { |
| 92 |
inb(0x84); |
95 |
IO_DELAY(); |
| 93 |
outb(IO_RTC, reg); |
96 |
outb(IO_RTC, reg); |
| 94 |
rtc_reg = reg; |
97 |
rtc_reg = reg; |
| 95 |
inb(0x84); |
98 |
IO_DELAY(); |
| 96 |
} |
99 |
} |
| 97 |
outb(IO_RTC + 1, val); |
100 |
outb(IO_RTC + 1, val); |
| 98 |
inb(0x84); |
101 |
IO_DELAY(); |
| 99 |
RTC_UNLOCK; |
102 |
RTC_UNLOCK; |
| 100 |
} |
103 |
} |
| 101 |
|
104 |
|
|
Lines 105-111
Link Here
|
| 105 |
return(bcd2bin(rtcin(port))); |
108 |
return(bcd2bin(rtcin(port))); |
| 106 |
} |
109 |
} |
| 107 |
|
110 |
|
| 108 |
static void |
111 |
void |
| 109 |
atrtc_start(void) |
112 |
atrtc_start(void) |
| 110 |
{ |
113 |
{ |
| 111 |
|
114 |
|
|
Lines 155-169
Link Here
|
| 155 |
* RTC driver for subr_rtc |
158 |
* RTC driver for subr_rtc |
| 156 |
*/ |
159 |
*/ |
| 157 |
|
160 |
|
| 158 |
struct atrtc_softc { |
161 |
int |
| 159 |
int port_rid, intr_rid; |
|
|
| 160 |
struct resource *port_res; |
| 161 |
struct resource *intr_res; |
| 162 |
void *intr_handler; |
| 163 |
struct eventtimer et; |
| 164 |
}; |
| 165 |
|
| 166 |
static int |
| 167 |
rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period) |
162 |
rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period) |
| 168 |
{ |
163 |
{ |
| 169 |
|
164 |
|
|
Lines 172-178
Link Here
|
| 172 |
return (0); |
167 |
return (0); |
| 173 |
} |
168 |
} |
| 174 |
|
169 |
|
| 175 |
static int |
170 |
int |
| 176 |
rtc_stop(struct eventtimer *et) |
171 |
rtc_stop(struct eventtimer *et) |
| 177 |
{ |
172 |
{ |
| 178 |
|
173 |
|
|
Lines 201-207
Link Here
|
| 201 |
* Stat clock ticks can still be lost, causing minor loss of accuracy |
196 |
* Stat clock ticks can still be lost, causing minor loss of accuracy |
| 202 |
* in the statistics, but the stat clock will no longer stop. |
197 |
* in the statistics, but the stat clock will no longer stop. |
| 203 |
*/ |
198 |
*/ |
| 204 |
static int |
199 |
int |
| 205 |
rtc_intr(void *arg) |
200 |
rtc_intr(void *arg) |
| 206 |
{ |
201 |
{ |
| 207 |
struct atrtc_softc *sc = (struct atrtc_softc *)arg; |
202 |
struct atrtc_softc *sc = (struct atrtc_softc *)arg; |
|
Lines 215-300
Link Here
|
| 215 |
return(flag ? FILTER_HANDLED : FILTER_STRAY); |
210 |
return(flag ? FILTER_HANDLED : FILTER_STRAY); |
| 216 |
} |
211 |
} |
| 217 |
|
212 |
|
| 218 |
/* |
213 |
int |
| 219 |
* Attach to the ISA PnP descriptors for the timer and realtime clock. |
|
|
| 220 |
*/ |
| 221 |
static struct isa_pnp_id atrtc_ids[] = { |
| 222 |
{ 0x000bd041 /* PNP0B00 */, "AT realtime clock" }, |
| 223 |
{ 0 } |
| 224 |
}; |
| 225 |
|
| 226 |
static int |
| 227 |
atrtc_probe(device_t dev) |
| 228 |
{ |
| 229 |
int result; |
| 230 |
|
| 231 |
result = ISA_PNP_PROBE(device_get_parent(dev), dev, atrtc_ids); |
| 232 |
/* ENOENT means no PnP-ID, device is hinted. */ |
| 233 |
if (result == ENOENT) { |
| 234 |
device_set_desc(dev, "AT realtime clock"); |
| 235 |
return (BUS_PROBE_LOW_PRIORITY); |
| 236 |
} |
| 237 |
return (result); |
| 238 |
} |
| 239 |
|
| 240 |
static int |
| 241 |
atrtc_attach(device_t dev) |
| 242 |
{ |
| 243 |
struct atrtc_softc *sc; |
| 244 |
u_long s; |
| 245 |
int i; |
| 246 |
|
| 247 |
sc = device_get_softc(dev); |
| 248 |
sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, |
| 249 |
IO_RTC, IO_RTC + 1, 2, RF_ACTIVE); |
| 250 |
if (sc->port_res == NULL) |
| 251 |
device_printf(dev, "Warning: Couldn't map I/O.\n"); |
| 252 |
atrtc_start(); |
| 253 |
clock_register(dev, 1000000); |
| 254 |
bzero(&sc->et, sizeof(struct eventtimer)); |
| 255 |
if (!atrtcclock_disable && |
| 256 |
(resource_int_value(device_get_name(dev), device_get_unit(dev), |
| 257 |
"clock", &i) != 0 || i != 0)) { |
| 258 |
sc->intr_rid = 0; |
| 259 |
while (bus_get_resource(dev, SYS_RES_IRQ, sc->intr_rid, |
| 260 |
&s, NULL) == 0 && s != 8) |
| 261 |
sc->intr_rid++; |
| 262 |
sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ, |
| 263 |
&sc->intr_rid, 8, 8, 1, RF_ACTIVE); |
| 264 |
if (sc->intr_res == NULL) { |
| 265 |
device_printf(dev, "Can't map interrupt.\n"); |
| 266 |
return (0); |
| 267 |
} else if ((bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK, |
| 268 |
rtc_intr, NULL, sc, &sc->intr_handler))) { |
| 269 |
device_printf(dev, "Can't setup interrupt.\n"); |
| 270 |
return (0); |
| 271 |
} else { |
| 272 |
/* Bind IRQ to BSP to avoid live migration. */ |
| 273 |
bus_bind_intr(dev, sc->intr_res, 0); |
| 274 |
} |
| 275 |
sc->et.et_name = "RTC"; |
| 276 |
sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_POW2DIV; |
| 277 |
sc->et.et_quality = 0; |
| 278 |
sc->et.et_frequency = 32768; |
| 279 |
sc->et.et_min_period = 0x00080000; |
| 280 |
sc->et.et_max_period = 0x80000000; |
| 281 |
sc->et.et_start = rtc_start; |
| 282 |
sc->et.et_stop = rtc_stop; |
| 283 |
sc->et.et_priv = dev; |
| 284 |
et_register(&sc->et); |
| 285 |
} |
| 286 |
return(0); |
| 287 |
} |
| 288 |
|
| 289 |
static int |
| 290 |
atrtc_resume(device_t dev) |
| 291 |
{ |
| 292 |
|
| 293 |
atrtc_restore(); |
| 294 |
return(0); |
| 295 |
} |
| 296 |
|
| 297 |
static int |
| 298 |
atrtc_settime(device_t dev __unused, struct timespec *ts) |
214 |
atrtc_settime(device_t dev __unused, struct timespec *ts) |
| 299 |
{ |
215 |
{ |
| 300 |
struct clocktime ct; |
216 |
struct clocktime ct; |
|
Lines 322-328
Link Here
|
| 322 |
return (0); |
238 |
return (0); |
| 323 |
} |
239 |
} |
| 324 |
|
240 |
|
| 325 |
static int |
241 |
int |
| 326 |
atrtc_gettime(device_t dev, struct timespec *ts) |
242 |
atrtc_gettime(device_t dev, struct timespec *ts) |
| 327 |
{ |
243 |
{ |
| 328 |
struct clocktime ct; |
244 |
struct clocktime ct; |
|
Lines 362-395
Link Here
|
| 362 |
return (clock_ct_to_ts(&ct, ts)); |
278 |
return (clock_ct_to_ts(&ct, ts)); |
| 363 |
} |
279 |
} |
| 364 |
|
280 |
|
| 365 |
static device_method_t atrtc_methods[] = { |
|
|
| 366 |
/* Device interface */ |
| 367 |
DEVMETHOD(device_probe, atrtc_probe), |
| 368 |
DEVMETHOD(device_attach, atrtc_attach), |
| 369 |
DEVMETHOD(device_detach, bus_generic_detach), |
| 370 |
DEVMETHOD(device_shutdown, bus_generic_shutdown), |
| 371 |
DEVMETHOD(device_suspend, bus_generic_suspend), |
| 372 |
/* XXX stop statclock? */ |
| 373 |
DEVMETHOD(device_resume, atrtc_resume), |
| 374 |
|
| 375 |
/* clock interface */ |
| 376 |
DEVMETHOD(clock_gettime, atrtc_gettime), |
| 377 |
DEVMETHOD(clock_settime, atrtc_settime), |
| 378 |
|
| 379 |
{ 0, 0 } |
| 380 |
}; |
| 381 |
|
| 382 |
static driver_t atrtc_driver = { |
| 383 |
"atrtc", |
| 384 |
atrtc_methods, |
| 385 |
sizeof(struct atrtc_softc), |
| 386 |
}; |
| 387 |
|
| 388 |
static devclass_t atrtc_devclass; |
| 389 |
|
| 390 |
DRIVER_MODULE(atrtc, isa, atrtc_driver, atrtc_devclass, 0, 0); |
| 391 |
DRIVER_MODULE(atrtc, acpi, atrtc_driver, atrtc_devclass, 0, 0); |
| 392 |
|
| 393 |
#include "opt_ddb.h" |
281 |
#include "opt_ddb.h" |
| 394 |
#ifdef DDB |
282 |
#ifdef DDB |
| 395 |
#include <ddb/ddb.h> |
283 |
#include <ddb/ddb.h> |