|
|
1.1 root 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: #include "devtab.h"
9:
10: /*
11: * Support for up to 4 Slot card slots. Generalizing above that is hard
12: * since addressing is not obvious. - presotto
13: *
14: * WARNING: This has never been tried with more than one card slot.
15: */
16:
17: /*
18: * Intel 82365SL PCIC controller for the PCMCIA or
19: * Cirrus Logic PD6710/PD6720 which is mostly register compatible
20: */
21: enum
22: {
23: /*
24: * registers indices
25: */
26: Rid= 0x0, /* identification and revision */
27: Ris= 0x1, /* interface status */
28: Rpc= 0x2, /* power control */
29: Foutena= (1<<7), /* output enable */
30: Fautopower= (1<<5), /* automatic power switching */
31: Fcardena= (1<<4), /* PC card enable */
32: Rigc= 0x3, /* interrupt and general control */
33: Fiocard= (1<<5), /* I/O card (vs memory) */
34: Fnotreset= (1<<6), /* reset if not set */
35: FSMIena= (1<<4), /* enable change interrupt on SMI */
36: Rcsc= 0x4, /* card status change */
37: Rcscic= 0x5, /* card status change interrupt config */
38: Fchangeena= (1<<3), /* card changed */
39: Fbwarnena= (1<<1), /* card battery warning */
40: Fbdeadena= (1<<0), /* card battery dead */
41: Rwe= 0x6, /* address window enable */
42: Fmem16= (1<<5), /* use A23-A12 to decode address */
43: Rio= 0x7, /* I/O control */
44: Fwidth16= (1<<0), /* 16 bit data width */
45: Fiocs16= (1<<1), /* IOCS16 determines data width */
46: Ftiming= (1<<3), /* timing register to use */
47: Riobtm0lo= 0x8, /* I/O address 0 start low byte */
48: Riobtm0hi= 0x9, /* I/O address 0 start high byte */
49: Riotop0lo= 0xa, /* I/O address 0 stop low byte */
50: Riotop0hi= 0xb, /* I/O address 0 stop high byte */
51: Riobtm1lo= 0xc, /* I/O address 1 start low byte */
52: Riobtm1hi= 0xd, /* I/O address 1 start high byte */
53: Riotop1lo= 0xe, /* I/O address 1 stop low byte */
54: Riotop1hi= 0xf, /* I/O address 1 stop high byte */
55: Rmap= 0x10, /* map 0 */
56:
57: /*
58: * CL-PD67xx extension registers
59: */
60: Rmisc1= 0x16, /* misc control 1 */
61: F5Vdetect= (1<<0),
62: Fvcc3V= (1<<1),
63: Fpmint= (1<<2),
64: Fpsirq= (1<<3),
65: Fspeaker= (1<<4),
66: Finpack= (1<<7),
67: Rfifo= 0x17, /* fifo control */
68: Fflush= (1<<7), /* flush fifo */
69: Rmisc2= 0x1E, /* misc control 2 */
70: Flowpow= (1<<1), /* low power mode */
71: Rchipinfo= 0x1F, /* chip information */
72: Ratactl= 0x26, /* ATA control */
73:
74: /*
75: * offsets into the system memory address maps
76: */
77: Mbtmlo= 0x0, /* System mem addr mapping start low byte */
78: Mbtmhi= 0x1, /* System mem addr mapping start high byte */
79: F16bit= (1<<7), /* 16-bit wide data path */
80: Mtoplo= 0x2, /* System mem addr mapping stop low byte */
81: Mtophi= 0x3, /* System mem addr mapping stop high byte */
82: Ftimer1= (1<<6), /* timer set 1 */
83: Mofflo= 0x4, /* Card memory offset address low byte */
84: Moffhi= 0x5, /* Card memory offset address high byte */
85: Fregactive= (1<<6), /* attribute memory */
86:
87: Mbits= 13, /* msb of Mchunk */
88: Mchunk= 1<<Mbits, /* logical mapping granularity */
89: Nmap= 4, /* max number of maps to use */
90:
91: /*
92: * configuration registers - they start at an offset in attribute
93: * memory found in the CIS.
94: */
95: Rconfig= 0,
96: Creset= (1<<7), /* reset device */
97: Clevel= (1<<6), /* level sensitive interrupt line */
98:
99: Maxctab= 8, /* maximum configuration table entries */
100: };
101:
102: #define MAP(x,o) (Rmap + (x)*0x8 + o)
103:
104: typedef struct I82365 I82365;
105: typedef struct Slot Slot;
106: typedef struct Conftab Conftab;
107:
108: /* a controller */
109: enum
110: {
111: Ti82365,
112: Tpd6710,
113: Tpd6720,
114: };
115: struct I82365
116: {
117: int type;
118: int dev;
119: int nslot;
120: int xreg; /* index register address */
121: int dreg; /* data register address */
122: };
123: static I82365 *controller[4];
124: static int ncontroller;
125:
126: /* configuration table entry */
127: struct Conftab
128: {
129: int index;
130: ushort irqs; /* legal irqs */
131: ushort port; /* port address */
132: uchar irqtype;
133: uchar nioregs; /* number of io registers */
134: uchar bit16; /* true for 16 bit access */
135: uchar vpp1;
136: uchar vpp2;
137: uchar memwait;
138: ulong maxwait;
139: ulong readywait;
140: ulong otherwait;
141: };
142:
143: /* a card slot */
144: struct Slot
145: {
146: Lock;
147: int ref;
148:
149: I82365 *cp; /* controller for this slot */
150: long memlen; /* memory length */
151: uchar base; /* index register base */
152: uchar slotno; /* slot number */
153:
154: /* status */
155: uchar special; /* in use for a special device */
156: uchar already; /* already inited */
157: uchar occupied;
158: uchar battery;
159: uchar wrprot;
160: uchar powered;
161: uchar configed;
162: uchar enabled;
163: uchar busy;
164:
165: /* cis info */
166: char verstr[512]; /* version string */
167: uchar cpresent; /* config registers present */
168: ulong caddr; /* relative address of config registers */
169: int nctab; /* number of config table entries */
170: Conftab ctab[Maxctab];
171: Conftab *def; /* default conftab */
172:
173: /* for walking through cis */
174: int cispos; /* current position scanning cis */
175: uchar *cisbase;
176:
177: /* memory maps */
178: Lock mlock; /* lock down the maps */
179: int time;
180: PCMmap mmap[Nmap]; /* maps, last is always for the kernel */
181: };
182: static Slot *slot;
183: static Slot *lastslot;
184: static nslot;
185:
186: static void cisread(Slot*);
187: static void i82365intr(Ureg*, void*);
188: static int pcmio(int, ISAConf*);
189: static long pcmread(int, int, void*, long, ulong);
190: static long pcmwrite(int, int, void*, long, ulong);
191:
192: /*
193: * reading and writing card registers
194: */
195: static uchar
196: rdreg(Slot *pp, int index)
197: {
198: outb(pp->cp->xreg, pp->base + index);
199: return inb(pp->cp->dreg);
200: }
201: static void
202: wrreg(Slot *pp, int index, uchar val)
203: {
204: outb(pp->cp->xreg, pp->base + index);
205: outb(pp->cp->dreg, val);
206: }
207:
208: /*
209: * get info about card
210: */
211: static void
212: slotinfo(Slot *pp)
213: {
214: uchar isr;
215:
216: isr = rdreg(pp, Ris);
217: pp->occupied = (isr & (3<<2)) == (3<<2);
218: pp->powered = isr & (1<<6);
219: pp->battery = (isr & 3) == 3;
220: pp->wrprot = isr & (1<<4);
221: pp->busy = isr & (1<<5);
222: }
223:
224: static int
225: vcode(int volt)
226: {
227: switch(volt){
228: case 5:
229: return 1;
230: case 12:
231: return 2;
232: default:
233: return 0;
234: }
235: }
236:
237: /*
238: * enable the slot card
239: */
240: static void
241: slotena(Slot *pp)
242: {
243: if(pp->enabled)
244: return;
245:
246: /* power up and unreset, wait's are empirical (???) */
247: wrreg(pp, Rpc, Fautopower|Foutena|Fcardena);
248: delay(300);
249: wrreg(pp, Rigc, 0);
250: delay(100);
251: wrreg(pp, Rigc, Fnotreset);
252: delay(500);
253:
254: /* get configuration */
255: slotinfo(pp);
256: if(pp->occupied){
257: cisread(pp);
258: pp->enabled = 1;
259: } else
260: wrreg(pp, Rpc, Fautopower);
261: }
262:
263: /*
264: * disable the slot card
265: */
266: static void
267: slotdis(Slot *pp)
268: {
269: wrreg(pp, Rpc, 0); /* turn off card power */
270: wrreg(pp, Rwe, 0); /* no windows */
271: pp->enabled = 0;
272: }
273:
274: /*
275: * status change interrupt
276: */
277: static void
278: i82365intr(Ureg *ur, void *a)
279: {
280: uchar csc, was;
281: Slot *pp;
282:
283: USED(ur,a);
284: if(slot == 0)
285: return;
286:
287: for(pp = slot; pp < lastslot; pp++){
288: csc = rdreg(pp, Rcsc);
289: was = pp->occupied;
290: slotinfo(pp);
291: if(csc & (1<<3) && was != pp->occupied){
292: if(pp->occupied)
293: print("slot%d card inserted\n", pp->slotno);
294: else {
295: print("slot%d card removed\n", pp->slotno);
296: slotdis(pp);
297: }
298: }
299: }
300: }
301:
302: enum
303: {
304: Mshift= 12,
305: Mgran= (1<<Mshift), /* granularity of maps */
306: Mmask= ~(Mgran-1), /* mask for address bits important to the chip */
307: };
308:
309: /*
310: * get a map for pc card region, return corrected len
311: */
312: PCMmap*
313: pcmmap(int slotno, ulong offset, int len, int attr)
314: {
315: Slot *pp;
316: uchar we, bit;
317: PCMmap *m, *nm;
318: int i;
319: ulong e;
320:
321: pp = slot + slotno;
322: lock(&pp->mlock);
323:
324: /* convert offset to granularity */
325: if(len <= 0)
326: len = 1;
327: e = ROUND(offset+len, Mgran);
328: offset &= Mmask;
329: len = e - offset;
330:
331: /* look for a map that covers the right area */
332: we = rdreg(pp, Rwe);
333: bit = 1;
334: nm = 0;
335: for(m = pp->mmap; m < &pp->mmap[Nmap]; m++){
336: if((we & bit))
337: if(m->attr == attr)
338: if(offset >= m->ca && e <= m->cea){
339:
340: m->ref++;
341: unlock(&pp->mlock);
342: return m;
343: }
344: bit <<= 1;
345: if(nm == 0 && m->ref == 0)
346: nm = m;
347: }
348: m = nm;
349: if(m == 0){
350: unlock(&pp->mlock);
351: return 0;
352: }
353:
354: /* if isa space isn't big enough, free it and get more */
355: if(m->len < len){
356: if(m->isa){
357: putisa(m->isa, m->len);
358: m->len = 0;
359: }
360: m->isa = getisa(0, len, Mgran)&~KZERO;
361: if(m->isa == 0){
362: print("pcmmap: out of isa space\n");
363: unlock(&pp->mlock);
364: return 0;
365: }
366: m->len = len;
367: }
368:
369: /* set up new map */
370: m->ca = offset;
371: m->cea = m->ca + m->len;
372: m->attr = attr;
373: i = m-pp->mmap;
374: bit = 1<<i;
375: wrreg(pp, Rwe, we & ~bit); /* disable map before changing it */
376: wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift);
377: wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
378: wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
379: wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
380: offset -= m->isa;
381: offset &= (1<<25)-1;
382: offset >>= Mshift;
383: wrreg(pp, MAP(i, Mofflo), offset);
384: wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
385: wrreg(pp, Rwe, we | bit); /* enable map */
386: m->ref = 1;
387:
388: unlock(&pp->mlock);
389: return m;
390: }
391:
392: void
393: pcmunmap(int slotno, PCMmap* m)
394: {
395: Slot *pp;
396:
397: pp = slot + slotno;
398: lock(&pp->mlock);
399: m->ref--;
400: unlock(&pp->mlock);
401: }
402:
403:
404: static void
405: increfp(Slot *pp)
406: {
407: lock(pp);
408: if(pp->ref++ == 0)
409: slotena(pp);
410: unlock(pp);
411: }
412:
413: static void
414: decrefp(Slot *pp)
415: {
416: lock(pp);
417: if(pp->ref-- == 1)
418: slotdis(pp);
419: unlock(pp);
420: }
421:
422: /*
423: * look for a card whose version contains 'idstr'
424: */
425: int
426: pcmspecial(char *idstr, ISAConf *isa)
427: {
428: Slot *pp;
429: extern char *strstr(char*, char*);
430:
431: i82365reset();
432: for(pp = slot; pp < lastslot; pp++){
433: if(pp->special)
434: continue; /* already taken */
435: increfp(pp);
436:
437: if(pp->occupied)
438: if(strstr(pp->verstr, idstr))
439: if(isa == 0 || pcmio(pp->slotno, isa) == 0){
440: pp->special = 1;
441: return pp->slotno;
442: }
443:
444: decrefp(pp);
445: }
446: return -1;
447: }
448:
449: void
450: pcmspecialclose(int slotno)
451: {
452: Slot *pp;
453:
454: if(slotno >= nslot)
455: panic("pcmspecialclose");
456: pp = slot + slotno;
457: pp->special = 0;
458: decrefp(pp);
459: }
460:
461: enum
462: {
463: Qdir,
464: Qmem,
465: Qattr,
466: Qctl,
467: };
468:
469: #define SLOTNO(c) ((c->qid.path>>8)&0xff)
470: #define TYPE(c) (c->qid.path&0xff)
471: #define QID(s,t) (((s)<<8)|(t))
472:
473: static int
474: pcmgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
475: {
476: int slotno;
477: Qid qid;
478: long len;
479: Slot *pp;
480: char name[NAMELEN];
481:
482: USED(tab, ntab);
483: if(i>=3*nslot)
484: return -1;
485: slotno = i/3;
486: pp = slot + slotno;
487: len = 0;
488: switch(i%3){
489: case 0:
490: qid.path = QID(slotno, Qmem);
491: sprint(name, "pcm%dmem", slotno);
492: len = pp->memlen;
493: break;
494: case 1:
495: qid.path = QID(slotno, Qattr);
496: sprint(name, "pcm%dattr", slotno);
497: len = pp->memlen;
498: break;
499: case 2:
500: qid.path = QID(slotno, Qctl);
501: sprint(name, "pcm%dctl", slotno);
502: break;
503: }
504: qid.vers = 0;
505: devdir(c, qid, name, len, eve, 0660, dp);
506: return 1;
507: }
508:
509: static char *chipname[] =
510: {
511: [Ti82365] "Intel 82365SL",
512: [Tpd6710] "Cirrus Logic PD6710",
513: [Tpd6720] "Cirrus Logic PD6720",
514: };
515:
516: static I82365*
517: i82386probe(int x, int d, int dev)
518: {
519: uchar c;
520: I82365 *cp;
521:
522: outb(x, Rid + (dev<<7));
523: c = inb(d);
524: if((c & 0xf0) != 0x80)
525: return 0; /* not this family */
526:
527: cp = xalloc(sizeof(I82365));
528: cp->xreg = x;
529: cp->dreg = d;
530: cp->dev = dev;
531: cp->type = Ti82365;
532: cp->nslot = 2;
533:
534: switch(c){
535: case 0x82:
536: case 0x83:
537: /* could be a cirrus */
538: outb(x, Rchipinfo + (dev<<7));
539: outb(d, 0);
540: c = inb(d);
541: if((c & 0xdf) == 0xdc){
542: c = inb(d);
543: if((c & 0xdf) != 0x0c)
544: break;
545: }
546: if(c & 0x40){
547: cp->type = Tpd6720;
548: } else {
549: cp->type = Tpd6710;
550: cp->nslot = 1;
551: }
552: break;
553: }
554:
555: print("pcmcia controller%d is a %d slot %s\n", ncontroller, cp->nslot,
556: chipname[cp->type]);
557:
558: /* low power mode */
559: outb(x, Rmisc2 + (dev<<7));
560: outb(d, Flowpow);
561:
562: controller[ncontroller++] = cp;
563: return cp;
564: }
565:
566: static void
567: i82365dump(Slot *pp)
568: {
569: int i;
570:
571: for(i = 0; i < 0x40; i++){
572: if((i&0x7) == 0)
573: print("\n%ux: ", i);
574: print("%ux ", rdreg(pp, i));
575: }
576: print("\n");
577: }
578:
579: /*
580: * set up for slot cards
581: */
582: void
583: i82365reset(void)
584: {
585: static int already;
586: int i, j;
587: I82365 *cp;
588: Slot *pp;
589:
590: if(already)
591: return;
592: already = 1;
593:
594: /* look for controllers */
595: i82386probe(0x3E0, 0x3E1, 0);
596: i82386probe(0x3E0, 0x3E1, 1);
597: i82386probe(0x3E2, 0x3E3, 0);
598: i82386probe(0x3E2, 0x3E3, 1);
599: for(i = 0; i < ncontroller; i++)
600: nslot += controller[i]->nslot;
601: slot = xalloc(nslot * sizeof(Slot));
602:
603: /* if the card is there turn on 5V power to keep its battery alive */
604: lastslot = slot;
605: for(i = 0; i < ncontroller; i++){
606: cp = controller[i];
607: for(j = 0; j < cp->nslot; j++){
608: pp = lastslot++;
609: pp->slotno = pp - slot;
610: pp->memlen = 64*MB;
611: pp->base = (cp->dev<<7) | (j<<6);
612: pp->cp = cp;
613: slotdis(pp);
614:
615: /* interrupt on status change */
616: wrreg(pp, Rcscic, ((PCMCIAvec-Int0vec)<<4) | Fchangeena);
617: }
618: }
619:
620: /* for card management interrupts */
621: setvec(PCMCIAvec, i82365intr, 0);
622: }
623:
624: void
625: i82365init(void)
626: {
627: }
628:
629: Chan *
630: i82365attach(char *spec)
631: {
632: return devattach('y', spec);
633: }
634:
635: Chan *
636: i82365clone(Chan *c, Chan *nc)
637: {
638: return devclone(c, nc);
639: }
640:
641: int
642: i82365walk(Chan *c, char *name)
643: {
644: return devwalk(c, name, 0, 0, pcmgen);
645: }
646:
647: void
648: i82365stat(Chan *c, char *db)
649: {
650: devstat(c, db, 0, 0, pcmgen);
651: }
652:
653: Chan *
654: i82365open(Chan *c, int omode)
655: {
656: if(c->qid.path == CHDIR){
657: if(omode != OREAD)
658: error(Eperm);
659: } else
660: increfp(slot + SLOTNO(c));
661: c->mode = openmode(omode);
662: c->flag |= COPEN;
663: c->offset = 0;
664: return c;
665: }
666:
667: void
668: i82365create(Chan *c, char *name, int omode, ulong perm)
669: {
670: USED(c, name, omode, perm);
671: error(Eperm);
672: }
673:
674: void
675: i82365remove(Chan *c)
676: {
677: USED(c);
678: error(Eperm);
679: }
680:
681: void
682: i82365wstat(Chan *c, char *dp)
683: {
684: USED(c, dp);
685: error(Eperm);
686: }
687:
688: void
689: i82365close(Chan *c)
690: {
691: if(c->flag & COPEN)
692: if(c->qid.path != CHDIR)
693: decrefp(slot+SLOTNO(c));
694: }
695:
696: /* a memmove using only bytes */
697: static void
698: memmoveb(uchar *to, uchar *from, int n)
699: {
700: while(n-- > 0)
701: *to++ = *from++;
702: }
703:
704: /* a memmove using only shorts & bytes */
705: static void
706: memmoves(uchar *to, uchar *from, int n)
707: {
708: ushort *t, *f;
709:
710: if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
711: while(n-- > 0)
712: *to++ = *from++;
713: } else {
714: n = n/2;
715: t = (ushort*)to;
716: f = (ushort*)from;
717: while(n-- > 0)
718: *t++ = *f++;
719: }
720: }
721:
722: static long
723: pcmread(int slotno, int attr, void *a, long n, ulong offset)
724: {
725: int i, len;
726: PCMmap *m;
727: ulong ka;
728: uchar *ac;
729: Slot *pp;
730:
731: pp = slot + slotno;
732: if(pp->memlen < offset)
733: return 0;
734: if(pp->memlen < offset + n)
735: n = pp->memlen - offset;
736:
737: m = 0;
738: if(waserror()){
739: if(m)
740: pcmunmap(pp->slotno, m);
741: nexterror();
742: }
743:
744: ac = a;
745: for(len = n; len > 0; len -= i){
746: m = pcmmap(pp->slotno, offset, 0, attr);
747: if(m == 0)
748: error("can't map PCMCIA card");
749: if(offset + len > m->cea)
750: i = m->cea - offset;
751: else
752: i = len;
753: ka = KZERO|(m->isa + offset - m->ca);
754: memmoveb(ac, (void*)ka, i);
755: pcmunmap(pp->slotno, m);
756: offset += i;
757: ac += i;
758: }
759:
760: poperror();
761: return n;
762: }
763:
764: long
765: i82365read(Chan *c, void *a, long n, ulong offset)
766: {
767: char *cp, buf[2048];
768: ulong p;
769: Slot *pp;
770:
771: p = TYPE(c);
772: switch(p){
773: case Qdir:
774: return devdirread(c, a, n, 0, 0, pcmgen);
775: case Qmem:
776: case Qattr:
777: return pcmread(SLOTNO(c), p==Qattr, a, n, offset);
778: case Qctl:
779: cp = buf;
780: pp = slot + SLOTNO(c);
781: if(pp->occupied)
782: cp += sprint(cp, "occupied\n");
783: if(pp->enabled)
784: cp += sprint(cp, "enabled\n");
785: if(pp->powered)
786: cp += sprint(cp, "powered\n");
787: if(pp->configed)
788: cp += sprint(cp, "configed\n");
789: if(pp->wrprot)
790: cp += sprint(cp, "write protected\n");
791: if(pp->busy)
792: cp += sprint(cp, "busy\n");
793: cp += sprint(cp, "battery lvl %d\n", pp->battery);
794: {
795: int i;
796:
797: for(i = 0; i < 0x40; i++){
798: if((i&0x7) == 0)
799: cp += sprint(cp, "\n%ux: ", i);
800: cp += sprint(cp, "%ux ", rdreg(pp, i));
801: }
802: cp += sprint(cp, "\n");
803: }
804: *cp = 0;
805: return readstr(offset, a, n, buf);
806: default:
807: n=0;
808: break;
809: }
810: return n;
811: }
812:
813: static long
814: pcmwrite(int dev, int attr, void *a, long n, ulong offset)
815: {
816: int i, len;
817: PCMmap *m;
818: ulong ka;
819: uchar *ac;
820: Slot *pp;
821:
822: pp = slot + dev;
823: if(pp->memlen < offset)
824: return 0;
825: if(pp->memlen < offset + n)
826: n = pp->memlen - offset;
827:
828: m = 0;
829: if(waserror()){
830: if(m)
831: pcmunmap(pp->slotno, m);
832: nexterror();
833: }
834:
835: ac = a;
836: for(len = n; len > 0; len -= i){
837: m = pcmmap(pp->slotno, offset, 0, attr);
838: if(m == 0)
839: error("can't map PCMCIA card");
840: if(offset + len > m->cea)
841: i = m->cea - offset;
842: else
843: i = len;
844: ka = KZERO|(m->isa + offset - m->ca);
845: memmoveb((void*)ka, ac, i);
846: pcmunmap(pp->slotno, m);
847: offset += i;
848: ac += i;
849: }
850:
851: poperror();
852: return n;
853: }
854:
855: long
856: i82365write(Chan *c, void *a, long n, ulong offset)
857: {
858: ulong p;
859: Slot *pp;
860:
861: p = TYPE(c);
862: switch(p){
863: case Qmem:
864: case Qattr:
865: pp = slot + SLOTNO(c);
866: if(pp->occupied == 0 || pp->enabled == 0)
867: error(Eio);
868: n = pcmwrite(pp->slotno, p == Qattr, a, n, offset);
869: if(n < 0)
870: error(Eio);
871: break;
872: default:
873: error(Ebadusefd);
874: }
875: return n;
876: }
877:
878: /*
879: * configure the Slot for IO. We assume very heavily that we can read
880: * cofiguration info from the CIS. If not, we won't set up correctly.
881: */
882: static int
883: pcmio(int slotno, ISAConf *isa)
884: {
885: uchar we, x, *p;
886: Slot *pp;
887: Conftab *ct;
888: PCMmap *m;
889: int irq;
890:
891: irq = isa->irq;
892: if(irq == 2)
893: irq = 9;
894:
895: if(slotno > nslot)
896: return -1;
897: pp = slot + slotno;
898:
899: if(!pp->occupied)
900: return -1;
901:
902: /* find a configuration with the right port */
903: for(ct = pp->ctab; ct < &pp->ctab[pp->nctab]; ct++){
904: if(ct->nioregs && ct->port == isa->port && ((1<<irq) & ct->irqs))
905: break;
906: }
907:
908: /* if non found, settle for one with the some ioregs */
909: if(ct == &pp->ctab[pp->nctab])
910: for(ct = pp->ctab; ct < &pp->ctab[pp->nctab]; ct++)
911: if(ct->nioregs && ((1<<irq) & ct->irqs))
912: break;
913:
914: if(ct == &pp->ctab[pp->nctab])
915: return -1;
916:
917: /* route interrupts */
918: isa->irq = irq;
919: wrreg(pp, Rigc, irq | Fnotreset | Fiocard);
920:
921: /* set power and enable device */
922: x = vcode(ct->vpp1);
923: wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena);
924:
925: /* 16-bit data path */
926: if(ct->bit16)
927: x = Fiocs16|Fwidth16;
928: else
929: x = 0;
930: wrreg(pp, Rio, Ftiming|x);
931:
932: /* enable io port map 0 */
933: if(isa->port == 0)
934: isa->port = ct->port;
935: we = rdreg(pp, Rwe);
936: wrreg(pp, Riobtm0lo, isa->port);
937: wrreg(pp, Riobtm0hi, isa->port>>8);
938: wrreg(pp, Riotop0lo, (isa->port+ct->nioregs-1));
939: wrreg(pp, Riotop0hi, (isa->port+ct->nioregs-1)>>8);
940: wrreg(pp, Rwe, we | (1<<6));
941:
942: /* only touch Rconfig if it is present */
943: if(pp->cpresent & (1<<Rconfig)){
944: /* Reset adapter */
945: m = pcmmap(slotno, pp->caddr + Rconfig, 1, 1);
946: p = (uchar*)(KZERO|(m->isa + pp->caddr + Rconfig - m->ca));
947:
948: /* set configuration and interrupt type */
949: x = ct->index;
950: if((ct->irqtype & 0x20) && ((ct->irqtype & 0x40)==0 || isa->irq>7))
951: x |= Clevel;
952: *p = x;
953: delay(5);
954:
955: pcmunmap(slotno, m);
956: }
957: return 0;
958: }
959:
960: /*
961: * read and crack the card information structure enough to set
962: * important parameters like power
963: */
964: static void tcfig(Slot*, int);
965: static void tentry(Slot*, int);
966: static void tvers1(Slot*, int);
967:
968: static void (*parse[256])(Slot*, int) =
969: {
970: [0x15] tvers1,
971: [0x1A] tcfig,
972: [0x1B] tentry,
973: };
974:
975: static int
976: readc(Slot *pp, uchar *x)
977: {
978: if(pp->cispos >= Mchunk)
979: return 0;
980: *x = pp->cisbase[2*pp->cispos];
981: pp->cispos++;
982: return 1;
983: }
984:
985: static void
986: cisread(Slot *pp)
987: {
988: uchar link;
989: uchar type;
990: int this, i;
991: PCMmap *m;
992:
993: memset(pp->ctab, 0, sizeof(pp->ctab));
994: pp->caddr = 0;
995: pp->cpresent = 0;
996: pp->configed = 0;
997: pp->nctab = 0;
998:
999: m = pcmmap(pp->slotno, 0, 0, 1);
1000: if(m == 0)
1001: return;
1002: pp->cisbase = (uchar*)(KZERO|m->isa);
1003: pp->cispos = 0;
1004:
1005: /* loop through all the tuples */
1006: for(i = 0; i < 1000; i++){
1007: this = pp->cispos;
1008: if(readc(pp, &type) != 1)
1009: break;
1010: if(readc(pp, &link) != 1)
1011: break;
1012: if(parse[type])
1013: (*parse[type])(pp, type);
1014: if(link == 0xff)
1015: break;
1016: pp->cispos = this + (2+link);
1017: }
1018: pcmunmap(pp->slotno, m);
1019: }
1020:
1021: static ulong
1022: getlong(Slot *pp, int size)
1023: {
1024: uchar c;
1025: int i;
1026: ulong x;
1027:
1028: x = 0;
1029: for(i = 0; i < size; i++){
1030: if(readc(pp, &c) != 1)
1031: break;
1032: x |= c<<(i*8);
1033: }
1034: return x;
1035: }
1036:
1037: static void
1038: tcfig(Slot *pp, int ttype)
1039: {
1040: uchar size, rasize, rmsize;
1041: uchar last;
1042:
1043: USED(ttype);
1044: if(readc(pp, &size) != 1)
1045: return;
1046: rasize = (size&0x3) + 1;
1047: rmsize = ((size>>2)&0xf) + 1;
1048: if(readc(pp, &last) != 1)
1049: return;
1050: pp->caddr = getlong(pp, rasize);
1051: pp->cpresent = getlong(pp, rmsize);
1052: }
1053:
1054: static ulong vexp[8] =
1055: {
1056: 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
1057: };
1058: static ulong vmant[16] =
1059: {
1060: 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
1061: };
1062:
1063: static ulong
1064: microvolt(Slot *pp)
1065: {
1066: uchar c;
1067: ulong microvolts;
1068: ulong exp;
1069:
1070: if(readc(pp, &c) != 1)
1071: return 0;
1072: exp = vexp[c&0x7];
1073: microvolts = vmant[(c>>3)&0xf]*exp;
1074: while(c & 0x80){
1075: if(readc(pp, &c) != 1)
1076: return 0;
1077: switch(c){
1078: case 0x7d:
1079: break; /* high impedence when sleeping */
1080: case 0x7e:
1081: case 0x7f:
1082: microvolts = 0; /* no connection */
1083: break;
1084: default:
1085: exp /= 10;
1086: microvolts += exp*(c&0x7f);
1087: }
1088: }
1089: return microvolts;
1090: }
1091:
1092: static ulong
1093: nanoamps(Slot *pp)
1094: {
1095: uchar c;
1096: ulong nanoamps;
1097:
1098: if(readc(pp, &c) != 1)
1099: return 0;
1100: nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
1101: while(c & 0x80){
1102: if(readc(pp, &c) != 1)
1103: return 0;
1104: if(c == 0x7d || c == 0x7e || c == 0x7f)
1105: nanoamps = 0;
1106: }
1107: return nanoamps;
1108: }
1109:
1110: /*
1111: * only nominal voltage is important for config
1112: */
1113: static ulong
1114: power(Slot *pp)
1115: {
1116: uchar feature;
1117: ulong mv;
1118:
1119: mv = 0;
1120: if(readc(pp, &feature) != 1)
1121: return 0;
1122: if(feature & 1)
1123: mv = microvolt(pp);
1124: if(feature & 2)
1125: microvolt(pp);
1126: if(feature & 4)
1127: microvolt(pp);
1128: if(feature & 8)
1129: nanoamps(pp);
1130: if(feature & 0x10)
1131: nanoamps(pp);
1132: if(feature & 0x20)
1133: nanoamps(pp);
1134: if(feature & 0x40)
1135: nanoamps(pp);
1136: return mv/1000000;
1137: }
1138:
1139: static ulong mantissa[16] =
1140: { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };
1141:
1142: static ulong exponent[8] =
1143: { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };
1144:
1145: static ulong
1146: ttiming(Slot *pp, int scale)
1147: {
1148: uchar unscaled;
1149: ulong nanosecs;
1150:
1151: if(readc(pp, &unscaled) != 1)
1152: return 0;
1153: nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
1154: nanosecs = nanosecs * vexp[scale];
1155: return nanosecs;
1156: }
1157:
1158: static void
1159: timing(Slot *pp, Conftab *ct)
1160: {
1161: uchar c, i;
1162:
1163: if(readc(pp, &c) != 1)
1164: return;
1165: i = c&0x3;
1166: if(i != 3)
1167: ct->maxwait = ttiming(pp, i); /* max wait */
1168: i = (c>>2)&0x7;
1169: if(i != 7)
1170: ct->readywait = ttiming(pp, i); /* max ready/busy wait */
1171: i = (c>>5)&0x7;
1172: if(i != 7)
1173: ct->otherwait = ttiming(pp, i); /* reserved wait */
1174: }
1175:
1176: void
1177: iospaces(Slot *pp, Conftab *ct)
1178: {
1179: uchar c;
1180: int i;
1181: ulong len;
1182:
1183: if(readc(pp, &c) != 1)
1184: return;
1185:
1186: ct->nioregs = 1<<(c&0x1f);
1187: ct->bit16 = ((c>>5)&3) >= 2;
1188: if((c & 0x80) == 0)
1189: return;
1190:
1191: if(readc(pp, &c) != 1)
1192: return;
1193:
1194: for(i = (c&0xf)+1; i; i--){
1195: ct->port = getlong(pp, (c>>4)&0x3);
1196: len = getlong(pp, (c>>6)&0x3);
1197: USED(len);
1198: }
1199: }
1200:
1201: static void
1202: irq(Slot *pp, Conftab *ct)
1203: {
1204: uchar c;
1205:
1206: if(readc(pp, &c) != 1)
1207: return;
1208: ct->irqtype = c & 0xe0;
1209: if(c & 0x10)
1210: ct->irqs = getlong(pp, 2);
1211: else
1212: ct->irqs = 1<<(c&0xf);
1213: ct->irqs &= 0xDEB8; /* levels available to card */
1214: }
1215:
1216: static void
1217: memspace(Slot *pp, int asize, int lsize, int host)
1218: {
1219: ulong haddress, address, len;
1220:
1221: len = getlong(pp, lsize)*256;
1222: address = getlong(pp, asize)*256;
1223: USED(len, address);
1224: if(host){
1225: haddress = getlong(pp, asize)*256;
1226: USED(haddress);
1227: }
1228: }
1229:
1230: void
1231: tentry(Slot *pp, int ttype)
1232: {
1233: uchar c, i, feature;
1234: Conftab *ct;
1235:
1236: USED(ttype);
1237:
1238: if(pp->nctab >= Maxctab)
1239: return;
1240: if(readc(pp, &c) != 1)
1241: return;
1242: ct = &pp->ctab[pp->nctab++];
1243:
1244: /* copy from last default config */
1245: if(pp->def)
1246: *ct = *pp->def;
1247:
1248: ct->index = c & 0x3f;
1249:
1250: /* is this the new default? */
1251: if(c & 0x40)
1252: pp->def = ct;
1253:
1254: /* memory wait specified? */
1255: if(c & 0x80){
1256: if(readc(pp, &i) != 1)
1257: return;
1258: if(i&0x80)
1259: ct->memwait = 1;
1260: }
1261:
1262: if(readc(pp, &feature) != 1)
1263: return;
1264: switch(feature&0x3){
1265: case 1:
1266: ct->vpp1 = ct->vpp2 = power(pp);
1267: break;
1268: case 2:
1269: power(pp);
1270: ct->vpp1 = ct->vpp2 = power(pp);
1271: break;
1272: case 3:
1273: power(pp);
1274: ct->vpp1 = power(pp);
1275: ct->vpp2 = power(pp);
1276: break;
1277: default:
1278: break;
1279: }
1280: if(feature&0x4)
1281: timing(pp, ct);
1282: if(feature&0x8)
1283: iospaces(pp, ct);
1284: if(feature&0x10)
1285: irq(pp, ct);
1286: switch((feature>>5)&0x3){
1287: case 1:
1288: memspace(pp, 0, 2, 0);
1289: break;
1290: case 2:
1291: memspace(pp, 2, 2, 0);
1292: break;
1293: case 3:
1294: if(readc(pp, &c) != 1)
1295: return;
1296: for(i = 0; i <= (c&0x7); i++)
1297: memspace(pp, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
1298: break;
1299: }
1300: pp->configed++;
1301: }
1302:
1303: void
1304: tvers1(Slot *pp, int ttype)
1305: {
1306: uchar c, major, minor;
1307: int i;
1308:
1309: USED(ttype);
1310: if(readc(pp, &major) != 1)
1311: return;
1312: if(readc(pp, &minor) != 1)
1313: return;
1314: for(i = 0; i < sizeof(pp->verstr)-1; i++){
1315: if(readc(pp, &c) != 1)
1316: return;
1317: if(c == 0)
1318: c = '\n';
1319: if(c == 0xff)
1320: break;
1321: pp->verstr[i] = c;
1322: }
1323: pp->verstr[i] = 0;
1324: }
1325:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.