155211Smsmith/*-
255211Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
355211Smsmith * All rights reserved.
455211Smsmith *
555211Smsmith * Redistribution and use in source and binary forms, with or without
655211Smsmith * modification, are permitted provided that the following conditions
755211Smsmith * are met:
855211Smsmith * 1. Redistributions of source code must retain the above copyright
955211Smsmith *    notice, this list of conditions and the following disclaimer.
1055211Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1155211Smsmith *    notice, this list of conditions and the following disclaimer in the
1255211Smsmith *    documentation and/or other materials provided with the distribution.
1355211Smsmith *
1455211Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1555211Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1655211Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1755211Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1855211Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1955211Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2055211Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2155211Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2255211Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2355211Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2455211Smsmith * SUCH DAMAGE.
2539441Smsmith */
2639441Smsmith
27119482Sobrien#include <sys/cdefs.h>
28119482Sobrien__FBSDID("$FreeBSD$");
29119482Sobrien
3039441Smsmith#include <stand.h>
3139441Smsmith#include <btxv86.h>
3264187Sjhb#include "bootstrap.h"
3364187Sjhb#include "libi386.h"
3439441Smsmith
35179825Sollistatic int	bios_seconds(void);
36179825Solli
3739441Smsmith/*
38179825Solli * Return the BIOS time-of-day value.
3939441Smsmith *
4039441Smsmith * XXX uses undocumented BCD support from libstand.
4139441Smsmith */
42179825Sollistatic int
43179825Sollibios_seconds(void)
4439441Smsmith{
4564187Sjhb    int			hr, minute, sec;
4639441Smsmith
4739441Smsmith    v86.ctl = 0;
4839441Smsmith    v86.addr = 0x1a;		/* int 0x1a, function 2 */
4939441Smsmith    v86.eax = 0x0200;
5039441Smsmith    v86int();
5139441Smsmith
5239441Smsmith    hr = bcd2bin((v86.ecx & 0xff00) >> 8);	/* hour in %ch */
5364187Sjhb    minute = bcd2bin(v86.ecx & 0xff);		/* minute in %cl */
5439441Smsmith    sec = bcd2bin((v86.edx & 0xff00) >> 8);	/* second in %dh */
5539441Smsmith
56179825Solli    return (hr * 3600 + minute * 60 + sec);
57179825Solli}
58179825Solli
59179825Solli/*
60179825Solli * Return the time in seconds since the beginning of the day.
61179825Solli *
62179825Solli * Some BIOSes (notably qemu) don't correctly read the RTC
63179825Solli * registers in an atomic way, sometimes returning bogus values.
64179825Solli * Therefore we "debounce" the reading by accepting it only when
65228782Sed * we got 8 identical values in succession.
66179825Solli *
67179825Solli * If we pass midnight, don't wrap back to 0.
68179825Solli */
69179825Sollitime_t
70179825Sollitime(time_t *t)
71179825Solli{
72179825Solli    static time_t lasttime;
73179825Solli    time_t now, check;
74228782Sed    int same, try;
75179825Solli
76228782Sed    same = try = 0;
77179825Solli    check = bios_seconds();
78179825Solli    do {
79179825Solli	now = check;
80179825Solli	check = bios_seconds();
81228782Sed	if (check != now)
82228782Sed	    same = 0;
83228782Sed    } while (++same < 8 && ++try < 1000);
84179825Solli
8539441Smsmith    if (now < lasttime)
8639441Smsmith	now += 24 * 3600;
8739441Smsmith    lasttime = now;
8839441Smsmith
8939441Smsmith    if (t != NULL)
9039441Smsmith	*t = now;
9139441Smsmith    return(now);
9239441Smsmith}
9339441Smsmith
9439441Smsmith/*
9539441Smsmith * Use the BIOS Wait function to pause for (period) microseconds.
9639441Smsmith *
9739441Smsmith * Resolution of this function is variable, but typically around
9839441Smsmith * 1ms.
9939441Smsmith */
10039441Smsmithvoid
10139441Smsmithdelay(int period)
10239441Smsmith{
10339441Smsmith    v86.ctl = 0;
10440209Speter    v86.addr = 0x15;		/* int 0x15, function 0x86 */
10539441Smsmith    v86.eax = 0x8600;
10639441Smsmith    v86.ecx = period >> 16;
10739441Smsmith    v86.edx = period & 0xffff;
10839441Smsmith    v86int();
10939441Smsmith}
110