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
9 /*
10 * Intel 82365SL PCIC controller and compatibles.
11 */
12 enum
13 {
14 /*
15 * registers indices
16 */
17 Rid= 0x0, /* identification and revision */
18 Ris= 0x1, /* interface status */
19 Rpc= 0x2, /* power control */
20 Foutena= (1<<7), /* output enable */
21 Fautopower= (1<<5), /* automatic power switching */
22 Fcardena= (1<<4), /* PC card enable */
23 Rigc= 0x3, /* interrupt and general control */
24 Fiocard= (1<<5), /* I/O card (vs memory) */
25 Fnotreset= (1<<6), /* reset if not set */
26 FSMIena= (1<<4), /* enable change interrupt on SMI */
27 Rcsc= 0x4, /* card status change */
28 Rcscic= 0x5, /* card status change interrupt config */
29 Fchangeena= (1<<3), /* card changed */
30 Fbwarnena= (1<<1), /* card battery warning */
31 Fbdeadena= (1<<0), /* card battery dead */
32 Rwe= 0x6, /* address window enable */
33 Fmem16= (1<<5), /* use A23-A12 to decode address */
34 Rio= 0x7, /* I/O control */
35 Fwidth16= (1<<0), /* 16 bit data width */
36 Fiocs16= (1<<1), /* IOCS16 determines data width */
37 Fzerows= (1<<2), /* zero wait state */
38 Ftiming= (1<<3), /* timing register to use */
39 Riobtm0lo= 0x8, /* I/O address 0 start low byte */
40 Riobtm0hi= 0x9, /* I/O address 0 start high byte */
41 Riotop0lo= 0xa, /* I/O address 0 stop low byte */
42 Riotop0hi= 0xb, /* I/O address 0 stop high byte */
43 Riobtm1lo= 0xc, /* I/O address 1 start low byte */
44 Riobtm1hi= 0xd, /* I/O address 1 start high byte */
45 Riotop1lo= 0xe, /* I/O address 1 stop low byte */
46 Riotop1hi= 0xf, /* I/O address 1 stop high byte */
47 Rmap= 0x10, /* map 0 */
48
49 /*
50 * CL-PD67xx extension registers
51 */
52 Rmisc1= 0x16, /* misc control 1 */
53 F5Vdetect= (1<<0),
54 Fvcc3V= (1<<1),
55 Fpmint= (1<<2),
56 Fpsirq= (1<<3),
57 Fspeaker= (1<<4),
58 Finpack= (1<<7),
59 Rfifo= 0x17, /* fifo control */
60 Fflush= (1<<7), /* flush fifo */
61 Rmisc2= 0x1E, /* misc control 2 */
62 Flowpow= (1<<1), /* low power mode */
63 Rchipinfo= 0x1F, /* chip information */
64 Ratactl= 0x26, /* ATA control */
65
66 /*
67 * offsets into the system memory address maps
68 */
69 Mbtmlo= 0x0, /* System mem addr mapping start low byte */
70 Mbtmhi= 0x1, /* System mem addr mapping start high byte */
71 F16bit= (1<<7), /* 16-bit wide data path */
72 Mtoplo= 0x2, /* System mem addr mapping stop low byte */
73 Mtophi= 0x3, /* System mem addr mapping stop high byte */
74 Ftimer1= (1<<6), /* timer set 1 */
75 Mofflo= 0x4, /* Card memory offset address low byte */
76 Moffhi= 0x5, /* Card memory offset address high byte */
77 Fregactive= (1<<6), /* attribute memory */
78
79 /*
80 * configuration registers - they start at an offset in attribute
81 * memory found in the CIS.
82 */
83 Rconfig= 0,
84 Creset= (1<<7), /* reset device */
85 Clevel= (1<<6), /* level sensitive interrupt line */
86 Cirq= (1<<2), /* IRQ enable */
87 Cdecode= (1<<1), /* address decode */
88 Cfunc= (1<<0), /* function enable */
89 Riobase0= 5,
90 Riobase1= 6,
91 Riosize= 9,
92 };
93
94 #define MAP(x,o) (Rmap + (x)*0x8 + o)
95
96 typedef struct I82365 I82365;
97
98 /* a controller */
99 enum
100 {
101 Ti82365,
102 Tpd6710,
103 Tpd6720,
104 Tvg46x,
105 };
106 struct I82365
107 {
108 int type;
109 int dev;
110 int nslot;
111 int xreg; /* index register address */
112 int dreg; /* data register address */
113 int irq;
114 };
115 static I82365 *controller[4];
116 static int ncontroller;
117 static PCMslot *slot;
118 static PCMslot *lastslot;
119 static nslot;
120
121 static void i82365intr(Ureg*, void*);
122 static int pcmio(int, ISAConf*);
123 static long pcmread(int, int, void*, long, vlong);
124 static long pcmwrite(int, int, void*, long, vlong);
125
126 static void i82365dump(PCMslot*);
127
128 /*
129 * reading and writing card registers
130 */
131 static uchar
rdreg(PCMslot * pp,int index)132 rdreg(PCMslot *pp, int index)
133 {
134 outb(((I82365*)pp->cp)->xreg, pp->base + index);
135 return inb(((I82365*)pp->cp)->dreg);
136 }
137 static void
wrreg(PCMslot * pp,int index,uchar val)138 wrreg(PCMslot *pp, int index, uchar val)
139 {
140 outb(((I82365*)pp->cp)->xreg, pp->base + index);
141 outb(((I82365*)pp->cp)->dreg, val);
142 }
143
144 /*
145 * get info about card
146 */
147 static void
slotinfo(PCMslot * pp)148 slotinfo(PCMslot *pp)
149 {
150 uchar isr;
151
152 isr = rdreg(pp, Ris);
153 pp->occupied = (isr & (3<<2)) == (3<<2);
154 pp->powered = isr & (1<<6);
155 pp->battery = (isr & 3) == 3;
156 pp->wrprot = isr & (1<<4);
157 pp->busy = isr & (1<<5);
158 pp->msec = TK2MS(MACHP(0)->ticks);
159 }
160
161 static int
vcode(int volt)162 vcode(int volt)
163 {
164 switch(volt){
165 case 5:
166 return 1;
167 case 12:
168 return 2;
169 default:
170 return 0;
171 }
172 }
173
174 /*
175 * enable the slot card
176 */
177 static void
slotena(PCMslot * pp)178 slotena(PCMslot *pp)
179 {
180 if(pp->enabled)
181 return;
182
183 /* power up and unreset, wait's are empirical (???) */
184 wrreg(pp, Rpc, Fautopower|Foutena|Fcardena);
185 delay(300);
186 wrreg(pp, Rigc, 0);
187 delay(100);
188 wrreg(pp, Rigc, Fnotreset);
189 delay(500);
190
191 /* get configuration */
192 slotinfo(pp);
193 if(pp->occupied){
194 pcmcisread(pp);
195 pp->enabled = 1;
196 } else
197 wrreg(pp, Rpc, Fautopower);
198 }
199
200 /*
201 * disable the slot card
202 */
203 static void
slotdis(PCMslot * pp)204 slotdis(PCMslot *pp)
205 {
206 wrreg(pp, Rpc, 0); /* turn off card power */
207 wrreg(pp, Rwe, 0); /* no windows */
208 pp->enabled = 0;
209 }
210
211 /*
212 * status change interrupt
213 */
214 static void
i82365intr(Ureg *,void *)215 i82365intr(Ureg *, void *)
216 {
217 uchar csc, was;
218 PCMslot *pp;
219
220 if(slot == 0)
221 return;
222
223 for(pp = slot; pp < lastslot; pp++){
224 csc = rdreg(pp, Rcsc);
225 was = pp->occupied;
226 slotinfo(pp);
227 if(csc & (1<<3) && was != pp->occupied){
228 if(!pp->occupied)
229 slotdis(pp);
230 }
231 }
232 }
233
234 enum
235 {
236 Mshift= 12,
237 Mgran= (1<<Mshift), /* granularity of maps */
238 Mmask= ~(Mgran-1), /* mask for address bits important to the chip */
239 };
240
241 /*
242 * get a map for pc card region, return corrected len
243 */
244 PCMmap*
pcmmap(int slotno,ulong offset,int len,int attr)245 pcmmap(int slotno, ulong offset, int len, int attr)
246 {
247 PCMslot *pp;
248 uchar we, bit;
249 PCMmap *m, *nm;
250 int i;
251 ulong e;
252
253 pp = slot + slotno;
254 lock(&pp->mlock);
255
256 /* convert offset to granularity */
257 if(len <= 0)
258 len = 1;
259 e = ROUND(offset+len, Mgran);
260 offset &= Mmask;
261 len = e - offset;
262
263 /* look for a map that covers the right area */
264 we = rdreg(pp, Rwe);
265 bit = 1;
266 nm = 0;
267 for(m = pp->mmap; m < &pp->mmap[nelem(pp->mmap)]; m++){
268 if((we & bit))
269 if(m->attr == attr)
270 if(offset >= m->ca && e <= m->cea){
271
272 m->ref++;
273 unlock(&pp->mlock);
274 return m;
275 }
276 bit <<= 1;
277 if(nm == 0 && m->ref == 0)
278 nm = m;
279 }
280 m = nm;
281 if(m == 0){
282 unlock(&pp->mlock);
283 return 0;
284 }
285
286 /* if isa space isn't big enough, free it and get more */
287 if(m->len < len){
288 if(m->isa){
289 umbfree(m->isa, m->len);
290 m->len = 0;
291 }
292 m->isa = PADDR(umbmalloc(0, len, Mgran));
293 if(m->isa == 0){
294 print("pcmmap: out of isa space\n");
295 unlock(&pp->mlock);
296 return 0;
297 }
298 m->len = len;
299 }
300
301 /* set up new map */
302 m->ca = offset;
303 m->cea = m->ca + m->len;
304 m->attr = attr;
305 i = m-pp->mmap;
306 bit = 1<<i;
307 wrreg(pp, Rwe, we & ~bit); /* disable map before changing it */
308 wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift);
309 wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
310 wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
311 wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
312 offset -= m->isa;
313 offset &= (1<<25)-1;
314 offset >>= Mshift;
315 wrreg(pp, MAP(i, Mofflo), offset);
316 wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
317 wrreg(pp, Rwe, we | bit); /* enable map */
318 m->ref = 1;
319
320 unlock(&pp->mlock);
321 return m;
322 }
323
324 void
pcmunmap(int slotno,PCMmap * m)325 pcmunmap(int slotno, PCMmap* m)
326 {
327 PCMslot *pp;
328
329 pp = slot + slotno;
330 lock(&pp->mlock);
331 m->ref--;
332 unlock(&pp->mlock);
333 }
334
335 static void
increfp(PCMslot * pp)336 increfp(PCMslot *pp)
337 {
338 lock(pp);
339 if(pp->ref++ == 0)
340 slotena(pp);
341 unlock(pp);
342 }
343
344 static void
decrefp(PCMslot * pp)345 decrefp(PCMslot *pp)
346 {
347 lock(pp);
348 if(pp->ref-- == 1)
349 slotdis(pp);
350 unlock(pp);
351 }
352
353 /*
354 * look for a card whose version contains 'idstr'
355 */
356 static int
pcmcia_pcmspecial(char * idstr,ISAConf * isa)357 pcmcia_pcmspecial(char *idstr, ISAConf *isa)
358 {
359 PCMslot *pp;
360 extern char *strstr(char*, char*);
361 int enabled;
362
363 for(pp = slot; pp < lastslot; pp++){
364 if(pp->special)
365 continue; /* already taken */
366
367 /*
368 * make sure we don't power on cards when we already know what's
369 * in them. We'll reread every two minutes if necessary
370 */
371 enabled = 0;
372 if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000){
373 increfp(pp);
374 enabled++;
375 }
376
377 if(pp->occupied) {
378 if(strstr(pp->verstr, idstr)){
379 if (!enabled){
380 enabled = 1;
381 increfp(pp);
382 }
383 if(isa == 0 || pcmio(pp->slotno, isa) == 0){
384 pp->special = 1;
385 return pp->slotno;
386 }
387 }
388 } else
389 pp->special = 1;
390 if (enabled)
391 decrefp(pp);
392 }
393 return -1;
394 }
395
396 static void
pcmcia_pcmspecialclose(int slotno)397 pcmcia_pcmspecialclose(int slotno)
398 {
399 PCMslot *pp;
400
401 if(slotno >= nslot)
402 panic("pcmspecialclose");
403 pp = slot + slotno;
404 pp->special = 0;
405 decrefp(pp);
406 }
407
408 enum
409 {
410 Qdir,
411 Qmem,
412 Qattr,
413 Qctl,
414
415 Nents = 3,
416 };
417
418 #define SLOTNO(c) ((ulong)((c->qid.path>>8)&0xff))
419 #define TYPE(c) ((ulong)(c->qid.path&0xff))
420 #define QID(s,t) (((s)<<8)|(t))
421
422 static int
pcmgen(Chan * c,char *,Dirtab *,int,int i,Dir * dp)423 pcmgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp)
424 {
425 int slotno;
426 Qid qid;
427 long len;
428 PCMslot *pp;
429
430 if(i == DEVDOTDOT){
431 mkqid(&qid, Qdir, 0, QTDIR);
432 devdir(c, qid, "#y", 0, eve, 0555, dp);
433 return 1;
434 }
435
436 if(i >= Nents*nslot)
437 return -1;
438 slotno = i/Nents;
439 pp = slot + slotno;
440 len = 0;
441 switch(i%Nents){
442 case 0:
443 qid.path = QID(slotno, Qmem);
444 snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
445 len = pp->memlen;
446 break;
447 case 1:
448 qid.path = QID(slotno, Qattr);
449 snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
450 len = pp->memlen;
451 break;
452 case 2:
453 qid.path = QID(slotno, Qctl);
454 snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
455 break;
456 }
457 qid.vers = 0;
458 qid.type = QTFILE;
459 devdir(c, qid, up->genbuf, len, eve, 0660, dp);
460 return 1;
461 }
462
463 static char *chipname[] =
464 {
465 [Ti82365] "Intel 82365SL",
466 [Tpd6710] "Cirrus Logic CL-PD6710",
467 [Tpd6720] "Cirrus Logic CL-PD6720",
468 [Tvg46x] "Vadem VG-46x",
469 };
470
471 static I82365*
i82365probe(int x,int d,int dev)472 i82365probe(int x, int d, int dev)
473 {
474 uchar c, id;
475 I82365 *cp;
476 ISAConf isa;
477 int i, nslot;
478
479 outb(x, Rid + (dev<<7));
480 id = inb(d);
481 if((id & 0xf0) != 0x80)
482 return 0; /* not a memory & I/O card */
483 if((id & 0x0f) == 0x00)
484 return 0; /* no revision number, not possible */
485
486 cp = xalloc(sizeof(I82365));
487 cp->xreg = x;
488 cp->dreg = d;
489 cp->dev = dev;
490 cp->type = Ti82365;
491 cp->nslot = 2;
492
493 switch(id){
494 case 0x82:
495 case 0x83:
496 case 0x84:
497 /* could be a cirrus */
498 outb(x, Rchipinfo + (dev<<7));
499 outb(d, 0);
500 c = inb(d);
501 if((c & 0xc0) != 0xc0)
502 break;
503 c = inb(d);
504 if((c & 0xc0) != 0x00)
505 break;
506 if(c & 0x20){
507 cp->type = Tpd6720;
508 } else {
509 cp->type = Tpd6710;
510 cp->nslot = 1;
511 }
512
513 /* low power mode */
514 outb(x, Rmisc2 + (dev<<7));
515 c = inb(d);
516 outb(d, c & ~Flowpow);
517 break;
518 }
519
520 /* if it's not a Cirrus, it could be a Vadem... */
521 if(cp->type == Ti82365){
522 /* unlock the Vadem extended regs */
523 outb(x, 0x0E + (dev<<7));
524 outb(x, 0x37 + (dev<<7));
525
526 /* make the id register show the Vadem id */
527 outb(x, 0x3A + (dev<<7));
528 c = inb(d);
529 outb(d, c|0xC0);
530 outb(x, Rid + (dev<<7));
531 c = inb(d);
532 if(c & 0x08)
533 cp->type = Tvg46x;
534
535 /* go back to Intel compatible id */
536 outb(x, 0x3A + (dev<<7));
537 c = inb(d);
538 outb(d, c & ~0xC0);
539 }
540
541 memset(&isa, 0, sizeof(ISAConf));
542 if(isaconfig("pcmcia", ncontroller, &isa) && isa.irq)
543 cp->irq = isa.irq;
544 else
545 cp->irq = IrqPCMCIA;
546
547 for(i = 0; i < isa.nopt; i++){
548 if(cistrncmp(isa.opt[i], "nslot=", 6))
549 continue;
550 nslot = strtol(&isa.opt[i][6], nil, 0);
551 if(nslot > 0 && nslot <= 2)
552 cp->nslot = nslot;
553 }
554
555 controller[ncontroller++] = cp;
556 return cp;
557 }
558
559 static void
i82365dump(PCMslot * pp)560 i82365dump(PCMslot *pp)
561 {
562 int i;
563
564 for(i = 0; i < 0x40; i++){
565 if((i&0x0F) == 0)
566 print("\n%2.2uX: ", i);
567 print("%2.2uX ", rdreg(pp, i));
568 if(((i+1) & 0x0F) == 0x08)
569 print(" - ");
570 }
571 print("\n");
572 }
573
574 /*
575 * set up for slot cards
576 */
577 void
devi82365link(void)578 devi82365link(void)
579 {
580 static int already;
581 int i, j;
582 I82365 *cp;
583 PCMslot *pp;
584 char buf[32], *p;
585
586 if(already)
587 return;
588 already = 1;
589
590 if((p=getconf("pcmcia0")) && strncmp(p, "disabled", 8)==0)
591 return;
592
593 if(_pcmspecial)
594 return;
595
596 /* look for controllers if the ports aren't already taken */
597 if(ioalloc(0x3E0, 2, 0, "i82365.0") >= 0){
598 i82365probe(0x3E0, 0x3E1, 0);
599 i82365probe(0x3E0, 0x3E1, 1);
600 if(ncontroller == 0)
601 iofree(0x3E0);
602 }
603 if(ioalloc(0x3E2, 2, 0, "i82365.1") >= 0){
604 i = ncontroller;
605 i82365probe(0x3E2, 0x3E3, 0);
606 i82365probe(0x3E2, 0x3E3, 1);
607 if(ncontroller == i)
608 iofree(0x3E2);
609 }
610
611 if(ncontroller == 0)
612 return;
613
614 _pcmspecial = pcmcia_pcmspecial;
615 _pcmspecialclose = pcmcia_pcmspecialclose;
616
617 for(i = 0; i < ncontroller; i++)
618 nslot += controller[i]->nslot;
619 slot = xalloc(nslot * sizeof(PCMslot));
620
621 lastslot = slot;
622 for(i = 0; i < ncontroller; i++){
623 cp = controller[i];
624 print("#y%d: %d slot %s: port 0x%uX irq %d\n",
625 i, cp->nslot, chipname[cp->type], cp->xreg, cp->irq);
626 for(j = 0; j < cp->nslot; j++){
627 pp = lastslot++;
628 pp->slotno = pp - slot;
629 pp->memlen = 64*MB;
630 pp->base = (cp->dev<<7) | (j<<6);
631 pp->cp = cp;
632 pp->msec = ~0;
633 pp->verstr[0] = 0;
634 slotdis(pp);
635
636 /* interrupt on status change */
637 wrreg(pp, Rcscic, (cp->irq<<4) | Fchangeena);
638 rdreg(pp, Rcsc);
639 }
640
641 /* for card management interrupts */
642 snprint(buf, sizeof buf, "i82365.%d", i);
643 intrenable(cp->irq, i82365intr, 0, BUSUNKNOWN, buf);
644 }
645 }
646
647 static Chan*
i82365attach(char * spec)648 i82365attach(char *spec)
649 {
650 return devattach('y', spec);
651 }
652
653 static Walkqid*
i82365walk(Chan * c,Chan * nc,char ** name,int nname)654 i82365walk(Chan *c, Chan *nc, char **name, int nname)
655 {
656 return devwalk(c, nc, name, nname, 0, 0, pcmgen);
657 }
658
659 static int
i82365stat(Chan * c,uchar * db,int n)660 i82365stat(Chan *c, uchar *db, int n)
661 {
662 return devstat(c, db, n, 0, 0, pcmgen);
663 }
664
665 static Chan*
i82365open(Chan * c,int omode)666 i82365open(Chan *c, int omode)
667 {
668 if(c->qid.type & QTDIR){
669 if(omode != OREAD)
670 error(Eperm);
671 } else
672 increfp(slot + SLOTNO(c));
673 c->mode = openmode(omode);
674 c->flag |= COPEN;
675 c->offset = 0;
676 return c;
677 }
678
679 static void
i82365close(Chan * c)680 i82365close(Chan *c)
681 {
682 if(c->flag & COPEN)
683 if((c->qid.type & QTDIR) == 0)
684 decrefp(slot+SLOTNO(c));
685 }
686
687 /* a memmove using only bytes */
688 static void
memmoveb(uchar * to,uchar * from,int n)689 memmoveb(uchar *to, uchar *from, int n)
690 {
691 while(n-- > 0)
692 *to++ = *from++;
693 }
694
695 /* a memmove using only shorts & bytes */
696 static void
memmoves(uchar * to,uchar * from,int n)697 memmoves(uchar *to, uchar *from, int n)
698 {
699 ushort *t, *f;
700
701 if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
702 while(n-- > 0)
703 *to++ = *from++;
704 } else {
705 n = n/2;
706 t = (ushort*)to;
707 f = (ushort*)from;
708 while(n-- > 0)
709 *t++ = *f++;
710 }
711 }
712
713 static long
pcmread(int slotno,int attr,void * a,long n,vlong off)714 pcmread(int slotno, int attr, void *a, long n, vlong off)
715 {
716 int i, len;
717 PCMmap *m;
718 uchar *ac;
719 PCMslot *pp;
720 ulong offset = off;
721
722 pp = slot + slotno;
723 if(pp->memlen < offset)
724 return 0;
725 if(pp->memlen < offset + n)
726 n = pp->memlen - offset;
727
728 m = 0;
729 if(waserror()){
730 if(m)
731 pcmunmap(pp->slotno, m);
732 nexterror();
733 }
734
735 ac = a;
736 for(len = n; len > 0; len -= i){
737 m = pcmmap(pp->slotno, offset, 0, attr);
738 if(m == 0)
739 error("cannot map PCMCIA card");
740 if(offset + len > m->cea)
741 i = m->cea - offset;
742 else
743 i = len;
744 memmoveb(ac, KADDR(m->isa + offset - m->ca), i);
745 pcmunmap(pp->slotno, m);
746 offset += i;
747 ac += i;
748 }
749
750 poperror();
751 return n;
752 }
753
754 static long
i82365read(Chan * c,void * a,long n,vlong off)755 i82365read(Chan *c, void *a, long n, vlong off)
756 {
757 char *p, *buf, *e;
758 PCMslot *pp;
759 ulong offset = off;
760
761 switch(TYPE(c)){
762 case Qdir:
763 return devdirread(c, a, n, 0, 0, pcmgen);
764 case Qmem:
765 case Qattr:
766 return pcmread(SLOTNO(c), TYPE(c) == Qattr, a, n, off);
767 case Qctl:
768 buf = p = malloc(READSTR);
769 if(p == nil)
770 error(Enomem);
771 e = p + READSTR;
772 pp = slot + SLOTNO(c);
773
774 buf[0] = 0;
775 if(pp->occupied){
776 p = seprint(p, e, "occupied\n");
777 if(pp->verstr[0])
778 p = seprint(p, e, "version %s\n", pp->verstr);
779 }
780 if(pp->enabled)
781 p = seprint(p, e, "enabled\n");
782 if(pp->powered)
783 p = seprint(p, e, "powered\n");
784 if(pp->configed)
785 p = seprint(p, e, "configed\n");
786 if(pp->wrprot)
787 p = seprint(p, e, "write protected\n");
788 if(pp->busy)
789 p = seprint(p, e, "busy\n");
790 seprint(p, e, "battery lvl %d\n", pp->battery);
791
792 n = readstr(offset, a, n, buf);
793 free(buf);
794
795 return n;
796 }
797 error(Ebadarg);
798 return -1; /* not reached */
799 }
800
801 static long
pcmwrite(int dev,int attr,void * a,long n,vlong off)802 pcmwrite(int dev, int attr, void *a, long n, vlong off)
803 {
804 int i, len;
805 PCMmap *m;
806 uchar *ac;
807 PCMslot *pp;
808 ulong offset = off;
809
810 pp = slot + dev;
811 if(pp->memlen < offset)
812 return 0;
813 if(pp->memlen < offset + n)
814 n = pp->memlen - offset;
815
816 m = 0;
817 if(waserror()){
818 if(m)
819 pcmunmap(pp->slotno, m);
820 nexterror();
821 }
822
823 ac = a;
824 for(len = n; len > 0; len -= i){
825 m = pcmmap(pp->slotno, offset, 0, attr);
826 if(m == 0)
827 error("cannot map PCMCIA card");
828 if(offset + len > m->cea)
829 i = m->cea - offset;
830 else
831 i = len;
832 memmoveb(KADDR(m->isa + offset - m->ca), ac, i);
833 pcmunmap(pp->slotno, m);
834 offset += i;
835 ac += i;
836 }
837
838 poperror();
839 return n;
840 }
841
842 static long
i82365write(Chan * c,void * a,long n,vlong off)843 i82365write(Chan *c, void *a, long n, vlong off)
844 {
845 PCMslot *pp;
846 char buf[32];
847
848 switch(TYPE(c)){
849 case Qctl:
850 if(n >= sizeof(buf))
851 n = sizeof(buf) - 1;
852 strncpy(buf, a, n);
853 buf[n] = 0;
854 pp = slot + SLOTNO(c);
855 if(!pp->occupied)
856 error(Eio);
857
858 /* set vpp on card */
859 if(strncmp(buf, "vpp", 3) == 0)
860 wrreg(pp, Rpc, vcode(atoi(buf+3))|Fautopower|Foutena|Fcardena);
861 return n;
862 case Qmem:
863 case Qattr:
864 pp = slot + SLOTNO(c);
865 if(pp->occupied == 0 || pp->enabled == 0)
866 error(Eio);
867 n = pcmwrite(pp->slotno, TYPE(c) == Qattr, a, n, off);
868 if(n < 0)
869 error(Eio);
870 return n;
871 }
872 error(Ebadarg);
873 return -1; /* not reached */
874 }
875
876 Dev i82365devtab = {
877 'y',
878 "i82365",
879
880 devreset,
881 devinit,
882 devshutdown,
883 i82365attach,
884 i82365walk,
885 i82365stat,
886 i82365open,
887 devcreate,
888 i82365close,
889 i82365read,
890 devbread,
891 i82365write,
892 devbwrite,
893 devremove,
894 devwstat,
895 };
896
897 /*
898 * configure the PCMslot for IO. We assume very heavily that we can read
899 * configuration info from the CIS. If not, we won't set up correctly.
900 */
901 static int
pcmio(int slotno,ISAConf * isa)902 pcmio(int slotno, ISAConf *isa)
903 {
904 uchar we, x, *p;
905 PCMslot *pp;
906 PCMconftab *ct, *et, *t;
907 PCMmap *m;
908 int i, index, irq;
909 char *cp;
910
911 irq = isa->irq;
912 if(irq == 2)
913 irq = 9;
914
915 if(slotno > nslot)
916 return -1;
917 pp = slot + slotno;
918
919 if(!pp->occupied)
920 return -1;
921
922 et = &pp->ctab[pp->nctab];
923
924 ct = 0;
925 for(i = 0; i < isa->nopt; i++){
926 if(strncmp(isa->opt[i], "index=", 6))
927 continue;
928 index = strtol(&isa->opt[i][6], &cp, 0);
929 if(cp == &isa->opt[i][6] || index >= pp->nctab)
930 return -1;
931 ct = &pp->ctab[index];
932 }
933
934 if(ct == 0){
935 /* assume default is right */
936 if(pp->def)
937 ct = pp->def;
938 else
939 ct = pp->ctab;
940
941 /* try for best match */
942 if(ct->nio == 0
943 || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
944 for(t = pp->ctab; t < et; t++)
945 if(t->nio
946 && t->io[0].start == isa->port
947 && ((1<<irq) & t->irqs)){
948 ct = t;
949 break;
950 }
951 }
952 if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
953 for(t = pp->ctab; t < et; t++)
954 if(t->nio && ((1<<irq) & t->irqs)){
955 ct = t;
956 break;
957 }
958 }
959 if(ct->nio == 0){
960 for(t = pp->ctab; t < et; t++)
961 if(t->nio){
962 ct = t;
963 break;
964 }
965 }
966 }
967
968 if(ct == et || ct->nio == 0)
969 return -1;
970 if(isa->port == 0 && ct->io[0].start == 0)
971 return -1;
972
973 /* route interrupts */
974 isa->irq = irq;
975 wrreg(pp, Rigc, irq | Fnotreset | Fiocard);
976
977 /* set power and enable device */
978 x = vcode(ct->vpp1);
979 wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena);
980
981 /* 16-bit data path */
982 if(ct->bit16)
983 x = Ftiming|Fiocs16|Fwidth16;
984 else
985 x = Ftiming;
986 if(ct->nio == 2 && ct->io[1].start)
987 x |= x<<4;
988 wrreg(pp, Rio, x);
989
990 /*
991 * enable io port map 0
992 * the 'top' register value includes the last valid address
993 */
994 if(isa->port == 0)
995 isa->port = ct->io[0].start;
996 we = rdreg(pp, Rwe);
997 wrreg(pp, Riobtm0lo, isa->port);
998 wrreg(pp, Riobtm0hi, isa->port>>8);
999 i = isa->port+ct->io[0].len-1;
1000 wrreg(pp, Riotop0lo, i);
1001 wrreg(pp, Riotop0hi, i>>8);
1002 we |= 1<<6;
1003 if(ct->nio >= 2 && ct->io[1].start){
1004 wrreg(pp, Riobtm1lo, ct->io[1].start);
1005 wrreg(pp, Riobtm1hi, ct->io[1].start>>8);
1006 i = ct->io[1].start+ct->io[1].len-1;
1007 wrreg(pp, Riotop1lo, i);
1008 wrreg(pp, Riotop1hi, i>>8);
1009 we |= 1<<7;
1010 }
1011 wrreg(pp, Rwe, we);
1012
1013 /* only touch Rconfig if it is present */
1014 m = pcmmap(slotno, pp->cfg[0].caddr + Rconfig, 0x20, 1);
1015 p = KADDR(m->isa + pp->cfg[0].caddr - m->ca);
1016 if(pp->cfg[0].cpresent & (1<<Rconfig)){
1017 /* Reset adapter */
1018
1019 /* set configuration and interrupt type.
1020 * if level is possible on the card, use it.
1021 */
1022 x = ct->index;
1023 if(ct->irqtype & 0x20)
1024 x |= Clevel;
1025
1026 /* enable the device, enable address decode and
1027 * irq enable.
1028 */
1029 x |= Cfunc|Cdecode|Cirq;
1030
1031 p[0] = x;
1032 //delay(5);
1033 microdelay(40);
1034 }
1035
1036 if(pp->cfg[0].cpresent & (1<<Riobase0)){
1037 /* set up the iobase 0 */
1038 p[Riobase0 << 1] = isa->port;
1039 p[Riobase1 << 1] = isa->port >> 8;
1040 }
1041
1042 if(pp->cfg[0].cpresent & (1<<Riosize))
1043 p[Riosize << 1] = ct->io[0].len;
1044 pcmunmap(slotno, m);
1045 return 0;
1046 }
1047