summaryrefslogtreecommitdiff
path: root/sys/src/9/port/cis.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/port/cis.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/port/cis.c')
-rwxr-xr-xsys/src/9/port/cis.c539
1 files changed, 539 insertions, 0 deletions
diff --git a/sys/src/9/port/cis.c b/sys/src/9/port/cis.c
new file mode 100755
index 000000000..368eb6d68
--- /dev/null
+++ b/sys/src/9/port/cis.c
@@ -0,0 +1,539 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "io.h"
+
+enum{
+ Linktarget = 0x13,
+};
+
+/*
+ * read and crack the card information structure enough to set
+ * important parameters like power
+ */
+/* cis memory walking */
+typedef struct Cisdat {
+ uchar *cisbase;
+ int cispos;
+ int cisskip;
+ int cislen;
+} Cisdat;
+
+static void tcfig(PCMslot*, Cisdat*, int);
+static void tentry(PCMslot*, Cisdat*, int);
+static void tvers1(PCMslot*, Cisdat*, int);
+static void tlonglnkmfc(PCMslot*, Cisdat*, int);
+
+static int
+readc(Cisdat *cis, uchar *x)
+{
+ if(cis->cispos >= cis->cislen)
+ return 0;
+ *x = cis->cisbase[cis->cisskip*cis->cispos];
+ cis->cispos++;
+ return 1;
+}
+
+static int
+xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
+{
+ PCMmap *m;
+ Cisdat cis;
+ int i, l;
+ uchar *p;
+ uchar type, link, n, c;
+ int this, subtype;
+
+ m = pcmmap(slotno, 0, 0, attr);
+ if(m == 0)
+ return -1;
+
+ cis.cisbase = KADDR(m->isa);
+ cis.cispos = 0;
+ cis.cisskip = attr ? 2 : 1;
+ cis.cislen = m->len;
+
+ /* loop through all the tuples */
+ for(i = 0; i < 1000; i++){
+ this = cis.cispos;
+ if(readc(&cis, &type) != 1)
+ break;
+ if(type == 0xFF)
+ break;
+ if(readc(&cis, &link) != 1)
+ break;
+ if(link == 0xFF)
+ break;
+
+ n = link;
+ if(link > 1 && subtuple != -1){
+ if(readc(&cis, &c) != 1)
+ break;
+ subtype = c;
+ n--;
+ }else
+ subtype = -1;
+
+ if(type == tuple && subtype == subtuple){
+ p = v;
+ for(l=0; l<nv && l<n; l++)
+ if(readc(&cis, p++) != 1)
+ break;
+ pcmunmap(slotno, m);
+ return nv;
+ }
+ cis.cispos = this + (2+link);
+ }
+ pcmunmap(slotno, m);
+ return -1;
+}
+
+int
+pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
+{
+ int n;
+
+ /* try attribute space, then memory */
+ if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
+ return n;
+ return xcistuple(slotno, tuple, subtuple, v, nv, 0);
+}
+
+void
+pcmcisread(PCMslot *pp)
+{
+ int this;
+ Cisdat cis;
+ PCMmap *m;
+ uchar type, link;
+
+ memset(pp->ctab, 0, sizeof(pp->ctab));
+ pp->ncfg = 0;
+ memset(pp->cfg, 0, sizeof(pp->cfg));
+ pp->configed = 0;
+ pp->nctab = 0;
+ pp->verstr[0] = 0;
+
+ /*
+ * Read all tuples in attribute space.
+ */
+ m = pcmmap(pp->slotno, 0, 0, 1);
+ if(m == 0)
+ return;
+
+ cis.cisbase = KADDR(m->isa);
+ cis.cispos = 0;
+ cis.cisskip = 2;
+ cis.cislen = m->len;
+
+ /* loop through all the tuples */
+ for(;;){
+ this = cis.cispos;
+ if(readc(&cis, &type) != 1)
+ break;
+ if(type == 0xFF)
+ break;
+ if(readc(&cis, &link) != 1)
+ break;
+
+ switch(type){
+ default:
+ break;
+ case 6:
+ tlonglnkmfc(pp, &cis, type);
+ break;
+ case 0x15:
+ tvers1(pp, &cis, type);
+ break;
+ case 0x1A:
+ tcfig(pp, &cis, type);
+ break;
+ case 0x1B:
+ tentry(pp, &cis, type);
+ break;
+ }
+
+ if(link == 0xFF)
+ break;
+ cis.cispos = this + (2+link);
+ }
+ pcmunmap(pp->slotno, m);
+}
+
+static ulong
+getlong(Cisdat *cis, int size)
+{
+ uchar c;
+ int i;
+ ulong x;
+
+ x = 0;
+ for(i = 0; i < size; i++){
+ if(readc(cis, &c) != 1)
+ break;
+ x |= c<<(i*8);
+ }
+ return x;
+}
+
+static void
+tcfig(PCMslot *pp, Cisdat *cis, int )
+{
+ uchar size, rasize, rmsize;
+ uchar last;
+
+ if(readc(cis, &size) != 1)
+ return;
+ rasize = (size&0x3) + 1;
+ rmsize = ((size>>2)&0xf) + 1;
+ if(readc(cis, &last) != 1)
+ return;
+
+ if(pp->ncfg >= 8){
+ print("tcfig: too many configuration registers\n");
+ return;
+ }
+
+ pp->cfg[pp->ncfg].caddr = getlong(cis, rasize);
+ pp->cfg[pp->ncfg].cpresent = getlong(cis, rmsize);
+ pp->ncfg++;
+}
+
+static ulong vexp[8] =
+{
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+static ulong vmant[16] =
+{
+ 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
+};
+
+static ulong
+microvolt(Cisdat *cis)
+{
+ uchar c;
+ ulong microvolts;
+ ulong exp;
+
+ if(readc(cis, &c) != 1)
+ return 0;
+ exp = vexp[c&0x7];
+ microvolts = vmant[(c>>3)&0xf]*exp;
+ while(c & 0x80){
+ if(readc(cis, &c) != 1)
+ return 0;
+ switch(c){
+ case 0x7d:
+ break; /* high impedence when sleeping */
+ case 0x7e:
+ case 0x7f:
+ microvolts = 0; /* no connection */
+ break;
+ default:
+ exp /= 10;
+ microvolts += exp*(c&0x7f);
+ }
+ }
+ return microvolts;
+}
+
+static ulong
+nanoamps(Cisdat *cis)
+{
+ uchar c;
+ ulong nanoamps;
+
+ if(readc(cis, &c) != 1)
+ return 0;
+ nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
+ while(c & 0x80){
+ if(readc(cis, &c) != 1)
+ return 0;
+ if(c == 0x7d || c == 0x7e || c == 0x7f)
+ nanoamps = 0;
+ }
+ return nanoamps;
+}
+
+/*
+ * only nominal voltage (feature 1) is important for config,
+ * other features must read card to stay in sync.
+ */
+static ulong
+power(Cisdat *cis)
+{
+ uchar feature;
+ ulong mv;
+
+ mv = 0;
+ if(readc(cis, &feature) != 1)
+ return 0;
+ if(feature & 1)
+ mv = microvolt(cis);
+ if(feature & 2)
+ microvolt(cis);
+ if(feature & 4)
+ microvolt(cis);
+ if(feature & 8)
+ nanoamps(cis);
+ if(feature & 0x10)
+ nanoamps(cis);
+ if(feature & 0x20)
+ nanoamps(cis);
+ if(feature & 0x40)
+ nanoamps(cis);
+ return mv/1000000;
+}
+
+static ulong mantissa[16] =
+{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };
+
+static ulong exponent[8] =
+{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };
+
+static ulong
+ttiming(Cisdat *cis, int scale)
+{
+ uchar unscaled;
+ ulong nanosecs;
+
+ if(readc(cis, &unscaled) != 1)
+ return 0;
+ nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
+ nanosecs = nanosecs * vexp[scale];
+ return nanosecs;
+}
+
+static void
+timing(Cisdat *cis, PCMconftab *ct)
+{
+ uchar c, i;
+
+ if(readc(cis, &c) != 1)
+ return;
+ i = c&0x3;
+ if(i != 3)
+ ct->maxwait = ttiming(cis, i); /* max wait */
+ i = (c>>2)&0x7;
+ if(i != 7)
+ ct->readywait = ttiming(cis, i); /* max ready/busy wait */
+ i = (c>>5)&0x7;
+ if(i != 7)
+ ct->otherwait = ttiming(cis, i); /* reserved wait */
+}
+
+static void
+iospaces(Cisdat *cis, PCMconftab *ct)
+{
+ uchar c;
+ int i, nio;
+
+ ct->nio = 0;
+ if(readc(cis, &c) != 1)
+ return;
+
+ ct->bit16 = ((c>>5)&3) >= 2;
+ if(!(c & 0x80)){
+ ct->io[0].start = 0;
+ ct->io[0].len = 1<<(c&0x1f);
+ ct->nio = 1;
+ return;
+ }
+
+ if(readc(cis, &c) != 1)
+ return;
+
+ /*
+ * For each of the range descriptions read the
+ * start address and the length (value is length-1).
+ */
+ nio = (c&0xf)+1;
+ for(i = 0; i < nio; i++){
+ ct->io[i].start = getlong(cis, (c>>4)&0x3);
+ ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
+ }
+ ct->nio = nio;
+}
+
+static void
+irq(Cisdat *cis, PCMconftab *ct)
+{
+ uchar c;
+
+ if(readc(cis, &c) != 1)
+ return;
+ ct->irqtype = c & 0xe0;
+ if(c & 0x10)
+ ct->irqs = getlong(cis, 2);
+ else
+ ct->irqs = 1<<(c&0xf);
+ ct->irqs &= 0xDEB8; /* levels available to card */
+}
+
+static void
+memspace(Cisdat *cis, int asize, int lsize, int host)
+{
+ ulong haddress, address, len;
+
+ len = getlong(cis, lsize)*256;
+ address = getlong(cis, asize)*256;
+ USED(len, address);
+ if(host){
+ haddress = getlong(cis, asize)*256;
+ USED(haddress);
+ }
+}
+
+static void
+tentry(PCMslot *pp, Cisdat *cis, int )
+{
+ uchar c, i, feature;
+ PCMconftab *ct;
+
+ if(pp->nctab >= nelem(pp->ctab))
+ return;
+ if(readc(cis, &c) != 1)
+ return;
+ ct = &pp->ctab[pp->nctab++];
+
+ /* copy from last default config */
+ if(pp->def)
+ *ct = *pp->def;
+
+ ct->index = c & 0x3f;
+
+ /* is this the new default? */
+ if(c & 0x40)
+ pp->def = ct;
+
+ /* memory wait specified? */
+ if(c & 0x80){
+ if(readc(cis, &i) != 1)
+ return;
+ if(i&0x80)
+ ct->memwait = 1;
+ }
+
+ if(readc(cis, &feature) != 1)
+ return;
+ switch(feature&0x3){
+ case 1:
+ ct->vpp1 = ct->vpp2 = power(cis);
+ break;
+ case 2:
+ power(cis);
+ ct->vpp1 = ct->vpp2 = power(cis);
+ break;
+ case 3:
+ power(cis);
+ ct->vpp1 = power(cis);
+ ct->vpp2 = power(cis);
+ break;
+ default:
+ break;
+ }
+ if(feature&0x4)
+ timing(cis, ct);
+ if(feature&0x8)
+ iospaces(cis, ct);
+ if(feature&0x10)
+ irq(cis, ct);
+ switch((feature>>5)&0x3){
+ case 1:
+ memspace(cis, 0, 2, 0);
+ break;
+ case 2:
+ memspace(cis, 2, 2, 0);
+ break;
+ case 3:
+ if(readc(cis, &c) != 1)
+ return;
+ for(i = 0; i <= (c&0x7); i++)
+ memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
+ break;
+ }
+ pp->configed++;
+}
+
+static void
+tvers1(PCMslot *pp, Cisdat *cis, int )
+{
+ uchar c, major, minor, last;
+ int i;
+
+ if(readc(cis, &major) != 1)
+ return;
+ if(readc(cis, &minor) != 1)
+ return;
+ last = 0;
+ for(i = 0; i < sizeof(pp->verstr)-1; i++){
+ if(readc(cis, &c) != 1)
+ return;
+ if(c == 0)
+ c = ';';
+ if(c == '\n')
+ c = ';';
+ if(c == 0xff)
+ break;
+ if(c == ';' && last == ';')
+ continue;
+ pp->verstr[i] = c;
+ last = c;
+ }
+ pp->verstr[i] = 0;
+}
+
+static void
+tlonglnkmfc(PCMslot *pp, Cisdat *cis, int)
+{
+ int i, npos, opos;
+ uchar nfn, space, expect, type, this, link;
+
+ readc(cis, &nfn);
+ for(i = 0; i < nfn; i++){
+ readc(cis, &space);
+ npos = getlong(cis, 4);
+ opos = cis->cispos;
+ cis->cispos = npos;
+ expect = Linktarget;
+
+ while(1){
+ this = cis->cispos;
+ if(readc(cis, &type) != 1)
+ break;
+ if(type == 0xFF)
+ break;
+ if(readc(cis, &link) != 1)
+ break;
+
+ if(expect && expect != type){
+ print("tlonglnkmfc: expected %X found %X\n",
+ expect, type);
+ break;
+ }
+ expect = 0;
+
+ switch(type){
+ default:
+ break;
+ case 0x15:
+ tvers1(pp, cis, type);
+ break;
+ case 0x1A:
+ tcfig(pp, cis, type);
+ break;
+ case 0x1B:
+ tentry(pp, cis, type);
+ break;
+ }
+
+ if(link == 0xFF)
+ break;
+ cis->cispos = this + (2+link);
+ }
+ cis->cispos = opos;
+ }
+}