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