plan 9 kernel history: overview | file list | diff list

1990/1204/power/devrtc.c (diff list | history)

power/devrtc.c on 1990/1204
1990/1204    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"errno.h" 
#include	"devtab.h" 
 
#include	"io.h" 
 
typedef struct Rtc Rtc; 
struct Rtc 
{ 
	QLock; 
	int	sec; 
	int	min; 
	int	hour; 
	int	mday; 
	int	mon; 
	int	year; 
}; 
Rtc rtc; 
 
Dirtab rtcdir[]={ 
	"rtc",		{1},	0,	0600, 
}; 
 
static uchar pattern[] = 
{ 
	0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c 
}; 
 
/* 
 *  issue pattern recognition bits to nv ram to address the 
 *  real time clock 
 */ 
rtcpattern(void) 
{ 
	uchar *nv; 
	uchar ch; 
	int i, j; 
 
	nv = RTC; 
 
	/* 
	 *  read the pattern sequence pointer to reset it 
	 */ 
	ch = *nv; 
 
	/* 
	 *  stuff the pattern recognition codes one bit at 
	 *  a time into *nv. 
	 */ 
	for(i = 0; i < sizeof(pattern); i++){ 
		ch = pattern[i]; 
		for (j = 0; j < 8; j++){ 
			*nv = ch & 0x1; 
			ch >>= 1; 
		} 
	} 
} 
 
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) 
{ 
	if(c->qid.path != CHDIR) 
		return 0; 
	if(strcmp(name, "rtc") == 0){ 
		c->qid.path = 1; 
		return 1; 
	} 
	return 0; 
} 
 
void	  
rtcstat(Chan *c, char *dp) 
{ 
	devstat(c, dp, rtcdir, 1, devgen); 
} 
 
Chan* 
rtcopen(Chan *c, int omode) 
{ 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
void	  
rtccreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	error(Eperm); 
} 
 
void	  
rtcclose(Chan *c) 
{ 
} 
 
#define GETBCD(o) ((clock[o]&0xf) + 10*(clock[o]>>4)) 
 
long	  
rtcread(Chan *c, void *buf, long n) 
{ 
	int i,j; 
	uchar ch; 
	uchar *nv; 
	uchar clock[8]; 
	char atime[64]; 
 
	if(c->offset!=0) 
		error(Ebadarg);  
	nv = RTC; 
 
	/* 
	 *  set up the pattern for the clock 
	 */ 
	qlock(&rtc); 
	rtcpattern(); 
 
	/* 
	 *  read out the clock one bit at a time 
	 */ 
	for (i = 0; i < 8; i++){ 
		ch = 0; 
		for (j = 0; j < 8; j++) 
			ch |= ((*nv & 0x1) << j); 
		clock[i] = ch; 
	} 
	qunlock(&rtc); 
	rtc.sec = GETBCD(1); 
	rtc.min = GETBCD(2); 
	rtc.hour = GETBCD(3); 
	rtc.mday = GETBCD(5); 
	rtc.mon = GETBCD(6); 
	rtc.year = GETBCD(7); 
 
	/* 
	 *  the world starts jan 1 1970 
	 */ 
	if(rtc.year < 70) 
		rtc.year += 2000; 
	else 
		rtc.year += 1900; 
 
	sprint(atime, "%.2d:%.2d:%.2d %d/%d/%d", rtc.hour, rtc.min, rtc.sec, 
		rtc.mon, rtc.mday, rtc.year); 
	i = strlen(atime); 
 
	if(c->offset >= i) 
		return 0; 
	if(c->offset + n > i) 
		n = i - c->offset; 
	strncpy(buf, &atime[c->offset], n); 
 
	return n; 
} 
 
static int perm[] = 
{ 
	3, 2, 1, 6, 5, 7 
}; 
 
long	  
rtcwrite(Chan *c, void *buf, long n) 
{ 
	int i,j; 
	uchar ch; 
	uchar clock[8]; 
	uchar *nv; 
	char *cp; 
 
	if(c->offset!=0) 
		error(Ebadarg); 
 
	/* 
	 *  parse (most any separator will do) 
	 */ 
	ch = 0; 
	j = 0; 
	clock[0] = clock[4] = 0; 
	cp = buf; 
	for(i = 0; i < n; i++){ 
		switch(*cp){ 
		case ':': case ' ': case '\t': case '/': case '-': 
			clock[perm[j++]] = ch; 
			ch = 0; 
			break; 
		case '0': case '1': case '2': case '3': case '4': 
		case '5': case '6': case '7': case '8': case '9': 
			ch = (ch<<4) | (*cp - '0'); 
			break; 
		default: 
			error(Ebadarg); 
		} 
		cp++; 
	} 
	clock[perm[j++]] = ch; 
	if(j != 6) 
		error(Ebadarg); 
 
	/* 
	 *  set up the pattern for the clock 
	 */ 
	qlock(&rtc); 
	rtcpattern(); 
 
	/* 
	 *  write the clock one bit at a time 
	 */ 
	nv = RTC; 
	for (i = 0; i < 8; i++){ 
		ch = clock[i]; 
		for (j = 0; j < 8; j++){ 
			*nv = ch & 1; 
			ch >>= 1; 
		} 
	} 
	qunlock(&rtc); 
	return n; 
} 
 
void	  
rtcremove(Chan *c) 
{ 
	error(Eperm); 
} 
 
void	  
rtcwstat(Chan *c, char *dp) 
{ 
	error(Eperm); 
} 
 
#define SEC2MIN 60 
#define SEC2HOUR (60*SEC2MIN) 
#define SEC2DAY (24*SEC2HOUR) 
#define SEC2YR (365*SEC2DAY) 
 
static	char	dmsize[12] = 
{ 
	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 
}; 
 
/* 
 *  compute seconds since Jan 1 1970 
 */ 
ulong 
rtc2sec(void) 
{ 
	ulong secs; 
	int i; 
 
	for(i = 1970; i < rtc.year; i++) 
		secs += dysize(i); 
	for(i = 0; i < rtc.mon-1; i++) 
		secs += dmsize[i] * SEC2DAY; 
	if(dysize(rtc.year)==366 && rtc.mon>2) 
		secs += 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 
 */ 
sec2rtc(ulong secs) 
{ 
	int d0, d1; 
	long hms, day; 
 
	/* 
	 * 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 % SEC2MIN; 
	d1 = hms / SEC2MIN; 
	rtc.min = d1 % SEC2MIN; 
	d1 /= SEC2MIN; 
	rtc.hour = d1; 
 
	/* 
	 * year number 
	 */ 
	if(day >= 0) 
		for(d1 = 70; day >= dysize(d1); d1++) 
			day -= dysize(d1); 
	else 
		for (d1 = 70; day < 0; d1--) 
			day += dysize(d1-1); 
	rtc.year = d1; 
 
	/* 
	 * generate month 
	 */ 
	if(dysize(d1) == 366) 
		dmsize[1] = 29; 
	for(d1 = 0; d0 >= dmsize[d1]; d1++) 
		d0 -= dmsize[d1]; 
	dmsize[1] = 28; 
	rtc.mday = d0 + 1; 
	rtc.mon = d1; 
	return; 
} 
 
/* 
 *  days to year 
 */ 
static 
dysize(int y) 
{ 
 
	if((y%4) == 0) 
		return 366; 
	return 365; 
} 
 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)