Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/carrera/devrtc.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname carrera/devrtc.c 1993/0916
## diff -e /dev/null /n/fornaxdump/1993/0916/sys/src/brazil/carrera/devrtc.c
0a
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"devtab.h"
#include	"io.h"

/*
 *  real time clock and non-volatile ram
 */

typedef struct Rtc	Rtc;
struct Rtc
{
	int	sec;
	int	min;
	int	hour;
	int	mday;
	int	mon;
	int	year;
};
QLock rtclock;	/* mutex on clock operations */


enum{
	Qrtc = 1,
	Qnvram,

	Seconds=	0x00,
	Minutes=	0x02,
	Hours=		0x04, 
	Mday=		0x07,
	Month=		0x08,
	Year=		0x09,
	Status=		0x0A,

	Nvsize = 4096,
};

#define	NRTC	2
Dirtab rtcdir[]={
	"nvram",	{Qnvram, 0},	Nvsize,	0664,
	"rtc",		{Qrtc, 0},	0,	0664,
};

ulong rtc2sec(Rtc*);
void sec2rtc(ulong, Rtc*);
int *yrsize(int);

void
rtcreset(void)
{
}

void
rtcinit(void)
{
}

Chan*
rtcattach(char *spec)
{
	return devattach('r', spec);
}

Chan*
rtcclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int	 
rtcwalk(Chan *c, char *name)
{
	return devwalk(c, name, rtcdir, NRTC, devgen);
}

void	 
rtcstat(Chan *c, char *dp)
{
	devstat(c, dp, rtcdir, NRTC, devgen);
}

Chan*
rtcopen(Chan *c, int omode)
{
	omode = openmode(omode);
	switch(c->qid.path){
	case Qrtc:
		if(strcmp(up->user, eve)!=0 && omode!=OREAD)
			error(Eperm);
		break;
	case Qnvram:
		if(strcmp(up->user, eve)!=0)
			error(Eperm);
	}
	return devopen(c, omode, rtcdir, NRTC, devgen);
}

void	 
rtccreate(Chan *c, char *name, int omode, ulong perm)
{
	USED(c, name, omode, perm);
	error(Eperm);
}

void	 
rtcclose(Chan *c)
{
	USED(c);
}

static uchar
bcd2binary(int reg)
{
	uchar x;
/*
	x = (*(uchar*)Rtcindex)&~0x7f;
	*(uchar*)Rtcindex = x|reg;
	x = *(uchar*)Rtcdata;
	return (x&0xf) + 10*(x>>4);
/**/
	return 0;
}

long	 
rtctime(void)
{
	Rtc rtc;
	int x;

	/*
	 *  read and convert from bcd
	 */
	x = splhi();
	rtc.sec = bcd2binary(Seconds);
	rtc.min = bcd2binary(Minutes);
	rtc.hour = bcd2binary(Hours);
	rtc.mday = bcd2binary(Mday);
	rtc.mon = bcd2binary(Month);
	rtc.year = bcd2binary(Year);
	splx(x);

	/*
	 *  the world starts jan 1 1970
	 */
	if(rtc.year < 70)
		rtc.year += 2000;
	else
		rtc.year += 1900;
	return rtc2sec(&rtc);
}

long	 
rtcread(Chan *c, void *buf, long n, ulong offset)
{
	ulong t, ot;
	uchar *f, *to, *e;

	if(c->qid.path & CHDIR)
		return devdirread(c, buf, n, rtcdir, NRTC, devgen);

	switch(c->qid.path){
	case Qrtc:
		t = rtctime();
		do{
			ot = t;
			t = rtctime();	/* make sure there's no skew */
		}while(t != ot);
		n = readnum(offset, buf, n, t, 12);
		return n;
	case Qnvram:
		if(offset > Nvsize)
			return -1;
		if(offset + n > Nvsize)
			n = Nvsize - offset;
		f = (uchar*)Nvram+offset;
		to = buf;
		e = f + n;
		while(f < e)
			*to++ = *f++;
		return n;
	}
	error(Ebadarg);
	return 0;
}

static void
binary2bcd(int reg, uchar val)
{
	uchar x;
/*
	x = (*(uchar*)Rtcindex)&~0x7f;
	*(uchar*)Rtcindex = x|reg;
	*(uchar*)Rtcdata = (val % 10) | (((val / 10) % 10)<<4);
/**/
}


long	 
rtcwrite(Chan *c, void *buf, long n, ulong offset)
{
	Rtc rtc;
	ulong secs;
	char *cp, *ep;
	uchar *f, *t, *e;
	int s;

	USED(c);
	switch(c->qid.path){
	case Qrtc:
		/*
		 *  read the time
		 */
		cp = ep = buf;
		ep += n;
		while(cp < ep){
			if(*cp>='0' && *cp<='9')
				break;
			cp++;
		}
		secs = strtoul(cp, 0, 0);
		sec2rtc(secs, &rtc);
	
		/*
		 *  convert to bcd
		 */
		s = splhi();
		binary2bcd(Seconds, rtc.sec);
		binary2bcd(Minutes, rtc.min);
		binary2bcd(Hours, rtc.hour);
		binary2bcd(Mday, rtc.mday);
		binary2bcd(Month, rtc.mon);
		binary2bcd(Year, rtc.year);
		splx(s);

		return n;
	case Qnvram:
		if(offset > Nvsize)
			return -1;
		if(offset + n > Nvsize)
			n = Nvsize - offset;
		t = (uchar*)Nvram+offset;
		f = buf;
		e = f + n;
		while(f < e)
			*t++ = *f++;
		return n;
	}
	error(Ebadarg);
	return 0;
}

void	 
rtcremove(Chan *c)
{
	USED(c);
	error(Eperm);
}

void	 
rtcwstat(Chan *c, char *dp)
{
	USED(c, dp);
	error(Eperm);
}

#define SEC2MIN 60L
#define SEC2HOUR (60L*SEC2MIN)
#define SEC2DAY (24L*SEC2HOUR)

/*
 *  days per month plus days/year
 */
static	int	dmsize[] =
{
	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static	int	ldmsize[] =
{
	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

/*
 *  return the days/month for the given year
 */
int *
yrsize(int yr)
{
	if((yr % 4) == 0)
		return ldmsize;
	else
		return dmsize;
}

/*
 *  compute seconds since Jan 1 1970
 */
ulong
rtc2sec(Rtc *rtc)
{
	ulong secs;
	int i;
	int *d2m;

	secs = 0;

	/*
	 *  seconds per year
	 */
	for(i = 1970; i < rtc->year; i++){
		d2m = yrsize(i);
		secs += d2m[0] * SEC2DAY;
	}

	/*
	 *  seconds per month
	 */
	d2m = yrsize(rtc->year);
	for(i = 1; i < rtc->mon; i++)
		secs += d2m[i] * SEC2DAY;

	secs += (rtc->mday-1) * SEC2DAY;
	secs += rtc->hour * SEC2HOUR;
	secs += rtc->min * SEC2MIN;
	secs += rtc->sec;

	return secs;
}

/*
 *  compute rtc from seconds since Jan 1 1970
 */
void
sec2rtc(ulong secs, Rtc *rtc)
{
	int d;
	long hms, day;
	int *d2m;

	/*
	 * break initial number into days
	 */
	hms = secs % SEC2DAY;
	day = secs / SEC2DAY;
	if(hms < 0) {
		hms += SEC2DAY;
		day -= 1;
	}

	/*
	 * generate hours:minutes:seconds
	 */
	rtc->sec = hms % 60;
	d = hms / 60;
	rtc->min = d % 60;
	d /= 60;
	rtc->hour = d;

	/*
	 * year number
	 */
	if(day >= 0)
		for(d = 1970; day >= *yrsize(d); d++)
			day -= *yrsize(d);
	else
		for (d = 1970; day < 0; d--)
			day += *yrsize(d-1);
	rtc->year = d;

	/*
	 * generate month
	 */
	d2m = yrsize(rtc->year);
	for(d = 1; day >= d2m[d]; d++)
		day -= d2m[d];
	rtc->mday = day + 1;
	rtc->mon = d;

	return;
}
.
## diffname carrera/devrtc.c 1994/0225
## diff -e /n/fornaxdump/1993/0916/sys/src/brazil/carrera/devrtc.c /n/fornaxdump/1994/0225/sys/src/brazil/carrera/devrtc.c
198d
194d
124,125d
119c

.
## diffname carrera/devrtc.c 1995/0108
## diff -e /n/fornaxdump/1994/0225/sys/src/brazil/carrera/devrtc.c /n/fornaxdump/1995/0108/sys/src/brazil/carrera/devrtc.c
249a
}

long
rtcbwrite(Chan *c, Block *bp, ulong offset)
{
	return devbwrite(c, bp, offset);
.
187a
Block*
rtcbread(Chan *c, long n, ulong offset)
{
	return devbread(c, n, offset);
}

.
27c
enum
{
.
## diffname carrera/devrtc.c 1996/0223
## diff -e /n/fornaxdump/1995/0108/sys/src/brazil/carrera/devrtc.c /n/fornaxdump/1996/0223/sys/src/brazil/carrera/devrtc.c
7d
## diffname carrera/devrtc.c 1997/0327
## diff -e /n/fornaxdump/1996/0223/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1997/0327/sys/src/brazil/carrera/devrtc.c
344c
static void
.
309c
static ulong
.
297c
static int*
.
264,277d
258,262c
Dev rtcdevtab = {
	devreset,
	devinit,
	rtcattach,
	devclone,
	rtcwalk,
	rtcstat,
	rtcopen,
	devcreate,
	rtcclose,
	rtcread,
	devbread,
	rtcwrite,
	devbwrite,
	devremove,
	devwstat,
};
.
204c
static long	 
.
188,193d
161c
		return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
.
154c
static long	 
.
102,109c
static void	 
.
99c
	return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
.
86c
static Chan*
.
83c
	devstat(c, dp, rtcdir, nelem(rtcdir), devgen);
.
80c
static void	 
.
77c
	return devwalk(c, name, rtcdir, nelem(rtcdir), devgen);
.
68,74c
static int	 
.
52,62c
static Chan*
.
48,50c
static ulong rtc2sec(Rtc*);
static void sec2rtc(ulong, Rtc*);
.
42d
23c
static QLock rtclock;	/* mutex on clock operations */
.
## diffname carrera/devrtc.c 1997/0401
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1997/0401/sys/src/brazil/carrera/devrtc.c
207c
		binary2bcd(Year, rtc.year-1970);
.
141,144c
		qunlock(&rtclock);
.
139a
		qlock(&rtclock);
.
132c
	ulong t;
.
128a
static Lock rtlock;

long
rtctime(void)
{
	int i;
	long t, ot;

	ilock(&rtlock);

	/* loop till we get two reads in a row the same */
	t = _rtctime();
	for(i = 0; i < 100; i++){
		ot = t;
		t = _rtctime();
		if(ot == t)
			break;
	}
	if(i == 100) print("we are boofheads\n");

	iunlock(&rtlock);

	return t;
}

.
119,125c
		/*
		 *  read and convert from bcd
		 */
		rtc.sec = bcd2binary(Seconds);
		rtc.min = bcd2binary(Minutes);
		rtc.hour = bcd2binary(Hours);
		rtc.mday = bcd2binary(Mday);
		rtc.mon = bcd2binary(Month);
		rtc.year = bcd2binary(Year)+1970;

		x = (*(uchar*)Rtcindex)&~0x7f;
		*(uchar*)Rtcindex = x|Status;
		x = *(uchar*)Rtcdata;
		if((x & 0x80) == 0)
			break;
	}

.
107,117c
	for(i = 0; i < 10000; i++){
		x = (*(uchar*)Rtcindex)&~0x7f;
		*(uchar*)Rtcindex = x|Status;
		x = *(uchar*)Rtcdata;
		if(x & 0x80)
			continue;
.
105c
	int i, x;
.
101,102c
static long	 
_rtctime(void)
.
## diffname carrera/devrtc.c 1997/0403
## diff -e /n/emeliedump/1997/0401/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1997/0403/sys/src/brazil/carrera/devrtc.c
197c
	if(statusB & 0x04)
		*(uchar*)Rtcdata = val;
	else
		*(uchar*)Rtcdata = (val % 10) | (((val / 10) % 10)<<4);
.
194a

.
171a
dumprtcstatus();
.
156a
#else
	extern ulong boottime;

	return boottime+TK2SEC(MACHP(0)->ticks);
#endif /* notdef */
.
155a
	if(i == 100) print("we are boofheads\n");

.
152,153d
138a
#define notdef
#ifdef notdef
.
130a
	if(statusB & 0x04){
		rtc.sec = clock[0];
		rtc.min = clock[1];
		rtc.hour = clock[2];
		rtc.mday = clock[3];
		rtc.mon = clock[4];
		rtc.year = clock[5];
	}
	else{
		/*
		 *  convert from BCD
		 */
		rtc.sec = GETBCD(0);
		rtc.min = GETBCD(1);
		rtc.hour = GETBCD(2);
		rtc.mday = GETBCD(3);
		rtc.mon = GETBCD(4);
		rtc.year = GETBCD(5);
	}

	/*
	 *  the world starts jan 1 1970
	 */
	rtc.year += 1970;

.
126,127c
		r = *(uchar*)Rtcdata;
		if((r & 0x80) == 0)
.
124d
114,122c
		/* read clock values */
		*(uchar*)Rtcindex = x|Seconds;
		clock[0] = *(uchar*)Rtcdata;
		*(uchar*)Rtcindex = x|Minutes;
		clock[1] = *(uchar*)Rtcdata;
		*(uchar*)Rtcindex = x|Hours;
		clock[2] = *(uchar*)Rtcdata;
		*(uchar*)Rtcindex = x|Mday;
		clock[3] = *(uchar*)Rtcdata;
		*(uchar*)Rtcindex = x|Month;
		clock[4] = *(uchar*)Rtcdata;
		*(uchar*)Rtcindex = x|Year;
		clock[5] = *(uchar*)Rtcdata;
.
112a
		}
.
110,111c
		r = *(uchar*)Rtcdata;
		if(r & 0x80){
			busy++;
.
106a
	/* don't do the read until the clock is no longer busy */
	busy = 0;
.
105a
	uchar clock[Nclock], r;
	int busy;
.
100a
#define GETBCD(o) ((clock[o]&0xf) + 10*(clock[o]>>4))

static void
dumprtcstatus(void)
{
	int i, x;
	uchar status[4], r;

	for(i = 0; i < 10000; i++){
		x = (*(uchar*)Rtcindex)&~0x7f;
		*(uchar*)Rtcindex = x|Status;
		r = *(uchar*)Rtcdata;
		if(r & 0x80)
			continue;

		status[0] = r;
		*(uchar*)Rtcindex = x|StatusB;
		status[1] = *(uchar*)Rtcdata;
		*(uchar*)Rtcindex = x|StatusC;
		status[2] = *(uchar*)Rtcdata;
		*(uchar*)Rtcindex = x|StatusD;
		status[3] = *(uchar*)Rtcdata;

		*(uchar*)Rtcindex = x|Status;
		r = *(uchar*)Rtcdata;
		if((r & 0x80) == 0)
			break;
	}

	print("RTC: %uX %uX %uX %uX\n", status[0], status[1], status[2], status[3]);
}

.
52a
	getstatusB();
.
49a
static uchar statusB;

static void
getstatusB(void)
{
	int i, x;
	uchar r;

	for(i = 0; i < 10000; i++){
		x = (*(uchar*)Rtcindex)&~0x7f;
		*(uchar*)Rtcindex = x|Status;
		r = *(uchar*)Rtcdata;
		if(r & 0x80)
			continue;

		*(uchar*)Rtcindex = x|StatusB;
		statusB = *(uchar*)Rtcdata;
		break;
	}
}

.
39a

	Nclock=		6,
.
37a
	StatusB=	0x0B,
	StatusC=	0x0C,
	StatusD=	0x0D,
.
## diffname carrera/devrtc.c 1997/0404
## diff -e /n/emeliedump/1997/0403/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1997/0404/sys/src/brazil/carrera/devrtc.c
361c
	rtcreset,
.
342a
		if(!isbinary){	
			/*
			 *  convert to bcd
			 */
			rtc.sec = PUTBCD(rtc.sec);
			rtc.min = PUTBCD(rtc.min);
			rtc.hour = PUTBCD(rtc.hour);
			rtc.mday = PUTBCD(rtc.mday);
			rtc.mon = PUTBCD(rtc.mon);
			rtc.year = PUTBCD(rtc.year);
		}

		ilock(&rtclock);
		/* set clock values */
		x = (*(uchar*)Rtcindex)&~0x7f;
		*(uchar*)Rtcindex = x|Seconds;
		*(uchar*)Rtcdata = rtc.sec;
		*(uchar*)Rtcindex = x|Minutes;
		*(uchar*)Rtcdata = rtc.min;
		*(uchar*)Rtcindex = x|Hours;
		*(uchar*)Rtcdata = rtc.hour;
		*(uchar*)Rtcindex = x|Mday;
		*(uchar*)Rtcdata = rtc.mday;
		*(uchar*)Rtcindex = x|Month;
		*(uchar*)Rtcdata = rtc.mon;
		*(uchar*)Rtcindex = x|Year;
		*(uchar*)Rtcdata = rtc.year;
		iunlock(&rtclock);

.
330,341c
		rtc.year -= 1970;
.
313c
	uchar x;
.
292,305d
270,275c
		return readnum(offset, buf, n, rtctime(), 12);
.
262d
252,256d
249,250d
247c
	iunlock(&rtclock);
.
237c
	ilock(&rtclock);
.
232,233d
227,228d
211,216c
		rtc.sec = GETBCD(rtc.sec);
		rtc.min = GETBCD(rtc.min);
		rtc.hour = GETBCD(rtc.hour);
		rtc.mday = GETBCD(rtc.mday);
		rtc.mon = GETBCD(rtc.mon);
		rtc.year = GETBCD(rtc.year);
.
199,207c
	if(!isbinary){
.
195c
		if((r & Update) == 0)
.
191c
		rtc.year = *(uchar*)Rtcdata;
.
189c
		rtc.mon = *(uchar*)Rtcdata;
.
187c
		rtc.mday = *(uchar*)Rtcdata;
.
185c
		rtc.hour = *(uchar*)Rtcdata;
.
183c
		rtc.min = *(uchar*)Rtcdata;
.
181c
		rtc.sec = *(uchar*)Rtcdata;
.
177d
174,175c
		if(r & Update)
.
169d
165,166c
	uchar r;
.
117,159d
79d
71c
		isbinary = *(uchar*)Rtcdata & 0x04;
.
58c
rtcreset(void)
.
55c
static int isbinary;
static Lock rtclock;
.
46a
#define GETBCD(v)	(((v) & 0x0F) + 10*((v)>>4))
#define PUTBCD(v)	((v) % 10)|((((v)/10) % 10)<<4)

.
41a
	Update=		0x80,

.
25d
23d
## diffname carrera/devrtc.c 1997/0408
## diff -e /n/emeliedump/1997/0404/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1997/0408/sys/src/brazil/carrera/devrtc.c
295a
	'r',
	"rtc",

.
## diffname carrera/devrtc.c 1997/0411
## diff -e /n/emeliedump/1997/0408/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1997/0411/sys/src/brazil/carrera/devrtc.c
193a
#else
	extern ulong boottime;

	return boottime+TK2SEC(MACHP(0)->ticks);
#endif /* notdef */
.
177a
#ifdef notdef
.
## diffname carrera/devrtc.c 1998/0319
## diff -e /n/emeliedump/1997/0411/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1998/0319/sys/src/brazil/carrera/devrtc.c
238d
236a
	ulong offset = off;
.
230c
rtcwrite(Chan *c, void *buf, long n, vlong off)
.
205a
	ulong offset = off;
.
203c
rtcread(Chan *c, void *buf, long n, vlong off)
.
117d
115c
rtcclose(Chan*)
.
## diffname carrera/devrtc.c 1999/0128
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1999/0128/sys/src/brazil/carrera/devrtc.c
282a
}else{
		splhi();
		MACHP(0)->ticks = HZ*(secs - boottime);	/* inverse of SEC2TK() */
		spllo();
}
.
266a
/* disgusting hack because RTC doesn't work and m->ticks drifts */
if(boottime == 0){
.
195,196d
12a
extern ulong boottime;

.
## diffname carrera/devrtc.c 1999/0228
## diff -e /n/emeliedump/1999/0128/sys/src/brazil/carrera/devrtc.c /n/emeliedump/1999/0228/sys/src/brazil/carrera/devrtc.c
285,289d
267,268d
196,198d
179d
## diffname carrera/devrtc.c 2001/0527 # deleted
## diff -e /n/emeliedump/1999/0228/sys/src/brazil/carrera/devrtc.c /n/emeliedump/2001/0527/sys/src/9/carrera/devrtc.c
1,431d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].