M carrera/clock.c => carrera/clock.c +1 -0
@@ 91,6 91,7 @@ clock(Ureg *ur)
}
checkalarms();
+ uartclock();
mouseclock();
if(up == 0 || up->state != Running)
M carrera/fns.h => carrera/fns.h +4 -3
@@ 96,6 96,7 @@ void vector0(void);
void vector100(void);
void vector180(void);
void vmereset(void);
+void uartclock(void);
void uvst(void*, void*);
void uvld(void*, void*);
void wbflush(void);
@@ 103,9 104,9 @@ void wrcompare(ulong);
void Xdelay(int);
void serialinit(void);
-void NS16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
-void NS16552setup(ulong, ulong);
-void NS16552intr(int);
+void ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
+void ns16552setup(ulong, ulong);
+void ns16552intr(int);
void etherintr(void);
void iomapinit(void);
void enetaddr(uchar*);
M carrera/kbd.c => carrera/kbd.c +1 -0
@@ 354,6 354,7 @@ kbdinit(void)
int i;
kbdq = qopen(4*1024, 0, 0, 0);
+ qnoblock(kbdq, 1);
/*
* empty the buffer
M carrera/main.c => carrera/main.c +1 -1
@@ 163,7 163,7 @@ machinit(void)
void
serialinit(void)
{
- NS16552setup(Uart1, UartFREQ);
+ ns16552install();
kbdinit();
}
A carrera/ns16552.h => carrera/ns16552.h +41 -0
@@ 0,0 1,41 @@
+#define outb(p, ch) *(uchar*)((p)^7) = ch
+#define uartwrreg(u,r,v) outb((u)->port + (r), (u)->sticky[r] | (v))
+#define uartrdreg(u,r) *(uchar*)(((u)->port + (r))^7)
+
+#define uartpower(x, y)
+
+void
+ns16552install(void)
+{
+ static int already;
+
+ if(already)
+ return;
+ already = 1;
+
+ ns16552setup(Uart1, UartFREQ);
+}
+
+#define RD(r) (*(uchar*)((Uart1+r)^7))
+static void
+ns16552iputc(char c)
+{
+ while((RD(5) & (1<<5)) == 0)
+ ;
+ *(uchar*)(Uart1^7) = c;
+ while((RD(5) & (1<<5)) == 0)
+ ;
+}
+
+int
+iprint(char *fmt, ...)
+{
+ int n, i;
+ char buf[512];
+
+ n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
+ for(i = 0; i < n; i++)
+ ns16552iputc(buf[i]);
+
+ return n;
+}
M carrera/trap.c => carrera/trap.c +2 -2
@@ 298,10 298,10 @@ intr(Ureg *ur)
default:
panic("unknown devint=#%lux", devint);
case 0x28: /* Serial 1 */
- NS16552intr(0);
+ ns16552intr(0);
break;
case 0x24: /* Serial 2 */
- NS16552intr(1);
+ ns16552intr(1);
break;
case 0x10:
fiberint(0);
M pc/fault386.c => pc/fault386.c +1 -3
@@ 24,7 24,6 @@ fault386(Ureg *ur, void *arg)
read = !(ur->ecode & 2);
user = (ur->cs&0xffff) == UESEL;
spllo();
-/*print("F%d:A#%lux:U%d:R%d|", up->pid, addr, user, read);/**/
n = fault(addr, read);
if(n < 0){
if(user){
@@ 33,9 32,8 @@ fault386(Ureg *ur, void *arg)
postnote(up, 1, buf, NDebug);
return;
}
-print("fault: 0x%lux", addr);
dumpregs(ur);
- panic("fault: 0x%lux", addr);
+ panic("fault: 0x%lux\n", addr);
}
up->insyscall = insyscall;
}
M pc/fns.h => pc/fns.h +1 -3
@@ 97,9 97,7 @@ int x86(void);
#define KADDR(a) ((void*)((ulong)(a)|KZERO))
#define PADDR(a) ((ulong)(a)&~KZERO)
-void NS16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
-int NS16552m3mouse(Queue*, int);
-int NS16552mouse(Queue*, int);
+void ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int));
void hnputl(void*, ulong v);
void hnputs(void*, ushort v);
M pc/kbd.c => pc/kbd.c +3 -2
@@ 254,9 254,9 @@ serialmouse(int port, char *type, int setspeed)
if(setspeed)
setspeed = 1200;
if(type && *type == 'M')
- NS16552special(port, setspeed, &mouseq, 0, m3mouseputc);
+ ns16552special(port, setspeed, &mouseq, 0, m3mouseputc);
else
- NS16552special(port, setspeed, &mouseq, 0, mouseputc);
+ ns16552special(port, setspeed, &mouseq, 0, mouseputc);
mousetype = Mouseserial;
}
@@ 597,6 597,7 @@ kbdinit(void)
int c;
kbdq = qopen(4*1024, 0, 0, 0);
+ qnoblock(kbdq, 1);
setvec(Kbdvec, kbdintr, 0);
A pc/ns16552.h => pc/ns16552.h +147 -0
@@ 0,0 1,147 @@
+/*
+ * PC specific code for the ns16552. It includes support for the 2 built
+ * in uarts plus up to 5 MP-008 8 uart ISA cards.
+ */
+enum
+{
+ Maxcard= 5, /* max serial cards */
+ UartFREQ= 1843200,
+
+ Serial= 0,
+ Modem= 1,
+};
+
+#define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v))
+#define uartrdreg(u,r) inb((u)->port + r)
+
+void ns16552setup(ulong, ulong);
+
+/*
+ * definition of an optional serial card
+ */
+typedef struct Scard
+{
+ ISAConf; /* card configuration */
+ int first; /* number of first port */
+} Scard;
+static Scard *scard[Maxcard]; /* configs for the serial card */
+
+/* power management currently only makes sense on the AT&T safari */
+static void
+uartpower(int dev, int onoff)
+{
+ switch(dev){
+ case Modem:
+ if(modem(onoff) < 0)
+ print("can't turn %s modem speaker\n", onoff?"on":"off");
+ break;
+ case Serial:
+ if(serial(onoff) < 0)
+ print("can't turn %s serial port power\n", onoff?"on":"off");
+ break;
+ }
+}
+
+/*
+ * handle an interrupt to a single uart
+ */
+static void
+ns16552intrx(Ureg *ur, void *arg)
+{
+ USED(ur);
+
+ ns16552intr((ulong)arg);
+}
+
+/*
+ * interrupts from the multiport card, MP-008. A polling port
+ * tells which of 8 devices interrupted.
+ */
+static void
+mp008intr(Ureg *ur, void *arg)
+{
+ int i, loops;
+ uchar n;
+ Scard *mp;
+
+ USED(ur);
+ mp = arg;
+ for(loops = 0;; loops++){
+ if(loops > 1024)
+ panic("mp008intr");
+ n = ~inb(mp->mem);
+ if(n == 0)
+ return;
+ for(i = 0; n; i++){
+ if(n & 1)
+ ns16552intrx(ur, uart[mp->first+i]);
+ n >>= 1;
+ }
+ }
+}
+
+/*
+ * install the uarts (called by reset)
+ */
+static void
+ns16552install(void)
+{
+ int i, j, port;
+ Scard *sc;
+
+ /* first two ports are always there and always the normal frequency */
+ ns16552setup(0x3F8, UartFREQ);
+ setvec(Uart0vec, ns16552intrx, (void*)0);
+ ns16552setup(0x2F8, UartFREQ);
+ setvec(Uart1vec, ns16552intrx, (void*)1);
+
+ /* the rest come out of plan9.ini */
+ for(i = 0; i < Maxcard; i++){
+ sc = scard[i] = xalloc(sizeof(Scard));
+ if(isaconfig("serial", i, sc) == 0){
+ xfree(sc);
+ break;
+ }
+
+ if(strcmp(sc->type, "MP008") == 0 || strcmp(sc->type, "mp008") == 0){
+ /*
+ * port gives base port address for uarts
+ * irq is interrupt
+ * mem is the polling port
+ * size is the number of serial ports on the same polling port
+ * freq is the baud rate generator frequency
+ */
+ if(sc->size == 0)
+ sc->size = 8;
+ if(sc->freq == 0)
+ sc->freq = UartFREQ;
+ sc->first = nuart;
+ setvec(Int0vec+sc->irq, mp008intr, sc);
+ port = sc->port;
+ for(j=0; j < sc->size; j++){
+ ns16552setup(port, sc->freq);
+ port += 8;
+ }
+ } else {
+ /*
+ * port gives base port address for the uart
+ * irq is interrupt
+ * freq is the baud rate generator frequency
+ */
+ ns16552setup(sc->port, sc->freq);
+ setvec(Int0vec+sc->irq, ns16552intrx, (void*)(nuart-1));
+ }
+ }
+}
+
+int
+iprint(char *fmt, ...)
+{
+ char buf[PRINTSIZE];
+ int n;
+
+ n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
+ screenputs(buf, n);
+
+ return n;
+}
M pc/trap.c => pc/trap.c +1 -0
@@ 346,6 346,7 @@ dumpregs(Ureg *ur)
x = (ulong*)(ur+1);
dumpregs2(ur);
+ print(" CR0 %8.8lux CR2 %8.8lux\n", getcr0(), getcr2());
print(" magic %lux %lux %lux\n", x[0], x[1], x[2]);
print(" ur %lux up %lux\n", ur, up);
}
M port/devcons.c => port/devcons.c +7 -5
@@ 34,7 34,9 @@ void
printinit(void)
{
klogq = qopen(32*1024, 0, 0, 0);
+ qnoblock(klogq, 1);
lineq = qopen(2*1024, 0, 0, 0);
+ qnoblock(lineq, 1);
}
/*
@@ 73,7 75,7 @@ putstrn0(char *str, int n, int usewrite)
buf[m] = '\r';
buf[m+1] = '\n';
if(usewrite)
- qwrite(printq, buf, m+2, 0);
+ qwrite(printq, buf, m+2);
else {
x = splhi();
qproduce(printq, buf, m+2);
@@ 83,7 85,7 @@ putstrn0(char *str, int n, int usewrite)
n -= m + 1;
} else {
if(usewrite)
- qwrite(printq, str, n, 0);
+ qwrite(printq, str, n);
else {
x = splhi();
qproduce(printq, str, n);
@@ 138,7 140,7 @@ kprint(char *fmt, ...)
int n;
n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
- qwrite(klogq, buf, n, 1);
+ qwrite(klogq, buf, n);
return n;
}
@@ 540,7 542,7 @@ consread(Chan *c, void *buf, long n, ulong offset)
if(kbd.x == sizeof(kbd.line) || eol){
if(ch == 0x04)
kbd.x--;
- qwrite(lineq, kbd.line, kbd.x, 1);
+ qwrite(lineq, kbd.line, kbd.x);
kbd.x = 0;
}
}
@@ 743,7 745,7 @@ conswrite(Chan *c, void *va, long n, ulong offset)
if(strncmp(a, "rawon", 5) == 0){
qlock(&kbd);
if(kbd.x){
- qwrite(kbdq, kbd.line, kbd.x, 1);
+ qwrite(kbdq, kbd.line, kbd.x);
kbd.x = 0;
}
kbd.raw = 1;
A port/devns16552.c => port/devns16552.c +895 -0
@@ 0,0 1,895 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#include "devtab.h"
+#include "../port/netif.h"
+
+/*
+ * Driver for the ns16552.
+ */
+enum
+{
+ /*
+ * register numbers
+ */
+ Data= 0, /* xmit/rcv buffer */
+ Iena= 1, /* interrupt enable */
+ Ircv= (1<<0), /* for char rcv'd */
+ Ixmt= (1<<1), /* for xmit buffer empty */
+ Irstat=(1<<2), /* for change in rcv'er status */
+ Imstat=(1<<3), /* for change in modem status */
+ Istat= 2, /* interrupt flag (read) */
+ Fenabd=(3<<6), /* on if fifo's enabled */
+ Fifoctl=2, /* fifo control (write) */
+ Fena= (1<<0), /* enable xmit/rcv fifos */
+ Ftrig= (1<<6), /* trigger after 4 input characters */
+ Fclear=(3<<1), /* clear xmit & rcv fifos */
+ Format= 3, /* byte format */
+ Bits8= (3<<0), /* 8 bits/byte */
+ Stop2= (1<<2), /* 2 stop bits */
+ Pena= (1<<3), /* generate parity */
+ Peven= (1<<4), /* even parity */
+ Pforce=(1<<5), /* force parity */
+ Break= (1<<6), /* generate a break */
+ Dra= (1<<7), /* address the divisor */
+ Mctl= 4, /* modem control */
+ Dtr= (1<<0), /* data terminal ready */
+ Rts= (1<<1), /* request to send */
+ Ri= (1<<2), /* ring */
+ Inton= (1<<3), /* turn on interrupts */
+ Loop= (1<<4), /* loop back */
+ Lstat= 5, /* line status */
+ Inready=(1<<0), /* receive buffer full */
+ Oerror=(1<<1), /* receiver overrun */
+ Perror=(1<<2), /* receiver parity error */
+ Ferror=(1<<3), /* rcv framing error */
+ Outready=(1<<5), /* output buffer full */
+ Mstat= 6, /* modem status */
+ Ctsc= (1<<0), /* clear to send changed */
+ Dsrc= (1<<1), /* data set ready changed */
+ Rire= (1<<2), /* rising edge of ring indicator */
+ Dcdc= (1<<3), /* data carrier detect changed */
+ Cts= (1<<4), /* complement of clear to send line */
+ Dsr= (1<<5), /* complement of data set ready line */
+ Ring= (1<<6), /* complement of ring indicator line */
+ Dcd= (1<<7), /* complement of data carrier detect line */
+ Scratch=7, /* scratchpad */
+ Dlsb= 0, /* divisor lsb */
+ Dmsb= 1, /* divisor msb */
+
+ CTLS= 023,
+ CTLQ= 021,
+
+ Stagesize= 1024,
+ Nuart= 32, /* max per machine */
+};
+
+typedef struct Uart Uart;
+struct Uart
+{
+ QLock;
+
+ Uart *elist; /* next enabled interface */
+
+ uchar sticky[8]; /* sticky write register values */
+ ulong port;
+ Lock plock; /* for printing variable */
+ int printing; /* true if printing */
+ ulong freq; /* clock frequency */
+ int opens;
+ uchar mask; /* bits/char */
+ uchar istat; /* last istat read */
+ uchar fifoon; /* fifo's enabled */
+ uchar nofifo; /* earlier chip version with nofifo */
+ int enabled;
+ int dev;
+
+ int frame;
+ int overrun;
+
+ /* flow control */
+ int xonoff; /* software flow control on */
+ int blocked;
+ int modem; /* hardware flow control on */
+ int cts;
+ int ctsbackoff;
+ Rendez r;
+
+ /* buffers */
+ int (*putc)(Queue*, int);
+ Queue *iq;
+ Queue *oq;
+
+ /* staging areas to avoid some of the per character costs */
+ uchar istage[Stagesize];
+ uchar *ip;
+ uchar *ie;
+
+ uchar ostage[Stagesize];
+ uchar *op;
+ uchar *oe;
+};
+
+static Uart *uart[Nuart];
+static int nuart;
+
+static int haveinput;
+struct Uartalloc {
+ Lock;
+ Uart *elist; /* list of enabled interfaces */
+} uartalloc;
+
+void ns16552intr(int);
+
+/*
+ * pick up architecture specific routines and definitions
+ */
+#include "ns16552.h"
+
+/*
+ * set the baud rate by calculating and setting the baudrate
+ * generator constant. This will work with fairly non-standard
+ * baud rates.
+ */
+static void
+ns16552setbaud(Uart *p, int rate)
+{
+ ulong brconst;
+
+ brconst = (p->freq+8*rate-1)/(16*rate);
+
+ uartwrreg(p, Format, Dra);
+ outb(p->port + Dmsb, (brconst>>8) & 0xff);
+ outb(p->port + Dlsb, brconst & 0xff);
+ uartwrreg(p, Format, 0);
+}
+
+static void
+ns16552parity(Uart *p, char type)
+{
+ switch(type){
+ case 'e':
+ p->sticky[Format] |= Pena|Peven;
+ break;
+ case 'o':
+ p->sticky[Format] &= ~Peven;
+ p->sticky[Format] |= Pena;
+ break;
+ default:
+ p->sticky[Format] &= ~(Pena|Peven);
+ break;
+ }
+ uartwrreg(p, Format, 0);
+}
+
+/*
+ * set bits/character, default 8
+ */
+void
+ns16552bits(Uart *p, int bits)
+{
+ if(bits < 5 || bits > 8)
+ error(Ebadarg);
+
+ p->sticky[Format] &= ~3;
+ p->sticky[Format] |= bits-5;
+
+ uartwrreg(p, Format, 0);
+}
+
+
+/*
+ * toggle DTR
+ */
+void
+ns16552dtr(Uart *p, int n)
+{
+ if(n)
+ p->sticky[Mctl] |= Dtr;
+ else
+ p->sticky[Mctl] &= ~Dtr;
+
+ uartwrreg(p, Mctl, 0);
+}
+
+/*
+ * toggle RTS
+ */
+void
+ns16552rts(Uart *p, int n)
+{
+ if(n)
+ p->sticky[Mctl] |= Rts;
+ else
+ p->sticky[Mctl] &= ~Rts;
+
+ uartwrreg(p, Mctl, 0);
+}
+
+/*
+ * send break
+ */
+void
+ns16552break(Uart *p, int ms)
+{
+ if(ms == 0)
+ ms = 200;
+
+ uartwrreg(p, Format, Break);
+ tsleep(&up->sleep, return0, 0, ms);
+ uartwrreg(p, Format, 0);
+}
+
+void
+ns16552fifoon(Uart *p)
+{
+ ulong i, x, c;
+
+ if(p->nofifo)
+ return;
+
+ x = splhi();
+
+ /* empty buffer */
+ c = 0; /* c is to to avoid an unused warning */
+ for(i = 0; i < 16; i++)
+ c = uartrdreg(p, Data);
+ USED(c);
+ ns16552intr(p->dev);
+
+ /* turn on fifo */
+ p->fifoon = 1;
+ uartwrreg(p, Fifoctl, Fena|Ftrig);
+
+ ns16552intr(p->dev);
+ USED(c);
+ if((p->istat & Fenabd) == 0){
+ /* didn't work, must be an earlier chip type */
+ p->nofifo = 1;
+ }
+
+ splx(x);
+}
+
+/*
+ * modem flow control on/off (rts/cts)
+ */
+void
+ns16552mflow(Uart *p, int n)
+{
+ if(n){
+ p->sticky[Iena] |= Imstat;
+ uartwrreg(p, Iena, 0);
+ p->modem = 1;
+ p->cts = uartrdreg(p, Mstat) & Cts;
+
+ /* turn on fifo's */
+ ns16552fifoon(p);
+ } else {
+ p->sticky[Iena] &= ~Imstat;
+ uartwrreg(p, Iena, 0);
+ p->modem = 0;
+ p->cts = 1;
+
+ /* turn off fifo's */
+ p->fifoon = 0;
+ uartwrreg(p, Fifoctl, 0);
+ }
+}
+
+/*
+ * turn on a port's interrupts. set DTR and RTS
+ */
+void
+ns16552enable(Uart *p)
+{
+ Uart **l;
+
+ if(p->enabled)
+ return;
+
+ uartpower(p->dev, 1);
+
+ /*
+ * turn on interrupts
+ */
+ p->sticky[Iena] = Ircv | Ixmt | Irstat;
+ uartwrreg(p, Iena, 0);
+
+ /*
+ * turn on DTR and RTS
+ */
+ ns16552dtr(p, 1);
+ ns16552rts(p, 1);
+
+ /*
+ * assume we can send
+ */
+ p->cts = 1;
+ p->blocked = 0;
+
+ lock(&uartalloc);
+ for(l = &uartalloc.elist; *l; l = &(*l)->elist){
+ if(*l == p)
+ break;
+ }
+ if(*l == 0){
+ p->elist = uartalloc.elist;
+ uartalloc.elist = p;
+ }
+ p->enabled = 1;
+ unlock(&uartalloc);
+}
+
+/*
+ * turn off a port's interrupts. reset DTR and RTS
+ */
+void
+ns16552disable(Uart *p)
+{
+ Uart **l;
+
+ /*
+ * turn off interrpts
+ */
+ p->sticky[Iena] = 0;
+ uartwrreg(p, Iena, 0);
+
+ /*
+ * revert to default settings
+ */
+ p->sticky[Format] = Bits8;
+ uartwrreg(p, Format, 0);
+
+ /*
+ * turn off DTR, RTS, hardware flow control & fifo's
+ */
+ ns16552dtr(p, 0);
+ ns16552rts(p, 0);
+ ns16552mflow(p, 0);
+ p->xonoff = p->blocked = 0;
+
+ uartpower(p->dev, 0);
+
+ lock(&uartalloc);
+ for(l = &uartalloc.elist; *l; l = &(*l)->elist){
+ if(*l == p){
+ *l = p->elist;
+ break;
+ }
+ }
+ p->enabled = 0;
+ unlock(&uartalloc);
+}
+
+/*
+ * put some bytes into the local queue to avoid calling
+ * qconsume for every character
+ */
+static int
+stageoutput(Uart *p)
+{
+ int n;
+
+ n = qconsume(p->oq, p->ostage, Stagesize);
+ if(n <= 0)
+ return 0;
+ p->op = p->ostage;
+ p->oe = p->ostage + n;
+ return n;
+}
+
+/*
+ * (re)start output
+ */
+static void
+ns16552kick(Uart *p)
+{
+ int x, n;
+
+ x = splhi();
+ lock(&p->plock);
+ if(p->printing == 0 || (uartrdreg(p, Lstat) & Outready))
+ if(p->cts && p->blocked == 0){
+ n = 0;
+ while((uartrdreg(p, Lstat) & Outready) == 0){
+ if(++n > 10000){
+ print("stuck serial line\n");
+ break;
+ }
+ }
+ do{
+ if(p->op >= p->oe && stageoutput(p) == 0)
+ break;
+ outb(p->port + Data, *(p->op++));
+ }while(uartrdreg(p, Lstat) & Outready);
+ }
+ unlock(&p->plock);
+ splx(x);
+}
+
+/*
+ * default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
+ * transmit and receive enabled, interrupts disabled.
+ */
+static void
+ns16552setup0(Uart *p)
+{
+ memset(p->sticky, 0, sizeof(p->sticky));
+ /*
+ * set rate to 9600 baud.
+ * 8 bits/character.
+ * 1 stop bit.
+ * interrpts enabled.
+ */
+ p->sticky[Format] = Bits8;
+ uartwrreg(p, Format, 0);
+ p->sticky[Mctl] |= Inton;
+ uartwrreg(p, Mctl, 0x0);
+
+ ns16552setbaud(p, 9600);
+
+ p->iq = qopen(4*1024, 0, 0, 0);
+ p->oq = qopen(4*1024, 0, ns16552kick, p);
+
+ p->ip = p->istage;
+ p->ie = &p->istage[Stagesize];
+ p->op = p->ostage;
+ p->oe = p->ostage;
+}
+
+/*
+ * called by main() to create a new duart
+ */
+void
+ns16552setup(ulong port, ulong freq)
+{
+ Uart *p;
+
+ if(nuart >= Nuart)
+ return;
+
+ p = xalloc(sizeof(Uart));
+ uart[nuart] = p;
+ p->dev = nuart;
+ nuart++;
+ p->port = port;
+ p->freq = freq;
+ ns16552setup0(p);
+}
+
+/*
+ * called by main() to configure a duart port as a console or a mouse
+ */
+void
+ns16552special(int port, int baud, Queue **in, Queue **out, int (*putc)(Queue*, int))
+{
+ Uart *p = uart[port];
+
+ ns16552enable(p);
+ if(baud)
+ ns16552setbaud(p, baud);
+ p->putc = putc;
+ if(in)
+ *in = p->iq;
+ if(out)
+ *out = p->oq;
+ p->opens++;
+}
+
+/*
+ * handle an interrupt to a single uart
+ */
+void
+ns16552intr(int dev)
+{
+ uchar ch;
+ int s, l, loops;
+ Uart *p = uart[dev];
+
+ for(loops = 0;; loops++){
+ if(loops > 100000)
+ panic("ns16552intr");
+ p->istat = s = uartrdreg(p, Istat);
+ switch(s&0x3f){
+ case 6: /* receiver line status */
+ l = uartrdreg(p, Lstat);
+ if(l & Ferror)
+ p->frame++;
+ if(l & Oerror)
+ p->overrun++;
+ break;
+
+ case 4: /* received data available */
+ case 12:
+ ch = uartrdreg(p, Data) & 0xff;
+ if(p->xonoff){
+ if(ch == CTLS){
+ p->blocked = 1;
+ }else if (ch == CTLQ){
+ p->blocked = 0;
+ /* clock gets output going again */
+ }
+ }
+ if(p->putc)
+ (*p->putc)(p->iq, ch);
+ else {
+ if(p->ip < p->ie)
+ *p->ip++ = ch;
+ haveinput = 1;
+ }
+ break;
+
+ case 2: /* transmitter not full */
+ lock(&p->plock);
+ l = uartrdreg(p, Lstat) & Outready;
+ if(l && p->cts && p->blocked == 0)
+ if(p->op < p->oe || stageoutput(p)){
+ do{
+ outb(p->port + Data, *(p->op++));
+ if(p->op >= p->oe && stageoutput(p) == 0)
+ break;
+ l = uartrdreg(p, Lstat) & Outready;
+ }while(l);
+ }
+ if(l)
+ p->printing = 0;
+ unlock(&p->plock);
+ break;
+
+ case 0: /* modem status */
+ ch = uartrdreg(p, Mstat);
+ if(ch & Ctsc){
+ p->cts = ch & Cts; /* clock gets output going again */
+ p->ctsbackoff += 1;
+ }
+ break;
+
+ default:
+ if(s&1)
+ return;
+ print("weird modem interrupt #%2.2ux\n", s);
+ break;
+ }
+ }
+}
+
+/*
+ * we save up input characters till clock time
+ *
+ * There's also a bit of code to get a stalled print going.
+ * It shouldn't happen, but it does. Obviously I don't
+ * understand interrupts. -- presotto
+ */
+void
+uartclock(void)
+{
+ int n;
+ Uart *p;
+
+ for(p = uartalloc.elist; p; p = p->elist){
+ ns16552intr(p->dev);
+ if(haveinput){
+ n = p->ip - p->istage;
+ if(n > 0 && p->iq){
+ if(n > Stagesize)
+ panic("uartclock");
+ if(qproduce(p->iq, p->istage, n) != n)
+ ;
+ p->ip = p->istage;
+ }
+ }
+ if(p->ctsbackoff-- < 0){
+ p->ctsbackoff = 0;
+ ns16552kick(p);
+ }
+ }
+ haveinput = 0;
+}
+
+Dirtab *ns16552dir;
+
+/*
+ * all uarts must be ns16552setup() by this point or inside of ns16552install()
+ */
+void
+ns16552reset(void)
+{
+ int i;
+ Dirtab *dp;
+
+ ns16552install(); /* architecture specific */
+
+ ns16552dir = xalloc(3 * nuart * sizeof(Dirtab));
+ dp = ns16552dir;
+ for(i = 0; i < nuart; i++){
+ /* 3 directory entries per port */
+ sprint(dp->name, "eia%d", i);
+ dp->qid.path = NETQID(i, Ndataqid);
+ dp->perm = 0666;
+ dp++;
+ sprint(dp->name, "eia%dctl", i);
+ dp->qid.path = NETQID(i, Nctlqid);
+ dp->perm = 0666;
+ dp++;
+ sprint(dp->name, "eia%dstat", i);
+ dp->qid.path = NETQID(i, Nstatqid);
+ dp->perm = 0444;
+ dp++;
+ }
+}
+
+void
+ns16552init(void)
+{
+}
+
+Chan*
+ns16552attach(char *spec)
+{
+ return devattach('t', spec);
+}
+
+Chan*
+ns16552clone(Chan *c, Chan *nc)
+{
+ return devclone(c, nc);
+}
+
+int
+ns16552walk(Chan *c, char *name)
+{
+ return devwalk(c, name, ns16552dir, 3*nuart, devgen);
+}
+
+void
+ns16552stat(Chan *c, char *dp)
+{
+ int i;
+ Uart *p;
+ Dir dir;
+
+ i = NETID(c->qid.path);
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ p = uart[i];
+ devdir(c, c->qid, ns16552dir[3*i].name, qlen(p->iq), eve, 0660, &dir);
+ convD2M(&dir, dp);
+ break;
+ default:
+ devstat(c, dp, ns16552dir, 3*nuart, devgen);
+ break;
+ }
+}
+
+Chan*
+ns16552open(Chan *c, int omode)
+{
+ Uart *p;
+
+ if(c->qid.path & CHDIR){
+ if(omode != OREAD)
+ error(Ebadarg);
+ } else if(NETTYPE(c->qid.path) == Nstatqid){
+ ;
+ } else {
+ p = uart[NETID(c->qid.path)];
+ qlock(p);
+ p->opens++;
+ ns16552enable(p);
+ qreopen(p->iq);
+ qreopen(p->oq);
+ qunlock(p);
+ }
+
+ c->mode = omode&~OTRUNC;
+ c->flag |= COPEN;
+ c->offset = 0;
+ return c;
+}
+
+void
+ns16552create(Chan *c, char *name, int omode, ulong perm)
+{
+ USED(c, name, omode, perm);
+ error(Eperm);
+}
+
+void
+ns16552close(Chan *c)
+{
+ Uart *p;
+
+ if(c->qid.path & CHDIR)
+ return;
+ if(NETTYPE(c->qid.path) == Nstatqid)
+ return;
+
+ p = uart[NETID(c->qid.path)];
+ if(c->flag & COPEN){
+ qlock(p);
+ p->opens--;
+ if(p->opens == 0){
+ ns16552disable(p);
+ qclose(p->iq);
+ qclose(p->oq);
+ p->ip = p->istage;
+ }
+ qunlock(p);
+ }
+}
+
+static long
+uartstatus(Chan *c, Uart *p, void *buf, long n, long offset)
+{
+ uchar mstat;
+ uchar tstat;
+ char str[256];
+ int i;
+
+ str[0] = 0;
+ tstat = p->sticky[Mctl];
+ mstat = uartrdreg(p, Mstat);
+ i = sprint(str, "%d printing %d cts %d qlen %d/%d", NETID(c->qid.path),
+ p->printing, p->cts, qlen(p->iq), qlen(p->oq));
+ sprint(str+i, " lstat %ux mstat %ux istat %ux ier %ux ferr %d oerr %d",
+ uartrdreg(p, Lstat), mstat, uartrdreg(p, Istat), uartrdreg(p, Iena),
+ p->frame, p->overrun);
+ 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");
+ strcat(str, "\n");
+ return readstr(offset, buf, n, str);
+}
+
+long
+ns16552read(Chan *c, void *buf, long n, ulong offset)
+{
+ Uart *p;
+
+ if(c->qid.path & CHDIR)
+ return devdirread(c, buf, n, ns16552dir, 3*nuart, devgen);
+
+ p = uart[NETID(c->qid.path)];
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ return qread(p->iq, buf, n);
+ case Nctlqid:
+ return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
+ case Nstatqid:
+ return uartstatus(c, p, buf, n, offset);
+ }
+
+ return 0;
+}
+
+static void
+ns16552ctl(Uart *p, char *cmd)
+{
+ int i, n;
+
+ /* let output drain for a while */
+ for(i = 0; i < 16 && qlen(p->oq); i++)
+ tsleep(&p->r, qlen, p->oq, 125);
+
+ if(strncmp(cmd, "break", 5) == 0){
+ ns16552break(p, 0);
+ return;
+ }
+
+
+ n = atoi(cmd+1);
+ switch(*cmd){
+ case 'B':
+ case 'b':
+ ns16552setbaud(p, n);
+ break;
+ case 'D':
+ case 'd':
+ ns16552dtr(p, n);
+ break;
+ case 'H':
+ case 'h':
+ qhangup(p->iq);
+ qhangup(p->oq);
+ break;
+ case 'L':
+ case 'l':
+ ns16552bits(p, n);
+ break;
+ case 'm':
+ case 'M':
+ ns16552mflow(p, n);
+ break;
+ case 'n':
+ case 'N':
+ qnoblock(p->oq, n);
+ break;
+ case 'P':
+ case 'p':
+ ns16552parity(p, *(cmd+1));
+ break;
+ case 'K':
+ case 'k':
+ ns16552break(p, n);
+ break;
+ case 'R':
+ case 'r':
+ ns16552rts(p, n);
+ break;
+ case 'Q':
+ case 'q':
+ qsetlimit(p->iq, n);
+ qsetlimit(p->oq, n);
+ break;
+ case 'W':
+ case 'w':
+ /* obsolete */
+ break;
+ case 'X':
+ case 'x':
+ p->xonoff = n;
+ break;
+ }
+}
+
+long
+ns16552write(Chan *c, void *buf, long n, ulong offset)
+{
+ Uart *p;
+ char cmd[32];
+
+ USED(offset);
+
+ if(c->qid.path & CHDIR)
+ error(Eperm);
+
+ p = uart[NETID(c->qid.path)];
+
+ /*
+ * The fifo's turn themselves off sometimes.
+ * It must be something I don't understand. -- presotto
+ */
+ if((p->istat & Fenabd) == 0 && p->fifoon && p->nofifo == 0)
+ ns16552fifoon(p);
+
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ return qwrite(p->oq, buf, n);
+ case Nctlqid:
+ if(n >= sizeof(cmd))
+ n = sizeof(cmd)-1;
+ memmove(cmd, buf, n);
+ cmd[n] = 0;
+ ns16552ctl(p, cmd);
+ return n;
+ }
+}
+
+void
+ns16552remove(Chan *c)
+{
+ USED(c);
+ error(Eperm);
+}
+
+void
+ns16552wstat(Chan *c, char *dp)
+{
+ USED(c, dp);
+ error(Eperm);
+}
M port/devpipe.c => port/devpipe.c +2 -2
@@ 313,11 313,11 @@ pipewrite(Chan *c, void *va, long n, ulong offset)
switch(NETTYPE(c->qid.path)){
case Qdata0:
- n = qwrite(p->q[1], va, n, 0);
+ n = qwrite(p->q[1], va, n);
break;
case Qdata1:
- n = qwrite(p->q[0], va, n, 0);
+ n = qwrite(p->q[0], va, n);
break;
default:
M port/portfns.h => port/portfns.h +3 -1
@@ 202,7 202,9 @@ long qread(Queue*, void*, int);
void qreopen(Queue*);
void qunlock(QLock*);
int qwindow(Queue*);
-long qwrite(Queue*, void*, int, int);
+long qwrite(Queue*, void*, int);
+void qsetlimit(Queue*, int);
+void qnoblock(Queue*, int);
int readnum(ulong, char*, ulong, ulong, int);
int readstr(ulong, char*, ulong, char*);
void ready(Proc*);
M port/qio.c => port/qio.c +34 -10
@@ 13,6 13,8 @@ struct
static int debuging;
+#define QDEBUG if(0)
+
/*
* IO queues
*/
@@ 27,7 29,9 @@ struct Queue
int len; /* bytes in queue */
int limit; /* max bytes in queue */
+ int inilim; /* initial limit */
int state;
+ int noblock; /* true if writes return immediately when q full */
int eof; /* number of eofs read by user */
void (*kick)(void*); /* restart output */
@@ 172,7 176,7 @@ qconsume(Queue *q, void *vp, int len)
unlock(q);
return -1;
}
-checkb(b, "qconsume 1");
+ QDEBUG checkb(b, "qconsume 1");
n = BLEN(b);
if(n < len)
@@ 195,7 199,7 @@ checkb(b, "qconsume 1");
if(dowakeup)
wakeup(&q->wr);
-checkb(b, "qconsume 2");
+ QDEBUG checkb(b, "qconsume 2");
/* discard the block if we're done with it */
if((q->state & Qmsg) || len == n)
freeb(b);
@@ 238,7 242,7 @@ qpass(Queue *q, Block *b)
q->bfirst = b;
q->blast = b;
q->len += len;
-checkb(b, "qpass");
+ QDEBUG checkb(b, "qpass");
if(q->len >= q->limit/2)
q->state |= Qflow;
@@ 308,7 312,7 @@ qproduce(Queue *q, void *vp, int len)
q->bfirst = b;
q->blast = b;
q->len += len;
-checkb(b, "qproduce");
+ QDEBUG checkb(b, "qproduce");
if(q->state & Qstarve){
q->state &= ~Qstarve;
@@ 337,7 341,7 @@ qopen(int limit, int msg, void (*kick)(void*), void *arg)
if(q == 0)
return 0;
- q->limit = limit;
+ q->limit = q->inilim = limit;
q->kick = kick;
q->arg = arg;
q->state = msg ? Qmsg : 0;
@@ 422,7 426,7 @@ qread(Queue *q, void *vp, int len)
sleep(&q->rr, notempty, q);
}
}
-checkb(b, "qread 1");
+ QDEBUG checkb(b, "qread 1");
/* remove a buffered block */
q->bfirst = b->next;
@@ 443,7 447,7 @@ checkb(b, "qread 1");
memmove(p, b->rp, n);
b->rp += n;
-checkb(b, "qread 2");
+ 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);
@@ 482,7 486,7 @@ qnotfull(void *a)
* all copies should be outside of ilock since they can fault.
*/
long
-qwrite(Queue *q, void *vp, int len, int nowait)
+qwrite(Queue *q, void *vp, int len)
{
int n, sofar, dowakeup;
Block *b;
@@ 530,7 534,7 @@ qwrite(Queue *q, void *vp, int len, int nowait)
/* flow control */
while(!qnotfull(q)){
- if(nowait){
+ if(q->noblock){
freeb(b);
qunlock(&q->wlock);
poperror();
@@ 549,7 553,7 @@ qwrite(Queue *q, void *vp, int len, int nowait)
}
poperror();
-checkb(b, "qwrite");
+ QDEBUG checkb(b, "qwrite");
if(q->syncbuf){
/* we guessed wrong and did an extra copy */
if(n > q->synclen)
@@ 645,6 649,8 @@ qreopen(Queue *q)
q->state &= ~Qclosed;
q->state |= Qstarve;
q->eof = 0;
+ q->noblock = 0;
+ q->limit = q->inilim;
}
/*
@@ 678,3 684,21 @@ qcanread(Queue *q)
{
return q->bfirst!=0;
}
+
+/*
+ * change queue limit
+ */
+void
+qsetlimit(Queue *q, int limit)
+{
+ q->limit = limit;
+}
+
+/*
+ * set blocking/nonblocking
+ */
+void
+qnoblock(Queue *q, int onoff)
+{
+ q->noblock = onoff;
+}
M power/devduart.c => power/devduart.c +1 -1
@@ 672,7 672,7 @@ duartwrite(Chan *c, void *va, long n, ulong offset)
p = &uart[NETID(c->qid.path)];
switch(NETTYPE(c->qid.path)){
case Ndataqid:
- return qwrite(p->oq, va, n, 0);
+ return qwrite(p->oq, va, n);
case Nctlqid:
if(n >= sizeof(cmd))
n = sizeof(cmd)-1;