The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devuart.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: a360403e85b41c865e76c90be4e2d476


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.