@@ 278,8 278,12 @@ struct Astarchan
int baud; /* baud rate */
int framing; /* framing errors */
int overrun; /* overruns */
+ int hup_dsr; /* hangup when dsr goes away */
+ int hup_dcd; /* hangup when dcd goes away */
int dtr; /* non-zero means dtr on */
int rts; /* non-zero means rts on */
+ int dsr; /* non-zero means dsr on */
+ int dcd; /* non-zero means dcd on */
Queue *iq;
Queue *oq;
@@ 761,31 765,37 @@ bctlread(Astar *a, void *buf, long n, ulong offset)
static long
statread(Astarchan *ac, void *buf, long n, ulong offset)
{
- char s[128];
- int mstat, bstat;
+ char s[256];
+ int mstat, bstat, fstat;
LOCKPAGE(ac->a, 0);
mstat = LEUS(ac->ccb->mstat);
bstat = LEUS(ac->ccb->bstat);
+ fstat = LEUS(ac->ccb->format);
UNLOCKPAGE(ac->a);
- /* CCB.mstat fields */
- sprint(s, "opens %d ferr %d oerr %d baud %d", ac->opens, ac->framing,
- ac->overrun, ac->baud);
- if(mstat & Cctsstat)
- strcat(s, " cts");
- if(mstat & Cdsrstat)
- strcat(s, " dsr");
- if(mstat & Cristat)
- strcat(s, " ring");
- if(mstat & Cdcdstat)
- strcat(s, " dcd");
- if(ac->dtr)
- strcat(s, " dtr");
- if(ac->rts && (bstat & Crbrts) == 0)
- strcat(s, " rts");
- strcat(s, "\n");
-
+ snprint(s, sizeof s,
+ "b%d c%d d%d e%d l%d m%d p%c r%d s%d\n"
+ "%ld %d %d%s%s%s%s\n",
+
+ ac->baud,
+ ac->hup_dcd,
+ ac->dtr,
+ ac->hup_dsr,
+ (fstat & Clenmask),
+ 0, /* change in modem status? */
+ (fstat & Cparmask) ? ((fstat & Cevenpar) == Cevenpar ? 'e' : 'o') : 'n',
+ (bstat & Crbrts) ? 1 : 0,
+ (fstat & C2stop) ? 2 : 1,
+
+ ac - ac->a->c,
+ ac->framing,
+ ac->overrun,
+ (mstat & Cctsstat) ? " cts" : "",
+ (mstat & Cdsrstat) ? " dsr" : "",
+ (mstat & Cdcdstat) ? " dcd" : "",
+ (mstat & Cristat) ? " ring" : ""
+ );
return readstr(offset, buf, n, s);
}
@@ 1184,6 1194,7 @@ disable(Astarchan *ac)
ac->ccb->proto = LEUS(n);
UNLOCKPAGE(ac->a);
chancmd(ac, Crcvdis|Cxmtdis|Cflushin|Cflushout|Cconfall);
+ ac->dsr = ac->dcd = 0;
}
/*
@@ 1543,6 1554,24 @@ astarkickin(Astarchan *ac)
iunlock(&ac->a->pagelock);
}
+static void
+astarmodemchange(Astarchan *ac)
+{
+ Astar *a = ac->a;
+ int mstat;
+
+ if(a->needpage)
+ setpage(a, 0);
+ mstat = LEUS(ac->ccb->mstat);
+ if(ac->hup_dsr && ac->dsr == 1 && (mstat & Cdsrstat) == 0
+ || ac->hup_dcd && ac->dcd == 1 && (mstat & Cdcdstat) == 0){
+ qhangup(ac->iq, nil);
+ qhangup(ac->oq, nil);
+ }
+ ac->dsr = mstat & Cdsrstat;
+ ac->dcd = mstat & Cdcdstat;
+}
+
/*
* handle an interrupt
*/
@@ 1571,7 1600,6 @@ astarintr(Ureg *ur, void *arg)
errvec = LEUS(xchgw(&a->gcb->errserv, 0));
mvec = LEUS(xchgw(&a->gcb->modemserv, 0));
cmdvec = LEUS(xchgw(&a->gcb->cmdserv, 0));
- USED(mvec);
/* reenable interrupts */
if(a->pci){
@@ 1606,6 1634,12 @@ astarintr(Ureg *ur, void *arg)
ac++;
}
ac = a->c;
+ for(vec = mvec; vec; vec >>= 1){
+ if(vec&1)
+ astarmodemchange(ac);
+ ac++;
+ }
+ ac = a->c;
for(vec = errvec; vec; vec >>= 1){
c = LEUS(ac->ccb->errstat);
if(c & Cframing)
@@ 113,8 113,10 @@ struct Uart
int modem; /* hardware flow control on */
int xonoff; /* software flow control on */
int blocked;
- int cts;
+ int cts, dsr, dcd; /* keep track of modem status */
int ctsbackoff;
+ int hup_dsr, hup_dcd; /* send hangup upstream? */
+ int dohup;
Rendez r;
};
@@ 157,6 159,21 @@ ns16552setbaud(Uart *p, int rate)
p->baud = rate;
}
+/*
+ * decide if we should hangup when dsr or dcd drops.
+ */
+static void
+ns16552dsrhup(Uart *p, int n)
+{
+ p->hup_dsr = n;
+}
+
+static void
+ns16552dcdhup(Uart *p, int n)
+{
+ p->hup_dcd = n;
+}
+
static void
ns16552parity(Uart *p, char type)
{
@@ 311,6 328,9 @@ ns16552enable(Uart *p)
uartpower(p->dev, 1);
+ p->hup_dsr = p->hup_dcd = 0;
+ p->cts = p->dsr = p->dcd = 0;
+
/*
* turn on interrupts
*/
@@ 594,6 614,24 @@ ns16552intr(int dev)
p->ctsbackoff = 2; /* clock gets output going again */
iunlock(&p->tlock);
}
+ if (ch & Dsrc) {
+ l = ch & Dsr;
+ if(p->hup_dsr && p->dsr && !l){
+ ilock(&p->rlock);
+ p->dohup = 1;
+ iunlock(&p->rlock);
+ }
+ p->dsr = l;
+ }
+ if (ch & Dcdc) {
+ l = ch & Dcd;
+ if(p->hup_dcd && p->dcd && !l){
+ ilock(&p->rlock);
+ p->dohup = 1;
+ iunlock(&p->rlock);
+ }
+ p->dcd = l;
+ }
break;
default:
@@ 641,6 679,15 @@ uartclock(void)
}
iunlock(&p->rlock);
}
+ if(p->dohup){
+ ilock(&p->rlock);
+ if(p->dohup){
+ qhangup(p->iq, 0);
+ qhangup(p->oq, 0);
+ }
+ p->dohup = 0;
+ iunlock(&p->rlock);
+ }
/* this adds hysteresis to hardware flow control */
if(p->ctsbackoff){
@@ 767,6 814,7 @@ ns16552close(Chan *c)
qclose(p->iq);
qclose(p->oq);
p->ip = p->istage;
+ p->dcd = p->dsr = p->dohup = 0;
}
qunlock(p);
break;
@@ 776,34 824,37 @@ ns16552close(Chan *c)
static long
uartstatus(Chan*, Uart *p, void *buf, long n, long offset)
{
- uchar mstat;
- uchar tstat;
+ uchar mstat, fstat, istat, tstat;
char str[256];
str[0] = 0;
tstat = p->sticky[Mctl];
mstat = uartrdreg(p, Mstat);
- sprint(str, "opens %d ferr %d oerr %d baud %d", p->opens,
- p->frame, p->overrun, p->baud);
- if(mstat & Cts)
- strcat(str, " cts");
- if(mstat & Dsr)
- strcat(str, " dsr");
- if(mstat & Ring)
- strcat(str, " ring");
- if(mstat & Dcd)
- strcat(str, " dcd");
- if(tstat & Dtr)
- strcat(str, " dtr");
- if(tstat & Rts)
- strcat(str, " rts");
-{
-int i, j;
-
-i = strlen(str);
-for(j = 0; j < 8; j++) i+=sprint(str+i, " %ux", uartrdreg(p, j));
-}
- strcat(str, "\n");
+ istat = p->sticky[Iena];
+ fstat = p->sticky[Format];
+ snprint(str, sizeof str,
+ "b%d c%d d%d e%d l%d m%d p%c r%d s%d\n"
+ "%d %d %d%s%s%s%s%s\n",
+
+ p->baud,
+ p->hup_dcd,
+ (tstat & Dtr) != 0,
+ p->hup_dsr,
+ (fstat & Bits8) + 5,
+ (istat & Imstat) != 0,
+ (fstat & Pena) ? ((fstat & Peven) ? 'e' : 'o') : 'n',
+ (tstat & Rts) != 0,
+ (fstat & Stop2) ? 2 : 1,
+
+ p->dev,
+ p->frame,
+ p->overrun,
+ p->fifoon ? " fifo" : "",
+ (mstat & Cts) ? " cts" : "",
+ (mstat & Dsr) ? " dsr" : "",
+ (mstat & Dcd) ? " dcd" : "",
+ (mstat & Ring) ? " ring" : ""
+ );
return readstr(offset, buf, n, str);
}
@@ 852,10 903,18 @@ ns16552ctl(Uart *p, char *cmd)
case 'b':
ns16552setbaud(p, n);
break;
+ case 'C':
+ case 'c':
+ ns16552dcdhup(p, n);
+ break;
case 'D':
case 'd':
ns16552dtr(p, n);
break;
+ case 'E':
+ case 'e':
+ ns16552dsrhup(p, n);
+ break;
case 'f':
case 'F':
qflush(p->oq);