root/kern/tty_subr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cinit
  2. clalloc
  3. clfree
  4. getc
  5. q_to_b
  6. ndqb
  7. ndflush
  8. putc
  9. clrbits
  10. b_to_q
  11. nextc
  12. firstc
  13. unputc
  14. catq

    1 /*      $OpenBSD: tty_subr.c,v 1.18 2005/12/21 12:43:49 jsg Exp $       */
    2 /*      $NetBSD: tty_subr.c,v 1.13 1996/02/09 19:00:43 christos Exp $   */
    3 
    4 /*
    5  * Copyright (c) 1993, 1994 Theo de Raadt
    6  * All rights reserved.
    7  *
    8  * Per Lindqvist <pgd@compuram.bbt.se> supplied an almost fully working
    9  * set of true clist functions that this is very loosely based on.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/buf.h>
   35 #include <sys/ioctl.h>
   36 #include <sys/tty.h>
   37 #include <sys/malloc.h>
   38 
   39 /*
   40  * If TTY_QUOTE functionality isn't required by a line discipline,
   41  * it can free c_cq and set it to NULL. This speeds things up,
   42  * and also does not use any extra memory. This is useful for (say)
   43  * a SLIP line discipline that wants a 32K ring buffer for data
   44  * but doesn't need quoting.
   45  */
   46 #define QMEM(n)         ((((n)-1)/NBBY)+1)
   47 
   48 void    cinit(void);
   49 void    clrbits(u_char *, int, int);
   50 
   51 /*
   52  * Initialize clists.
   53  */
   54 void
   55 cinit(void)
   56 {
   57 }
   58 
   59 /*
   60  * Initialize a particular clist. Ok, they are really ring buffers,
   61  * of the specified length, with/without quoting support.
   62  */
   63 int
   64 clalloc(struct clist *clp, int size, int quot)
   65 {
   66 
   67         clp->c_cs = malloc(size, M_TTYS, M_WAITOK);
   68         bzero(clp->c_cs, size);
   69 
   70         if (quot) {
   71                 clp->c_cq = malloc(QMEM(size), M_TTYS, M_WAITOK);
   72                 bzero(clp->c_cq, QMEM(size));
   73         } else
   74                 clp->c_cq = (u_char *)0;
   75 
   76         clp->c_cf = clp->c_cl = (u_char *)0;
   77         clp->c_ce = clp->c_cs + size;
   78         clp->c_cn = size;
   79         clp->c_cc = 0;
   80         return (0);
   81 }
   82 
   83 void
   84 clfree(struct clist *clp)
   85 {
   86         if (clp->c_cs) {
   87                 bzero(clp->c_cs, clp->c_cn);
   88                 free(clp->c_cs, M_TTYS);
   89         }
   90         if (clp->c_cq) {
   91                 bzero(clp->c_cq, QMEM(clp->c_cn));
   92                 free(clp->c_cq, M_TTYS);
   93         }
   94         clp->c_cs = clp->c_cq = (u_char *)0;
   95 }
   96 
   97 
   98 /*
   99  * Get a character from a clist.
  100  */
  101 int
  102 getc(struct clist *clp)
  103 {
  104         int c = -1;
  105         int s;
  106 
  107         s = spltty();
  108         if (clp->c_cc == 0)
  109                 goto out;
  110 
  111         c = *clp->c_cf & 0xff;
  112         if (clp->c_cq) {
  113                 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) )
  114                         c |= TTY_QUOTE;
  115         }
  116         if (++clp->c_cf == clp->c_ce)
  117                 clp->c_cf = clp->c_cs;
  118         if (--clp->c_cc == 0)
  119                 clp->c_cf = clp->c_cl = (u_char *)0;
  120 out:
  121         splx(s);
  122         return c;
  123 }
  124 
  125 /*
  126  * Copy clist to buffer.
  127  * Return number of bytes moved.
  128  */
  129 int
  130 q_to_b(struct clist *clp, u_char *cp, int count)
  131 {
  132         int cc;
  133         u_char *p = cp;
  134         int s;
  135 
  136         s = spltty();
  137         /* optimize this while loop */
  138         while (count > 0 && clp->c_cc > 0) {
  139                 cc = clp->c_cl - clp->c_cf;
  140                 if (clp->c_cf >= clp->c_cl)
  141                         cc = clp->c_ce - clp->c_cf;
  142                 if (cc > count)
  143                         cc = count;
  144                 bcopy(clp->c_cf, p, cc);
  145                 count -= cc;
  146                 p += cc;
  147                 clp->c_cc -= cc;
  148                 clp->c_cf += cc;
  149                 if (clp->c_cf == clp->c_ce)
  150                         clp->c_cf = clp->c_cs;
  151         }
  152         if (clp->c_cc == 0)
  153                 clp->c_cf = clp->c_cl = (u_char *)0;
  154         splx(s);
  155         return p - cp;
  156 }
  157 
  158 /*
  159  * Return count of contiguous characters in clist.
  160  * Stop counting if flag&character is non-null.
  161  */
  162 int
  163 ndqb(struct clist *clp, int flag)
  164 {
  165         int count = 0;
  166         int i;
  167         int cc;
  168         int s;
  169 
  170         s = spltty();
  171         if ((cc = clp->c_cc) == 0)
  172                 goto out;
  173 
  174         if (flag == 0) {
  175                 count = clp->c_cl - clp->c_cf;
  176                 if (count <= 0)
  177                         count = clp->c_ce - clp->c_cf;
  178                 goto out;
  179         }
  180 
  181         i = clp->c_cf - clp->c_cs;
  182         if (flag & TTY_QUOTE) {
  183                 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
  184                     isset(clp->c_cq, i))) {
  185                         count++;
  186                         if (i == clp->c_cn)
  187                                 break;
  188                 }
  189         } else {
  190                 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
  191                         count++;
  192                         if (i == clp->c_cn)
  193                                 break;
  194                 }
  195         }
  196 out:
  197         splx(s);
  198         return count;
  199 }
  200 
  201 /*
  202  * Flush count bytes from clist.
  203  */
  204 void
  205 ndflush(struct clist *clp, int count)
  206 {
  207         int cc;
  208         int s;
  209 
  210         s = spltty();
  211         if (count == clp->c_cc) {
  212                 clp->c_cc = 0;
  213                 clp->c_cf = clp->c_cl = (u_char *)0;
  214                 goto out;
  215         }
  216         /* optimize this while loop */
  217         while (count > 0 && clp->c_cc > 0) {
  218                 cc = clp->c_cl - clp->c_cf;
  219                 if (clp->c_cf >= clp->c_cl)
  220                         cc = clp->c_ce - clp->c_cf;
  221                 if (cc > count)
  222                         cc = count;
  223                 count -= cc;
  224                 clp->c_cc -= cc;
  225                 clp->c_cf += cc;
  226                 if (clp->c_cf == clp->c_ce)
  227                         clp->c_cf = clp->c_cs;
  228         }
  229         if (clp->c_cc == 0)
  230                 clp->c_cf = clp->c_cl = (u_char *)0;
  231 out:
  232         splx(s);
  233 }
  234 
  235 /*
  236  * Put a character into the output queue.
  237  */
  238 int
  239 putc(int c, struct clist *clp)
  240 {
  241         int i;
  242         int s;
  243 
  244         s = spltty();
  245         if (clp->c_cc == clp->c_cn)
  246                 goto out;
  247 
  248         if (clp->c_cc == 0) {
  249                 if (!clp->c_cs) {
  250 #if defined(DIAGNOSTIC) || 1
  251                         printf("putc: required clalloc\n");
  252 #endif
  253                         if (clalloc(clp, 1024, 1)) {
  254 out:
  255                                 splx(s);
  256                                 return -1;
  257                         }
  258                 }
  259                 clp->c_cf = clp->c_cl = clp->c_cs;
  260         }
  261 
  262         *clp->c_cl = c & 0xff;
  263         i = clp->c_cl - clp->c_cs;
  264         if (clp->c_cq) {
  265                 if (c & TTY_QUOTE)
  266                         setbit(clp->c_cq, i);
  267                 else
  268                         clrbit(clp->c_cq, i);
  269         }
  270         clp->c_cc++;
  271         clp->c_cl++;
  272         if (clp->c_cl == clp->c_ce)
  273                 clp->c_cl = clp->c_cs;
  274         splx(s);
  275         return 0;
  276 }
  277 
  278 /*
  279  * optimized version of
  280  *
  281  * for (i = 0; i < len; i++)
  282  *      clrbit(cp, off + len);
  283  */
  284 void
  285 clrbits(u_char *cp, int off, int len)
  286 {
  287         int sby, sbi, eby, ebi;
  288         int i;
  289         u_char mask;
  290 
  291         if (len==1) {
  292                 clrbit(cp, off);
  293                 return;
  294         }
  295 
  296         sby = off / NBBY;
  297         sbi = off % NBBY;
  298         eby = (off+len) / NBBY;
  299         ebi = (off+len) % NBBY;
  300         if (sby == eby) {
  301                 mask = ((1 << (ebi - sbi)) - 1) << sbi;
  302                 cp[sby] &= ~mask;
  303         } else {
  304                 mask = (1<<sbi) - 1;
  305                 cp[sby++] &= mask;
  306 
  307                 mask = (1<<ebi) - 1;
  308                 cp[eby] &= ~mask;
  309 
  310                 for (i = sby; i < eby; i++)
  311                         cp[i] = 0x00;
  312         }
  313 }
  314 
  315 /*
  316  * Copy buffer to clist.
  317  * Return number of bytes not transferred.
  318  */
  319 int
  320 b_to_q(u_char *cp, int count, struct clist *clp)
  321 {
  322         int cc;
  323         u_char *p = cp;
  324         int s;
  325 
  326         if (count <= 0)
  327                 return 0;
  328 
  329         s = spltty();
  330         if (clp->c_cc == clp->c_cn)
  331                 goto out;
  332 
  333         if (clp->c_cc == 0) {
  334                 if (!clp->c_cs) {
  335 #if defined(DIAGNOSTIC) || 1
  336                         printf("b_to_q: required clalloc\n");
  337 #endif
  338                         if (clalloc(clp, 1024, 1))
  339                                 goto out;
  340                 }
  341                 clp->c_cf = clp->c_cl = clp->c_cs;
  342         }
  343 
  344         /* optimize this while loop */
  345         while (count > 0 && clp->c_cc < clp->c_cn) {
  346                 cc = clp->c_ce - clp->c_cl;
  347                 if (clp->c_cf > clp->c_cl)
  348                         cc = clp->c_cf - clp->c_cl;
  349                 if (cc > count)
  350                         cc = count;
  351                 bcopy(p, clp->c_cl, cc);
  352                 if (clp->c_cq) {
  353                         clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
  354                 }
  355                 p += cc;
  356                 count -= cc;
  357                 clp->c_cc += cc;
  358                 clp->c_cl += cc;
  359                 if (clp->c_cl == clp->c_ce)
  360                         clp->c_cl = clp->c_cs;
  361         }
  362 out:
  363         splx(s);
  364         return count;
  365 }
  366 
  367 static int cc;
  368 
  369 /*
  370  * Given a non-NULL pointer into the clist return the pointer
  371  * to the next character in the list or return NULL if no more chars.
  372  *
  373  * Callers must not allow getc's to happen between firstc's and getc's
  374  * so that the pointer becomes invalid.  Note that interrupts are NOT
  375  * masked.
  376  */
  377 u_char *
  378 nextc(struct clist *clp, u_char *cp, int *c)
  379 {
  380 
  381         if (clp->c_cf == cp) {
  382                 /*
  383                  * First time initialization.
  384                  */
  385                 cc = clp->c_cc;
  386         }
  387         if (cc == 0 || cp == NULL)
  388                 return NULL;
  389         if (--cc == 0)
  390                 return NULL;
  391         if (++cp == clp->c_ce)
  392                 cp = clp->c_cs;
  393         *c = *cp & 0xff;
  394         if (clp->c_cq) {
  395                 if (isset(clp->c_cq, cp - clp->c_cs))
  396                         *c |= TTY_QUOTE;
  397         }
  398         return cp;
  399 }
  400 
  401 /*
  402  * Given a non-NULL pointer into the clist return the pointer
  403  * to the first character in the list or return NULL if no more chars.
  404  *
  405  * Callers must not allow getc's to happen between firstc's and getc's
  406  * so that the pointer becomes invalid.  Note that interrupts are NOT
  407  * masked.
  408  *
  409  * *c is set to the NEXT character
  410  */
  411 u_char *
  412 firstc(struct clist *clp, int *c)
  413 {
  414         u_char *cp;
  415 
  416         cc = clp->c_cc;
  417         if (cc == 0)
  418                 return NULL;
  419         cp = clp->c_cf;
  420         *c = *cp & 0xff;
  421         if (clp->c_cq) {
  422                 if (isset(clp->c_cq, cp - clp->c_cs))
  423                         *c |= TTY_QUOTE;
  424         }
  425         return clp->c_cf;
  426 }
  427 
  428 /*
  429  * Remove the last character in the clist and return it.
  430  */
  431 int
  432 unputc(struct clist *clp)
  433 {
  434         unsigned int c = -1;
  435         int s;
  436 
  437         s = spltty();
  438         if (clp->c_cc == 0)
  439                 goto out;
  440 
  441         if (clp->c_cl == clp->c_cs)
  442                 clp->c_cl = clp->c_ce - 1;
  443         else
  444                 --clp->c_cl;
  445         clp->c_cc--;
  446 
  447         c = *clp->c_cl & 0xff;
  448         if (clp->c_cq) {
  449                 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
  450                         c |= TTY_QUOTE;
  451         }
  452         if (clp->c_cc == 0)
  453                 clp->c_cf = clp->c_cl = (u_char *)0;
  454 out:
  455         splx(s);
  456         return c;
  457 }
  458 
  459 /*
  460  * Put the chars in the from queue on the end of the to queue.
  461  */
  462 void
  463 catq(struct clist *from, struct clist *to)
  464 {
  465         int c;
  466         int s;
  467 
  468         s = spltty();
  469         if (from->c_cc == 0) {  /* nothing to move */
  470                 splx(s);
  471                 return;
  472         }
  473 
  474         /*
  475          * if `to' queue is empty and the queues are the same max size,
  476          * it is more efficient to just swap the clist structures.
  477          */
  478         if (to->c_cc == 0 && from->c_cn == to->c_cn) {
  479                 struct clist tmp;
  480 
  481                 tmp = *from;
  482                 *from = *to;
  483                 *to = tmp;
  484                 splx(s);
  485                 return;
  486         }
  487         splx(s);
  488 
  489         while ((c = getc(from)) != -1)
  490                 putc(c, to);
  491 }

/* [<][>][^][v][top][bottom][index][help] */