Annotation of qemu/roms/seabios/src/clock.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.