]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/devuart.c
merge
[plan9front.git] / sys / src / 9 / omap / devuart.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "io.h"
7 #include        "../port/error.h"
8
9 #include        "../port/netif.h"
10
11 enum
12 {
13         /* soft flow control chars */
14         CTLS= 023,
15         CTLQ= 021,
16 };
17
18 extern Dev uartdevtab;
19 extern PhysUart* physuart[];
20
21 static Uart* uartlist;
22 static Uart** uart;
23 static int uartnuart;
24 static Dirtab *uartdir;
25 static int uartndir;
26 static Timer *uarttimer;
27
28 struct Uartalloc {
29         Lock;
30         Uart *elist;    /* list of enabled interfaces */
31 } uartalloc;
32
33 static void     uartclock(void);
34 static void     uartflow(void*);
35
36 /*
37  *  enable/disable uart and add/remove to list of enabled uarts
38  */
39 //static
40 Uart*
41 uartenable(Uart *p)
42 {
43         Uart **l;
44
45         if (up == nil)
46                 return p;               /* too soon; try again later */
47 //              return nil;
48
49         if(p->iq == nil){
50                 if((p->iq = qopen(8*1024, Qcoalesce, uartflow, p)) == nil)
51                         return nil;
52         }
53         else
54                 qreopen(p->iq);
55         if(p->oq == nil){
56                 if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
57                         qfree(p->iq);
58                         p->iq = nil;
59                         return nil;
60                 }
61         }
62         else
63                 qreopen(p->oq);
64
65         p->ir = p->istage;
66         p->iw = p->istage;
67         p->ie = &p->istage[Stagesize];
68         p->op = p->ostage;
69         p->oe = p->ostage;
70
71         p->hup_dsr = p->hup_dcd = 0;
72         p->dsr = p->dcd = 0;
73
74         /* assume we can send */
75         p->cts = 1;
76         p->ctsbackoff = 0;
77
78 if (up) {
79         if(p->bits == 0)
80                 uartctl(p, "l8");
81         if(p->stop == 0)
82                 uartctl(p, "s1");
83         if(p->parity == 0)
84                 uartctl(p, "pn");
85         if(p->baud == 0)
86                 uartctl(p, "b9600");
87         (*p->phys->enable)(p, 1);
88 }
89
90         /*
91          * use ilock because uartclock can otherwise interrupt here
92          * and would hang on an attempt to lock uartalloc.
93          */
94         ilock(&uartalloc);
95         for(l = &uartalloc.elist; *l; l = &(*l)->elist){
96                 if(*l == p)
97                         break;
98         }
99         if(*l == 0){
100                 p->elist = uartalloc.elist;
101                 uartalloc.elist = p;
102         }
103         p->enabled = 1;
104         iunlock(&uartalloc);
105
106         return p;
107 }
108
109 static void
110 uartdisable(Uart *p)
111 {
112         Uart **l;
113
114         (*p->phys->disable)(p);
115
116         ilock(&uartalloc);
117         for(l = &uartalloc.elist; *l; l = &(*l)->elist){
118                 if(*l == p){
119                         *l = p->elist;
120                         break;
121                 }
122         }
123         p->enabled = 0;
124         iunlock(&uartalloc);
125 }
126
127 static void
128 setlength(int i)
129 {
130         Uart *p;
131
132         if(i > 0){
133                 p = uart[i];
134                 if(p && p->opens && p->iq)
135                         uartdir[1+3*i].length = qlen(p->iq);
136         } else for(i = 0; i < uartnuart; i++){
137                 p = uart[i];
138                 if(p && p->opens && p->iq)
139                         uartdir[1+3*i].length = qlen(p->iq);
140         }
141 }
142
143 /*
144  *  set up the '#t' directory
145  */
146 static void
147 uartreset(void)
148 {
149         int i;
150         Dirtab *dp;
151         Uart *p, *tail;
152
153         tail = nil;
154         for(i = 0; physuart[i] != nil; i++){
155                 if(physuart[i]->pnp == nil)
156                         continue;
157                 if((p = physuart[i]->pnp()) == nil)
158                         continue;
159                 if(uartlist != nil)
160                         tail->next = p;
161                 else
162                         uartlist = p;
163                 for(tail = p; tail->next != nil; tail = tail->next)
164                         uartnuart++;
165                 uartnuart++;
166         }
167
168         if(uartnuart)
169                 uart = xalloc(uartnuart*sizeof(Uart*));
170
171         uartndir = 1 + 3*uartnuart;
172         uartdir = xalloc(uartndir * sizeof(Dirtab));
173         if (uart == nil || uartdir == nil)
174                 panic("uartreset: no memory");
175         dp = uartdir;
176         strcpy(dp->name, ".");
177         mkqid(&dp->qid, 0, 0, QTDIR);
178         dp->length = 0;
179         dp->perm = DMDIR|0555;
180         dp++;
181         p = uartlist;
182         for(i = 0; i < uartnuart; i++){
183                 /* 3 directory entries per port */
184                 snprint(dp->name, sizeof dp->name, "eia%d", i);
185                 dp->qid.path = NETQID(i, Ndataqid);
186                 dp->perm = 0660;
187                 dp++;
188                 snprint(dp->name, sizeof dp->name, "eia%dctl", i);
189                 dp->qid.path = NETQID(i, Nctlqid);
190                 dp->perm = 0660;
191                 dp++;
192                 snprint(dp->name, sizeof dp->name, "eia%dstatus", i);
193                 dp->qid.path = NETQID(i, Nstatqid);
194                 dp->perm = 0444;
195                 dp++;
196
197                 uart[i] = p;
198                 p->dev = i;
199                 if(p->console || p->special){
200                         if(uartenable(p) != nil){
201                                 if(p->console && up)
202                                         serialoq = p->oq;
203                                 p->opens++;
204                         }
205                 }
206                 p = p->next;
207         }
208
209         if(uartnuart){
210                 /*
211                  * at 115200 baud, the 1024 char buffer takes 56 ms to process,
212                  * processing it every 22 ms should be fine.
213                  */
214                 uarttimer = addclock0link(uartclock, 22);
215         }
216 }
217
218
219 static Chan*
220 uartattach(char *spec)
221 {
222         return devattach('t', spec);
223 }
224
225 static Walkqid*
226 uartwalk(Chan *c, Chan *nc, char **name, int nname)
227 {
228         return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
229 }
230
231 static int
232 uartstat(Chan *c, uchar *dp, int n)
233 {
234         if(NETTYPE(c->qid.path) == Ndataqid)
235                 setlength(NETID(c->qid.path));
236         return devstat(c, dp, n, uartdir, uartndir, devgen);
237 }
238
239 static Chan*
240 uartopen(Chan *c, int omode)
241 {
242         Uart *p;
243
244         c = devopen(c, omode, uartdir, uartndir, devgen);
245
246         switch(NETTYPE(c->qid.path)){
247         case Nctlqid:
248         case Ndataqid:
249                 p = uart[NETID(c->qid.path)];
250                 qlock(p);
251                 if(p->opens++ == 0 && uartenable(p) == nil){
252                         qunlock(p);
253                         c->flag &= ~COPEN;
254                         error(Enodev);
255                 }
256                 qunlock(p);
257                 break;
258         }
259
260         c->iounit = qiomaxatomic;
261         return c;
262 }
263
264 static int
265 uartdrained(void* arg)
266 {
267         Uart *p;
268
269         p = arg;
270         return qlen(p->oq) == 0 && p->op == p->oe;
271 }
272
273 static void
274 uartdrainoutput(Uart *p)
275 {
276         if(!p->enabled || up == nil)
277                 return;
278
279         p->drain = 1;
280         if(waserror()){
281                 p->drain = 0;
282                 nexterror();
283         }
284         sleep(&p->r, uartdrained, p);
285         poperror();
286 }
287
288 static void
289 uartclose(Chan *c)
290 {
291         Uart *p;
292
293         if(c->qid.type & QTDIR)
294                 return;
295         if((c->flag & COPEN) == 0)
296                 return;
297         switch(NETTYPE(c->qid.path)){
298         case Ndataqid:
299         case Nctlqid:
300                 p = uart[NETID(c->qid.path)];
301                 qlock(p);
302                 if(--(p->opens) == 0){
303                         qclose(p->iq);
304                         ilock(&p->rlock);
305                         p->ir = p->iw = p->istage;
306                         iunlock(&p->rlock);
307
308                         /*
309                          */
310                         qhangup(p->oq, nil);
311                         if(!waserror()){
312                                 uartdrainoutput(p);
313                                 poperror();
314                         }
315                         qclose(p->oq);
316                         uartdisable(p);
317                         p->dcd = p->dsr = p->dohup = 0;
318                 }
319                 qunlock(p);
320                 break;
321         }
322 }
323
324 static long
325 uartread(Chan *c, void *buf, long n, vlong off)
326 {
327         Uart *p;
328         ulong offset = off;
329
330         if(c->qid.type & QTDIR){
331                 setlength(-1);
332                 return devdirread(c, buf, n, uartdir, uartndir, devgen);
333         }
334
335         p = uart[NETID(c->qid.path)];
336         switch(NETTYPE(c->qid.path)){
337         case Ndataqid:
338                 return qread(p->iq, buf, n);
339         case Nctlqid:
340                 return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
341         case Nstatqid:
342                 return (*p->phys->status)(p, buf, n, offset);
343         }
344
345         return 0;
346 }
347
348 int
349 uartctl(Uart *p, char *cmd)
350 {
351         char *f[16];
352         int i, n, nf;
353
354         nf = tokenize(cmd, f, nelem(f));
355         for(i = 0; i < nf; i++){
356                 if(strncmp(f[i], "break", 5) == 0){
357                         (*p->phys->dobreak)(p, 0);
358                         continue;
359                 }
360
361                 n = atoi(f[i]+1);
362                 switch(*f[i]){
363                 case 'B':
364                 case 'b':
365                         uartdrainoutput(p);
366                         if((*p->phys->baud)(p, n) < 0)
367                                 return -1;
368                         break;
369                 case 'C':
370                 case 'c':
371                         p->hup_dcd = n;
372                         break;
373                 case 'D':
374                 case 'd':
375                         uartdrainoutput(p);
376                         (*p->phys->dtr)(p, n);
377                         break;
378                 case 'E':
379                 case 'e':
380                         p->hup_dsr = n;
381                         break;
382                 case 'f':
383                 case 'F':
384                         if(p->oq != nil)
385                                 qflush(p->oq);
386                         break;
387                 case 'H':
388                 case 'h':
389                         if(p->iq != nil)
390                                 qhangup(p->iq, 0);
391                         if(p->oq != nil)
392                                 qhangup(p->oq, 0);
393                         break;
394                 case 'i':
395                 case 'I':
396                         uartdrainoutput(p);
397                         (*p->phys->fifo)(p, n);
398                         break;
399                 case 'K':
400                 case 'k':
401                         uartdrainoutput(p);
402                         (*p->phys->dobreak)(p, n);
403                         break;
404                 case 'L':
405                 case 'l':
406                         uartdrainoutput(p);
407                         if((*p->phys->bits)(p, n) < 0)
408                                 return -1;
409                         break;
410                 case 'm':
411                 case 'M':
412                         uartdrainoutput(p);
413                         (*p->phys->modemctl)(p, n);
414                         break;
415                 case 'n':
416                 case 'N':
417                         if(p->oq != nil)
418                                 qnoblock(p->oq, n);
419                         break;
420                 case 'P':
421                 case 'p':
422                         uartdrainoutput(p);
423                         if((*p->phys->parity)(p, *(f[i]+1)) < 0)
424                                 return -1;
425                         break;
426                 case 'Q':
427                 case 'q':
428                         if(p->iq != nil)
429                                 qsetlimit(p->iq, n);
430                         if(p->oq != nil)
431                                 qsetlimit(p->oq, n);
432                         break;
433                 case 'R':
434                 case 'r':
435                         uartdrainoutput(p);
436                         (*p->phys->rts)(p, n);
437                         break;
438                 case 'S':
439                 case 's':
440                         uartdrainoutput(p);
441                         if((*p->phys->stop)(p, n) < 0)
442                                 return -1;
443                         break;
444                 case 'W':
445                 case 'w':
446                         if(uarttimer == nil || n < 1)
447                                 return -1;
448                         uarttimer->tns = (vlong)n * 100000LL;
449                         break;
450                 case 'X':
451                 case 'x':
452                         if(p->enabled){
453                                 ilock(&p->tlock);
454                                 p->xonoff = n;
455                                 iunlock(&p->tlock);
456                         }
457                         break;
458                 }
459         }
460         return 0;
461 }
462
463 static long
464 uartwrite(Chan *c, void *buf, long n, vlong)
465 {
466         Uart *p;
467         char *cmd;
468
469         if(c->qid.type & QTDIR)
470                 error(Eperm);
471
472         p = uart[NETID(c->qid.path)];
473
474         switch(NETTYPE(c->qid.path)){
475         case Ndataqid:
476                 qlock(p);
477                 if(waserror()){
478                         qunlock(p);
479                         nexterror();
480                 }
481
482                 n = qwrite(p->oq, buf, n);
483
484                 qunlock(p);
485                 poperror();
486                 break;
487         case Nctlqid:
488                 cmd = malloc(n+1);
489                 memmove(cmd, buf, n);
490                 cmd[n] = 0;
491                 qlock(p);
492                 if(waserror()){
493                         qunlock(p);
494                         free(cmd);
495                         nexterror();
496                 }
497
498                 /* let output drain */
499                 if(uartctl(p, cmd) < 0)
500                         error(Ebadarg);
501
502                 qunlock(p);
503                 poperror();
504                 free(cmd);
505                 break;
506         }
507
508         return n;
509 }
510
511 static int
512 uartwstat(Chan *c, uchar *dp, int n)
513 {
514         Dir d;
515         Dirtab *dt;
516
517         if(!iseve())
518                 error(Eperm);
519         if(QTDIR & c->qid.type)
520                 error(Eperm);
521         if(NETTYPE(c->qid.path) == Nstatqid)
522                 error(Eperm);
523
524         dt = &uartdir[1 + 3 * NETID(c->qid.path)];
525         n = convM2D(dp, n, &d, nil);
526         if(n == 0)
527                 error(Eshortstat);
528         if(d.mode != ~0UL)
529                 dt[0].perm = dt[1].perm = d.mode;
530         return n;
531 }
532
533 void
534 uartpower(int on)
535 {
536         Uart *p;
537
538         for(p = uartlist; p != nil; p = p->next) {
539                 if(p->phys->power)
540                         (*p->phys->power)(p, on);
541         }
542 }
543
544 Dev uartdevtab = {
545         't',
546         "uart",
547
548         uartreset,
549         devinit,
550         devshutdown,
551         uartattach,
552         uartwalk,
553         uartstat,
554         uartopen,
555         devcreate,
556         uartclose,
557         uartread,
558         devbread,
559         uartwrite,
560         devbwrite,
561         devremove,
562         uartwstat,
563         uartpower,
564 };
565
566 /*
567  *  restart input if it's off
568  */
569 static void
570 uartflow(void *v)
571 {
572         Uart *p;
573
574         p = v;
575         if(p->modem)
576                 (*p->phys->rts)(p, 1);
577 }
578
579 /*
580  *  put some bytes into the local queue to avoid calling
581  *  qconsume for every character
582  */
583 int
584 uartstageoutput(Uart *p)
585 {
586         int n;
587
588         n = qconsume(p->oq, p->ostage, Stagesize);
589         if(n <= 0)
590 //              n = 0;                  /* experiment */
591                 return 0;
592         p->op = p->ostage;
593         p->oe = p->ostage + n;
594         return n;
595 }
596
597 /*
598  *  restart output
599  */
600 void
601 uartkick(void *v)
602 {
603         Uart *p = v;
604
605         if(p->blocked)
606                 return;
607
608         ilock(&p->tlock);
609         (*p->phys->kick)(p);
610         iunlock(&p->tlock);
611
612         if(p->drain && uartdrained(p)){
613                 p->drain = 0;
614                 wakeup(&p->r);
615         }
616 }
617
618 /*
619  * Move data from the interrupt staging area to
620  * the input Queue.
621  */
622 static void
623 uartstageinput(Uart *p)
624 {
625         int n;
626         uchar *ir, *iw;
627
628         while(p->ir != p->iw){
629                 ir = p->ir;
630                 if(p->ir > p->iw){
631                         iw = p->ie;
632                         p->ir = p->istage;
633                 }
634                 else{
635                         iw = p->iw;
636                         p->ir = p->iw;
637                 }
638                 if((n = qproduce(p->iq, ir, iw - ir)) < 0){
639                         p->serr++;
640                         (*p->phys->rts)(p, 0);
641                 }
642                 else if(n == 0)
643                         p->berr++;
644         }
645 }
646
647 /*
648  *  receive a character at interrupt time
649  */
650 void
651 uartrecv(Uart *p,  char ch)
652 {
653         uchar *next;
654
655         /* software flow control */
656         if(p->xonoff){
657                 if(ch == CTLS){
658                         p->blocked = 1;
659                 }else if(ch == CTLQ){
660                         p->blocked = 0;
661                         p->ctsbackoff = 2; /* clock gets output going again */
662                 }
663         }
664
665         /* receive the character */
666         if(p->putc)
667                 p->putc(p->iq, ch);
668         else if (p->iw) {               /* maybe the line isn't enabled yet */
669                 ilock(&p->rlock);
670                 next = p->iw + 1;
671                 if(next == p->ie)
672                         next = p->istage;
673                 if(next == p->ir)
674                         uartstageinput(p);
675                 if(next != p->ir){
676                         *p->iw = ch;
677                         p->iw = next;
678                 }
679                 iunlock(&p->rlock);
680         }
681 }
682
683 /*
684  *  we save up input characters till clock time to reduce
685  *  per character interrupt overhead.
686  */
687 static void
688 uartclock(void)
689 {
690         Uart *p;
691
692         ilock(&uartalloc);
693         for(p = uartalloc.elist; p; p = p->elist){
694
695                 /* this hopefully amortizes cost of qproduce to many chars */
696                 if(p->iw != p->ir){
697                         ilock(&p->rlock);
698                         uartstageinput(p);
699                         iunlock(&p->rlock);
700                 }
701
702                 /* hang up if requested */
703                 if(p->dohup){
704                         qhangup(p->iq, 0);
705                         qhangup(p->oq, 0);
706                         p->dohup = 0;
707                 }
708
709                 /* this adds hysteresis to hardware/software flow control */
710                 if(p->ctsbackoff){
711                         ilock(&p->tlock);
712                         if(p->ctsbackoff){
713                                 if(--(p->ctsbackoff) == 0)
714                                         (*p->phys->kick)(p);
715                         }
716                         iunlock(&p->tlock);
717                 }
718                 uartkick(p);            /* keep it moving */
719         }
720         iunlock(&uartalloc);
721 }
722
723 /*
724  * polling console input, output
725  */
726
727 Uart* consuart;
728
729 int
730 uartgetc(void)
731 {
732         if(consuart == nil || consuart->phys->getc == nil)
733                 return -1;
734         return consuart->phys->getc(consuart);
735 }
736
737 void
738 uartputc(int c)
739 {
740         if(consuart == nil || consuart->phys->putc == nil)
741                 return;
742         consuart->phys->putc(consuart, c);
743 }
744
745 void
746 uartputs(char *s, int n)
747 {
748         char *e;
749
750         if(consuart == nil || consuart->phys->putc == nil)
751                 return;
752
753         e = s+n;
754         for(; s<e; s++){
755                 if(*s == '\n')
756                         consuart->phys->putc(consuart, '\r');
757                 consuart->phys->putc(consuart, *s);
758         }
759 }