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