xref: /inferno-os/os/mpc/devrtc.c (revision 7e00430948d8af545f880e82bb30cd3ee50deb04)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 #include	"io.h"
9 
10 /*
11  * MPC8xx real time clock
12  * optional board option switch
13  * optional nvram
14  * interrupt statistics
15  */
16 
17 enum{
18 	Qdir,
19 	Qrtc,
20 	Qswitch,
21 	Qnvram,
22 	Qintstat,
23 
24 	Qporta,
25 	Qportb,
26 	Qportc,
27 
28 	/* sccr */
29 	RTDIV=	1<<24,
30 	RTSEL=	1<<23,
31 
32 	/* rtcsc */
33 	RTE=	1<<0,
34 	R38K=	1<<4,
35 };
36 
37 static	QLock	rtclock;		/* mutex on clock operations */
38 
39 static Dirtab rtcdir[]={
40 	".",		{Qdir,0,QTDIR},	0,	0555,
41 	"rtc",		{Qrtc, 0},	12,	0664,
42 	"switch",	{Qswitch, 0}, 0, 0444,
43 	"intstat",	{Qintstat, 0}, 0, 0444,
44 	"porta",	{Qporta, 0}, 0, 0444,
45 	"portb",	{Qportb, 0}, 0, 0444,
46 	"portc",	{Qportc, 0}, 0, 0444,
47 	"nvram",	{Qnvram, 0},	0,	0660,
48 };
49 static long nrtc = nelem(rtcdir)-1;	/* excludes nvram */
50 
51 static	long	readport(int, ulong, char*, long);
52 
53 static void
54 rtcreset(void)
55 {
56 	IMM *io;
57 	int n;
58 
59 	io = m->iomem;
60 	io->rtcsck = KEEP_ALIVE_KEY;
61 	n = (RTClevel<<8)|RTE;
62 	if(m->clockgen == 5*MHz)
63 		n |= R38K;
64 	io->rtcsc = n;
65 	io->rtcsck = ~KEEP_ALIVE_KEY;
66 	if(conf.nvramsize != 0){
67 		rtcdir[nrtc].length = conf.nvramsize;
68 		nrtc++;
69 	}
70 }
71 
72 static Chan*
73 rtcattach(char *spec)
74 {
75 	return devattach('r', spec);
76 }
77 
78 static Walkqid*
79 rtcwalk(Chan *c, Chan *nc, char **name, int nname)
80 {
81 	return devwalk(c, nc, name, nname, rtcdir, nrtc, devgen);
82 }
83 
84 static int
85 rtcstat(Chan *c, uchar *dp, int n)
86 {
87 	return devstat(c, dp, n, rtcdir, nrtc, devgen);
88 }
89 
90 static Chan*
91 rtcopen(Chan *c, int omode)
92 {
93 	return devopen(c, omode, rtcdir, nrtc, devgen);
94 }
95 
96 static void
97 rtcclose(Chan*)
98 {
99 }
100 
101 static long
102 rtcread(Chan *c, void *buf, long n, vlong off)
103 {
104 	ulong offset = off;
105 	ulong t;
106 	char *b;
107 
108 	if(c->qid.type & QTDIR)
109 		return devdirread(c, buf, n, rtcdir, nrtc, devgen);
110 
111 	switch((ulong)c->qid.path){
112 	case Qrtc:
113 		t = m->iomem->rtc;
114 		n = readnum(offset, buf, n, t, 12);
115 		return n;
116 	case Qswitch:
117 		return readnum(offset, buf, n, archoptionsw(), 12);
118 	case Qintstat:
119 		b = malloc(2048);
120 		if(waserror()){
121 			free(b);
122 			nexterror();
123 		}
124 		intrstats(b, 2048);
125 		t = readstr(offset, buf, n, b);
126 		poperror();
127 		free(b);
128 		return t;
129 	case Qporta:
130 	case Qportb:
131 	case Qportc:
132 		return readport(c->qid.path, offset, buf, n);
133 	case Qnvram:
134 		if(offset < 0 || offset >= conf.nvramsize)
135 			return 0;
136 		if(offset + n > conf.nvramsize)
137 			n = conf.nvramsize - offset;
138 		memmove(buf, (char*)conf.nvrambase+offset, n);
139 		return n;
140 	}
141 	error(Egreg);
142 	return 0;		/* not reached */
143 }
144 
145 static long
146 rtcwrite(Chan *c, void *buf, long n, vlong off)
147 {
148 	ulong offset = off;
149 	ulong secs;
150 	char *cp, sbuf[32];
151 	IMM *io;
152 
153 	switch((ulong)c->qid.path){
154 	case Qrtc:
155 		/*
156 		 *  read the time
157 		 */
158 		if(offset != 0 || n >= sizeof(sbuf)-1)
159 			error(Ebadarg);
160 		memmove(sbuf, buf, n);
161 		sbuf[n] = '\0';
162 		cp = sbuf;
163 		while(*cp){
164 			if(*cp>='0' && *cp<='9')
165 				break;
166 			cp++;
167 		}
168 		secs = strtoul(cp, 0, 0);
169 		/*
170 		 * set it
171 		 */
172 		io = ioplock();
173 		io->rtck = KEEP_ALIVE_KEY;
174 		io->rtc = secs;
175 		io->rtck = ~KEEP_ALIVE_KEY;
176 		iopunlock();
177 		return n;
178 	case Qnvram:
179 		if(offset < 0 || offset >= conf.nvramsize)
180 			return 0;
181 		if(offset + n > conf.nvramsize)
182 			n = conf.nvramsize - offset;
183 		memmove((char*)conf.nvrambase+offset, buf, n);
184 		return n;
185 	}
186 	error(Egreg);
187 	return 0;		/* not reached */
188 }
189 
190 static long
191 readport(int p, ulong offset, char *buf, long n)
192 {
193 	long t;
194 	char *b;
195 	int v[4], i;
196 	IMM *io;
197 
198 	io = m->iomem;
199 	for(i=0;i<nelem(v); i++)
200 		v[i] = 0;
201 	switch(p){
202 	case Qporta:
203 		v[0] = io->padat;
204 		v[1] = io->padir;
205 		v[2] = io->papar;
206 		break;
207 	case Qportb:
208 		v[0] = io->pbdat;
209 		v[1] = io->pbdir;
210 		v[2] = io->pbpar;
211 		break;
212 	case Qportc:
213 		v[0] = io->pcdat;
214 		v[1] = io->pcdir;
215 		v[2] = io->pcpar;
216 		v[3] = io->pcso;
217 		break;
218 	}
219 	b = malloc(READSTR);
220 	if(waserror()){
221 		free(b);
222 		nexterror();
223 	}
224 	t = 0;
225 	for(i=0; i<nelem(v); i++)
226 		t += snprint(b+t, READSTR-t, " %8.8ux", v[i]);
227 	t = readstr(offset, buf, n, b);
228 	poperror();
229 	free(b);
230 	return t;
231 }
232 
233 long
234 rtctime(void)
235 {
236 	return m->iomem->rtc;
237 }
238 
239 Dev rtcdevtab = {
240 	'r',
241 	"rtc",
242 
243 	rtcreset,
244 	devinit,
245 	devshutdown,
246 	rtcattach,
247 	rtcwalk,
248 	rtcstat,
249 	rtcopen,
250 	devcreate,
251 	rtcclose,
252 	rtcread,
253 	devbread,
254 	rtcwrite,
255 	devbwrite,
256 	devremove,
257 	devwstat,
258 };
259