FreeBSD/Linux Kernel Cross Reference
sys/mtx/devarch.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8
9 typedef struct IOMap IOMap;
10 struct IOMap
11 {
12 IOMap *next;
13 char tag[13];
14 ulong start;
15 ulong end;
16 };
17
18 static struct
19 {
20 Lock;
21 IOMap *m;
22 IOMap *free;
23 IOMap maps[32]; // some initial free maps
24
25 QLock ql; // lock for reading map
26 } iomap;
27
28 enum {
29 Qdir = 0,
30 Qioalloc = 1,
31 Qiob,
32 Qiow,
33 Qiol,
34 Qbase,
35
36 Qmax = 16,
37 };
38
39 typedef long Rdwrfn(Chan*, void*, long, vlong);
40
41 static Rdwrfn *readfn[Qmax];
42 static Rdwrfn *writefn[Qmax];
43
44 static Dirtab archdir[] = {
45 ".", { Qdir, 0, QTDIR }, 0, 0555,
46 "ioalloc", { Qioalloc, 0 }, 0, 0444,
47 "iob", { Qiob, 0 }, 0, 0660,
48 "iow", { Qiow, 0 }, 0, 0660,
49 "iol", { Qiol, 0 }, 0, 0660,
50 };
51 Lock archwlock; /* the lock is only for changing archdir */
52 int narchdir = Qbase;
53 int (*_pcmspecial)(char *, ISAConf *);
54 void (*_pcmspecialclose)(int);
55
56 /*
57 * Add a file to the #P listing. Once added, you can't delete it.
58 * You can't add a file with the same name as one already there,
59 * and you get a pointer to the Dirtab entry so you can do things
60 * like change the Qid version. Changing the Qid path is disallowed.
61 */
62 Dirtab*
63 addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
64 {
65 int i;
66 Dirtab d;
67 Dirtab *dp;
68
69 memset(&d, 0, sizeof d);
70 strcpy(d.name, name);
71 d.perm = perm;
72
73 lock(&archwlock);
74 if(narchdir >= Qmax){
75 unlock(&archwlock);
76 return nil;
77 }
78
79 for(i=0; i<narchdir; i++)
80 if(strcmp(archdir[i].name, name) == 0){
81 unlock(&archwlock);
82 return nil;
83 }
84
85 d.qid.path = narchdir;
86 archdir[narchdir] = d;
87 readfn[narchdir] = rdfn;
88 writefn[narchdir] = wrfn;
89 dp = &archdir[narchdir++];
90 unlock(&archwlock);
91
92 return dp;
93 }
94
95 void
96 ioinit(void)
97 {
98 int i;
99
100 for(i = 0; i < nelem(iomap.maps)-1; i++)
101 iomap.maps[i].next = &iomap.maps[i+1];
102 iomap.maps[i].next = nil;
103 iomap.free = iomap.maps;
104
105 // a dummy entry at 2^17
106 ioalloc(0x20000, 1, 0, "dummy");
107 }
108
109 //
110 // alloc some io port space and remember who it was
111 // alloced to. if port < 0, find a free region.
112 //
113 int
114 ioalloc(int port, int size, int align, char *tag)
115 {
116 IOMap *m, **l;
117 int i;
118
119 lock(&iomap);
120 if(port < 0){
121 // find a free port above 0x400 and below 0x1000
122 port = 0x400;
123 for(l = &iomap.m; *l; l = &(*l)->next){
124 m = *l;
125 i = m->start - port;
126 if(i > size)
127 break;
128 if(align > 0)
129 port = ((port+align-1)/align)*align;
130 else
131 port = m->end;
132 }
133 if(*l == nil){
134 unlock(&iomap);
135 return -1;
136 }
137 } else {
138 // see if the space clashes with previously allocated ports
139 for(l = &iomap.m; *l; l = &(*l)->next){
140 m = *l;
141 if(m->end <= port)
142 continue;
143 if(m->start >= port+size)
144 break;
145 unlock(&iomap);
146 return -1;
147 }
148 }
149 m = iomap.free;
150 if(m == nil){
151 print("ioalloc: out of maps");
152 unlock(&iomap);
153 return port;
154 }
155 iomap.free = m->next;
156 m->next = *l;
157 m->start = port;
158 m->end = port + size;
159 strncpy(m->tag, tag, sizeof(m->tag));
160 m->tag[sizeof(m->tag)-1] = 0;
161 *l = m;
162
163 archdir[0].qid.vers++;
164
165 unlock(&iomap);
166 return m->start;
167 }
168
169 void
170 iofree(int port)
171 {
172 IOMap *m, **l;
173
174 lock(&iomap);
175 for(l = &iomap.m; *l; l = &(*l)->next){
176 if((*l)->start == port){
177 m = *l;
178 *l = m->next;
179 m->next = iomap.free;
180 iomap.free = m;
181 break;
182 }
183 if((*l)->start > port)
184 break;
185 }
186 archdir[0].qid.vers++;
187 unlock(&iomap);
188 }
189
190 int
191 iounused(int start, int end)
192 {
193 IOMap *m;
194
195 for(m = iomap.m; m; m = m->next){
196 if(start >= m->start && start < m->end
197 || start <= m->start && end > m->start)
198 return 0;
199 }
200 return 1;
201 }
202
203 static void
204 checkport(int start, int end)
205 {
206 /* standard vga regs are OK */
207 if(start >= 0x2b0 && end <= 0x2df+1)
208 return;
209 if(start >= 0x3c0 && end <= 0x3da+1)
210 return;
211
212 if(iounused(start, end))
213 return;
214 error(Eperm);
215 }
216
217 static Chan*
218 archattach(char* spec)
219 {
220 return devattach('P', spec);
221 }
222
223 Walkqid*
224 archwalk(Chan* c, Chan *nc, char** name, int nname)
225 {
226 return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
227 }
228
229 static int
230 archstat(Chan* c, uchar* dp, int n)
231 {
232 return devstat(c, dp, n, archdir, narchdir, devgen);
233 }
234
235 static Chan*
236 archopen(Chan* c, int omode)
237 {
238 return devopen(c, omode, archdir, nelem(archdir), devgen);
239 }
240
241 static void
242 archclose(Chan*)
243 {
244 }
245
246 enum
247 {
248 Linelen= 31,
249 };
250
251 static long
252 archread(Chan *c, void *a, long n, vlong offset)
253 {
254 char buf[Linelen+1], *p;
255 int port;
256 ushort *sp;
257 ulong *lp;
258 IOMap *m;
259 Rdwrfn *fn;
260
261 switch((ulong)c->qid.path){
262
263 case Qdir:
264 return devdirread(c, a, n, archdir, nelem(archdir), devgen);
265
266 case Qiob:
267 port = offset;
268 checkport(offset, offset+n);
269 for(p = a; port < offset+n; port++)
270 *p++ = inb(port);
271 return n;
272
273 case Qiow:
274 if((n & 0x01) || (offset & 0x01))
275 error(Ebadarg);
276 checkport(offset, offset+n+1);
277 n /= 2;
278 sp = a;
279 for(port = offset; port < offset+n; port += 2)
280 *sp++ = ins(port);
281 return n*2;
282
283 case Qiol:
284 if((n & 0x03) || (offset & 0x03))
285 error(Ebadarg);
286 checkport(offset, offset+n+3);
287 n /= 4;
288 lp = a;
289 for(port = offset; port < offset+n; port += 4)
290 *lp++ = inl(port);
291 return n*4;
292
293 case Qioalloc:
294 break;
295
296 default:
297 if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
298 return fn(c, a, n, offset);
299 error(Eperm);
300 break;
301 }
302
303 offset = offset/Linelen;
304 n = n/Linelen;
305 p = a;
306 lock(&iomap);
307 for(m = iomap.m; n > 0 && m != nil; m = m->next){
308 if(offset-- > 0)
309 continue;
310 if(strcmp(m->tag, "dummy") == 0)
311 break;
312 sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
313 memmove(p, buf, Linelen);
314 p += Linelen;
315 n--;
316 }
317 unlock(&iomap);
318
319 return p - (char*)a;
320 }
321
322 static long
323 archwrite(Chan *c, void *a, long n, vlong offset)
324 {
325 char *p;
326 int port;
327 ushort *sp;
328 ulong *lp;
329 Rdwrfn *fn;
330
331 switch((ulong)c->qid.path){
332
333 case Qiob:
334 p = a;
335 checkport(offset, offset+n);
336 for(port = offset; port < offset+n; port++)
337 outb(port, *p++);
338 return n;
339
340 case Qiow:
341 if((n & 01) || (offset & 01))
342 error(Ebadarg);
343 checkport(offset, offset+n+1);
344 n /= 2;
345 sp = a;
346 for(port = offset; port < offset+n; port += 2)
347 outs(port, *sp++);
348 return n*2;
349
350 case Qiol:
351 if((n & 0x03) || (offset & 0x03))
352 error(Ebadarg);
353 checkport(offset, offset+n+3);
354 n /= 4;
355 lp = a;
356 for(port = offset; port < offset+n; port += 4)
357 outl(port, *lp++);
358 return n*4;
359
360 default:
361 if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
362 return fn(c, a, n, offset);
363 error(Eperm);
364 break;
365 }
366 return 0;
367 }
368
369 Dev archdevtab = {
370 'P',
371 "arch",
372
373 devreset,
374 devinit,
375 devshutdown,
376 archattach,
377 archwalk,
378 archstat,
379 archopen,
380 devcreate,
381 archclose,
382 archread,
383 devbread,
384 archwrite,
385 devbwrite,
386 devremove,
387 devwstat,
388 };
389
390 int
391 pcmspecial(char *idstr, ISAConf *isa)
392 {
393 return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
394 }
395
396 void
397 pcmspecialclose(int a)
398 {
399 if (_pcmspecialclose != nil)
400 _pcmspecialclose(a);
401 }
Cache object: 06f06fb2271867d912921c2e90e71289
|