2 * ISA PNP 1.0 support + access to PCI configuration space
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?
12 #include "../port/lib.h"
17 #include "../port/error.h"
19 typedef struct Pnp Pnp;
20 typedef struct Card Card;
42 #define DPRINT if(pnp.debug) print
43 #define XPRINT if(1) print
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))
65 static Dirtab topdir[] = {
66 ".", { Qtopdir, 0, QTDIR }, 0, 0555,
67 "pnp", { Qpnpdir, 0, QTDIR }, 0, 0555,
68 "pci", { Qpcidir, 0, QTDIR }, 0, 0555,
71 static Dirtab pnpdir[] = {
72 ".", { Qpnpdir, 0, QTDIR }, 0, 0555,
73 "ctl", { Qpnpctl, 0, 0 }, 0, 0666,
77 static int wrconfig(Card*, char*);
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,
94 /* Send initiation key, putting each card in Sleep state */
100 /* ensure each card's LFSR is reset */
104 /* send initiation key */
105 for (i = 0; i < 32; i++)
106 outb(Address, key[i]);
109 /* isolation protocol... */
118 return (r1 == 0x55) && (r2 == 0xaa);
122 isolate(int rddata, ulong *id1, ulong *id2)
127 outb(Address, 0x01); /* point to serial isolation register */
130 for(i = 0; i < 64; i++){
131 bit = readbit(rddata);
132 csum = (csum>>1) | (((csum&1) ^ ((csum>>1)&1) ^ bit)<<7);
134 *p = (*p>>1) | (bit<<7);
138 *p = (*p>>1) | (readbit(rddata)<<7);
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];
145 DPRINT("pnp: bad checksum id1 %lux id2 %lux csum %x != %x\n", *id1, *id2, csum, id[8]); /**/
146 return id[8] == csum;
150 getresbyte(int rddata)
155 while ((inb(rddata) & 1) == 0)
156 if (tries++ > 1000000)
157 error("pnp: timeout waiting for resource data\n");
163 serial(ulong id1, ulong id2)
170 i2 = ((id1<<3)&24)+((id1>>13)&7);
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);
176 snprint(buf, sizeof(buf), "%.4lux%.4lux.%lux", (id1<<8)&0xff00|(id1>>8)&0x00ff, x, id2);
181 findcsn(int csn, int create, int dolock)
188 for(c = *l; c != nil; c = *l) {
196 if((nc = malloc(sizeof(Card))) == nil)
197 panic("pnp: no memory for Card");
216 for(c = pnp.cards; c != nil; c = c->next) {
227 int i, n, x, ncfg, n1, n2;
231 x = getresbyte(rddata);
232 if((x & 0x80) == 0) {
234 for(i = 1; i < n; i++)
238 n1 = getresbyte(rddata);
239 n2 = getresbyte(rddata);
241 for (i = 3; i < n; i++)
251 /* look for cards, and assign them CSNs */
253 pnpscan(int rddata, int dawn)
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 */
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)
271 c = findcsn(csn, 1, 0);
275 else if(c->cfgstr != nil) {
276 if(!wrconfig(c, c->cfgstr))
277 print("pnp%d: bad cfg: %s\n", c->csn, c->cfgstr);
280 cmd(0x06, c->csn); /* set the card's csn */
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 */
286 cmd(0x02, 0x02); /* return cards to Wait for Key state */
299 int csn, i1, i2, i3, x;
300 char *s, *p, buf[20];
303 memset(&isa, 0, sizeof(ISAConf));
305 if (isaconfig("pnp", 0, &isa) == 0)
307 if(isa.port < 0x203 || isa.port > 0x3ff)
309 for(csn = 1; csn < 256; csn++) {
310 snprint(buf, sizeof buf, "pnp%d", csn);
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') {
316 print("pnp%d: bad conf string %s\n", csn, s);
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);
331 c = findcsn(csn, 1, 0);
336 pnpscan(isa.port, 1);
340 csngen(Chan *c, int t, int csn, Card *cp, Dir *dp)
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);
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);
360 pcigen(Chan *c, int t, int tbdf, Dir *dp)
364 q = (Qid){BUSBDF(tbdf)|t, 0, 0};
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);
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);
381 pnpgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
388 switch(TYPE(c->qid)){
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);
396 return devgen(c, nil, topdir, nelem(topdir), s, dp);
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);
404 if(s < nelem(pnpdir)-1)
405 return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);
406 s -= nelem(pnpdir)-1;
409 while(s >= 2 && cp != nil) {
416 return csngen(c, s+Qcsnctl, cp->csn, cp, dp);
418 return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);
422 cp = findcsn(csn, 0, 1);
425 return csngen(c, TYPE(c->qid), csn, cp, dp);
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);
433 p = pcimatch(nil, 0, 0);
434 while(s >= 2 && p != nil) {
435 p = pcimatch(p, 0, 0);
440 return pcigen(c, s+Qpcictl, p->tbdf, dp);
443 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
444 p = pcimatchtbdf(tbdf);
447 return pcigen(c, TYPE(c->qid), tbdf, dp);
455 pnpattach(char *spec)
457 return devattach(pnpdevtab.dc, spec);
461 pnpwalk(Chan* c, Chan *nc, char** name, int nname)
463 return devwalk(c, nc, name, nname, (Dirtab *)0, 0, pnpgen);
467 pnpstat(Chan* c, uchar* dp, int n)
469 return devstat(c, dp, n, (Dirtab *)0, 0L, pnpgen);
473 pnpopen(Chan *c, int omode)
475 c = devopen(c, omode, (Dirtab*)0, 0, pnpgen);
476 switch(TYPE(c->qid)){
489 pnpread(Chan *c, void *va, long n, vlong offset)
494 char buf[256], *ebuf, *w;
498 switch(TYPE(c->qid)){
502 return devdirread(c, a, n, (Dirtab *)0, 0L, pnpgen);
505 snprint(up->genbuf, sizeof up->genbuf, "enabled %#x\n",
508 snprint(up->genbuf, sizeof up->genbuf, "disabled\n");
509 return readstr(offset, a, n, up->genbuf);
512 cp = findcsn(csn, 0, 1);
515 if(offset+n > cp->ncfg)
516 n = cp->ncfg - offset;
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 */
530 cp = findcsn(csn, 0, 1);
533 snprint(up->genbuf, sizeof up->genbuf, "%s\n",
534 serial(cp->id1, cp->id2));
535 return readstr(offset, a, n, up->genbuf);
537 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
538 p = pcimatchtbdf(tbdf);
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)
547 w = seprint(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size);
551 return readstr(offset, a, n, buf);
553 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
554 p = pcimatchtbdf(tbdf);
562 if(!(r & 3) && n == 4){
567 if(!(r & 1) && n == 2){
572 for(i = 0; i < n; i++){
586 pnpwrite(Chan *c, void *va, long n, vlong offset)
601 switch(TYPE(c->qid)){
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");
613 error("pnp port already set");
614 if(!pnpscan(port, 0))
615 error("no cards found");
619 else if(strncmp(buf, "debug ", 6) == 0)
620 pnp.debug = strtoul(buf+6, 0, 0);
626 cp = findcsn(csn, 0, 1);
629 if(!wrconfig(cp, buf))
633 tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
634 p = pcimatchtbdf(tbdf);
642 if(!(r & 3) && n == 4){
647 if(!(r & 1) && n == 2){
652 for(i = 0; i < n; i++){
666 wrconfig(Card *c, char *cmd)
668 /* This should implement setting of I/O bases, etc */