2 #include "../port/lib.h"
6 #include "../port/error.h"
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.
16 static PCMslot slot[2];
21 Rendez event; // where to wait for card events
22 int evreader; // there's a reader for events
39 * configuration registers - they start at an offset in attribute
40 * memory found in the CIS.
43 Creset= (1<<7), /* reset device */
44 Clevel= (1<<6), /* level sensitive interrupt line */
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*);
53 #define TYPE(c) (((ulong)c->qid.path)&0xff)
54 #define PATH(s,t) (((s)<<8)|(t))
62 return slot + ((x>>8)&0xff);
66 pcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp)
74 mkqid(&qid, Qdir, 0, QTDIR);
75 devdir(c, qid, "#y", 0, eve, 0555, dp);
79 if(i >= Nents*nslot + 1)
83 qid.path = PATH(0, Qevs);
84 snprint(up->genbuf, sizeof up->genbuf, "pcmevs");
93 qid.path = PATH(slotno, Qmem);
94 snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
98 qid.path = PATH(slotno, Qattr);
99 snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
103 qid.path = PATH(slotno, Qctl);
104 snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
110 devdir(c, qid, up->genbuf, len, eve, 0660, dp);
119 for(i = 0; i < 8*sizeof(x); i++)
126 * set up the cards, default timing is 300 ns
131 /* staticly map the whole area */
132 slotmap(0, PHYSPCM0REGS, PYHSPCM0ATTR, PYHSPCM0MEM);
133 slotmap(1, PHYSPCM1REGS, PYHSPCM1ATTR, PYHSPCM1MEM);
135 /* set timing to the default, 300 */
136 slottiming(0, 300, 300, 300, 0);
137 slottiming(1, 300, 300, 300, 0);
139 /* if there's no pcmcia sleave, no interrupts */
140 if(gpioregs->level & GPIO_OPT_IND_i)
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");
149 pcmciaattach(char *spec)
151 return devattach('y', spec);
155 pcmciawalk(Chan *c, Chan *nc, char **name, int nname)
157 return devwalk(c, nc, name, nname, 0, 0, pcmgen);
161 pcmciastat(Chan *c, uchar *db, int n)
163 return devstat(c, db, n, 0, 0, pcmgen);
167 pcmciaopen(Chan *c, int omode)
171 if(c->qid.type & QTDIR){
178 c->mode = openmode(omode);
188 if((c->qid.type & QTDIR) == 0)
192 /* a memmove using only bytes */
194 memmoveb(uchar *to, uchar *from, int n)
200 /* a memmove using only shorts & bytes */
202 memmoves(uchar *to, uchar *from, int n)
206 if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
219 pcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
230 memmoveb(a, start+off, n);
237 pcmctlread(void *a, long n, ulong off, PCMslot *sp)
241 buf = p = malloc(READSTR);
250 p = seprint(p, e, "occupied\n");
252 p = seprint(p, e, "version %s\n", sp->verstr);
256 n = readstr(off, a, n, buf);
265 if (slot[0].inserted)
267 if (slot[1].inserted)
273 pcmevsread(void *a, long n, ulong off)
280 error("At most one reader");
288 while((i = inserted(nil)) == 0){
290 tsleep(&pcmcia.event, inserted, nil, 500);
293 slot[i-1].inserted = 0;
294 buf = malloc(READSTR);
297 seprint(buf, e, "#y/pcm%dctl\n", i-1);
298 n = readstr(off, a, n, buf);
305 pcmciaread(Chan *c, void *a, long n, vlong off)
314 return devdirread(c, a, n, 0, 0, pcmgen);
318 return pcmread(a, n, offset, sp, sp->mem, 64*OneMeg);
322 return pcmread(a, n, offset, sp, sp->attr, OneMeg);
324 return pcmevsread(a, n, offset);
326 return pcmctlread(a, n, offset, sp);
329 return -1; /* not reached */
333 pcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
344 memmoveb(start+off, a, n);
351 pcmctlwrite(char *p, long n, ulong, PCMslot *sp)
360 cmd = parsecmd(p, n);
361 if(strcmp(cmd->f[0], "configure") == 0){
368 /* see if driver exists and is configurable */
374 p += chartorune(&r, p);
377 error("no such device type");
378 if(devtab[dtx]->config == nil)
379 error("not a dynamicly configurable device");
381 /* set pcmcia card configuration */
384 index = sp->def->index;
387 if(i < 0 || i >= sp->nctab)
388 error("bad configuration index");
391 if(sp->cfg[0].cpresent & (1<<Rconfig)){
393 cp += sp->cfg[0].caddr + Rconfig;
397 /* configure device */
398 memset(&cf, 0, sizeof cf);
399 kstrdup(&cf.type, cmd->f[2]);
400 cf.mem = (ulong)sp->mem;
402 cf.ports[0].port = (ulong)sp->regs;
403 cf.ports[0].size = 0;
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];
414 /* don't let the power turn off */
416 }else if(strcmp(cmd->f[0], "remove") == 0){
417 /* see if driver exists and is configurable */
423 p += chartorune(&r, p);
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");
432 /* let the power turn off */
441 pcmciawrite(Chan *c, void *a, long n, vlong off)
452 return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg);
456 return pcmwrite(a, n, offset, sp, sp->attr, OneMeg);
462 return pcmctlwrite(a, n, offset, sp);
465 return -1; /* not reached */
469 * power up/down pcmcia
476 /* if there's no pcmcia sleave, no interrupts */
477 iprint("pcmciapower %d\n", on);
480 /* set timing to the default, 300 */
481 slottiming(0, 300, 300, 300, 0);
482 slottiming(1, 300, 300, 300, 0);
484 /* if there's no pcmcia sleave, no interrupts */
485 if(gpioregs->level & GPIO_OPT_IND_i){
486 iprint("pcmciapower: no sleeve\n");
490 for (sp = slot; sp < slot + nslot; sp++){
493 iprint("pcmciapower: %s\n", sp->verstr);
500 if(gpioregs->level & GPIO_OPT_IND_i){
501 iprint("pcmciapower: no sleeve\n");
505 for (sp = slot; sp < slot + nslot; sp++){
514 egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
540 /* see what's there */
542 slotinfo(Ureg*, void*)
544 ulong x = gpioregs->level;
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;
551 if(x & GPIO_CARD_IND0_i){
552 slot[0].occupied = slot[0].inserted = 0;
555 if(slot[0].occupied == 0){
556 slot[0].inserted = 1;
559 slot[0].occupied = 1;
561 if(x & GPIO_CARD_IND1_i){
562 slot[1].occupied = slot[1].inserted = 0;
565 if(slot[1].occupied == 0){
566 slot[1].inserted = 1;
569 slot[1].occupied = 1;
572 wakeup(&pcmcia.event);
576 /* use reference card to turn cards on and off */
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);
591 egpiobits(EGPIO_pcmcia_reset, 1);
593 egpiobits(EGPIO_pcmcia_reset, 0);
598 if(sp->occupied && sp->cisread == 0) {
609 iprint("decrefp %ld\n", sp - slot);
611 if(decref(&pcmcia) == 0){
612 iprint("increfp power down\n");
613 egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
618 * the regions are staticly mapped
621 slotmap(int slotno, ulong regs, ulong attr, ulong mem)
627 sp->memlen = 64*OneMeg;
630 sp->mem = mapmem(mem, 64*OneMeg, 0);
632 sp->memmap.cea = 64*MB;
633 sp->memmap.isa = (ulong)mem;
634 sp->memmap.len = 64*OneMeg;
637 sp->attr = mapmem(attr, OneMeg, 0);
639 sp->attrmap.cea = MB;
640 sp->attrmap.isa = (ulong)attr;
641 sp->attrmap.len = OneMeg;
642 sp->attrmap.attr = 1;
644 sp->regs = mapspecial(regs, 32*1024);
648 pcmmap(int slotno, ulong, int, int attr)
653 return &slot[slotno].attrmap;
655 return &slot[slotno].memmap;
659 pcmunmap(int, PCMmap*)
666 * count = ceiling[access-time/(2*3*T)] - 1, where T is a processor cycle
674 /* get 100 times cycle time */
675 y = 100000000/(conf.hz/1000);
677 /* get 10 times ns/(cycle*6) */
688 slottiming(int slotno, int tio, int tattr, int tmem, int fast)
695 x |= ns2count(tio) << MECR_io0;
696 x |= ns2count(tattr) << MECR_attr0;
697 x |= ns2count(tmem) << MECR_mem0;
699 x |= memconfregs->mecr & 0xffff0000;
702 x |= memconfregs->mecr & 0xffff;
704 memconfregs->mecr = x;
707 /* For compat with ../pc devices. Don't use it for the bitsy
710 pcmspecial(char*, ISAConf*)