A bitsy/devpcmcia.c => bitsy/devpcmcia.c +355 -0
@@ 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,
+};
M bitsy/devuda1341.c => bitsy/devuda1341.c +151 -29
@@ 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;
};
@@ 399,11 409,18 @@ setempty(IOstate *b)
}
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;
}
@@ 599,6 635,36 @@ sendaudio(IOstate *s) {
}
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)
M bitsy/fns.h => bitsy/fns.h +10 -3
@@ 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)
M bitsy/io.h => bitsy/io.h +91 -1
@@ 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;
+};
M bitsy/main.c => bitsy/main.c +9 -1
@@ 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);
+}
M bitsy/mem.h => bitsy/mem.h +14 -2
@@ 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 */
@@ 107,6 109,16 @@
#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
*/
#define PsrMusr 0x00000010 /* mode */
M bitsy/mmu.c => bitsy/mmu.c +117 -13
@@ 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
*/
M bitsy/sa1110dma.c => bitsy/sa1110dma.c +4 -4
@@ 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<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
return 0;
}
- cachewbregion((ulong)addr, count);
+ cachewbregion(addr, count);
n = 1;
if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
(status & (1<<BIU | 1<<STRTA)) == 0) {
M bitsy/sa1110dma.h => bitsy/sa1110dma.h +1 -1
@@ 11,7 11,7 @@ void dmainit(void);
int dmaalloc(int, int, int, int, int, ulong, void (*)(void*, ulong), void*);
void dmafree(int);
-ulong dmastart(int, void *, int);
+ulong dmastart(int, ulong, int);
void dmawait(int);
int dmaidle(int);
M pc/dat.h => pc/dat.h +1 -0
@@ 9,6 9,7 @@ typedef struct Notsave Notsave;
typedef struct PCArch PCArch;
typedef struct Pcidev Pcidev;
typedef struct PCMmap PCMmap;
+typedef struct PCMslot PCMslot;
typedef struct Page Page;
typedef struct PMMU PMMU;
typedef struct Proc Proc;
M pc/devi82365.c => pc/devi82365.c +33 -537
@@ 7,7 7,7 @@
#include "io.h"
/*
- * Support for up to 4 Slot card slots. Generalizing above that is hard
+ * Support for up to 4 PCMslot card slots. Generalizing above that is hard
* since addressing is not obvious. - presotto
*
* WARNING: This has never been tried with more than one card slot.
@@ 84,10 84,6 @@ enum
Moffhi= 0x5, /* Card memory offset address high byte */
Fregactive= (1<<6), /* attribute memory */
- Mbits= 13, /* msb of Mchunk */
- Mchunk= 1<<Mbits, /* logical mapping granularity */
- Nmap= 4, /* max number of maps to use */
-
/*
* configuration registers - they start at an offset in attribute
* memory found in the CIS.
@@ 95,16 91,11 @@ enum
Rconfig= 0,
Creset= (1<<7), /* reset device */
Clevel= (1<<6), /* level sensitive interrupt line */
-
- Maxctab= 8, /* maximum configuration table entries */
};
#define MAP(x,o) (Rmap + (x)*0x8 + o)
typedef struct I82365 I82365;
-typedef struct Slot Slot;
-typedef struct Conftab Conftab;
-typedef struct Cisdat Cisdat;
/* a controller */
enum
@@ 125,109 116,39 @@ struct I82365
};
static I82365 *controller[4];
static int ncontroller;
-
-/* configuration table entry */
-struct Conftab
-{
- 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 Slot
-{
- Lock;
- int ref;
-
- I82365 *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 */
- Conftab ctab[Maxctab];
- Conftab *def; /* default conftab */
-
- /* for walking through cis */
- Cisdat;
-
- /* memory maps */
- Lock mlock; /* lock down the maps */
- int time;
- PCMmap mmap[Nmap]; /* maps, last is always for the kernel */
-};
-static Slot *slot;
-static Slot *lastslot;
+static PCMslot *slot;
+static PCMslot *lastslot;
static nslot;
-static void cisread(Slot*);
static void i82365intr(Ureg*, void*);
static void i82365reset(void);
static int pcmio(int, ISAConf*);
static long pcmread(int, int, void*, long, vlong);
static long pcmwrite(int, int, void*, long, vlong);
-static void i82365dump(Slot*);
+static void i82365dump(PCMslot*);
/*
* reading and writing card registers
*/
static uchar
-rdreg(Slot *pp, int index)
+rdreg(PCMslot *pp, int index)
{
- outb(pp->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<nv && l<n; l++)
- if(readc(&cis, p++) != 1)
- break;
- pcmunmap(slotno, m);
- return nv;
- }
- cis.cispos = this + (2+link);
- }
- pcmunmap(slotno, m);
- return -1;
-}
-
-int
-pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
-{
- int n;
-
- /* try attribute space, then memory */
- if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 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;
-}
M pc/fns.h => pc/fns.h +1 -0
@@ 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*);
M pc/io.h => pc/io.h +89 -15
@@ 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 */
+};
A port/cis.c => port/cis.c +431 -0
@@ 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<nv && l<n; l++)
+ if(readc(&cis, p++) != 1)
+ break;
+ pcmunmap(slotno, m);
+ return nv;
+ }
+ cis.cispos = this + (2+link);
+ }
+ pcmunmap(slotno, m);
+ return -1;
+}
+
+int
+pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
+{
+ int n;
+
+ /* try attribute space, then memory */
+ if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 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;
+}