]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devpnp.c
fix fuckup
[plan9front.git] / sys / src / 9 / port / devpnp.c
1 /*
2  *      ISA PNP 1.0 support + access to PCI configuration space
3  *
4  *      TODO
5  *              - implement PNP card configuration (setting io bases etc)
6  *              - write user program to drive PNP configuration...
7  *              - extend PCI raw access to configuration space (writes, byte/short access?)
8  *              - implement PCI access to memory/io space/BIOS ROM
9  *              - use c->aux instead of performing lookup on each read/write?
10  */
11 #include        "u.h"
12 #include        "../port/lib.h"
13 #include        "mem.h"
14 #include        "dat.h"
15 #include        "fns.h"
16 #include        "io.h"
17 #include        "../port/error.h"
18
19 typedef struct Pnp Pnp;
20 typedef struct Card Card;
21
22 struct Pnp
23 {
24         QLock;
25         int             rddata;
26         int             debug;
27         Card            *cards;
28 };
29
30 struct Card
31 {
32         int             csn;
33         ulong   id1;
34         ulong   id2;
35         char            *cfgstr;
36         int             ncfg;
37         Card*   next;
38 };
39
40 static Pnp      pnp;
41
42 #define DPRINT  if(pnp.debug) print
43 #define XPRINT  if(1) print
44
45 enum {
46         Address = 0x279,
47         WriteData = 0xa79,
48
49         Qtopdir = 0,
50
51         Qpnpdir,
52         Qpnpctl,
53         Qcsnctl,
54         Qcsnraw,
55
56         Qpcidir,
57         Qpcictl,
58         Qpciraw,
59 };
60
61 #define TYPE(q)         ((ulong)(q).path & 0x0F)
62 #define CSN(q)          (((ulong)(q).path>>4) & 0xFF)
63 #define QID(c, t)       (((c)<<4)|(t))
64
65 static Dirtab topdir[] = {
66         ".",    { Qtopdir, 0, QTDIR },  0,      0555,
67         "pnp",  { Qpnpdir, 0, QTDIR },  0,      0555,
68         "pci",  { Qpcidir, 0, QTDIR },  0,      0555,
69 };
70
71 static Dirtab pnpdir[] = {
72         ".",    { Qpnpdir, 0, QTDIR },  0,      0555,
73         "ctl",  { Qpnpctl, 0, 0 },      0,      0666,
74 };
75
76 extern Dev pnpdevtab;
77 static int wrconfig(Card*, char*);
78
79 static char key[32] =
80 {
81         0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
82         0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
83         0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
84         0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39,
85 };
86
87 static void
88 cmd(int reg, int val)
89 {
90         outb(Address, reg);
91         outb(WriteData, val);
92 }
93
94 /* Send initiation key, putting each card in Sleep state */
95 static void
96 initiation(void)
97 {
98         int i;
99
100         /* ensure each card's LFSR is reset */
101         outb(Address, 0x00);
102         outb(Address, 0x00);
103
104         /* send initiation key */
105         for (i = 0; i < 32; i++)
106                 outb(Address, key[i]);
107 }
108
109 /* isolation protocol... */
110 static int
111 readbit(int rddata)
112 {
113         int r1, r2;
114
115         r1 = inb(rddata);
116         r2 = inb(rddata);
117         microdelay(250);
118         return (r1 == 0x55) && (r2 == 0xaa);
119 }
120
121 static int
122 isolate(int rddata, ulong *id1, ulong *id2)
123 {
124         int i, csum, bit;
125         uchar *p, id[9];
126
127         outb(Address, 0x01);    /* point to serial isolation register */
128         delay(1);
129         csum = 0x6a;
130         for(i = 0; i < 64; i++){
131                 bit = readbit(rddata);
132                 csum = (csum>>1) | (((csum&1) ^ ((csum>>1)&1) ^ bit)<<7);
133                 p = &id[i>>3];
134                 *p = (*p>>1) | (bit<<7);
135         }
136         for(; i < 72; i++){
137                 p = &id[i>>3];
138                 *p = (*p>>1) | (readbit(rddata)<<7);
139         }
140         *id1 = (id[3]<<24)|(id[2]<<16)|(id[1]<<8)|id[0];
141         *id2 = (id[7]<<24)|(id[6]<<16)|(id[5]<<8)|id[4];
142         if(*id1 == 0)
143                 return 0;
144         if(id[8] != csum)
145                 DPRINT("pnp: bad checksum id1 %lux id2 %lux csum %x != %x\n", *id1, *id2, csum, id[8]); /**/
146         return id[8] == csum;
147 }
148
149 static int
150 getresbyte(int rddata)
151 {
152         int tries = 0;
153
154         outb(Address, 0x05);
155         while ((inb(rddata) & 1) == 0)
156                 if (tries++ > 1000000)
157                         error("pnp: timeout waiting for resource data\n");
158         outb(Address, 0x04);
159         return inb(rddata);
160 }
161
162 static char *
163 serial(ulong id1, ulong id2)
164 {
165         int i1, i2, i3;
166         ulong x;
167         static char buf[20];
168
169         i1 = (id1>>2)&31;
170         i2 = ((id1<<3)&24)+((id1>>13)&7);
171         i3 = (id1>>8)&31;
172         x = (id1>>8)&0xff00|(id1>>24)&0x00ff;
173         if (i1 > 0 && i1 < 27 && i2 > 0 && i2 < 27 && i3 > 0 && i3 < 27 && (id1 & (1<<7)) == 0)
174                 snprint(buf, sizeof(buf), "%c%c%c%.4lux.%lux", 'A'+i1-1, 'A'+i2-1, 'A'+i3-1, x, id2);
175         else
176                 snprint(buf, sizeof(buf), "%.4lux%.4lux.%lux", (id1<<8)&0xff00|(id1>>8)&0x00ff, x, id2);
177         return buf;
178 }
179
180 static Card *
181 findcsn(int csn, int create, int dolock)
182 {
183         Card *c, *nc, **l;
184
185         if(dolock)
186                 qlock(&pnp);
187         l = &pnp.cards;
188         for(c = *l; c != nil; c = *l) {
189                 if(c->csn == csn)
190                         goto done;
191                 if(c->csn > csn)
192                         break;
193                 l = &c->next;
194         }
195         if(create) {
196                 if((nc = malloc(sizeof(Card))) == nil)
197                         panic("pnp: no memory for Card");
198                 *l = nc;
199                 nc->next = c;
200                 nc->csn = csn;
201                 c = nc;
202         }
203 done:
204         if(dolock)
205                 qunlock(&pnp);
206         return c;
207 }
208
209 static int
210 newcsn(void)
211 {
212         int csn;
213         Card *c;
214
215         csn = 1;
216         for(c = pnp.cards; c != nil; c = c->next) {
217                 if(c->csn > csn)
218                         break;
219                 csn = c->csn+1;
220         }
221         return csn;
222 }
223
224 static int
225 pnpncfg(int rddata)
226 {
227         int i, n, x, ncfg, n1, n2;
228
229         ncfg = 0;
230         for (;;) {
231                 x = getresbyte(rddata);
232                 if((x & 0x80) == 0) {
233                         n = (x&7)+1;
234                         for(i = 1; i < n; i++)
235                                 getresbyte(rddata);
236                 }
237                 else {
238                         n1 = getresbyte(rddata);
239                         n2 = getresbyte(rddata);
240                         n = (n2<<8)|n1 + 3;
241                         for (i = 3; i < n; i++)
242                                 getresbyte(rddata);
243                 }
244                 ncfg += n;
245                 if((x>>3) == 0x0f)
246                         break;
247         }
248         return ncfg;
249 }
250
251 /* look for cards, and assign them CSNs */
252 static int
253 pnpscan(int rddata, int dawn)
254 {
255         Card *c;
256         int csn;
257         ulong id1, id2;
258
259         initiation();                           /* upsilon sigma */
260         cmd(0x02, 0x04+0x01);           /* reset CSN on all cards and reset logical devices */
261         delay(1);                                       /* delay after resetting cards */
262
263         cmd(0x03, 0);                           /* Wake all cards with a CSN of 0 */
264         cmd(0x00, rddata>>2);           /* Set the READ_DATA port on all cards */
265         while(isolate(rddata, &id1, &id2)) {
266                 for(c = pnp.cards; c != nil; c = c->next)
267                         if(c->id1 == id1 && c->id2 == id2)
268                                 break;
269                 if(c == nil) {
270                         csn = newcsn();
271                         c = findcsn(csn, 1, 0);
272                         c->id1 = id1;
273                         c->id2 = id2;
274                 }
275                 else if(c->cfgstr != nil) {
276                         if(!wrconfig(c, c->cfgstr))
277                                 print("pnp%d: bad cfg: %s\n", c->csn, c->cfgstr);
278                         c->cfgstr = nil;
279                 }
280                 cmd(0x06, c->csn);              /* set the card's csn */
281                 if(dawn)
282                         print("pnp%d: %s\n", c->csn, serial(id1, id2));
283                 c->ncfg = pnpncfg(rddata);
284                 cmd(0x03, 0);           /* Wake all cards with a CSN of 0, putting this card to sleep */
285         }
286         cmd(0x02, 0x02);                        /* return cards to Wait for Key state */
287         if(pnp.cards != 0) {
288                 pnp.rddata = rddata;
289                 return 1;
290         }
291         return 0;
292 }
293
294 static void
295 pnpreset(void)
296 {
297         Card *c;
298         ulong id1, id2;
299         int csn, i1, i2, i3, x;
300         char *s, *p, buf[20];
301         ISAConf isa;
302
303         memset(&isa, 0, sizeof(ISAConf));
304         pnp.rddata = -1;
305         if (isaconfig("pnp", 0, &isa) == 0)
306                 return;
307         if(isa.port < 0x203 || isa.port > 0x3ff)
308                 return;
309         for(csn = 1; csn < 256; csn++) {
310                 snprint(buf, sizeof buf, "pnp%d", csn);
311                 s = getconf(buf);
312                 if(s == 0)
313                         continue;
314                 if(strlen(s) < 8 || s[7] != '.' || s[0] < 'A' || s[0] > 'Z' || s[1] < 'A' || s[1] > 'Z' || s[2] < 'A' || s[2] > 'Z') {
315 bad:
316                         print("pnp%d: bad conf string %s\n", csn, s);
317                         continue;       
318                 }
319                 i1 = s[0]-'A'+1;
320                 i2 = s[1]-'A'+1;
321                 i3 = s[2]-'A'+1;
322                 x = strtoul(&s[3], 0, 16);
323                 id1 = (i1<<2)|((i2>>3)&3)|((i2&7)<<13)|(i3<<8)|((x&0xff)<<24)|((x&0xff00)<<8);
324                 id2 = strtoul(&s[8], &p, 16);
325                 if(*p == ' ')
326                         p++;
327                 else if(*p == '\0')
328                         p = nil;
329                 else
330                         goto bad;
331                 c = findcsn(csn, 1, 0);
332                 c->id1 = id1;
333                 c->id2 = id2;
334                 c->cfgstr = p;
335         }
336         pnpscan(isa.port, 1);
337 }
338
339 static int
340 csngen(Chan *c, int t, int csn, Card *cp, Dir *dp)
341 {
342         Qid q;
343
344         switch(t) {
345         case Qcsnctl:
346                 q = (Qid){QID(csn, Qcsnctl), 0, 0};
347                 snprint(up->genbuf, sizeof up->genbuf, "csn%dctl", csn);
348                 devdir(c, q, up->genbuf, 0, eve, 0664, dp);
349                 return 1;
350         case Qcsnraw:
351                 q = (Qid){QID(csn, Qcsnraw), 0, 0};
352                 snprint(up->genbuf, sizeof up->genbuf, "csn%draw", csn);
353                 devdir(c, q, up->genbuf, cp->ncfg, eve, 0444, dp);
354                 return 1;
355         }
356         return -1;
357 }
358
359 static int
360 pcigen(Chan *c, int t, int tbdf, Dir *dp)
361 {
362         Qid q;
363
364         q = (Qid){BUSBDF(tbdf)|t, 0, 0};
365         switch(t) {
366         case Qpcictl:
367                 snprint(up->genbuf, sizeof up->genbuf, "%d.%d.%dctl",
368                         BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
369                 devdir(c, q, up->genbuf, 0, eve, 0444, dp);
370                 return 1;
371         case Qpciraw:
372                 snprint(up->genbuf, sizeof up->genbuf, "%d.%d.%draw",
373                         BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
374                 devdir(c, q, up->genbuf, 128, eve, 0660, dp);
375                 return 1;
376         }
377         return -1;
378 }
379
380 static int
381 pnpgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
382 {
383         Qid q;
384         Card *cp;
385         Pcidev *p;
386         int csn, tbdf;
387
388         switch(TYPE(c->qid)){
389         case Qtopdir:
390                 if(s == DEVDOTDOT){
391                         q = (Qid){QID(0, Qtopdir), 0, QTDIR};
392                         snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
393                         devdir(c, q, up->genbuf, 0, eve, 0555, dp);
394                         return 1;
395                 }
396                 return devgen(c, nil, topdir, nelem(topdir), s, dp);
397         case Qpnpdir:
398                 if(s == DEVDOTDOT){
399                         q = (Qid){QID(0, Qtopdir), 0, QTDIR};
400                         snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
401                         devdir(c, q, up->genbuf, 0, eve, 0555, dp);
402                         return 1;
403                 }
404                 if(s < nelem(pnpdir)-1)
405                         return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);
406                 s -= nelem(pnpdir)-1;
407                 qlock(&pnp);
408                 cp = pnp.cards;
409                 while(s >= 2 && cp != nil) {
410                         s -= 2;
411                         cp = cp->next;
412                 }
413                 qunlock(&pnp);
414                 if(cp == nil)
415                         return -1;
416                 return csngen(c, s+Qcsnctl, cp->csn, cp, dp);
417         case Qpnpctl:
418                 return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);
419         case Qcsnctl:
420         case Qcsnraw:
421                 csn = CSN(c->qid);
422                 cp = findcsn(csn, 0, 1);
423                 if(cp == nil)
424                         return -1;
425                 return csngen(c, TYPE(c->qid), csn, cp, dp);
426         case Qpcidir:
427                 if(s == DEVDOTDOT){
428                         q = (Qid){QID(0, Qtopdir), 0, QTDIR};
429                         snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
430                         devdir(c, q, up->genbuf, 0, eve, 0555, dp);
431                         return 1;
432                 }
433                 p = pcimatch(nil, 0, 0);
434                 while(s >= 2 && p != nil) {
435                         p = pcimatch(p, 0, 0);
436                         s -= 2;
437                 }
438                 if(p == nil)
439                         return -1;
440                 return pcigen(c, s+Qpcictl, p->tbdf, dp);
441         case Qpcictl:
442         case Qpciraw:
443                 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
444                 p = pcimatchtbdf(tbdf);
445                 if(p == nil)
446                         return -1;
447                 return pcigen(c, TYPE(c->qid), tbdf, dp);
448         default:
449                 break;
450         }
451         return -1;
452 }
453
454 static Chan*
455 pnpattach(char *spec)
456 {
457         return devattach(pnpdevtab.dc, spec);
458 }
459
460 Walkqid*
461 pnpwalk(Chan* c, Chan *nc, char** name, int nname)
462 {
463         return devwalk(c, nc, name, nname, (Dirtab *)0, 0, pnpgen);
464 }
465
466 static int
467 pnpstat(Chan* c, uchar* dp, int n)
468 {
469         return devstat(c, dp, n, (Dirtab *)0, 0L, pnpgen);
470 }
471
472 static Chan*
473 pnpopen(Chan *c, int omode)
474 {
475         c = devopen(c, omode, (Dirtab*)0, 0, pnpgen);
476         switch(TYPE(c->qid)){
477         default:
478                 break;
479         }
480         return c;
481 }
482
483 static void
484 pnpclose(Chan*)
485 {
486 }
487
488 static long
489 pnpread(Chan *c, void *va, long n, vlong offset)
490 {
491         ulong x;
492         Card *cp;
493         Pcidev *p;
494         char buf[256], *ebuf, *w;
495         char *a = va;
496         int csn, i, tbdf, r;
497
498         switch(TYPE(c->qid)){
499         case Qtopdir:
500         case Qpnpdir:
501         case Qpcidir:
502                 return devdirread(c, a, n, (Dirtab *)0, 0L, pnpgen);
503         case Qpnpctl:
504                 if(pnp.rddata > 0)
505                         snprint(up->genbuf, sizeof up->genbuf, "enabled %#x\n",
506                                 pnp.rddata);
507                 else
508                         snprint(up->genbuf, sizeof up->genbuf, "disabled\n");
509                 return readstr(offset, a, n, up->genbuf);
510         case Qcsnraw:
511                 csn = CSN(c->qid);
512                 cp = findcsn(csn, 0, 1);
513                 if(cp == nil)
514                         error(Egreg);
515                 if(offset+n > cp->ncfg)
516                         n = cp->ncfg - offset;
517                 qlock(&pnp);
518                 initiation();
519                 cmd(0x03, csn);                         /* Wake up the card */
520                 for(i = 0; i < offset+9; i++)           /* 9 == skip serial + csum */
521                         getresbyte(pnp.rddata);
522                 for(i = 0; i < n; i++)
523                         a[i] = getresbyte(pnp.rddata);
524                 cmd(0x03, 0);                                   /* Wake all cards with a CSN of 0, putting this card to sleep */
525                 cmd(0x02, 0x02);                                /* return cards to Wait for Key state */
526                 qunlock(&pnp);
527                 break;
528         case Qcsnctl:
529                 csn = CSN(c->qid);
530                 cp = findcsn(csn, 0, 1);
531                 if(cp == nil)
532                         error(Egreg);
533                 snprint(up->genbuf, sizeof up->genbuf, "%s\n",
534                         serial(cp->id1, cp->id2));
535                 return readstr(offset, a, n, up->genbuf);
536         case Qpcictl:
537                 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
538                 p = pcimatchtbdf(tbdf);
539                 if(p == nil)
540                         error(Egreg);
541                 ebuf = buf+sizeof buf-1;        /* -1 for newline */
542                 w = seprint(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d",
543                         p->ccrb, p->ccru, p->ccrp, p->vid, p->did, p->intl);
544                 for(i=0; i<nelem(p->mem); i++){
545                         if(p->mem[i].size == 0)
546                                 continue;
547                         w = seprint(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size);
548                 }
549                 *w++ = '\n';
550                 *w = '\0';
551                 return readstr(offset, a, n, buf);
552         case Qpciraw:
553                 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
554                 p = pcimatchtbdf(tbdf);
555                 if(p == nil)
556                         error(Egreg);
557                 if(offset > 256)
558                         return 0;
559                 if(n+offset > 256)
560                         n = 256-offset;
561                 r = offset;
562                 if(!(r & 3) && n == 4){
563                         x = pcicfgr32(p, r);
564                         PBIT32(a, x);
565                         return 4;
566                 }
567                 if(!(r & 1) && n == 2){
568                         x = pcicfgr16(p, r);
569                         PBIT16(a, x);
570                         return 2;
571                 }
572                 for(i = 0; i <  n; i++){
573                         x = pcicfgr8(p, r);
574                         PBIT8(a, x);
575                         a++;
576                         r++;
577                 }
578                 return i;
579         default:
580                 error(Egreg);
581         }
582         return n;
583 }
584
585 static long
586 pnpwrite(Chan *c, void *va, long n, vlong offset)
587 {
588         Card *cp;
589         Pcidev *p;
590         ulong port, x;
591         char buf[256];
592         uchar *a;
593         int csn, i, r, tbdf;
594
595         if(n >= sizeof(buf))
596                 n = sizeof(buf)-1;
597         a = va;
598         strncpy(buf, va, n);
599         buf[n] = 0;
600
601         switch(TYPE(c->qid)){
602         case Qpnpctl:
603                 if(strncmp(buf, "port ", 5) == 0) {
604                         port = strtoul(buf+5, 0, 0);
605                         if(port < 0x203 || port > 0x3ff)
606                                 error("bad value for rddata port");
607                         qlock(&pnp);
608                         if(waserror()) {
609                                 qunlock(&pnp);
610                                 nexterror();
611                         }
612                         if(pnp.rddata > 0)
613                                 error("pnp port already set");
614                         if(!pnpscan(port, 0))
615                                 error("no cards found");
616                         qunlock(&pnp);
617                         poperror();
618                 }
619                 else if(strncmp(buf, "debug ", 6) == 0)
620                         pnp.debug = strtoul(buf+6, 0, 0);
621                 else
622                         error(Ebadctl);
623                 break;
624         case Qcsnctl:
625                 csn = CSN(c->qid);
626                 cp = findcsn(csn, 0, 1);
627                 if(cp == nil)
628                         error(Egreg);
629                 if(!wrconfig(cp, buf))
630                         error(Ebadctl);
631                 break;
632         case Qpciraw:
633                 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
634                 p = pcimatchtbdf(tbdf);
635                 if(p == nil)
636                         error(Egreg);
637                 if(offset > 256)
638                         return 0;
639                 if(n+offset > 256)
640                         n = 256-offset;
641                 r = offset;
642                 if(!(r & 3) && n == 4){
643                         x = GBIT32(a);
644                         pcicfgw32(p, r, x);
645                         return 4;
646                 }
647                 if(!(r & 1) && n == 2){
648                         x = GBIT16(a);
649                         pcicfgw16(p, r, x);
650                         return 2;
651                 }
652                 for(i = 0; i <  n; i++){
653                         x = GBIT8(a);
654                         pcicfgw8(p, r, x);
655                         a++;
656                         r++;
657                 }
658                 return i;
659         default:
660                 error(Egreg);
661         }
662         return n;
663 }
664
665 static int
666 wrconfig(Card *c, char *cmd)
667 {
668         /* This should implement setting of I/O bases, etc */
669         USED(c, cmd);
670         return 1;
671 }
672
673
674 Dev pnpdevtab = {
675         '$',
676         "pnp",
677
678         pnpreset,
679         devinit,
680         devshutdown,
681         pnpattach,
682         pnpwalk,
683         pnpstat,
684         pnpopen,
685         devcreate,
686         pnpclose,
687         pnpread,
688         devbread,
689         pnpwrite,
690         devbwrite,
691         devremove,
692         devwstat,
693 };