## 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
|