/* #define	HOWFAR *//* * Real time clock driver * * (C) 1984 UniSoft Corp. of Berkeley CA * * UniPlus Source Code. This program is proprietary * with Unisoft Corporation and is not to be reproduced * or used in any manner except as authorized in * writing by Unisoft. * * Only reads and writes of 4 bytes (sizeof time_t, the standard unix * representation of time) are allowed for the real time clock. * The rtime structure contains the time most recently read or written. * * struct rtime {		See page 35 LHRM * 	time_t	rt_tod;		Seconds since the Epoch (unix time) * 	long	rt_alrm;	Seconds remaining to trigger alarm (unused) * 	short	rt_year;	year			(0 - 15) * 	short	rt_day;		julian day		(1 - 366) * 	short	rt_hour;	hour			(0 - 23) * 	short	rt_min;		minute			(0 - 59) * 	short	rt_sec;		second			(0 - 59) * 	short	rt_tenth;	tenths of a second	(0 - 9) * }; */#include "sys/param.h"#include "sys/config.h"#include "sys/mmu.h"#include "sys/types.h"#include "sys/sysmacros.h"#include "sys/dir.h"#include "sys/signal.h"#include "sys/user.h"#include "sys/errno.h"#include "sys/utsname.h"#include "sys/buf.h"#include "sys/elog.h"#include "sys/erec.h"#include "sys/iobuf.h"#include "sys/systm.h"#include "sys/var.h"#include "setjmp.h"#include "sys/reg.h"#include "sys/tty.h"#include "sys/local.h"struct rtime rtime;int rtcrwait;		/* flag to sleep on waiting for read to complete *//* * Read the real time clock.  The command to do this is issued through * the COPS.  In response, the keyboard gets 6 special interrupts with * the data.  kbintr stores this data in rtime and calls rtcsettod when * the sixth one has been handled.  rtcsettod calculates the time as * unix likes to think of it, which is as it is returned. *//* ARGSUSED */rtcread(dev)dev_t dev;{	time_t rt;	if (u.u_count != sizeof(time_t)) {		u.u_error = ENXIO;		return;	}	rt = rtcdoread();	iomove((caddr_t)&rt, sizeof(time_t), B_READ);}/* * This routine is normally called from rtcread.  However the kernel * reads the clock by calling rtcdoread directly from clkset. */rtcdoread(){	l2copscmd(READCLOCK);	rtcrwait = 1;	while (rtcrwait)		(void) sleep((caddr_t)&rtcrwait, TTIPRI);	return(rtime.rt_tod);}/* * Set rt_tod (real time in seconds since epoch) given the real * time clock time currently in the rest of the rtime structure. * Those values (rt_year, rt_day, rt_hour, rt_min, rt_sec) are * set in response to l2copscmd(READCLOCK), and are returned through * special keyboard interrupts (kbintr). */#define dsize(x) (x%4==0 ?366 :365)#define YEAR 70rtcsettod (){	register struct rtime *p = &rtime;	register short i, j;	i = -1;	for (j=YEAR; j-YEAR<p->rt_year; j++)		i += dsize(j);	p->rt_tod = i + p->rt_day;		/* Days since epoch */	p->rt_tod *= 24;	p->rt_tod += p->rt_hour;	p->rt_tod *= 60;	p->rt_tod += p->rt_min;	p->rt_tod *= 60;	p->rt_tod += p->rt_sec;#ifdef HOWFAR	printf("DATE: %d.%d %d:%d.%d\n", p->rt_year, p->rt_day,		p->rt_hour, p->rt_min, p->rt_sec);#endif HOWFAR	if (rtcrwait) {		rtcrwait = 0;		wakeup((caddr_t)&rtcrwait);	}}/* * Set the real time clock to the time indicated.  Note that nt is in * seconds since midnight 1/1/1970 GMT.  The timezone has already been * corrected for. *//* ARGSUSED */rtcwrite(dev)dev_t dev;{	register struct rtime *p = &rtime;	register long nt;	register long i, j;	if (u.u_count != sizeof(time_t)) {		u.u_error = ENXIO;		return;	}	iomove((caddr_t)&rtime.rt_tod, sizeof(time_t), B_WRITE);	nt = p->rt_tod;	i = nt % 86400;		/* 86400 = 24*60*60 = number secs./day */	j = nt / 86400;	if (i < 0) {		i += 86400;		j -= 1;	}	nt = j;	p->rt_sec = i % 60;	i /= 60;	p->rt_min = i % 60;	i /= 60;	p->rt_hour = i % 24;	j = YEAR;	for (j=YEAR; i=dsize(j); j++) {		if (nt < i)			break;		nt -= i;	}	p->rt_year = j - YEAR;	if (p->rt_year < 10) {#ifdef HOWFAR		printf("can't remember dates before 1980\n");#endif HOWFAR		u.u_error = EINVAL;		return;	}	p->rt_day = ++nt;	l2copscmd(SETCLOCK);	/* stop clock, start setup mode */	for (i=0; i<5; i++)		l2copscmd(CLKNIBBLE);	/* no alarm implemented yet */	l2copscmd(CLKNIBBLE | (p->rt_year - 10));	i = p->rt_day / 10;	j = i / 10;	l2copscmd((char)(CLKNIBBLE | j));	l2copscmd((char)(CLKNIBBLE | (i % 10)));	l2copscmd(CLKNIBBLE | (p->rt_day % 10));	l2copscmd(CLKNIBBLE | (p->rt_hour / 10));	l2copscmd(CLKNIBBLE | (p->rt_hour % 10));	l2copscmd(CLKNIBBLE | (p->rt_min / 10));	l2copscmd(CLKNIBBLE | (p->rt_min % 10));	l2copscmd(CLKNIBBLE | (p->rt_sec / 10));	l2copscmd(CLKNIBBLE | (p->rt_sec % 10));	l2copscmd(STRTCLOCK);	/* start clock, leave timer disabled *//*	l2copscmd(READCLOCK);	/* Now read it back */}