19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier * ISA PNP 1.0 support + access to PCI configuration space
39a747e4fSDavid du Colombier *
49a747e4fSDavid du Colombier * TODO
59a747e4fSDavid du Colombier * - implement PNP card configuration (setting io bases etc)
69a747e4fSDavid du Colombier * - write user program to drive PNP configuration...
79a747e4fSDavid du Colombier * - extend PCI raw access to configuration space (writes, byte/short access?)
89a747e4fSDavid du Colombier * - implement PCI access to memory/io space/BIOS ROM
99a747e4fSDavid du Colombier * - use c->aux instead of performing lookup on each read/write?
109a747e4fSDavid du Colombier */
119a747e4fSDavid du Colombier #include "u.h"
129a747e4fSDavid du Colombier #include "../port/lib.h"
139a747e4fSDavid du Colombier #include "mem.h"
149a747e4fSDavid du Colombier #include "dat.h"
159a747e4fSDavid du Colombier #include "fns.h"
169a747e4fSDavid du Colombier #include "io.h"
179a747e4fSDavid du Colombier #include "../port/error.h"
189a747e4fSDavid du Colombier
199a747e4fSDavid du Colombier typedef struct Pnp Pnp;
209a747e4fSDavid du Colombier typedef struct Card Card;
219a747e4fSDavid du Colombier
229a747e4fSDavid du Colombier struct Pnp
239a747e4fSDavid du Colombier {
249a747e4fSDavid du Colombier QLock;
259a747e4fSDavid du Colombier int rddata;
269a747e4fSDavid du Colombier int debug;
279a747e4fSDavid du Colombier Card *cards;
289a747e4fSDavid du Colombier };
299a747e4fSDavid du Colombier
309a747e4fSDavid du Colombier struct Card
319a747e4fSDavid du Colombier {
329a747e4fSDavid du Colombier int csn;
339a747e4fSDavid du Colombier ulong id1;
349a747e4fSDavid du Colombier ulong id2;
359a747e4fSDavid du Colombier char *cfgstr;
369a747e4fSDavid du Colombier int ncfg;
379a747e4fSDavid du Colombier Card* next;
389a747e4fSDavid du Colombier };
399a747e4fSDavid du Colombier
409a747e4fSDavid du Colombier static Pnp pnp;
419a747e4fSDavid du Colombier
429a747e4fSDavid du Colombier #define DPRINT if(pnp.debug) print
439a747e4fSDavid du Colombier #define XPRINT if(1) print
449a747e4fSDavid du Colombier
459a747e4fSDavid du Colombier enum {
469a747e4fSDavid du Colombier Address = 0x279,
479a747e4fSDavid du Colombier WriteData = 0xa79,
489a747e4fSDavid du Colombier
499a747e4fSDavid du Colombier Qtopdir = 0,
509a747e4fSDavid du Colombier
519a747e4fSDavid du Colombier Qpnpdir,
529a747e4fSDavid du Colombier Qpnpctl,
539a747e4fSDavid du Colombier Qcsnctl,
549a747e4fSDavid du Colombier Qcsnraw,
559a747e4fSDavid du Colombier
569a747e4fSDavid du Colombier Qpcidir,
579a747e4fSDavid du Colombier Qpcictl,
589a747e4fSDavid du Colombier Qpciraw,
599a747e4fSDavid du Colombier };
609a747e4fSDavid du Colombier
619a747e4fSDavid du Colombier #define TYPE(q) ((ulong)(q).path & 0x0F)
629a747e4fSDavid du Colombier #define CSN(q) (((ulong)(q).path>>4) & 0xFF)
639a747e4fSDavid du Colombier #define QID(c, t) (((c)<<4)|(t))
649a747e4fSDavid du Colombier
659a747e4fSDavid du Colombier static Dirtab topdir[] = {
669a747e4fSDavid du Colombier ".", { Qtopdir, 0, QTDIR }, 0, 0555,
679a747e4fSDavid du Colombier "pnp", { Qpnpdir, 0, QTDIR }, 0, 0555,
689a747e4fSDavid du Colombier "pci", { Qpcidir, 0, QTDIR }, 0, 0555,
699a747e4fSDavid du Colombier };
709a747e4fSDavid du Colombier
719a747e4fSDavid du Colombier static Dirtab pnpdir[] = {
729a747e4fSDavid du Colombier ".", { Qpnpdir, 0, QTDIR }, 0, 0555,
739a747e4fSDavid du Colombier "ctl", { Qpnpctl, 0, 0 }, 0, 0666,
749a747e4fSDavid du Colombier };
759a747e4fSDavid du Colombier
769a747e4fSDavid du Colombier extern Dev pnpdevtab;
779a747e4fSDavid du Colombier static int wrconfig(Card*, char*);
789a747e4fSDavid du Colombier
799a747e4fSDavid du Colombier static char key[32] =
809a747e4fSDavid du Colombier {
819a747e4fSDavid du Colombier 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
829a747e4fSDavid du Colombier 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
839a747e4fSDavid du Colombier 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
849a747e4fSDavid du Colombier 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39,
859a747e4fSDavid du Colombier };
869a747e4fSDavid du Colombier
879a747e4fSDavid du Colombier static void
cmd(int reg,int val)889a747e4fSDavid du Colombier cmd(int reg, int val)
899a747e4fSDavid du Colombier {
909a747e4fSDavid du Colombier outb(Address, reg);
919a747e4fSDavid du Colombier outb(WriteData, val);
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier
949a747e4fSDavid du Colombier /* Send initiation key, putting each card in Sleep state */
959a747e4fSDavid du Colombier static void
initiation(void)969a747e4fSDavid du Colombier initiation(void)
979a747e4fSDavid du Colombier {
989a747e4fSDavid du Colombier int i;
999a747e4fSDavid du Colombier
1009a747e4fSDavid du Colombier /* ensure each card's LFSR is reset */
1019a747e4fSDavid du Colombier outb(Address, 0x00);
1029a747e4fSDavid du Colombier outb(Address, 0x00);
1039a747e4fSDavid du Colombier
1049a747e4fSDavid du Colombier /* send initiation key */
1059a747e4fSDavid du Colombier for (i = 0; i < 32; i++)
1069a747e4fSDavid du Colombier outb(Address, key[i]);
1079a747e4fSDavid du Colombier }
1089a747e4fSDavid du Colombier
1099a747e4fSDavid du Colombier /* isolation protocol... */
1109a747e4fSDavid du Colombier static int
readbit(int rddata)1119a747e4fSDavid du Colombier readbit(int rddata)
1129a747e4fSDavid du Colombier {
1139a747e4fSDavid du Colombier int r1, r2;
1149a747e4fSDavid du Colombier
1159a747e4fSDavid du Colombier r1 = inb(rddata);
1169a747e4fSDavid du Colombier r2 = inb(rddata);
1179a747e4fSDavid du Colombier microdelay(250);
1189a747e4fSDavid du Colombier return (r1 == 0x55) && (r2 == 0xaa);
1199a747e4fSDavid du Colombier }
1209a747e4fSDavid du Colombier
1219a747e4fSDavid du Colombier static int
isolate(int rddata,ulong * id1,ulong * id2)1229a747e4fSDavid du Colombier isolate(int rddata, ulong *id1, ulong *id2)
1239a747e4fSDavid du Colombier {
1249a747e4fSDavid du Colombier int i, csum, bit;
1259a747e4fSDavid du Colombier uchar *p, id[9];
1269a747e4fSDavid du Colombier
1279a747e4fSDavid du Colombier outb(Address, 0x01); /* point to serial isolation register */
1289a747e4fSDavid du Colombier delay(1);
1299a747e4fSDavid du Colombier csum = 0x6a;
1309a747e4fSDavid du Colombier for(i = 0; i < 64; i++){
1319a747e4fSDavid du Colombier bit = readbit(rddata);
1329a747e4fSDavid du Colombier csum = (csum>>1) | (((csum&1) ^ ((csum>>1)&1) ^ bit)<<7);
1339a747e4fSDavid du Colombier p = &id[i>>3];
1349a747e4fSDavid du Colombier *p = (*p>>1) | (bit<<7);
1359a747e4fSDavid du Colombier }
1369a747e4fSDavid du Colombier for(; i < 72; i++){
1379a747e4fSDavid du Colombier p = &id[i>>3];
1389a747e4fSDavid du Colombier *p = (*p>>1) | (readbit(rddata)<<7);
1399a747e4fSDavid du Colombier }
1409a747e4fSDavid du Colombier *id1 = (id[3]<<24)|(id[2]<<16)|(id[1]<<8)|id[0];
1419a747e4fSDavid du Colombier *id2 = (id[7]<<24)|(id[6]<<16)|(id[5]<<8)|id[4];
1429a747e4fSDavid du Colombier if(*id1 == 0)
1439a747e4fSDavid du Colombier return 0;
1449a747e4fSDavid du Colombier if(id[8] != csum)
1459a747e4fSDavid du Colombier DPRINT("pnp: bad checksum id1 %lux id2 %lux csum %x != %x\n", *id1, *id2, csum, id[8]); /**/
1469a747e4fSDavid du Colombier return id[8] == csum;
1479a747e4fSDavid du Colombier }
1489a747e4fSDavid du Colombier
1499a747e4fSDavid du Colombier static int
getresbyte(int rddata)1509a747e4fSDavid du Colombier getresbyte(int rddata)
1519a747e4fSDavid du Colombier {
1529a747e4fSDavid du Colombier int tries = 0;
1539a747e4fSDavid du Colombier
1549a747e4fSDavid du Colombier outb(Address, 0x05);
1559a747e4fSDavid du Colombier while ((inb(rddata) & 1) == 0)
1569a747e4fSDavid du Colombier if (tries++ > 1000000)
1579a747e4fSDavid du Colombier error("pnp: timeout waiting for resource data\n");
1589a747e4fSDavid du Colombier outb(Address, 0x04);
1599a747e4fSDavid du Colombier return inb(rddata);
1609a747e4fSDavid du Colombier }
1619a747e4fSDavid du Colombier
1629a747e4fSDavid du Colombier static char *
serial(ulong id1,ulong id2)1639a747e4fSDavid du Colombier serial(ulong id1, ulong id2)
1649a747e4fSDavid du Colombier {
1659a747e4fSDavid du Colombier int i1, i2, i3;
1669a747e4fSDavid du Colombier ulong x;
1679a747e4fSDavid du Colombier static char buf[20];
1689a747e4fSDavid du Colombier
1699a747e4fSDavid du Colombier i1 = (id1>>2)&31;
1709a747e4fSDavid du Colombier i2 = ((id1<<3)&24)+((id1>>13)&7);
1719a747e4fSDavid du Colombier i3 = (id1>>8)&31;
1729a747e4fSDavid du Colombier x = (id1>>8)&0xff00|(id1>>24)&0x00ff;
1739a747e4fSDavid du Colombier if (i1 > 0 && i1 < 27 && i2 > 0 && i2 < 27 && i3 > 0 && i3 < 27 && (id1 & (1<<7)) == 0)
1749a747e4fSDavid du Colombier snprint(buf, sizeof(buf), "%c%c%c%.4lux.%lux", 'A'+i1-1, 'A'+i2-1, 'A'+i3-1, x, id2);
1759a747e4fSDavid du Colombier else
1769a747e4fSDavid du Colombier snprint(buf, sizeof(buf), "%.4lux%.4lux.%lux", (id1<<8)&0xff00|(id1>>8)&0x00ff, x, id2);
1779a747e4fSDavid du Colombier return buf;
1789a747e4fSDavid du Colombier }
1799a747e4fSDavid du Colombier
1809a747e4fSDavid du Colombier static Card *
findcsn(int csn,int create,int dolock)1819a747e4fSDavid du Colombier findcsn(int csn, int create, int dolock)
1829a747e4fSDavid du Colombier {
1839a747e4fSDavid du Colombier Card *c, *nc, **l;
1849a747e4fSDavid du Colombier
1859a747e4fSDavid du Colombier if(dolock)
1869a747e4fSDavid du Colombier qlock(&pnp);
1879a747e4fSDavid du Colombier l = &pnp.cards;
1889a747e4fSDavid du Colombier for(c = *l; c != nil; c = *l) {
1899a747e4fSDavid du Colombier if(c->csn == csn)
1909a747e4fSDavid du Colombier goto done;
1919a747e4fSDavid du Colombier if(c->csn > csn)
1929a747e4fSDavid du Colombier break;
1939a747e4fSDavid du Colombier l = &c->next;
1949a747e4fSDavid du Colombier }
1959a747e4fSDavid du Colombier if(create) {
1969a747e4fSDavid du Colombier *l = nc = malloc(sizeof(Card));
197*aa72973aSDavid du Colombier if(nc == nil) {
198*aa72973aSDavid du Colombier if(dolock)
199*aa72973aSDavid du Colombier qunlock(&pnp);
200*aa72973aSDavid du Colombier error(Enomem);
201*aa72973aSDavid du Colombier }
2029a747e4fSDavid du Colombier nc->next = c;
2039a747e4fSDavid du Colombier nc->csn = csn;
2049a747e4fSDavid du Colombier c = nc;
2059a747e4fSDavid du Colombier }
2069a747e4fSDavid du Colombier done:
2079a747e4fSDavid du Colombier if(dolock)
2089a747e4fSDavid du Colombier qunlock(&pnp);
2099a747e4fSDavid du Colombier return c;
2109a747e4fSDavid du Colombier }
2119a747e4fSDavid du Colombier
2129a747e4fSDavid du Colombier static int
newcsn(void)2139a747e4fSDavid du Colombier newcsn(void)
2149a747e4fSDavid du Colombier {
2159a747e4fSDavid du Colombier int csn;
2169a747e4fSDavid du Colombier Card *c;
2179a747e4fSDavid du Colombier
2189a747e4fSDavid du Colombier csn = 1;
2199a747e4fSDavid du Colombier for(c = pnp.cards; c != nil; c = c->next) {
2209a747e4fSDavid du Colombier if(c->csn > csn)
2219a747e4fSDavid du Colombier break;
2229a747e4fSDavid du Colombier csn = c->csn+1;
2239a747e4fSDavid du Colombier }
2249a747e4fSDavid du Colombier return csn;
2259a747e4fSDavid du Colombier }
2269a747e4fSDavid du Colombier
2279a747e4fSDavid du Colombier static int
pnpncfg(int rddata)2289a747e4fSDavid du Colombier pnpncfg(int rddata)
2299a747e4fSDavid du Colombier {
2309a747e4fSDavid du Colombier int i, n, x, ncfg, n1, n2;
2319a747e4fSDavid du Colombier
2329a747e4fSDavid du Colombier ncfg = 0;
2339a747e4fSDavid du Colombier for (;;) {
2349a747e4fSDavid du Colombier x = getresbyte(rddata);
2359a747e4fSDavid du Colombier if((x & 0x80) == 0) {
2369a747e4fSDavid du Colombier n = (x&7)+1;
2379a747e4fSDavid du Colombier for(i = 1; i < n; i++)
2389a747e4fSDavid du Colombier getresbyte(rddata);
2399a747e4fSDavid du Colombier }
2409a747e4fSDavid du Colombier else {
2419a747e4fSDavid du Colombier n1 = getresbyte(rddata);
2429a747e4fSDavid du Colombier n2 = getresbyte(rddata);
2439a747e4fSDavid du Colombier n = (n2<<8)|n1 + 3;
2449a747e4fSDavid du Colombier for (i = 3; i < n; i++)
2459a747e4fSDavid du Colombier getresbyte(rddata);
2469a747e4fSDavid du Colombier }
2479a747e4fSDavid du Colombier ncfg += n;
2489a747e4fSDavid du Colombier if((x>>3) == 0x0f)
2499a747e4fSDavid du Colombier break;
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier return ncfg;
2529a747e4fSDavid du Colombier }
2539a747e4fSDavid du Colombier
2549a747e4fSDavid du Colombier /* look for cards, and assign them CSNs */
2559a747e4fSDavid du Colombier static int
pnpscan(int rddata,int dawn)2569a747e4fSDavid du Colombier pnpscan(int rddata, int dawn)
2579a747e4fSDavid du Colombier {
2589a747e4fSDavid du Colombier Card *c;
2599a747e4fSDavid du Colombier int csn;
2609a747e4fSDavid du Colombier ulong id1, id2;
2619a747e4fSDavid du Colombier
2629a747e4fSDavid du Colombier initiation(); /* upsilon sigma */
2639a747e4fSDavid du Colombier cmd(0x02, 0x04+0x01); /* reset CSN on all cards and reset logical devices */
2649a747e4fSDavid du Colombier delay(1); /* delay after resetting cards */
2659a747e4fSDavid du Colombier
2669a747e4fSDavid du Colombier cmd(0x03, 0); /* Wake all cards with a CSN of 0 */
2679a747e4fSDavid du Colombier cmd(0x00, rddata>>2); /* Set the READ_DATA port on all cards */
2689a747e4fSDavid du Colombier while(isolate(rddata, &id1, &id2)) {
2699a747e4fSDavid du Colombier for(c = pnp.cards; c != nil; c = c->next)
2709a747e4fSDavid du Colombier if(c->id1 == id1 && c->id2 == id2)
2719a747e4fSDavid du Colombier break;
2729a747e4fSDavid du Colombier if(c == nil) {
2739a747e4fSDavid du Colombier csn = newcsn();
2749a747e4fSDavid du Colombier c = findcsn(csn, 1, 0);
2759a747e4fSDavid du Colombier c->id1 = id1;
2769a747e4fSDavid du Colombier c->id2 = id2;
2779a747e4fSDavid du Colombier }
2789a747e4fSDavid du Colombier else if(c->cfgstr != nil) {
2799a747e4fSDavid du Colombier if(!wrconfig(c, c->cfgstr))
2809a747e4fSDavid du Colombier print("pnp%d: bad cfg: %s\n", c->csn, c->cfgstr);
2819a747e4fSDavid du Colombier c->cfgstr = nil;
2829a747e4fSDavid du Colombier }
2839a747e4fSDavid du Colombier cmd(0x06, c->csn); /* set the card's csn */
2849a747e4fSDavid du Colombier if(dawn)
2859a747e4fSDavid du Colombier print("pnp%d: %s\n", c->csn, serial(id1, id2));
2869a747e4fSDavid du Colombier c->ncfg = pnpncfg(rddata);
2879a747e4fSDavid du Colombier cmd(0x03, 0); /* Wake all cards with a CSN of 0, putting this card to sleep */
2889a747e4fSDavid du Colombier }
2899a747e4fSDavid du Colombier cmd(0x02, 0x02); /* return cards to Wait for Key state */
2909a747e4fSDavid du Colombier if(pnp.cards != 0) {
2919a747e4fSDavid du Colombier pnp.rddata = rddata;
2929a747e4fSDavid du Colombier return 1;
2939a747e4fSDavid du Colombier }
2949a747e4fSDavid du Colombier return 0;
2959a747e4fSDavid du Colombier }
2969a747e4fSDavid du Colombier
2979a747e4fSDavid du Colombier static void
pnpreset(void)2989a747e4fSDavid du Colombier pnpreset(void)
2999a747e4fSDavid du Colombier {
3009a747e4fSDavid du Colombier Card *c;
3019a747e4fSDavid du Colombier ulong id1, id2;
3029a747e4fSDavid du Colombier int csn, i1, i2, i3, x;
3039a747e4fSDavid du Colombier char *s, *p, buf[20];
3049a747e4fSDavid du Colombier ISAConf isa;
3059a747e4fSDavid du Colombier
3069a747e4fSDavid du Colombier memset(&isa, 0, sizeof(ISAConf));
3079a747e4fSDavid du Colombier pnp.rddata = -1;
3089a747e4fSDavid du Colombier if (isaconfig("pnp", 0, &isa) == 0)
3099a747e4fSDavid du Colombier return;
3109a747e4fSDavid du Colombier if(isa.port < 0x203 || isa.port > 0x3ff)
3119a747e4fSDavid du Colombier return;
3129a747e4fSDavid du Colombier for(csn = 1; csn < 256; csn++) {
31357d98441SDavid du Colombier snprint(buf, sizeof buf, "pnp%d", csn);
3149a747e4fSDavid du Colombier s = getconf(buf);
3159a747e4fSDavid du Colombier if(s == 0)
3169a747e4fSDavid du Colombier continue;
3179a747e4fSDavid du Colombier if(strlen(s) < 8 || s[7] != '.' || s[0] < 'A' || s[0] > 'Z' || s[1] < 'A' || s[1] > 'Z' || s[2] < 'A' || s[2] > 'Z') {
3189a747e4fSDavid du Colombier bad:
3199a747e4fSDavid du Colombier print("pnp%d: bad conf string %s\n", csn, s);
3209a747e4fSDavid du Colombier continue;
3219a747e4fSDavid du Colombier }
3229a747e4fSDavid du Colombier i1 = s[0]-'A'+1;
3239a747e4fSDavid du Colombier i2 = s[1]-'A'+1;
3249a747e4fSDavid du Colombier i3 = s[2]-'A'+1;
3259a747e4fSDavid du Colombier x = strtoul(&s[3], 0, 16);
3269a747e4fSDavid du Colombier id1 = (i1<<2)|((i2>>3)&3)|((i2&7)<<13)|(i3<<8)|((x&0xff)<<24)|((x&0xff00)<<8);
3279a747e4fSDavid du Colombier id2 = strtoul(&s[8], &p, 16);
3289a747e4fSDavid du Colombier if(*p == ' ')
3299a747e4fSDavid du Colombier p++;
3309a747e4fSDavid du Colombier else if(*p == '\0')
3319a747e4fSDavid du Colombier p = nil;
3329a747e4fSDavid du Colombier else
3339a747e4fSDavid du Colombier goto bad;
3349a747e4fSDavid du Colombier c = findcsn(csn, 1, 0);
3359a747e4fSDavid du Colombier c->id1 = id1;
3369a747e4fSDavid du Colombier c->id2 = id2;
3379a747e4fSDavid du Colombier c->cfgstr = p;
3389a747e4fSDavid du Colombier }
3399a747e4fSDavid du Colombier pnpscan(isa.port, 1);
3409a747e4fSDavid du Colombier }
3419a747e4fSDavid du Colombier
3429a747e4fSDavid du Colombier static int
csngen(Chan * c,int t,int csn,Card * cp,Dir * dp)3439a747e4fSDavid du Colombier csngen(Chan *c, int t, int csn, Card *cp, Dir *dp)
3449a747e4fSDavid du Colombier {
3459a747e4fSDavid du Colombier Qid q;
3469a747e4fSDavid du Colombier
3479a747e4fSDavid du Colombier switch(t) {
3489a747e4fSDavid du Colombier case Qcsnctl:
3499a747e4fSDavid du Colombier q = (Qid){QID(csn, Qcsnctl), 0, 0};
35057d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "csn%dctl", csn);
3519a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0664, dp);
3529a747e4fSDavid du Colombier return 1;
3539a747e4fSDavid du Colombier case Qcsnraw:
3549a747e4fSDavid du Colombier q = (Qid){QID(csn, Qcsnraw), 0, 0};
35557d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "csn%draw", csn);
3569a747e4fSDavid du Colombier devdir(c, q, up->genbuf, cp->ncfg, eve, 0444, dp);
3579a747e4fSDavid du Colombier return 1;
3589a747e4fSDavid du Colombier }
3599a747e4fSDavid du Colombier return -1;
3609a747e4fSDavid du Colombier }
3619a747e4fSDavid du Colombier
3629a747e4fSDavid du Colombier static int
pcigen(Chan * c,int t,int tbdf,Dir * dp)3639a747e4fSDavid du Colombier pcigen(Chan *c, int t, int tbdf, Dir *dp)
3649a747e4fSDavid du Colombier {
3659a747e4fSDavid du Colombier Qid q;
3669a747e4fSDavid du Colombier
3679a747e4fSDavid du Colombier q = (Qid){BUSBDF(tbdf)|t, 0, 0};
3689a747e4fSDavid du Colombier switch(t) {
3699a747e4fSDavid du Colombier case Qpcictl:
37057d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "%d.%d.%dctl",
37157d98441SDavid du Colombier BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
3729a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0444, dp);
3739a747e4fSDavid du Colombier return 1;
3749a747e4fSDavid du Colombier case Qpciraw:
37557d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "%d.%d.%draw",
37657d98441SDavid du Colombier BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
37751af9883SDavid du Colombier devdir(c, q, up->genbuf, 128, eve, 0660, dp);
3789a747e4fSDavid du Colombier return 1;
3799a747e4fSDavid du Colombier }
3809a747e4fSDavid du Colombier return -1;
3819a747e4fSDavid du Colombier }
3829a747e4fSDavid du Colombier
3839a747e4fSDavid du Colombier static int
pnpgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)3849a747e4fSDavid du Colombier pnpgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
3859a747e4fSDavid du Colombier {
3869a747e4fSDavid du Colombier Qid q;
3879a747e4fSDavid du Colombier Card *cp;
3889a747e4fSDavid du Colombier Pcidev *p;
3899a747e4fSDavid du Colombier int csn, tbdf;
3909a747e4fSDavid du Colombier
3919a747e4fSDavid du Colombier switch(TYPE(c->qid)){
3929a747e4fSDavid du Colombier case Qtopdir:
3939a747e4fSDavid du Colombier if(s == DEVDOTDOT){
3949a747e4fSDavid du Colombier q = (Qid){QID(0, Qtopdir), 0, QTDIR};
39557d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
3969a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
3979a747e4fSDavid du Colombier return 1;
3989a747e4fSDavid du Colombier }
3999a747e4fSDavid du Colombier return devgen(c, nil, topdir, nelem(topdir), s, dp);
4009a747e4fSDavid du Colombier case Qpnpdir:
4019a747e4fSDavid du Colombier if(s == DEVDOTDOT){
4029a747e4fSDavid du Colombier q = (Qid){QID(0, Qtopdir), 0, QTDIR};
40357d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
4049a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
4059a747e4fSDavid du Colombier return 1;
4069a747e4fSDavid du Colombier }
4079a747e4fSDavid du Colombier if(s < nelem(pnpdir)-1)
4089a747e4fSDavid du Colombier return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);
4099a747e4fSDavid du Colombier s -= nelem(pnpdir)-1;
4109a747e4fSDavid du Colombier qlock(&pnp);
4119a747e4fSDavid du Colombier cp = pnp.cards;
4129a747e4fSDavid du Colombier while(s >= 2 && cp != nil) {
4139a747e4fSDavid du Colombier s -= 2;
4149a747e4fSDavid du Colombier cp = cp->next;
4159a747e4fSDavid du Colombier }
4169a747e4fSDavid du Colombier qunlock(&pnp);
4179a747e4fSDavid du Colombier if(cp == nil)
4189a747e4fSDavid du Colombier return -1;
4199a747e4fSDavid du Colombier return csngen(c, s+Qcsnctl, cp->csn, cp, dp);
4209a747e4fSDavid du Colombier case Qpnpctl:
4219a747e4fSDavid du Colombier return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);
4229a747e4fSDavid du Colombier case Qcsnctl:
4239a747e4fSDavid du Colombier case Qcsnraw:
4249a747e4fSDavid du Colombier csn = CSN(c->qid);
4259a747e4fSDavid du Colombier cp = findcsn(csn, 0, 1);
4269a747e4fSDavid du Colombier if(cp == nil)
4279a747e4fSDavid du Colombier return -1;
4289a747e4fSDavid du Colombier return csngen(c, TYPE(c->qid), csn, cp, dp);
4299a747e4fSDavid du Colombier case Qpcidir:
4309a747e4fSDavid du Colombier if(s == DEVDOTDOT){
4319a747e4fSDavid du Colombier q = (Qid){QID(0, Qtopdir), 0, QTDIR};
43257d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "#%C", pnpdevtab.dc);
4339a747e4fSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
4349a747e4fSDavid du Colombier return 1;
4359a747e4fSDavid du Colombier }
4369a747e4fSDavid du Colombier p = pcimatch(nil, 0, 0);
4379a747e4fSDavid du Colombier while(s >= 2 && p != nil) {
4389a747e4fSDavid du Colombier p = pcimatch(p, 0, 0);
4399a747e4fSDavid du Colombier s -= 2;
4409a747e4fSDavid du Colombier }
4419a747e4fSDavid du Colombier if(p == nil)
4429a747e4fSDavid du Colombier return -1;
4439a747e4fSDavid du Colombier return pcigen(c, s+Qpcictl, p->tbdf, dp);
4449a747e4fSDavid du Colombier case Qpcictl:
4459a747e4fSDavid du Colombier case Qpciraw:
4469a747e4fSDavid du Colombier tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
4479a747e4fSDavid du Colombier p = pcimatchtbdf(tbdf);
4489a747e4fSDavid du Colombier if(p == nil)
4499a747e4fSDavid du Colombier return -1;
4509a747e4fSDavid du Colombier return pcigen(c, TYPE(c->qid), tbdf, dp);
4519a747e4fSDavid du Colombier default:
4529a747e4fSDavid du Colombier break;
4539a747e4fSDavid du Colombier }
4549a747e4fSDavid du Colombier return -1;
4559a747e4fSDavid du Colombier }
4569a747e4fSDavid du Colombier
4579a747e4fSDavid du Colombier static Chan*
pnpattach(char * spec)4589a747e4fSDavid du Colombier pnpattach(char *spec)
4599a747e4fSDavid du Colombier {
4609a747e4fSDavid du Colombier return devattach(pnpdevtab.dc, spec);
4619a747e4fSDavid du Colombier }
4629a747e4fSDavid du Colombier
4639a747e4fSDavid du Colombier Walkqid*
pnpwalk(Chan * c,Chan * nc,char ** name,int nname)4649a747e4fSDavid du Colombier pnpwalk(Chan* c, Chan *nc, char** name, int nname)
4659a747e4fSDavid du Colombier {
4669a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, (Dirtab *)0, 0, pnpgen);
4679a747e4fSDavid du Colombier }
4689a747e4fSDavid du Colombier
4699a747e4fSDavid du Colombier static int
pnpstat(Chan * c,uchar * dp,int n)4709a747e4fSDavid du Colombier pnpstat(Chan* c, uchar* dp, int n)
4719a747e4fSDavid du Colombier {
4729a747e4fSDavid du Colombier return devstat(c, dp, n, (Dirtab *)0, 0L, pnpgen);
4739a747e4fSDavid du Colombier }
4749a747e4fSDavid du Colombier
4759a747e4fSDavid du Colombier static Chan*
pnpopen(Chan * c,int omode)4769a747e4fSDavid du Colombier pnpopen(Chan *c, int omode)
4779a747e4fSDavid du Colombier {
4789a747e4fSDavid du Colombier c = devopen(c, omode, (Dirtab*)0, 0, pnpgen);
4799a747e4fSDavid du Colombier switch(TYPE(c->qid)){
4809a747e4fSDavid du Colombier default:
4819a747e4fSDavid du Colombier break;
4829a747e4fSDavid du Colombier }
4839a747e4fSDavid du Colombier return c;
4849a747e4fSDavid du Colombier }
4859a747e4fSDavid du Colombier
4869a747e4fSDavid du Colombier static void
pnpclose(Chan *)4879a747e4fSDavid du Colombier pnpclose(Chan*)
4889a747e4fSDavid du Colombier {
4899a747e4fSDavid du Colombier }
4909a747e4fSDavid du Colombier
4919a747e4fSDavid du Colombier static long
pnpread(Chan * c,void * va,long n,vlong offset)4929a747e4fSDavid du Colombier pnpread(Chan *c, void *va, long n, vlong offset)
4939a747e4fSDavid du Colombier {
4949a747e4fSDavid du Colombier ulong x;
4959a747e4fSDavid du Colombier Card *cp;
4969a747e4fSDavid du Colombier Pcidev *p;
4979a747e4fSDavid du Colombier char buf[256], *ebuf, *w;
4989a747e4fSDavid du Colombier char *a = va;
4999a747e4fSDavid du Colombier int csn, i, tbdf, r;
5009a747e4fSDavid du Colombier
5019a747e4fSDavid du Colombier switch(TYPE(c->qid)){
5029a747e4fSDavid du Colombier case Qtopdir:
5039a747e4fSDavid du Colombier case Qpnpdir:
5049a747e4fSDavid du Colombier case Qpcidir:
5059a747e4fSDavid du Colombier return devdirread(c, a, n, (Dirtab *)0, 0L, pnpgen);
5069a747e4fSDavid du Colombier case Qpnpctl:
5079a747e4fSDavid du Colombier if(pnp.rddata > 0)
50857d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "enabled %#x\n",
50957d98441SDavid du Colombier pnp.rddata);
5109a747e4fSDavid du Colombier else
51157d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "disabled\n");
5129a747e4fSDavid du Colombier return readstr(offset, a, n, up->genbuf);
5139a747e4fSDavid du Colombier case Qcsnraw:
5149a747e4fSDavid du Colombier csn = CSN(c->qid);
5159a747e4fSDavid du Colombier cp = findcsn(csn, 0, 1);
5169a747e4fSDavid du Colombier if(cp == nil)
5179a747e4fSDavid du Colombier error(Egreg);
5189a747e4fSDavid du Colombier if(offset+n > cp->ncfg)
5199a747e4fSDavid du Colombier n = cp->ncfg - offset;
5209a747e4fSDavid du Colombier qlock(&pnp);
5219a747e4fSDavid du Colombier initiation();
5229a747e4fSDavid du Colombier cmd(0x03, csn); /* Wake up the card */
5239a747e4fSDavid du Colombier for(i = 0; i < offset+9; i++) /* 9 == skip serial + csum */
5249a747e4fSDavid du Colombier getresbyte(pnp.rddata);
5259a747e4fSDavid du Colombier for(i = 0; i < n; i++)
5269a747e4fSDavid du Colombier a[i] = getresbyte(pnp.rddata);
5279a747e4fSDavid du Colombier cmd(0x03, 0); /* Wake all cards with a CSN of 0, putting this card to sleep */
5289a747e4fSDavid du Colombier cmd(0x02, 0x02); /* return cards to Wait for Key state */
5299a747e4fSDavid du Colombier qunlock(&pnp);
5309a747e4fSDavid du Colombier break;
5319a747e4fSDavid du Colombier case Qcsnctl:
5329a747e4fSDavid du Colombier csn = CSN(c->qid);
5339a747e4fSDavid du Colombier cp = findcsn(csn, 0, 1);
5349a747e4fSDavid du Colombier if(cp == nil)
5359a747e4fSDavid du Colombier error(Egreg);
53657d98441SDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "%s\n",
53757d98441SDavid du Colombier serial(cp->id1, cp->id2));
5389a747e4fSDavid du Colombier return readstr(offset, a, n, up->genbuf);
5399a747e4fSDavid du Colombier case Qpcictl:
5409a747e4fSDavid du Colombier tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
5419a747e4fSDavid du Colombier p = pcimatchtbdf(tbdf);
5429a747e4fSDavid du Colombier if(p == nil)
5439a747e4fSDavid du Colombier error(Egreg);
5449a747e4fSDavid du Colombier ebuf = buf+sizeof buf-1; /* -1 for newline */
5459a747e4fSDavid du Colombier w = seprint(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d",
5469a747e4fSDavid du Colombier p->ccrb, p->ccru, p->ccrp, p->vid, p->did, p->intl);
5479a747e4fSDavid du Colombier for(i=0; i<nelem(p->mem); i++){
5489a747e4fSDavid du Colombier if(p->mem[i].size == 0)
5499a747e4fSDavid du Colombier continue;
5509a747e4fSDavid du Colombier w = seprint(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size);
5519a747e4fSDavid du Colombier }
5529a747e4fSDavid du Colombier *w++ = '\n';
5539a747e4fSDavid du Colombier *w = '\0';
5549a747e4fSDavid du Colombier return readstr(offset, a, n, buf);
5559a747e4fSDavid du Colombier case Qpciraw:
5569a747e4fSDavid du Colombier tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
5579a747e4fSDavid du Colombier p = pcimatchtbdf(tbdf);
5589a747e4fSDavid du Colombier if(p == nil)
5599a747e4fSDavid du Colombier error(Egreg);
5609a747e4fSDavid du Colombier if(offset > 256)
5619a747e4fSDavid du Colombier return 0;
5629a747e4fSDavid du Colombier if(n+offset > 256)
5639a747e4fSDavid du Colombier n = 256-offset;
5649a747e4fSDavid du Colombier r = offset;
56551af9883SDavid du Colombier if(!(r & 3) && n == 4){
5669a747e4fSDavid du Colombier x = pcicfgr32(p, r);
56751af9883SDavid du Colombier PBIT32(a, x);
56851af9883SDavid du Colombier return 4;
56951af9883SDavid du Colombier }
57051af9883SDavid du Colombier if(!(r & 1) && n == 2){
57151af9883SDavid du Colombier x = pcicfgr16(p, r);
57251af9883SDavid du Colombier PBIT16(a, x);
57351af9883SDavid du Colombier return 2;
57451af9883SDavid du Colombier }
57551af9883SDavid du Colombier for(i = 0; i < n; i++){
57651af9883SDavid du Colombier x = pcicfgr8(p, r);
57751af9883SDavid du Colombier PBIT8(a, x);
57851af9883SDavid du Colombier a++;
57951af9883SDavid du Colombier r++;
5809a747e4fSDavid du Colombier }
5819a747e4fSDavid du Colombier return i;
5829a747e4fSDavid du Colombier default:
5839a747e4fSDavid du Colombier error(Egreg);
5849a747e4fSDavid du Colombier }
5859a747e4fSDavid du Colombier return n;
5869a747e4fSDavid du Colombier }
5879a747e4fSDavid du Colombier
5889a747e4fSDavid du Colombier static long
pnpwrite(Chan * c,void * va,long n,vlong offset)58951af9883SDavid du Colombier pnpwrite(Chan *c, void *va, long n, vlong offset)
5909a747e4fSDavid du Colombier {
5919a747e4fSDavid du Colombier Card *cp;
59251af9883SDavid du Colombier Pcidev *p;
59351af9883SDavid du Colombier ulong port, x;
594274d35baSDavid du Colombier char buf[256];
595274d35baSDavid du Colombier uchar *a;
59651af9883SDavid du Colombier int csn, i, r, tbdf;
5979a747e4fSDavid du Colombier
5989a747e4fSDavid du Colombier if(n >= sizeof(buf))
5999a747e4fSDavid du Colombier n = sizeof(buf)-1;
60051af9883SDavid du Colombier a = va;
601274d35baSDavid du Colombier strncpy(buf, va, n);
6029a747e4fSDavid du Colombier buf[n] = 0;
6039a747e4fSDavid du Colombier
6049a747e4fSDavid du Colombier switch(TYPE(c->qid)){
6059a747e4fSDavid du Colombier case Qpnpctl:
6069a747e4fSDavid du Colombier if(strncmp(buf, "port ", 5) == 0) {
6079a747e4fSDavid du Colombier port = strtoul(buf+5, 0, 0);
6089a747e4fSDavid du Colombier if(port < 0x203 || port > 0x3ff)
6099a747e4fSDavid du Colombier error("bad value for rddata port");
6109a747e4fSDavid du Colombier qlock(&pnp);
6119a747e4fSDavid du Colombier if(waserror()) {
6129a747e4fSDavid du Colombier qunlock(&pnp);
6139a747e4fSDavid du Colombier nexterror();
6149a747e4fSDavid du Colombier }
6159a747e4fSDavid du Colombier if(pnp.rddata > 0)
6169a747e4fSDavid du Colombier error("pnp port already set");
6179a747e4fSDavid du Colombier if(!pnpscan(port, 0))
6189a747e4fSDavid du Colombier error("no cards found");
6199a747e4fSDavid du Colombier qunlock(&pnp);
6209a747e4fSDavid du Colombier poperror();
6219a747e4fSDavid du Colombier }
6229a747e4fSDavid du Colombier else if(strncmp(buf, "debug ", 6) == 0)
6239a747e4fSDavid du Colombier pnp.debug = strtoul(buf+6, 0, 0);
6249a747e4fSDavid du Colombier else
6259a747e4fSDavid du Colombier error(Ebadctl);
6269a747e4fSDavid du Colombier break;
6279a747e4fSDavid du Colombier case Qcsnctl:
6289a747e4fSDavid du Colombier csn = CSN(c->qid);
6299a747e4fSDavid du Colombier cp = findcsn(csn, 0, 1);
6309a747e4fSDavid du Colombier if(cp == nil)
6319a747e4fSDavid du Colombier error(Egreg);
6329a747e4fSDavid du Colombier if(!wrconfig(cp, buf))
6339a747e4fSDavid du Colombier error(Ebadctl);
6349a747e4fSDavid du Colombier break;
63551af9883SDavid du Colombier case Qpciraw:
63651af9883SDavid du Colombier tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
63751af9883SDavid du Colombier p = pcimatchtbdf(tbdf);
63851af9883SDavid du Colombier if(p == nil)
63951af9883SDavid du Colombier error(Egreg);
64051af9883SDavid du Colombier if(offset > 256)
64151af9883SDavid du Colombier return 0;
64251af9883SDavid du Colombier if(n+offset > 256)
64351af9883SDavid du Colombier n = 256-offset;
64451af9883SDavid du Colombier r = offset;
64551af9883SDavid du Colombier if(!(r & 3) && n == 4){
64651af9883SDavid du Colombier x = GBIT32(a);
64751af9883SDavid du Colombier pcicfgw32(p, r, x);
64851af9883SDavid du Colombier return 4;
64951af9883SDavid du Colombier }
65051af9883SDavid du Colombier if(!(r & 1) && n == 2){
65151af9883SDavid du Colombier x = GBIT16(a);
65251af9883SDavid du Colombier pcicfgw16(p, r, x);
65351af9883SDavid du Colombier return 2;
65451af9883SDavid du Colombier }
65551af9883SDavid du Colombier for(i = 0; i < n; i++){
65651af9883SDavid du Colombier x = GBIT8(a);
65751af9883SDavid du Colombier pcicfgw8(p, r, x);
65851af9883SDavid du Colombier a++;
65951af9883SDavid du Colombier r++;
66051af9883SDavid du Colombier }
66151af9883SDavid du Colombier return i;
6629a747e4fSDavid du Colombier default:
6639a747e4fSDavid du Colombier error(Egreg);
6649a747e4fSDavid du Colombier }
6659a747e4fSDavid du Colombier return n;
6669a747e4fSDavid du Colombier }
6679a747e4fSDavid du Colombier
6689a747e4fSDavid du Colombier static int
wrconfig(Card * c,char * cmd)6699a747e4fSDavid du Colombier wrconfig(Card *c, char *cmd)
6709a747e4fSDavid du Colombier {
6719a747e4fSDavid du Colombier /* This should implement setting of I/O bases, etc */
6729a747e4fSDavid du Colombier USED(c, cmd);
6739a747e4fSDavid du Colombier return 1;
6749a747e4fSDavid du Colombier }
6759a747e4fSDavid du Colombier
6769a747e4fSDavid du Colombier
6779a747e4fSDavid du Colombier Dev pnpdevtab = {
6789a747e4fSDavid du Colombier '$',
6799a747e4fSDavid du Colombier "pnp",
6809a747e4fSDavid du Colombier
6819a747e4fSDavid du Colombier pnpreset,
6829a747e4fSDavid du Colombier devinit,
6839a747e4fSDavid du Colombier devshutdown,
6849a747e4fSDavid du Colombier pnpattach,
6859a747e4fSDavid du Colombier pnpwalk,
6869a747e4fSDavid du Colombier pnpstat,
6879a747e4fSDavid du Colombier pnpopen,
6889a747e4fSDavid du Colombier devcreate,
6899a747e4fSDavid du Colombier pnpclose,
6909a747e4fSDavid du Colombier pnpread,
6919a747e4fSDavid du Colombier devbread,
6929a747e4fSDavid du Colombier pnpwrite,
6939a747e4fSDavid du Colombier devbwrite,
6949a747e4fSDavid du Colombier devremove,
6959a747e4fSDavid du Colombier devwstat,
6969a747e4fSDavid du Colombier };
697