[comp.os.minix] New timedate.c to read clock card

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
/