vgabios: Add scrolling for linear (packed pixel) graphics mode.
[seabios.git] / src / clock.c
index 5a30e3523351032b842cbe3f490f8c66c6e086b7..fcdc698bb15b8c9a0cad8a950312fa1b3b35e965 100644 (file)
@@ -1,6 +1,6 @@
 // 16bit code to handle system clocks.
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2002  MandrakeSoft S.A.
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -12,7 +12,7 @@
 #include "pic.h" // eoi_pic1
 #include "bregs.h" // struct bregs
 #include "biosvar.h" // GET_GLOBAL
-#include "usb-hid.h" // usb_check_key
+#include "usb-hid.h" // usb_check_event
 
 // RTC register flags
 #define RTC_A_UIP 0x80
@@ -54,7 +54,6 @@
  * TSC 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;
@@ -95,7 +94,7 @@ tscdelay(u64 diff)
 {
     u64 start = rdtscll();
     u64 end = start + diff;
-    while (!check_time(end))
+    while (!check_tsc(end))
         cpu_relax();
 }
 
@@ -104,7 +103,7 @@ tscsleep(u64 diff)
 {
     u64 start = rdtscll();
     u64 end = start + diff;
-    while (!check_time(end))
+    while (!check_tsc(end))
         yield();
 }
 
@@ -156,18 +155,19 @@ rtc_updating(void)
     // to 0, and will return 0 if such a transition occurs.  A -1
     // is returned only after timing out.  The maximum period
     // that this bit should be set is constrained to (1984+244)
-    // useconds, so we wait for 3 msec max.
+    // useconds, but we wait for longer just to be sure.
 
     if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
         return 0;
-    u64 end = calc_future_tsc(3);
-    do {
+    u64 end = calc_future_tsc(15);
+    for (;;) {
         if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
             return 0;
-    } while (!check_time(end));
-
-    // update-in-progress never transitioned to 0
-    return -1;
+        if (check_tsc(end))
+            // update-in-progress never transitioned to 0
+            return -1;
+        yield();
+    }
 }
 
 static void
@@ -211,10 +211,9 @@ timer_setup(void)
     u32 ticks = (hours * 60 + minutes) * 60 + seconds;
     ticks = ((u64)ticks * PIT_TICK_RATE) / PIT_TICK_INTERVAL;
     SET_BDA(timer_counter, ticks);
-    SET_BDA(timer_rollover, 0);
 
-    enable_hwirq(0, entry_08);
-    enable_hwirq(8, entry_70);
+    enable_hwirq(0, FUNC16(entry_08));
+    enable_hwirq(8, FUNC16(entry_70));
 }
 
 
@@ -222,10 +221,40 @@ timer_setup(void)
  * Standard clock functions
  ****************************************************************/
 
+#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
+
+// Calculate the timer value at 'count' number of full timer ticks in
+// the future.
+u32
+calc_future_timer_ticks(u32 count)
+{
+    return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY;
+}
+
+// Return the timer value that is 'msecs' time in the future.
+u32
+calc_future_timer(u32 msecs)
+{
+    if (!msecs)
+        return GET_BDA(timer_counter);
+    u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL);
+    u32 ticks = DIV_ROUND_UP(kticks, 1000);
+    return calc_future_timer_ticks(ticks);
+}
+
+// Check if the given timer value has passed.
+int
+check_timer(u32 end)
+{
+    return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY)
+            < (TICKS_PER_DAY/2));
+}
+
 // get current clock count
 static void
 handle_1a00(struct bregs *regs)
 {
+    yield();
     u32 ticks = GET_BDA(timer_counter);
     regs->cx = ticks >> 16;
     regs->dx = ticks;
@@ -450,7 +479,7 @@ handle_08(void)
 
     SET_BDA(timer_counter, counter);
 
-    usb_check_key();
+    usb_check_event();
 
     // chain to user timer tick INT #0x1c
     u32 eax=0, flags;