#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "io.h" /* * BUG: insertion events are detected by polling. * Should look into the compaq docs to see if * there's an interrupt for card insertion * there's probably one. */ static PCMslot slot[2];int nslot = 2; struct { Ref; Rendez event; // where to wait for card events int evreader; // there's a reader for events} pcmcia; enum{ Qdir, Qmem, Qattr, Qctl, Qevs, Nents = 3,}; enum{ /* * configuration registers - they start at an offset in attribute * memory found in the CIS. */ Rconfig= 0, Creset= (1<<7), /* reset device */ Clevel= (1<<6), /* level sensitive interrupt line */}; static void increfp(PCMslot*);static void decrefp(PCMslot*);static void slotmap(int, ulong, ulong, ulong);static void slottiming(int, int, int, int, int);static void slotinfo(Ureg*, void*); #define TYPE(c) (((ulong)c->qid.path)&0xff)#define PATH(s,t) (((s)<<8)|(t)) static PCMslot*slotof(Chan *c){ ulong x; x = c->qid.path; return slot + ((x>>8)&0xff);} static intpcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp){ int slotno; Qid qid; long len; PCMslot *sp; if(i == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#y", 0, eve, 0555, dp); return 1; } if(i >= Nents*nslot + 1) return -1; if(i == Nents*nslot){ len = 0; qid.path = PATH(0, Qevs); snprint(up->genbuf, sizeof up->genbuf, "pcmevs"); goto found; } slotno = i/Nents; sp = slot + slotno; len = 0; switch(i%Nents){ case 0: qid.path = PATH(slotno, Qmem); snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno); len = sp->memlen; break; case 1: qid.path = PATH(slotno, Qattr); snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno); len = sp->memlen; break; case 2: qid.path = PATH(slotno, Qctl); snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno); break; }found: qid.vers = 0; qid.type = QTFILE; devdir(c, qid, up->genbuf, len, eve, 0660, dp); return 1;} static intbitno(ulong x){ int i; for(i = 0; i < 8*sizeof(x); i++) if((1<<i) & x) break; return i;} /* * set up the cards, default timing is 300 ns */static voidpcmciareset(void){ /* staticly map the whole area */ slotmap(0, PHYSPCM0REGS, PYHSPCM0ATTR, PYHSPCM0MEM); slotmap(1, PHYSPCM1REGS, PYHSPCM1ATTR, PYHSPCM1MEM); /* set timing to the default, 300 */ slottiming(0, 300, 300, 300, 0); slottiming(1, 300, 300, 300, 0); /* if there's no pcmcia sleave, no interrupts */ if(gpioregs->level & GPIO_OPT_IND_i) return; /* sleave there, interrupt on card removal */ intrenable(GPIOrising, bitno(GPIO_CARD_IND1_i), slotinfo, nil, "pcmcia slot1 status"); intrenable(GPIOrising, bitno(GPIO_CARD_IND0_i), slotinfo, nil, "pcmcia slot0 status");} static Chan*pcmciaattach(char *spec){ return devattach('y', spec);} static Walkqid*pcmciawalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, pcmgen);} static intpcmciastat(Chan *c, uchar *db, int n){ return devstat(c, db, n, 0, 0, pcmgen);} static Chan*pcmciaopen(Chan *c, int omode){ PCMslot *slotp; if(c->qid.type & QTDIR){ if(omode != OREAD) error(Eperm); } else { slotp = slotof(c); increfp(slotp); } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;} static voidpcmciaclose(Chan *c){ if(c->flag & COPEN) if((c->qid.type & QTDIR) == 0) decrefp(slotof(c));} /* a memmove using only bytes */static voidmemmoveb(uchar *to, uchar *from, int n){ while(n-- > 0) *to++ = *from++;} /* a memmove using only shorts & bytes */static voidmemmoves(uchar *to, uchar *from, int n){ ushort *t, *f; if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){ while(n-- > 0) *to++ = *from++; } else { n = n/2; t = (ushort*)to; f = (ushort*)from; while(n-- > 0) *t++ = *f++; }} static longpcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len){ rlock(sp); if(waserror()){ runlock(sp); nexterror(); } if(off > len) return 0; if(off + n > len) n = len - off; memmoveb(a, start+off, n); runlock(sp); poperror(); return n;} static longpcmctlread(void *a, long n, ulong off, PCMslot *sp){ char *p, *buf, *e; buf = p = malloc(READSTR); if(waserror()){ free(buf); nexterror(); } e = p + READSTR; buf[0] = 0; if(sp->occupied){ p = seprint(p, e, "occupied\n"); if(sp->verstr[0]) p = seprint(p, e, "version %s\n", sp->verstr); } USED(p); n = readstr(off, a, n, buf); free(buf); poperror(); return n;} static intinserted(void *){ if (slot[0].inserted) return 1; if (slot[1].inserted) return 2; return 0;} static longpcmevsread(void *a, long n, ulong off){ int i; char *buf = nil; char *e; if (pcmcia.evreader) error("At most one reader"); off = 0; pcmcia.evreader++; if (waserror()){ free(buf); pcmcia.evreader--; nexterror(); } while((i = inserted(nil)) == 0){ slotinfo(nil, nil); tsleep(&pcmcia.event, inserted, nil, 500); } pcmcia.evreader--; slot[i-1].inserted = 0; buf = malloc(READSTR); e = buf + READSTR; buf[0] = 0; seprint(buf, e, "#y/pcm%dctl\n", i-1); n = readstr(off, a, n, buf); free(buf); poperror(); return n;} static longpcmciaread(Chan *c, void *a, long n, vlong off){ PCMslot *sp; ulong offset = off; sp = slotof(c); switch(TYPE(c)){ case Qdir: return devdirread(c, a, n, 0, 0, pcmgen); case Qmem: if(!sp->occupied) error(Eio); return pcmread(a, n, offset, sp, sp->mem, 64*OneMeg); case Qattr: if(!sp->occupied) error(Eio); return pcmread(a, n, offset, sp, sp->attr, OneMeg); case Qevs: return pcmevsread(a, n, offset); case Qctl: return pcmctlread(a, n, offset, sp); } error(Ebadarg); return -1; /* not reached */} static longpcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len){ rlock(sp); if(waserror()){ runlock(sp); nexterror(); } if(off > len) error(Eio); if(off + n > len) error(Eio); memmoveb(start+off, a, n); poperror(); runlock(sp); return n;} static longpcmctlwrite(char *p, long n, ulong, PCMslot *sp){ Cmdbuf *cmd; uchar *cp; int index, i, dtx; Rune r; DevConf cf; Devport port; cmd = parsecmd(p, n); if(strcmp(cmd->f[0], "configure") == 0){ wlock(sp); if(waserror()){ wunlock(sp); nexterror(); } /* see if driver exists and is configurable */ if(cmd->nf < 3) error(Ebadarg); p = cmd->f[1]; if(*p++ != '#') error(Ebadarg); p += chartorune(&r, p); dtx = devno(r, 1); if(dtx < 0) error("no such device type"); if(devtab[dtx]->config == nil) error("not a dynamicly configurable device"); /* set pcmcia card configuration */ index = 0; if(sp->def != nil) index = sp->def->index; if(cmd->nf > 3){ i = atoi(cmd->f[3]); if(i < 0 || i >= sp->nctab) error("bad configuration index"); index = i; } if(sp->cfg[0].cpresent & (1<<Rconfig)){ cp = sp->attr; cp += sp->cfg[0].caddr + Rconfig; *cp = index; } /* configure device */ memset(&cf, 0, sizeof cf); kstrdup(&cf.type, cmd->f[2]); cf.mem = (ulong)sp->mem; cf.ports = &port; cf.ports[0].port = (ulong)sp->regs; cf.ports[0].size = 0; cf.nports = 1; cf.itype = GPIOfalling; cf.intnum = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i); if(devtab[dtx]->config(1, p, &cf) < 0) error("couldn't configure device"); sp->dev = devtab[dtx]; free(cf.type); wunlock(sp); poperror(); /* don't let the power turn off */ increfp(sp); }else if(strcmp(cmd->f[0], "remove") == 0){ /* see if driver exists and is configurable */ if(cmd->nf != 2) error(Ebadarg); p = cmd->f[1]; if(*p++ != '#') error(Ebadarg); p += chartorune(&r, p); dtx = devno(r, 1); if(dtx < 0) error("no such device type"); if(devtab[dtx]->config == nil) error("not a dynamicly configurable device"); if(devtab[dtx]->config(0, p, nil) < 0) error("couldn't unconfigure device"); /* let the power turn off */ decrefp(sp); } free(cmd); return 0;} static longpcmciawrite(Chan *c, void *a, long n, vlong off){ PCMslot *sp; ulong offset = off; sp = slotof(c); switch(TYPE(c)){ case Qmem: if(!sp->occupied) error(Eio); return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg); case Qattr: if(!sp->occupied) error(Eio); return pcmwrite(a, n, offset, sp, sp->attr, OneMeg); case Qevs: break; case Qctl: if(!sp->occupied) error(Eio); return pcmctlwrite(a, n, offset, sp); } error(Ebadarg); return -1; /* not reached */} /* * power up/down pcmcia */voidpcmciapower(int on){ PCMslot *sp; /* if there's no pcmcia sleave, no interrupts */iprint("pcmciapower %d\n", on); if (on){ /* set timing to the default, 300 */ slottiming(0, 300, 300, 300, 0); slottiming(1, 300, 300, 300, 0); /* if there's no pcmcia sleave, no interrupts */ if(gpioregs->level & GPIO_OPT_IND_i){ iprint("pcmciapower: no sleeve\n"); return; } for (sp = slot; sp < slot + nslot; sp++){ if (sp->dev){ increfp(sp); iprint("pcmciapower: %s\n", sp->verstr); delay(10000); if (sp->dev->power) sp->dev->power(on); } } }else{ if(gpioregs->level & GPIO_OPT_IND_i){Lines 1–500 of 713. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "io.h" /* * BUG: insertion events are detected by polling. * Should look into the compaq docs to see if * there's an interrupt for card insertion * there's probably one. */ static PCMslot slot[2]; int nslot = 2; struct { Ref; Rendez event; // where to wait for card events int evreader; // there's a reader for events } pcmcia; enum { Qdir, Qmem, Qattr, Qctl, Qevs, Nents = 3, }; enum { /* * configuration registers - they start at an offset in attribute * memory found in the CIS. */ Rconfig= 0, Creset= (1<<7), /* reset device */ Clevel= (1<<6), /* level sensitive interrupt line */ }; static void increfp(PCMslot*); static void decrefp(PCMslot*); static void slotmap(int, ulong, ulong, ulong); static void slottiming(int, int, int, int, int); static void slotinfo(Ureg*, void*); #define TYPE(c) (((ulong)c->qid.path)&0xff) #define PATH(s,t) (((s)<<8)|(t)) static PCMslot* slotof(Chan *c) { ulong x; x = c->qid.path; return slot + ((x>>8)&0xff); } static int pcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp) { int slotno; Qid qid; long len; PCMslot *sp; if(i == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#y", 0, eve, 0555, dp); return 1; } if(i >= Nents*nslot + 1) return -1; if(i == Nents*nslot){ len = 0; qid.path = PATH(0, Qevs); snprint(up->genbuf, sizeof up->genbuf, "pcmevs"); goto found; } slotno = i/Nents; sp = slot + slotno; len = 0; switch(i%Nents){ case 0: qid.path = PATH(slotno, Qmem); snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno); len = sp->memlen; break; case 1: qid.path = PATH(slotno, Qattr); snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno); len = sp->memlen; break; case 2: qid.path = PATH(slotno, Qctl); snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno); break; } found: qid.vers = 0; qid.type = QTFILE; devdir(c, qid, up->genbuf, len, eve, 0660, dp); return 1; } static int bitno(ulong x) { int i; for(i = 0; i < 8*sizeof(x); i++) if((1<<i) & x) break; return i; } /* * set up the cards, default timing is 300 ns */ static void pcmciareset(void) { /* staticly map the whole area */ slotmap(0, PHYSPCM0REGS, PYHSPCM0ATTR, PYHSPCM0MEM); slotmap(1, PHYSPCM1REGS, PYHSPCM1ATTR, PYHSPCM1MEM); /* set timing to the default, 300 */ slottiming(0, 300, 300, 300, 0); slottiming(1, 300, 300, 300, 0); /* if there's no pcmcia sleave, no interrupts */ if(gpioregs->level & GPIO_OPT_IND_i) return; /* sleave there, interrupt on card removal */ intrenable(GPIOrising, bitno(GPIO_CARD_IND1_i), slotinfo, nil, "pcmcia slot1 status"); intrenable(GPIOrising, bitno(GPIO_CARD_IND0_i), slotinfo, nil, "pcmcia slot0 status"); } static Chan* pcmciaattach(char *spec) { return devattach('y', spec); } static Walkqid* pcmciawalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, pcmgen); } static int pcmciastat(Chan *c, uchar *db, int n) { return devstat(c, db, n, 0, 0, pcmgen); } static Chan* pcmciaopen(Chan *c, int omode) { PCMslot *slotp; if(c->qid.type & QTDIR){ if(omode != OREAD) error(Eperm); } else { slotp = slotof(c); increfp(slotp); } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } static void pcmciaclose(Chan *c) { if(c->flag & COPEN) if((c->qid.type & QTDIR) == 0) decrefp(slotof(c)); } /* a memmove using only bytes */ static void memmoveb(uchar *to, uchar *from, int n) { while(n-- > 0) *to++ = *from++; } /* a memmove using only shorts & bytes */ static void memmoves(uchar *to, uchar *from, int n) { ushort *t, *f; if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){ while(n-- > 0) *to++ = *from++; } else { n = n/2; t = (ushort*)to; f = (ushort*)from; while(n-- > 0) *t++ = *f++; } } static long pcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len) { rlock(sp); if(waserror()){ runlock(sp); nexterror(); } if(off > len) return 0; if(off + n > len) n = len - off; memmoveb(a, start+off, n); runlock(sp); poperror(); return n; } static long pcmctlread(void *a, long n, ulong off, PCMslot *sp) { char *p, *buf, *e; buf = p = malloc(READSTR); if(waserror()){ free(buf); nexterror(); } e = p + READSTR; buf[0] = 0; if(sp->occupied){ p = seprint(p, e, "occupied\n"); if(sp->verstr[0]) p = seprint(p, e, "version %s\n", sp->verstr); } USED(p); n = readstr(off, a, n, buf); free(buf); poperror(); return n; } static int inserted(void *) { if (slot[0].inserted) return 1; if (slot[1].inserted) return 2; return 0; } static long pcmevsread(void *a, long n, ulong off) { int i; char *buf = nil; char *e; if (pcmcia.evreader) error("At most one reader"); off = 0; pcmcia.evreader++; if (waserror()){ free(buf); pcmcia.evreader--; nexterror(); } while((i = inserted(nil)) == 0){ slotinfo(nil, nil); tsleep(&pcmcia.event, inserted, nil, 500); } pcmcia.evreader--; slot[i-1].inserted = 0; buf = malloc(READSTR); e = buf + READSTR; buf[0] = 0; seprint(buf, e, "#y/pcm%dctl\n", i-1); n = readstr(off, a, n, buf); free(buf); poperror(); return n; } static long pcmciaread(Chan *c, void *a, long n, vlong off) { PCMslot *sp; ulong offset = off; sp = slotof(c); switch(TYPE(c)){ case Qdir: return devdirread(c, a, n, 0, 0, pcmgen); case Qmem: if(!sp->occupied) error(Eio); return pcmread(a, n, offset, sp, sp->mem, 64*OneMeg); case Qattr: if(!sp->occupied) error(Eio); return pcmread(a, n, offset, sp, sp->attr, OneMeg); case Qevs: return pcmevsread(a, n, offset); case Qctl: return pcmctlread(a, n, offset, sp); } error(Ebadarg); return -1; /* not reached */ } static long pcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len) { rlock(sp); if(waserror()){ runlock(sp); nexterror(); } if(off > len) error(Eio); if(off + n > len) error(Eio); memmoveb(start+off, a, n); poperror(); runlock(sp); return n; } static long pcmctlwrite(char *p, long n, ulong, PCMslot *sp) { Cmdbuf *cmd; uchar *cp; int index, i, dtx; Rune r; DevConf cf; Devport port; cmd = parsecmd(p, n); if(strcmp(cmd->f[0], "configure") == 0){ wlock(sp); if(waserror()){ wunlock(sp); nexterror(); } /* see if driver exists and is configurable */ if(cmd->nf < 3) error(Ebadarg); p = cmd->f[1]; if(*p++ != '#') error(Ebadarg); p += chartorune(&r, p); dtx = devno(r, 1); if(dtx < 0) error("no such device type"); if(devtab[dtx]->config == nil) error("not a dynamicly configurable device"); /* set pcmcia card configuration */ index = 0; if(sp->def != nil) index = sp->def->index; if(cmd->nf > 3){ i = atoi(cmd->f[3]); if(i < 0 || i >= sp->nctab) error("bad configuration index"); index = i; } if(sp->cfg[0].cpresent & (1<<Rconfig)){ cp = sp->attr; cp += sp->cfg[0].caddr + Rconfig; *cp = index; } /* configure device */ memset(&cf, 0, sizeof cf); kstrdup(&cf.type, cmd->f[2]); cf.mem = (ulong)sp->mem; cf.ports = &port; cf.ports[0].port = (ulong)sp->regs; cf.ports[0].size = 0; cf.nports = 1; cf.itype = GPIOfalling; cf.intnum = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i); if(devtab[dtx]->config(1, p, &cf) < 0) error("couldn't configure device"); sp->dev = devtab[dtx]; free(cf.type); wunlock(sp); poperror(); /* don't let the power turn off */ increfp(sp); }else if(strcmp(cmd->f[0], "remove") == 0){ /* see if driver exists and is configurable */ if(cmd->nf != 2) error(Ebadarg); p = cmd->f[1]; if(*p++ != '#') error(Ebadarg); p += chartorune(&r, p); dtx = devno(r, 1); if(dtx < 0) error("no such device type"); if(devtab[dtx]->config == nil) error("not a dynamicly configurable device"); if(devtab[dtx]->config(0, p, nil) < 0) error("couldn't unconfigure device"); /* let the power turn off */ decrefp(sp); } free(cmd); return 0; } static long pcmciawrite(Chan *c, void *a, long n, vlong off) { PCMslot *sp; ulong offset = off; sp = slotof(c); switch(TYPE(c)){ case Qmem: if(!sp->occupied) error(Eio); return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg); case Qattr: if(!sp->occupied) error(Eio); return pcmwrite(a, n, offset, sp, sp->attr, OneMeg); case Qevs: break; case Qctl: if(!sp->occupied) error(Eio); return pcmctlwrite(a, n, offset, sp); } error(Ebadarg); return -1; /* not reached */ } /* * power up/down pcmcia */ void pcmciapower(int on) { PCMslot *sp; /* if there's no pcmcia sleave, no interrupts */ iprint("pcmciapower %d\n", on); if (on){ /* set timing to the default, 300 */ slottiming(0, 300, 300, 300, 0); slottiming(1, 300, 300, 300, 0); /* if there's no pcmcia sleave, no interrupts */ if(gpioregs->level & GPIO_OPT_IND_i){ iprint("pcmciapower: no sleeve\n"); return; } for (sp = slot; sp < slot + nslot; sp++){ if (sp->dev){ increfp(sp); iprint("pcmciapower: %s\n", sp->verstr); delay(10000); if (sp->dev->power) sp->dev->power(on); } } }else{ if(gpioregs->level & GPIO_OPT_IND_i){