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 /