]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/cis.c
devproc: return process id when reading /proc/n/ctl file
[plan9front.git] / sys / src / 9 / port / cis.c
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 #include "io.h"
8
9 enum{
10         Linktarget = 0x13,
11 };
12         
13 /*
14  *  read and crack the card information structure enough to set
15  *  important parameters like power
16  */
17 /* cis memory walking */
18 typedef struct Cisdat {
19         uchar   *cisbase;
20         int     cispos;
21         int     cisskip;
22         int     cislen;
23 } Cisdat;
24
25 static void     tcfig(PCMslot*, Cisdat*, int);
26 static void     tentry(PCMslot*, Cisdat*, int);
27 static void     tvers1(PCMslot*, Cisdat*, int);
28 static void     tlonglnkmfc(PCMslot*, Cisdat*, int);
29
30 static int
31 readc(Cisdat *cis, uchar *x)
32 {
33         if(cis->cispos >= cis->cislen)
34                 return 0;
35         *x = cis->cisbase[cis->cisskip*cis->cispos];
36         cis->cispos++;
37         return 1;
38 }
39
40 static int
41 xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
42 {
43         PCMmap *m;
44         Cisdat cis;
45         int i, l;
46         uchar *p;
47         uchar type, link, n, c;
48         int this, subtype;
49
50         m = pcmmap(slotno, 0, 0, attr);
51         if(m == 0)
52                 return -1;
53
54         cis.cisbase = KADDR(m->isa);
55         cis.cispos = 0;
56         cis.cisskip = attr ? 2 : 1;
57         cis.cislen = m->len;
58
59         /* loop through all the tuples */
60         for(i = 0; i < 1000; i++){
61                 this = cis.cispos;
62                 if(readc(&cis, &type) != 1)
63                         break;
64                 if(type == 0xFF)
65                         break;
66                 if(readc(&cis, &link) != 1)
67                         break;
68                 if(link == 0xFF)
69                         break;
70
71                 n = link;
72                 if(link > 1 && subtuple != -1){
73                         if(readc(&cis, &c) != 1)
74                                 break;
75                         subtype = c;
76                         n--;
77                 }else
78                         subtype = -1;
79
80                 if(type == tuple && subtype == subtuple){
81                         p = v;
82                         for(l=0; l<nv && l<n; l++)
83                                 if(readc(&cis, p++) != 1)
84                                         break;
85                         pcmunmap(slotno, m);
86                         return nv;
87                 }
88                 cis.cispos = this + (2+link);
89         }
90         pcmunmap(slotno, m);
91         return -1;
92 }
93
94 int
95 pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
96 {
97         int n;
98
99         /* try attribute space, then memory */
100         if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
101                 return n;
102         return xcistuple(slotno, tuple, subtuple, v, nv, 0);
103 }
104
105 void
106 pcmcisread(PCMslot *pp)
107 {
108         int this;
109         Cisdat cis;
110         PCMmap *m;
111         uchar type, link;
112
113         memset(pp->ctab, 0, sizeof(pp->ctab));
114         pp->ncfg = 0;
115         memset(pp->cfg, 0, sizeof(pp->cfg));
116         pp->configed = 0;
117         pp->nctab = 0;
118         pp->verstr[0] = 0;
119
120         /*
121          * Read all tuples in attribute space.
122          */
123         m = pcmmap(pp->slotno, 0, 0, 1);
124         if(m == 0)
125                 return;
126
127         cis.cisbase = KADDR(m->isa);
128         cis.cispos = 0;
129         cis.cisskip = 2;
130         cis.cislen = m->len;
131
132         /* loop through all the tuples */
133         for(;;){
134                 this = cis.cispos;
135                 if(readc(&cis, &type) != 1)
136                         break;
137                 if(type == 0xFF)
138                         break;
139                 if(readc(&cis, &link) != 1)
140                         break;
141
142                 switch(type){
143                 default:
144                         break;
145                 case 6:
146                         tlonglnkmfc(pp, &cis, type);
147                         break;
148                 case 0x15:
149                         tvers1(pp, &cis, type);
150                         break;
151                 case 0x1A:
152                         tcfig(pp, &cis, type);
153                         break;
154                 case 0x1B:
155                         tentry(pp, &cis, type);
156                         break;
157                 }
158
159                 if(link == 0xFF)
160                         break;
161                 cis.cispos = this + (2+link);
162         }
163         pcmunmap(pp->slotno, m);
164 }
165
166 static ulong
167 getlong(Cisdat *cis, int size)
168 {
169         uchar c;
170         int i;
171         ulong x;
172
173         x = 0;
174         for(i = 0; i < size; i++){
175                 if(readc(cis, &c) != 1)
176                         break;
177                 x |= c<<(i*8);
178         }
179         return x;
180 }
181
182 static void
183 tcfig(PCMslot *pp, Cisdat *cis, int )
184 {
185         uchar size, rasize, rmsize;
186         uchar last;
187
188         if(readc(cis, &size) != 1)
189                 return;
190         rasize = (size&0x3) + 1;
191         rmsize = ((size>>2)&0xf) + 1;
192         if(readc(cis, &last) != 1)
193                 return;
194
195         if(pp->ncfg >= 8){
196                 print("tcfig: too many configuration registers\n");
197                 return;
198         }
199         
200         pp->cfg[pp->ncfg].caddr = getlong(cis, rasize);
201         pp->cfg[pp->ncfg].cpresent = getlong(cis, rmsize);
202         pp->ncfg++;
203 }
204
205 static ulong vexp[8] =
206 {
207         1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
208 };
209 static ulong vmant[16] =
210 {
211         10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
212 };
213
214 static ulong
215 microvolt(Cisdat *cis)
216 {
217         uchar c;
218         ulong microvolts;
219         ulong exp;
220
221         if(readc(cis, &c) != 1)
222                 return 0;
223         exp = vexp[c&0x7];
224         microvolts = vmant[(c>>3)&0xf]*exp;
225         while(c & 0x80){
226                 if(readc(cis, &c) != 1)
227                         return 0;
228                 switch(c){
229                 case 0x7d:
230                         break;          /* high impedence when sleeping */
231                 case 0x7e:
232                 case 0x7f:
233                         microvolts = 0; /* no connection */
234                         break;
235                 default:
236                         exp /= 10;
237                         microvolts += exp*(c&0x7f);
238                 }
239         }
240         return microvolts;
241 }
242
243 static ulong
244 nanoamps(Cisdat *cis)
245 {
246         uchar c;
247         ulong nanoamps;
248
249         if(readc(cis, &c) != 1)
250                 return 0;
251         nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
252         while(c & 0x80){
253                 if(readc(cis, &c) != 1)
254                         return 0;
255                 if(c == 0x7d || c == 0x7e || c == 0x7f)
256                         nanoamps = 0;
257         }
258         return nanoamps;
259 }
260
261 /*
262  * only nominal voltage (feature 1) is important for config,
263  * other features must read card to stay in sync.
264  */
265 static ulong
266 power(Cisdat *cis)
267 {
268         uchar feature;
269         ulong mv;
270
271         mv = 0;
272         if(readc(cis, &feature) != 1)
273                 return 0;
274         if(feature & 1)
275                 mv = microvolt(cis);
276         if(feature & 2)
277                 microvolt(cis);
278         if(feature & 4)
279                 microvolt(cis);
280         if(feature & 8)
281                 nanoamps(cis);
282         if(feature & 0x10)
283                 nanoamps(cis);
284         if(feature & 0x20)
285                 nanoamps(cis);
286         if(feature & 0x40)
287                 nanoamps(cis);
288         return mv/1000000;
289 }
290
291 static ulong mantissa[16] =
292 { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };
293
294 static ulong exponent[8] =
295 { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };
296
297 static ulong
298 ttiming(Cisdat *cis, int scale)
299 {
300         uchar unscaled;
301         ulong nanosecs;
302
303         if(readc(cis, &unscaled) != 1)
304                 return 0;
305         nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
306         nanosecs = nanosecs * vexp[scale];
307         return nanosecs;
308 }
309
310 static void
311 timing(Cisdat *cis, PCMconftab *ct)
312 {
313         uchar c, i;
314
315         if(readc(cis, &c) != 1)
316                 return;
317         i = c&0x3;
318         if(i != 3)
319                 ct->maxwait = ttiming(cis, i);          /* max wait */
320         i = (c>>2)&0x7;
321         if(i != 7)
322                 ct->readywait = ttiming(cis, i);                /* max ready/busy wait */
323         i = (c>>5)&0x7;
324         if(i != 7)
325                 ct->otherwait = ttiming(cis, i);                /* reserved wait */
326 }
327
328 static void
329 iospaces(Cisdat *cis, PCMconftab *ct)
330 {
331         uchar c;
332         int i, nio;
333
334         ct->nio = 0;
335         if(readc(cis, &c) != 1)
336                 return;
337
338         ct->bit16 = ((c>>5)&3) >= 2;
339         if(!(c & 0x80)){
340                 ct->io[0].start = 0;
341                 ct->io[0].len = 1<<(c&0x1f);
342                 ct->nio = 1;
343                 return;
344         }
345
346         if(readc(cis, &c) != 1)
347                 return;
348
349         /*
350          * For each of the range descriptions read the
351          * start address and the length (value is length-1).
352          */
353         nio = (c&0xf)+1;
354         for(i = 0; i < nio; i++){
355                 ct->io[i].start = getlong(cis, (c>>4)&0x3);
356                 ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
357         }
358         ct->nio = nio;
359 }
360
361 static void
362 irq(Cisdat *cis, PCMconftab *ct)
363 {
364         uchar c;
365
366         if(readc(cis, &c) != 1)
367                 return;
368         ct->irqtype = c & 0xe0;
369         if(c & 0x10)
370                 ct->irqs = getlong(cis, 2);
371         else
372                 ct->irqs = 1<<(c&0xf);
373         ct->irqs &= 0xDEB8;             /* levels available to card */
374 }
375
376 static void
377 memspace(Cisdat *cis, int asize, int lsize, int host)
378 {
379         ulong haddress, address, len;
380
381         len = getlong(cis, lsize)*256;
382         address = getlong(cis, asize)*256;
383         USED(len, address);
384         if(host){
385                 haddress = getlong(cis, asize)*256;
386                 USED(haddress);
387         }
388 }
389
390 static void
391 tentry(PCMslot *pp, Cisdat *cis, int )
392 {
393         uchar c, i, feature;
394         PCMconftab *ct;
395
396         if(pp->nctab >= nelem(pp->ctab))
397                 return;
398         if(readc(cis, &c) != 1)
399                 return;
400         ct = &pp->ctab[pp->nctab++];
401
402         /* copy from last default config */
403         if(pp->def)
404                 *ct = *pp->def;
405
406         ct->index = c & 0x3f;
407
408         /* is this the new default? */
409         if(c & 0x40)
410                 pp->def = ct;
411
412         /* memory wait specified? */
413         if(c & 0x80){
414                 if(readc(cis, &i) != 1)
415                         return;
416                 if(i&0x80)
417                         ct->memwait = 1;
418         }
419
420         if(readc(cis, &feature) != 1)
421                 return;
422         switch(feature&0x3){
423         case 1:
424                 ct->vpp1 = ct->vpp2 = power(cis);
425                 break;
426         case 2:
427                 power(cis);
428                 ct->vpp1 = ct->vpp2 = power(cis);
429                 break;
430         case 3:
431                 power(cis);
432                 ct->vpp1 = power(cis);
433                 ct->vpp2 = power(cis);
434                 break;
435         default:
436                 break;
437         }
438         if(feature&0x4)
439                 timing(cis, ct);
440         if(feature&0x8)
441                 iospaces(cis, ct);
442         if(feature&0x10)
443                 irq(cis, ct);
444         switch((feature>>5)&0x3){
445         case 1:
446                 memspace(cis, 0, 2, 0);
447                 break;
448         case 2:
449                 memspace(cis, 2, 2, 0);
450                 break;
451         case 3:
452                 if(readc(cis, &c) != 1)
453                         return;
454                 for(i = 0; i <= (c&0x7); i++)
455                         memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
456                 break;
457         }
458         pp->configed++;
459 }
460
461 static void
462 tvers1(PCMslot *pp, Cisdat *cis, int )
463 {
464         uchar c, major, minor, last;
465         int  i;
466
467         if(readc(cis, &major) != 1)
468                 return;
469         if(readc(cis, &minor) != 1)
470                 return;
471         last = 0;
472         for(i = 0; i < sizeof(pp->verstr)-1; i++){
473                 if(readc(cis, &c) != 1)
474                         return;
475                 if(c == 0)
476                         c = ';';
477                 if(c == '\n')
478                         c = ';';
479                 if(c == 0xff)
480                         break;
481                 if(c == ';' && last == ';')
482                         continue;
483                 pp->verstr[i] = c;
484                 last = c;
485         }
486         pp->verstr[i] = 0;
487 }
488
489 static void
490 tlonglnkmfc(PCMslot *pp, Cisdat *cis, int)
491 {
492         int i, npos, opos;
493         uchar nfn, space, expect, type, this, link;
494
495         readc(cis, &nfn);
496         for(i = 0; i < nfn; i++){
497                 readc(cis, &space);
498                 npos        = getlong(cis, 4);
499                 opos        = cis->cispos;
500                 cis->cispos = npos;
501                 expect      = Linktarget;
502
503                 while(1){
504                         this = cis->cispos;
505                         if(readc(cis, &type) != 1)
506                                 break;
507                         if(type == 0xFF)
508                                 break;
509                         if(readc(cis, &link) != 1)
510                                 break;
511
512                         if(expect && expect != type){
513                                 print("tlonglnkmfc: expected %X found %X\n",
514                                         expect, type);
515                                 break;
516                         }
517                         expect = 0;
518
519                         switch(type){
520                         default:
521                                 break;
522                         case 0x15:
523                                 tvers1(pp, cis, type);
524                                 break;
525                         case 0x1A:
526                                 tcfig(pp, cis, type);
527                                 break;
528                         case 0x1B:
529                                 tentry(pp, cis, type);
530                                 break;
531                         }
532
533                         if(link == 0xFF)
534                                 break;
535                         cis->cispos = this + (2+link);
536                 }
537                 cis->cispos = opos;
538         }
539 }