@@ 97,6 97,7 @@ X86type x86type[] =
{ 4, 0, 24, "Intel486DX", },
{ 4, 1, 24, "Intel486DX", },
{ 4, 2, 24, "Intel486SX", },
+ { 4, 3, 24, "Intel486DX2", },
{ 4, 4, 24, "Intel486DX2", },
{ 4, 5, 24, "Intel486SL", },
{ 4, 8, 24, "IntelDX4", },
@@ 57,6 57,9 @@ enum
#define APAGE(x) ((x)>>Pageshift)
+#define LOCKPAGE(a, o) if((a)->needpage){ilock(&(a)->pagelock);setpage(a, o);}
+#define UNLOCKPAGE(a) if((a)->needpage)iunlock(&(a)->pagelock)
+
/* IRQ codes */
static int isairqcode[16] =
{
@@ 242,10 245,10 @@ struct Astar
Astarchan *c; /* channels */
int ramsize; /* 16k or 256k */
int memsize; /* size of memory currently mapped */
+ int needpage;
GCB *gcb; /* global board comm area */
uchar *addr; /* base of memory area */
int running;
-
};
/* host per channel info */
@@ 258,6 261,7 @@ struct Astarchan
CCB *ccb; /* channel control block */
int perm;
int opens;
+ int baud;
Queue *iq;
Queue *oq;
@@ 282,6 286,7 @@ enum
static int astarsetup(Astar*);
static void astarintr(Ureg*, void*);
static void astarkick(Astarchan*);
+static void astarkickin(Astarchan*);
static void enable(Astarchan*);
static void disable(Astarchan*);
static void astarctl(Astarchan*, char*);
@@ 526,8 531,11 @@ astaropen(Chan *c, int omode)
qunlock(ac);
nexterror();
}
- if(ac->opens++ == 0)
+ if(ac->opens++ == 0){
enable(ac);
+ qreopen(ac->iq);
+ qreopen(ac->oq);
+ }
qunlock(ac);
poperror();
break;
@@ 598,11 606,10 @@ memread(Astar *a, uchar *to, long n, ulong offset)
* go via tmp to avoid pagefaults while ilock'd
*/
tp = tmp;
- ilock(&a->pagelock);
- setpage(a, offset);
+ LOCKPAGE(a, offset);
for(e = tp + i; tp < e;)
*tp++ = *from++;
- iunlock(&a->pagelock);
+ UNLOCKPAGE(a);
memmove(to, tmp, i);
to += i;
@@ 645,7 652,7 @@ astarread(Chan *c, void *buf, long n, ulong offset)
case Qdata:
a = astar[BOARD(c->qid.path)];
ac = a->c + CHAN(c->qid.path);
- return qread(ac->oq, buf, n);
+ return qread(ac->iq, buf, n);
}
return 0;
@@ 684,11 691,10 @@ memwrite(Astar *a, uchar *from, long n, ulong offset)
*/
memmove(tmp, from, i);
tp = tmp;
- ilock(&a->pagelock);
- setpage(a, offset);
+ LOCKPAGE(a, offset);
for(e = tp + i; tp < e;)
*to++ = *tp++;
- iunlock(&a->pagelock);
+ UNLOCKPAGE(a);
from += i;
offset += i;
@@ 714,6 720,11 @@ startcp(Astar *a)
/* take board out of download mode and enable IRQ */
outb(a->port+ISActl1, ISAien|isairqcode[a->irq]|ISAnotdl);
a->memsize = a->ramsize;
+ setpage(a, 0);
+ if(a->memsize <= Pagesize)
+ a->needpage = 0;
+ else
+ a->needpage = 1;
/* wait for control program to signal life */
for(i = 0; i < 21; i++){
@@ 727,11 738,10 @@ startcp(Astar *a)
}
if(waserror()){
- iunlock(&a->pagelock);
+ UNLOCKPAGE(a);
poperror();
}
- ilock(&a->pagelock);
- setpage(a, 0);
+ LOCKPAGE(a, 0);
i = LEUS(a->gcb->type);
switch(i){
default:
@@ 761,7 771,8 @@ startcp(Astar *a)
error(Eio);
}
}
- iunlock(&a->pagelock);
+
+ UNLOCKPAGE(a);
poperror();
/* setup the channels */
@@ 773,13 784,15 @@ startcp(Astar *a)
ac->a = a;
ac->ccb = (CCB*)x;
ac->perm = 0660;
- ac->iq = qopen(4*1024, 0, 0, 0);
+ ac->iq = qopen(4*1024, 0, astarkickin, ac);
ac->oq = qopen(4*1024, 0, astarkick, ac);
x += sz;
}
- /* reenable interrupts */
+ /* enable control program interrupt generation */
+ LOCKPAGE(a, 0);
a->gcb->cmd2 = LEUS(Gintack);
+ UNLOCKPAGE(a);
}
static void
@@ 801,9 814,10 @@ bctlwrite(Astar *a, char *cmsg)
c = inb(a->port+ISActl1);
outb(a->port+ISActl1, c & ~ISAnotdl);
a->memsize = Pramsize;
+ a->needpage = 1;
/* enable ISA access to first 16k */
- outb(a->port+ISActl2, ISAmen);
+ setpage(a, 0);
} else if(strncmp(cmsg, "sharedmem", 9) == 0){
/* map shared memory */
@@ 835,10 849,9 @@ chancmddone(void *arg)
Astarchan *ac = arg;
int x;
- ilock(&ac->a->pagelock);
- setpage(ac->a, 0);
+ LOCKPAGE(ac->a, 0);
x = ac->ccb->cmd;
- iunlock(&ac->a->pagelock);
+ UNLOCKPAGE(ac->a);
return !x;
}
@@ 850,19 863,17 @@ chancmd(Astarchan *ac, int cmd)
ccb = ac->ccb;
- ilock(&ac->a->pagelock);
- setpage(ac->a, 0);
+ LOCKPAGE(ac->a, 0);
ccb->cmd = cmd;
- iunlock(&ac->a->pagelock);
+ UNLOCKPAGE(ac->a);
/* wait outside of lock */
tsleep(&ac->r, chancmddone, ac, 1000);
- ilock(&ac->a->pagelock);
- setpage(ac->a, 0);
+ LOCKPAGE(ac->a, 0);
status = ccb->status;
cmd = ccb->cmd;
- iunlock(&ac->a->pagelock);
+ UNLOCKPAGE(ac->a);
if(cmd){
print("astar%d cmd didn't terminate\n", ac->a->id);
error(Eio);
@@ 884,12 895,11 @@ enable(Astarchan *ac)
int n;
/* make sure we control RTS, DTR and break */
- ilock(&a->pagelock);
- setpage(a, 0);
+ LOCKPAGE(a, 0);
n = LEUS(ac->ccb->proto) | Cmctl;
ac->ccb->proto = LEUS(n);
ac->ccb->outlow = 64;
- iunlock(&a->pagelock);
+ UNLOCKPAGE(a);
chancmd(ac, Cconfall);
astarctl(ac, "b9600");
@@ 911,11 921,6 @@ disable(Astarchan *ac)
astarctl(ac, "d0");
astarctl(ac, "r0");
- ilock(&ac->a->pagelock);
- setpage(ac->a, 0);
- ac->ccb->intrigger = 0;
- iunlock(&ac->a->pagelock);
-
chancmd(ac, Crcvdis|Cxmtdis|Cflushin|Cflushout|Cconfall);
}
@@ 943,12 948,12 @@ astarctl(Astarchan *ac, char *cmd)
i = atoi(cmd+1);
a = ac->a;
- ilock(&a->pagelock);
- setpage(a, 0);
+ LOCKPAGE(a, 0);
switch(*cmd){
case 'B':
case 'b':
+ /* set baud rate (high rates are special - only 16 bits) */
switch(i){
case 76800:
ccb->baud = LEUS(Cb76800);
@@ 960,6 965,15 @@ astarctl(Astarchan *ac, char *cmd)
ccb->baud = LEUS(i);
break;
}
+ ac->baud = i;
+
+ /* set trigger level to about 50 per second */
+ n = i/500;
+ i = (LEUS(ccb->inlim) - LEUS(ccb->inbase))/2;
+ if(n > i)
+ n = i;
+ ccb->intrigger = LEUS(n);
+
command = Cconfall;
break;
case 'D':
@@ 993,15 1007,15 @@ astarctl(Astarchan *ac, char *cmd)
case 'M':
/* turn on cts */
n = LEUS(ccb->proto);
- if(i)
- n |= Cobeycts;
- else
- n &= ~Cobeycts;
+ if(i){
+ n |= Cobeycts|Cgenrts;
+ n &= ~Cmctl;
+ } else {
+ n &= ~(Cobeycts|Cgenrts);
+ n |= Cmctl;
+ }
ccb->proto = LEUS(n);
- /* set fifo sizes */
- ccb->intrigger = 8;
-
command = Cconfall;
break;
case 'n':
@@ 1031,12 1045,11 @@ astarctl(Astarchan *ac, char *cmd)
i = 250;
n = LEUS(ccb->mctl) | Cbreakctl;
ccb->mctl = LEUS(n);
- iunlock(&a->pagelock);
+ UNLOCKPAGE(a);
tsleep(&ac->r, return0, 0, i);
- ilock(&a->pagelock);
- setpage(a, 0);
+ LOCKPAGE(a, 0);
n &= ~Cbreakctl;
ccb->mctl = LEUS(n);
break;
@@ 1065,7 1078,7 @@ astarctl(Astarchan *ac, char *cmd)
command = Cconfall;
break;
}
- iunlock(&a->pagelock);
+ UNLOCKPAGE(a);
if(command)
chancmd(ac, command);
@@ 1160,7 1173,8 @@ astarkick1(Astarchan *ac)
uchar *rp, *wp, *bp, *ep, *p, *e;
int n;
- setpage(a, 0);
+ if(a->needpage)
+ setpage(a, 0);
ep = a->addr;
rp = ep + LEUS(ccb->outrp);
wp = ep + LEUS(ccb->outwp);
@@ 1177,14 1191,16 @@ astarkick1(Astarchan *ac)
n = qconsume(ac->oq, buf, n);
if(n <= 0)
break;
- setpage(a, bp - a->addr);
+ if(a->needpage)
+ setpage(a, bp - a->addr);
e = buf + n;
for(p = buf; p < e;){
*wp++ = *p++;
if(wp > ep)
wp = bp;
}
- setpage(a, 0);
+ if(a->needpage)
+ setpage(a, 0);
ccb->outwp = LEUS(wp - a->addr);
}
}
@@ 1208,7 1224,8 @@ astarinput(Astarchan *ac)
uchar *rp, *wp, *bp, *ep, *p, *e;
int n;
- setpage(a, 0);
+ if(a->needpage)
+ setpage(a, 0);
ep = a->addr;
rp = ep + LEUS(ccb->inrp);
wp = ep + LEUS(ccb->inwp);
@@ 1222,17 1239,33 @@ astarinput(Astarchan *ac)
n += ep - bp + 1;
if(n > sizeof(buf))
n = sizeof(buf);
- setpage(a, bp - a->addr);
+ if(a->needpage)
+ setpage(a, bp - a->addr);
e = buf + n;
for(p = buf; p < e;){
*p++ = *rp++;
if(rp > ep)
rp = bp;
}
- qproduce(ac->iq, buf, n);
+ if(qroduce(ac->iq, buf, n) < 0)
+ break; /* flow controlled */
+ if(a->needpage)
+ setpage(a, 0);
+ ccb->inrp = LEUS(rp - a->addr);
}
- setpage(a, 0);
- ccb->inrp = LEUS(rp - a->addr);
+ if(a->needpage)
+ setpage(a, 0);
+}
+
+/*
+ * get flow controlled input going again
+ */
+static void
+astarkick(Astarchan *ac)
+{
+ ilock(&ac->a->pagelock);
+ astarinput(ac);
+ iunlock(&ac->a->pagelock);
}
/*
@@ 1247,7 1280,8 @@ astarintr(Ureg *ur, void *arg)
USED(ur);
lock(&a->pagelock);
- setpage(a, 0);
+ if(a->needpage)
+ setpage(a, 0);
/* get causes */
invec = LEUS(xchgw(&a->gcb->inserv, 0));
@@ 294,6 294,7 @@ qproduce(Queue *q, void *vp, int len)
/* no waiting receivers, room in buffer? */
if(q->len >= q->limit){
+ q->state |= Qflow;
unlock(q);
return -1;
}
@@ 301,6 302,7 @@ qproduce(Queue *q, void *vp, int len)
/* save in buffer */
b = iallocb(len);
if(b == 0){
+ q->state |= Qflow;
unlock(q);
return -2;
}
@@ 375,31 377,11 @@ long
qread(Queue *q, void *vp, int len)
{
Block *b;
- int n, dowakeup, syncwait;
+ int n, dowakeup;
uchar *p = vp;
qlock(&q->rlock);
- syncwait = 0;
if(waserror()){
- /* can't let go if the buffer is in use */
- if(syncwait){
- qlock(&q->wlock);
- ilock(q);
- if(q->syncbuf == 0){
- /* we got some data before the interrupt, queue it */
- b = allocb(q->synclen);
- memmove(b->wp, vp, q->synclen);
- b->wp += q->synclen;
- b->next = q->bfirst;
- if(q->bfirst == 0)
- q->blast = b;
- q->bfirst = b;
- q->len += q->synclen;
- }
- q->syncbuf = 0;
- iunlock(q);
- qunlock(&q->wlock);
- }
qunlock(&q->rlock);
nexterror();
}
@@ 427,8 409,28 @@ qread(Queue *q, void *vp, int len)
q->synclen = len;
q->syncbuf = vp;
iunlock(q);
- syncwait = 1; USED(syncwait);
+ if(waserror()){
+ /* sync with qwrite() & qproduce() */
+ qlock(&q->wlock);
+ ilock(q);
+ if(q->syncbuf == 0){
+ /* we got some data before the interrupt */
+ b = allocb(q->synclen);
+ memmove(b->wp, vp, q->synclen);
+ b->wp += q->synclen;
+ b->next = q->bfirst;
+ if(q->bfirst == 0)
+ q->blast = b;
+ q->bfirst = b;
+ q->len += q->synclen;
+ }
+ q->syncbuf = 0;
+ iunlock(q);
+ qunlock(&q->wlock);
+ nexterror();
+ }
sleep(&q->rr, filled, q);
+ poperror();
len = q->synclen;
qunlock(&q->rlock);
poperror();
@@ 461,12 463,15 @@ qread(Queue *q, void *vp, int len)
b->rp += n;
QDEBUG checkb(b, "qread 2");
+
/* free it or put what's left on the queue */
if(b->rp >= b->wp || (q->state&Qmsg)) {
freeb(b);
} else {
ilock(q);
b->next = q->bfirst;
+ if(q->bfirst == 0)
+ q->blast = b;
q->bfirst = b;
q->len += BLEN(b);
iunlock(q);