From c7d3d963bc8253e3d35beddbff98aacea2a16e03 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 18 Nov 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-11-18 --- bitsy/devpcmcia.c | 355 ++++++++++++++++++++++++++++ bitsy/devuda1341.c | 180 +++++++++++--- bitsy/fns.h | 13 +- bitsy/io.h | 92 +++++++- bitsy/main.c | 10 +- bitsy/mem.h | 16 +- bitsy/mmu.c | 130 +++++++++-- bitsy/sa1110dma.c | 8 +- bitsy/sa1110dma.h | 2 +- pc/dat.h | 1 + pc/devi82365.c | 570 +++------------------------------------------ pc/fns.h | 1 + pc/io.h | 104 +++++++-- port/cis.c | 431 ++++++++++++++++++++++++++++++++++ 14 files changed, 1307 insertions(+), 606 deletions(-) create mode 100644 bitsy/devpcmcia.c create mode 100644 port/cis.c diff --git a/bitsy/devpcmcia.c b/bitsy/devpcmcia.c new file mode 100644 index 0000000000000000000000000000000000000000..a6ad1c950fd1ebb1590dcf17ad98c9ca220f9e74 --- /dev/null +++ b/bitsy/devpcmcia.c @@ -0,0 +1,355 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" + +static PCMslot slot[2]; +int nslot = 2; + +struct { + Ref; +} pcmcia; + +enum +{ + Qdir, + Qmem, + Qattr, + Qctl, + + Nents = 3, +}; + +#define SLOTNO(c) ((c->qid.path>>8)&0xff) +#define TYPE(c) (c->qid.path&0xff) +#define QID(s,t) (((s)<<8)|(t)) + +static int +pcmgen(Chan *c, Dirtab *, int , int i, Dir *dp) +{ + int slotno; + Qid qid; + long len; + PCMslot *pp; + char name[NAMELEN]; + + if(i == DEVDOTDOT){ + devdir(c, (Qid){CHDIR, 0}, "#y", 0, eve, 0555, dp); + return 1; + } + + if(i >= Nents*nslot) + return -1; + + slotno = i/Nents; + pp = slot + slotno; + len = 0; + switch(i%Nents){ + case 0: + qid.path = QID(slotno, Qmem); + sprint(name, "pcm%dmem", slotno); + len = pp->memlen; + break; + case 1: + qid.path = QID(slotno, Qattr); + sprint(name, "pcm%dattr", slotno); + len = pp->memlen; + break; + case 2: + qid.path = QID(slotno, Qctl); + sprint(name, "pcm%dctl", slotno); + break; + } + qid.vers = 0; + devdir(c, qid, name, len, eve, 0660, dp); + return 1; +} + +static void +slotinfo(void) +{ + ulong x = gpioregs->level; + + if(x & GPIO_OPT_IND_i){ + /* no expansion pack */ + slot[0].occupied = 0; + slot[1].occupied = 0; + } else { + slot[0].occupied = (x & GPIO_CARD_IND0_i) == 0; + slot[1].occupied = (x & GPIO_CARD_IND1_i) == 0; + } +} + +static void +increfp(PCMslot *pp) +{ + if(incref(&pcmcia) == 1) + exppackpower(1); + lock(pp); + if(pp->ref++ == 0) + ; + unlock(pp); + slotinfo(); +} +static void +decrefp(PCMslot *pp) +{ + slotinfo(); + lock(pp); + if(pp->ref-- == 1) + ; + unlock(pp); + if(decref(&pcmcia) == 0) + exppackpower(0); +} + +/* + * get a map for pc card region, return corrected len + */ +PCMmap* +pcmmap(int slotno, ulong, int, int attr) +{ + if(slotno > nslot) + panic("pcmmap"); + if(attr) + return &slot[slotno].attrmap; + else + return &slot[slotno].memmap; +} +void +pcmunmap(int, PCMmap*) +{ +} + +/* + * map in the space for the cards + */ +static void +pcmciareset(void) +{ + int j; + PCMslot *pp; + + for(j = 0; j < nslot; j++){ + pp = &slot[j]; + pp->slotno = j; + pp->memlen = 64*OneMeg; + pp->msec = ~0; + pp->verstr[0] = 0; + + pp->mem = mapmem(j == 0 ? PYHSPCM0MEM : PYHSPCM1MEM, 64*OneMeg); + pp->memmap.ca = 0; + pp->memmap.cea = 64*MB; + pp->memmap.isa = (ulong)pp->mem; + pp->memmap.len = 64*OneMeg; + pp->memmap.attr = 0; + + pp->attr = mapmem(j == 0 ? PYHSPCM0ATTR : PYHSPCM1ATTR, OneMeg); + pp->attrmap.ca = 0; + pp->attrmap.cea = 64*MB; + pp->attrmap.isa = (ulong)pp->attr; + pp->attrmap.len = OneMeg; + pp->attrmap.attr = 1; + + pp->regs = mapspecial(j == 0 ? PHYSPCM0REGS : PHYSPCM1REGS, 32*1024); + } +} + +static Chan* +pcmciaattach(char *spec) +{ + return devattach('y', spec); +} + +static int +pcmciawalk(Chan *c, char *name) +{ + return devwalk(c, name, 0, 0, pcmgen); +} + +static void +pcmciastat(Chan *c, char *db) +{ + devstat(c, db, 0, 0, pcmgen); +} + +static Chan* +pcmciaopen(Chan *c, int omode) +{ + if(c->qid.path == CHDIR){ + if(omode != OREAD) + error(Eperm); + } else + increfp(slot + SLOTNO(c)); + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +static void +pcmciaclose(Chan *c) +{ + if(c->flag & COPEN) + if(c->qid.path != CHDIR) + decrefp(slot+SLOTNO(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, uchar *start, ulong len) +{ + if(off > len) + return 0; + if(off + n > len) + n = len - off; + memmoves(a, start+off, n); + return n; +} + +static long +pcmctlread(void *a, long n, ulong off, PCMslot *pp) +{ + char *p, *buf, *e; + + buf = p = malloc(READSTR); + if(waserror()){ + free(buf); + nexterror(); + } + e = p + READSTR; + + buf[0] = 0; + if(pp->occupied){ + p = seprint(p, e, "occupied\n"); + if(pp->verstr[0]) + p = seprint(p, e, "version %s\n", pp->verstr); + } + USED(p); + + n = readstr(off, a, n, buf); + free(buf); + poperror(); + return n; +} + +static long +pcmciaread(Chan *c, void *a, long n, vlong off) +{ + PCMslot *pp; + ulong offset = off; + + pp = slot + SLOTNO(c); + + switch(TYPE(c)){ + case Qdir: + return devdirread(c, a, n, 0, 0, pcmgen); + case Qmem: + if(!pp->occupied) + error(Eio); + return pcmread(a, n, offset, pp->mem, 64*OneMeg); + case Qattr: + if(!pp->occupied) + error(Eio); + return pcmread(a, n, offset, pp->attr, OneMeg); + case Qctl: + return pcmctlread(a, n, offset, pp); + } + error(Ebadarg); + return -1; /* not reached */ +} + +static long +pcmwrite(void *a, long n, ulong off, uchar *start, ulong len) +{ + if(off > len) + error(Eio); + if(off + n > len) + error(Eio); + memmoveb(start+off, a, n); + return n; +} + +static long +pcmctlwrite(char *p, long n, ulong off, PCMslot *pp) +{ + /* nothing yet */ + USED(p, n, off, pp); + error(Ebadarg); + return 0; +} + +static long +pcmciawrite(Chan *c, void *a, long n, vlong off) +{ + PCMslot *pp; + ulong offset = off; + + pp = slot + SLOTNO(c); + + switch(TYPE(c)){ + case Qmem: + if(!pp->occupied) + error(Eio); + return pcmwrite(a, n, offset, pp->mem, 64*OneMeg); + case Qattr: + if(!pp->occupied) + error(Eio); + return pcmwrite(a, n, offset, pp->attr, OneMeg); + case Qctl: + if(!pp->occupied) + error(Eio); + return pcmctlwrite(a, n, offset, pp); + } + error(Ebadarg); + return -1; /* not reached */ +} + +Dev pcmciadevtab = { + 'y', + "pcmcia", + + pcmciareset, + devinit, + pcmciaattach, + devclone, + pcmciawalk, + pcmciastat, + pcmciaopen, + devcreate, + pcmciaclose, + pcmciaread, + devbread, + pcmciawrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/bitsy/devuda1341.c b/bitsy/devuda1341.c index cb78a1a30fe702cb66fbb4886e35aa0c8611fa15..0704b5b68e36958f03fbdc7d2c87c1dabccaec71 100644 --- a/bitsy/devuda1341.c +++ b/bitsy/devuda1341.c @@ -43,13 +43,15 @@ static int debug = 1; /* * L3 setup and hold times (expressed in µs) */ -#define L3_DataSetupTime 1 /* 190 ns */ -#define L3_DataHoldTime 1 /* 30 ns */ -#define L3_ModeSetupTime 1 /* 190 ns */ -#define L3_ModeHoldTime 1 /* 190 ns */ -#define L3_ClockHighTime 10 /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ -#define L3_ClockLowTime 10 /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ -#define L3_HaltTime 1 /* 190 ns */ +enum { + L3_DataSetupTime = 1, /* 190 ns */ + L3_DataHoldTime = 1, /* 30 ns */ + L3_ModeSetupTime = 1, /* 190 ns */ + L3_ModeHoldTime = 1, /* 190 ns */ + L3_ClockHighTime = 10, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ + L3_ClockLowTime = 10, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ + L3_HaltTime = 1, /* 190 ns */ +}; /* UDA 1341 Registers */ enum { @@ -73,10 +75,13 @@ enum { /* * UDA1341 L3 address and command types */ -#define UDA1341_DATA0 0 -#define UDA1341_DATA1 1 -#define UDA1341_STATUS 2 -#define UDA1341_L3Addr 0x14 + +enum { + UDA1341_DATA0 = 0, + UDA1341_DATA1, + UDA1341_STATUS, + UDA1341_L3Addr = 0x14, +}; typedef struct AQueue AQueue; typedef struct Buf Buf; @@ -122,6 +127,7 @@ audiodir[] = struct Buf { uchar* virt; + ulong phys; uint nbytes; }; @@ -137,6 +143,8 @@ struct IOstate volatile Buf *current; /* next dma to finish */ volatile Buf *next; /* next candidate for dma */ volatile Buf *filling; /* buffer being filled */ +/* just be be cute (and to have defines like linux, a real operating system) */ +#define emptying filling }; static struct @@ -172,7 +180,7 @@ static struct } volumes[] = { [Vaudio] "audio", Fout|Fmono, 50, 50, -[Vmic] "mic", Fin, 0, 0, +[Vmic] "mic", Fin|Fmono, 0, 0, [Vtreb] "treb", Fout|Fmono, 50, 50, [Vbass] "bass", Fout|Fmono, 50, 50, @@ -379,8 +387,10 @@ bufinit(IOstate *b) int i; if (debug) print("#A: bufinit\n"); - for (i = 0; i < Nbuf; i++) + for (i = 0; i < Nbuf; i++) { b->buf[i].virt = xalloc(Bufsize); + b->buf[i].phys = PADDR(b->buf[i].virt); + } b->bufinit = 1; }; @@ -398,12 +408,19 @@ setempty(IOstate *b) b->next = b->buf; } +static int +audioqnotempty(void *x) +{ + IOstate *s = x; + + return dmaidle(s->dma) || s->emptying != s->next; +} + static int audioqnotfull(void *x) { IOstate *s = x; - /* called with lock */ return dmaidle(s->dma) || s->filling != s->current; } @@ -418,8 +435,12 @@ uchar status1 = 0x80; uchar data00 = 0x00; /* volume control, bits 0 – 5 */ uchar data01 = 0x40; uchar data02 = 0x90; +ushort data0e0 = 0xe0c0; +ushort data0e1 = 0xe0c1; ushort data0e2 = 0xf2c2; -ushort data0e4 = 0xf3c4; +/* there is no data0e3 */ +ushort data0e4 = 0xe0c4; +ushort data0e5 = 0xe0c5; ushort data0e6 = 0xe3c6; static void @@ -459,7 +480,6 @@ enable(void) L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e2, 2); - L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 ); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e6, 2 ); if (debug) { @@ -495,6 +515,22 @@ mxvolume(void) { if(audio.amode & Aread){ left = audio.livol; right = audio.rivol; + if (left[Vmic]+right[Vmic] == 0) { + /* Turn on automatic gain control (AGC) */ + data0e4 |= 0x1000; + L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 ); + } else { + int v; + /* Turn on manual gain control */ + v = ((left[Vmic]+right[Vmic])*0x7f/200)&0x7f; + data0e4 &= ~0x1300; + data0e5 &= ~0x1f00; + data0e4 |= (v & 0x3)<<8; + data0e5 |= (v & 0x7c)<<6; + L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 ); + L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e5, 2 ); + } + } if(audio.amode & Awrite){ left = audio.lovol; @@ -576,7 +612,7 @@ sendaudio(IOstate *s) { ilock(&s->ilock); while (s->next != s->filling) { assert(s->next->nbytes); - if ((n = dmastart(s->dma, s->next->virt, s->next->nbytes)) == 0) { + if ((n = dmastart(s->dma, s->next->phys, s->next->nbytes)) == 0) { iostats.faildma++; break; } @@ -598,6 +634,36 @@ sendaudio(IOstate *s) { iunlock(&s->ilock); } +static void +recvaudio(IOstate *s) { + /* interrupt routine calls this too */ + int n; + + if (debug > 1) print("#A: recvaudio\n"); + ilock(&s->ilock); + while (s->next != s->emptying) { + assert(s->next->nbytes == 0); + if ((n = dmastart(s->dma, s->next->phys, Bufsize)) == 0) { + iostats.faildma++; + break; + } + iostats.totaldma++; + switch (n) { + case 1: + iostats.idledma++; + break; + case 3: + iostats.faildma++; + break; + } + if (debug > 1) print("#A: dmastart @%p\n", s->next); + s->next++; + if (s->next == &s->buf[Nbuf]) + s->next = &s->buf[0]; + } + iunlock(&s->ilock); +} + static void audiointr(void *x, ulong ndma) { IOstate *s = x; @@ -610,6 +676,15 @@ audiointr(void *x, ulong ndma) { s->current = &s->buf[0]; if (ndma > 0) sendaudio(s); + } else if (s == &audio.i) { + /* Only interrupt routine touches s->current */ + if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current); + s->current->nbytes = Bufsize; + s->current++; + if (s->current == &s->buf[Nbuf]) + s->current = &s->buf[0]; + if (ndma > 0) + recvaudio(s); } wakeup(&s->vous); } @@ -667,10 +742,10 @@ audioopen(Chan *c, int omode) /* read */ audio.amode |= Aread; if(audio.i.bufinit == 0) - bufinit(&audio.i); - setempty(&audio.i); + bufinit(s); + setempty(s); s->chan = c; - s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)&audio.o); + s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s); } if (omode & 0x2) { outenable(); @@ -722,15 +797,14 @@ audioclose(Chan *c) nexterror(); } if (audio.o.chan == c) { + /* closing the write end */ + audio.amode &= ~Awrite; s = &audio.o; qlock(s); if(waserror()){ qunlock(s); nexterror(); } - /* closing the write end */ - audio.amode &= ~Awrite; - if (s->filling->nbytes) { /* send remaining partial buffer */ s->filling++; @@ -749,8 +823,18 @@ audioclose(Chan *c) if (audio.i.chan == c) { /* closing the read end */ audio.amode &= ~Aread; + s = &audio.i; + qlock(s); + if(waserror()){ + qunlock(s); + nexterror(); + } + dmawait(s->dma); indisable(); - setempty(&audio.i); + setempty(s); + dmafree(s->dma); + qunlock(s); + poperror(); } if (audio.amode == 0) { /* turn audio off */ @@ -775,26 +859,62 @@ audioread(Chan *c, void *v, long n, vlong off) char buf[300]; int j; ulong offset = off; - char *a; + char *p; + IOstate *s; n0 = n; - a = v; + p = v; switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qdir: - return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); + return devdirread(c, p, n, audiodir, nelem(audiodir), devgen); case Qaudio: + if (debug > 1) print("#A: read %ld\n", n); + if((audio.amode & Aread) == 0) + error(Emode); + s = &audio.o; + qlock(s); + if(waserror()){ + qunlock(s); + nexterror(); + } + while(n > 0) { + /* wait if dma in progress */ + while (!dmaidle(s->dma) && s->emptying == s->next) { + if (debug > 1) print("#A: sleep\n"); + sleep(&s->vous, audioqnotempty, s); + } + + m = Bufsize - s->emptying->nbytes; + if(m > n) + m = n; + memmove(p, s->emptying->virt + s->emptying->nbytes, m); + + s->emptying->nbytes -= m; + n -= m; + p += m; + if(s->emptying->nbytes == 0) { + if (debug > 1) print("#A: emptied @%p\n", s->emptying); + s->emptying++; + if (s->emptying == &s->buf[Nbuf]) + s->emptying = s->buf; + sendaudio(s); + } + } + poperror(); + qunlock(s); + break; break; case Qstatus: buf[0] = 0; snprint(buf, sizeof(buf), "bytes %lud\ntime %lld\n", audio.totcount, audio.tottime); - return readstr(offset, a, n, buf); + return readstr(offset, p, n, buf); case Qvolume: j = 0; @@ -835,7 +955,7 @@ audioread(Chan *c, void *v, long n, vlong off) } j += snprint(buf+j, sizeof(buf)-j, "\n"); } - return readstr(offset, a, n, buf); + return readstr(offset, p, n, buf); } return n0-n; } @@ -874,6 +994,8 @@ audiowrite(Chan *c, void *vp, long n, vlong) */ if(field[i][0] >= '0' && field[i][0] <= '9') { m = strtoul(field[i], 0, 10); + if (m < 0 || m > 100) + error(Evolume); if(left && out) audio.lovol[v] = m; if(left && in) diff --git a/bitsy/fns.h b/bitsy/fns.h index 91f57f2bfa8440f97bdc28d859b55898a7007d4a..f5760898a47bfa548c07b1755d3aae1b1f788adb 100644 --- a/bitsy/fns.h +++ b/bitsy/fns.h @@ -15,9 +15,12 @@ void clockinit(void); void delay(int); void µdelay(int); void dmainit(void); +void egpiobits(ulong, int); void evenaddr(ulong); +void exppackpower(int); +void flashprogpower(int); void flushmmu(void); -int fpiarm(Ureg *ur); +int fpiarm(Ureg *ur); char* getconf(char*); ulong getfar(void); ulong getfsr(void); @@ -30,6 +33,7 @@ void intrenable(int, void (*)(Ureg*, void*), void*, char*); int iprint(char*, ...); void irpower(int); void lcdpower(int); +void* mapmem(ulong, int); void mappedIvecEnable(void); void mappedIvecDisable(void); void* mapspecial(ulong, int); @@ -39,9 +43,12 @@ void mmuenable(void); void mmudisable(void); void mmuinvalidate(void); void mmuinvalidateaddr(ulong); +ulong mmu_kaddr(ulong); +ulong mmu_paddr(ulong); int µcputc(Queue*, int); void noted(Ureg*, ulong); int notify(Ureg*); +int pcmcistuple(int, int, int, void*, int); void penbutton(int, int); void pentrackxy(int x, int y); #define procrestore(p) @@ -74,9 +81,9 @@ int unsac(uchar*, uchar*, int, int); void vectors(void); void vtable(void); void wbflush(void); +#define KADDR(a) (void*)mmu_kaddr((ulong)(a)) +#define PADDR(a) mmu_paddr((ulong)(a)) #define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) -#define KADDR(a) ((void*)((ulong)(a)|KZERO)) -#define PADDR(a) ((ulong)(a)) #define dcflush(a, b) diff --git a/bitsy/io.h b/bitsy/io.h index b28f153a8b7568bde04131f90ee8ee08bff987ee..326be19af229d33f0a5b52af626b1c42462e0343 100644 --- a/bitsy/io.h +++ b/bitsy/io.h @@ -76,7 +76,8 @@ enum GPIO_COM_CTS_i= 1<<25, /* CTS from UART3 */ GPIO_COM_RTS_o= 1<<26, /* RTS to UART3 */ GPIO_OPT_IND_i= 1<<27, /* expansion pack inserted */ -/* Peripheral Unit GPIO pin assignments: */ + +/* Peripheral Unit GPIO pin assignments: alternate functions */ GPIO_SSP_TXD_o= 1<<10, /* SSP Transmit Data */ GPIO_SSP_RXD_i= 1<<11, /* SSP Receive Data */ GPIO_SSP_SCLK_o= 1<<12, /* SSP Sample CLocK */ @@ -263,3 +264,92 @@ struct MCPregs { ulong control1; }; extern MCPregs *mcpregs; + +/* + * PCMCIA support code. + */ + +typedef struct PCMmap PCMmap; +typedef struct PCMslot PCMslot; +typedef struct PCMconftab PCMconftab; +typedef struct Cisdat Cisdat; + +/* + * Map between ISA memory space and PCMCIA card memory space. + */ +struct PCMmap { + ulong ca; /* card address */ + ulong cea; /* card end address */ + ulong isa; /* local virtual address */ + int len; /* length of the ISA area */ + int attr; /* attribute memory */ +}; + +/* configuration table entry */ +struct PCMconftab +{ + int index; + ushort irqs; /* legal irqs */ + uchar irqtype; + uchar bit16; /* true for 16 bit access */ + struct { + ulong start; + ulong len; + } io[16]; + int nio; + uchar vpp1; + uchar vpp2; + uchar memwait; + ulong maxwait; + ulong readywait; + ulong otherwait; +}; + +/* cis memory walking */ +struct Cisdat +{ + uchar *cisbase; + int cispos; + int cisskip; + int cislen; +}; + +/* a card slot */ +struct PCMslot +{ + Lock; + int ref; + + long memlen; /* memory length */ + uchar slotno; /* slot number */ + void *regs; /* i/o registers */ + void *mem; /* memory */ + void *attr; /* attribute memory */ + + /* status */ + uchar special; /* in use for a special device */ + uchar already; /* already inited */ + uchar occupied; + uchar battery; + uchar wrprot; + uchar powered; + uchar configed; + uchar enabled; + uchar busy; + + /* cis info */ + ulong msec; /* time of last slotinfo call */ + char verstr[512]; /* version string */ + uchar cpresent; /* config registers present */ + ulong caddr; /* relative address of config registers */ + int nctab; /* number of config table entries */ + PCMconftab ctab[8]; + PCMconftab *def; /* default conftab */ + + /* for walking through cis */ + Cisdat; + + /* maps are fixed */ + PCMmap memmap; + PCMmap attrmap; +}; diff --git a/bitsy/main.c b/bitsy/main.c index 1585eeaf97901c6dfa7ff6cb9826456507ba176e..52682c032b96aac1d555615bdceb889dc2c41a67 100644 --- a/bitsy/main.c +++ b/bitsy/main.c @@ -407,7 +407,7 @@ sspinit(void) { static ulong egpiosticky; -static void +void egpiobits(ulong bits, int on) { if(on) @@ -458,3 +458,11 @@ flashprogpower(int on) { egpiobits(EGPIO_prog_flash, on); } + +void +exppackpower(int on) +{ + egpiobits(EGPIO_exp_full_power|EGPIO_exp_nvram_power, on); + if(on) + delay(100); +} diff --git a/bitsy/mem.h b/bitsy/mem.h index 8f6a7385cb7edc2276b1935c5e07c542efa3daa1..385df721bdaf694d05ed9bb113372c6a2ee9f580 100644 --- a/bitsy/mem.h +++ b/bitsy/mem.h @@ -45,8 +45,10 @@ #define UTZERO (UZERO+BY2PG) /* first address in user text */ #define KZERO 0xC0000000 /* base of kernel address space */ #define KTZERO 0xC0008000 /* first address in kernel text */ -#define REGZERO 0xA0000000 /* 256 meg for mapspecial regs */ -#define REGTOP 0xB0000000 /* ... */ +#define EMEMZERO 0x90000000 /* 256 meg for add on memory */ +#define EMEMTOP 0xA0000000 /* ... */ +#define REGZERO 0xA0000000 /* 128 meg for mapspecial regs */ +#define REGTOP 0xA8000000 /* ... */ #define FLASHZERO 0xB0000000 /* 128 meg for flash */ #define FLASHTOP 0xB8000000 /* ... */ #define DRAMZERO 0xC0000000 /* 128 meg for memory */ @@ -106,6 +108,16 @@ #define INTRREGS 0x90050000 /* interrupt registers */ #define OSTIMERREGS 0x90000000 /* operating system timer registers */ +/* + * PCMCIA addresses + */ +#define PHYSPCM0REGS 0x20000000 +#define PYHSPCM0ATTR 0x28000000 +#define PYHSPCM0MEM 0x2C000000 +#define PHYSPCM1REGS 0x30000000 +#define PYHSPCM1ATTR 0x38000000 +#define PYHSPCM1MEM 0x3C000000 + /* * Program Status Registers */ diff --git a/bitsy/mmu.c b/bitsy/mmu.c index 361350ff4256415de5ed81a538b88e5d65b7d902..2abcc34f7e3bc7fb47a381cc318e9a5874a10c69 100644 --- a/bitsy/mmu.c +++ b/bitsy/mmu.c @@ -51,7 +51,7 @@ enum }; ulong *l1table; - +static int mmuinited; /* * We map all of memory, flash, and the zeros area with sections. @@ -67,28 +67,27 @@ mmuinit(void) l1table = xspanalloc(16*1024, 16*1024, 0); memset(l1table, 0, 16*1024); - /* map low mem */ + /* map low mem (I really don't know why I have to do this -- presotto) */ for(o = 0; o < 1*OneMeg; o += OneMeg) l1table[(0+o)>>20] = L1Section | L1KernelRW| L1Domain0 | L1Cached | L1Buffered | ((0+o)&L1SectBaseMask); /* map DRAM */ - for(o = 0; o < 128*OneMeg; o += OneMeg) + for(o = 0; o < DRAMTOP-DRAMZERO; o += OneMeg) l1table[(DRAMZERO+o)>>20] = L1Section | L1KernelRW| L1Domain0 | L1Cached | L1Buffered | ((PHYSDRAM0+o)&L1SectBaseMask); /* map zeros area */ - for(o = 0; o < 128 * OneMeg; o += OneMeg) + for(o = 0; o < NULLTOP-NULLZERO; o += OneMeg) l1table[(NULLZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0 | L1Cached | L1Buffered | ((PHYSNULL0+o)&L1SectBaseMask); /* map flash */ - for(o = 0; o < 128 * OneMeg; o += OneMeg) + for(o = 0; o < FLASHTOP-FLASHZERO; o += OneMeg) l1table[(FLASHZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0 - | L1Cached | L1Buffered | ((PHYSFLASH0+o)&L1SectBaseMask); /* map peripheral control module regs */ @@ -117,13 +116,15 @@ mmuinit(void) mmuinvalidate(); mmuenable(); cacheflush(); + + mmuinited = 1; } /* - * map special space uncached, assume that the space isn't already mapped + * map on request */ -void* -mapspecial(ulong pa, int len) +static void* +_map(ulong pa, int len, ulong zero, ulong top, ulong l1prop, ulong l2prop) { ulong *t; ulong va, i, base, end, off, entry; @@ -141,14 +142,14 @@ mapspecial(ulong pa, int len) } off = pa - base; - for(va = REGZERO; va < REGTOP && base <= end; va += OneMeg){ + for(va = zero; va < top && base <= end; va += OneMeg){ switch(l1table[va>>20] & L1TypeMask){ default: /* found unused entry on level 1 table */ if(large){ if(rv == nil) rv = (ulong*)(va+off); - l1table[va>>20] = L1Section | L1KernelRW | L1Domain0 | + l1table[va>>20] = L1Section | l1prop | L1Domain0 | (base & L1SectBaseMask); base += OneMeg; continue; @@ -166,7 +167,7 @@ mapspecial(ulong pa, int len) entry = l1table[va>>20]; i = entry & L1SectBaseMask; if(pa >= i && (pa+len) <= i + OneMeg) - if((entry & ~L1SectBaseMask) == (L1Section | L1KernelRW | L1Domain0)) + if((entry & ~L1SectBaseMask) == (L1Section | l1prop | L1Domain0)) return (void*)(va + (pa & (OneMeg-1))); continue; @@ -185,7 +186,7 @@ mapspecial(ulong pa, int len) if((entry & L2TypeMask) != L2SmallPage){ if(rv == nil) rv = (ulong*)(va+i+off); - t[i>>PGSHIFT] = L2SmallPage | L2KernelRW | + t[i>>PGSHIFT] = L2SmallPage | l2prop | (base & L2PageBaseMask); base += BY2PG; continue; @@ -201,6 +202,109 @@ mapspecial(ulong pa, int len) return rv; } +/* map in i/o registers */ +void* +mapspecial(ulong pa, int len) +{ + return _map(pa, len, REGZERO, REGTOP, L1KernelRW, L2KernelRW); +} + +/* map add on memory */ +void* +mapmem(ulong pa, int len) +{ + return _map(pa, len, EMEMZERO, EMEMTOP, L1KernelRW|L1Cached|L1Buffered, + L2KernelRW|L2Cached|L2Buffered); +} + +/* map a virtual address to a physical one */ +ulong +mmu_paddr(ulong va) +{ + ulong entry; + ulong *t; + + entry = l1table[va>>20]; + switch(entry & L1TypeMask){ + case L1Section: + return (entry & L1SectBaseMask) | (va & (OneMeg-1)); + case L1PageTable: + t = (ulong*)(entry & L1PTBaseMask); + va &= OneMeg-1; + entry = t[va>>PGSHIFT]; + switch(entry & L1TypeMask){ + case L2SmallPage: + return (entry & L2PageBaseMask) | (va & (BY2PG-1)); + } + } + return 0; +} + +/* map a physical address to a virtual one */ +static ulong +findva(ulong pa, ulong zero, ulong top) +{ + int i; + ulong entry, va; + ulong start, end; + ulong *t; + + for(va = zero; va < top; va += OneMeg){ + /* search the L1 entry */ + entry = l1table[va>>20]; + switch(entry & L1TypeMask){ + default: + return 0; /* no holes */ + case L1Section: + start = entry & L1SectBaseMask; + end = start + OneMeg; + if(pa >= start && pa < end) + return va | (pa & (OneMeg-1)); + continue; + case L1PageTable: + break; + } + + /* search the L2 entry */ + t = (ulong*)(l1table[va>>20] & L1PTBaseMask); + for(i = 0; i < OneMeg; i += BY2PG){ + entry = t[i>>PGSHIFT]; + + /* found unused entry on level 2 table */ + if((entry & L2TypeMask) != L2SmallPage) + break; + + start = entry & L2PageBaseMask; + end = start + BY2PG; + if(pa >= start && pa < end) + return va | (BY2PG*i) | (pa & (BY2PG-1)); + } + } + return 0; +} +ulong +mmu_kaddr(ulong pa) +{ + ulong va; + + /* try the easy stuff first (the first case is true most of the time) */ + if(pa >= PHYSDRAM0 && pa <= PHYSDRAM0+(DRAMTOP-DRAMZERO)) + return DRAMZERO+(pa-PHYSDRAM0); + if(pa >= PHYSFLASH0 && pa <= PHYSFLASH0+(FLASHTOP-FLASHZERO)) + return FLASHZERO+(pa-PHYSFLASH0); + if(pa >= PHYSNULL0 && pa <= PHYSNULL0+(NULLTOP-NULLZERO)) + return NULLZERO+(pa-PHYSNULL0); + + if(!mmuinited) + return 0; /* this shouldn't happen */ + + /* walk the map for the special regs and extended memory */ + va = findva(pa, EMEMZERO, EMEMTOP); + if(va != 0) + return va; + return findva(pa, REGZERO, REGTOP); +} + /* * table to map fault.c bits to physical bits */ diff --git a/bitsy/sa1110dma.c b/bitsy/sa1110dma.c index dcf3e32a751f422df1fdb75a174d04283a5a19d2..ef455dc61ae41027bfa2c844cc51b751a406a55e 100644 --- a/bitsy/sa1110dma.c +++ b/bitsy/sa1110dma.c @@ -57,9 +57,9 @@ struct dmaregs { ulong dcsr_set; ulong dcsr_clr; ulong dcsr_rd; - void* dstrtA; + ulong dstrtA; ulong dxcntA; - void* dstrtB; + ulong dstrtB; ulong dxcntB; } *dmaregs; @@ -116,7 +116,7 @@ dmafree(int i) { } ulong -dmastart(int chan, void *addr, int count) { +dmastart(int chan, ulong addr, int count) { ulong status, n; static int last; @@ -128,7 +128,7 @@ dmastart(int chan, void *addr, int count) { if ((status & (1<cp->xreg, pp->base + index); - return inb(pp->cp->dreg); + outb(((I82365*)pp->cp)->xreg, pp->base + index); + return inb(((I82365*)pp->cp)->dreg); } static void -wrreg(Slot *pp, int index, uchar val) +wrreg(PCMslot *pp, int index, uchar val) { - outb(pp->cp->xreg, pp->base + index); - outb(pp->cp->dreg, val); + outb(((I82365*)pp->cp)->xreg, pp->base + index); + outb(((I82365*)pp->cp)->dreg, val); } /* * get info about card */ static void -slotinfo(Slot *pp) +slotinfo(PCMslot *pp) { uchar isr; @@ -257,7 +178,7 @@ vcode(int volt) * enable the slot card */ static void -slotena(Slot *pp) +slotena(PCMslot *pp) { if(pp->enabled) return; @@ -273,7 +194,7 @@ slotena(Slot *pp) /* get configuration */ slotinfo(pp); if(pp->occupied){ - cisread(pp); + pcmcisread(pp); pp->enabled = 1; } else wrreg(pp, Rpc, Fautopower); @@ -283,7 +204,7 @@ slotena(Slot *pp) * disable the slot card */ static void -slotdis(Slot *pp) +slotdis(PCMslot *pp) { wrreg(pp, Rpc, 0); /* turn off card power */ wrreg(pp, Rwe, 0); /* no windows */ @@ -297,7 +218,7 @@ static void i82365intr(Ureg *, void *) { uchar csc, was; - Slot *pp; + PCMslot *pp; if(slot == 0) return; @@ -326,7 +247,7 @@ enum PCMmap* pcmmap(int slotno, ulong offset, int len, int attr) { - Slot *pp; + PCMslot *pp; uchar we, bit; PCMmap *m, *nm; int i; @@ -346,7 +267,7 @@ pcmmap(int slotno, ulong offset, int len, int attr) we = rdreg(pp, Rwe); bit = 1; nm = 0; - for(m = pp->mmap; m < &pp->mmap[Nmap]; m++){ + for(m = pp->mmap; m < &pp->mmap[nelem(pp->mmap)]; m++){ if((we & bit)) if(m->attr == attr) if(offset >= m->ca && e <= m->cea){ @@ -406,7 +327,7 @@ pcmmap(int slotno, ulong offset, int len, int attr) void pcmunmap(int slotno, PCMmap* m) { - Slot *pp; + PCMslot *pp; pp = slot + slotno; lock(&pp->mlock); @@ -415,7 +336,7 @@ pcmunmap(int slotno, PCMmap* m) } static void -increfp(Slot *pp) +increfp(PCMslot *pp) { lock(pp); if(pp->ref++ == 0) @@ -424,7 +345,7 @@ increfp(Slot *pp) } static void -decrefp(Slot *pp) +decrefp(PCMslot *pp) { lock(pp); if(pp->ref-- == 1) @@ -438,7 +359,7 @@ decrefp(Slot *pp) int pcmspecial(char *idstr, ISAConf *isa) { - Slot *pp; + PCMslot *pp; extern char *strstr(char*, char*); int enabled; @@ -479,7 +400,7 @@ pcmspecial(char *idstr, ISAConf *isa) void pcmspecialclose(int slotno) { - Slot *pp; + PCMslot *pp; if(slotno >= nslot) panic("pcmspecialclose"); @@ -508,7 +429,7 @@ pcmgen(Chan *c, Dirtab *, int , int i, Dir *dp) int slotno; Qid qid; long len; - Slot *pp; + PCMslot *pp; char name[NAMELEN]; if(i == DEVDOTDOT){ @@ -594,7 +515,6 @@ i82365probe(int x, int d, int dev) break; } -#ifdef adsf /* if it's not a Cirrus, it could be a Vadem... */ if(cp->type == Ti82365){ /* unlock the Vadem extended regs */ @@ -615,7 +535,6 @@ i82365probe(int x, int d, int dev) c = inb(d); outb(d, c & ~0xC0); } -#endif asdf /* low power mode */ outb(x, Rmisc2 + (dev<<7)); @@ -641,7 +560,7 @@ i82365probe(int x, int d, int dev) } static void -i82365dump(Slot *pp) +i82365dump(PCMslot *pp) { int i; @@ -664,7 +583,7 @@ i82365reset(void) static int already; int i, j; I82365 *cp; - Slot *pp; + PCMslot *pp; char buf[NAMELEN]; if(already) @@ -687,7 +606,7 @@ i82365reset(void) } for(i = 0; i < ncontroller; i++) nslot += controller[i]->nslot; - slot = xalloc(nslot * sizeof(Slot)); + slot = xalloc(nslot * sizeof(PCMslot)); /* if the card is there turn on 5V power to keep its battery alive */ lastslot = slot; @@ -788,7 +707,7 @@ pcmread(int slotno, int attr, void *a, long n, vlong off) int i, len; PCMmap *m; uchar *ac; - Slot *pp; + PCMslot *pp; ulong offset = off; pp = slot + slotno; @@ -827,7 +746,7 @@ static long i82365read(Chan *c, void *a, long n, vlong off) { char *p, *buf, *e; - Slot *pp; + PCMslot *pp; ulong offset = off; switch(TYPE(c)){ @@ -874,7 +793,7 @@ pcmwrite(int dev, int attr, void *a, long n, vlong off) int i, len; PCMmap *m; uchar *ac; - Slot *pp; + PCMslot *pp; ulong offset = off; pp = slot + dev; @@ -912,7 +831,7 @@ pcmwrite(int dev, int attr, void *a, long n, vlong off) static long i82365write(Chan *c, void *a, long n, vlong off) { - Slot *pp; + PCMslot *pp; char buf[32]; switch(TYPE(c)){ @@ -965,15 +884,15 @@ Dev i82365devtab = { }; /* - * configure the Slot for IO. We assume very heavily that we can read + * configure the PCMslot for IO. We assume very heavily that we can read * configuration info from the CIS. If not, we won't set up correctly. */ static int pcmio(int slotno, ISAConf *isa) { uchar we, x, *p; - Slot *pp; - Conftab *ct, *et, *t; + PCMslot *pp; + PCMconftab *ct, *et, *t; PCMmap *m; int i, index, irq; char *cp; @@ -1094,426 +1013,3 @@ pcmio(int slotno, ISAConf *isa) } return 0; } - -/* - * read and crack the card information structure enough to set - * important parameters like power - */ -static void tcfig(Slot*, Cisdat*, int); -static void tentry(Slot*, Cisdat*, int); -static void tvers1(Slot*, Cisdat*, int); - -struct { - int n; - void (*parse)(Slot*, Cisdat*, int); -} cistab[] = { - 0x15, tvers1, - 0x1A, tcfig, - 0x1B, tentry, -}; - -static int -readc(Cisdat *pp, uchar *x) -{ - if(pp->cispos >= pp->cislen) - return 0; - *x = pp->cisbase[pp->cisskip*pp->cispos]; - pp->cispos++; - return 1; -} - -static int -xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr) -{ - PCMmap *m; - Cisdat cis; - int i, l; - uchar *p; - uchar type, link, n, c; - int this, subtype; - - m = pcmmap(slotno, 0, 0, attr); - if(m == 0) - return -1; - - cis.cisbase = KADDR(m->isa); - cis.cispos = 0; - cis.cisskip = attr ? 2 : 1; - cis.cislen = Mchunk; - - /* loop through all the tuples */ - for(i = 0; i < 1000; i++){ - this = cis.cispos; - if(readc(&cis, &type) != 1) - break; - if(type == 0xFF) - break; - if(readc(&cis, &link) != 1) - break; - if(link == 0xFF) - break; - - n = link; - if (link > 1 && subtuple != -1) { - if (readc(&cis, &c) != 1) - break; - subtype = c; - n--; - } else - subtype = -1; - - if(type == tuple && subtype == subtuple) { - p = v; - for(l=0; l= 0) - return n; - return xcistuple(slotno, tuple, subtuple, v, nv, 0); -} - -static void -cisread(Slot *pp) -{ - uchar v[256]; - int i, nv; - Cisdat cis; - - memset(pp->ctab, 0, sizeof(pp->ctab)); - pp->caddr = 0; - pp->cpresent = 0; - pp->configed = 0; - pp->nctab = 0; - pp->verstr[0] = 0; - - for(i = 0; i < nelem(cistab); i++) { - if((nv = pcmcistuple(pp->slotno, cistab[i].n, -1, v, sizeof(v))) >= 0) { - cis.cisbase = v; - cis.cispos = 0; - cis.cisskip = 1; - cis.cislen = nv; - - (*cistab[i].parse)(pp, &cis, cistab[i].n); - } - } -} - -static ulong -getlong(Cisdat *cis, int size) -{ - uchar c; - int i; - ulong x; - - x = 0; - for(i = 0; i < size; i++){ - if(readc(cis, &c) != 1) - break; - x |= c<<(i*8); - } - return x; -} - -static void -tcfig(Slot *pp, Cisdat *cis, int ) -{ - uchar size, rasize, rmsize; - uchar last; - - if(readc(cis, &size) != 1) - return; - rasize = (size&0x3) + 1; - rmsize = ((size>>2)&0xf) + 1; - if(readc(cis, &last) != 1) - return; - pp->caddr = getlong(cis, rasize); - pp->cpresent = getlong(cis, rmsize); -} - -static ulong vexp[8] = -{ - 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 -}; -static ulong vmant[16] = -{ - 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90, -}; - -static ulong -microvolt(Cisdat *cis) -{ - uchar c; - ulong microvolts; - ulong exp; - - if(readc(cis, &c) != 1) - return 0; - exp = vexp[c&0x7]; - microvolts = vmant[(c>>3)&0xf]*exp; - while(c & 0x80){ - if(readc(cis, &c) != 1) - return 0; - switch(c){ - case 0x7d: - break; /* high impedence when sleeping */ - case 0x7e: - case 0x7f: - microvolts = 0; /* no connection */ - break; - default: - exp /= 10; - microvolts += exp*(c&0x7f); - } - } - return microvolts; -} - -static ulong -nanoamps(Cisdat *cis) -{ - uchar c; - ulong nanoamps; - - if(readc(cis, &c) != 1) - return 0; - nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf]; - while(c & 0x80){ - if(readc(cis, &c) != 1) - return 0; - if(c == 0x7d || c == 0x7e || c == 0x7f) - nanoamps = 0; - } - return nanoamps; -} - -/* - * only nominal voltage is important for config - */ -static ulong -power(Cisdat *cis) -{ - uchar feature; - ulong mv; - - mv = 0; - if(readc(cis, &feature) != 1) - return 0; - if(feature & 1) - mv = microvolt(cis); - if(feature & 2) - microvolt(cis); - if(feature & 4) - microvolt(cis); - if(feature & 8) - nanoamps(cis); - if(feature & 0x10) - nanoamps(cis); - if(feature & 0x20) - nanoamps(cis); - if(feature & 0x40) - nanoamps(cis); - return mv/1000000; -} - -static ulong mantissa[16] = -{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; - -static ulong exponent[8] = -{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, }; - -static ulong -ttiming(Cisdat *cis, int scale) -{ - uchar unscaled; - ulong nanosecs; - - if(readc(cis, &unscaled) != 1) - return 0; - nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10; - nanosecs = nanosecs * vexp[scale]; - return nanosecs; -} - -static void -timing(Cisdat *cis, Conftab *ct) -{ - uchar c, i; - - if(readc(cis, &c) != 1) - return; - i = c&0x3; - if(i != 3) - ct->maxwait = ttiming(cis, i); /* max wait */ - i = (c>>2)&0x7; - if(i != 7) - ct->readywait = ttiming(cis, i); /* max ready/busy wait */ - i = (c>>5)&0x7; - if(i != 7) - ct->otherwait = ttiming(cis, i); /* reserved wait */ -} - -static void -iospaces(Cisdat *cis, Conftab *ct) -{ - uchar c; - int i, nio; - - ct->nio = 0; - if(readc(cis, &c) != 1) - return; - - ct->bit16 = ((c>>5)&3) >= 2; - if(!(c & 0x80)){ - ct->io[0].start = 0; - ct->io[0].len = 1<<(c&0x1f); - ct->nio = 1; - return; - } - - if(readc(cis, &c) != 1) - return; - - nio = (c&0xf)+1; - for(i = 0; i < nio; i++){ - ct->io[i].start = getlong(cis, (c>>4)&0x3); - ct->io[0].len = getlong(cis, (c>>6)&0x3); - } - ct->nio = nio; -} - -static void -irq(Cisdat *cis, Conftab *ct) -{ - uchar c; - - if(readc(cis, &c) != 1) - return; - ct->irqtype = c & 0xe0; - if(c & 0x10) - ct->irqs = getlong(cis, 2); - else - ct->irqs = 1<<(c&0xf); - ct->irqs &= 0xDEB8; /* levels available to card */ -} - -static void -memspace(Cisdat *cis, int asize, int lsize, int host) -{ - ulong haddress, address, len; - - len = getlong(cis, lsize)*256; - address = getlong(cis, asize)*256; - USED(len, address); - if(host){ - haddress = getlong(cis, asize)*256; - USED(haddress); - } -} - -static void -tentry(Slot *pp, Cisdat *cis, int ) -{ - uchar c, i, feature; - Conftab *ct; - - if(pp->nctab >= Maxctab) - return; - if(readc(cis, &c) != 1) - return; - ct = &pp->ctab[pp->nctab++]; - - /* copy from last default config */ - if(pp->def) - *ct = *pp->def; - - ct->index = c & 0x3f; - - /* is this the new default? */ - if(c & 0x40) - pp->def = ct; - - /* memory wait specified? */ - if(c & 0x80){ - if(readc(cis, &i) != 1) - return; - if(i&0x80) - ct->memwait = 1; - } - - if(readc(cis, &feature) != 1) - return; - switch(feature&0x3){ - case 1: - ct->vpp1 = ct->vpp2 = power(cis); - break; - case 2: - power(cis); - ct->vpp1 = ct->vpp2 = power(cis); - break; - case 3: - power(cis); - ct->vpp1 = power(cis); - ct->vpp2 = power(cis); - break; - default: - break; - } - if(feature&0x4) - timing(cis, ct); - if(feature&0x8) - iospaces(cis, ct); - if(feature&0x10) - irq(cis, ct); - switch((feature>>5)&0x3){ - case 1: - memspace(cis, 0, 2, 0); - break; - case 2: - memspace(cis, 2, 2, 0); - break; - case 3: - if(readc(cis, &c) != 1) - return; - for(i = 0; i <= (c&0x7); i++) - memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80); - break; - } - pp->configed++; -} - -static void -tvers1(Slot *pp, Cisdat *cis, int ) -{ - uchar c, major, minor; - int i; - - if(readc(cis, &major) != 1) - return; - if(readc(cis, &minor) != 1) - return; - for(i = 0; i < sizeof(pp->verstr)-1; i++){ - if(readc(cis, &c) != 1) - return; - if(c == 0) - c = '\n'; - if(c == 0xff) - break; - pp->verstr[i] = c; - } - pp->verstr[i] = 0; -} diff --git a/pc/fns.h b/pc/fns.h index a8bdb2c5545ea44b278e750591779cffe0d92881..da5cee1d332cfe1e787f0a8b8f416ce8c0023eb9 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -95,6 +95,7 @@ Pcidev* pcimatch(Pcidev*, int, int); Pcidev* pcimatchtbdf(int); void pcireset(void); void pcisetbme(Pcidev*); +void pcmcisread(PCMslot*); int pcmcistuple(int, int, int, void*, int); PCMmap* pcmmap(int, ulong, int, int); int pcmspecial(char*, ISAConf*); diff --git a/pc/io.h b/pc/io.h index 35454e020e7f9af9ddab7edcfb7ee6f7a2c11b79..0d2276f96b4635443cd598cf39ce56cf7dec2bba 100644 --- a/pc/io.h +++ b/pc/io.h @@ -209,21 +209,6 @@ struct Pcidev #define ISAWINDOW 0 #define ISAWADDR(va) (PADDR(va)+ISAWINDOW) -/* - * PCMCIA support code. - */ -/* - * Map between ISA memory space and PCMCIA card memory space. - */ -struct PCMmap { - ulong ca; /* card address */ - ulong cea; /* card end address */ - ulong isa; /* ISA address */ - int len; /* length of the ISA area */ - int attr; /* attribute memory */ - int ref; -}; - /* SMBus transactions */ enum { @@ -249,3 +234,92 @@ struct SMBus { int busy; void (*transact)(SMBus*, int, int, int, uchar*); }; + +/* + * PCMCIA support code. + */ + +typedef struct PCMslot PCMslot; +typedef struct PCMconftab PCMconftab; +typedef struct Cisdat Cisdat; + +/* + * Map between ISA memory space and PCMCIA card memory space. + */ +struct PCMmap { + ulong ca; /* card address */ + ulong cea; /* card end address */ + ulong isa; /* ISA address */ + int len; /* length of the ISA area */ + int attr; /* attribute memory */ + int ref; +}; + +/* configuration table entry */ +struct PCMconftab +{ + int index; + ushort irqs; /* legal irqs */ + uchar irqtype; + uchar bit16; /* true for 16 bit access */ + struct { + ulong start; + ulong len; + } io[16]; + int nio; + uchar vpp1; + uchar vpp2; + uchar memwait; + ulong maxwait; + ulong readywait; + ulong otherwait; +}; + +/* cis memory walking */ +struct Cisdat +{ + uchar *cisbase; + int cispos; + int cisskip; + int cislen; +}; + +/* a card slot */ +struct PCMslot +{ + Lock; + int ref; + + void *cp; /* controller for this slot */ + long memlen; /* memory length */ + uchar base; /* index register base */ + uchar slotno; /* slot number */ + + /* status */ + uchar special; /* in use for a special device */ + uchar already; /* already inited */ + uchar occupied; + uchar battery; + uchar wrprot; + uchar powered; + uchar configed; + uchar enabled; + uchar busy; + + /* cis info */ + ulong msec; /* time of last slotinfo call */ + char verstr[512]; /* version string */ + uchar cpresent; /* config registers present */ + ulong caddr; /* relative address of config registers */ + int nctab; /* number of config table entries */ + PCMconftab ctab[8]; + PCMconftab *def; /* default conftab */ + + /* for walking through cis */ + Cisdat; + + /* memory maps */ + Lock mlock; /* lock down the maps */ + int time; + PCMmap mmap[4]; /* maps, last is always for the kernel */ +}; diff --git a/port/cis.c b/port/cis.c new file mode 100644 index 0000000000000000000000000000000000000000..6c08703bf9575e5c3729e8731c012eef52cd59c1 --- /dev/null +++ b/port/cis.c @@ -0,0 +1,431 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" + + +/* + * read and crack the card information structure enough to set + * important parameters like power + */ +static void tcfig(PCMslot*, Cisdat*, int); +static void tentry(PCMslot*, Cisdat*, int); +static void tvers1(PCMslot*, Cisdat*, int); + +struct { + int n; + void (*parse)(PCMslot*, Cisdat*, int); +} cistab[] = { + 0x15, tvers1, + 0x1A, tcfig, + 0x1B, tentry, +}; + +static int +readc(Cisdat *pp, uchar *x) +{ + if(pp->cispos >= pp->cislen) + return 0; + *x = pp->cisbase[pp->cisskip*pp->cispos]; + pp->cispos++; + return 1; +} + +static int +xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr) +{ + PCMmap *m; + Cisdat cis; + int i, l; + uchar *p; + uchar type, link, n, c; + int this, subtype; + + m = pcmmap(slotno, 0, 0, attr); + if(m == 0) + return -1; + + cis.cisbase = KADDR(m->isa); + cis.cispos = 0; + cis.cisskip = attr ? 2 : 1; + cis.cislen = m->len; + + /* loop through all the tuples */ + for(i = 0; i < 1000; i++){ + this = cis.cispos; + if(readc(&cis, &type) != 1) + break; + if(type == 0xFF) + break; + if(readc(&cis, &link) != 1) + break; + if(link == 0xFF) + break; + + n = link; + if (link > 1 && subtuple != -1) { + if (readc(&cis, &c) != 1) + break; + subtype = c; + n--; + } else + subtype = -1; + + if(type == tuple && subtype == subtuple) { + p = v; + for(l=0; l= 0) + return n; + return xcistuple(slotno, tuple, subtuple, v, nv, 0); +} + +void +pcmcisread(PCMslot *pp) +{ + uchar v[256]; + int i, nv; + Cisdat cis; + + memset(pp->ctab, 0, sizeof(pp->ctab)); + pp->caddr = 0; + pp->cpresent = 0; + pp->configed = 0; + pp->nctab = 0; + pp->verstr[0] = 0; + + for(i = 0; i < nelem(cistab); i++) { + if((nv = pcmcistuple(pp->slotno, cistab[i].n, -1, v, sizeof(v))) >= 0) { + cis.cisbase = v; + cis.cispos = 0; + cis.cisskip = 1; + cis.cislen = nv; + + (*cistab[i].parse)(pp, &cis, cistab[i].n); + } + } +} + +static ulong +getlong(Cisdat *cis, int size) +{ + uchar c; + int i; + ulong x; + + x = 0; + for(i = 0; i < size; i++){ + if(readc(cis, &c) != 1) + break; + x |= c<<(i*8); + } + return x; +} + +static void +tcfig(PCMslot *pp, Cisdat *cis, int ) +{ + uchar size, rasize, rmsize; + uchar last; + + if(readc(cis, &size) != 1) + return; + rasize = (size&0x3) + 1; + rmsize = ((size>>2)&0xf) + 1; + if(readc(cis, &last) != 1) + return; + pp->caddr = getlong(cis, rasize); + pp->cpresent = getlong(cis, rmsize); +} + +static ulong vexp[8] = +{ + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 +}; +static ulong vmant[16] = +{ + 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90, +}; + +static ulong +microvolt(Cisdat *cis) +{ + uchar c; + ulong microvolts; + ulong exp; + + if(readc(cis, &c) != 1) + return 0; + exp = vexp[c&0x7]; + microvolts = vmant[(c>>3)&0xf]*exp; + while(c & 0x80){ + if(readc(cis, &c) != 1) + return 0; + switch(c){ + case 0x7d: + break; /* high impedence when sleeping */ + case 0x7e: + case 0x7f: + microvolts = 0; /* no connection */ + break; + default: + exp /= 10; + microvolts += exp*(c&0x7f); + } + } + return microvolts; +} + +static ulong +nanoamps(Cisdat *cis) +{ + uchar c; + ulong nanoamps; + + if(readc(cis, &c) != 1) + return 0; + nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf]; + while(c & 0x80){ + if(readc(cis, &c) != 1) + return 0; + if(c == 0x7d || c == 0x7e || c == 0x7f) + nanoamps = 0; + } + return nanoamps; +} + +/* + * only nominal voltage is important for config + */ +static ulong +power(Cisdat *cis) +{ + uchar feature; + ulong mv; + + mv = 0; + if(readc(cis, &feature) != 1) + return 0; + if(feature & 1) + mv = microvolt(cis); + if(feature & 2) + microvolt(cis); + if(feature & 4) + microvolt(cis); + if(feature & 8) + nanoamps(cis); + if(feature & 0x10) + nanoamps(cis); + if(feature & 0x20) + nanoamps(cis); + if(feature & 0x40) + nanoamps(cis); + return mv/1000000; +} + +static ulong mantissa[16] = +{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; + +static ulong exponent[8] = +{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, }; + +static ulong +ttiming(Cisdat *cis, int scale) +{ + uchar unscaled; + ulong nanosecs; + + if(readc(cis, &unscaled) != 1) + return 0; + nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10; + nanosecs = nanosecs * vexp[scale]; + return nanosecs; +} + +static void +timing(Cisdat *cis, PCMconftab *ct) +{ + uchar c, i; + + if(readc(cis, &c) != 1) + return; + i = c&0x3; + if(i != 3) + ct->maxwait = ttiming(cis, i); /* max wait */ + i = (c>>2)&0x7; + if(i != 7) + ct->readywait = ttiming(cis, i); /* max ready/busy wait */ + i = (c>>5)&0x7; + if(i != 7) + ct->otherwait = ttiming(cis, i); /* reserved wait */ +} + +static void +iospaces(Cisdat *cis, PCMconftab *ct) +{ + uchar c; + int i, nio; + + ct->nio = 0; + if(readc(cis, &c) != 1) + return; + + ct->bit16 = ((c>>5)&3) >= 2; + if(!(c & 0x80)){ + ct->io[0].start = 0; + ct->io[0].len = 1<<(c&0x1f); + ct->nio = 1; + return; + } + + if(readc(cis, &c) != 1) + return; + + nio = (c&0xf)+1; + for(i = 0; i < nio; i++){ + ct->io[i].start = getlong(cis, (c>>4)&0x3); + ct->io[0].len = getlong(cis, (c>>6)&0x3); + } + ct->nio = nio; +} + +static void +irq(Cisdat *cis, PCMconftab *ct) +{ + uchar c; + + if(readc(cis, &c) != 1) + return; + ct->irqtype = c & 0xe0; + if(c & 0x10) + ct->irqs = getlong(cis, 2); + else + ct->irqs = 1<<(c&0xf); + ct->irqs &= 0xDEB8; /* levels available to card */ +} + +static void +memspace(Cisdat *cis, int asize, int lsize, int host) +{ + ulong haddress, address, len; + + len = getlong(cis, lsize)*256; + address = getlong(cis, asize)*256; + USED(len, address); + if(host){ + haddress = getlong(cis, asize)*256; + USED(haddress); + } +} + +static void +tentry(PCMslot *pp, Cisdat *cis, int ) +{ + uchar c, i, feature; + PCMconftab *ct; + + if(pp->nctab >= nelem(pp->ctab)) + return; + if(readc(cis, &c) != 1) + return; + ct = &pp->ctab[pp->nctab++]; + + /* copy from last default config */ + if(pp->def) + *ct = *pp->def; + + ct->index = c & 0x3f; + + /* is this the new default? */ + if(c & 0x40) + pp->def = ct; + + /* memory wait specified? */ + if(c & 0x80){ + if(readc(cis, &i) != 1) + return; + if(i&0x80) + ct->memwait = 1; + } + + if(readc(cis, &feature) != 1) + return; + switch(feature&0x3){ + case 1: + ct->vpp1 = ct->vpp2 = power(cis); + break; + case 2: + power(cis); + ct->vpp1 = ct->vpp2 = power(cis); + break; + case 3: + power(cis); + ct->vpp1 = power(cis); + ct->vpp2 = power(cis); + break; + default: + break; + } + if(feature&0x4) + timing(cis, ct); + if(feature&0x8) + iospaces(cis, ct); + if(feature&0x10) + irq(cis, ct); + switch((feature>>5)&0x3){ + case 1: + memspace(cis, 0, 2, 0); + break; + case 2: + memspace(cis, 2, 2, 0); + break; + case 3: + if(readc(cis, &c) != 1) + return; + for(i = 0; i <= (c&0x7); i++) + memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80); + break; + } + pp->configed++; +} + +static void +tvers1(PCMslot *pp, Cisdat *cis, int ) +{ + uchar c, major, minor; + int i; + + if(readc(cis, &major) != 1) + return; + if(readc(cis, &minor) != 1) + return; + for(i = 0; i < sizeof(pp->verstr)-1; i++){ + if(readc(cis, &c) != 1) + return; + if(c == 0) + c = '\n'; + if(c == 0xff) + break; + pp->verstr[i] = c; + } + pp->verstr[i] = 0; +}