FreeBSD/Linux Kernel Cross Reference
sys/bitsy/devpcmcia.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 * BUG: insertion events are detected by polling.
11 * Should look into the compaq docs to see if
12 * there's an interrupt for card insertion
13 * there's probably one.
14 */
15
16 static PCMslot slot[2];
17 int nslot = 2;
18
19 struct {
20 Ref;
21 Rendez event; // where to wait for card events
22 int evreader; // there's a reader for events
23 } pcmcia;
24
25 enum
26 {
27 Qdir,
28 Qmem,
29 Qattr,
30 Qctl,
31 Qevs,
32
33 Nents = 3,
34 };
35
36 enum
37 {
38 /*
39 * configuration registers - they start at an offset in attribute
40 * memory found in the CIS.
41 */
42 Rconfig= 0,
43 Creset= (1<<7), /* reset device */
44 Clevel= (1<<6), /* level sensitive interrupt line */
45 };
46
47 static void increfp(PCMslot*);
48 static void decrefp(PCMslot*);
49 static void slotmap(int, ulong, ulong, ulong);
50 static void slottiming(int, int, int, int, int);
51 static void slotinfo(Ureg*, void*);
52
53 #define TYPE(c) (((ulong)c->qid.path)&0xff)
54 #define PATH(s,t) (((s)<<8)|(t))
55
56 static PCMslot*
57 slotof(Chan *c)
58 {
59 ulong x;
60
61 x = c->qid.path;
62 return slot + ((x>>8)&0xff);
63 }
64
65 static int
66 pcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp)
67 {
68 int slotno;
69 Qid qid;
70 long len;
71 PCMslot *sp;
72
73 if(i == DEVDOTDOT){
74 mkqid(&qid, Qdir, 0, QTDIR);
75 devdir(c, qid, "#y", 0, eve, 0555, dp);
76 return 1;
77 }
78
79 if(i >= Nents*nslot + 1)
80 return -1;
81 if(i == Nents*nslot){
82 len = 0;
83 qid.path = PATH(0, Qevs);
84 snprint(up->genbuf, sizeof up->genbuf, "pcmevs");
85 goto found;
86 }
87
88 slotno = i/Nents;
89 sp = slot + slotno;
90 len = 0;
91 switch(i%Nents){
92 case 0:
93 qid.path = PATH(slotno, Qmem);
94 snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
95 len = sp->memlen;
96 break;
97 case 1:
98 qid.path = PATH(slotno, Qattr);
99 snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
100 len = sp->memlen;
101 break;
102 case 2:
103 qid.path = PATH(slotno, Qctl);
104 snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
105 break;
106 }
107 found:
108 qid.vers = 0;
109 qid.type = QTFILE;
110 devdir(c, qid, up->genbuf, len, eve, 0660, dp);
111 return 1;
112 }
113
114 static int
115 bitno(ulong x)
116 {
117 int i;
118
119 for(i = 0; i < 8*sizeof(x); i++)
120 if((1<<i) & x)
121 break;
122 return i;
123 }
124
125 /*
126 * set up the cards, default timing is 300 ns
127 */
128 static void
129 pcmciareset(void)
130 {
131 /* staticly map the whole area */
132 slotmap(0, PHYSPCM0REGS, PYHSPCM0ATTR, PYHSPCM0MEM);
133 slotmap(1, PHYSPCM1REGS, PYHSPCM1ATTR, PYHSPCM1MEM);
134
135 /* set timing to the default, 300 */
136 slottiming(0, 300, 300, 300, 0);
137 slottiming(1, 300, 300, 300, 0);
138
139 /* if there's no pcmcia sleave, no interrupts */
140 if(gpioregs->level & GPIO_OPT_IND_i)
141 return;
142
143 /* sleave there, interrupt on card removal */
144 intrenable(GPIOrising, bitno(GPIO_CARD_IND1_i), slotinfo, nil, "pcmcia slot1 status");
145 intrenable(GPIOrising, bitno(GPIO_CARD_IND0_i), slotinfo, nil, "pcmcia slot0 status");
146 }
147
148 static Chan*
149 pcmciaattach(char *spec)
150 {
151 return devattach('y', spec);
152 }
153
154 static Walkqid*
155 pcmciawalk(Chan *c, Chan *nc, char **name, int nname)
156 {
157 return devwalk(c, nc, name, nname, 0, 0, pcmgen);
158 }
159
160 static int
161 pcmciastat(Chan *c, uchar *db, int n)
162 {
163 return devstat(c, db, n, 0, 0, pcmgen);
164 }
165
166 static Chan*
167 pcmciaopen(Chan *c, int omode)
168 {
169 PCMslot *slotp;
170
171 if(c->qid.type & QTDIR){
172 if(omode != OREAD)
173 error(Eperm);
174 } else {
175 slotp = slotof(c);
176 increfp(slotp);
177 }
178 c->mode = openmode(omode);
179 c->flag |= COPEN;
180 c->offset = 0;
181 return c;
182 }
183
184 static void
185 pcmciaclose(Chan *c)
186 {
187 if(c->flag & COPEN)
188 if((c->qid.type & QTDIR) == 0)
189 decrefp(slotof(c));
190 }
191
192 /* a memmove using only bytes */
193 static void
194 memmoveb(uchar *to, uchar *from, int n)
195 {
196 while(n-- > 0)
197 *to++ = *from++;
198 }
199
200 /* a memmove using only shorts & bytes */
201 static void
202 memmoves(uchar *to, uchar *from, int n)
203 {
204 ushort *t, *f;
205
206 if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
207 while(n-- > 0)
208 *to++ = *from++;
209 } else {
210 n = n/2;
211 t = (ushort*)to;
212 f = (ushort*)from;
213 while(n-- > 0)
214 *t++ = *f++;
215 }
216 }
217
218 static long
219 pcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
220 {
221 rlock(sp);
222 if(waserror()){
223 runlock(sp);
224 nexterror();
225 }
226 if(off > len)
227 return 0;
228 if(off + n > len)
229 n = len - off;
230 memmoveb(a, start+off, n);
231 runlock(sp);
232 poperror();
233 return n;
234 }
235
236 static long
237 pcmctlread(void *a, long n, ulong off, PCMslot *sp)
238 {
239 char *p, *buf, *e;
240
241 buf = p = malloc(READSTR);
242 if(waserror()){
243 free(buf);
244 nexterror();
245 }
246 e = p + READSTR;
247
248 buf[0] = 0;
249 if(sp->occupied){
250 p = seprint(p, e, "occupied\n");
251 if(sp->verstr[0])
252 p = seprint(p, e, "version %s\n", sp->verstr);
253 }
254 USED(p);
255
256 n = readstr(off, a, n, buf);
257 free(buf);
258 poperror();
259 return n;
260 }
261
262 static int
263 inserted(void *)
264 {
265 if (slot[0].inserted)
266 return 1;
267 if (slot[1].inserted)
268 return 2;
269 return 0;
270 }
271
272 static long
273 pcmevsread(void *a, long n, ulong off)
274 {
275 int i;
276 char *buf = nil;
277 char *e;
278
279 if (pcmcia.evreader)
280 error("At most one reader");
281 off = 0;
282 pcmcia.evreader++;
283 if (waserror()){
284 free(buf);
285 pcmcia.evreader--;
286 nexterror();
287 }
288 while((i = inserted(nil)) == 0){
289 slotinfo(nil, nil);
290 tsleep(&pcmcia.event, inserted, nil, 500);
291 }
292 pcmcia.evreader--;
293 slot[i-1].inserted = 0;
294 buf = malloc(READSTR);
295 e = buf + READSTR;
296 buf[0] = 0;
297 seprint(buf, e, "#y/pcm%dctl\n", i-1);
298 n = readstr(off, a, n, buf);
299 free(buf);
300 poperror();
301 return n;
302 }
303
304 static long
305 pcmciaread(Chan *c, void *a, long n, vlong off)
306 {
307 PCMslot *sp;
308 ulong offset = off;
309
310 sp = slotof(c);
311
312 switch(TYPE(c)){
313 case Qdir:
314 return devdirread(c, a, n, 0, 0, pcmgen);
315 case Qmem:
316 if(!sp->occupied)
317 error(Eio);
318 return pcmread(a, n, offset, sp, sp->mem, 64*OneMeg);
319 case Qattr:
320 if(!sp->occupied)
321 error(Eio);
322 return pcmread(a, n, offset, sp, sp->attr, OneMeg);
323 case Qevs:
324 return pcmevsread(a, n, offset);
325 case Qctl:
326 return pcmctlread(a, n, offset, sp);
327 }
328 error(Ebadarg);
329 return -1; /* not reached */
330 }
331
332 static long
333 pcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
334 {
335 rlock(sp);
336 if(waserror()){
337 runlock(sp);
338 nexterror();
339 }
340 if(off > len)
341 error(Eio);
342 if(off + n > len)
343 error(Eio);
344 memmoveb(start+off, a, n);
345 poperror();
346 runlock(sp);
347 return n;
348 }
349
350 static long
351 pcmctlwrite(char *p, long n, ulong, PCMslot *sp)
352 {
353 Cmdbuf *cmd;
354 uchar *cp;
355 int index, i, dtx;
356 Rune r;
357 DevConf cf;
358 Devport port;
359
360 cmd = parsecmd(p, n);
361 if(strcmp(cmd->f[0], "configure") == 0){
362 wlock(sp);
363 if(waserror()){
364 wunlock(sp);
365 nexterror();
366 }
367
368 /* see if driver exists and is configurable */
369 if(cmd->nf < 3)
370 error(Ebadarg);
371 p = cmd->f[1];
372 if(*p++ != '#')
373 error(Ebadarg);
374 p += chartorune(&r, p);
375 dtx = devno(r, 1);
376 if(dtx < 0)
377 error("no such device type");
378 if(devtab[dtx]->config == nil)
379 error("not a dynamicly configurable device");
380
381 /* set pcmcia card configuration */
382 index = 0;
383 if(sp->def != nil)
384 index = sp->def->index;
385 if(cmd->nf > 3){
386 i = atoi(cmd->f[3]);
387 if(i < 0 || i >= sp->nctab)
388 error("bad configuration index");
389 index = i;
390 }
391 if(sp->cfg[0].cpresent & (1<<Rconfig)){
392 cp = sp->attr;
393 cp += sp->cfg[0].caddr + Rconfig;
394 *cp = index;
395 }
396
397 /* configure device */
398 memset(&cf, 0, sizeof cf);
399 kstrdup(&cf.type, cmd->f[2]);
400 cf.mem = (ulong)sp->mem;
401 cf.ports = &port;
402 cf.ports[0].port = (ulong)sp->regs;
403 cf.ports[0].size = 0;
404 cf.nports = 1;
405 cf.itype = GPIOfalling;
406 cf.intnum = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i);
407 if(devtab[dtx]->config(1, p, &cf) < 0)
408 error("couldn't configure device");
409 sp->dev = devtab[dtx];
410 free(cf.type);
411 wunlock(sp);
412 poperror();
413
414 /* don't let the power turn off */
415 increfp(sp);
416 }else if(strcmp(cmd->f[0], "remove") == 0){
417 /* see if driver exists and is configurable */
418 if(cmd->nf != 2)
419 error(Ebadarg);
420 p = cmd->f[1];
421 if(*p++ != '#')
422 error(Ebadarg);
423 p += chartorune(&r, p);
424 dtx = devno(r, 1);
425 if(dtx < 0)
426 error("no such device type");
427 if(devtab[dtx]->config == nil)
428 error("not a dynamicly configurable device");
429 if(devtab[dtx]->config(0, p, nil) < 0)
430 error("couldn't unconfigure device");
431
432 /* let the power turn off */
433 decrefp(sp);
434 }
435 free(cmd);
436
437 return 0;
438 }
439
440 static long
441 pcmciawrite(Chan *c, void *a, long n, vlong off)
442 {
443 PCMslot *sp;
444 ulong offset = off;
445
446 sp = slotof(c);
447
448 switch(TYPE(c)){
449 case Qmem:
450 if(!sp->occupied)
451 error(Eio);
452 return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg);
453 case Qattr:
454 if(!sp->occupied)
455 error(Eio);
456 return pcmwrite(a, n, offset, sp, sp->attr, OneMeg);
457 case Qevs:
458 break;
459 case Qctl:
460 if(!sp->occupied)
461 error(Eio);
462 return pcmctlwrite(a, n, offset, sp);
463 }
464 error(Ebadarg);
465 return -1; /* not reached */
466 }
467
468 /*
469 * power up/down pcmcia
470 */
471 void
472 pcmciapower(int on)
473 {
474 PCMslot *sp;
475
476 /* if there's no pcmcia sleave, no interrupts */
477 iprint("pcmciapower %d\n", on);
478
479 if (on){
480 /* set timing to the default, 300 */
481 slottiming(0, 300, 300, 300, 0);
482 slottiming(1, 300, 300, 300, 0);
483
484 /* if there's no pcmcia sleave, no interrupts */
485 if(gpioregs->level & GPIO_OPT_IND_i){
486 iprint("pcmciapower: no sleeve\n");
487 return;
488 }
489
490 for (sp = slot; sp < slot + nslot; sp++){
491 if (sp->dev){
492 increfp(sp);
493 iprint("pcmciapower: %s\n", sp->verstr);
494 delay(10000);
495 if (sp->dev->power)
496 sp->dev->power(on);
497 }
498 }
499 }else{
500 if(gpioregs->level & GPIO_OPT_IND_i){
501 iprint("pcmciapower: no sleeve\n");
502 return;
503 }
504
505 for (sp = slot; sp < slot + nslot; sp++){
506 if (sp->dev){
507 if (sp->dev->power)
508 sp->dev->power(on);
509 decrefp(sp);
510 }
511 sp->occupied = 0;
512 sp->cisread = 0;
513 }
514 egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
515 }
516 }
517
518 Dev pcmciadevtab = {
519 'y',
520 "pcmcia",
521
522 pcmciareset,
523 devinit,
524 devshutdown,
525 pcmciaattach,
526 pcmciawalk,
527 pcmciastat,
528 pcmciaopen,
529 devcreate,
530 pcmciaclose,
531 pcmciaread,
532 devbread,
533 pcmciawrite,
534 devbwrite,
535 devremove,
536 devwstat,
537 pcmciapower,
538 };
539
540 /* see what's there */
541 static void
542 slotinfo(Ureg*, void*)
543 {
544 ulong x = gpioregs->level;
545
546 if(x & GPIO_OPT_IND_i){
547 /* no expansion pack */
548 slot[0].occupied = slot[0].inserted = 0;
549 slot[1].occupied = slot[1].inserted = 0;
550 } else {
551 if(x & GPIO_CARD_IND0_i){
552 slot[0].occupied = slot[0].inserted = 0;
553 slot[0].cisread = 0;
554 } else {
555 if(slot[0].occupied == 0){
556 slot[0].inserted = 1;
557 slot[0].cisread = 0;
558 }
559 slot[0].occupied = 1;
560 }
561 if(x & GPIO_CARD_IND1_i){
562 slot[1].occupied = slot[1].inserted = 0;
563 slot[1].cisread = 0;
564 } else {
565 if(slot[1].occupied == 0){
566 slot[1].inserted = 1;
567 slot[1].cisread = 0;
568 }
569 slot[1].occupied = 1;
570 }
571 if (inserted(nil))
572 wakeup(&pcmcia.event);
573 }
574 }
575
576 /* use reference card to turn cards on and off */
577 static void
578 increfp(PCMslot *sp)
579 {
580 wlock(sp);
581 if(waserror()){
582 wunlock(sp);
583 nexterror();
584 }
585
586 iprint("increfp %ld\n", sp - slot);
587 if(incref(&pcmcia) == 1){
588 iprint("increfp full power\n");
589 egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 1);
590 delay(200);
591 egpiobits(EGPIO_pcmcia_reset, 1);
592 delay(100);
593 egpiobits(EGPIO_pcmcia_reset, 0);
594 delay(500);
595 }
596 incref(&sp->ref);
597 slotinfo(nil, nil);
598 if(sp->occupied && sp->cisread == 0) {
599 pcmcisread(sp);
600 }
601
602 wunlock(sp);
603 poperror();
604 }
605
606 static void
607 decrefp(PCMslot *sp)
608 {
609 iprint("decrefp %ld\n", sp - slot);
610 decref(&sp->ref);
611 if(decref(&pcmcia) == 0){
612 iprint("increfp power down\n");
613 egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
614 }
615 }
616
617 /*
618 * the regions are staticly mapped
619 */
620 static void
621 slotmap(int slotno, ulong regs, ulong attr, ulong mem)
622 {
623 PCMslot *sp;
624
625 sp = &slot[slotno];
626 sp->slotno = slotno;
627 sp->memlen = 64*OneMeg;
628 sp->verstr[0] = 0;
629
630 sp->mem = mapmem(mem, 64*OneMeg, 0);
631 sp->memmap.ca = 0;
632 sp->memmap.cea = 64*MB;
633 sp->memmap.isa = (ulong)mem;
634 sp->memmap.len = 64*OneMeg;
635 sp->memmap.attr = 0;
636
637 sp->attr = mapmem(attr, OneMeg, 0);
638 sp->attrmap.ca = 0;
639 sp->attrmap.cea = MB;
640 sp->attrmap.isa = (ulong)attr;
641 sp->attrmap.len = OneMeg;
642 sp->attrmap.attr = 1;
643
644 sp->regs = mapspecial(regs, 32*1024);
645 }
646
647 PCMmap*
648 pcmmap(int slotno, ulong, int, int attr)
649 {
650 if(slotno > nslot)
651 panic("pcmmap");
652 if(attr)
653 return &slot[slotno].attrmap;
654 else
655 return &slot[slotno].memmap;
656 }
657
658 void
659 pcmunmap(int, PCMmap*)
660 {
661 }
662
663 /*
664 * setup card timings
665 * times are in ns
666 * count = ceiling[access-time/(2*3*T)] - 1, where T is a processor cycle
667 *
668 */
669 static int
670 ns2count(int ns)
671 {
672 ulong y;
673
674 /* get 100 times cycle time */
675 y = 100000000/(conf.hz/1000);
676
677 /* get 10 times ns/(cycle*6) */
678 y = (1000*ns)/(6*y);
679
680 /* round up */
681 y += 9;
682 y /= 10;
683
684 /* subtract 1 */
685 return y-1;
686 }
687 static void
688 slottiming(int slotno, int tio, int tattr, int tmem, int fast)
689 {
690 ulong x;
691
692 x = 0;
693 if(fast)
694 x |= 1<<MECR_fast0;
695 x |= ns2count(tio) << MECR_io0;
696 x |= ns2count(tattr) << MECR_attr0;
697 x |= ns2count(tmem) << MECR_mem0;
698 if(slotno == 0){
699 x |= memconfregs->mecr & 0xffff0000;
700 } else {
701 x <<= 16;
702 x |= memconfregs->mecr & 0xffff;
703 }
704 memconfregs->mecr = x;
705 }
706
707 /* For compat with ../pc devices. Don't use it for the bitsy
708 */
709 int
710 pcmspecial(char*, ISAConf*)
711 {
712 return -1;
713 }
Cache object: b950b82e3e4ed42dd0a38c6c04e76fc1
|