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