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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
| 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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
|
64static int beeping; 65int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ 66u_int timer0_prescale; 67static char timer0_state = 0, timer2_state = 0; 68static char timer0_reprogram = 0; 69static void (*timer_func)() = hardclock; 70static void (*new_function)(); 71static u_int new_rate; 72static u_int hardclock_divisor; 73 74#ifdef I586_CPU 75int pentium_mhz = 0; 76#endif 77 78void 79clkintr(frame) 80 struct clockframe frame; 81{ 82#ifdef I586_CPU 83 /* 84 * This resets the CPU cycle counter to zero, to make our 85 * job easier in microtime(). Some fancy ifdefs could speed 86 * this up for Pentium-only kernels. 87 * We want this to be done as close as possible to the actual 88 * timer incrementing in hardclock(), because there is a window 89 * between the two where the value is no longer valid. Experimentation 90 * may reveal a good precompensation to apply in microtime(). 91 */ 92 if(pentium_mhz) { 93 __asm __volatile("movl $0x10,%%ecx\n" 94 "xorl %%eax,%%eax\n" 95 "movl %%eax,%%edx\n" 96 ".byte 0x0f, 0x30\n" 97 "#%0%1" 98 : "=m"(frame) /* no outputs */ 99 : "b"(&frame) /* fake input */ 100 : "ax", "cx", "dx"); 101 } 102#endif 103 hardclock(&frame); 104} 105 106static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 107 108/* 109 * This routine receives statistical clock interrupts from the RTC. 110 * As explained above, these occur at 128 interrupts per second. 111 * When profiling, we receive interrupts at a rate of 1024 Hz. 112 * 113 * This does not actually add as much overhead as it sounds, because 114 * when the statistical clock is active, the hardclock driver no longer 115 * needs to keep (inaccurate) statistics on its own. This decouples 116 * statistics gathering from scheduling interrupts. 117 * 118 * The RTC chip requires that we read status register C (RTC_INTR) 119 * to acknowledge an interrupt, before it will generate the next one. 120 */ 121void 122rtcintr(struct clockframe frame) 123{ 124 u_char stat; 125 stat = rtcin(RTC_INTR); 126 if(stat & RTCIR_PERIOD) { 127 statclock(&frame); 128 } 129} 130 131#ifdef DEBUG 132void 133printrtc(void) 134{ 135 outb(IO_RTC, RTC_STATUSA); 136 printf("RTC status A = %x", inb(IO_RTC+1)); 137 outb(IO_RTC, RTC_STATUSB); 138 printf(", B = %x", inb(IO_RTC+1)); 139 outb(IO_RTC, RTC_INTR); 140 printf(", C = %x\n", inb(IO_RTC+1)); 141} 142#endif 143 144#if 0 145void 146timerintr(struct clockframe frame) 147{ 148 timer_func(&frame); 149 switch (timer0_state) { 150 case 0: 151 break; 152 case 1: 153 if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { 154 hardclock(&frame); 155 timer0_prescale = 0; 156 } 157 break; 158 case 2: 159 disable_intr(); 160 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 161 outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256); 162 outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256); 163 enable_intr(); 164 timer0_divisor = TIMER_DIV(new_rate); 165 timer0_prescale = 0; 166 timer_func = new_function; 167 timer0_state = 1; 168 break; 169 case 3: 170 if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { 171 hardclock(&frame); 172 disable_intr(); 173 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 174 outb(TIMER_CNTR0, TIMER_DIV(hz)%256); 175 outb(TIMER_CNTR0, TIMER_DIV(hz)/256); 176 enable_intr(); 177 timer0_divisor = TIMER_DIV(hz); 178 timer0_prescale = 0; 179 timer_func = hardclock;; 180 timer0_state = 0; 181 } 182 break; 183 } 184} 185 186#endif 187 188int 189acquire_timer0(int rate, void (*function)() ) 190{ 191 if (timer0_state || !function) 192 return -1; 193 194 new_function = function; 195 new_rate = rate; 196 timer0_state = 2; 197 return 0; 198} 199 200 201int 202acquire_timer2(int mode) 203{ 204 if (timer2_state) 205 return -1; 206 timer2_state = 1; 207 outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f)); 208 return 0; 209} 210 211 212int 213release_timer0() 214{ 215 if (!timer0_state) 216 return -1; 217 timer0_state = 3; 218 return 0; 219} 220 221 222int 223release_timer2() 224{ 225 if (!timer2_state) 226 return -1; 227 timer2_state = 0; 228 outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT); 229 return 0; 230} 231 232 233static int 234getit() 235{ 236 int high, low; 237 238 disable_intr(); 239 /* select timer0 and latch counter value */ 240 outb(TIMER_MODE, TIMER_SEL0); 241 low = inb(TIMER_CNTR0); 242 high = inb(TIMER_CNTR0); 243 enable_intr(); 244 return ((high << 8) | low); 245} 246 247#ifdef I586_CPU 248static long long cycles_per_sec = 0; 249 250/* 251 * Figure out how fast the cyclecounter runs. This must be run with 252 * clock interrupts disabled, but with the timer/counter programmed 253 * and running. 254 */ 255void 256calibrate_cyclecounter(void) 257{ 258 volatile long edx, eax, lasteax, lastedx; 259 260 __asm __volatile(".byte 0x0f, 0x31" : "=a"(lasteax), "=d"(lastedx) : ); 261 DELAY(1000000); 262 __asm __volatile(".byte 0x0f, 0x31" : "=a"(eax), "=d"(edx) : ); 263 264 /* 265 * This assumes that you will never have a clock rate higher 266 * than 4GHz, probably a good assumption. 267 */ 268 cycles_per_sec = (long long)edx + eax; 269 cycles_per_sec -= (long long)lastedx + lasteax; 270 pentium_mhz = ((long)cycles_per_sec + 500000) / 1000000; /* round up */ 271} 272#endif 273 274/* 275 * Wait "n" microseconds. 276 * Relies on timer 1 counting down from (TIMER_FREQ / hz) 277 * Note: timer had better have been programmed before this is first used! 278 */ 279void 280DELAY(int n) 281{ 282 int counter_limit, prev_tick, tick, ticks_left, sec, usec; 283 284#ifdef DELAYDEBUG 285 int getit_calls = 1; 286 int n1; 287 static int state = 0; 288 289 if (state == 0) { 290 state = 1; 291 for (n1 = 1; n1 <= 10000000; n1 *= 10) 292 DELAY(n1); 293 state = 2; 294 } 295 if (state == 1) 296 printf("DELAY(%d)...", n); 297#endif 298 /* 299 * Read the counter first, so that the rest of the setup overhead is 300 * counted. Guess the initial overhead is 20 usec (on most systems it 301 * takes about 1.5 usec for each of the i/o's in getit(). The loop 302 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 303 * multiplications and divisions to scale the count take a while). 304 */ 305 prev_tick = getit(0, 0); 306 n -= 20; 307 /* 308 * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point 309 * and without any avoidable overflows. 310 */ 311 sec = n / 1000000; 312 usec = n - sec * 1000000; 313 ticks_left = sec * TIMER_FREQ 314 + usec * (TIMER_FREQ / 1000000) 315 + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 316 + usec * (TIMER_FREQ % 1000) / 1000000; 317 318 while (ticks_left > 0) { 319 tick = getit(0, 0); 320#ifdef DELAYDEBUG 321 ++getit_calls; 322#endif 323 if (tick > prev_tick) 324 ticks_left -= prev_tick - (tick - timer0_divisor); 325 else 326 ticks_left -= prev_tick - tick; 327 prev_tick = tick; 328 } 329#ifdef DELAYDEBUG 330 if (state == 1) 331 printf(" %d calls to getit() at %d usec each\n", 332 getit_calls, (n + 5) / getit_calls); 333#endif 334} 335 336 337static void 338sysbeepstop() 339{ 340 outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ 341 release_timer2(); 342 beeping = 0; 343} 344 345 346int 347sysbeep(int pitch, int period) 348{ 349 350 if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) 351 return -1; 352 disable_intr(); 353 outb(TIMER_CNTR2, pitch); 354 outb(TIMER_CNTR2, (pitch>>8)); 355 enable_intr(); 356 if (!beeping) { 357 outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */ 358 beeping = period; 359 timeout(sysbeepstop, 0, period); 360 } 361 return 0; 362} 363 364 365void 366startrtclock() 367{ 368 int s; 369 370 /* initialize 8253 clock */ 371 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 372 373 /* Correct rounding will buy us a better precision in timekeeping */ 374 outb (IO_TIMER1, TIMER_DIV(hz)%256); 375 outb (IO_TIMER1, TIMER_DIV(hz)/256); 376 timer0_divisor = hardclock_divisor = TIMER_DIV(hz); 377 378 /* initialize brain-dead battery powered clock */ 379 outb (IO_RTC, RTC_STATUSA); 380 outb (IO_RTC+1, rtc_statusa); 381 outb (IO_RTC, RTC_STATUSB); 382 outb (IO_RTC+1, RTCSB_24HR); 383 384 outb (IO_RTC, RTC_DIAG); 385 if (s = inb (IO_RTC+1)) 386 printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); 387} 388 389 390/* convert 2 digit BCD number */ 391int 392bcd(int i) 393{ 394 return ((i/16)*10 + (i%16)); 395} 396 397 398/* convert years to seconds (from 1970) */ 399unsigned long 400ytos(int y) 401{ 402 int i; 403 unsigned long ret; 404 405 ret = 0; 406 for(i = 1970; i < y; i++) { 407 if (i % 4) ret += 365*24*60*60; 408 else ret += 366*24*60*60; 409 } 410 return ret; 411} 412 413 414/* convert months to seconds */ 415unsigned long 416mtos(int m, int leap) 417{ 418 int i; 419 unsigned long ret; 420 421 ret = 0; 422 for(i=1; i<m; i++) { 423 switch(i){ 424 case 1: case 3: case 5: case 7: case 8: case 10: case 12: 425 ret += 31*24*60*60; break; 426 case 4: case 6: case 9: case 11: 427 ret += 30*24*60*60; break; 428 case 2: 429 if (leap) ret += 29*24*60*60; 430 else ret += 28*24*60*60; 431 } 432 } 433 return ret; 434} 435 436 437/* 438 * Initialize the time of day register, based on the time base which is, e.g. 439 * from a filesystem. 440 */ 441void 442inittodr(time_t base) 443{ 444 unsigned long sec; 445 int leap, day_week, t, yd; 446 int sa,s; 447 448 /* do we have a realtime clock present? (otherwise we loop below) */ 449 sa = rtcin(RTC_STATUSA); 450 if (sa == 0xff || sa == 0) return; 451 452 /* ready for a read? */ 453 while ((sa&RTCSA_TUP) == RTCSA_TUP) 454 sa = rtcin(RTC_STATUSA); 455 456 sec = bcd(rtcin(RTC_YEAR)) + 1900; 457 if (sec < 1970) 458 sec += 100; 459 460 leap = !(sec % 4); sec = ytos(sec); /* year */ 461 yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */ 462 t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */ 463 day_week = rtcin(RTC_WDAY); /* day */ 464 sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ 465 sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ 466 sec += bcd(rtcin(RTC_SEC)); /* seconds */ 467 sec += tz.tz_minuteswest * 60; 468 time.tv_sec = sec; 469} 470 471 472#ifdef garbage 473/* 474 * Initialze the time of day register, based on the time base which is, e.g. 475 * from a filesystem. 476 */ 477test_inittodr(time_t base) 478{ 479 480 outb(IO_RTC,9); /* year */ 481 printf("%d ",bcd(inb(IO_RTC+1))); 482 outb(IO_RTC,8); /* month */ 483 printf("%d ",bcd(inb(IO_RTC+1))); 484 outb(IO_RTC,7); /* day */ 485 printf("%d ",bcd(inb(IO_RTC+1))); 486 outb(IO_RTC,4); /* hour */ 487 printf("%d ",bcd(inb(IO_RTC+1))); 488 outb(IO_RTC,2); /* minutes */ 489 printf("%d ",bcd(inb(IO_RTC+1))); 490 outb(IO_RTC,0); /* seconds */ 491 printf("%d\n",bcd(inb(IO_RTC+1))); 492 493 time.tv_sec = base; 494} 495#endif 496 497/* 498 * Wire clock interrupt in. 499 */ 500void 501enablertclock() 502{ 503 register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr, 504 HWI_MASK | SWI_MASK, /* unit */ 0); 505 INTREN(IRQ0); 506 register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, rtcintr, 507 SWI_CLOCK_MASK, /* unit */ 0); 508 INTREN(IRQ8); 509 outb(IO_RTC, RTC_STATUSB); 510 outb(IO_RTC+1, RTCSB_PINTR | RTCSB_24HR); 511} 512 513 514/* 515 * Delay for some number of milliseconds. 516 */ 517void 518spinwait(int millisecs) 519{ 520 DELAY(1000 * millisecs); 521} 522 523void 524cpu_initclocks() 525{ 526 stathz = RTC_NOPROFRATE; 527 profhz = RTC_PROFRATE; 528 enablertclock(); 529} 530 531void 532setstatclockrate(int newhz) 533{ 534 if(newhz == RTC_PROFRATE) { 535 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; 536 } else { 537 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 538 } 539 outb(IO_RTC, RTC_STATUSA); 540 outb(IO_RTC+1, rtc_statusa); 541}
| 62static int beeping; 63int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ 64u_int timer0_prescale; 65static char timer0_state = 0, timer2_state = 0; 66static char timer0_reprogram = 0; 67static void (*timer_func)() = hardclock; 68static void (*new_function)(); 69static u_int new_rate; 70static u_int hardclock_divisor; 71 72#ifdef I586_CPU 73int pentium_mhz = 0; 74#endif 75 76void 77clkintr(frame) 78 struct clockframe frame; 79{ 80#ifdef I586_CPU 81 /* 82 * This resets the CPU cycle counter to zero, to make our 83 * job easier in microtime(). Some fancy ifdefs could speed 84 * this up for Pentium-only kernels. 85 * We want this to be done as close as possible to the actual 86 * timer incrementing in hardclock(), because there is a window 87 * between the two where the value is no longer valid. Experimentation 88 * may reveal a good precompensation to apply in microtime(). 89 */ 90 if(pentium_mhz) { 91 __asm __volatile("movl $0x10,%%ecx\n" 92 "xorl %%eax,%%eax\n" 93 "movl %%eax,%%edx\n" 94 ".byte 0x0f, 0x30\n" 95 "#%0%1" 96 : "=m"(frame) /* no outputs */ 97 : "b"(&frame) /* fake input */ 98 : "ax", "cx", "dx"); 99 } 100#endif 101 hardclock(&frame); 102} 103 104static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 105 106/* 107 * This routine receives statistical clock interrupts from the RTC. 108 * As explained above, these occur at 128 interrupts per second. 109 * When profiling, we receive interrupts at a rate of 1024 Hz. 110 * 111 * This does not actually add as much overhead as it sounds, because 112 * when the statistical clock is active, the hardclock driver no longer 113 * needs to keep (inaccurate) statistics on its own. This decouples 114 * statistics gathering from scheduling interrupts. 115 * 116 * The RTC chip requires that we read status register C (RTC_INTR) 117 * to acknowledge an interrupt, before it will generate the next one. 118 */ 119void 120rtcintr(struct clockframe frame) 121{ 122 u_char stat; 123 stat = rtcin(RTC_INTR); 124 if(stat & RTCIR_PERIOD) { 125 statclock(&frame); 126 } 127} 128 129#ifdef DEBUG 130void 131printrtc(void) 132{ 133 outb(IO_RTC, RTC_STATUSA); 134 printf("RTC status A = %x", inb(IO_RTC+1)); 135 outb(IO_RTC, RTC_STATUSB); 136 printf(", B = %x", inb(IO_RTC+1)); 137 outb(IO_RTC, RTC_INTR); 138 printf(", C = %x\n", inb(IO_RTC+1)); 139} 140#endif 141 142#if 0 143void 144timerintr(struct clockframe frame) 145{ 146 timer_func(&frame); 147 switch (timer0_state) { 148 case 0: 149 break; 150 case 1: 151 if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { 152 hardclock(&frame); 153 timer0_prescale = 0; 154 } 155 break; 156 case 2: 157 disable_intr(); 158 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 159 outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256); 160 outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256); 161 enable_intr(); 162 timer0_divisor = TIMER_DIV(new_rate); 163 timer0_prescale = 0; 164 timer_func = new_function; 165 timer0_state = 1; 166 break; 167 case 3: 168 if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { 169 hardclock(&frame); 170 disable_intr(); 171 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 172 outb(TIMER_CNTR0, TIMER_DIV(hz)%256); 173 outb(TIMER_CNTR0, TIMER_DIV(hz)/256); 174 enable_intr(); 175 timer0_divisor = TIMER_DIV(hz); 176 timer0_prescale = 0; 177 timer_func = hardclock;; 178 timer0_state = 0; 179 } 180 break; 181 } 182} 183 184#endif 185 186int 187acquire_timer0(int rate, void (*function)() ) 188{ 189 if (timer0_state || !function) 190 return -1; 191 192 new_function = function; 193 new_rate = rate; 194 timer0_state = 2; 195 return 0; 196} 197 198 199int 200acquire_timer2(int mode) 201{ 202 if (timer2_state) 203 return -1; 204 timer2_state = 1; 205 outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f)); 206 return 0; 207} 208 209 210int 211release_timer0() 212{ 213 if (!timer0_state) 214 return -1; 215 timer0_state = 3; 216 return 0; 217} 218 219 220int 221release_timer2() 222{ 223 if (!timer2_state) 224 return -1; 225 timer2_state = 0; 226 outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT); 227 return 0; 228} 229 230 231static int 232getit() 233{ 234 int high, low; 235 236 disable_intr(); 237 /* select timer0 and latch counter value */ 238 outb(TIMER_MODE, TIMER_SEL0); 239 low = inb(TIMER_CNTR0); 240 high = inb(TIMER_CNTR0); 241 enable_intr(); 242 return ((high << 8) | low); 243} 244 245#ifdef I586_CPU 246static long long cycles_per_sec = 0; 247 248/* 249 * Figure out how fast the cyclecounter runs. This must be run with 250 * clock interrupts disabled, but with the timer/counter programmed 251 * and running. 252 */ 253void 254calibrate_cyclecounter(void) 255{ 256 volatile long edx, eax, lasteax, lastedx; 257 258 __asm __volatile(".byte 0x0f, 0x31" : "=a"(lasteax), "=d"(lastedx) : ); 259 DELAY(1000000); 260 __asm __volatile(".byte 0x0f, 0x31" : "=a"(eax), "=d"(edx) : ); 261 262 /* 263 * This assumes that you will never have a clock rate higher 264 * than 4GHz, probably a good assumption. 265 */ 266 cycles_per_sec = (long long)edx + eax; 267 cycles_per_sec -= (long long)lastedx + lasteax; 268 pentium_mhz = ((long)cycles_per_sec + 500000) / 1000000; /* round up */ 269} 270#endif 271 272/* 273 * Wait "n" microseconds. 274 * Relies on timer 1 counting down from (TIMER_FREQ / hz) 275 * Note: timer had better have been programmed before this is first used! 276 */ 277void 278DELAY(int n) 279{ 280 int counter_limit, prev_tick, tick, ticks_left, sec, usec; 281 282#ifdef DELAYDEBUG 283 int getit_calls = 1; 284 int n1; 285 static int state = 0; 286 287 if (state == 0) { 288 state = 1; 289 for (n1 = 1; n1 <= 10000000; n1 *= 10) 290 DELAY(n1); 291 state = 2; 292 } 293 if (state == 1) 294 printf("DELAY(%d)...", n); 295#endif 296 /* 297 * Read the counter first, so that the rest of the setup overhead is 298 * counted. Guess the initial overhead is 20 usec (on most systems it 299 * takes about 1.5 usec for each of the i/o's in getit(). The loop 300 * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The 301 * multiplications and divisions to scale the count take a while). 302 */ 303 prev_tick = getit(0, 0); 304 n -= 20; 305 /* 306 * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point 307 * and without any avoidable overflows. 308 */ 309 sec = n / 1000000; 310 usec = n - sec * 1000000; 311 ticks_left = sec * TIMER_FREQ 312 + usec * (TIMER_FREQ / 1000000) 313 + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 314 + usec * (TIMER_FREQ % 1000) / 1000000; 315 316 while (ticks_left > 0) { 317 tick = getit(0, 0); 318#ifdef DELAYDEBUG 319 ++getit_calls; 320#endif 321 if (tick > prev_tick) 322 ticks_left -= prev_tick - (tick - timer0_divisor); 323 else 324 ticks_left -= prev_tick - tick; 325 prev_tick = tick; 326 } 327#ifdef DELAYDEBUG 328 if (state == 1) 329 printf(" %d calls to getit() at %d usec each\n", 330 getit_calls, (n + 5) / getit_calls); 331#endif 332} 333 334 335static void 336sysbeepstop() 337{ 338 outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ 339 release_timer2(); 340 beeping = 0; 341} 342 343 344int 345sysbeep(int pitch, int period) 346{ 347 348 if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) 349 return -1; 350 disable_intr(); 351 outb(TIMER_CNTR2, pitch); 352 outb(TIMER_CNTR2, (pitch>>8)); 353 enable_intr(); 354 if (!beeping) { 355 outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */ 356 beeping = period; 357 timeout(sysbeepstop, 0, period); 358 } 359 return 0; 360} 361 362 363void 364startrtclock() 365{ 366 int s; 367 368 /* initialize 8253 clock */ 369 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 370 371 /* Correct rounding will buy us a better precision in timekeeping */ 372 outb (IO_TIMER1, TIMER_DIV(hz)%256); 373 outb (IO_TIMER1, TIMER_DIV(hz)/256); 374 timer0_divisor = hardclock_divisor = TIMER_DIV(hz); 375 376 /* initialize brain-dead battery powered clock */ 377 outb (IO_RTC, RTC_STATUSA); 378 outb (IO_RTC+1, rtc_statusa); 379 outb (IO_RTC, RTC_STATUSB); 380 outb (IO_RTC+1, RTCSB_24HR); 381 382 outb (IO_RTC, RTC_DIAG); 383 if (s = inb (IO_RTC+1)) 384 printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS); 385} 386 387 388/* convert 2 digit BCD number */ 389int 390bcd(int i) 391{ 392 return ((i/16)*10 + (i%16)); 393} 394 395 396/* convert years to seconds (from 1970) */ 397unsigned long 398ytos(int y) 399{ 400 int i; 401 unsigned long ret; 402 403 ret = 0; 404 for(i = 1970; i < y; i++) { 405 if (i % 4) ret += 365*24*60*60; 406 else ret += 366*24*60*60; 407 } 408 return ret; 409} 410 411 412/* convert months to seconds */ 413unsigned long 414mtos(int m, int leap) 415{ 416 int i; 417 unsigned long ret; 418 419 ret = 0; 420 for(i=1; i<m; i++) { 421 switch(i){ 422 case 1: case 3: case 5: case 7: case 8: case 10: case 12: 423 ret += 31*24*60*60; break; 424 case 4: case 6: case 9: case 11: 425 ret += 30*24*60*60; break; 426 case 2: 427 if (leap) ret += 29*24*60*60; 428 else ret += 28*24*60*60; 429 } 430 } 431 return ret; 432} 433 434 435/* 436 * Initialize the time of day register, based on the time base which is, e.g. 437 * from a filesystem. 438 */ 439void 440inittodr(time_t base) 441{ 442 unsigned long sec; 443 int leap, day_week, t, yd; 444 int sa,s; 445 446 /* do we have a realtime clock present? (otherwise we loop below) */ 447 sa = rtcin(RTC_STATUSA); 448 if (sa == 0xff || sa == 0) return; 449 450 /* ready for a read? */ 451 while ((sa&RTCSA_TUP) == RTCSA_TUP) 452 sa = rtcin(RTC_STATUSA); 453 454 sec = bcd(rtcin(RTC_YEAR)) + 1900; 455 if (sec < 1970) 456 sec += 100; 457 458 leap = !(sec % 4); sec = ytos(sec); /* year */ 459 yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */ 460 t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */ 461 day_week = rtcin(RTC_WDAY); /* day */ 462 sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */ 463 sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */ 464 sec += bcd(rtcin(RTC_SEC)); /* seconds */ 465 sec += tz.tz_minuteswest * 60; 466 time.tv_sec = sec; 467} 468 469 470#ifdef garbage 471/* 472 * Initialze the time of day register, based on the time base which is, e.g. 473 * from a filesystem. 474 */ 475test_inittodr(time_t base) 476{ 477 478 outb(IO_RTC,9); /* year */ 479 printf("%d ",bcd(inb(IO_RTC+1))); 480 outb(IO_RTC,8); /* month */ 481 printf("%d ",bcd(inb(IO_RTC+1))); 482 outb(IO_RTC,7); /* day */ 483 printf("%d ",bcd(inb(IO_RTC+1))); 484 outb(IO_RTC,4); /* hour */ 485 printf("%d ",bcd(inb(IO_RTC+1))); 486 outb(IO_RTC,2); /* minutes */ 487 printf("%d ",bcd(inb(IO_RTC+1))); 488 outb(IO_RTC,0); /* seconds */ 489 printf("%d\n",bcd(inb(IO_RTC+1))); 490 491 time.tv_sec = base; 492} 493#endif 494 495/* 496 * Wire clock interrupt in. 497 */ 498void 499enablertclock() 500{ 501 register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr, 502 HWI_MASK | SWI_MASK, /* unit */ 0); 503 INTREN(IRQ0); 504 register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, rtcintr, 505 SWI_CLOCK_MASK, /* unit */ 0); 506 INTREN(IRQ8); 507 outb(IO_RTC, RTC_STATUSB); 508 outb(IO_RTC+1, RTCSB_PINTR | RTCSB_24HR); 509} 510 511 512/* 513 * Delay for some number of milliseconds. 514 */ 515void 516spinwait(int millisecs) 517{ 518 DELAY(1000 * millisecs); 519} 520 521void 522cpu_initclocks() 523{ 524 stathz = RTC_NOPROFRATE; 525 profhz = RTC_PROFRATE; 526 enablertclock(); 527} 528 529void 530setstatclockrate(int newhz) 531{ 532 if(newhz == RTC_PROFRATE) { 533 rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; 534 } else { 535 rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 536 } 537 outb(IO_RTC, RTC_STATUSA); 538 outb(IO_RTC+1, rtc_statusa); 539}
|