[comp.os.minix] Prg needed to query realtime clock on PC-AT

wee@iris (Chris Wee) (05/09/88)

Does anyone have a program/tool to read the date and time from
a standard IBM PC-AT?  I'm tired of responding to MINIX's date query.

Also, I would like to incorporate some history mechanism into the
current shell.  If such a product already exists, please e-mail
its location to me immediately - my OS classmates are weary with
typing.

chris wee		(wee@iris.ucdavis.edu)

Leisner.Henr@xerox.com (marty) (05/09/88)

Chris,

The answer is to get the time when you boot from the pc-at.  I have the
following code  in kernel/clock.c
#ifdef i286
#define CMOS_SECONDS	0
#define CMOS_MINUTES	2
#define CMOS_HOURS	4
#define CMOS_DATE	7
#define CMOS_MONTH	8
#define CMOS_YEAR	9

#define SECS_PER_DAY	(24L*60L*60L)
#define SECS_PER_YEAR	(365L*SECS_PER_DAY)

/* get the cmos time off the battery backed up clock  (6845) */
static real_time get_cmos_time()
{
	extern unsigned char read_cmos_ram();
	real_time temp;
	static int month_to_days[12] = 
		{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
	int year;
	int month;
	int day;
	
	year = convert_bcd(read_cmos_ram(CMOS_YEAR));
	month = convert_bcd(read_cmos_ram(CMOS_MONTH));

	if(month > 2 && !(year % 4))
		month_to_days[month - 1]++;	/* leap year */
	year -= 70;		/* only want years since 1970 */	
	day = month_to_days[month - 1];
	day += convert_bcd(read_cmos_ram(CMOS_DATE)) -1;
	day += (year + 1)/4;		/* take into account leap years */
       
	temp = (real_time)  year * SECS_PER_YEAR;
	
	temp += (real_time) day*SECS_PER_DAY;
	temp += (real_time) convert_bcd(read_cmos_ram(CMOS_HOURS))*3600L;
	temp += (real_time) convert_bcd(read_cmos_ram(CMOS_MINUTES))*60L;
	temp += (real_time) convert_bcd(read_cmos_ram(CMOS_SECONDS));
	
	return temp;
	
	
}
#endif
And in init_clock:
#ifdef i286
   real_time get_cmos_time();

/* get time off cmos battery backed up ram */ 
  ps = disable();
  lost_ticks = 0;
  realtime = 0;
  boot_time = get_cmos_time();
#endif

And stick the following in assembler somewhere:
CMOS_ADDR	=	070H	
CMOS_DATA	=	071H	 
procdef	read_cmos_ram,<<in_address,word>>
	pushf
	cli
	mov	ax,in_address
	out	CMOS_ADDR,al
	xor	ah,ah
	in	al,CMOS_DATA
	popf
	pret
pend	read_cmos_ram
	
procdef	convert_bcd,<<to_convert, byte>>
	mov	al,to_convert
	; convert from bcd to decimal
	mov	bl,al
	shr	al,4
	mov	cl,10
	mul	cl
	and	bl,0fH
	add	al,bl
	pret
pend convert_bcd

Please note the above code is quick and dirty.  It seems to work fine.  If
anyone sees any bugs, please let me know.  Telling time is not one of my strong
points ;-).  I'm only dealing with local time, no GMT stuff.

It is definitely a bad idea to let applications play with hardware ports
directly.  I believe Xenix/Microport systems have some sortta clock device to
let setuid applications set the hardware real-time clock.  Non-protected mode
Minix systems will allow you to do the above in user code, if you want to.

As for a history mechanism, I'm planning on bringing up the Alan Holub shell
written up in Dr. Dobb's Journal a couple of years ago.  I use it under Ms/Dos
and it supplies reasonable capability.  It should run nicely on Minix.


marty
ARPA:	leisner.henr@xerox.com
GV:  leisner.henr
NS:  martin leisner:henr801c:xerox
UUCP:  nsc!nscimg!amps!marty