#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h" #include "../port/netif.h" /* * Driver for the uart. */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) */ Ipend= 1, /* interrupt pending (not) */ Fenabd=(3<<6), /* on if fifo's enabled */ Fifoctl=2, /* fifo control (write) */ Fena= (1<<0), /* enable xmit/rcv fifos */ Fdma= (1<<3), /* dma on */ 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 */ Berror=(1<<4), /* break alarm */ 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 */ Ringl= (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= 2, /* max per machine */}; typedef struct Uart Uart;struct Uart{ QLock; int opens; int enabled; Uart *elist; /* next enabled interface */ char name[KNAMELEN]; uchar sticky[8]; /* sticky write register values */ void* regs; ulong port; ulong freq; /* clock frequency */ uchar mask; /* bits/char */ int dev; int baud; /* baud rate */ uchar istat; /* last istat read */ int frame; /* framing errors */ int overrun; /* rcvr overruns */ /* buffers */ int (*putc)(Queue*, int); Queue *iq; Queue *oq; Lock flock; /* fifo */ uchar fifoon; /* fifo's enabled */ uchar nofifo; /* earlier chip version with nofifo */ Lock rlock; /* receive */ uchar istage[Stagesize]; uchar *ip; uchar *ie; int haveinput; Lock tlock; /* transmit */ uchar ostage[Stagesize]; uchar *op; uchar *oe; int modem; /* hardware flow control on */ int xonoff; /* software flow control on */ int blocked; int cts, dsr, dcd; /* keep track of modem status */ int ctsbackoff; int hup_dsr, hup_dcd; /* send hangup upstream? */ int dohup; Rendez r;}; static Uart *uart[Nuart];static int nuart; struct Uartalloc { Lock; Uart *elist; /* list of enabled interfaces */} uartalloc; static void uartintr(Uart*); /* * pick up architecture specific routines and definitions */#include "uart.h" /* * set the baud rate by calculating and setting the baudrate * generator constant. This will work with fairly non-standard * baud rates. */static voiduartsetbaud(Uart *p, int rate){ ulong brconst; if(rate <= 0) return; p->freq = archuartclock(p->port, rate); if(p->freq == 0) return; brconst = (p->freq+8*rate-1)/(16*rate); uartwrreg(p, Format, Dra); uartwr(p, Dmsb, (brconst>>8) & 0xff); uartwr(p, Dlsb, brconst & 0xff); uartwrreg(p, Format, 0); p->baud = rate;} /* * decide if we should hangup when dsr or dcd drops. */static voiduartdsrhup(Uart *p, int n){ p->hup_dsr = n;} static voiduartdcdhup(Uart *p, int n){ p->hup_dcd = n;} static voiduartparity(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 */voiduartbits(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 */voiduartdtr(Uart *p, int n){ if(n) p->sticky[Mctl] |= Dtr; else p->sticky[Mctl] &= ~Dtr; uartwrreg(p, Mctl, 0);} /* * toggle RTS */voiduartrts(Uart *p, int n){ if(n) p->sticky[Mctl] |= Rts; else p->sticky[Mctl] &= ~Rts; uartwrreg(p, Mctl, 0);} /* * send break */static voiduartbreak(Uart *p, int ms){ if(ms == 0) ms = 200; uartwrreg(p, Format, Break); tsleep(&up->sleep, return0, 0, ms); uartwrreg(p, Format, 0);} static voiduartfifoon(Uart *p){ ulong i, x; if(p->nofifo || uartrdreg(p, Istat) & Fenabd) return; x = splhi(); /* reset fifos */ p->sticky[Fifoctl] = 0; uartwrreg(p, Fifoctl, Fclear); /* empty buffer and interrupt conditions */ for(i = 0; i < 16; i++){ if(uartrdreg(p, Istat)){ /* nothing to do */ } if(uartrdreg(p, Data)){ /* nothing to do */ } } /* turn on fifo */ p->fifoon = 1; p->sticky[Fifoctl] = Fena|Ftrig; uartwrreg(p, Fifoctl, 0); p->istat = uartrdreg(p, Istat); 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) */static voiduartmflow(Uart *p, int n){ ilock(&p->tlock); if(n){ p->sticky[Iena] |= Imstat; uartwrreg(p, Iena, 0); p->modem = 1; p->cts = uartrdreg(p, Mstat) & Cts; } else { p->sticky[Iena] &= ~Imstat; uartwrreg(p, Iena, 0); p->modem = 0; p->cts = 1; } iunlock(&p->tlock); // ilock(&p->flock);// if(1)// /* turn on fifo's */// uartfifoon(p);// else {// /* turn off fifo's */// p->fifoon = 0;// p->sticky[Fifoctl] = 0;// uartwrreg(p, Fifoctl, Fclear);// }// iunlock(&p->flock);} /* * turn on a port's interrupts. set DTR and RTS */static voiduartenable(Uart *p){ Uart **l; if(p->enabled) return; uartportpower(p, 1); p->hup_dsr = p->hup_dcd = 0; p->cts = p->dsr = p->dcd = 0; /* * turn on interrupts */ p->sticky[Iena] = Ircv | Ixmt | Irstat; uartwrreg(p, Iena, 0); /* * turn on DTR and RTS */ uartdtr(p, 1); uartrts(p, 1); uartfifoon(p); /* * assume we can send */ ilock(&p->tlock); p->cts = 1; p->blocked = 0; iunlock(&p->tlock); /* * set baud rate to the last used */ uartsetbaud(p, p->baud); 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 */static voiduartdisable(Uart *p){ Uart **l; /* * turn off interrupts */ 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 */ uartdtr(p, 0); uartrts(p, 0); uartmflow(p, 0); ilock(&p->tlock); p->xonoff = p->blocked = 0; iunlock(&p->tlock); uartportpower(p, 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 intstageoutput(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 voiduartkick0(Uart *p){ int i; if((p->modem && (p->cts == 0)) || p->blocked) return; /* * 128 here is an arbitrary limit to make sure * we don't stay in this loop too long. If the * chips output queue is longer than 128, too * bad -- presotto */ for(i = 0; i < 128; i++){ if(!(uartrdreg(p, Lstat) & Outready)) break; if(p->op >= p->oe && stageoutput(p) == 0) break; uartwr(p, Data, *p->op++); }} static voiduartkick(void *v){ Uart *p; p = v; ilock(&p->tlock); uartkick0(p); iunlock(&p->tlock);} /* * restart input if it's off */static voiduartflow(void *v){ Uart *p; p = v; if(p->modem) uartrts(p, 1); ilock(&p->rlock); p->haveinput = 1; iunlock(&p->rlock);} /* * default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,Lines 1–500 of 1064. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "../port/netif.h" /* * Driver for the uart. */ 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) */ Ipend= 1, /* interrupt pending (not) */ Fenabd=(3<<6), /* on if fifo's enabled */ Fifoctl=2, /* fifo control (write) */ Fena= (1<<0), /* enable xmit/rcv fifos */ Fdma= (1<<3), /* dma on */ 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 */ Berror=(1<<4), /* break alarm */ 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 */ Ringl= (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= 2, /* max per machine */ }; typedef struct Uart Uart; struct Uart { QLock; int opens; int enabled; Uart *elist; /* next enabled interface */ char name[KNAMELEN]; uchar sticky[8]; /* sticky write register values */ void* regs; ulong port; ulong freq; /* clock frequency */ uchar mask; /* bits/char */ int dev; int baud; /* baud rate */ uchar istat; /* last istat read */ int frame; /* framing errors */ int overrun; /* rcvr overruns */ /* buffers */ int (*putc)(Queue*, int); Queue *iq; Queue *oq; Lock flock; /* fifo */ uchar fifoon; /* fifo's enabled */ uchar nofifo; /* earlier chip version with nofifo */ Lock rlock; /* receive */ uchar istage[Stagesize]; uchar *ip; uchar *ie; int haveinput; Lock tlock; /* transmit */ uchar ostage[Stagesize]; uchar *op; uchar *oe; int modem; /* hardware flow control on */ int xonoff; /* software flow control on */ int blocked; int cts, dsr, dcd; /* keep track of modem status */ int ctsbackoff; int hup_dsr, hup_dcd; /* send hangup upstream? */ int dohup; Rendez r; }; static Uart *uart[Nuart]; static int nuart; struct Uartalloc { Lock; Uart *elist; /* list of enabled interfaces */ } uartalloc; static void uartintr(Uart*); /* * pick up architecture specific routines and definitions */ #include "uart.h" /* * set the baud rate by calculating and setting the baudrate * generator constant. This will work with fairly non-standard * baud rates. */ static void uartsetbaud(Uart *p, int rate) { ulong brconst; if(rate <= 0) return; p->freq = archuartclock(p->port, rate); if(p->freq == 0) return; brconst = (p->freq+8*rate-1)/(16*rate); uartwrreg(p, Format, Dra); uartwr(p, Dmsb, (brconst>>8) & 0xff); uartwr(p, Dlsb, brconst & 0xff); uartwrreg(p, Format, 0); p->baud = rate; } /* * decide if we should hangup when dsr or dcd drops. */ static void uartdsrhup(Uart *p, int n) { p->hup_dsr = n; } static void uartdcdhup(Uart *p, int n) { p->hup_dcd = n; } static void uartparity(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 uartbits(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 uartdtr(Uart *p, int n) { if(n) p->sticky[Mctl] |= Dtr; else p->sticky[Mctl] &= ~Dtr; uartwrreg(p, Mctl, 0); } /* * toggle RTS */ void uartrts(Uart *p, int n) { if(n) p->sticky[Mctl] |= Rts; else p->sticky[Mctl] &= ~Rts; uartwrreg(p, Mctl, 0); } /* * send break */ static void uartbreak(Uart *p, int ms) { if(ms == 0) ms = 200; uartwrreg(p, Format, Break); tsleep(&up->sleep, return0, 0, ms); uartwrreg(p, Format, 0); } static void uartfifoon(Uart *p) { ulong i, x; if(p->nofifo || uartrdreg(p, Istat) & Fenabd) return; x = splhi(); /* reset fifos */ p->sticky[Fifoctl] = 0; uartwrreg(p, Fifoctl, Fclear); /* empty buffer and interrupt conditions */ for(i = 0; i < 16; i++){ if(uartrdreg(p, Istat)){ /* nothing to do */ } if(uartrdreg(p, Data)){ /* nothing to do */ } } /* turn on fifo */ p->fifoon = 1; p->sticky[Fifoctl] = Fena|Ftrig; uartwrreg(p, Fifoctl, 0); p->istat = uartrdreg(p, Istat); 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) */ static void uartmflow(Uart *p, int n) { ilock(&p->tlock); if(n){ p->sticky[Iena] |= Imstat; uartwrreg(p, Iena, 0); p->modem = 1; p->cts = uartrdreg(p, Mstat) & Cts; } else { p->sticky[Iena] &= ~Imstat; uartwrreg(p, Iena, 0); p->modem = 0; p->cts = 1; } iunlock(&p->tlock); // ilock(&p->flock); // if(1) // /* turn on fifo's */ // uartfifoon(p); // else { // /* turn off fifo's */ // p->fifoon = 0; // p->sticky[Fifoctl] = 0; // uartwrreg(p, Fifoctl, Fclear); // } // iunlock(&p->flock); } /* * turn on a port's interrupts. set DTR and RTS */ static void uartenable(Uart *p) { Uart **l; if(p->enabled) return; uartportpower(p, 1); p->hup_dsr = p->hup_dcd = 0; p->cts = p->dsr = p->dcd = 0; /* * turn on interrupts */ p->sticky[Iena] = Ircv | Ixmt | Irstat; uartwrreg(p, Iena, 0); /* * turn on DTR and RTS */ uartdtr(p, 1); uartrts(p, 1); uartfifoon(p); /* * assume we can send */ ilock(&p->tlock); p->cts = 1; p->blocked = 0; iunlock(&p->tlock); /* * set baud rate to the last used */ uartsetbaud(p, p->baud); 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 */ static void uartdisable(Uart *p) { Uart **l; /* * turn off interrupts */ 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 */ uartdtr(p, 0); uartrts(p, 0); uartmflow(p, 0); ilock(&p->tlock); p->xonoff = p->blocked = 0; iunlock(&p->tlock); uartportpower(p, 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 uartkick0(Uart *p) { int i; if((p->modem && (p->cts == 0)) || p->blocked) return; /* * 128 here is an arbitrary limit to make sure * we don't stay in this loop too long. If the * chips output queue is longer than 128, too * bad -- presotto */ for(i = 0; i < 128; i++){ if(!(uartrdreg(p, Lstat) & Outready)) break; if(p->op >= p->oe && stageoutput(p) == 0) break; uartwr(p, Data, *p->op++); } } static void uartkick(void *v) { Uart *p; p = v; ilock(&p->tlock); uartkick0(p); iunlock(&p->tlock); } /* * restart input if it's off */ static void uartflow(void *v) { Uart *p; p = v; if(p->modem) uartrts(p, 1); ilock(&p->rlock); p->haveinput = 1; iunlock(&p->rlock); } /* * default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,