pcrtc.c revision 177642
1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz and Don Ahn. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/pc98/cbus/pcrtc.c 177642 2008-03-26 20:09:21Z phk $"); 37 38/* 39 * Routines to handle clock hardware. 40 */ 41 42/* 43 * inittodr, settodr and support routines written 44 * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at> 45 * 46 * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94 47 */ 48 49/* 50 * modified for PC98 by Kakefuda 51 */ 52 53#include "opt_apic.h" 54#include "opt_clock.h" 55#include "opt_isa.h" 56#include "opt_mca.h" 57 58#include <sys/param.h> 59#include <sys/systm.h> 60#include <sys/bus.h> 61#include <sys/clock.h> 62#include <sys/lock.h> 63#include <sys/kdb.h> 64#include <sys/mutex.h> 65#include <sys/proc.h> 66#include <sys/time.h> 67#include <sys/timetc.h> 68#include <sys/kernel.h> 69#include <sys/limits.h> 70#include <sys/module.h> 71#include <sys/sysctl.h> 72#include <sys/cons.h> 73#include <sys/power.h> 74 75#include <machine/clock.h> 76#include <machine/cpu.h> 77#include <machine/cputypes.h> 78#include <machine/frame.h> 79#include <machine/intr_machdep.h> 80#include <machine/md_var.h> 81#include <machine/psl.h> 82#ifdef DEV_APIC 83#include <machine/apicvar.h> 84#endif 85#include <machine/specialreg.h> 86#include <machine/ppireg.h> 87#include <machine/timerreg.h> 88 89#include <i386/isa/icu.h> 90#include <pc98/cbus/cbus.h> 91#include <pc98/pc98/pc98_machdep.h> 92#ifdef DEV_ISA 93#include <isa/isavar.h> 94#endif 95 96#define TIMER_DIV(x) ((i8254_freq + (x) / 2) / (x)) 97 98int clkintr_pending; 99int statclock_disable; 100#ifndef TIMER_FREQ 101#define TIMER_FREQ 2457600 102#endif 103u_int i8254_freq = TIMER_FREQ; 104TUNABLE_INT("hw.i8254.freq", &i8254_freq); 105int i8254_max_count; 106static int i8254_real_max_count; 107 108static struct mtx clock_lock; 109static struct intsrc *i8254_intsrc; 110static u_int32_t i8254_lastcount; 111static u_int32_t i8254_offset; 112static int (*i8254_pending)(struct intsrc *); 113static int i8254_ticked; 114static int using_lapic_timer; 115 116/* Values for timerX_state: */ 117#define RELEASED 0 118#define RELEASE_PENDING 1 119#define ACQUIRED 2 120#define ACQUIRE_PENDING 3 121 122static u_char timer1_state; 123static void rtc_serialcombit(int); 124static void rtc_serialcom(int); 125static int rtc_inb(void); 126static void rtc_outb(int); 127 128static unsigned i8254_get_timecount(struct timecounter *tc); 129static unsigned i8254_simple_get_timecount(struct timecounter *tc); 130static void set_i8254_freq(u_int freq, int intr_freq); 131 132static struct timecounter i8254_timecounter = { 133 i8254_get_timecount, /* get_timecount */ 134 0, /* no poll_pps */ 135 ~0u, /* counter_mask */ 136 0, /* frequency */ 137 "i8254", /* name */ 138 0 /* quality */ 139}; 140 141static int 142clkintr(struct trapframe *frame) 143{ 144 145 if (timecounter->tc_get_timecount == i8254_get_timecount) { 146 mtx_lock_spin(&clock_lock); 147 if (i8254_ticked) 148 i8254_ticked = 0; 149 else { 150 i8254_offset += i8254_max_count; 151 i8254_lastcount = 0; 152 } 153 clkintr_pending = 0; 154 mtx_unlock_spin(&clock_lock); 155 } 156 KASSERT(!using_lapic_timer, ("clk interrupt enabled with lapic timer")); 157 hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); 158 return (FILTER_HANDLED); 159} 160 161int 162timer_spkr_acquire(void) 163{ 164 int mode; 165 166 mode = TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT; 167 168 if (timer1_state != RELEASED) 169 return (-1); 170 timer1_state = ACQUIRED; 171 172 /* 173 * This access to the timer registers is as atomic as possible 174 * because it is a single instruction. We could do better if we 175 * knew the rate. Use of splclock() limits glitches to 10-100us, 176 * and this is probably good enough for timer2, so we aren't as 177 * careful with it as with timer0. 178 */ 179 outb(TIMER_MODE, TIMER_SEL1 | (mode & 0x3f)); 180 ppi_spkr_on(); /* enable counter1 output to speaker */ 181 182 return (0); 183} 184 185int 186timer_spkr_release(void) 187{ 188 189 if (timer1_state != ACQUIRED) 190 return (-1); 191 timer1_state = RELEASED; 192 outb(TIMER_MODE, TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT); 193 ppi_spkr_off(); /* disable counter1 output to speaker */ 194 return (0); 195} 196 197void 198timer_spkr_setfreq(int freq) 199{ 200 201 freq = i8254_freq / freq; 202 mtx_lock_spin(&clock_lock); 203 outb(TIMER_CNTR1, (freq) & 0xff); 204 outb(TIMER_CNTR1, (freq) >> 8); 205 mtx_unlock_spin(&clock_lock); 206} 207 208 209static int 210getit(void) 211{ 212 int high, low; 213 214 mtx_lock_spin(&clock_lock); 215 216 /* Select timer0 and latch counter value. */ 217 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 218 219 low = inb(TIMER_CNTR0); 220 high = inb(TIMER_CNTR0); 221 222 mtx_unlock_spin(&clock_lock); 223 return ((high << 8) | low); 224} 225 226/* 227 * Wait "n" microseconds. 228 * Relies on timer 1 counting down from (i8254_freq / hz) 229 * Note: timer had better have been programmed before this is first used! 230 */ 231void 232DELAY(int n) 233{ 234 int delta, prev_tick, tick, ticks_left; 235 236#ifdef DELAYDEBUG 237 int getit_calls = 1; 238 int n1; 239 static int state = 0; 240 241 if (state == 0) { 242 state = 1; 243 for (n1 = 1; n1 <= 10000000; n1 *= 10) 244 DELAY(n1); 245 state = 2; 246 } 247 if (state == 1) 248 printf("DELAY(%d)...", n); 249#endif 250 /* 251 * Read the counter first, so that the rest of the setup overhead is 252 * counted. Guess the initial overhead is 20 usec (on most systems it 253 * takes about 1.5 usec for each of the i/o's in getit(). The loop 254 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 255 * multiplications and divisions to scale the count take a while). 256 * 257 * However, if ddb is active then use a fake counter since reading 258 * the i8254 counter involves acquiring a lock. ddb must not do 259 * locking for many reasons, but it calls here for at least atkbd 260 * input. 261 */ 262#ifdef KDB 263 if (kdb_active) 264 prev_tick = 1; 265 else 266#endif 267 prev_tick = getit(); 268 n -= 0; /* XXX actually guess no initial overhead */ 269 /* 270 * Calculate (n * (i8254_freq / 1e6)) without using floating point 271 * and without any avoidable overflows. 272 */ 273 if (n <= 0) 274 ticks_left = 0; 275 else if (n < 256) 276 /* 277 * Use fixed point to avoid a slow division by 1000000. 278 * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest. 279 * 2^15 is the first power of 2 that gives exact results 280 * for n between 0 and 256. 281 */ 282 ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15; 283 else 284 /* 285 * Don't bother using fixed point, although gcc-2.7.2 286 * generates particularly poor code for the long long 287 * division, since even the slow way will complete long 288 * before the delay is up (unless we're interrupted). 289 */ 290 ticks_left = ((u_int)n * (long long)i8254_freq + 999999) 291 / 1000000; 292 293 while (ticks_left > 0) { 294#ifdef KDB 295 if (kdb_active) { 296 outb(0x5f, 0); 297 tick = prev_tick - 1; 298 if (tick <= 0) 299 tick = i8254_max_count; 300 } else 301#endif 302 tick = getit(); 303#ifdef DELAYDEBUG 304 ++getit_calls; 305#endif 306 delta = prev_tick - tick; 307 prev_tick = tick; 308 if (delta < 0) { 309 delta += i8254_max_count; 310 /* 311 * Guard against i8254_max_count being wrong. 312 * This shouldn't happen in normal operation, 313 * but it may happen if set_i8254_freq() is 314 * traced. 315 */ 316 if (delta < 0) 317 delta = 0; 318 } 319 ticks_left -= delta; 320 } 321#ifdef DELAYDEBUG 322 if (state == 1) 323 printf(" %d calls to getit() at %d usec each\n", 324 getit_calls, (n + 5) / getit_calls); 325#endif 326} 327 328static u_int 329calibrate_clocks(void) 330{ 331 int timeout; 332 u_int count, prev_count, tot_count; 333 u_short sec, start_sec; 334 335 if (bootverbose) 336 printf("Calibrating clock(s) ... "); 337 /* Check ARTIC. */ 338 if (!(PC98_SYSTEM_PARAMETER(0x458) & 0x80) && 339 !(PC98_SYSTEM_PARAMETER(0x45b) & 0x04)) 340 goto fail; 341 timeout = 100000000; 342 343 /* Read the ARTIC. */ 344 sec = inw(0x5e); 345 346 /* Wait for the ARTIC to changes. */ 347 start_sec = sec; 348 for (;;) { 349 sec = inw(0x5e); 350 if (sec != start_sec) 351 break; 352 if (--timeout == 0) 353 goto fail; 354 } 355 356 /* Start keeping track of the i8254 counter. */ 357 prev_count = getit(); 358 if (prev_count == 0 || prev_count > i8254_max_count) 359 goto fail; 360 tot_count = 0; 361 362 start_sec = sec; 363 for (;;) { 364 sec = inw(0x5e); 365 count = getit(); 366 if (count == 0 || count > i8254_max_count) 367 goto fail; 368 if (count > prev_count) 369 tot_count += prev_count - (count - i8254_max_count); 370 else 371 tot_count += prev_count - count; 372 prev_count = count; 373 if ((sec == start_sec + 1200) || /* 1200 = 307.2KHz >> 8 */ 374 (sec < start_sec && 375 (u_int)sec + 0x10000 == (u_int)start_sec + 1200)) 376 break; 377 if (--timeout == 0) 378 goto fail; 379 } 380 381 if (bootverbose) { 382 printf("i8254 clock: %u Hz\n", tot_count); 383 } 384 return (tot_count); 385 386fail: 387 if (bootverbose) 388 printf("failed, using default i8254 clock of %u Hz\n", 389 i8254_freq); 390 return (i8254_freq); 391} 392 393static void 394set_i8254_freq(u_int freq, int intr_freq) 395{ 396 int new_i8254_real_max_count; 397 398 i8254_timecounter.tc_frequency = freq; 399 mtx_lock_spin(&clock_lock); 400 i8254_freq = freq; 401 if (using_lapic_timer) 402 new_i8254_real_max_count = 0x10000; 403 else 404 new_i8254_real_max_count = TIMER_DIV(intr_freq); 405 if (new_i8254_real_max_count != i8254_real_max_count) { 406 i8254_real_max_count = new_i8254_real_max_count; 407 if (i8254_real_max_count == 0x10000) 408 i8254_max_count = 0xffff; 409 else 410 i8254_max_count = i8254_real_max_count; 411 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 412 outb(TIMER_CNTR0, i8254_real_max_count & 0xff); 413 outb(TIMER_CNTR0, i8254_real_max_count >> 8); 414 } 415 mtx_unlock_spin(&clock_lock); 416} 417 418static void 419i8254_restore(void) 420{ 421 422 mtx_lock_spin(&clock_lock); 423 outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 424 outb(TIMER_CNTR0, i8254_real_max_count & 0xff); 425 outb(TIMER_CNTR0, i8254_real_max_count >> 8); 426 mtx_unlock_spin(&clock_lock); 427} 428 429 430/* 431 * Restore all the timers non-atomically (XXX: should be atomically). 432 * 433 * This function is called from pmtimer_resume() to restore all the timers. 434 * This should not be necessary, but there are broken laptops that do not 435 * restore all the timers on resume. 436 */ 437void 438timer_restore(void) 439{ 440 441 i8254_restore(); /* restore i8254_freq and hz */ 442} 443 444/* This is separate from startrtclock() so that it can be called early. */ 445void 446i8254_init(void) 447{ 448 449 mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE); 450 451 if (pc98_machine_type & M_8M) 452 i8254_freq = 1996800L; /* 1.9968 MHz */ 453 else 454 i8254_freq = 2457600L; /* 2.4576 MHz */ 455 456 set_i8254_freq(i8254_freq, hz); 457} 458 459void 460startrtclock() 461{ 462 u_int delta, freq; 463 464 freq = calibrate_clocks(); 465#ifdef CLK_CALIBRATION_LOOP 466 if (bootverbose) { 467 printf( 468 "Press a key on the console to abort clock calibration\n"); 469 while (cncheckc() == -1) 470 calibrate_clocks(); 471 } 472#endif 473 474 /* 475 * Use the calibrated i8254 frequency if it seems reasonable. 476 * Otherwise use the default, and don't use the calibrated i586 477 * frequency. 478 */ 479 delta = freq > i8254_freq ? freq - i8254_freq : i8254_freq - freq; 480 if (delta < i8254_freq / 100) { 481#ifndef CLK_USE_I8254_CALIBRATION 482 if (bootverbose) 483 printf( 484"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); 485 freq = i8254_freq; 486#endif 487 i8254_freq = freq; 488 } else { 489 if (bootverbose) 490 printf( 491 "%d Hz differs from default of %d Hz by more than 1%%\n", 492 freq, i8254_freq); 493 } 494 495 set_i8254_freq(i8254_freq, hz); 496 tc_init(&i8254_timecounter); 497 498 init_TSC(); 499} 500 501static void 502rtc_serialcombit(int i) 503{ 504 outb(IO_RTC, ((i&0x01)<<5)|0x07); 505 DELAY(1); 506 outb(IO_RTC, ((i&0x01)<<5)|0x17); 507 DELAY(1); 508 outb(IO_RTC, ((i&0x01)<<5)|0x07); 509 DELAY(1); 510} 511 512static void 513rtc_serialcom(int i) 514{ 515 rtc_serialcombit(i&0x01); 516 rtc_serialcombit((i&0x02)>>1); 517 rtc_serialcombit((i&0x04)>>2); 518 rtc_serialcombit((i&0x08)>>3); 519 outb(IO_RTC, 0x07); 520 DELAY(1); 521 outb(IO_RTC, 0x0f); 522 DELAY(1); 523 outb(IO_RTC, 0x07); 524 DELAY(1); 525} 526 527static void 528rtc_outb(int val) 529{ 530 int s; 531 int sa = 0; 532 533 for (s=0;s<8;s++) { 534 sa = ((val >> s) & 0x01) ? 0x27 : 0x07; 535 outb(IO_RTC, sa); /* set DI & CLK 0 */ 536 DELAY(1); 537 outb(IO_RTC, sa | 0x10); /* CLK 1 */ 538 DELAY(1); 539 } 540 outb(IO_RTC, sa & 0xef); /* CLK 0 */ 541} 542 543static int 544rtc_inb(void) 545{ 546 int s; 547 int sa = 0; 548 549 for (s=0;s<8;s++) { 550 sa |= ((inb(0x33) & 0x01) << s); 551 outb(IO_RTC, 0x17); /* CLK 1 */ 552 DELAY(1); 553 outb(IO_RTC, 0x07); /* CLK 0 */ 554 DELAY(2); 555 } 556 return sa; 557} 558 559/* 560 * Initialize the time of day register, based on the time base which is, e.g. 561 * from a filesystem. 562 */ 563void 564inittodr(time_t base) 565{ 566 struct timespec ts; 567 struct clocktime ct; 568 int i; 569 570 if (base) { 571 ts.tv_sec = base; 572 ts.tv_nsec = 0; 573 tc_setclock(&ts); 574 } 575 576 rtc_serialcom(0x03); /* Time Read */ 577 rtc_serialcom(0x01); /* Register shift command. */ 578 DELAY(20); 579 580 ct.nsec = 0; 581 ct.sec = bcd2bin(rtc_inb() & 0xff); /* sec */ 582 ct.min = bcd2bin(rtc_inb() & 0xff); /* min */ 583 ct.hour = bcd2bin(rtc_inb() & 0xff); /* hour */ 584 ct.day = bcd2bin(rtc_inb() & 0xff); /* date */ 585 i = rtc_inb(); 586 ct.dow = i & 0x0f; /* dow */ 587 ct.mon = (i >> 4) & 0x0f; /* month */ 588 ct.year = bcd2bin(rtc_inb() & 0xff) + 1900; /* year */ 589 if (ct.year < 1995) 590 ct.year += 100; 591 /* Set dow = -1 because some clocks don't set it correctly. */ 592 ct.dow = -1; 593 if (clock_ct_to_ts(&ct, &ts)) { 594 printf("Invalid time in clock: check and reset the date!\n"); 595 return; 596 } 597 ts.tv_sec += utc_offset(); 598 tc_setclock(&ts); 599} 600 601/* 602 * Write system time back to RTC 603 */ 604void 605resettodr() 606{ 607 struct timespec ts; 608 struct clocktime ct; 609 610 if (disable_rtc_set) 611 return; 612 613 getnanotime(&ts); 614 ts.tv_sec -= utc_offset(); 615 clock_ts_to_ct(&ts, &ct); 616 617 rtc_serialcom(0x01); /* Register shift command. */ 618 619 rtc_outb(bin2bcd(ct.sec)); /* Write back Seconds */ 620 rtc_outb(bin2bcd(ct.min)); /* Write back Minutes */ 621 rtc_outb(bin2bcd(ct.hour)); /* Write back Hours */ 622 623 rtc_outb(bin2bcd(ct.day)); /* Write back Day */ 624 rtc_outb((ct.mon << 4) | ct.dow); /* Write back Month and DOW */ 625 rtc_outb(bin2bcd(ct.year % 100)); /* Write back Year */ 626 627 rtc_serialcom(0x02); /* Time set & Counter hold command. */ 628 rtc_serialcom(0x00); /* Register hold command. */ 629} 630 631 632/* 633 * Start both clocks running. 634 */ 635void 636cpu_initclocks() 637{ 638 639#ifdef DEV_APIC 640 using_lapic_timer = lapic_setup_clock(); 641#endif 642 /* 643 * If we aren't using the local APIC timer to drive the kernel 644 * clocks, setup the interrupt handler for the 8254 timer 0 so 645 * that it can drive hardclock(). Otherwise, change the 8254 646 * timecounter to user a simpler algorithm. 647 */ 648 if (!using_lapic_timer) { 649 intr_add_handler("clk", 0, (driver_filter_t *)clkintr, NULL, 650 NULL, INTR_TYPE_CLK, NULL); 651 i8254_intsrc = intr_lookup_source(0); 652 if (i8254_intsrc != NULL) 653 i8254_pending = 654 i8254_intsrc->is_pic->pic_source_pending; 655 } else { 656 i8254_timecounter.tc_get_timecount = 657 i8254_simple_get_timecount; 658 i8254_timecounter.tc_counter_mask = 0xffff; 659 set_i8254_freq(i8254_freq, hz); 660 } 661 662 init_TSC_tc(); 663} 664 665void 666cpu_startprofclock(void) 667{ 668} 669 670void 671cpu_stopprofclock(void) 672{ 673} 674 675static int 676sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS) 677{ 678 int error; 679 u_int freq; 680 681 /* 682 * Use `i8254' instead of `timer' in external names because `timer' 683 * is is too generic. Should use it everywhere. 684 */ 685 freq = i8254_freq; 686 error = sysctl_handle_int(oidp, &freq, 0, req); 687 if (error == 0 && req->newptr != NULL) 688 set_i8254_freq(freq, hz); 689 return (error); 690} 691 692SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 693 0, sizeof(u_int), sysctl_machdep_i8254_freq, "IU", ""); 694 695static unsigned 696i8254_simple_get_timecount(struct timecounter *tc) 697{ 698 699 return (i8254_max_count - getit()); 700} 701 702static unsigned 703i8254_get_timecount(struct timecounter *tc) 704{ 705 u_int count; 706 u_int high, low; 707 u_int eflags; 708 709 eflags = read_eflags(); 710 mtx_lock_spin(&clock_lock); 711 712 /* Select timer0 and latch counter value. */ 713 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 714 715 low = inb(TIMER_CNTR0); 716 high = inb(TIMER_CNTR0); 717 count = i8254_max_count - ((high << 8) | low); 718 if (count < i8254_lastcount || 719 (!i8254_ticked && (clkintr_pending || 720 ((count < 20 || (!(eflags & PSL_I) && count < i8254_max_count / 2u)) && 721 i8254_pending != NULL && i8254_pending(i8254_intsrc))))) { 722 i8254_ticked = 1; 723 i8254_offset += i8254_max_count; 724 } 725 i8254_lastcount = count; 726 count += i8254_offset; 727 mtx_unlock_spin(&clock_lock); 728 return (count); 729} 730 731#ifdef DEV_ISA 732/* 733 * Attach to the ISA PnP descriptors for the timer and realtime clock. 734 */ 735static struct isa_pnp_id attimer_ids[] = { 736 { 0x0001d041 /* PNP0100 */, "AT timer" }, 737 { 0x000bd041 /* PNP0B00 */, "AT realtime clock" }, 738 { 0 } 739}; 740 741static int 742attimer_probe(device_t dev) 743{ 744 int result; 745 746 if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids)) <= 0) 747 device_quiet(dev); 748 return(result); 749} 750 751static int 752attimer_attach(device_t dev) 753{ 754 return(0); 755} 756 757static device_method_t attimer_methods[] = { 758 /* Device interface */ 759 DEVMETHOD(device_probe, attimer_probe), 760 DEVMETHOD(device_attach, attimer_attach), 761 DEVMETHOD(device_detach, bus_generic_detach), 762 DEVMETHOD(device_shutdown, bus_generic_shutdown), 763 DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX stop statclock? */ 764 DEVMETHOD(device_resume, bus_generic_resume), /* XXX restart statclock? */ 765 { 0, 0 } 766}; 767 768static driver_t attimer_driver = { 769 "attimer", 770 attimer_methods, 771 1, /* no softc */ 772}; 773 774static devclass_t attimer_devclass; 775 776DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0); 777#endif /* DEV_ISA */ 778