baumann@hope.UUCP (Michael Baumann) (04/22/88)
I just got MINIX 1.2 running on my XT clone, and like a kid with a new
toy I started to install all the little helps I have pulled off the net
over the last year. HOWEVER, when I attempted to install Ed Subelman's
timedate, I discovered that not all Multi I/O cards are the same! So after
some minor disassembly of the clock control program that came with the
board I came up with the following.
This code allows reading of the battery backed-up clock, and presents
it in the format that "date" wants. Modify your /etc/rc to be
date -q < `/usr/bin/timedate` to get around having to type it in
each time you boot.
This is a 1.2 shar file containing 2 files, timedate.c and port.s.
The latter was lifted from klib88.s
-----------------------------------------------------------------------------
"Life is full of little suprises." -- Pandora (as quoted by Robert Asprin)
UUCP: {ucbvax!ucdavis,ucsd,ucivax}!ucrmath!hope!baumann
or !ucrmath!jinx!baumann
----------------------cut here for sharfile----------------------------------
echo x - timedate.c
gres '^X' '' > timedate.c << '/'
X/* timedate.c - get date and time from Multi I/O Card
X * and print on standard out. Format is MMDDYYHHMMSS
CARRIER
X * as required by "date".
X * Should be run in /etc/rc as: date -q < `/usr/bin/timedate`
X * Compile as: cc -o timedate timedate.c port_io.s
X *
X * Author: Ed Subelman 5/87
X *
X * Modified to support newer Multi I/O card from Tiawanese manufacturer.
X * the information is presented in full bytes, rather than the
X * original nibble mode. Also is a 24 hr clock unlike the orig.
X * created under MINIX 1.2
X *
X * Michael Baumann 4/88
X * Comments to {pick the best path}!ucrmath!jinx!baumann
X*/
X
X#include <stdio.h>
X
Xstruct tm {
X int year;
X int month;
X int day;
X int hour;
X int min;
X int sec;
X};
X
X/* Base address for accessing the Real Time Clock */
X
X#define CLK_BASE 0x0240
X
X/* offsets from base for desired registers. */
X
X#define SEC 0x02
X#define MIN 0x03
X#define HR 0x04
X#define DAY 0x06
X#define MON 0x07
X#define YR 0x09
X
X
X#define LOW_8 0x0ff /* prevent any funny stuff */
X
X#define TRIES 10 /* number of times to read clock */
X
X
Xmain(argc, argv)
X int argc;
X char *argv[];
X{
X struct tm tm1;
X struct tm tm2;
X int i;
X
X /* try several times to read the clock. This is needed to avoid
X the following sequence of events:
X time is 03:59:59.99
X you read the hour: 03
X the hard clock ticks: time is 04:00:00.00
X you read the minutes: 00. You are off by 1 hour!
X */
X
X for (i = 0; i < TRIES; i++)
X {
X read_clk(&tm1); /* read the clock twice */
X read_clk(&tm2);
X
X if (tm1.year == tm2.year /* and compare the results */
X && tm1.month == tm2.month
X && tm1.day == tm2.day
X && tm1.hour == tm2.hour
X && tm1.min == tm2.min
X && tm1.sec == tm2.sec)
X {
X /* data is BCD, so no conversion, just write the hex val */
X printf("%02x%02x%02x%02x%02x%02x\n",
X tm1.month, tm1.day, tm1.year,
X tm1.hour, tm1.min, tm1.sec);
X exit(0); /* normal termination */
X }
X }
X
X /* too many errors in reading the clock give up */
X fprintf(stderr, "%s: hard clock unstable\n", argv[0]);
X fflush(stderr);
X _cleanup();
X exit(1);
X}
X
X/* read the hard clock and fill values into a tm structure */
X
Xread_clk(tp)
X struct tm *tp;
X{
X int tmp;
X
X/* unlike the original version of the software, this clock stores
X * the information in byte wide BCD, rather than nibble BCD. This
X * made life a whole lot easier.
X */
X
X tp->year = get_val(YR);
X tp->month = get_val(MON);
X tp->day = get_val(DAY);
X
X tp->hour = get_val(HR);
X tp->min = get_val(MIN);
X tp->sec = get_val(SEC);
X
X
X}
X
X/* get_val() - read a register from the hard clock */
X
Xint get_val(reg)
X int reg;
X{
X int val;
X
X
X port_in (CLK_BASE+reg, &val); /* and get the value of the reg */
X
X return (val & LOW_8); /* make sure lower 8 bits only */
X}
X
/
echo x - port.s
gres '^X' '' > port.s << '/'
X| this file was grafted from klib88.s
X
X.globl _port_out, _port_in
X
X
X
X|*===========================================================================*
X|* port_out *
X|*===========================================================================*
X| port_out(port, value) writes 'value' on the I/O port 'port'.
X
X_port_out:
X push bx | save bx
X mov bx,sp | index off bx
X push ax | save ax
X push dx | save dx
X mov dx,4(bx) | dx = port
X mov ax,6(bx) | ax = value
X out | output 1 byte
X pop dx | restore dx
X pop ax | restore ax
X pop bx | restore bx
X ret | return to caller
X
X
X|*===========================================================================*
X|* port_in *
X|*===========================================================================*
X| port_in(port, &value) reads from port 'port' and puts the result in 'value'.
X_port_in:
X push bx | save bx
X mov bx,sp | index off bx
X push ax | save ax
X push dx | save dx
X mov dx,4(bx) | dx = port
X in | input 1 byte
X xorb ah,ah | clear ah
X mov bx,6(bx) | fetch address where byte is to go
X mov (bx),ax | return byte to caller in param
X pop dx | restore dx
X pop ax | restore ax
X pop bx | restore bx
X ret | return to caller
X
/