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/dev/syscons/schistory.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 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
    5  * Copyright (c) 1992-1998 Søren Schmidt
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer,
   13  *    without modification, immediately at the beginning of the file.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. The name of the author may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include "opt_syscons.h"
   36 
   37 #ifndef SC_NO_HISTORY
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/conf.h>
   42 #include <sys/consio.h>
   43 #include <sys/tty.h>
   44 #include <sys/kernel.h>
   45 #include <sys/malloc.h>
   46 
   47 #if defined(__arm__) || defined(__mips__) || defined(__powerpc__)
   48 #include <machine/sc_machdep.h>
   49 #else
   50 #include <machine/pc/display.h>
   51 #endif
   52 
   53 #include <dev/syscons/syscons.h>
   54 
   55 /*
   56  * XXX Placeholder.
   57  * This calculations should be dynamically scaled by number of separate sc
   58  * devices.  A base value of 'extra_history_size' should be defined for
   59  * each syscons unit, and added and subtracted from the dynamic
   60  * 'extra_history_size' as units are added and removed.  This way, each time
   61  * a new syscons unit goes online, extra_history_size is automatically bumped.
   62  */
   63 #define MAXSC   1
   64 
   65 #if !defined(SC_MAX_HISTORY_SIZE)
   66 #define SC_MAX_HISTORY_SIZE     (1000 * MAXCONS * MAXSC)
   67 #endif
   68 
   69 #if !defined(SC_HISTORY_SIZE)
   70 #define SC_HISTORY_SIZE         (ROW * 4)
   71 #endif
   72 
   73 #if (SC_HISTORY_SIZE * MAXCONS * MAXSC) > SC_MAX_HISTORY_SIZE
   74 #undef SC_MAX_HISTORY_SIZE
   75 #define SC_MAX_HISTORY_SIZE     (SC_HISTORY_SIZE * MAXCONS * MAXSC)
   76 #endif
   77 
   78 /* local variables */
   79 static int              extra_history_size
   80                                 = SC_MAX_HISTORY_SIZE - SC_HISTORY_SIZE*MAXCONS;
   81 
   82 /* local functions */
   83 static void copy_history(sc_vtb_t *from, sc_vtb_t *to);
   84 static void history_to_screen(scr_stat *scp);
   85 
   86 /* allocate a history buffer */
   87 int
   88 sc_alloc_history_buffer(scr_stat *scp, int lines, int prev_ysize, int wait)
   89 {
   90         /*
   91          * syscons unconditionally allocates buffers up to 
   92          * SC_HISTORY_SIZE lines or scp->ysize lines, whichever 
   93          * is larger. A value greater than that is allowed, 
   94          * subject to extra_history_size.
   95          */
   96         sc_vtb_t *history;
   97         sc_vtb_t *prev_history;
   98         int cur_lines;                          /* current buffer size */
   99         int min_lines;                          /* guaranteed buffer size */
  100         int delta;                              /* lines to put back */
  101 
  102         if (lines <= 0)
  103                 lines = SC_HISTORY_SIZE;        /* use the default value */
  104 
  105         /* make it at least as large as the screen size */
  106         lines = imax(lines, scp->ysize);
  107 
  108         /* remove the history buffer while we update it */
  109         history = prev_history = scp->history;
  110         scp->history = NULL;
  111 
  112         /* calculate the amount of lines to put back to extra_history_size */
  113         delta = 0;
  114         if (prev_history) {
  115                 cur_lines = sc_vtb_rows(history);
  116                 min_lines = imax(SC_HISTORY_SIZE, prev_ysize);
  117                 if (cur_lines > min_lines)
  118                         delta = cur_lines - min_lines;
  119         }
  120 
  121         /* lines up to min_lines are always allowed. */
  122         min_lines = imax(SC_HISTORY_SIZE, scp->ysize);
  123         if (lines > min_lines) {
  124                 if (lines - min_lines > extra_history_size + delta) {
  125                         /* too many lines are requested */
  126                         scp->history = prev_history;
  127                         return EINVAL;
  128                 }
  129         }
  130 
  131         /* allocate a new buffer */
  132         history = (sc_vtb_t *)malloc(sizeof(*history),
  133                                      M_DEVBUF,
  134                                      (wait) ? M_WAITOK : M_NOWAIT);
  135         if (history != NULL) {
  136                 if (lines > min_lines)
  137                         extra_history_size -= lines - min_lines;
  138                 /* XXX error check? */
  139                 sc_vtb_init(history, VTB_RINGBUFFER, scp->xsize, lines,
  140                             NULL, wait);
  141                 /* FIXME: XXX no good? */
  142                 sc_vtb_clear(history, scp->sc->scr_map[0x20],
  143                              SC_NORM_ATTR << 8);
  144                 if (prev_history != NULL)
  145                         copy_history(prev_history, history);
  146                 scp->history_pos = sc_vtb_tail(history);
  147         } else {
  148                 scp->history_pos = 0;
  149         }
  150 
  151         /* destroy the previous buffer */
  152         if (prev_history != NULL) {
  153                 extra_history_size += delta;
  154                 sc_vtb_destroy(prev_history);
  155                 free(prev_history, M_DEVBUF);
  156         }
  157 
  158         scp->history = history;
  159 
  160         return 0;
  161 }
  162 
  163 static void
  164 copy_history(sc_vtb_t *from, sc_vtb_t *to)
  165 {
  166         int lines;
  167         int cols;
  168         int cols1;
  169         int cols2;
  170         int pos;
  171         int i;
  172 
  173         lines = sc_vtb_rows(from);
  174         cols1 = sc_vtb_cols(from);
  175         cols2 = sc_vtb_cols(to);
  176         cols = imin(cols1, cols2);
  177         pos = sc_vtb_tail(from);
  178         for (i = 0; i < lines; ++i) {
  179                 sc_vtb_append(from, pos, to, cols);
  180                 if (cols < cols2)
  181                         sc_vtb_seek(to, sc_vtb_pos(to, 
  182                                                    sc_vtb_tail(to), 
  183                                                    cols2 - cols));
  184                 pos = sc_vtb_pos(from, pos, cols1);
  185         }
  186 }
  187 
  188 void
  189 sc_free_history_buffer(scr_stat *scp, int prev_ysize)
  190 {
  191         sc_vtb_t *history;
  192         int cur_lines;                          /* current buffer size */
  193         int min_lines;                          /* guaranteed buffer size */
  194 
  195         history = scp->history;
  196         scp->history = NULL;
  197         if (history == NULL)
  198                 return;
  199 
  200         cur_lines = sc_vtb_rows(history);
  201         min_lines = imax(SC_HISTORY_SIZE, prev_ysize);
  202         extra_history_size += (cur_lines > min_lines) ? 
  203                                   cur_lines - min_lines : 0;
  204 
  205         sc_vtb_destroy(history);
  206         free(history, M_DEVBUF);
  207 }
  208 
  209 /* copy entire screen into the top of the history buffer */
  210 void
  211 sc_hist_save(scr_stat *scp)
  212 {
  213         sc_vtb_append(&scp->vtb, 0, scp->history, scp->xsize*scp->ysize);
  214         scp->history_pos = sc_vtb_tail(scp->history);
  215 }
  216 
  217 /* restore the screen by copying from the history buffer */
  218 int
  219 sc_hist_restore(scr_stat *scp)
  220 {
  221         int ret;
  222 
  223         if (scp->history_pos != sc_vtb_tail(scp->history)) {
  224                 scp->history_pos = sc_vtb_tail(scp->history);
  225                 history_to_screen(scp);
  226                 ret =  0;
  227         } else {
  228                 ret = 1;
  229         }
  230         sc_vtb_seek(scp->history, sc_vtb_pos(scp->history, 
  231                                              sc_vtb_tail(scp->history),
  232                                              -scp->xsize*scp->ysize));
  233         return ret;
  234 }
  235 
  236 /* copy screen-full of saved lines */
  237 static void
  238 history_to_screen(scr_stat *scp)
  239 {
  240         int pos;
  241         int i;
  242 
  243         pos = scp->history_pos;
  244         for (i = 1; i <= scp->ysize; ++i) {
  245                 pos = sc_vtb_pos(scp->history, pos, -scp->xsize);
  246                 sc_vtb_copy(scp->history, pos,
  247                             &scp->vtb, scp->xsize*(scp->ysize - i),
  248                             scp->xsize);
  249         }
  250         mark_all(scp);
  251 }
  252 
  253 /* go to the tail of the history buffer */
  254 void
  255 sc_hist_home(scr_stat *scp)
  256 {
  257         scp->history_pos = sc_vtb_tail(scp->history);
  258         history_to_screen(scp);
  259 }
  260 
  261 /* go to the top of the history buffer */
  262 void
  263 sc_hist_end(scr_stat *scp)
  264 {
  265         scp->history_pos = sc_vtb_pos(scp->history, sc_vtb_tail(scp->history),
  266                                       scp->xsize*scp->ysize);
  267         history_to_screen(scp);
  268 }
  269 
  270 /* move one line up */
  271 int
  272 sc_hist_up_line(scr_stat *scp)
  273 {
  274         if (sc_vtb_pos(scp->history, scp->history_pos, -(scp->xsize*scp->ysize))
  275             == sc_vtb_tail(scp->history))
  276                 return -1;
  277         scp->history_pos = sc_vtb_pos(scp->history, scp->history_pos,
  278                                       -scp->xsize);
  279         history_to_screen(scp);
  280         return 0;
  281 }
  282 
  283 /* move one line down */
  284 int
  285 sc_hist_down_line(scr_stat *scp)
  286 {
  287         if (scp->history_pos == sc_vtb_tail(scp->history))
  288                 return -1;
  289         scp->history_pos = sc_vtb_pos(scp->history, scp->history_pos,
  290                                       scp->xsize);
  291         history_to_screen(scp);
  292         return 0;
  293 }
  294 
  295 int
  296 sc_hist_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
  297 {
  298         scr_stat *scp;
  299         int error;
  300 
  301         switch (cmd) {
  302         case CONS_HISTORY:      /* set history size */
  303                 scp = SC_STAT(tp);
  304                 if (*(int *)data <= 0)
  305                         return EINVAL;
  306                 if (scp->status & BUFFER_SAVED)
  307                         return EBUSY;
  308                 DPRINTF(5, ("lines:%d, ysize:%d, pool:%d\n",
  309                             *(int *)data, scp->ysize, extra_history_size));
  310                 error = sc_alloc_history_buffer(scp, 
  311                                                imax(*(int *)data, scp->ysize),
  312                                                scp->ysize, TRUE);
  313                 DPRINTF(5, ("error:%d, rows:%d, pool:%d\n", error,
  314                             sc_vtb_rows(scp->history), extra_history_size));
  315                 return error;
  316 
  317         case CONS_CLRHIST:
  318                 scp = SC_STAT(tp);
  319                 sc_vtb_clear(scp->history, scp->sc->scr_map[0x20],
  320                     SC_NORM_ATTR << 8);
  321                 return 0;
  322         }
  323 
  324         return ENOIOCTL;
  325 }
  326 
  327 #endif /* SC_NO_HISTORY */

Cache object: 8749eae5b18f4136648de1619ac1c109


[ 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.