summaryrefslogtreecommitdiff
path: root/libc/bios/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/bios/time.c')
-rw-r--r--libc/bios/time.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/libc/bios/time.c b/libc/bios/time.c
new file mode 100644
index 0000000..9bc63e5
--- /dev/null
+++ b/libc/bios/time.c
@@ -0,0 +1,127 @@
+/*
+ * Time functions for standalone mode, on the first call to time() it tries
+ * to query the RTC, on success it sets it's own day counter an the PC's
+ * ticks since midnight clock. From the second call on it uses the day
+ * counter and ticks clock.
+ *
+ * NOTES:
+ * DOS's midnight bug is here too, it's actually in the bios.
+ * If there's no RTC the clock will fall to Jan 3 1970.
+ */
+
+#include <time.h>
+
+static int mdays[13] = { 0,31,31+28,31+28+31,31+28+31+30,
+ 31+28+31+30+31,31+28+31+30+31+30,31+28+31+30+31+30+31,
+ 31+28+31+30+31+30+31+31,31+28+31+30+31+30+31+31+30,
+ 31+28+31+30+31+30+31+31+30+31,31+28+31+30+31+30+31+31+30+31+30,
+ 365 };
+
+#define SECSPERHOUR (60*60)
+#define SECSPERDAY (SECSPERHOUR*24L)
+
+/****************************************
+ * Return the number of seconds that have elapsed since the start
+ * of 1970.
+ * Input:
+ * timer pointer to where to store result (or NULL)
+ * Output:
+ * *timer = result (unless timer == NULL)
+ * Returns:
+ * time
+ */
+
+static int xt_days = 0, ax_val, huns = 0;
+
+static long get_time(ah)
+{
+#asm
+#if !__FIRST_ARG_IN_AX__
+ mov bx,sp
+ mov ax,[bx+2]
+#endif
+ mov ah,al
+ int $1A
+ jnc intok
+ mov cx,#-1
+ mov dx,cx
+intok:
+ mov [_ax_val],ax
+ mov ax,dx
+ mov dx,cx
+#endasm
+}
+
+static int
+unbcd(bcdval)
+int bcdval;
+{
+ return (bcdval&0xF) + 10*((bcdval>>4)&0xF);
+}
+
+time_t time(timer)
+time_t *timer;
+{
+ unsigned day,month,year;
+ long rv;
+ time_t t;
+
+ if( xt_days ) goto XT_time;
+
+ rv = get_time(0x02);
+ if(rv == -1) goto XT_time;
+ huns = unbcd(rv & 0xFF); /* Save for stime */
+ rv >>= 8; t = unbcd(rv & 0xFF);
+ rv >>= 8; t += unbcd(rv & 0xFF)*60;
+ rv >>= 8; t += unbcd(rv & 0xFF)*3600;
+
+ rv = get_time(0x04);
+ if(rv == -1) goto XT_time;
+ day = unbcd(rv & 0xFF);
+ rv >>= 8; month = unbcd(rv & 0xFF) -1;
+ rv >>= 8; year = unbcd(rv & 0xFF);
+ rv >>= 8; year += unbcd(rv & 0xFF)*100;
+ year -= 1970;
+ if( year < 1950 && year >= 1900 )
+ year += 100; /* Century is not updated on RTC */
+
+ if (month <= 1 || year & 3) /* if before Feb or not a leap year */
+ day--; /* don't add day for leap year */
+ day += mdays[month]; /* day in year */
+ day += (year + 3) >> 2; /* add a day for each leap year */
+ t += ((year * 365L) + day) * SECSPERDAY;
+
+ stime(t);
+
+ if(0)
+ {
+XT_time:
+ rv = get_time(0);
+ xt_days += (ax_val&0xFF);
+ rv = xt_days*SECSPERDAY + rv * 1080 / 19663;
+ }
+
+ if (timer)
+ *timer = t;
+ return t;
+}
+
+static long ticks;
+
+stime(timer)
+time_t timer;
+{
+ xt_days = (timer/SECSPERDAY);
+
+ ticks = ((timer%SECSPERDAY) * 19663L + huns*196) / 1080;
+ huns = 0;
+
+#asm
+ mov cx,[_ticks+2]
+ mov dx,[_ticks]
+ mov ah,#1
+ int $1A
+#endasm
+
+ return 0;
+}