Support USB interrupt schedules on OHCI and UHCI.
[seabios.git] / src / clock.c
index 7077631b6e457ba90ffc6fe011480037e829e482..5a30e3523351032b842cbe3f490f8c66c6e086b7 100644 (file)
  * TSC timer
  ****************************************************************/
 
-#define PIT_TICK_RATE 1193180   // Underlying HZ of PIT
-#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
 #define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
 #define CALIBRATE_COUNT 0x800   // Approx 1.7ms
 
 u32 cpu_khz VAR16VISIBLE;
 
 static void
-calibrate_tsc()
+calibrate_tsc(void)
 {
     // Setup "timer2"
     u8 orig = inb(PORT_PS2_CTRLB);
@@ -150,7 +148,7 @@ calc_future_tsc_usec(u32 usecs)
  ****************************************************************/
 
 static int
-rtc_updating()
+rtc_updating(void)
 {
     // This function checks to see if the update-in-progress bit
     // is set in CMOS Status Register A.  If not, it returns 0.
@@ -173,7 +171,7 @@ rtc_updating()
 }
 
 static void
-pit_setup()
+pit_setup(void)
 {
     // timer0: binary count, 16bit count, mode 2
     outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE);
@@ -183,7 +181,7 @@ pit_setup()
 }
 
 static void
-init_rtc()
+init_rtc(void)
 {
     outb_cmos(0x26, CMOS_STATUS_A);    // 32,768Khz src, 976.5625us updates
     u8 regB = inb_cmos(CMOS_STATUS_B);
@@ -199,7 +197,7 @@ bcd2bin(u8 val)
 }
 
 void
-timer_setup()
+timer_setup(void)
 {
     dprintf(3, "init timer\n");
     calibrate_tsc();
@@ -253,7 +251,7 @@ static void
 handle_1a02(struct bregs *regs)
 {
     if (rtc_updating()) {
-        set_fail(regs);
+        set_invalid(regs);
         return;
     }
 
@@ -302,7 +300,7 @@ handle_1a04(struct bregs *regs)
 {
     regs->ah = 0;
     if (rtc_updating()) {
-        set_fail(regs);
+        set_invalid(regs);
         return;
     }
     regs->cl = inb_cmos(CMOS_RTC_YEAR);
@@ -336,7 +334,7 @@ handle_1a05(struct bregs *regs)
     // My assumption: RegB = (RegB & 01111111b)
     if (rtc_updating()) {
         init_rtc();
-        set_fail(regs);
+        set_invalid(regs);
         return;
     }
     outb_cmos(regs->cl, CMOS_RTC_YEAR);
@@ -370,7 +368,7 @@ handle_1a06(struct bregs *regs)
     regs->ax = 0;
     if (val8 & RTC_B_AIE) {
         // Alarm interrupt enabled already
-        set_fail(regs);
+        set_invalid(regs);
         return;
     }
     if (rtc_updating()) {
@@ -411,7 +409,7 @@ handle_1a07(struct bregs *regs)
 static void
 handle_1aXX(struct bregs *regs)
 {
-    set_fail(regs);
+    set_unimplemented(regs);
 }
 
 // INT 1Ah Time-of-day Service Entry Point
@@ -435,7 +433,7 @@ handle_1a(struct bregs *regs)
 
 // INT 08h System Timer ISR Entry Point
 void VISIBLE16
-handle_08()
+handle_08(void)
 {
     debug_isr(DEBUG_ISR_08);
 
@@ -466,6 +464,32 @@ handle_08()
  * Periodic timer
  ****************************************************************/
 
+void
+useRTC(void)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int count = GET_EBDA2(ebda_seg, RTCusers);
+    SET_EBDA2(ebda_seg, RTCusers, count+1);
+    if (count)
+        return;
+    // Turn on the Periodic Interrupt timer
+    u8 bRegister = inb_cmos(CMOS_STATUS_B);
+    outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B);
+}
+
+void
+releaseRTC(void)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int count = GET_EBDA2(ebda_seg, RTCusers);
+    SET_EBDA2(ebda_seg, RTCusers, count-1);
+    if (count != 1)
+        return;
+    // Clear the Periodic Interrupt.
+    u8 bRegister = inb_cmos(CMOS_STATUS_B);
+    outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B);
+}
+
 static int
 set_usertimer(u32 usecs, u16 seg, u16 offset)
 {
@@ -476,22 +500,18 @@ set_usertimer(u32 usecs, u16 seg, u16 offset)
     SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING);  // Set status byte.
     SET_BDA(user_wait_complete_flag, SEGOFF(seg, offset));
     SET_BDA(user_wait_timeout, usecs);
-
-    // Turn on the Periodic Interrupt timer
-    u8 bRegister = inb_cmos(CMOS_STATUS_B);
-    outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B);
-
+    useRTC();
     return 0;
 }
 
 static void
-clear_usertimer()
+clear_usertimer(void)
 {
+    if (!(GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING))
+        return;
     // Turn off status byte.
     SET_BDA(rtc_wait_flag, 0);
-    // Clear the Periodic Interrupt.
-    u8 bRegister = inb_cmos(CMOS_STATUS_B);
-    outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B);
+    releaseRTC();
 }
 
 #define RET_ECLOCKINUSE  0x83
@@ -505,7 +525,7 @@ handle_1586(struct bregs *regs)
     u32 count = (regs->cx << 16) | regs->dx;
     int ret = set_usertimer(count, GET_SEG(SS), (u32)&statusflag);
     if (ret) {
-        set_code_fail(regs, RET_ECLOCKINUSE);
+        set_code_invalid(regs, RET_ECLOCKINUSE);
         return;
     }
     while (!statusflag)
@@ -520,7 +540,7 @@ handle_158300(struct bregs *regs)
     int ret = set_usertimer((regs->cx << 16) | regs->dx, regs->es, regs->bx);
     if (ret)
         // Interval already set.
-        set_code_fail(regs, RET_EUNSUPPORTED);
+        set_code_invalid(regs, RET_EUNSUPPORTED);
     else
         set_success(regs);
 }
@@ -536,7 +556,7 @@ handle_158301(struct bregs *regs)
 static void
 handle_1583XX(struct bregs *regs)
 {
-    set_code_fail(regs, RET_EUNSUPPORTED);
+    set_code_unimplemented(regs, RET_EUNSUPPORTED);
     regs->al--;
 }
 
@@ -554,7 +574,7 @@ handle_1583(struct bregs *regs)
 
 // int70h: IRQ8 - CMOS RTC
 void VISIBLE16
-handle_70()
+handle_70(void)
 {
     debug_isr(DEBUG_ISR_70);
 
@@ -574,6 +594,8 @@ handle_70()
 
     // Handle Periodic Interrupt.
 
+    check_preempt();
+
     if (!GET_BDA(rtc_wait_flag))
         goto done;