|
|
1.1 ! root 1: // 16bit code to handle system clocks. ! 2: // ! 3: // Copyright (C) 2008 Kevin O'Connor <[email protected]> ! 4: // Copyright (C) 2002 MandrakeSoft S.A. ! 5: // ! 6: // This file may be distributed under the terms of the GNU LGPLv3 license. ! 7: ! 8: #include "biosvar.h" // SET_BDA ! 9: #include "util.h" // debug_enter ! 10: #include "disk.h" // floppy_tick ! 11: #include "cmos.h" // inb_cmos ! 12: #include "pic.h" // eoi_pic1 ! 13: #include "bregs.h" // struct bregs ! 14: #include "biosvar.h" // GET_GLOBAL ! 15: #include "usb-hid.h" // usb_check_key ! 16: ! 17: // RTC register flags ! 18: #define RTC_A_UIP 0x80 ! 19: ! 20: #define RTC_B_SET 0x80 ! 21: #define RTC_B_PIE 0x40 ! 22: #define RTC_B_AIE 0x20 ! 23: #define RTC_B_UIE 0x10 ! 24: #define RTC_B_BIN 0x04 ! 25: #define RTC_B_24HR 0x02 ! 26: #define RTC_B_DSE 0x01 ! 27: ! 28: ! 29: // Bits for PORT_PS2_CTRLB ! 30: #define PPCB_T2GATE (1<<0) ! 31: #define PPCB_SPKR (1<<1) ! 32: #define PPCB_T2OUT (1<<5) ! 33: ! 34: // Bits for PORT_PIT_MODE ! 35: #define PM_SEL_TIMER0 (0<<6) ! 36: #define PM_SEL_TIMER1 (1<<6) ! 37: #define PM_SEL_TIMER2 (2<<6) ! 38: #define PM_SEL_READBACK (3<<6) ! 39: #define PM_ACCESS_LATCH (0<<4) ! 40: #define PM_ACCESS_LOBYTE (1<<4) ! 41: #define PM_ACCESS_HIBYTE (2<<4) ! 42: #define PM_ACCESS_WORD (3<<4) ! 43: #define PM_MODE0 (0<<1) ! 44: #define PM_MODE1 (1<<1) ! 45: #define PM_MODE2 (2<<1) ! 46: #define PM_MODE3 (3<<1) ! 47: #define PM_MODE4 (4<<1) ! 48: #define PM_MODE5 (5<<1) ! 49: #define PM_CNT_BINARY (0<<0) ! 50: #define PM_CNT_BCD (1<<0) ! 51: ! 52: ! 53: /**************************************************************** ! 54: * TSC timer ! 55: ****************************************************************/ ! 56: ! 57: #define PIT_TICK_RATE 1193180 // Underlying HZ of PIT ! 58: #define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer ! 59: #define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL) ! 60: #define CALIBRATE_COUNT 0x800 // Approx 1.7ms ! 61: ! 62: u32 cpu_khz VAR16VISIBLE; ! 63: ! 64: static void ! 65: calibrate_tsc() ! 66: { ! 67: // Setup "timer2" ! 68: u8 orig = inb(PORT_PS2_CTRLB); ! 69: outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB); ! 70: /* binary, mode 0, LSB/MSB, Ch 2 */ ! 71: outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE); ! 72: /* LSB of ticks */ ! 73: outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2); ! 74: /* MSB of ticks */ ! 75: outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2); ! 76: ! 77: u64 start = rdtscll(); ! 78: while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0) ! 79: ; ! 80: u64 end = rdtscll(); ! 81: ! 82: // Restore PORT_PS2_CTRLB ! 83: outb(orig, PORT_PS2_CTRLB); ! 84: ! 85: // Store calibrated cpu khz. ! 86: u64 diff = end - start; ! 87: dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n" ! 88: , (u32)start, (u32)end, (u32)diff); ! 89: u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT; ! 90: SET_GLOBAL(cpu_khz, hz / 1000); ! 91: ! 92: dprintf(1, "CPU Mhz=%u\n", hz / 1000000); ! 93: } ! 94: ! 95: static void ! 96: tscdelay(u64 diff) ! 97: { ! 98: u64 start = rdtscll(); ! 99: u64 end = start + diff; ! 100: while (!check_time(end)) ! 101: cpu_relax(); ! 102: } ! 103: ! 104: static void ! 105: tscsleep(u64 diff) ! 106: { ! 107: u64 start = rdtscll(); ! 108: u64 end = start + diff; ! 109: while (!check_time(end)) ! 110: yield(); ! 111: } ! 112: ! 113: void ndelay(u32 count) { ! 114: tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000); ! 115: } ! 116: void udelay(u32 count) { ! 117: tscdelay(count * GET_GLOBAL(cpu_khz) / 1000); ! 118: } ! 119: void mdelay(u32 count) { ! 120: tscdelay(count * GET_GLOBAL(cpu_khz)); ! 121: } ! 122: ! 123: void nsleep(u32 count) { ! 124: tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000); ! 125: } ! 126: void usleep(u32 count) { ! 127: tscsleep(count * GET_GLOBAL(cpu_khz) / 1000); ! 128: } ! 129: void msleep(u32 count) { ! 130: tscsleep(count * GET_GLOBAL(cpu_khz)); ! 131: } ! 132: ! 133: // Return the TSC value that is 'msecs' time in the future. ! 134: u64 ! 135: calc_future_tsc(u32 msecs) ! 136: { ! 137: u32 khz = GET_GLOBAL(cpu_khz); ! 138: return rdtscll() + ((u64)khz * msecs); ! 139: } ! 140: u64 ! 141: calc_future_tsc_usec(u32 usecs) ! 142: { ! 143: u32 khz = GET_GLOBAL(cpu_khz); ! 144: return rdtscll() + ((u64)(khz/1000) * usecs); ! 145: } ! 146: ! 147: ! 148: /**************************************************************** ! 149: * Init ! 150: ****************************************************************/ ! 151: ! 152: static int ! 153: rtc_updating() ! 154: { ! 155: // This function checks to see if the update-in-progress bit ! 156: // is set in CMOS Status Register A. If not, it returns 0. ! 157: // If it is set, it tries to wait until there is a transition ! 158: // to 0, and will return 0 if such a transition occurs. A -1 ! 159: // is returned only after timing out. The maximum period ! 160: // that this bit should be set is constrained to (1984+244) ! 161: // useconds, so we wait for 3 msec max. ! 162: ! 163: if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0) ! 164: return 0; ! 165: u64 end = calc_future_tsc(3); ! 166: do { ! 167: if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0) ! 168: return 0; ! 169: } while (!check_time(end)); ! 170: ! 171: // update-in-progress never transitioned to 0 ! 172: return -1; ! 173: } ! 174: ! 175: static void ! 176: pit_setup() ! 177: { ! 178: // timer0: binary count, 16bit count, mode 2 ! 179: outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE); ! 180: // maximum count of 0000H = 18.2Hz ! 181: outb(0x0, PORT_PIT_COUNTER0); ! 182: outb(0x0, PORT_PIT_COUNTER0); ! 183: } ! 184: ! 185: static void ! 186: init_rtc() ! 187: { ! 188: outb_cmos(0x26, CMOS_STATUS_A); // 32,768Khz src, 976.5625us updates ! 189: u8 regB = inb_cmos(CMOS_STATUS_B); ! 190: outb_cmos((regB & RTC_B_DSE) | RTC_B_24HR, CMOS_STATUS_B); ! 191: inb_cmos(CMOS_STATUS_C); ! 192: inb_cmos(CMOS_STATUS_D); ! 193: } ! 194: ! 195: static u32 ! 196: bcd2bin(u8 val) ! 197: { ! 198: return (val & 0xf) + ((val >> 4) * 10); ! 199: } ! 200: ! 201: void ! 202: timer_setup() ! 203: { ! 204: dprintf(3, "init timer\n"); ! 205: calibrate_tsc(); ! 206: pit_setup(); ! 207: ! 208: init_rtc(); ! 209: rtc_updating(); ! 210: u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS)); ! 211: u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES)); ! 212: u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS)); ! 213: u32 ticks = (hours * 60 + minutes) * 60 + seconds; ! 214: ticks = ((u64)ticks * PIT_TICK_RATE) / PIT_TICK_INTERVAL; ! 215: SET_BDA(timer_counter, ticks); ! 216: SET_BDA(timer_rollover, 0); ! 217: ! 218: enable_hwirq(0, entry_08); ! 219: enable_hwirq(8, entry_70); ! 220: } ! 221: ! 222: ! 223: /**************************************************************** ! 224: * Standard clock functions ! 225: ****************************************************************/ ! 226: ! 227: // get current clock count ! 228: static void ! 229: handle_1a00(struct bregs *regs) ! 230: { ! 231: u32 ticks = GET_BDA(timer_counter); ! 232: regs->cx = ticks >> 16; ! 233: regs->dx = ticks; ! 234: regs->al = GET_BDA(timer_rollover); ! 235: SET_BDA(timer_rollover, 0); // reset flag ! 236: set_success(regs); ! 237: } ! 238: ! 239: // Set Current Clock Count ! 240: static void ! 241: handle_1a01(struct bregs *regs) ! 242: { ! 243: u32 ticks = (regs->cx << 16) | regs->dx; ! 244: SET_BDA(timer_counter, ticks); ! 245: SET_BDA(timer_rollover, 0); // reset flag ! 246: // XXX - should use set_code_success()? ! 247: regs->ah = 0; ! 248: set_success(regs); ! 249: } ! 250: ! 251: // Read CMOS Time ! 252: static void ! 253: handle_1a02(struct bregs *regs) ! 254: { ! 255: if (rtc_updating()) { ! 256: set_invalid(regs); ! 257: return; ! 258: } ! 259: ! 260: regs->dh = inb_cmos(CMOS_RTC_SECONDS); ! 261: regs->cl = inb_cmos(CMOS_RTC_MINUTES); ! 262: regs->ch = inb_cmos(CMOS_RTC_HOURS); ! 263: regs->dl = inb_cmos(CMOS_STATUS_B) & RTC_B_DSE; ! 264: regs->ah = 0; ! 265: regs->al = regs->ch; ! 266: set_success(regs); ! 267: } ! 268: ! 269: // Set CMOS Time ! 270: static void ! 271: handle_1a03(struct bregs *regs) ! 272: { ! 273: // Using a debugger, I notice the following masking/setting ! 274: // of bits in Status Register B, by setting Reg B to ! 275: // a few values and getting its value after INT 1A was called. ! 276: // ! 277: // try#1 try#2 try#3 ! 278: // before 1111 1101 0111 1101 0000 0000 ! 279: // after 0110 0010 0110 0010 0000 0010 ! 280: // ! 281: // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 ! 282: // My assumption: RegB = ((RegB & 01100000b) | 00000010b) ! 283: if (rtc_updating()) { ! 284: init_rtc(); ! 285: // fall through as if an update were not in progress ! 286: } ! 287: outb_cmos(regs->dh, CMOS_RTC_SECONDS); ! 288: outb_cmos(regs->cl, CMOS_RTC_MINUTES); ! 289: outb_cmos(regs->ch, CMOS_RTC_HOURS); ! 290: // Set Daylight Savings time enabled bit to requested value ! 291: u8 val8 = ((inb_cmos(CMOS_STATUS_B) & (RTC_B_PIE|RTC_B_AIE)) ! 292: | RTC_B_24HR | (regs->dl & RTC_B_DSE)); ! 293: outb_cmos(val8, CMOS_STATUS_B); ! 294: regs->ah = 0; ! 295: regs->al = val8; // val last written to Reg B ! 296: set_success(regs); ! 297: } ! 298: ! 299: // Read CMOS Date ! 300: static void ! 301: handle_1a04(struct bregs *regs) ! 302: { ! 303: regs->ah = 0; ! 304: if (rtc_updating()) { ! 305: set_invalid(regs); ! 306: return; ! 307: } ! 308: regs->cl = inb_cmos(CMOS_RTC_YEAR); ! 309: regs->dh = inb_cmos(CMOS_RTC_MONTH); ! 310: regs->dl = inb_cmos(CMOS_RTC_DAY_MONTH); ! 311: if (CONFIG_COREBOOT) { ! 312: if (regs->cl > 0x80) ! 313: regs->ch = 0x19; ! 314: else ! 315: regs->ch = 0x20; ! 316: } else { ! 317: regs->ch = inb_cmos(CMOS_CENTURY); ! 318: } ! 319: regs->al = regs->ch; ! 320: set_success(regs); ! 321: } ! 322: ! 323: // Set CMOS Date ! 324: static void ! 325: handle_1a05(struct bregs *regs) ! 326: { ! 327: // Using a debugger, I notice the following masking/setting ! 328: // of bits in Status Register B, by setting Reg B to ! 329: // a few values and getting its value after INT 1A was called. ! 330: // ! 331: // try#1 try#2 try#3 try#4 ! 332: // before 1111 1101 0111 1101 0000 0010 0000 0000 ! 333: // after 0110 1101 0111 1101 0000 0010 0000 0000 ! 334: // ! 335: // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 ! 336: // My assumption: RegB = (RegB & 01111111b) ! 337: if (rtc_updating()) { ! 338: init_rtc(); ! 339: set_invalid(regs); ! 340: return; ! 341: } ! 342: outb_cmos(regs->cl, CMOS_RTC_YEAR); ! 343: outb_cmos(regs->dh, CMOS_RTC_MONTH); ! 344: outb_cmos(regs->dl, CMOS_RTC_DAY_MONTH); ! 345: if (!CONFIG_COREBOOT) ! 346: outb_cmos(regs->ch, CMOS_CENTURY); ! 347: // clear halt-clock bit ! 348: u8 val8 = inb_cmos(CMOS_STATUS_B) & ~RTC_B_SET; ! 349: outb_cmos(val8, CMOS_STATUS_B); ! 350: regs->ah = 0; ! 351: regs->al = val8; // AL = val last written to Reg B ! 352: set_success(regs); ! 353: } ! 354: ! 355: // Set Alarm Time in CMOS ! 356: static void ! 357: handle_1a06(struct bregs *regs) ! 358: { ! 359: // Using a debugger, I notice the following masking/setting ! 360: // of bits in Status Register B, by setting Reg B to ! 361: // a few values and getting its value after INT 1A was called. ! 362: // ! 363: // try#1 try#2 try#3 ! 364: // before 1101 1111 0101 1111 0000 0000 ! 365: // after 0110 1111 0111 1111 0010 0000 ! 366: // ! 367: // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 ! 368: // My assumption: RegB = ((RegB & 01111111b) | 00100000b) ! 369: u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B ! 370: regs->ax = 0; ! 371: if (val8 & RTC_B_AIE) { ! 372: // Alarm interrupt enabled already ! 373: set_invalid(regs); ! 374: return; ! 375: } ! 376: if (rtc_updating()) { ! 377: init_rtc(); ! 378: // fall through as if an update were not in progress ! 379: } ! 380: outb_cmos(regs->dh, CMOS_RTC_SECONDS_ALARM); ! 381: outb_cmos(regs->cl, CMOS_RTC_MINUTES_ALARM); ! 382: outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM); ! 383: // enable Status Reg B alarm bit, clear halt clock bit ! 384: outb_cmos((val8 & ~RTC_B_SET) | RTC_B_AIE, CMOS_STATUS_B); ! 385: set_success(regs); ! 386: } ! 387: ! 388: // Turn off Alarm ! 389: static void ! 390: handle_1a07(struct bregs *regs) ! 391: { ! 392: // Using a debugger, I notice the following masking/setting ! 393: // of bits in Status Register B, by setting Reg B to ! 394: // a few values and getting its value after INT 1A was called. ! 395: // ! 396: // try#1 try#2 try#3 try#4 ! 397: // before 1111 1101 0111 1101 0010 0000 0010 0010 ! 398: // after 0100 0101 0101 0101 0000 0000 0000 0010 ! 399: // ! 400: // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1 ! 401: // My assumption: RegB = (RegB & 01010111b) ! 402: u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B ! 403: // clear clock-halt bit, disable alarm bit ! 404: outb_cmos(val8 & ~(RTC_B_SET|RTC_B_AIE), CMOS_STATUS_B); ! 405: regs->ah = 0; ! 406: regs->al = val8; // val last written to Reg B ! 407: set_success(regs); ! 408: } ! 409: ! 410: // Unsupported ! 411: static void ! 412: handle_1aXX(struct bregs *regs) ! 413: { ! 414: set_unimplemented(regs); ! 415: } ! 416: ! 417: // INT 1Ah Time-of-day Service Entry Point ! 418: void VISIBLE16 ! 419: handle_1a(struct bregs *regs) ! 420: { ! 421: debug_enter(regs, DEBUG_HDL_1a); ! 422: switch (regs->ah) { ! 423: case 0x00: handle_1a00(regs); break; ! 424: case 0x01: handle_1a01(regs); break; ! 425: case 0x02: handle_1a02(regs); break; ! 426: case 0x03: handle_1a03(regs); break; ! 427: case 0x04: handle_1a04(regs); break; ! 428: case 0x05: handle_1a05(regs); break; ! 429: case 0x06: handle_1a06(regs); break; ! 430: case 0x07: handle_1a07(regs); break; ! 431: case 0xb1: handle_1ab1(regs); break; ! 432: default: handle_1aXX(regs); break; ! 433: } ! 434: } ! 435: ! 436: // INT 08h System Timer ISR Entry Point ! 437: void VISIBLE16 ! 438: handle_08() ! 439: { ! 440: debug_isr(DEBUG_ISR_08); ! 441: ! 442: floppy_tick(); ! 443: ! 444: u32 counter = GET_BDA(timer_counter); ! 445: counter++; ! 446: // compare to one days worth of timer ticks at 18.2 hz ! 447: if (counter >= TICKS_PER_DAY) { ! 448: // there has been a midnight rollover at this point ! 449: counter = 0; ! 450: SET_BDA(timer_rollover, GET_BDA(timer_rollover) + 1); ! 451: } ! 452: ! 453: SET_BDA(timer_counter, counter); ! 454: ! 455: usb_check_key(); ! 456: ! 457: // chain to user timer tick INT #0x1c ! 458: u32 eax=0, flags; ! 459: call16_simpint(0x1c, &eax, &flags); ! 460: ! 461: eoi_pic1(); ! 462: } ! 463: ! 464: ! 465: /**************************************************************** ! 466: * Periodic timer ! 467: ****************************************************************/ ! 468: ! 469: void ! 470: useRTC() ! 471: { ! 472: u16 ebda_seg = get_ebda_seg(); ! 473: int count = GET_EBDA2(ebda_seg, RTCusers); ! 474: SET_EBDA2(ebda_seg, RTCusers, count+1); ! 475: if (count) ! 476: return; ! 477: // Turn on the Periodic Interrupt timer ! 478: u8 bRegister = inb_cmos(CMOS_STATUS_B); ! 479: outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B); ! 480: } ! 481: ! 482: void ! 483: releaseRTC() ! 484: { ! 485: u16 ebda_seg = get_ebda_seg(); ! 486: int count = GET_EBDA2(ebda_seg, RTCusers); ! 487: SET_EBDA2(ebda_seg, RTCusers, count-1); ! 488: if (count != 1) ! 489: return; ! 490: // Clear the Periodic Interrupt. ! 491: u8 bRegister = inb_cmos(CMOS_STATUS_B); ! 492: outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B); ! 493: } ! 494: ! 495: static int ! 496: set_usertimer(u32 usecs, u16 seg, u16 offset) ! 497: { ! 498: if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING) ! 499: return -1; ! 500: ! 501: // Interval not already set. ! 502: SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING); // Set status byte. ! 503: SET_BDA(user_wait_complete_flag, SEGOFF(seg, offset)); ! 504: SET_BDA(user_wait_timeout, usecs); ! 505: useRTC(); ! 506: return 0; ! 507: } ! 508: ! 509: static void ! 510: clear_usertimer() ! 511: { ! 512: if (!(GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING)) ! 513: return; ! 514: // Turn off status byte. ! 515: SET_BDA(rtc_wait_flag, 0); ! 516: releaseRTC(); ! 517: } ! 518: ! 519: #define RET_ECLOCKINUSE 0x83 ! 520: ! 521: // Wait for CX:DX microseconds ! 522: void ! 523: handle_1586(struct bregs *regs) ! 524: { ! 525: // Use the rtc to wait for the specified time. ! 526: u8 statusflag = 0; ! 527: u32 count = (regs->cx << 16) | regs->dx; ! 528: int ret = set_usertimer(count, GET_SEG(SS), (u32)&statusflag); ! 529: if (ret) { ! 530: set_code_invalid(regs, RET_ECLOCKINUSE); ! 531: return; ! 532: } ! 533: while (!statusflag) ! 534: wait_irq(); ! 535: set_success(regs); ! 536: } ! 537: ! 538: // Set Interval requested. ! 539: static void ! 540: handle_158300(struct bregs *regs) ! 541: { ! 542: int ret = set_usertimer((regs->cx << 16) | regs->dx, regs->es, regs->bx); ! 543: if (ret) ! 544: // Interval already set. ! 545: set_code_invalid(regs, RET_EUNSUPPORTED); ! 546: else ! 547: set_success(regs); ! 548: } ! 549: ! 550: // Clear interval requested ! 551: static void ! 552: handle_158301(struct bregs *regs) ! 553: { ! 554: clear_usertimer(); ! 555: set_success(regs); ! 556: } ! 557: ! 558: static void ! 559: handle_1583XX(struct bregs *regs) ! 560: { ! 561: set_code_unimplemented(regs, RET_EUNSUPPORTED); ! 562: regs->al--; ! 563: } ! 564: ! 565: void ! 566: handle_1583(struct bregs *regs) ! 567: { ! 568: switch (regs->al) { ! 569: case 0x00: handle_158300(regs); break; ! 570: case 0x01: handle_158301(regs); break; ! 571: default: handle_1583XX(regs); break; ! 572: } ! 573: } ! 574: ! 575: #define USEC_PER_RTC DIV_ROUND_CLOSEST(1000000, 1024) ! 576: ! 577: // int70h: IRQ8 - CMOS RTC ! 578: void VISIBLE16 ! 579: handle_70() ! 580: { ! 581: debug_isr(DEBUG_ISR_70); ! 582: ! 583: // Check which modes are enabled and have occurred. ! 584: u8 registerB = inb_cmos(CMOS_STATUS_B); ! 585: u8 registerC = inb_cmos(CMOS_STATUS_C); ! 586: ! 587: if (!(registerB & (RTC_B_PIE|RTC_B_AIE))) ! 588: goto done; ! 589: if (registerC & RTC_B_AIE) { ! 590: // Handle Alarm Interrupt. ! 591: u32 eax=0, flags; ! 592: call16_simpint(0x4a, &eax, &flags); ! 593: } ! 594: if (!(registerC & RTC_B_PIE)) ! 595: goto done; ! 596: ! 597: // Handle Periodic Interrupt. ! 598: ! 599: check_preempt(); ! 600: ! 601: if (!GET_BDA(rtc_wait_flag)) ! 602: goto done; ! 603: ! 604: // Wait Interval (Int 15, AH=83) active. ! 605: u32 time = GET_BDA(user_wait_timeout); // Time left in microseconds. ! 606: if (time < USEC_PER_RTC) { ! 607: // Done waiting - write to specified flag byte. ! 608: struct segoff_s segoff = GET_BDA(user_wait_complete_flag); ! 609: u16 ptr_seg = segoff.seg; ! 610: u8 *ptr_far = (u8*)(segoff.offset+0); ! 611: u8 oldval = GET_FARVAR(ptr_seg, *ptr_far); ! 612: SET_FARVAR(ptr_seg, *ptr_far, oldval | 0x80); ! 613: ! 614: clear_usertimer(); ! 615: } else { ! 616: // Continue waiting. ! 617: time -= USEC_PER_RTC; ! 618: SET_BDA(user_wait_timeout, time); ! 619: } ! 620: ! 621: done: ! 622: eoi_pic2(); ! 623: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.