FreeBSD/Linux Kernel Cross Reference
sys/pc/devi82365.c
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
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
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
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
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
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
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
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*
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
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
336 increfp(PCMslot *pp)
337 {
338 lock(pp);
339 if(pp->ref++ == 0)
340 slotena(pp);
341 unlock(pp);
342 }
343
344 static void
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
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
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
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*
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
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
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*
648 i82365attach(char *spec)
649 {
650 return devattach('y', spec);
651 }
652
653 static Walkqid*
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
660 i82365stat(Chan *c, uchar *db, int n)
661 {
662 return devstat(c, db, n, 0, 0, pcmgen);
663 }
664
665 static Chan*
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
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
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
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
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
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 e = p + READSTR;
770 pp = slot + SLOTNO(c);
771
772 buf[0] = 0;
773 if(pp->occupied){
774 p = seprint(p, e, "occupied\n");
775 if(pp->verstr[0])
776 p = seprint(p, e, "version %s\n", pp->verstr);
777 }
778 if(pp->enabled)
779 p = seprint(p, e, "enabled\n");
780 if(pp->powered)
781 p = seprint(p, e, "powered\n");
782 if(pp->configed)
783 p = seprint(p, e, "configed\n");
784 if(pp->wrprot)
785 p = seprint(p, e, "write protected\n");
786 if(pp->busy)
787 p = seprint(p, e, "busy\n");
788 seprint(p, e, "battery lvl %d\n", pp->battery);
789
790 n = readstr(offset, a, n, buf);
791 free(buf);
792
793 return n;
794 }
795 error(Ebadarg);
796 return -1; /* not reached */
797 }
798
799 static long
800 pcmwrite(int dev, int attr, void *a, long n, vlong off)
801 {
802 int i, len;
803 PCMmap *m;
804 uchar *ac;
805 PCMslot *pp;
806 ulong offset = off;
807
808 pp = slot + dev;
809 if(pp->memlen < offset)
810 return 0;
811 if(pp->memlen < offset + n)
812 n = pp->memlen - offset;
813
814 m = 0;
815 if(waserror()){
816 if(m)
817 pcmunmap(pp->slotno, m);
818 nexterror();
819 }
820
821 ac = a;
822 for(len = n; len > 0; len -= i){
823 m = pcmmap(pp->slotno, offset, 0, attr);
824 if(m == 0)
825 error("cannot map PCMCIA card");
826 if(offset + len > m->cea)
827 i = m->cea - offset;
828 else
829 i = len;
830 memmoveb(KADDR(m->isa + offset - m->ca), ac, i);
831 pcmunmap(pp->slotno, m);
832 offset += i;
833 ac += i;
834 }
835
836 poperror();
837 return n;
838 }
839
840 static long
841 i82365write(Chan *c, void *a, long n, vlong off)
842 {
843 PCMslot *pp;
844 char buf[32];
845
846 switch(TYPE(c)){
847 case Qctl:
848 if(n >= sizeof(buf))
849 n = sizeof(buf) - 1;
850 strncpy(buf, a, n);
851 buf[n] = 0;
852 pp = slot + SLOTNO(c);
853 if(!pp->occupied)
854 error(Eio);
855
856 /* set vpp on card */
857 if(strncmp(buf, "vpp", 3) == 0)
858 wrreg(pp, Rpc, vcode(atoi(buf+3))|Fautopower|Foutena|Fcardena);
859 return n;
860 case Qmem:
861 case Qattr:
862 pp = slot + SLOTNO(c);
863 if(pp->occupied == 0 || pp->enabled == 0)
864 error(Eio);
865 n = pcmwrite(pp->slotno, TYPE(c) == Qattr, a, n, off);
866 if(n < 0)
867 error(Eio);
868 return n;
869 }
870 error(Ebadarg);
871 return -1; /* not reached */
872 }
873
874 Dev i82365devtab = {
875 'y',
876 "i82365",
877
878 devreset,
879 devinit,
880 devshutdown,
881 i82365attach,
882 i82365walk,
883 i82365stat,
884 i82365open,
885 devcreate,
886 i82365close,
887 i82365read,
888 devbread,
889 i82365write,
890 devbwrite,
891 devremove,
892 devwstat,
893 };
894
895 /*
896 * configure the PCMslot for IO. We assume very heavily that we can read
897 * configuration info from the CIS. If not, we won't set up correctly.
898 */
899 static int
900 pcmio(int slotno, ISAConf *isa)
901 {
902 uchar we, x, *p;
903 PCMslot *pp;
904 PCMconftab *ct, *et, *t;
905 PCMmap *m;
906 int i, index, irq;
907 char *cp;
908
909 irq = isa->irq;
910 if(irq == 2)
911 irq = 9;
912
913 if(slotno > nslot)
914 return -1;
915 pp = slot + slotno;
916
917 if(!pp->occupied)
918 return -1;
919
920 et = &pp->ctab[pp->nctab];
921
922 ct = 0;
923 for(i = 0; i < isa->nopt; i++){
924 if(strncmp(isa->opt[i], "index=", 6))
925 continue;
926 index = strtol(&isa->opt[i][6], &cp, 0);
927 if(cp == &isa->opt[i][6] || index >= pp->nctab)
928 return -1;
929 ct = &pp->ctab[index];
930 }
931
932 if(ct == 0){
933 /* assume default is right */
934 if(pp->def)
935 ct = pp->def;
936 else
937 ct = pp->ctab;
938
939 /* try for best match */
940 if(ct->nio == 0
941 || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
942 for(t = pp->ctab; t < et; t++)
943 if(t->nio
944 && t->io[0].start == isa->port
945 && ((1<<irq) & t->irqs)){
946 ct = t;
947 break;
948 }
949 }
950 if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
951 for(t = pp->ctab; t < et; t++)
952 if(t->nio && ((1<<irq) & t->irqs)){
953 ct = t;
954 break;
955 }
956 }
957 if(ct->nio == 0){
958 for(t = pp->ctab; t < et; t++)
959 if(t->nio){
960 ct = t;
961 break;
962 }
963 }
964 }
965
966 if(ct == et || ct->nio == 0)
967 return -1;
968 if(isa->port == 0 && ct->io[0].start == 0)
969 return -1;
970
971 /* route interrupts */
972 isa->irq = irq;
973 wrreg(pp, Rigc, irq | Fnotreset | Fiocard);
974
975 /* set power and enable device */
976 x = vcode(ct->vpp1);
977 wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena);
978
979 /* 16-bit data path */
980 if(ct->bit16)
981 x = Ftiming|Fiocs16|Fwidth16;
982 else
983 x = Ftiming;
984 if(ct->nio == 2 && ct->io[1].start)
985 x |= x<<4;
986 wrreg(pp, Rio, x);
987
988 /*
989 * enable io port map 0
990 * the 'top' register value includes the last valid address
991 */
992 if(isa->port == 0)
993 isa->port = ct->io[0].start;
994 we = rdreg(pp, Rwe);
995 wrreg(pp, Riobtm0lo, isa->port);
996 wrreg(pp, Riobtm0hi, isa->port>>8);
997 i = isa->port+ct->io[0].len-1;
998 wrreg(pp, Riotop0lo, i);
999 wrreg(pp, Riotop0hi, i>>8);
1000 we |= 1<<6;
1001 if(ct->nio >= 2 && ct->io[1].start){
1002 wrreg(pp, Riobtm1lo, ct->io[1].start);
1003 wrreg(pp, Riobtm1hi, ct->io[1].start>>8);
1004 i = ct->io[1].start+ct->io[1].len-1;
1005 wrreg(pp, Riotop1lo, i);
1006 wrreg(pp, Riotop1hi, i>>8);
1007 we |= 1<<7;
1008 }
1009 wrreg(pp, Rwe, we);
1010
1011 /* only touch Rconfig if it is present */
1012 m = pcmmap(slotno, pp->cfg[0].caddr + Rconfig, 0x20, 1);
1013 p = KADDR(m->isa + pp->cfg[0].caddr - m->ca);
1014 if(pp->cfg[0].cpresent & (1<<Rconfig)){
1015 /* Reset adapter */
1016
1017 /* set configuration and interrupt type.
1018 * if level is possible on the card, use it.
1019 */
1020 x = ct->index;
1021 if(ct->irqtype & 0x20)
1022 x |= Clevel;
1023
1024 /* enable the device, enable address decode and
1025 * irq enable.
1026 */
1027 x |= Cfunc|Cdecode|Cirq;
1028
1029 p[0] = x;
1030 //delay(5);
1031 microdelay(40);
1032 }
1033
1034 if(pp->cfg[0].cpresent & (1<<Riobase0)){
1035 /* set up the iobase 0 */
1036 p[Riobase0 << 1] = isa->port;
1037 p[Riobase1 << 1] = isa->port >> 8;
1038 }
1039
1040 if(pp->cfg[0].cpresent & (1<<Riosize))
1041 p[Riosize << 1] = ct->io[0].len;
1042 pcmunmap(slotno, m);
1043 return 0;
1044 }
Cache object: 6bcd9182ea4349ef6d2abb3709e9bdbc
|