193631029SDavid du Colombier #include "u.h"
293631029SDavid du Colombier #include "../port/lib.h"
393631029SDavid du Colombier #include "mem.h"
493631029SDavid du Colombier #include "dat.h"
593631029SDavid du Colombier #include "fns.h"
693631029SDavid du Colombier #include "io.h"
793631029SDavid du Colombier #include "../port/error.h"
893631029SDavid du Colombier
993631029SDavid du Colombier #include "../port/netif.h"
1093631029SDavid du Colombier
1193631029SDavid du Colombier enum
1293631029SDavid du Colombier {
1393631029SDavid du Colombier /* soft flow control chars */
1493631029SDavid du Colombier CTLS= 023,
1593631029SDavid du Colombier CTLQ= 021,
1693631029SDavid du Colombier };
1793631029SDavid du Colombier
1893631029SDavid du Colombier extern Dev uartdevtab;
1993631029SDavid du Colombier extern PhysUart* physuart[];
2093631029SDavid du Colombier
2193631029SDavid du Colombier static Uart* uartlist;
2293631029SDavid du Colombier static Uart** uart;
2393631029SDavid du Colombier static int uartnuart;
2493631029SDavid du Colombier static Dirtab *uartdir;
2593631029SDavid du Colombier static int uartndir;
2693631029SDavid du Colombier static Timer *uarttimer;
2793631029SDavid du Colombier
2893631029SDavid du Colombier struct Uartalloc {
2993631029SDavid du Colombier Lock;
3093631029SDavid du Colombier Uart *elist; /* list of enabled interfaces */
3193631029SDavid du Colombier } uartalloc;
3293631029SDavid du Colombier
3393631029SDavid du Colombier static void uartclock(void);
3493631029SDavid du Colombier static void uartflow(void*);
3593631029SDavid du Colombier
3693631029SDavid du Colombier /*
3793631029SDavid du Colombier * enable/disable uart and add/remove to list of enabled uarts
3893631029SDavid du Colombier */
3993631029SDavid du Colombier //static
4093631029SDavid du Colombier Uart*
uartenable(Uart * p)4193631029SDavid du Colombier uartenable(Uart *p)
4293631029SDavid du Colombier {
4393631029SDavid du Colombier Uart **l;
4493631029SDavid du Colombier
4593631029SDavid du Colombier if (up == nil)
4693631029SDavid du Colombier return p; /* too soon; try again later */
4793631029SDavid du Colombier // return nil;
4893631029SDavid du Colombier
4993631029SDavid du Colombier if(p->iq == nil){
5093631029SDavid du Colombier if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)
5193631029SDavid du Colombier return nil;
5293631029SDavid du Colombier }
5393631029SDavid du Colombier else
5493631029SDavid du Colombier qreopen(p->iq);
5593631029SDavid du Colombier if(p->oq == nil){
5693631029SDavid du Colombier if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
5793631029SDavid du Colombier qfree(p->iq);
5893631029SDavid du Colombier p->iq = nil;
5993631029SDavid du Colombier return nil;
6093631029SDavid du Colombier }
6193631029SDavid du Colombier }
6293631029SDavid du Colombier else
6393631029SDavid du Colombier qreopen(p->oq);
6493631029SDavid du Colombier
6593631029SDavid du Colombier p->ir = p->istage;
6693631029SDavid du Colombier p->iw = p->istage;
6793631029SDavid du Colombier p->ie = &p->istage[Stagesize];
6893631029SDavid du Colombier p->op = p->ostage;
6993631029SDavid du Colombier p->oe = p->ostage;
7093631029SDavid du Colombier
7193631029SDavid du Colombier p->hup_dsr = p->hup_dcd = 0;
7293631029SDavid du Colombier p->dsr = p->dcd = 0;
7393631029SDavid du Colombier
7493631029SDavid du Colombier /* assume we can send */
7593631029SDavid du Colombier p->cts = 1;
7693631029SDavid du Colombier p->ctsbackoff = 0;
7793631029SDavid du Colombier
7893631029SDavid du Colombier if (up) {
7993631029SDavid du Colombier if(p->bits == 0)
8093631029SDavid du Colombier uartctl(p, "l8");
8193631029SDavid du Colombier if(p->stop == 0)
8293631029SDavid du Colombier uartctl(p, "s1");
8393631029SDavid du Colombier if(p->parity == 0)
8493631029SDavid du Colombier uartctl(p, "pn");
8593631029SDavid du Colombier if(p->baud == 0)
8693631029SDavid du Colombier uartctl(p, "b9600");
8793631029SDavid du Colombier (*p->phys->enable)(p, 1);
8893631029SDavid du Colombier }
8993631029SDavid du Colombier
9093631029SDavid du Colombier /*
9193631029SDavid du Colombier * use ilock because uartclock can otherwise interrupt here
9293631029SDavid du Colombier * and would hang on an attempt to lock uartalloc.
9393631029SDavid du Colombier */
9493631029SDavid du Colombier ilock(&uartalloc);
9593631029SDavid du Colombier for(l = &uartalloc.elist; *l; l = &(*l)->elist){
9693631029SDavid du Colombier if(*l == p)
9793631029SDavid du Colombier break;
9893631029SDavid du Colombier }
9993631029SDavid du Colombier if(*l == 0){
10093631029SDavid du Colombier p->elist = uartalloc.elist;
10193631029SDavid du Colombier uartalloc.elist = p;
10293631029SDavid du Colombier }
10393631029SDavid du Colombier p->enabled = 1;
10493631029SDavid du Colombier iunlock(&uartalloc);
10593631029SDavid du Colombier
10693631029SDavid du Colombier return p;
10793631029SDavid du Colombier }
10893631029SDavid du Colombier
10993631029SDavid du Colombier static void
uartdisable(Uart * p)11093631029SDavid du Colombier uartdisable(Uart *p)
11193631029SDavid du Colombier {
11293631029SDavid du Colombier Uart **l;
11393631029SDavid du Colombier
11493631029SDavid du Colombier (*p->phys->disable)(p);
11593631029SDavid du Colombier
11693631029SDavid du Colombier ilock(&uartalloc);
11793631029SDavid du Colombier for(l = &uartalloc.elist; *l; l = &(*l)->elist){
11893631029SDavid du Colombier if(*l == p){
11993631029SDavid du Colombier *l = p->elist;
12093631029SDavid du Colombier break;
12193631029SDavid du Colombier }
12293631029SDavid du Colombier }
12393631029SDavid du Colombier p->enabled = 0;
12493631029SDavid du Colombier iunlock(&uartalloc);
12593631029SDavid du Colombier }
12693631029SDavid du Colombier
12793631029SDavid du Colombier void
uartmouse(Uart * p,int (* putc)(Queue *,int),int setb1200)12893631029SDavid du Colombier uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200)
12993631029SDavid du Colombier {
13093631029SDavid du Colombier qlock(p);
13193631029SDavid du Colombier if(p->opens++ == 0 && uartenable(p) == nil){
13293631029SDavid du Colombier qunlock(p);
13393631029SDavid du Colombier error(Enodev);
13493631029SDavid du Colombier }
13593631029SDavid du Colombier if(setb1200)
13693631029SDavid du Colombier uartctl(p, "b1200");
13793631029SDavid du Colombier p->putc = putc;
13893631029SDavid du Colombier p->special = 1;
13993631029SDavid du Colombier qunlock(p);
14093631029SDavid du Colombier }
14193631029SDavid du Colombier
14293631029SDavid du Colombier void
uartsetmouseputc(Uart * p,int (* putc)(Queue *,int))14393631029SDavid du Colombier uartsetmouseputc(Uart* p, int (*putc)(Queue*, int))
14493631029SDavid du Colombier {
14593631029SDavid du Colombier qlock(p);
14693631029SDavid du Colombier if(p->opens == 0 || p->special == 0){
14793631029SDavid du Colombier qunlock(p);
14893631029SDavid du Colombier error(Enodev);
14993631029SDavid du Colombier }
15093631029SDavid du Colombier p->putc = putc;
15193631029SDavid du Colombier qunlock(p);
15293631029SDavid du Colombier }
15393631029SDavid du Colombier
15493631029SDavid du Colombier static void
setlength(int i)15593631029SDavid du Colombier setlength(int i)
15693631029SDavid du Colombier {
15793631029SDavid du Colombier Uart *p;
15893631029SDavid du Colombier
15993631029SDavid du Colombier if(i > 0){
16093631029SDavid du Colombier p = uart[i];
16193631029SDavid du Colombier if(p && p->opens && p->iq)
16293631029SDavid du Colombier uartdir[1+3*i].length = qlen(p->iq);
16393631029SDavid du Colombier } else for(i = 0; i < uartnuart; i++){
16493631029SDavid du Colombier p = uart[i];
16593631029SDavid du Colombier if(p && p->opens && p->iq)
16693631029SDavid du Colombier uartdir[1+3*i].length = qlen(p->iq);
16793631029SDavid du Colombier }
16893631029SDavid du Colombier }
16993631029SDavid du Colombier
17093631029SDavid du Colombier /*
17193631029SDavid du Colombier * set up the '#t' directory
17293631029SDavid du Colombier */
17393631029SDavid du Colombier static void
uartreset(void)17493631029SDavid du Colombier uartreset(void)
17593631029SDavid du Colombier {
17693631029SDavid du Colombier int i;
17793631029SDavid du Colombier Dirtab *dp;
17893631029SDavid du Colombier Uart *p, *tail;
17993631029SDavid du Colombier
18093631029SDavid du Colombier tail = nil;
18193631029SDavid du Colombier for(i = 0; physuart[i] != nil; i++){
18293631029SDavid du Colombier if(physuart[i]->pnp == nil)
18393631029SDavid du Colombier continue;
18493631029SDavid du Colombier if((p = physuart[i]->pnp()) == nil)
18593631029SDavid du Colombier continue;
18693631029SDavid du Colombier if(uartlist != nil)
18793631029SDavid du Colombier tail->next = p;
18893631029SDavid du Colombier else
18993631029SDavid du Colombier uartlist = p;
19093631029SDavid du Colombier for(tail = p; tail->next != nil; tail = tail->next)
19193631029SDavid du Colombier uartnuart++;
19293631029SDavid du Colombier uartnuart++;
19393631029SDavid du Colombier }
19493631029SDavid du Colombier
19593631029SDavid du Colombier if(uartnuart)
19693631029SDavid du Colombier uart = xalloc(uartnuart*sizeof(Uart*));
19793631029SDavid du Colombier
19893631029SDavid du Colombier uartndir = 1 + 3*uartnuart;
19993631029SDavid du Colombier uartdir = xalloc(uartndir * sizeof(Dirtab));
20093631029SDavid du Colombier if (uart == nil || uartdir == nil)
20193631029SDavid du Colombier panic("uartreset: no memory");
20293631029SDavid du Colombier dp = uartdir;
20393631029SDavid du Colombier strcpy(dp->name, ".");
20493631029SDavid du Colombier mkqid(&dp->qid, 0, 0, QTDIR);
20593631029SDavid du Colombier dp->length = 0;
20693631029SDavid du Colombier dp->perm = DMDIR|0555;
20793631029SDavid du Colombier dp++;
20893631029SDavid du Colombier p = uartlist;
20993631029SDavid du Colombier for(i = 0; i < uartnuart; i++){
21093631029SDavid du Colombier /* 3 directory entries per port */
21157d98441SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%d", i);
21293631029SDavid du Colombier dp->qid.path = NETQID(i, Ndataqid);
21393631029SDavid du Colombier dp->perm = 0660;
21493631029SDavid du Colombier dp++;
21557d98441SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%dctl", i);
21693631029SDavid du Colombier dp->qid.path = NETQID(i, Nctlqid);
21793631029SDavid du Colombier dp->perm = 0660;
21893631029SDavid du Colombier dp++;
21957d98441SDavid du Colombier snprint(dp->name, sizeof dp->name, "eia%dstatus", i);
22093631029SDavid du Colombier dp->qid.path = NETQID(i, Nstatqid);
22193631029SDavid du Colombier dp->perm = 0444;
22293631029SDavid du Colombier dp++;
22393631029SDavid du Colombier
22493631029SDavid du Colombier uart[i] = p;
22593631029SDavid du Colombier p->dev = i;
22693631029SDavid du Colombier if(p->console || p->special){
22793631029SDavid du Colombier if(uartenable(p) != nil){
22893631029SDavid du Colombier if(p->console && up){
22993631029SDavid du Colombier kbdq = p->iq;
23093631029SDavid du Colombier serialoq = p->oq;
23193631029SDavid du Colombier p->putc = kbdcr2nl;
23293631029SDavid du Colombier }
23393631029SDavid du Colombier p->opens++;
23493631029SDavid du Colombier }
23593631029SDavid du Colombier }
23693631029SDavid du Colombier p = p->next;
23793631029SDavid du Colombier }
23893631029SDavid du Colombier
23993631029SDavid du Colombier if(uartnuart){
24093631029SDavid du Colombier /*
24193631029SDavid du Colombier * at 115200 baud, the 1024 char buffer takes 56 ms to process,
24293631029SDavid du Colombier * processing it every 22 ms should be fine.
24393631029SDavid du Colombier */
24493631029SDavid du Colombier uarttimer = addclock0link(uartclock, 22);
24593631029SDavid du Colombier }
24693631029SDavid du Colombier }
24793631029SDavid du Colombier
24893631029SDavid du Colombier
24993631029SDavid du Colombier static Chan*
uartattach(char * spec)25093631029SDavid du Colombier uartattach(char *spec)
25193631029SDavid du Colombier {
25293631029SDavid du Colombier return devattach('t', spec);
25393631029SDavid du Colombier }
25493631029SDavid du Colombier
25593631029SDavid du Colombier static Walkqid*
uartwalk(Chan * c,Chan * nc,char ** name,int nname)25693631029SDavid du Colombier uartwalk(Chan *c, Chan *nc, char **name, int nname)
25793631029SDavid du Colombier {
25893631029SDavid du Colombier return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
25993631029SDavid du Colombier }
26093631029SDavid du Colombier
26193631029SDavid du Colombier static int
uartstat(Chan * c,uchar * dp,int n)26293631029SDavid du Colombier uartstat(Chan *c, uchar *dp, int n)
26393631029SDavid du Colombier {
26493631029SDavid du Colombier if(NETTYPE(c->qid.path) == Ndataqid)
26593631029SDavid du Colombier setlength(NETID(c->qid.path));
26693631029SDavid du Colombier return devstat(c, dp, n, uartdir, uartndir, devgen);
26793631029SDavid du Colombier }
26893631029SDavid du Colombier
26993631029SDavid du Colombier static Chan*
uartopen(Chan * c,int omode)27093631029SDavid du Colombier uartopen(Chan *c, int omode)
27193631029SDavid du Colombier {
27293631029SDavid du Colombier Uart *p;
27393631029SDavid du Colombier
27493631029SDavid du Colombier c = devopen(c, omode, uartdir, uartndir, devgen);
27593631029SDavid du Colombier
27693631029SDavid du Colombier switch(NETTYPE(c->qid.path)){
27793631029SDavid du Colombier case Nctlqid:
27893631029SDavid du Colombier case Ndataqid:
27993631029SDavid du Colombier p = uart[NETID(c->qid.path)];
28093631029SDavid du Colombier qlock(p);
28193631029SDavid du Colombier if(p->opens++ == 0 && uartenable(p) == nil){
28293631029SDavid du Colombier qunlock(p);
28393631029SDavid du Colombier c->flag &= ~COPEN;
28493631029SDavid du Colombier error(Enodev);
28593631029SDavid du Colombier }
28693631029SDavid du Colombier qunlock(p);
28793631029SDavid du Colombier break;
28893631029SDavid du Colombier }
28993631029SDavid du Colombier
29093631029SDavid du Colombier c->iounit = qiomaxatomic;
29193631029SDavid du Colombier return c;
29293631029SDavid du Colombier }
29393631029SDavid du Colombier
29493631029SDavid du Colombier static int
uartdrained(void * arg)29593631029SDavid du Colombier uartdrained(void* arg)
29693631029SDavid du Colombier {
29793631029SDavid du Colombier Uart *p;
29893631029SDavid du Colombier
29993631029SDavid du Colombier p = arg;
30093631029SDavid du Colombier return qlen(p->oq) == 0 && p->op == p->oe;
30193631029SDavid du Colombier }
30293631029SDavid du Colombier
30393631029SDavid du Colombier static void
uartdrainoutput(Uart * p)30493631029SDavid du Colombier uartdrainoutput(Uart *p)
30593631029SDavid du Colombier {
30693631029SDavid du Colombier if(!p->enabled || up == nil)
30793631029SDavid du Colombier return;
30893631029SDavid du Colombier
30993631029SDavid du Colombier p->drain = 1;
31093631029SDavid du Colombier if(waserror()){
31193631029SDavid du Colombier p->drain = 0;
31293631029SDavid du Colombier nexterror();
31393631029SDavid du Colombier }
31493631029SDavid du Colombier sleep(&p->r, uartdrained, p);
31593631029SDavid du Colombier poperror();
31693631029SDavid du Colombier }
31793631029SDavid du Colombier
31893631029SDavid du Colombier static void
uartclose(Chan * c)31993631029SDavid du Colombier uartclose(Chan *c)
32093631029SDavid du Colombier {
32193631029SDavid du Colombier Uart *p;
32293631029SDavid du Colombier
32393631029SDavid du Colombier if(c->qid.type & QTDIR)
32493631029SDavid du Colombier return;
32593631029SDavid du Colombier if((c->flag & COPEN) == 0)
32693631029SDavid du Colombier return;
32793631029SDavid du Colombier switch(NETTYPE(c->qid.path)){
32893631029SDavid du Colombier case Ndataqid:
32993631029SDavid du Colombier case Nctlqid:
33093631029SDavid du Colombier p = uart[NETID(c->qid.path)];
33193631029SDavid du Colombier qlock(p);
33293631029SDavid du Colombier if(--(p->opens) == 0){
33393631029SDavid du Colombier qclose(p->iq);
33493631029SDavid du Colombier ilock(&p->rlock);
33593631029SDavid du Colombier p->ir = p->iw = p->istage;
33693631029SDavid du Colombier iunlock(&p->rlock);
33793631029SDavid du Colombier
33893631029SDavid du Colombier /*
33993631029SDavid du Colombier */
34093631029SDavid du Colombier qhangup(p->oq, nil);
34193631029SDavid du Colombier if(!waserror()){
34293631029SDavid du Colombier uartdrainoutput(p);
34393631029SDavid du Colombier poperror();
34493631029SDavid du Colombier }
34593631029SDavid du Colombier qclose(p->oq);
34693631029SDavid du Colombier uartdisable(p);
34793631029SDavid du Colombier p->dcd = p->dsr = p->dohup = 0;
34893631029SDavid du Colombier }
34993631029SDavid du Colombier qunlock(p);
35093631029SDavid du Colombier break;
35193631029SDavid du Colombier }
35293631029SDavid du Colombier }
35393631029SDavid du Colombier
35493631029SDavid du Colombier static long
uartread(Chan * c,void * buf,long n,vlong off)35593631029SDavid du Colombier uartread(Chan *c, void *buf, long n, vlong off)
35693631029SDavid du Colombier {
35793631029SDavid du Colombier Uart *p;
35893631029SDavid du Colombier ulong offset = off;
35993631029SDavid du Colombier
36093631029SDavid du Colombier if(c->qid.type & QTDIR){
36193631029SDavid du Colombier setlength(-1);
36293631029SDavid du Colombier return devdirread(c, buf, n, uartdir, uartndir, devgen);
36393631029SDavid du Colombier }
36493631029SDavid du Colombier
36593631029SDavid du Colombier p = uart[NETID(c->qid.path)];
36693631029SDavid du Colombier switch(NETTYPE(c->qid.path)){
36793631029SDavid du Colombier case Ndataqid:
36893631029SDavid du Colombier return qread(p->iq, buf, n);
36993631029SDavid du Colombier case Nctlqid:
37093631029SDavid du Colombier return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
37193631029SDavid du Colombier case Nstatqid:
37293631029SDavid du Colombier return (*p->phys->status)(p, buf, n, offset);
37393631029SDavid du Colombier }
37493631029SDavid du Colombier
37593631029SDavid du Colombier return 0;
37693631029SDavid du Colombier }
37793631029SDavid du Colombier
37893631029SDavid du Colombier int
uartctl(Uart * p,char * cmd)37993631029SDavid du Colombier uartctl(Uart *p, char *cmd)
38093631029SDavid du Colombier {
38193631029SDavid du Colombier char *f[16];
38293631029SDavid du Colombier int i, n, nf;
38393631029SDavid du Colombier
38493631029SDavid du Colombier nf = tokenize(cmd, f, nelem(f));
38593631029SDavid du Colombier for(i = 0; i < nf; i++){
38693631029SDavid du Colombier if(strncmp(f[i], "break", 5) == 0){
38793631029SDavid du Colombier (*p->phys->dobreak)(p, 0);
38893631029SDavid du Colombier continue;
38993631029SDavid du Colombier }
39093631029SDavid du Colombier
39193631029SDavid du Colombier n = atoi(f[i]+1);
39293631029SDavid du Colombier switch(*f[i]){
39393631029SDavid du Colombier case 'B':
39493631029SDavid du Colombier case 'b':
39593631029SDavid du Colombier uartdrainoutput(p);
39693631029SDavid du Colombier if((*p->phys->baud)(p, n) < 0)
39793631029SDavid du Colombier return -1;
39893631029SDavid du Colombier break;
39993631029SDavid du Colombier case 'C':
40093631029SDavid du Colombier case 'c':
40193631029SDavid du Colombier p->hup_dcd = n;
40293631029SDavid du Colombier break;
40393631029SDavid du Colombier case 'D':
40493631029SDavid du Colombier case 'd':
40593631029SDavid du Colombier uartdrainoutput(p);
40693631029SDavid du Colombier (*p->phys->dtr)(p, n);
40793631029SDavid du Colombier break;
40893631029SDavid du Colombier case 'E':
40993631029SDavid du Colombier case 'e':
41093631029SDavid du Colombier p->hup_dsr = n;
41193631029SDavid du Colombier break;
41293631029SDavid du Colombier case 'f':
41393631029SDavid du Colombier case 'F':
41493631029SDavid du Colombier if(p->oq != nil)
41593631029SDavid du Colombier qflush(p->oq);
41693631029SDavid du Colombier break;
41793631029SDavid du Colombier case 'H':
41893631029SDavid du Colombier case 'h':
41993631029SDavid du Colombier if(p->iq != nil)
42093631029SDavid du Colombier qhangup(p->iq, 0);
42193631029SDavid du Colombier if(p->oq != nil)
42293631029SDavid du Colombier qhangup(p->oq, 0);
42393631029SDavid du Colombier break;
42493631029SDavid du Colombier case 'i':
42593631029SDavid du Colombier case 'I':
42693631029SDavid du Colombier uartdrainoutput(p);
42793631029SDavid du Colombier (*p->phys->fifo)(p, n);
42893631029SDavid du Colombier break;
42993631029SDavid du Colombier case 'K':
43093631029SDavid du Colombier case 'k':
43193631029SDavid du Colombier uartdrainoutput(p);
43293631029SDavid du Colombier (*p->phys->dobreak)(p, n);
43393631029SDavid du Colombier break;
43493631029SDavid du Colombier case 'L':
43593631029SDavid du Colombier case 'l':
43693631029SDavid du Colombier uartdrainoutput(p);
43793631029SDavid du Colombier if((*p->phys->bits)(p, n) < 0)
43893631029SDavid du Colombier return -1;
43993631029SDavid du Colombier break;
44093631029SDavid du Colombier case 'm':
44193631029SDavid du Colombier case 'M':
44293631029SDavid du Colombier uartdrainoutput(p);
44393631029SDavid du Colombier (*p->phys->modemctl)(p, n);
44493631029SDavid du Colombier break;
44593631029SDavid du Colombier case 'n':
44693631029SDavid du Colombier case 'N':
44793631029SDavid du Colombier if(p->oq != nil)
44893631029SDavid du Colombier qnoblock(p->oq, n);
44993631029SDavid du Colombier break;
45093631029SDavid du Colombier case 'P':
45193631029SDavid du Colombier case 'p':
45293631029SDavid du Colombier uartdrainoutput(p);
45393631029SDavid du Colombier if((*p->phys->parity)(p, *(f[i]+1)) < 0)
45493631029SDavid du Colombier return -1;
45593631029SDavid du Colombier break;
45693631029SDavid du Colombier case 'Q':
45793631029SDavid du Colombier case 'q':
45893631029SDavid du Colombier if(p->iq != nil)
45993631029SDavid du Colombier qsetlimit(p->iq, n);
46093631029SDavid du Colombier if(p->oq != nil)
46193631029SDavid du Colombier qsetlimit(p->oq, n);
46293631029SDavid du Colombier break;
46393631029SDavid du Colombier case 'R':
46493631029SDavid du Colombier case 'r':
46593631029SDavid du Colombier uartdrainoutput(p);
46693631029SDavid du Colombier (*p->phys->rts)(p, n);
46793631029SDavid du Colombier break;
46893631029SDavid du Colombier case 'S':
46993631029SDavid du Colombier case 's':
47093631029SDavid du Colombier uartdrainoutput(p);
47193631029SDavid du Colombier if((*p->phys->stop)(p, n) < 0)
47293631029SDavid du Colombier return -1;
47393631029SDavid du Colombier break;
47493631029SDavid du Colombier case 'W':
47593631029SDavid du Colombier case 'w':
47693631029SDavid du Colombier if(uarttimer == nil || n < 1)
47793631029SDavid du Colombier return -1;
47893631029SDavid du Colombier uarttimer->tns = (vlong)n * 100000LL;
47993631029SDavid du Colombier break;
48093631029SDavid du Colombier case 'X':
48193631029SDavid du Colombier case 'x':
48293631029SDavid du Colombier if(p->enabled){
48393631029SDavid du Colombier ilock(&p->tlock);
48493631029SDavid du Colombier p->xonoff = n;
48593631029SDavid du Colombier iunlock(&p->tlock);
48693631029SDavid du Colombier }
48793631029SDavid du Colombier break;
48893631029SDavid du Colombier }
48993631029SDavid du Colombier }
49093631029SDavid du Colombier return 0;
49193631029SDavid du Colombier }
49293631029SDavid du Colombier
49393631029SDavid du Colombier static long
uartwrite(Chan * c,void * buf,long n,vlong)49493631029SDavid du Colombier uartwrite(Chan *c, void *buf, long n, vlong)
49593631029SDavid du Colombier {
49693631029SDavid du Colombier Uart *p;
49793631029SDavid du Colombier char *cmd;
49893631029SDavid du Colombier
49993631029SDavid du Colombier if(c->qid.type & QTDIR)
50093631029SDavid du Colombier error(Eperm);
50193631029SDavid du Colombier
50293631029SDavid du Colombier p = uart[NETID(c->qid.path)];
50393631029SDavid du Colombier
50493631029SDavid du Colombier switch(NETTYPE(c->qid.path)){
50593631029SDavid du Colombier case Ndataqid:
50693631029SDavid du Colombier qlock(p);
50793631029SDavid du Colombier if(waserror()){
50893631029SDavid du Colombier qunlock(p);
50993631029SDavid du Colombier nexterror();
51093631029SDavid du Colombier }
51193631029SDavid du Colombier
51293631029SDavid du Colombier n = qwrite(p->oq, buf, n);
51393631029SDavid du Colombier
51493631029SDavid du Colombier qunlock(p);
51593631029SDavid du Colombier poperror();
51693631029SDavid du Colombier break;
51793631029SDavid du Colombier case Nctlqid:
51893631029SDavid du Colombier cmd = malloc(n+1);
51993631029SDavid du Colombier memmove(cmd, buf, n);
52093631029SDavid du Colombier cmd[n] = 0;
52193631029SDavid du Colombier qlock(p);
52293631029SDavid du Colombier if(waserror()){
52393631029SDavid du Colombier qunlock(p);
52493631029SDavid du Colombier free(cmd);
52593631029SDavid du Colombier nexterror();
52693631029SDavid du Colombier }
52793631029SDavid du Colombier
52893631029SDavid du Colombier /* let output drain */
52993631029SDavid du Colombier if(uartctl(p, cmd) < 0)
53093631029SDavid du Colombier error(Ebadarg);
53193631029SDavid du Colombier
53293631029SDavid du Colombier qunlock(p);
53393631029SDavid du Colombier poperror();
53493631029SDavid du Colombier free(cmd);
53593631029SDavid du Colombier break;
53693631029SDavid du Colombier }
53793631029SDavid du Colombier
53893631029SDavid du Colombier return n;
53993631029SDavid du Colombier }
54093631029SDavid du Colombier
54193631029SDavid du Colombier static int
uartwstat(Chan * c,uchar * dp,int n)54293631029SDavid du Colombier uartwstat(Chan *c, uchar *dp, int n)
54393631029SDavid du Colombier {
54493631029SDavid du Colombier Dir d;
54593631029SDavid du Colombier Dirtab *dt;
54693631029SDavid du Colombier
54793631029SDavid du Colombier if(!iseve())
54893631029SDavid du Colombier error(Eperm);
54993631029SDavid du Colombier if(QTDIR & c->qid.type)
55093631029SDavid du Colombier error(Eperm);
55193631029SDavid du Colombier if(NETTYPE(c->qid.path) == Nstatqid)
55293631029SDavid du Colombier error(Eperm);
55393631029SDavid du Colombier
55493631029SDavid du Colombier dt = &uartdir[1 + 3 * NETID(c->qid.path)];
55593631029SDavid du Colombier n = convM2D(dp, n, &d, nil);
55693631029SDavid du Colombier if(n == 0)
55793631029SDavid du Colombier error(Eshortstat);
55893631029SDavid du Colombier if(d.mode != ~0UL)
55993631029SDavid du Colombier dt[0].perm = dt[1].perm = d.mode;
56093631029SDavid du Colombier return n;
56193631029SDavid du Colombier }
56293631029SDavid du Colombier
56393631029SDavid du Colombier void
uartpower(int on)56493631029SDavid du Colombier uartpower(int on)
56593631029SDavid du Colombier {
56693631029SDavid du Colombier Uart *p;
56793631029SDavid du Colombier
56893631029SDavid du Colombier for(p = uartlist; p != nil; p = p->next) {
56993631029SDavid du Colombier if(p->phys->power)
57093631029SDavid du Colombier (*p->phys->power)(p, on);
57193631029SDavid du Colombier }
57293631029SDavid du Colombier }
57393631029SDavid du Colombier
57493631029SDavid du Colombier Dev uartdevtab = {
57593631029SDavid du Colombier 't',
57693631029SDavid du Colombier "uart",
57793631029SDavid du Colombier
57893631029SDavid du Colombier uartreset,
57993631029SDavid du Colombier devinit,
58093631029SDavid du Colombier devshutdown,
58193631029SDavid du Colombier uartattach,
58293631029SDavid du Colombier uartwalk,
58393631029SDavid du Colombier uartstat,
58493631029SDavid du Colombier uartopen,
58593631029SDavid du Colombier devcreate,
58693631029SDavid du Colombier uartclose,
58793631029SDavid du Colombier uartread,
58893631029SDavid du Colombier devbread,
58993631029SDavid du Colombier uartwrite,
59093631029SDavid du Colombier devbwrite,
59193631029SDavid du Colombier devremove,
59293631029SDavid du Colombier uartwstat,
59393631029SDavid du Colombier uartpower,
59493631029SDavid du Colombier };
59593631029SDavid du Colombier
59693631029SDavid du Colombier /*
59793631029SDavid du Colombier * restart input if it's off
59893631029SDavid du Colombier */
59993631029SDavid du Colombier static void
uartflow(void * v)60093631029SDavid du Colombier uartflow(void *v)
60193631029SDavid du Colombier {
60293631029SDavid du Colombier Uart *p;
60393631029SDavid du Colombier
60493631029SDavid du Colombier p = v;
60593631029SDavid du Colombier if(p->modem)
60693631029SDavid du Colombier (*p->phys->rts)(p, 1);
60793631029SDavid du Colombier }
60893631029SDavid du Colombier
60993631029SDavid du Colombier /*
61093631029SDavid du Colombier * put some bytes into the local queue to avoid calling
61193631029SDavid du Colombier * qconsume for every character
61293631029SDavid du Colombier */
61393631029SDavid du Colombier int
uartstageoutput(Uart * p)61493631029SDavid du Colombier uartstageoutput(Uart *p)
61593631029SDavid du Colombier {
61693631029SDavid du Colombier int n;
61793631029SDavid du Colombier
61893631029SDavid du Colombier n = qconsume(p->oq, p->ostage, Stagesize);
61993631029SDavid du Colombier if(n <= 0)
62093631029SDavid du Colombier // n = 0; /* experiment */
62193631029SDavid du Colombier return 0;
62293631029SDavid du Colombier p->op = p->ostage;
62393631029SDavid du Colombier p->oe = p->ostage + n;
62493631029SDavid du Colombier return n;
62593631029SDavid du Colombier }
62693631029SDavid du Colombier
62793631029SDavid du Colombier /*
62893631029SDavid du Colombier * restart output
62993631029SDavid du Colombier */
63093631029SDavid du Colombier void
uartkick(void * v)63193631029SDavid du Colombier uartkick(void *v)
63293631029SDavid du Colombier {
63393631029SDavid du Colombier Uart *p = v;
63493631029SDavid du Colombier
63593631029SDavid du Colombier if(p->blocked)
63693631029SDavid du Colombier return;
63793631029SDavid du Colombier
63893631029SDavid du Colombier ilock(&p->tlock);
63993631029SDavid du Colombier (*p->phys->kick)(p);
64093631029SDavid du Colombier iunlock(&p->tlock);
64193631029SDavid du Colombier
64293631029SDavid du Colombier if(p->drain && uartdrained(p)){
64393631029SDavid du Colombier p->drain = 0;
64493631029SDavid du Colombier wakeup(&p->r);
64593631029SDavid du Colombier }
64693631029SDavid du Colombier }
64793631029SDavid du Colombier
64893631029SDavid du Colombier /*
64993631029SDavid du Colombier * Move data from the interrupt staging area to
65093631029SDavid du Colombier * the input Queue.
65193631029SDavid du Colombier */
65293631029SDavid du Colombier static void
uartstageinput(Uart * p)65393631029SDavid du Colombier uartstageinput(Uart *p)
65493631029SDavid du Colombier {
65593631029SDavid du Colombier int n;
65693631029SDavid du Colombier uchar *ir, *iw;
65793631029SDavid du Colombier
65893631029SDavid du Colombier while(p->ir != p->iw){
65993631029SDavid du Colombier ir = p->ir;
66093631029SDavid du Colombier if(p->ir > p->iw){
66193631029SDavid du Colombier iw = p->ie;
66293631029SDavid du Colombier p->ir = p->istage;
66393631029SDavid du Colombier }
66493631029SDavid du Colombier else{
66593631029SDavid du Colombier iw = p->iw;
66693631029SDavid du Colombier p->ir = p->iw;
66793631029SDavid du Colombier }
66893631029SDavid du Colombier if((n = qproduce(p->iq, ir, iw - ir)) < 0){
66993631029SDavid du Colombier p->serr++;
67093631029SDavid du Colombier (*p->phys->rts)(p, 0);
67193631029SDavid du Colombier }
67293631029SDavid du Colombier else if(n == 0)
67393631029SDavid du Colombier p->berr++;
67493631029SDavid du Colombier }
67593631029SDavid du Colombier }
67693631029SDavid du Colombier
67793631029SDavid du Colombier /*
67893631029SDavid du Colombier * receive a character at interrupt time
67993631029SDavid du Colombier */
68093631029SDavid du Colombier void
uartrecv(Uart * p,char ch)68193631029SDavid du Colombier uartrecv(Uart *p, char ch)
68293631029SDavid du Colombier {
68393631029SDavid du Colombier uchar *next;
68493631029SDavid du Colombier
68593631029SDavid du Colombier /* software flow control */
68693631029SDavid du Colombier if(p->xonoff){
68793631029SDavid du Colombier if(ch == CTLS){
68893631029SDavid du Colombier p->blocked = 1;
68993631029SDavid du Colombier }else if(ch == CTLQ){
69093631029SDavid du Colombier p->blocked = 0;
69193631029SDavid du Colombier p->ctsbackoff = 2; /* clock gets output going again */
69293631029SDavid du Colombier }
69393631029SDavid du Colombier }
69493631029SDavid du Colombier
69593631029SDavid du Colombier /* receive the character */
69693631029SDavid du Colombier if(p->putc)
69793631029SDavid du Colombier p->putc(p->iq, ch);
69893631029SDavid du Colombier else if (p->iw) { /* maybe the line isn't enabled yet */
69993631029SDavid du Colombier ilock(&p->rlock);
70093631029SDavid du Colombier next = p->iw + 1;
70193631029SDavid du Colombier if(next == p->ie)
70293631029SDavid du Colombier next = p->istage;
70393631029SDavid du Colombier if(next == p->ir)
70493631029SDavid du Colombier uartstageinput(p);
70593631029SDavid du Colombier if(next != p->ir){
70693631029SDavid du Colombier *p->iw = ch;
70793631029SDavid du Colombier p->iw = next;
70893631029SDavid du Colombier }
70993631029SDavid du Colombier iunlock(&p->rlock);
71093631029SDavid du Colombier }
71193631029SDavid du Colombier }
71293631029SDavid du Colombier
71393631029SDavid du Colombier /*
71493631029SDavid du Colombier * we save up input characters till clock time to reduce
71593631029SDavid du Colombier * per character interrupt overhead.
71693631029SDavid du Colombier */
71793631029SDavid du Colombier static void
uartclock(void)71893631029SDavid du Colombier uartclock(void)
71993631029SDavid du Colombier {
72093631029SDavid du Colombier Uart *p;
72193631029SDavid du Colombier
72293631029SDavid du Colombier ilock(&uartalloc);
72393631029SDavid du Colombier for(p = uartalloc.elist; p; p = p->elist){
72493631029SDavid du Colombier
72593631029SDavid du Colombier /* this hopefully amortizes cost of qproduce to many chars */
72693631029SDavid du Colombier if(p->iw != p->ir){
72793631029SDavid du Colombier ilock(&p->rlock);
72893631029SDavid du Colombier uartstageinput(p);
72993631029SDavid du Colombier iunlock(&p->rlock);
73093631029SDavid du Colombier }
73193631029SDavid du Colombier
73293631029SDavid du Colombier /* hang up if requested */
73393631029SDavid du Colombier if(p->dohup){
73493631029SDavid du Colombier qhangup(p->iq, 0);
73593631029SDavid du Colombier qhangup(p->oq, 0);
73693631029SDavid du Colombier p->dohup = 0;
73793631029SDavid du Colombier }
73893631029SDavid du Colombier
73993631029SDavid du Colombier /* this adds hysteresis to hardware/software flow control */
74093631029SDavid du Colombier if(p->ctsbackoff){
74193631029SDavid du Colombier ilock(&p->tlock);
74293631029SDavid du Colombier if(p->ctsbackoff){
74393631029SDavid du Colombier if(--(p->ctsbackoff) == 0)
74493631029SDavid du Colombier (*p->phys->kick)(p);
74593631029SDavid du Colombier }
74693631029SDavid du Colombier iunlock(&p->tlock);
74793631029SDavid du Colombier }
748bacfa46cSDavid du Colombier uartkick(p); /* keep it moving */
74993631029SDavid du Colombier }
75093631029SDavid du Colombier iunlock(&uartalloc);
75193631029SDavid du Colombier }
75293631029SDavid du Colombier
75393631029SDavid du Colombier /*
75493631029SDavid du Colombier * polling console input, output
75593631029SDavid du Colombier */
75693631029SDavid du Colombier
75793631029SDavid du Colombier Uart* consuart;
75893631029SDavid du Colombier
75993631029SDavid du Colombier int
uartgetc(void)76093631029SDavid du Colombier uartgetc(void)
76193631029SDavid du Colombier {
76293631029SDavid du Colombier if(consuart == nil || consuart->phys->getc == nil)
76393631029SDavid du Colombier return -1;
76493631029SDavid du Colombier return consuart->phys->getc(consuart);
76593631029SDavid du Colombier }
76693631029SDavid du Colombier
76793631029SDavid du Colombier void
uartputc(int c)76893631029SDavid du Colombier uartputc(int c)
76993631029SDavid du Colombier {
770*696c1e60SDavid du Colombier char c2;
771*696c1e60SDavid du Colombier
772*696c1e60SDavid du Colombier if(consuart == nil || consuart->phys->putc == nil) {
773*696c1e60SDavid du Colombier c2 = c;
774*696c1e60SDavid du Colombier if (lprint)
775*696c1e60SDavid du Colombier (*lprint)(&c2, 1);
77693631029SDavid du Colombier return;
777*696c1e60SDavid du Colombier }
77893631029SDavid du Colombier consuart->phys->putc(consuart, c);
77993631029SDavid du Colombier }
78093631029SDavid du Colombier
78193631029SDavid du Colombier void
uartputs(char * s,int n)78293631029SDavid du Colombier uartputs(char *s, int n)
78393631029SDavid du Colombier {
78493631029SDavid du Colombier char *e;
78593631029SDavid du Colombier
786*696c1e60SDavid du Colombier if(consuart == nil || consuart->phys->putc == nil) {
787*696c1e60SDavid du Colombier if (lprint)
788*696c1e60SDavid du Colombier (*lprint)(s, n);
78993631029SDavid du Colombier return;
790*696c1e60SDavid du Colombier }
79193631029SDavid du Colombier
79293631029SDavid du Colombier e = s+n;
79393631029SDavid du Colombier for(; s<e; s++){
79493631029SDavid du Colombier if(*s == '\n')
79593631029SDavid du Colombier consuart->phys->putc(consuart, '\r');
79693631029SDavid du Colombier consuart->phys->putc(consuart, *s);
79793631029SDavid du Colombier }
79893631029SDavid du Colombier }
799