From 60b1d230de6cc75aa00e978e45f75b4c64d812d2 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 14 Nov 1994 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1994-11-14 --- pc/devastar.c | 410 ++++++++++++++++++++++++++++++++++++++++---------- pc/fns.h | 1 + pc/l.s | 9 ++ 3 files changed, 338 insertions(+), 82 deletions(-) diff --git a/pc/devastar.c b/pc/devastar.c index a650a9bfd2ba1accb3ae681dac4c4df757512349..6878f9177fb657036bd346bb752d6be20fbd48df 100644 --- a/pc/devastar.c +++ b/pc/devastar.c @@ -107,6 +107,9 @@ enum G100e= 0xA, Gx00i= 0xC, + /* GCB.cmd2 bit */ + Gintack= 0x1, + /* GCB.status2 bits */ Ghas232= (1<<0), Ghas422= (1<<1), @@ -229,36 +232,36 @@ enum /* host per controller info */ struct Astar { - QLock; + QLock; /* lock for rendez */ + Rendez r; /* waiting for command completion */ ISAConf; + Lock pagelock; /* lock for setting page */ + int page; /* page currently mapped */ int id; /* from plan9.ini */ int nchan; /* number of channels */ Astarchan *c; /* channels */ int ramsize; /* 16k or 256k */ int memsize; /* size of memory currently mapped */ - int page; /* page currently mapped */ GCB *gbc; /* global board comm area */ uchar *addr; /* base of memory area */ int running; - Rendez r; /* when waiting for board */ }; /* host per channel info */ struct Astarchan { - QLock; + QLock; /* lock for rendez */ + Rendez r; /* waiting for command completion */ Astar *a; /* controller */ CCB *ccb; /* channel control block */ int perm; int opens; - /* buffers */ Queue *iq; Queue *oq; - Rendez r; }; Astar *astar[Maxcard]; @@ -277,12 +280,16 @@ enum #define CHAN(x) ((((x)&~CHDIR)>>8)&0xff) #define QID(b,c,t) (((b)<<16)|((c)<<8)|(t)) -static int astarsetup(Astar*); +static int astarsetup(Astar*); +static void astarintr(Ureg*, void*); +static void astarkick(Astarchan*); +static void enable(Astarchan*); +static void disable(Astarchan*); /* * Only 16k maps into ISA space */ -void +static void setpage(Astar *a, ulong offset) { int i; @@ -401,6 +408,8 @@ astarreset(void) } print("serial%d avanstar addr %lux irq %d\n", i, a->addr, a->irq); nastar++; + + setvec(Int0vec + a->irq, astarintr, a); } } @@ -500,6 +509,18 @@ astaropen(Chan *c, int omode) if(!iseve()) error(Eperm); break; + case Qdata: + case Qctl: + qlock(ac); + if(waserror()){ + qunlock(a); + nexterror(); + } + if(ac->opens++ == 0) + enable(ac); + qunlock(ac); + poperror(); + break; } return c; @@ -513,34 +534,31 @@ astarclose(Chan *c) switch(TYPE(c->qid.path)){ case Qmem: - a = astar[BOARD(c->qid.path)]; - qlock(a); - if(--a->opens == 0){ - /* take board out of download mode and enable IRQ */ - outb(a->port+ISActl1, ISAien|isairqcode[a->irq]); - - /* enable ISA access to first 16k */ - outb(a->port+ISActl2, ISAmen|0); - - /* wait for program ready */ - for(i = 0; i < 21; i++){ - if(inb(a->port+ISActl1) & ISApr) - break; - tsleep(&r, return0, 0, 500); - } - if((inb(a->port+ISActl1) & ISApr) == 0) - print("astar%d program not ready\n", a->id); + break; + case Qdata: + case Qctl: + qlock(ac); + if(waserror()){ + qunlock(a); + nexterror(); } - qunlock(a); + if(--ac->opens == 0) + disable(ac); + qunlock(ac); + poperror(); break; } } +/* + * read ISA mapped memory + */ static long memread(Astar *a, uchar *to, long n, ulong offset) { - uchar *from, *e; + uchar *from, *e, *tp; int i, rem; + uchar tmp[256]; if(offset+n > a->memsize){ if(offset >= a->memsize) @@ -548,32 +566,37 @@ memread(Astar *a, uchar *to, long n, ulong offset) n = a->memsize - offset; } - if(waserror()){ - qunlock(a); - nexterror(); - } - qlock(a); - for(rem = n; rem > 0; rem -= i){ /* map in right piece of memory */ - setpage(a, offset); i = offset&Pagemask; - to = a->addr + i; + from = a->addr + i; i = Pagesize - i; if(i > rem) i = rem; - - /* byte at a time so endian doesn't matter */ + if(i > sizeof tmp) + i = sizeof tmp; + + /* + * byte at a time so endian doesn't matter, + * go via tmp to avoid pagefaults while ilock'd + */ + tp = tmp; + ilock(&a->pagelock); + setpage(a, offset); for(e = from + i; from < e;) - *to++ = *from++; + *tp++ = *from++; + iunlock(&a->pagelock); + memmove(to, tmp, i); + to += i; } - qunlock(a); - poperror(); return n; } +/* + * read ISA status + */ static long bctlread(Chan *c, void *buf, long n, ulong offset) { @@ -604,11 +627,15 @@ astarread(Chan *c, void *buf, long n, ulong offset) return 0; } +/* + * write ISA mapped memory + */ static long memwrite(Astar *a, uchar *from, long n, ulong offset) { - uchar *to, *e; + uchar *to, *e, *tp; int i, rem; + uchar tmp[256]; if(offset+n > a->memsize){ if(offset >= a->memsize) @@ -616,44 +643,34 @@ memwrite(Astar *a, uchar *from, long n, ulong offset) n = a->memsize - offset; } - if(waserror()){ - qunlock(a); - nexterror(); - } - qlock(a); - for(rem = n; rem > 0; rem -= i){ /* map in right piece of memory */ - setpage(a, offset); i = offset&Pagemask; - from = a->addr + i; + to = a->addr + i; i = Pagesize - i; if(i > rem) i = rem; + if(i > sizeof tmp) + i = sizeof tmp; - /* byte at a time so endian doesn't matter */ + /* + * byte at a time so endian doesn't matter, + * go via tmp to avoid pagefaults while ilock'd + */ + memmove(tmp, from, i); + tp = tmp; + ilock(&a->pagelock); + setpage(a, offset); for(e = from + i; from < e;) - *to++ = *from++; + *to++ = *tp++; + iunlock(&a->pagelock); + from += i; } - qunlock(a); - poperror(); return n; } -/* - * setup a channel - */ -static void -chansetup(Astar *a, Astarchan *ac, void *ccb) -{ - ac->a = a; - ac->ccb = ccb; - ac->iq = qopen(4*1024, 0, 0, 0); - ac->oq = qopen(4*1024, 0, astarkick, p); -} - /* * start control progarm */ @@ -663,6 +680,7 @@ startcp(Astar *a) int n, i, sz; uchar *x; CCB *ccb; + Astarchan *ac; if(a->running) error(Eio); @@ -682,6 +700,11 @@ startcp(Astar *a) error(Eio); } + if(waserror()){ + iunlock(&a->pagelock); + poperror(); + } + ilock(&a->pagelock); setpage(a, 0); i = LEUS(a->gcb->type); switch(i){ @@ -712,13 +735,19 @@ startcp(Astar *a) error(Eio); } } + iunlock(&a->pagelock); + poperror(); /* setup the channels */ a->running = 1; a->nchan = i; a->c = xalloc(a->nchan * sizeof(Astarchan)); for(i = 0; i < a->nchan; i++){ - chansetup(a, &a->c[i], (CCB*)x); + ac = &a->c[i]; + ac->a = a; + ac->ccb = (CCB*)x; + ac->iq = qopen(4*1024, 0, 0, 0); + ac->oq = qopen(4*1024, 0, astarkick, ac); x += sz; } } @@ -760,14 +789,106 @@ bctlwrite(Astar *a, char *msg) return n; } +/* + * Send a command to a channel + * (must be called with ac qlocked) + */ +static int +chancmddone(void *arg) +{ + CCB *ccb = arg; + int x; + + ilock(&ac->a->pagelock); + setpage(ac->a, 0); + x = ccb->cmd; + iunlock(&ac->a->pagelock); + + return x; +} +static void +chancmd(Astarchan *ac, int cmd) +{ + int i; + CCB *ccb; + + ccb = ac->ccb; + + ilock(&ac->a->pagelock); + setpage(ac->a, 0); + ccb->cmd = cmd; + iunlock(&ac->a->pagelock); + + /* wait outside of lock */ + tsleep(&ac->r, chancmddone, ccb, 1000); + + ilock(&ac->a->pagelock); + setpage(ac->a, 0); + if(ccb->cmd){ + print("astar%d cmd didn't terminate\n", ac->a->id); + error(Eio); + } + if(ccb->status){ + print("astar%d cmd status %ux\n", ac->a->id, ccb->status); + error(Eio); + } + iunlock(&ac->a->pagelock); +} + +/* + * enable a channel for IO, set standard params. + * (must be called with ac qlocked) + */ +static void +enable(Astarchan *ac) +{ + Astar qÍ*a = ac->a; + /* make sure we control RTS, DTR and break */ + ilock(&a->pagelock); + setpage(a, 0); + n = LEUS(ac->ccb->proto) | Cmctl; + ac->ccb->proto = LEUS(n); + iunlock(&a->pagelock); + + chancmd(ac, Crcvena|Cxmtena|Cflushin|Cflushout|Confall); + + astarctl(ac, "b9600"); + astarctl(ac, "l8"); + astarctl(ac, "p0"); + astarctl(ac, "d1"); + astarctl(ac, "r1"); +} + +/* + * disable a channel for IO + * (must be called with ac qlocked) + */ +static void +disable(Astarchan *ac) +{ + astarctl(ac, "d0"); + astarctl(ac, "r0"); + + ilock(&ac->a->pagelock); + setpage(ac->a, 0); + ccb->intrigger = 8; + ccb->outlow = 32; + iunlock(&ac->a->pagelock); + + chancmd(ac, Crcvdis|Cxmtdis|Cflushin|Cflushout|Cconfall); +} + /* * change channel parameters + * (must be called with ac qlocked) */ -void +static void astarctl(Astarchan *ac, char *cmd) { int i, n; int command; + CCB *ccb; + Astar *a; /* let output drain for a while */ for(i = 0; i < 16 && qlen(ac->oq); i++) @@ -776,26 +897,36 @@ astarctl(Astarchan *ac, char *cmd) if(strncmp(cmd, "break", 5) == 0) cmd = "k"; + ccb = ac->ccb; command = 0; - n = atoi(cmd+1); + i = atoi(cmd+1); + a = ac->a; + ilock(&a->pagelock); + setpage(a, 0); switch(*cmd){ case 'B': case 'b': - switch(n){ + switch(i){ case 76800: - ac->ccb->baud = LEUS(Cb76800); + ccb->baud = LEUS(Cb76800); break; case 115200: - ac->ccb->baud = LEUS(Cb115200); + ccb->baud = LEUS(Cb115200); break; default: - ac->ccb->baud = LEUS(n); + ccb->baud = LEUS(n); break; } command = Cconfall; break; case 'D': case 'd': + n = LEUS(ccb->mctl); + if(i) + n |= Cdtrctl; + else + n &= ~Cdtrctl; + ccb->mctl = LEUS(n); break; case 'f': case 'F': @@ -811,14 +942,24 @@ astarctl(Astarchan *ac, char *cmd) n -= 5; if(n < 0 || n > 3) error(Ebadarg); - n |= LEUS(ac->ccb->format) & ~Clenmask; - ac->ccb->format = LEUS(n); + n |= LEUS(ccb->format) & ~Clenmask; + ccb->format = LEUS(n); command = Cconfall; break; case 'm': case 'M': - n = LEUS(ac->ccb->format) | Cobeycts; - ac->ccb->proto = LEUS(n); + /* turn on cts */ + n = LEUS(ccb->proto); + if(i) + n |= Cobeycts; + else + n &= ~Cobeycts; + ccb->proto = LEUS(n); + + /* set fifo sizes */ + ccb->intrigger = 8; + ccb->outlow = 32; + command = Cconfall; break; case 'n': @@ -838,15 +979,33 @@ astarctl(Astarchan *ac, char *cmd) n = Cnopar; break; } - n |= LEUS(ac->ccb->format) & ~Cparmask; - ac->ccb->format = LEUS(n); + n |= LEUS(ccb->format) & ~Cparmask; + ccb->format = LEUS(n); command = Cconfall; break; case 'K': case 'k': + if(i <= 0) + i = 250; + n = LEUS(ccb->mctl) | Cbreakctl; + ccb->mctl = LEUS(n); + iunlock(&a->pagelock); + + tsleep(&ac->r, return0, 0, i); + + ilock(&a->pagelock); + setpage(a, 0); + n &= ~Cbreakctl; + ccb->mctl = LEUS(n); break; case 'R': case 'r': + n = LEUS(ccb->mctl); + if(i) + n |= Crtsctl; + else + n &= ~Crtsctl; + ccb->mctl = LEUS(n); break; case 'Q': case 'q': @@ -855,13 +1014,20 @@ astarctl(Astarchan *ac, char *cmd) break; case 'X': case 'x': - n = LEUS(ac->ccb->format) | Cobeyxon; - ac->ccb->proto = LEUS(n); + n = LEUS(ccb->proto); + if(i) + n |= Cobeyxon; + else + n &= ~Cobeyxon; + ccb->proto = LEUS(n); command = Cconfall; break; } -} + iunlock(&a->pagelock); + if(command) + chancmd(ac, command); +} long astarwrite(Chan *c, void *buf, long n, ulong offset) @@ -887,11 +1053,20 @@ astarwrite(Chan *c, void *buf, long n, ulong offset) ac = a->c + CHAN(c->qid.path); return qwrite(ac->oq, buf, n); case Qctl: + ac = a->c + CHAN(c->qid.path); if(n > sizeof cmsg) n = sizeof(cmsg) - 1; memmove(cmsg, buf, n); cmsg[n] = 0; - return astarctl(a, msg); + + if(waserror()){ + qunlock(ac); + nexterror(); + } + qlock(ac); + astarctl(ac, msg); + qunlock(ac); + poperror(); } return 0; @@ -918,3 +1093,74 @@ astarwstat(Chan *c, char *dp) error(Eperm); } +/* + * get output going + */ +static void +astarkick1(Astarchan *ac) +{ + Astar *a = ac->a; + CCB *ccb = a->ccb; + uchar tmp[256]; + int n; + + for(;;){ + setpage(a, 0); + } +} +static void +astarkick(Astarchan *ac) +{ + ilock(&ac->a->pagelock); + astarkick(ac); + iunlock(&ac->a->pagelock); +} + +/* + * handle an interrupt + */ +static void +astarintr(Ureg *ur, void *arg) +{ + Astar *a = arg; + Astarchan *ac; + ulong vec, invec, outvec, errvec, mvec, cmdvec; + int i; + + USED(ur); + lock(&a->pagelock); + setpage(a, 0); + + /* get causes */ + invec = LEUS(xchgw(&a->gcb->inserv, 0)); + outvec = LEUS(xchgw(&a->gcb->outserv, 0)); + errvec = LEUS(xchgw(&a->gcb->errserv, 0)); + mvec = LEUS(xchgw(&a->gcb->modemserv, 0)); + cmdvec = LEUS(xchgw(&a->gcb->cmdserv, 0)); + + /* reenable interrupts */ + a->cmd2 = LEUS(Gintack); + + /* service interrupts */ + ac = a->c; + for(vec = LEUS(xchgw(&a->gcb->inserv, 0)); vec; vec >>= 1){ + if(vec&1){ + } + setpage(a, 0); + ac++; + } + ac = a->c; + for(vec = LEUS(xchgw(&a->gcb->outserv, 0)); vec; vec >>= 1){ + if(vec&1) + astarkick1(ac); + setpage(a, 0); + ac++; + } + ac = a->c; + for(vec = LEUS(xchgw(&a->gcb->cmdserv, 0)); vec; vec >>= 1){ + if(vec&1) + wakeup(&ac->r); + ac++; + } + unlock(&a->pagelock); +} diff --git a/pc/fns.h b/pc/fns.h index f671b703f0cf1e39100a45664eea4d26a7e56fa8..f9dc1e3c3b7f898712e30b450a6303445c322750 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -92,6 +92,7 @@ void vgasavecrash(uchar*, int); void vgarestorecrash(uchar*, int); int x86(void); int x86cpuid(int*, int*); +int xchgw(ushort*, int); #define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) #define kmapperm(x) kmap(x) diff --git a/pc/l.s b/pc/l.s index 02a5d3068d14261faaf5ca90d1187dcd1c6a6994..572266f512cccc235a425bdaf43f1020113b4c13 100644 --- a/pc/l.s +++ b/pc/l.s @@ -250,6 +250,15 @@ TEXT tas(SB),$0 XCHGL AX,(BX) RET +/* + * xchgw(v, *p) short for the avanstar stargate driver + */ +TEXT xchgw(SB),$0 + MOVL v+4(FP),AX + MOVL p+0(FP),BX + XCHGW AX,(BX) + RET + /* * routines to load/read various system registers */